• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?php
2/*
3 *
4 * Copyright 2015-2016 gRPC authors.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19require_once realpath(dirname(__FILE__).'/../../vendor/autoload.php');
20
21// The following includes are needed when using protobuf 3.1.0
22// and will suppress warnings when using protobuf 3.2.0+
23@include_once 'src/proto/grpc/testing/test.pb.php';
24@include_once 'src/proto/grpc/testing/test_grpc_pb.php';
25
26use Google\Auth\CredentialsLoader;
27use Google\Auth\ApplicationDefaultCredentials;
28use GuzzleHttp\ClientInterface;
29
30/**
31 * Assertion function that always exits with an error code if the assertion is
32 * falsy.
33 *
34 * @param $value Assertion value. Should be true.
35 * @param $error_message Message to display if the assertion is false
36 */
37function hardAssert($value, $error_message)
38{
39    if (!$value) {
40        echo $error_message."\n";
41        exit(1);
42    }
43}
44
45function hardAssertIfStatusOk($status)
46{
47    if ($status->code !== Grpc\STATUS_OK) {
48        echo "Call did not complete successfully. Status object:\n";
49        var_dump($status);
50        exit(1);
51    }
52}
53
54/**
55 * Run the empty_unary test.
56 *
57 * @param $stub Stub object that has service methods
58 */
59function emptyUnary($stub)
60{
61    list($result, $status) =
62        $stub->EmptyCall(new Grpc\Testing\EmptyMessage())->wait();
63    hardAssertIfStatusOk($status);
64    hardAssert($result !== null, 'Call completed with a null response');
65}
66
67/**
68 * Run the large_unary test.
69 *
70 * @param $stub Stub object that has service methods
71 */
72function largeUnary($stub)
73{
74    performLargeUnary($stub);
75}
76
77/**
78 * Shared code between large unary test and auth test.
79 *
80 * @param $stub Stub object that has service methods
81 * @param $fillUsername boolean whether to fill result with username
82 * @param $fillOauthScope boolean whether to fill result with oauth scope
83 */
84function performLargeUnary($stub, $fillUsername = false,
85                           $fillOauthScope = false, $callback = false)
86{
87    $request_len = 271828;
88    $response_len = 314159;
89
90    $request = new Grpc\Testing\SimpleRequest();
91    $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
92    $request->setResponseSize($response_len);
93    $payload = new Grpc\Testing\Payload();
94    $payload->setType(Grpc\Testing\PayloadType::COMPRESSABLE);
95    $payload->setBody(str_repeat("\0", $request_len));
96    $request->setPayload($payload);
97    $request->setFillUsername($fillUsername);
98    $request->setFillOauthScope($fillOauthScope);
99
100    $options = [];
101    if ($callback) {
102        $options['call_credentials_callback'] = $callback;
103    }
104
105    list($result, $status) = $stub->UnaryCall($request, [], $options)->wait();
106    hardAssertIfStatusOk($status);
107    hardAssert($result !== null, 'Call returned a null response');
108    $payload = $result->getPayload();
109    hardAssert($payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
110               'Payload had the wrong type');
111    hardAssert(strlen($payload->getBody()) === $response_len,
112               'Payload had the wrong length');
113    hardAssert($payload->getBody() === str_repeat("\0", $response_len),
114               'Payload had the wrong content');
115
116    return $result;
117}
118
119/**
120 * Run the service account credentials auth test.
121 *
122 * @param $stub Stub object that has service methods
123 * @param $args array command line args
124 */
125function serviceAccountCreds($stub, $args)
126{
127    if (!array_key_exists('oauth_scope', $args)) {
128        throw new Exception('Missing oauth scope');
129    }
130    $jsonKey = json_decode(
131        file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
132        true);
133    $result = performLargeUnary($stub, $fillUsername = true,
134                                $fillOauthScope = true);
135    hardAssert($result->getUsername() === $jsonKey['client_email'],
136               'invalid email returned');
137    hardAssert(strpos($args['oauth_scope'], $result->getOauthScope()) !== false,
138               'invalid oauth scope returned');
139}
140
141/**
142 * Run the compute engine credentials auth test.
143 * Has not been run from gcloud as of 2015-05-05.
144 *
145 * @param $stub Stub object that has service methods
146 * @param $args array command line args
147 */
148function computeEngineCreds($stub, $args)
149{
150    if (!array_key_exists('oauth_scope', $args)) {
151        throw new Exception('Missing oauth scope');
152    }
153    if (!array_key_exists('default_service_account', $args)) {
154        throw new Exception('Missing default_service_account');
155    }
156    $result = performLargeUnary($stub, $fillUsername = true,
157                                $fillOauthScope = true);
158    hardAssert($args['default_service_account'] === $result->getUsername(),
159               'invalid email returned');
160}
161
162/**
163 * Run the jwt token credentials auth test.
164 *
165 * @param $stub Stub object that has service methods
166 * @param $args array command line args
167 */
168function jwtTokenCreds($stub, $args)
169{
170    $jsonKey = json_decode(
171        file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
172        true);
173    $result = performLargeUnary($stub, $fillUsername = true,
174                                $fillOauthScope = true);
175    hardAssert($result->getUsername() === $jsonKey['client_email'],
176               'invalid email returned');
177}
178
179/**
180 * Run the oauth2_auth_token auth test.
181 *
182 * @param $stub Stub object that has service methods
183 * @param $args array command line args
184 */
185function oauth2AuthToken($stub, $args)
186{
187    $jsonKey = json_decode(
188        file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
189        true);
190    $result = performLargeUnary($stub, $fillUsername = true,
191                                $fillOauthScope = true);
192    hardAssert($result->getUsername() === $jsonKey['client_email'],
193               'invalid email returned');
194}
195
196function updateAuthMetadataCallback($context)
197{
198    $authUri = $context->service_url;
199    $methodName = $context->method_name;
200    $auth_credentials = ApplicationDefaultCredentials::getCredentials();
201
202    $metadata = [];
203    $result = $auth_credentials->updateMetadata([], $authUri);
204    foreach ($result as $key => $value) {
205        $metadata[strtolower($key)] = $value;
206    }
207
208    return $metadata;
209}
210
211/**
212 * Run the per_rpc_creds auth test.
213 *
214 * @param $stub Stub object that has service methods
215 * @param $args array command line args
216 */
217function perRpcCreds($stub, $args)
218{
219    $jsonKey = json_decode(
220        file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
221        true);
222
223    $result = performLargeUnary($stub, $fillUsername = true,
224                                $fillOauthScope = true,
225                                'updateAuthMetadataCallback');
226    hardAssert($result->getUsername() === $jsonKey['client_email'],
227               'invalid email returned');
228}
229
230/**
231 * Run the client_streaming test.
232 *
233 * @param $stub Stub object that has service methods
234 */
235function clientStreaming($stub)
236{
237    $request_lengths = [27182, 8, 1828, 45904];
238
239    $requests = array_map(
240        function ($length) {
241            $request = new Grpc\Testing\StreamingInputCallRequest();
242            $payload = new Grpc\Testing\Payload();
243            $payload->setBody(str_repeat("\0", $length));
244            $request->setPayload($payload);
245
246            return $request;
247        }, $request_lengths);
248
249    $call = $stub->StreamingInputCall();
250    foreach ($requests as $request) {
251        $call->write($request);
252    }
253    list($result, $status) = $call->wait();
254    hardAssertIfStatusOk($status);
255    hardAssert($result->getAggregatedPayloadSize() === 74922,
256               'aggregated_payload_size was incorrect');
257}
258
259/**
260 * Run the server_streaming test.
261 *
262 * @param $stub Stub object that has service methods.
263 */
264function serverStreaming($stub)
265{
266    $sizes = [31415, 9, 2653, 58979];
267
268    $request = new Grpc\Testing\StreamingOutputCallRequest();
269    $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
270    foreach ($sizes as $size) {
271        $response_parameters = new Grpc\Testing\ResponseParameters();
272        $response_parameters->setSize($size);
273        $request->getResponseParameters()[] = $response_parameters;
274    }
275
276    $call = $stub->StreamingOutputCall($request);
277    $i = 0;
278    foreach ($call->responses() as $value) {
279        hardAssert($i < 4, 'Too many responses');
280        $payload = $value->getPayload();
281        hardAssert(
282            $payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
283            'Payload '.$i.' had the wrong type');
284        hardAssert(strlen($payload->getBody()) === $sizes[$i],
285                   'Response '.$i.' had the wrong length');
286        $i += 1;
287    }
288    hardAssertIfStatusOk($call->getStatus());
289}
290
291/**
292 * Run the ping_pong test.
293 *
294 * @param $stub Stub object that has service methods.
295 */
296function pingPong($stub)
297{
298    $request_lengths = [27182, 8, 1828, 45904];
299    $response_lengths = [31415, 9, 2653, 58979];
300
301    $call = $stub->FullDuplexCall();
302    for ($i = 0; $i < 4; ++$i) {
303        $request = new Grpc\Testing\StreamingOutputCallRequest();
304        $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
305        $response_parameters = new Grpc\Testing\ResponseParameters();
306        $response_parameters->setSize($response_lengths[$i]);
307        $request->getResponseParameters()[] = $response_parameters;
308        $payload = new Grpc\Testing\Payload();
309        $payload->setBody(str_repeat("\0", $request_lengths[$i]));
310        $request->setPayload($payload);
311
312        $call->write($request);
313        $response = $call->read();
314
315        hardAssert($response !== null, 'Server returned too few responses');
316        $payload = $response->getPayload();
317        hardAssert(
318            $payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
319            'Payload '.$i.' had the wrong type');
320        hardAssert(strlen($payload->getBody()) === $response_lengths[$i],
321                   'Payload '.$i.' had the wrong length');
322    }
323    $call->writesDone();
324    hardAssert($call->read() === null, 'Server returned too many responses');
325    hardAssertIfStatusOk($call->getStatus());
326}
327
328/**
329 * Run the empty_stream test.
330 *
331 * @param $stub Stub object that has service methods.
332 */
333function emptyStream($stub)
334{
335    $call = $stub->FullDuplexCall();
336    $call->writesDone();
337    hardAssert($call->read() === null, 'Server returned too many responses');
338    hardAssertIfStatusOk($call->getStatus());
339}
340
341/**
342 * Run the cancel_after_begin test.
343 *
344 * @param $stub Stub object that has service methods.
345 */
346function cancelAfterBegin($stub)
347{
348    $call = $stub->StreamingInputCall();
349    $call->cancel();
350    list($result, $status) = $call->wait();
351    hardAssert($status->code === Grpc\STATUS_CANCELLED,
352               'Call status was not CANCELLED');
353}
354
355/**
356 * Run the cancel_after_first_response test.
357 *
358 * @param $stub Stub object that has service methods.
359 */
360function cancelAfterFirstResponse($stub)
361{
362    $call = $stub->FullDuplexCall();
363    $request = new Grpc\Testing\StreamingOutputCallRequest();
364    $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
365    $response_parameters = new Grpc\Testing\ResponseParameters();
366    $response_parameters->setSize(31415);
367    $request->getResponseParameters()[] = $response_parameters;
368    $payload = new Grpc\Testing\Payload();
369    $payload->setBody(str_repeat("\0", 27182));
370    $request->setPayload($payload);
371
372    $call->write($request);
373    $response = $call->read();
374
375    $call->cancel();
376    hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED,
377               'Call status was not CANCELLED');
378}
379
380function timeoutOnSleepingServer($stub)
381{
382    $call = $stub->FullDuplexCall([], ['timeout' => 1000]);
383    $request = new Grpc\Testing\StreamingOutputCallRequest();
384    $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
385    $response_parameters = new Grpc\Testing\ResponseParameters();
386    $response_parameters->setSize(8);
387    $request->getResponseParameters()[] = $response_parameters;
388    $payload = new Grpc\Testing\Payload();
389    $payload->setBody(str_repeat("\0", 9));
390    $request->setPayload($payload);
391
392    $call->write($request);
393    $response = $call->read();
394
395    hardAssert($call->getStatus()->code === Grpc\STATUS_DEADLINE_EXCEEDED,
396               'Call status was not DEADLINE_EXCEEDED');
397}
398
399function customMetadata($stub)
400{
401    $ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
402    $ECHO_INITIAL_VALUE = 'test_initial_metadata_value';
403    $ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
404    $ECHO_TRAILING_VALUE = 'ababab';
405    $request_len = 271828;
406    $response_len = 314159;
407
408    $request = new Grpc\Testing\SimpleRequest();
409    $request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
410    $request->setResponseSize($response_len);
411    $payload = new Grpc\Testing\Payload();
412    $payload->setType(Grpc\Testing\PayloadType::COMPRESSABLE);
413    $payload->setBody(str_repeat("\0", $request_len));
414    $request->setPayload($payload);
415
416    $metadata = [
417        $ECHO_INITIAL_KEY => [$ECHO_INITIAL_VALUE],
418        $ECHO_TRAILING_KEY => [$ECHO_TRAILING_VALUE],
419    ];
420    $call = $stub->UnaryCall($request, $metadata);
421
422    $initial_metadata = $call->getMetadata();
423    hardAssert(array_key_exists($ECHO_INITIAL_KEY, $initial_metadata),
424               'Initial metadata does not contain expected key');
425    hardAssert(
426        $initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
427        'Incorrect initial metadata value');
428
429    list($result, $status) = $call->wait();
430    hardAssertIfStatusOk($status);
431
432    $trailing_metadata = $call->getTrailingMetadata();
433    hardAssert(array_key_exists($ECHO_TRAILING_KEY, $trailing_metadata),
434               'Trailing metadata does not contain expected key');
435    hardAssert(
436        $trailing_metadata[$ECHO_TRAILING_KEY][0] === $ECHO_TRAILING_VALUE,
437        'Incorrect trailing metadata value');
438
439    $streaming_call = $stub->FullDuplexCall($metadata);
440
441    $streaming_request = new Grpc\Testing\StreamingOutputCallRequest();
442    $streaming_request->setPayload($payload);
443    $response_parameters = new Grpc\Testing\ResponseParameters();
444    $response_parameters->setSize($response_len);
445    $streaming_request->getResponseParameters()[] = $response_parameters;
446    $streaming_call->write($streaming_request);
447    $streaming_call->writesDone();
448    $result = $streaming_call->read();
449
450    hardAssertIfStatusOk($streaming_call->getStatus());
451
452    $streaming_initial_metadata = $streaming_call->getMetadata();
453    hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata),
454               'Initial metadata does not contain expected key');
455    hardAssert(
456        $streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
457        'Incorrect initial metadata value');
458
459    $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
460    hardAssert(array_key_exists($ECHO_TRAILING_KEY,
461                                $streaming_trailing_metadata),
462               'Trailing metadata does not contain expected key');
463    hardAssert($streaming_trailing_metadata[$ECHO_TRAILING_KEY][0] ===
464               $ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
465}
466
467function statusCodeAndMessage($stub)
468{
469    $echo_status = new Grpc\Testing\EchoStatus();
470    $echo_status->setCode(2);
471    $echo_status->setMessage('test status message');
472
473    $request = new Grpc\Testing\SimpleRequest();
474    $request->setResponseStatus($echo_status);
475
476    $call = $stub->UnaryCall($request);
477    list($result, $status) = $call->wait();
478
479    hardAssert($status->code === 2,
480               'Received unexpected UnaryCall status code: '.
481               $status->code);
482    hardAssert($status->details === 'test status message',
483               'Received unexpected UnaryCall status details: '.
484               $status->details);
485
486    $streaming_call = $stub->FullDuplexCall();
487
488    $streaming_request = new Grpc\Testing\StreamingOutputCallRequest();
489    $streaming_request->setResponseStatus($echo_status);
490    $streaming_call->write($streaming_request);
491    $streaming_call->writesDone();
492    $result = $streaming_call->read();
493
494    $status = $streaming_call->getStatus();
495    hardAssert($status->code === 2,
496               'Received unexpected FullDuplexCall status code: '.
497               $status->code);
498    hardAssert($status->details === 'test status message',
499               'Received unexpected FullDuplexCall status details: '.
500               $status->details);
501}
502
503# NOTE: the stub input to this function is from UnimplementedService
504function unimplementedService($stub)
505{
506    $call = $stub->UnimplementedCall(new Grpc\Testing\EmptyMessage());
507    list($result, $status) = $call->wait();
508    hardAssert($status->code === Grpc\STATUS_UNIMPLEMENTED,
509               'Received unexpected status code');
510}
511
512# NOTE: the stub input to this function is from TestService
513function unimplementedMethod($stub)
514{
515    $call = $stub->UnimplementedCall(new Grpc\Testing\EmptyMessage());
516    list($result, $status) = $call->wait();
517    hardAssert($status->code === Grpc\STATUS_UNIMPLEMENTED,
518               'Received unexpected status code');
519}
520
521function _makeStub($args)
522{
523    if (!array_key_exists('server_host', $args)) {
524        throw new Exception('Missing argument: --server_host is required');
525    }
526    if (!array_key_exists('server_port', $args)) {
527        throw new Exception('Missing argument: --server_port is required');
528    }
529    if (!array_key_exists('test_case', $args)) {
530        throw new Exception('Missing argument: --test_case is required');
531    }
532
533    if ($args['server_port'] === 443) {
534        $server_address = $args['server_host'];
535    } else {
536        $server_address = $args['server_host'].':'.$args['server_port'];
537    }
538
539    $test_case = $args['test_case'];
540
541    $host_override = 'foo.test.google.fr';
542    if (array_key_exists('server_host_override', $args)) {
543        $host_override = $args['server_host_override'];
544    }
545
546    $use_tls = false;
547    if (array_key_exists('use_tls', $args) &&
548        $args['use_tls'] != 'false') {
549        $use_tls = true;
550    }
551
552    $use_test_ca = false;
553    if (array_key_exists('use_test_ca', $args) &&
554        $args['use_test_ca'] != 'false') {
555        $use_test_ca = true;
556    }
557
558    $opts = [];
559
560    if ($use_tls) {
561        if ($use_test_ca) {
562            $ssl_credentials = Grpc\ChannelCredentials::createSsl(
563                file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
564        } else {
565            $ssl_credentials = Grpc\ChannelCredentials::createSsl();
566        }
567        $opts['credentials'] = $ssl_credentials;
568        $opts['grpc.ssl_target_name_override'] = $host_override;
569    } else {
570        $opts['credentials'] = Grpc\ChannelCredentials::createInsecure();
571    }
572
573    if (in_array($test_case, ['service_account_creds',
574                              'compute_engine_creds', 'jwt_token_creds', ])) {
575        if ($test_case === 'jwt_token_creds') {
576            $auth_credentials = ApplicationDefaultCredentials::getCredentials();
577        } else {
578            $auth_credentials = ApplicationDefaultCredentials::getCredentials(
579                $args['oauth_scope']
580            );
581        }
582        $opts['update_metadata'] = $auth_credentials->getUpdateMetadataFunc();
583    }
584
585    if ($test_case === 'oauth2_auth_token') {
586        $auth_credentials = ApplicationDefaultCredentials::getCredentials(
587            $args['oauth_scope']
588        );
589        $token = $auth_credentials->fetchAuthToken();
590        $update_metadata =
591            function ($metadata,
592                      $authUri = null,
593                      ClientInterface $client = null) use ($token) {
594                $metadata_copy = $metadata;
595                $metadata_copy[CredentialsLoader::AUTH_METADATA_KEY] =
596                    [sprintf('%s %s',
597                             $token['token_type'],
598                             $token['access_token'])];
599
600                return $metadata_copy;
601            };
602        $opts['update_metadata'] = $update_metadata;
603    }
604
605    if ($test_case === 'unimplemented_service') {
606        $stub = new Grpc\Testing\UnimplementedServiceClient($server_address,
607                                                            $opts);
608    } else {
609        $stub = new Grpc\Testing\TestServiceClient($server_address, $opts);
610    }
611
612    return $stub;
613}
614
615function interop_main($args, $stub = false)
616{
617    if (!$stub) {
618        $stub = _makeStub($args);
619    }
620
621    $test_case = $args['test_case'];
622    echo "Running test case $test_case\n";
623
624    switch ($test_case) {
625        case 'empty_unary':
626            emptyUnary($stub);
627            break;
628        case 'large_unary':
629            largeUnary($stub);
630            break;
631        case 'client_streaming':
632            clientStreaming($stub);
633            break;
634        case 'server_streaming':
635            serverStreaming($stub);
636            break;
637        case 'ping_pong':
638            pingPong($stub);
639            break;
640        case 'empty_stream':
641            emptyStream($stub);
642            break;
643        case 'cancel_after_begin':
644            cancelAfterBegin($stub);
645            break;
646        case 'cancel_after_first_response':
647            cancelAfterFirstResponse($stub);
648            break;
649        case 'timeout_on_sleeping_server':
650            timeoutOnSleepingServer($stub);
651            break;
652        case 'custom_metadata':
653            customMetadata($stub);
654            break;
655        case 'status_code_and_message':
656            statusCodeAndMessage($stub);
657            break;
658        case 'unimplemented_service':
659            unimplementedService($stub);
660            break;
661        case 'unimplemented_method':
662            unimplementedMethod($stub);
663            break;
664        case 'service_account_creds':
665            serviceAccountCreds($stub, $args);
666            break;
667        case 'compute_engine_creds':
668            computeEngineCreds($stub, $args);
669            break;
670        case 'jwt_token_creds':
671            jwtTokenCreds($stub, $args);
672            break;
673        case 'oauth2_auth_token':
674            oauth2AuthToken($stub, $args);
675            break;
676        case 'per_rpc_creds':
677            perRpcCreds($stub, $args);
678            break;
679        default:
680            echo "Unsupported test case $test_case\n";
681            exit(1);
682    }
683
684    return $stub;
685}
686
687if (isset($_SERVER['PHP_SELF']) &&
688    preg_match('/interop_client/', $_SERVER['PHP_SELF'])) {
689    $args = getopt('', ['server_host:', 'server_port:', 'test_case:',
690                        'use_tls::', 'use_test_ca::',
691                        'server_host_override:', 'oauth_scope:',
692                        'default_service_account:', ]);
693    interop_main($args);
694}
695