From e9f8965a3286cce8cb94e6b47c4fce2c9c1d3be7 Mon Sep 17 00:00:00 2001 From: webhook_bot Date: Tue, 7 May 2024 16:38:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84gateway=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E6=8A=BD=E8=B1=A1=EF=BC=8C=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E6=8A=BD=E8=B1=A1=E5=B1=82=E7=9A=84=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- README.md | 2 +- src/Client/GatewayBaseClient.php | 28 +++ src/Client/GrpcBaseClient.php | 32 ++- src/Client/Options.php | 8 + src/Exceptions/GrpcPhpClientException.php | 5 + src/Metadata/GatewayHandle.php | 4 +- src/Middlewares/GatewayMiddleware.php | 61 ++++- src/Middlewares/GatewayRetry.php | 2 +- src/Middlewares/GrpcOpenTelemetryTrace.php | 3 + tests/Features/BaseGatewayTest.php | 30 +++ tests/Features/BaseTest.php | 11 +- tests/Features/OpenTelemetryGatewayTest.php | 61 +++++ tests/Features/OpenTelemetryTest.php | 32 +-- tests/Mock/TestServer.php | 13 +- tests/Mock/TestServerAbsRpc.php | 4 +- tests/Mock/TestServerGatewayRpc.php | 30 +++ tests/MockGo/go.mod | 15 +- tests/MockGo/go.sum | 42 ++-- tests/MockGo/main.go | 69 +----- tests/MockGo/main_gateway.go | 63 +++++ tests/MockGo/mock/test_server.pb.go | 63 ++--- tests/MockGo/mock/test_server.pb.gw.go | 240 ++++++++++++++++++++ tests/MockGo/server.go | 75 ++++++ tests/MockPHP/MockService.php | 1 + tests/TestCase.php | 6 + tests/data/test_server.proto | 18 +- tests/data/test_server_gen.sh | 12 +- 28 files changed, 756 insertions(+), 177 deletions(-) create mode 100644 src/Client/Options.php create mode 100644 src/Exceptions/GrpcPhpClientException.php create mode 100644 tests/Features/BaseGatewayTest.php create mode 100644 tests/Features/OpenTelemetryGatewayTest.php create mode 100644 tests/Mock/TestServerGatewayRpc.php create mode 100644 tests/MockGo/main_gateway.go create mode 100644 tests/MockGo/mock/test_server.pb.gw.go create mode 100644 tests/MockGo/server.go diff --git a/.gitignore b/.gitignore index 4668574..4d7d233 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea /vendor/ -.DS_Store \ No newline at end of file +.DS_Store +.phpunit.result.cache \ No newline at end of file diff --git a/README.md b/README.md index 3eb93c9..072ab5d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ abstract grpc and grpc-gateway - [x] 添加解析 protobuf Any 参数的工具 UtilAny - [x] 一元请求重试中间件 - [x] 支持配置化的默认调用行为 -- [x] 支持OTLP链路追踪 +- [x] 支持OpenTelemetry链路追踪(grpc、gateway都已支持) - [x] 开发自动生成grpc原生客户端抽象层 [protoc-gen-php-abs-grpc](https://github.com/reatang/protoc-gen-php-abs-grpc) - [ ] 开发自动生成grpc-gateway抽象层 `很显然,没搞呢` diff --git a/src/Client/GatewayBaseClient.php b/src/Client/GatewayBaseClient.php index ba249e9..015e207 100644 --- a/src/Client/GatewayBaseClient.php +++ b/src/Client/GatewayBaseClient.php @@ -9,6 +9,7 @@ use GuzzleHttp\RequestOptions; use Psr\Http\Message\ResponseInterface; use Reatang\GrpcPHPAbstract\Exceptions\GrpcException; +use Reatang\GrpcPHPAbstract\Exceptions\GrpcPhpClientException; use Reatang\GrpcPHPAbstract\Metadata\GatewayHandle; use Reatang\GrpcPHPAbstract\Metadata\Metadata; use Reatang\GrpcPHPAbstract\Middlewares\GatewayMiddleware; @@ -42,6 +43,7 @@ public function __construct(string $host, array $middleware = []) $h->push(Middleware::httpErrors(), 'http_errors'); $h->push(Middleware::prepareBody(), 'prepare_body'); $h->push(GatewayMiddleware::retry(), 'retry'); + $h->push(GatewayMiddleware::openTelemetryTrace(), "open_telemetry"); $this->client = new Client([ 'base_uri' => $this->host(), @@ -92,6 +94,28 @@ public function addRoute(string $methodName, string $url, string $response) } } + /** + * 处理各种额外选项 + * + * @param $reqOpts + * + * @return array + * @throws GrpcPhpClientException + */ + private function requestOpts($reqOpts) : array + { + $opts = []; + if (isset($reqOpts[Options::Metadata])) { + if (!($reqOpts[Options::Metadata] instanceof Metadata)) { + throw new GrpcPhpClientException("Request Options: [Metadata] need " . Metadata::class); + } + + $opts[RequestOptions::HEADERS] = GatewayHandle::toHeader($reqOpts[Options::Metadata]); + } + + return $opts; + } + /** * @param $name * @param $arguments @@ -113,6 +137,10 @@ public function __call($name, $arguments) $opts[RequestOptions::BODY] = $arguments[0]->serializeToJsonString(); } + if (isset($arguments[1])) { + $opts = array_merge($opts, $this->requestOpts($arguments[1])); + } + $response = $this->client->request('POST', $route->getUrl(), $opts); } catch (ServerException $exception) { throw $this->exception($exception); diff --git a/src/Client/GrpcBaseClient.php b/src/Client/GrpcBaseClient.php index 518986f..37a699b 100644 --- a/src/Client/GrpcBaseClient.php +++ b/src/Client/GrpcBaseClient.php @@ -143,6 +143,25 @@ protected function metadata(AbstractCall $call): Metadata return GrpcHandle::parseCall($call); } + /** + * @param Metadata $metadata + * + * @return array + */ + private function requestMetadata(Metadata $metadata) : array + { + $md = $metadata->header->toArray(); + foreach ($md as $k => $v) { + if (!is_array($v)) { + $v = [$v]; + } + + $md[$k] = $v; + } + + return $md; + } + /** * 返回原生的grpc调用结果 * @@ -153,16 +172,21 @@ protected function metadata(AbstractCall $call): Metadata */ protected function rawCall($method, $arguments) { - if (!isset($arguments[1])) { - $arguments[1] = []; + $rawArguments[0] = $arguments[0]; + if (isset($arguments[1]) && $arguments[1][Options::Metadata]) { + $rawArguments[1] = $this->requestMetadata($arguments[1][Options::Metadata]); + } else { + $rawArguments[1] = []; } // timeout 单位:微秒 if ($this->timeout > 0) { - $arguments[2]['timeout'] = $this->timeout * 1000; + $rawArguments[2] = [ + 'timeout' => $this->timeout * 1000, + ]; } - $call = call_user_func_array([$this->client, ucfirst($method)], $arguments); + $call = call_user_func_array([$this->client, ucfirst($method)], $rawArguments); return $call->wait(); } diff --git a/src/Client/Options.php b/src/Client/Options.php new file mode 100644 index 0000000..f4a93ab --- /dev/null +++ b/src/Client/Options.php @@ -0,0 +1,8 @@ +header->toArray() as $h => $v) { - $n[GatewayHandle::MetadataHeaderPrefix . $h] = is_array($v) ? join(',', $v) : $v; + $n[GatewayHandle::MetadataHeaderPrefix . ucfirst($h)] = is_array($v) ? join(',', $v) : $v; } foreach ($metadata->trailer->toArray() as $h => $v) { - $n[GatewayHandle::MetadataTrailerPrefix . $h] = is_array($v) ? join(',', $v) : $v; + $n[GatewayHandle::MetadataTrailerPrefix . ucfirst($h)] = is_array($v) ? join(',', $v) : $v; } return $n; diff --git a/src/Middlewares/GatewayMiddleware.php b/src/Middlewares/GatewayMiddleware.php index 3e90e4c..33f805f 100644 --- a/src/Middlewares/GatewayMiddleware.php +++ b/src/Middlewares/GatewayMiddleware.php @@ -2,9 +2,17 @@ namespace Reatang\GrpcPHPAbstract\Middlewares; +use GuzzleHttp\Psr7\Response; +use OpenTelemetry\API\Globals; +use OpenTelemetry\API\Trace\SpanKind; +use OpenTelemetry\API\Trace\StatusCode; +use OpenTelemetry\Context\Context; +use OpenTelemetry\SemConv\TraceAttributes; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; use Reatang\GrpcPHPAbstract\Metadata\GatewayHandle; use Reatang\GrpcPHPAbstract\Metadata\Metadata; +use Reatang\GrpcPHPAbstract\Utils\MetadataAccessGetterSetter; class GatewayMiddleware { @@ -24,8 +32,8 @@ class GatewayMiddleware */ public static function GrpcGatewayOpt($timeout): callable { - return static function (callable $handler) use ($timeout): callable { - return static function (RequestInterface $request, array $options) use ($handler, $timeout) { + return function (callable $handler) use ($timeout): callable { + return function (RequestInterface $request, array $options) use ($handler, $timeout) { $request = $request ->withAddedHeader('Accept', '*') ->withAddedHeader(GatewayHandle::metadataGrpcTimeout, $timeout); @@ -45,8 +53,8 @@ public static function GrpcGatewayOpt($timeout): callable */ public static function GrpcMetadata(array $headers, array $trailers = []): callable { - return static function (callable $handler) use ($headers, $trailers) : callable { - return static function (RequestInterface $request, array $options) use ($headers, $trailers, $handler) { + return function (callable $handler) use ($headers, $trailers) : callable { + return function (RequestInterface $request, array $options) use ($headers, $trailers, $handler) { $md = Metadata::create($headers, $trailers); foreach (GatewayHandle::toHeader($md) as $k => $v) { @@ -72,4 +80,49 @@ public static function retry(int $maxAttempt = 3, int $delay = 300): callable return new GatewayRetry($maxAttempt, $delay, $handler); }; } + + public static function openTelemetryTrace(): callable + { + $tracer = Globals::tracerProvider()->getTracer("reatang/grpc-php-abstract"); + + return function (callable $handler) use ($tracer) { + return function (RequestInterface $request, array $options) use ($handler, $tracer) { + $name = sprintf("POST %s", $request->getUri()->getPath()); + + $span = $tracer->spanBuilder($name) + ->setSpanKind(SpanKind::KIND_CLIENT) + ->setParent(Context::getCurrent()) + ->startSpan(); + $ctx = $span->storeInContext(Context::getCurrent()); + $scope = $span->activate(); + + $metadata = []; + Globals::propagator()->inject($metadata, MetadataAccessGetterSetter::getInstance(), $ctx); + + foreach (GatewayHandle::toHeader(Metadata::create($metadata)) as $k => $v) { + $request = $request->withAddedHeader($k, $v); + } + + /** @var \GuzzleHttp\Promise\FulfilledPromise $promise */ + $promise = $handler($request, $options); + + $promise->then(function (ResponseInterface $response) use ($span, $scope) { + $span->setAttributes([ + TraceAttributes::HTTP_STATUS_CODE => $response->getStatusCode(), + ]); + $span->setStatus(StatusCode::STATUS_OK)->end(); + $scope->detach(); + }, function (\Throwable $e) use ($span, $scope) { + $span->setAttributes([ + TraceAttributes::EXCEPTION_TYPE => get_class($e), + TraceAttributes::EXCEPTION_MESSAGE => $e->getMessage(), + ]); + $span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage())->end(); + $scope->detach(); + }); + + return $promise; + }; + }; + } } \ No newline at end of file diff --git a/src/Middlewares/GatewayRetry.php b/src/Middlewares/GatewayRetry.php index 7b5a134..70298d6 100644 --- a/src/Middlewares/GatewayRetry.php +++ b/src/Middlewares/GatewayRetry.php @@ -84,7 +84,7 @@ private function onRejected(RequestInterface $req, array $options) { return function ($reason) use ($req, $options) { if (!$this->decider($options['retries'], $req, null, $reason)) { - return \GuzzleHttp\Promise\rejection_for($reason); + return \GuzzleHttp\Promise\Create::rejectionFor($reason); } return $this->doRetry($req, $options); diff --git a/src/Middlewares/GrpcOpenTelemetryTrace.php b/src/Middlewares/GrpcOpenTelemetryTrace.php index 32c4e16..49f4a7e 100644 --- a/src/Middlewares/GrpcOpenTelemetryTrace.php +++ b/src/Middlewares/GrpcOpenTelemetryTrace.php @@ -59,6 +59,9 @@ public function interceptUnaryUnary( $span->setAttribute(TraceAttributes::RPC_GRPC_STATUS_CODE, $status->code); if ($status->code != \Grpc\STATUS_OK) { + $span->setAttributes([ + TraceAttributes::RPC_GRPC_STATUS_CODE => $status->code, + ]); $span->setStatus(StatusCode::STATUS_ERROR, $status->details)->end(); } else { $span->setStatus(StatusCode::STATUS_OK)->end(); diff --git a/tests/Features/BaseGatewayTest.php b/tests/Features/BaseGatewayTest.php new file mode 100644 index 0000000..94842a3 --- /dev/null +++ b/tests/Features/BaseGatewayTest.php @@ -0,0 +1,30 @@ +getMockGatewayClient()->Ping(new PingRequest(["ping" => "test"])); + $this->assertEquals($response->getPong(), "PONG"); + } + + public function testMetadata() + { + $metadata = "123"; + $response = $this->getMockGatewayClient()->Ping(new PingRequest(["ping" => "metadata"]), [ + Options::Metadata => Metadata::create(["abc" => $metadata]), + ]); + + $this->assertEquals($response->getPong(), "PONG" . $metadata); + } +} diff --git a/tests/Features/BaseTest.php b/tests/Features/BaseTest.php index 3730ed9..baf7f8e 100644 --- a/tests/Features/BaseTest.php +++ b/tests/Features/BaseTest.php @@ -2,6 +2,9 @@ namespace Reatang\GrpcPHPAbstract\Tests\Features; +use GuzzleHttp\RequestOptions; +use Reatang\GrpcPHPAbstract\Client\Options; +use Reatang\GrpcPHPAbstract\Metadata\Metadata; use Reatang\GrpcPHPAbstract\Tests\Mock\PB\PingRequest; use Reatang\GrpcPHPAbstract\Tests\Mock\TestServer; use Reatang\GrpcPHPAbstract\Tests\Mock\TestServerClient; @@ -18,14 +21,10 @@ public function testPing() public function testMetadata() { $metadata = "123"; - /** @var TestServerClient $c */ - $c = $this->getMockClient()->rawClient(); - $call = $c->Ping(new PingRequest(["ping" => "metadata"]), [ - "abc" => [$metadata], + $response = $this->getMockClient()->Ping(new PingRequest(["ping" => "metadata"]), [ + Options::Metadata => Metadata::create(["abc" => $metadata]), ]); - [$response, $status] = $call->wait(); - $this->assertEquals($status->code, 0); $this->assertEquals($response->getPong(), "PONG" . $metadata); } } diff --git a/tests/Features/OpenTelemetryGatewayTest.php b/tests/Features/OpenTelemetryGatewayTest.php new file mode 100644 index 0000000..58eec90 --- /dev/null +++ b/tests/Features/OpenTelemetryGatewayTest.php @@ -0,0 +1,61 @@ +create()); + $processor = new NoopSpanProcessor(); + $tracerProvider = new TracerProvider( + $processor, + new ParentBased(new AlwaysOnSampler()), + ); + + Sdk::builder() + ->setTracerProvider($tracerProvider) + ->setPropagator(new MultiTextMapPropagator([ + TraceContextPropagator::getInstance(), + BaggagePropagator::getInstance(), + ])) + ->setAutoShutdown(true) + ->buildAndRegisterGlobal(); + } + + public function testBase() + { + $response = $this->getMockGatewayClient()->OTel(new OTelRequest()); + + $this->assertTrue(!empty($response->getTrace())); + $this->assertNotEquals($response->getTrace(), '00000000000000000000000000000000'); + } + + public function testBaggage() + { + $baggageVar = "123"; + $scope = Baggage::getCurrent()->toBuilder()->set("baggage1", $baggageVar)->build()->activate(); + + $response = $this->getMockGatewayClient()->OTel(new OTelRequest()); + + $scope->detach(); + + $this->assertTrue(!empty($response->getTrace())); + $this->assertNotEquals($response->getTrace(), '00000000000000000000000000000000'); + $this->assertEquals($baggageVar, $response->getBaggage()); + } +} \ No newline at end of file diff --git a/tests/Features/OpenTelemetryTest.php b/tests/Features/OpenTelemetryTest.php index 4ef4d96..bb665d6 100644 --- a/tests/Features/OpenTelemetryTest.php +++ b/tests/Features/OpenTelemetryTest.php @@ -4,19 +4,15 @@ use OpenTelemetry\API\Baggage\Baggage; use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator; -use OpenTelemetry\API\Globals; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\Context\Propagation\MultiTextMapPropagator; use OpenTelemetry\SDK\Sdk; use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; use OpenTelemetry\SDK\Trace\Sampler\ParentBased; -use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporterFactory; use OpenTelemetry\SDK\Trace\SpanProcessor\NoopSpanProcessor; -use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; use OpenTelemetry\SDK\Trace\TracerProvider; use Reatang\GrpcPHPAbstract\Middlewares\GrpcOpenTelemetryTrace; use Reatang\GrpcPHPAbstract\Tests\Mock\PB\OTelRequest; -use Reatang\GrpcPHPAbstract\Tests\Mock\PB\OTelResponse; use Reatang\GrpcPHPAbstract\Tests\Mock\TestServerAbsRpc; use Reatang\GrpcPHPAbstract\Tests\TestCase; @@ -52,37 +48,23 @@ protected function getMockClient(): TestServerAbsRpc public function testBase() { - $call = $this->getMockClient()->rawClient()->OTel(new OTelRequest(), []); + $response = $this->getMockClient()->OTel(new OTelRequest()); - [$response, $status] = $call->wait(); - if ($status->code > 0) { - var_dump($status); - } - - $this->assertEquals($status->code, 0); + $this->assertNotEquals($response->getTrace(), '00000000000000000000000000000000'); $this->assertTrue(!empty($response->getTrace())); } public function testBaggage() { $baggageVar = "123"; - $currentBaggage = Baggage::getCurrent()->toBuilder()->set("baggage1", $baggageVar)->build()->activate(); - - $metadata = []; - Globals::propagator()->inject($metadata); - - $call = $this->getMockClient()->rawClient()->OTel(new OTelRequest(), $metadata); + $scope = Baggage::getCurrent()->toBuilder()->set("baggage1", $baggageVar)->build()->activate(); - /** @var OTelResponse $response */ - [$response, $status] = $call->wait(); + $response = $this->getMockClient()->OTel(new OTelRequest()); - $currentBaggage->detach(); - if ($status->code > 0) { - var_dump($status); - } + $scope->detach(); - $this->assertEquals($status->code, 0); $this->assertTrue(!empty($response->getTrace())); - $this->assertEquals($response->getBaggage(), $baggageVar); + $this->assertNotEquals($response->getTrace(), '00000000000000000000000000000000'); + $this->assertEquals($baggageVar, $response->getBaggage()); } } \ No newline at end of file diff --git a/tests/Mock/TestServer.php b/tests/Mock/TestServer.php index 11d2052..c53677a 100644 --- a/tests/Mock/TestServer.php +++ b/tests/Mock/TestServer.php @@ -14,9 +14,10 @@ public static function initOnce() { if (static::$is_initialized == true) { return; } + \GPBMetadata\Google\Api\Annotations::initOnce(); $pool->internalAddGeneratedFile( ' - + test_server.proto$reatang.grpc_php_abstract.tests.mock" PingRequest ping ( " @@ -25,11 +26,13 @@ public static function initOnce() { OTelRequest". OTelResponse trace (  -baggage ( 2 +baggage ( 2 -TestServerm -Ping1.reatang.grpc_php_abstract.tests.mock.PingRequest2.reatang.grpc_php_abstract.tests.mock.PingResponsem -OTel1.reatang.grpc_php_abstract.tests.mock.OTelRequest2.reatang.grpc_php_abstract.tests.mock.OTelResponseB[Z./mockPB\\"Reatang\\GrpcPHPAbstract\\Tests\\Mock"Reatang\\GrpcPHPAbstract\\Tests\\Mockbproto3' +TestServer +Ping1.reatang.grpc_php_abstract.tests.mock.PingRequest2.reatang.grpc_php_abstract.tests.mock.PingResponse"" +/grpc/ping:* +OTel1.reatang.grpc_php_abstract.tests.mock.OTelRequest2.reatang.grpc_php_abstract.tests.mock.OTelResponse"" +/grpc/otel:*B[Z./mockPB\\"Reatang\\GrpcPHPAbstract\\Tests\\Mock"Reatang\\GrpcPHPAbstract\\Tests\\Mockbproto3' , true); static::$is_initialized = true; diff --git a/tests/Mock/TestServerAbsRpc.php b/tests/Mock/TestServerAbsRpc.php index 73a8f61..5fc5808 100644 --- a/tests/Mock/TestServerAbsRpc.php +++ b/tests/Mock/TestServerAbsRpc.php @@ -14,8 +14,8 @@ /** * @property TestServerClient $client * - * @method PingResponse Ping(PingRequest $request) - * @method OTelResponse OTel(OTelRequest $request) + * @method PingResponse Ping(PingRequest $request, array $opts = []) + * @method OTelResponse OTel(OTelRequest $request, array $opts = []) * */ class TestServerAbsRpc extends GrpcBaseClient diff --git a/tests/Mock/TestServerGatewayRpc.php b/tests/Mock/TestServerGatewayRpc.php new file mode 100644 index 0000000..4099e66 --- /dev/null +++ b/tests/Mock/TestServerGatewayRpc.php @@ -0,0 +1,30 @@ +addRoute("Ping", "/grpc/ping", PingResponse::class); + $this->addRoute("OTel", "/grpc/otel", OTelResponse::class); + } +} \ No newline at end of file diff --git a/tests/MockGo/go.mod b/tests/MockGo/go.mod index 7e233b2..6296831 100644 --- a/tests/MockGo/go.mod +++ b/tests/MockGo/go.mod @@ -3,13 +3,15 @@ module mock_service go 1.20 require ( + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 - google.golang.org/grpc v1.55.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe + google.golang.org/grpc v1.61.0 + google.golang.org/protobuf v1.32.0 ) require ( @@ -17,8 +19,9 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect ) diff --git a/tests/MockGo/go.sum b/tests/MockGo/go.sum index 0a26b74..3f71fb0 100644 --- a/tests/MockGo/go.sum +++ b/tests/MockGo/go.sum @@ -1,7 +1,9 @@ -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -11,7 +13,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= @@ -26,21 +30,25 @@ go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiM go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/tests/MockGo/main.go b/tests/MockGo/main.go index 4472d15..6fbbe1c 100644 --- a/tests/MockGo/main.go +++ b/tests/MockGo/main.go @@ -1,81 +1,16 @@ package main import ( - "context" - "fmt" "mock_service/mock" "net" - "os" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/baggage" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - "go.opentelemetry.io/otel/propagation" - "go.opentelemetry.io/otel/sdk/resource" - sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.17.0" - oteltrace "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" "google.golang.org/grpc/reflection" - "google.golang.org/grpc/status" ) -type Service struct { - mock.UnimplementedTestServerServer -} - -func (s Service) Ping(ctx context.Context, request *mock.PingRequest) (*mock.PingResponse, error) { - if request.GetPing() == "" || request.GetPing() == "ping" { - return &mock.PingResponse{Pong: "PONG"}, nil - } else if request.GetPing() == "metadata" { - if md, b := metadata.FromIncomingContext(ctx); b { - abc := md.Get("abc") - if len(abc) == 0 { - return nil, status.Errorf(codes.InvalidArgument, "参数错误") - } - - return &mock.PingResponse{Pong: fmt.Sprintf("PONG%s", abc[0])}, nil - } - } - - return nil, status.Errorf(codes.NotFound, "未找到的测试") -} - -func (s Service) OTel(ctx context.Context, request *mock.OTelRequest) (*mock.OTelResponse, error) { - bag, span := baggage.FromContext(ctx), oteltrace.SpanContextFromContext(ctx) - - return &mock.OTelResponse{ - Trace: span.TraceID().String(), - Baggage: bag.Member("baggage1").Value(), - }, nil -} - func main() { - // otel 初始化 - resourceAttr, err := resource.New(context.Background(), - resource.WithAttributes( - semconv.ServiceName("go_grpc_mock"), - ), - ) - if err != nil { - panic(err) - } - - exporter, err := stdouttrace.New(stdouttrace.WithWriter(os.Stdout)) - if err != nil { - panic(err) - } - - tp := sdktrace.NewTracerProvider( - sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(1.0))), - sdktrace.WithResource(resourceAttr), - sdktrace.WithBatcher(exporter), - ) - otel.SetTracerProvider(tp) - otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) + otelStart() // 服务启动 lis, err := net.Listen("tcp", ":9099") @@ -89,7 +24,7 @@ func main() { server := grpc.NewServer(options...) - mock.RegisterTestServerServer(server, &Service{}) + mock.RegisterTestServerServer(server, &Server{}) reflection.Register(server) if err := server.Serve(lis); err != nil { diff --git a/tests/MockGo/main_gateway.go b/tests/MockGo/main_gateway.go new file mode 100644 index 0000000..846afa5 --- /dev/null +++ b/tests/MockGo/main_gateway.go @@ -0,0 +1,63 @@ +package main + +import ( + "context" + "log" + "mock_service/mock" + "net" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/reflection" + "google.golang.org/grpc/test/bufconn" +) + +// MockServerContextDialer 内嵌式server dialer +func MockServerContextDialer() func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer(grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor())) + mock.RegisterTestServerServer(server, &Server{}) + + reflection.Register(server) + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func main() { + otelStart() + + conn, err := grpc.Dial("", + grpc.WithContextDialer(MockServerContextDialer()), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + log.Fatal(err) + } + + mux := runtime.NewServeMux() + + err = mock.RegisterTestServerHandler(context.Background(), mux, conn) + if err != nil { + log.Fatal(err) + return + } + + http.Handle("/", mux) + + log.Println("server start :9098") + if err := http.ListenAndServe(":9098", nil); err != nil { + log.Fatal(err) + } + + log.Println("server stop") +} diff --git a/tests/MockGo/mock/test_server.pb.go b/tests/MockGo/mock/test_server.pb.go index d8c5012..d62f37c 100644 --- a/tests/MockGo/mock/test_server.pb.go +++ b/tests/MockGo/mock/test_server.pb.go @@ -7,6 +7,7 @@ package mock import ( + _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -213,38 +214,42 @@ var file_test_server_proto_rawDesc = []byte{ 0x0a, 0x11, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x22, 0x21, 0x0a, 0x0b, 0x50, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x22, 0x22, 0x0a, 0x0c, - 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, - 0x22, 0x0d, 0x0a, 0x0b, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x3e, 0x0a, 0x0c, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x67, 0x67, 0x61, 0x67, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x67, 0x67, 0x61, 0x67, 0x65, 0x32, - 0xea, 0x01, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x6d, - 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x31, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x69, - 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x72, 0x65, 0x61, 0x74, - 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, - 0x04, 0x4f, 0x54, 0x65, 0x6c, 0x12, 0x31, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, + 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x21, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x22, 0x22, 0x0a, 0x0c, 0x50, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x22, 0x0d, + 0x0a, 0x0b, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, + 0x0c, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x72, + 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x67, 0x67, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x67, 0x67, 0x61, 0x67, 0x65, 0x32, 0x9a, 0x02, + 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x84, 0x01, 0x0a, + 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x31, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x4f, 0x54, 0x65, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, + 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, - 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5b, 0x5a, 0x06, - 0x2e, 0x2f, 0x6d, 0x6f, 0x63, 0x6b, 0xc2, 0x02, 0x03, 0x50, 0x42, 0x5c, 0xca, 0x02, 0x22, 0x52, - 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x5c, 0x47, 0x72, 0x70, 0x63, 0x50, 0x48, 0x50, 0x41, 0x62, - 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5c, 0x54, 0x65, 0x73, 0x74, 0x73, 0x5c, 0x4d, 0x6f, 0x63, - 0x6b, 0xd0, 0x02, 0x01, 0xe2, 0x02, 0x22, 0x52, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x5c, 0x47, - 0x72, 0x70, 0x63, 0x50, 0x48, 0x50, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5c, 0x54, - 0x65, 0x73, 0x74, 0x73, 0x5c, 0x4d, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, + 0x69, 0x6e, 0x67, 0x12, 0x84, 0x01, 0x0a, 0x04, 0x4f, 0x54, 0x65, 0x6c, 0x12, 0x31, 0x2e, 0x72, + 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x68, 0x70, 0x5f, + 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x6d, + 0x6f, 0x63, 0x6b, 0x2e, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x32, 0x2e, 0x72, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x70, + 0x68, 0x70, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x73, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x4f, 0x54, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, + 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6f, 0x74, 0x65, 0x6c, 0x42, 0x5b, 0x5a, 0x06, 0x2e, 0x2f, + 0x6d, 0x6f, 0x63, 0x6b, 0xc2, 0x02, 0x03, 0x50, 0x42, 0x5c, 0xca, 0x02, 0x22, 0x52, 0x65, 0x61, + 0x74, 0x61, 0x6e, 0x67, 0x5c, 0x47, 0x72, 0x70, 0x63, 0x50, 0x48, 0x50, 0x41, 0x62, 0x73, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x5c, 0x54, 0x65, 0x73, 0x74, 0x73, 0x5c, 0x4d, 0x6f, 0x63, 0x6b, 0xd0, + 0x02, 0x01, 0xe2, 0x02, 0x22, 0x52, 0x65, 0x61, 0x74, 0x61, 0x6e, 0x67, 0x5c, 0x47, 0x72, 0x70, + 0x63, 0x50, 0x48, 0x50, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5c, 0x54, 0x65, 0x73, + 0x74, 0x73, 0x5c, 0x4d, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/tests/MockGo/mock/test_server.pb.gw.go b/tests/MockGo/mock/test_server.pb.gw.go new file mode 100644 index 0000000..ef3e26a --- /dev/null +++ b/tests/MockGo/mock/test_server.pb.gw.go @@ -0,0 +1,240 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: test_server.proto + +/* +Package mock is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package mock + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_TestServer_Ping_0(ctx context.Context, marshaler runtime.Marshaler, client TestServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq PingRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Ping(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_TestServer_Ping_0(ctx context.Context, marshaler runtime.Marshaler, server TestServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq PingRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Ping(ctx, &protoReq) + return msg, metadata, err + +} + +func request_TestServer_OTel_0(ctx context.Context, marshaler runtime.Marshaler, client TestServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq OTelRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.OTel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_TestServer_OTel_0(ctx context.Context, marshaler runtime.Marshaler, server TestServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq OTelRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.OTel(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterTestServerHandlerServer registers the http handlers for service TestServer to "mux". +// UnaryRPC :call TestServerServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterTestServerHandlerFromEndpoint instead. +func RegisterTestServerHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TestServerServer) error { + + mux.Handle("POST", pattern_TestServer_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/reatang.grpc_php_abstract.tests.mock.TestServer/Ping", runtime.WithHTTPPathPattern("/grpc/ping")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_TestServer_Ping_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_TestServer_Ping_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_TestServer_OTel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/reatang.grpc_php_abstract.tests.mock.TestServer/OTel", runtime.WithHTTPPathPattern("/grpc/otel")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_TestServer_OTel_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_TestServer_OTel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterTestServerHandlerFromEndpoint is same as RegisterTestServerHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterTestServerHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.DialContext(ctx, endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterTestServerHandler(ctx, mux, conn) +} + +// RegisterTestServerHandler registers the http handlers for service TestServer to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterTestServerHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterTestServerHandlerClient(ctx, mux, NewTestServerClient(conn)) +} + +// RegisterTestServerHandlerClient registers the http handlers for service TestServer +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TestServerClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TestServerClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "TestServerClient" to call the correct interceptors. +func RegisterTestServerHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TestServerClient) error { + + mux.Handle("POST", pattern_TestServer_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/reatang.grpc_php_abstract.tests.mock.TestServer/Ping", runtime.WithHTTPPathPattern("/grpc/ping")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_TestServer_Ping_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_TestServer_Ping_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_TestServer_OTel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/reatang.grpc_php_abstract.tests.mock.TestServer/OTel", runtime.WithHTTPPathPattern("/grpc/otel")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_TestServer_OTel_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_TestServer_OTel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_TestServer_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"grpc", "ping"}, "")) + + pattern_TestServer_OTel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"grpc", "otel"}, "")) +) + +var ( + forward_TestServer_Ping_0 = runtime.ForwardResponseMessage + + forward_TestServer_OTel_0 = runtime.ForwardResponseMessage +) diff --git a/tests/MockGo/server.go b/tests/MockGo/server.go new file mode 100644 index 0000000..bb16cb6 --- /dev/null +++ b/tests/MockGo/server.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "mock_service/mock" + "os" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/baggage" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" + oteltrace "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +type Server struct { + mock.UnimplementedTestServerServer +} + +func (s Server) Ping(ctx context.Context, request *mock.PingRequest) (*mock.PingResponse, error) { + if request.GetPing() == "" || request.GetPing() == "ping" || request.GetPing() == "test" { + return &mock.PingResponse{Pong: "PONG"}, nil + } else if request.GetPing() == "metadata" { + if md, b := metadata.FromIncomingContext(ctx); b { + abc := md.Get("abc") + if len(abc) == 0 { + return nil, status.Errorf(codes.InvalidArgument, "参数错误") + } + + return &mock.PingResponse{Pong: fmt.Sprintf("PONG%s", abc[0])}, nil + } + } + + return nil, status.Errorf(codes.NotFound, "未找到的测试") +} + +func (s Server) OTel(ctx context.Context, request *mock.OTelRequest) (*mock.OTelResponse, error) { + bag, span := baggage.FromContext(ctx), oteltrace.SpanContextFromContext(ctx) + + return &mock.OTelResponse{ + Trace: span.TraceID().String(), + Baggage: bag.Member("baggage1").Value(), + }, nil +} + +func otelStart() { + // otel 初始化 + resourceAttr, err := resource.New(context.Background(), + resource.WithAttributes( + semconv.ServiceName("go_grpc_mock"), + ), + ) + if err != nil { + panic(err) + } + + exporter, err := stdouttrace.New(stdouttrace.WithWriter(os.Stdout)) + if err != nil { + panic(err) + } + + tp := sdktrace.NewTracerProvider( + sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(1.0))), + sdktrace.WithResource(resourceAttr), + sdktrace.WithBatcher(exporter), + ) + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) +} diff --git a/tests/MockPHP/MockService.php b/tests/MockPHP/MockService.php index ded2d82..0103b06 100644 --- a/tests/MockPHP/MockService.php +++ b/tests/MockPHP/MockService.php @@ -11,6 +11,7 @@ use Reatang\GrpcPHPAbstract\Tests\Mock\PB\OTelResponse; use Reatang\GrpcPHPAbstract\Tests\Mock\PB\PingRequest; use Reatang\GrpcPHPAbstract\Tests\Mock\PB\PingResponse; +use Reatang\GrpcPHPAbstract\Tests\Mock\PB\TestServerInterface; use Reatang\GrpcPHPAbstract\Tests\Mock\TestServerStub; class MockService extends TestServerStub diff --git a/tests/TestCase.php b/tests/TestCase.php index 10f198e..87d7213 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,6 +2,7 @@ namespace Reatang\GrpcPHPAbstract\Tests; use Reatang\GrpcPHPAbstract\Tests\Mock\TestServerAbsRpc; +use Reatang\GrpcPHPAbstract\Tests\Mock\TestServerGatewayRpc; class TestCase extends \PHPUnit\Framework\TestCase { @@ -9,4 +10,9 @@ protected function getMockClient(): TestServerAbsRpc { return new TestServerAbsRpc("127.0.0.1:9099"); } + + protected function getMockGatewayClient(): TestServerGatewayRpc + { + return new TestServerGatewayRpc("127.0.0.1:9098"); + } } \ No newline at end of file diff --git a/tests/data/test_server.proto b/tests/data/test_server.proto index 34e54fc..a0a1017 100644 --- a/tests/data/test_server.proto +++ b/tests/data/test_server.proto @@ -9,6 +9,8 @@ option php_metadata_namespace = "Reatang\\GrpcPHPAbstract\\Tests\\Mock"; option php_namespace = "Reatang\\GrpcPHPAbstract\\Tests\\Mock"; option php_generic_services = true; +import "google/api/annotations.proto"; + message PingRequest { string ping = 1; } @@ -26,7 +28,17 @@ message OTelResponse { } service TestServer { - rpc Ping(PingRequest) returns(PingResponse); - - rpc OTel(OTelRequest) returns(OTelResponse); + rpc Ping(PingRequest) returns(PingResponse) { + option (google.api.http) = { + post: "/grpc/ping" + body: "*" + }; + }; + + rpc OTel(OTelRequest) returns(OTelResponse){ + option (google.api.http) = { + post: "/grpc/otel" + body: "*" + }; + } } \ No newline at end of file diff --git a/tests/data/test_server_gen.sh b/tests/data/test_server_gen.sh index 2f05d2c..5757731 100755 --- a/tests/data/test_server_gen.sh +++ b/tests/data/test_server_gen.sh @@ -1,7 +1,10 @@ #!/bin/bash +GOOGLE_IDL=${HOME}/protoc/googleapis +PROTOBUF_IDL=${HOME}/protoc/protoc-21.12/include + # PHP -protoc -I ./ \ +protoc -I $PROTOBUF_IDL -I $GOOGLE_IDL -I ./ \ --php_out=../ \ --php-abs-grpc_out=../ --plugin=protoc-gen-grpc=${GOPATH}/bin/protoc-gen-php-abs-grpc \ --grpc_out=../ --grpc_opt=generate_server --plugin=protoc-gen-grpc=${HOME}/protoc/grpc-1.52.1/grpc_php_plugin \ @@ -13,7 +16,8 @@ if [ $? -eq 0 ]; then fi # go -protoc -I ./ \ - --go_out=../go_grpc/mock --go_opt=paths=source_relative \ - --go-grpc_out=../go_grpc/mock --go-grpc_opt=paths=source_relative \ +protoc -I $PROTOBUF_IDL -I $GOOGLE_IDL -I ./ \ + --go_out=../MockGo/mock --go_opt=paths=source_relative \ + --go-grpc_out=../MockGo/mock --go-grpc_opt=paths=source_relative \ + --grpc-gateway_out=../MockGo/mock --grpc-gateway_opt=paths=source_relative \ test_server.proto \ No newline at end of file