From 7197ce64ee1fdacb1de9ce58d56735bf19fe4105 Mon Sep 17 00:00:00 2001 From: Hannah Shi Date: Thu, 1 Jul 2021 10:55:52 -0700 Subject: [PATCH] PHP: php server commit 6/n, add php server interop test (#26202) * add php server interop test * fix CI failure --- src/php/bin/interop_server.sh | 21 +++ src/php/tests/interop/interop_server.php | 217 +++++++++++++++++++++++ tools/run_tests/run_interop_tests.py | 8 +- 3 files changed, 244 insertions(+), 2 deletions(-) create mode 100755 src/php/bin/interop_server.sh create mode 100644 src/php/tests/interop/interop_server.php diff --git a/src/php/bin/interop_server.sh b/src/php/bin/interop_server.sh new file mode 100755 index 0000000000000..64f031f8f8d24 --- /dev/null +++ b/src/php/bin/interop_server.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Copyright 2020 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. + +set -e +cd $(dirname $0) +source ./determine_extension_dir.sh +cd ../tests/interop +php $extension_dir -d max_execution_time=300 \ + interop_server.php $@ 1>&2 diff --git a/src/php/tests/interop/interop_server.php b/src/php/tests/interop/interop_server.php new file mode 100644 index 0000000000000..f280fe7b48fe7 --- /dev/null +++ b/src/php/tests/interop/interop_server.php @@ -0,0 +1,217 @@ +clientMetadata(); + if (array_key_exists($ECHO_INITIAL_KEY, $client_metadata)) { + $initial_metadata = [ + $ECHO_INITIAL_KEY => + $client_metadata[$ECHO_INITIAL_KEY], + ]; + } + if (array_key_exists($ECHO_TRAILING_KEY, $client_metadata)) { + $trailing_metadata = [ + $ECHO_TRAILING_KEY => + $client_metadata[$ECHO_TRAILING_KEY], + ]; + } + return [$initial_metadata, $trailing_metadata]; + } + + private function maybeEchoStatusAndMessage( + $request, + $trailing_metadata = [] + ) { + if (!$request->hasResponseStatus()) { + return null; + } + return \Grpc\Status::status( + $request->getResponseStatus()->getCode(), + $request->getResponseStatus()->getMessage(), + $trailing_metadata + ); + } + + public function EmptyCall( + \Grpc\Testing\EmptyMessage $request, + \Grpc\ServerContext $context + ): ?\Grpc\Testing\EmptyMessage { + list($initial_metadata, $trailing_metadata) = + $this->maybeEchoMetadata($context); + $context->setStatus(\Grpc\Status::ok($trailing_metadata)); + $context->setInitialMetadata($initial_metadata); + return new \Grpc\Testing\EmptyMessage(); + } + + public function UnaryCall( + \Grpc\Testing\SimpleRequest $request, + \Grpc\ServerContext $context + ): ?\Grpc\Testing\SimpleResponse { + list($initial_metadata, $trailing_metadata) = + $this->maybeEchoMetadata($context); + $echo_status = $this->maybeEchoStatusAndMessage( + $request, + $trailing_metadata + ); + + $payload = new \Grpc\Testing\Payload([ + 'type' => $request->getResponseType(), + 'body' => str_repeat("\0", $request->getResponseSize()), + ]); + $response = new \Grpc\Testing\SimpleResponse([ + 'payload' => $payload, + ]); + + $context->setInitialMetadata($initial_metadata); + $context->setStatus($echo_status ?? \Grpc\Status::ok($trailing_metadata)); + return $response; + } + + public function CacheableUnaryCall( + \Grpc\Testing\SimpleRequest $request, + \Grpc\ServerContext $context + ): ?\Grpc\Testing\SimpleResponse { + $context->setStatus(\Grpc\Status::unimplemented()); + return null; + } + + public function StreamingOutputCall( + \Grpc\Testing\StreamingOutputCallRequest $request, + \Grpc\ServerCallWriter $writter, + \Grpc\ServerContext $context + ): void { + $echo_status = $this->maybeEchoStatusAndMessage($request); + + foreach ($request->getResponseParameters() as $parameter) { + if ($parameter->getIntervalUs() > 0) { + usleep($parameter->getIntervalUs()); + } + $payload = new \Grpc\Testing\Payload([ + 'type' => $request->getResponseType(), + 'body' => str_repeat("\0", $parameter->getSize()), + ]); + $response = new \Grpc\Testing\StreamingOutputCallResponse([ + 'payload' => $payload, + ]); + $options = []; + $writter->write($response, $options); + } + $context->setStatus($echo_status ?? \Grpc\Status::ok()); + $writter->finish(); + } + + public function StreamingInputCall( + \Grpc\ServerCallReader $reader, + \Grpc\ServerContext $context + ): ?\Grpc\Testing\StreamingInputCallResponse { + $aggregate_size = 0; + while ($request = $reader->read()) { + if ($request->hasPayload()) { + $aggregate_size += strlen($request->getPayload()->getBody()); + } + } + $response = new \Grpc\Testing\StreamingInputCallResponse(); + $response->setAggregatedPayloadSize($aggregate_size); + return $response; + } + + public function FullDuplexCall( + \Grpc\ServerCallReader $reader, + \Grpc\ServerCallWriter $writter, + \Grpc\ServerContext $context + ): void { + list($initial_metadata, $trailing_metadata) = + $this->maybeEchoMetadata($context); + $context->setInitialMetadata($initial_metadata); + while ($request = $reader->read()) { + $echo_status = $this->maybeEchoStatusAndMessage( + $request, + $trailing_metadata + ); + if ($echo_status) { + $context->setStatus($echo_status); + $writter->finish(); + return; + } + + foreach ($request->getResponseParameters() as $parameter) { + if ($parameter->getIntervalUs() > 0) { + usleep($parameter->getIntervalUs()); + } + $payload = new \Grpc\Testing\Payload([ + 'type' => $request->getResponseType(), + 'body' => str_repeat("\0", $parameter->getSize()), + ]); + $response = new \Grpc\Testing\StreamingOutputCallResponse([ + 'payload' => $payload, + ]); + $options = []; + $writter->write($response, $options); + } + } + $context->setStatus(\Grpc\Status::ok($trailing_metadata)); + $writter->finish(); + } + + public function HalfDuplexCall( + \Grpc\ServerCallReader $reader, + \Grpc\ServerCallWriter $writter, + \Grpc\ServerContext $context + ): void { + $context->setStatus(\Grpc\Status::unimplemented()); + $writter->finish(); + } + + public function UnimplementedCall( + \Grpc\Testing\EmptyMessage $request, + \Grpc\ServerContext $context + ): ?\Grpc\Testing\EmptyMessage { + $context->setStatus(\Grpc\Status::unimplemented()); + return null; + } +}; + + +$args = getopt('', ['port:', 'use_tls::',]); + +$server = new \Grpc\RpcServer(); + +$listening_address = '0.0.0.0:' . $args['port']; +if ($args['use_tls']) { + $server_credentials = \Grpc\ServerCredentials::createSsl( + null, + file_get_contents(dirname(__FILE__) . '/../data/server1.key'), + file_get_contents(dirname(__FILE__) . '/../data/server1.pem') + ); + $server->addSecureHttp2Port($listening_address, $server_credentials); +} else { + $server->addHttp2Port($listening_address); +} +$server->handle(new TestService()); +echo 'Server running on ' . $listening_address . PHP_EOL; +$server->run(); diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 4f525d552c26c..f422bec96f60b 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -487,6 +487,7 @@ class PHP7Language: def __init__(self): self.client_cwd = None + self.server_cwd = None self.safename = str(self) def client_cmd(self, args): @@ -495,6 +496,9 @@ def client_cmd(self, args): def cloud_to_prod_env(self): return {} + def server_cmd(self, args): + return ['src/php/bin/interop_server.sh'] + args + def global_env(self): return {} @@ -505,7 +509,7 @@ def unimplemented_test_cases(self): _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS def unimplemented_test_cases_server(self): - return [] + return _SKIP_COMPRESSION def __str__(self): return 'php7' @@ -714,7 +718,7 @@ def __str__(self): # languages supported as cloud_to_cloud servers _SERVERS = [ 'c++', 'node', 'csharp', 'csharpcoreclr', 'aspnetcore', 'java', 'go', - 'ruby', 'python', 'dart', 'pythonasyncio' + 'ruby', 'python', 'dart', 'pythonasyncio', 'php7' ] _TEST_CASES = [