blob: 88be899fdd1167a83952d3b88793988a6a6f4c69 [file] [log] [blame]
<?php
/*
*
* Copyright 2015-2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
require_once realpath(dirname(__FILE__).'/../../vendor/autoload.php');
// The following includes are needed when using protobuf 3.1.0
// and will suppress warnings when using protobuf 3.2.0+
@include_once 'src/proto/grpc/testing/test.pb.php';
@include_once 'src/proto/grpc/testing/test_grpc_pb.php';
use Google\Auth\CredentialsLoader;
use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\ClientInterface;
/**
* Assertion function that always exits with an error code if the assertion is
* falsy.
*
* @param $value Assertion value. Should be true.
* @param $error_message Message to display if the assertion is false
*/
function hardAssert($value, $error_message)
{
if (!$value) {
echo $error_message."\n";
exit(1);
}
}
function hardAssertIfStatusOk($status)
{
if ($status->code !== Grpc\STATUS_OK) {
echo "Call did not complete successfully. Status object:\n";
var_dump($status);
exit(1);
}
}
/**
* Run the empty_unary test.
*
* @param $stub Stub object that has service methods
*/
function emptyUnary($stub)
{
list($result, $status) =
$stub->EmptyCall(new Grpc\Testing\EmptyMessage())->wait();
hardAssertIfStatusOk($status);
hardAssert($result !== null, 'Call completed with a null response');
}
/**
* Run the large_unary test.
*
* @param $stub Stub object that has service methods
*/
function largeUnary($stub)
{
performLargeUnary($stub);
}
/**
* Shared code between large unary test and auth test.
*
* @param $stub Stub object that has service methods
* @param $fillUsername boolean whether to fill result with username
* @param $fillOauthScope boolean whether to fill result with oauth scope
*/
function performLargeUnary($stub, $fillUsername = false,
$fillOauthScope = false, $callback = false)
{
$request_len = 271828;
$response_len = 314159;
$request = new Grpc\Testing\SimpleRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
$request->setResponseSize($response_len);
$payload = new Grpc\Testing\Payload();
$payload->setType(Grpc\Testing\PayloadType::COMPRESSABLE);
$payload->setBody(str_repeat("\0", $request_len));
$request->setPayload($payload);
$request->setFillUsername($fillUsername);
$request->setFillOauthScope($fillOauthScope);
$options = [];
if ($callback) {
$options['call_credentials_callback'] = $callback;
}
list($result, $status) = $stub->UnaryCall($request, [], $options)->wait();
hardAssertIfStatusOk($status);
hardAssert($result !== null, 'Call returned a null response');
$payload = $result->getPayload();
hardAssert($payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
'Payload had the wrong type');
hardAssert(strlen($payload->getBody()) === $response_len,
'Payload had the wrong length');
hardAssert($payload->getBody() === str_repeat("\0", $response_len),
'Payload had the wrong content');
return $result;
}
/**
* Run the client_compressed_unary test.
*
* @param $stub Stub object that has service methods
*/
function clientCompressedUnary($stub)
{
$request_len = 271828;
$response_len = 314159;
$falseBoolValue = new Grpc\Testing\BoolValue(['value' => false]);
$trueBoolValue = new Grpc\Testing\BoolValue(['value' => true]);
// 1. Probing for compression-checks support
$payload = new Grpc\Testing\Payload([
'body' => str_repeat("\0", $request_len),
]);
$request = new Grpc\Testing\SimpleRequest([
'payload' => $payload,
'response_size' => $response_len,
'expect_compressed' => $trueBoolValue, // lie
]);
list($result, $status) = $stub->UnaryCall($request, [], [])->wait();
hardAssert(
$status->code === GRPC\STATUS_INVALID_ARGUMENT,
'Received unexpected UnaryCall status code: ' .
$status->code
);
// 2. with/without compressed message
foreach ([true, false] as $compression) {
$request->setExpectCompressed($compression ? $trueBoolValue : $falseBoolValue);
$metadata = $compression ? [
'grpc-internal-encoding-request' => ['gzip'],
] : [];
list($result, $status) = $stub->UnaryCall($request, $metadata, [])->wait();
hardAssertIfStatusOk($status);
hardAssert($result !== null, 'Call returned a null response');
$payload = $result->getPayload();
hardAssert(
strlen($payload->getBody()) === $response_len,
'Payload had the wrong length'
);
hardAssert(
$payload->getBody() === str_repeat("\0", $response_len),
'Payload had the wrong content'
);
}
}
/**
* Run the service account credentials auth test.
*
* @param $stub Stub object that has service methods
* @param $args array command line args
*/
function serviceAccountCreds($stub, $args)
{
if (!array_key_exists('oauth_scope', $args)) {
throw new Exception('Missing oauth scope');
}
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
$result = performLargeUnary($stub, $fillUsername = true,
$fillOauthScope = true);
hardAssert($result->getUsername() === $jsonKey['client_email'],
'invalid email returned');
hardAssert(strpos($args['oauth_scope'], $result->getOauthScope()) !== false,
'invalid oauth scope returned');
}
/**
* Run the compute engine credentials auth test.
* Has not been run from gcloud as of 2015-05-05.
*
* @param $stub Stub object that has service methods
* @param $args array command line args
*/
function computeEngineCreds($stub, $args)
{
if (!array_key_exists('oauth_scope', $args)) {
throw new Exception('Missing oauth scope');
}
if (!array_key_exists('default_service_account', $args)) {
throw new Exception('Missing default_service_account');
}
$result = performLargeUnary($stub, $fillUsername = true,
$fillOauthScope = true);
hardAssert($args['default_service_account'] === $result->getUsername(),
'invalid email returned');
}
/**
* Run the jwt token credentials auth test.
*
* @param $stub Stub object that has service methods
* @param $args array command line args
*/
function jwtTokenCreds($stub, $args)
{
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
$result = performLargeUnary($stub, $fillUsername = true,
$fillOauthScope = true);
hardAssert($result->getUsername() === $jsonKey['client_email'],
'invalid email returned');
}
/**
* Run the oauth2_auth_token auth test.
*
* @param $stub Stub object that has service methods
* @param $args array command line args
*/
function oauth2AuthToken($stub, $args)
{
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
$result = performLargeUnary($stub, $fillUsername = true,
$fillOauthScope = true);
hardAssert($result->getUsername() === $jsonKey['client_email'],
'invalid email returned');
}
function updateAuthMetadataCallback($context)
{
$authUri = $context->service_url;
$methodName = $context->method_name;
$auth_credentials = ApplicationDefaultCredentials::getCredentials();
$metadata = [];
$result = $auth_credentials->updateMetadata([], $authUri);
foreach ($result as $key => $value) {
$metadata[strtolower($key)] = $value;
}
return $metadata;
}
/**
* Run the per_rpc_creds auth test.
*
* @param $stub Stub object that has service methods
* @param $args array command line args
*/
function perRpcCreds($stub, $args)
{
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
$result = performLargeUnary($stub, $fillUsername = true,
$fillOauthScope = true,
'updateAuthMetadataCallback');
hardAssert($result->getUsername() === $jsonKey['client_email'],
'invalid email returned');
}
/**
* Run the client_streaming test.
*
* @param $stub Stub object that has service methods
*/
function clientStreaming($stub)
{
$request_lengths = [27182, 8, 1828, 45904];
$requests = array_map(
function ($length) {
$request = new Grpc\Testing\StreamingInputCallRequest();
$payload = new Grpc\Testing\Payload();
$payload->setBody(str_repeat("\0", $length));
$request->setPayload($payload);
return $request;
}, $request_lengths);
$call = $stub->StreamingInputCall();
foreach ($requests as $request) {
$call->write($request);
}
list($result, $status) = $call->wait();
hardAssertIfStatusOk($status);
hardAssert($result->getAggregatedPayloadSize() === 74922,
'aggregated_payload_size was incorrect');
}
/**
* Run the server_streaming test.
*
* @param $stub Stub object that has service methods.
*/
function serverStreaming($stub)
{
$sizes = [31415, 9, 2653, 58979];
$request = new Grpc\Testing\StreamingOutputCallRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
foreach ($sizes as $size) {
$response_parameters = new Grpc\Testing\ResponseParameters();
$response_parameters->setSize($size);
$request->getResponseParameters()[] = $response_parameters;
}
$call = $stub->StreamingOutputCall($request);
$i = 0;
foreach ($call->responses() as $value) {
hardAssert($i < 4, 'Too many responses');
$payload = $value->getPayload();
hardAssert(
$payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
'Payload '.$i.' had the wrong type');
hardAssert(strlen($payload->getBody()) === $sizes[$i],
'Response '.$i.' had the wrong length');
$i += 1;
}
hardAssertIfStatusOk($call->getStatus());
}
/**
* Run the ping_pong test.
*
* @param $stub Stub object that has service methods.
*/
function pingPong($stub)
{
$request_lengths = [27182, 8, 1828, 45904];
$response_lengths = [31415, 9, 2653, 58979];
$call = $stub->FullDuplexCall();
for ($i = 0; $i < 4; ++$i) {
$request = new Grpc\Testing\StreamingOutputCallRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
$response_parameters = new Grpc\Testing\ResponseParameters();
$response_parameters->setSize($response_lengths[$i]);
$request->getResponseParameters()[] = $response_parameters;
$payload = new Grpc\Testing\Payload();
$payload->setBody(str_repeat("\0", $request_lengths[$i]));
$request->setPayload($payload);
$call->write($request);
$response = $call->read();
hardAssert($response !== null, 'Server returned too few responses');
$payload = $response->getPayload();
hardAssert(
$payload->getType() === Grpc\Testing\PayloadType::COMPRESSABLE,
'Payload '.$i.' had the wrong type');
hardAssert(strlen($payload->getBody()) === $response_lengths[$i],
'Payload '.$i.' had the wrong length');
}
$call->writesDone();
hardAssert($call->read() === null, 'Server returned too many responses');
hardAssertIfStatusOk($call->getStatus());
}
/**
* Run the empty_stream test.
*
* @param $stub Stub object that has service methods.
*/
function emptyStream($stub)
{
$call = $stub->FullDuplexCall();
$call->writesDone();
hardAssert($call->read() === null, 'Server returned too many responses');
hardAssertIfStatusOk($call->getStatus());
}
/**
* Run the cancel_after_begin test.
*
* @param $stub Stub object that has service methods.
*/
function cancelAfterBegin($stub)
{
$call = $stub->StreamingInputCall();
$call->cancel();
list($result, $status) = $call->wait();
hardAssert($status->code === Grpc\STATUS_CANCELLED,
'Call status was not CANCELLED');
}
/**
* Run the cancel_after_first_response test.
*
* @param $stub Stub object that has service methods.
*/
function cancelAfterFirstResponse($stub)
{
$call = $stub->FullDuplexCall();
$request = new Grpc\Testing\StreamingOutputCallRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
$response_parameters = new Grpc\Testing\ResponseParameters();
$response_parameters->setSize(31415);
$request->getResponseParameters()[] = $response_parameters;
$payload = new Grpc\Testing\Payload();
$payload->setBody(str_repeat("\0", 27182));
$request->setPayload($payload);
$call->write($request);
$response = $call->read();
$call->cancel();
hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED,
'Call status was not CANCELLED');
}
function timeoutOnSleepingServer($stub)
{
$call = $stub->FullDuplexCall([], ['timeout' => 1000]);
$request = new Grpc\Testing\StreamingOutputCallRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
$response_parameters = new Grpc\Testing\ResponseParameters();
$response_parameters->setSize(8);
$request->getResponseParameters()[] = $response_parameters;
$payload = new Grpc\Testing\Payload();
$payload->setBody(str_repeat("\0", 9));
$request->setPayload($payload);
$call->write($request);
$response = $call->read();
hardAssert($call->getStatus()->code === Grpc\STATUS_DEADLINE_EXCEEDED,
'Call status was not DEADLINE_EXCEEDED');
}
function customMetadata($stub)
{
$ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
$ECHO_INITIAL_VALUE = 'test_initial_metadata_value';
$ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
$ECHO_TRAILING_VALUE = 'ababab';
$request_len = 271828;
$response_len = 314159;
$request = new Grpc\Testing\SimpleRequest();
$request->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
$request->setResponseSize($response_len);
$payload = new Grpc\Testing\Payload();
$payload->setType(Grpc\Testing\PayloadType::COMPRESSABLE);
$payload->setBody(str_repeat("\0", $request_len));
$request->setPayload($payload);
$metadata = [
$ECHO_INITIAL_KEY => [$ECHO_INITIAL_VALUE],
$ECHO_TRAILING_KEY => [$ECHO_TRAILING_VALUE],
];
$call = $stub->UnaryCall($request, $metadata);
$initial_metadata = $call->getMetadata();
hardAssert(array_key_exists($ECHO_INITIAL_KEY, $initial_metadata),
'Initial metadata does not contain expected key');
hardAssert(
$initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
'Incorrect initial metadata value');
list($result, $status) = $call->wait();
hardAssertIfStatusOk($status);
$trailing_metadata = $call->getTrailingMetadata();
hardAssert(array_key_exists($ECHO_TRAILING_KEY, $trailing_metadata),
'Trailing metadata does not contain expected key');
hardAssert(
$trailing_metadata[$ECHO_TRAILING_KEY][0] === $ECHO_TRAILING_VALUE,
'Incorrect trailing metadata value');
$streaming_call = $stub->FullDuplexCall($metadata);
$streaming_request = new Grpc\Testing\StreamingOutputCallRequest();
$streaming_request->setPayload($payload);
$response_parameters = new Grpc\Testing\ResponseParameters();
$response_parameters->setSize($response_len);
$streaming_request->getResponseParameters()[] = $response_parameters;
$streaming_call->write($streaming_request);
$streaming_call->writesDone();
$result = $streaming_call->read();
hardAssertIfStatusOk($streaming_call->getStatus());
$streaming_initial_metadata = $streaming_call->getMetadata();
hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata),
'Initial metadata does not contain expected key');
hardAssert(
$streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
'Incorrect initial metadata value');
$streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
hardAssert(array_key_exists($ECHO_TRAILING_KEY,
$streaming_trailing_metadata),
'Trailing metadata does not contain expected key');
hardAssert($streaming_trailing_metadata[$ECHO_TRAILING_KEY][0] ===
$ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
}
function statusCodeAndMessage($stub)
{
$echo_status = new Grpc\Testing\EchoStatus();
$echo_status->setCode(2);
$echo_status->setMessage('test status message');
$request = new Grpc\Testing\SimpleRequest();
$request->setResponseStatus($echo_status);
$call = $stub->UnaryCall($request);
list($result, $status) = $call->wait();
hardAssert($status->code === 2,
'Received unexpected UnaryCall status code: '.
$status->code);
hardAssert($status->details === 'test status message',
'Received unexpected UnaryCall status details: '.
$status->details);
$streaming_call = $stub->FullDuplexCall();
$streaming_request = new Grpc\Testing\StreamingOutputCallRequest();
$streaming_request->setResponseStatus($echo_status);
$streaming_call->write($streaming_request);
$streaming_call->writesDone();
$result = $streaming_call->read();
$status = $streaming_call->getStatus();
hardAssert($status->code === 2,
'Received unexpected FullDuplexCall status code: '.
$status->code);
hardAssert($status->details === 'test status message',
'Received unexpected FullDuplexCall status details: '.
$status->details);
}
# NOTE: the stub input to this function is from UnimplementedService
function unimplementedService($stub)
{
$call = $stub->UnimplementedCall(new Grpc\Testing\EmptyMessage());
list($result, $status) = $call->wait();
hardAssert($status->code === Grpc\STATUS_UNIMPLEMENTED,
'Received unexpected status code');
}
# NOTE: the stub input to this function is from TestService
function unimplementedMethod($stub)
{
$call = $stub->UnimplementedCall(new Grpc\Testing\EmptyMessage());
list($result, $status) = $call->wait();
hardAssert($status->code === Grpc\STATUS_UNIMPLEMENTED,
'Received unexpected status code');
}
function _makeStub($args)
{
if (!array_key_exists('server_host', $args)) {
throw new Exception('Missing argument: --server_host is required');
}
if (!array_key_exists('server_port', $args)) {
throw new Exception('Missing argument: --server_port is required');
}
if (!array_key_exists('test_case', $args)) {
throw new Exception('Missing argument: --test_case is required');
}
$server_address = $args['server_host'].':'.$args['server_port'];
$test_case = $args['test_case'];
$host_override = '';
if (array_key_exists('server_host_override', $args)) {
$host_override = $args['server_host_override'];
}
$use_tls = false;
if (array_key_exists('use_tls', $args) &&
$args['use_tls'] != 'false') {
$use_tls = true;
}
$use_test_ca = false;
if (array_key_exists('use_test_ca', $args) &&
$args['use_test_ca'] != 'false') {
$use_test_ca = true;
}
$opts = [];
if ($use_tls) {
if ($use_test_ca) {
$ssl_credentials = Grpc\ChannelCredentials::createSsl(
file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
} else {
$ssl_credentials = Grpc\ChannelCredentials::createSsl();
}
$opts['credentials'] = $ssl_credentials;
if (!empty($host_override)) {
$opts['grpc.ssl_target_name_override'] = $host_override;
}
} else {
$opts['credentials'] = Grpc\ChannelCredentials::createInsecure();
}
if (in_array($test_case, ['service_account_creds',
'compute_engine_creds', 'jwt_token_creds', ])) {
if ($test_case === 'jwt_token_creds') {
$auth_credentials = ApplicationDefaultCredentials::getCredentials();
} else {
$auth_credentials = ApplicationDefaultCredentials::getCredentials(
$args['oauth_scope']
);
}
$opts['update_metadata'] = $auth_credentials->getUpdateMetadataFunc();
}
if ($test_case === 'oauth2_auth_token') {
$auth_credentials = ApplicationDefaultCredentials::getCredentials(
$args['oauth_scope']
);
$token = $auth_credentials->fetchAuthToken();
$update_metadata =
function ($metadata,
$authUri = null,
ClientInterface $client = null) use ($token) {
$metadata_copy = $metadata;
$metadata_copy[CredentialsLoader::AUTH_METADATA_KEY] =
[sprintf('%s %s',
$token['token_type'],
$token['access_token'])];
return $metadata_copy;
};
$opts['update_metadata'] = $update_metadata;
}
if ($test_case === 'unimplemented_service') {
$stub = new Grpc\Testing\UnimplementedServiceClient($server_address,
$opts);
} else {
$stub = new Grpc\Testing\TestServiceClient($server_address, $opts);
}
return $stub;
}
function interop_main($args, $stub = false)
{
if (!$stub) {
$stub = _makeStub($args);
}
$test_case = $args['test_case'];
echo "Running test case $test_case\n";
switch ($test_case) {
case 'empty_unary':
emptyUnary($stub);
break;
case 'large_unary':
largeUnary($stub);
break;
case 'client_streaming':
clientStreaming($stub);
break;
case 'server_streaming':
serverStreaming($stub);
break;
case 'ping_pong':
pingPong($stub);
break;
case 'empty_stream':
emptyStream($stub);
break;
case 'cancel_after_begin':
cancelAfterBegin($stub);
break;
case 'cancel_after_first_response':
cancelAfterFirstResponse($stub);
break;
case 'timeout_on_sleeping_server':
timeoutOnSleepingServer($stub);
break;
case 'custom_metadata':
customMetadata($stub);
break;
case 'status_code_and_message':
statusCodeAndMessage($stub);
break;
case 'unimplemented_service':
unimplementedService($stub);
break;
case 'unimplemented_method':
unimplementedMethod($stub);
break;
case 'service_account_creds':
serviceAccountCreds($stub, $args);
break;
case 'compute_engine_creds':
computeEngineCreds($stub, $args);
break;
case 'jwt_token_creds':
jwtTokenCreds($stub, $args);
break;
case 'oauth2_auth_token':
oauth2AuthToken($stub, $args);
break;
case 'per_rpc_creds':
perRpcCreds($stub, $args);
break;
case 'client_compressed_unary':
clientCompressedUnary($stub);
break;
default:
echo "Unsupported test case $test_case\n";
exit(1);
}
return $stub;
}
if (isset($_SERVER['PHP_SELF']) &&
preg_match('/interop_client/', $_SERVER['PHP_SELF'])) {
$args = getopt('', ['server_host:', 'server_port:', 'test_case:',
'use_tls::', 'use_test_ca::',
'server_host_override:', 'oauth_scope:',
'default_service_account:', ]);
interop_main($args);
}