xref: /aosp_15_r20/external/grpc-grpc/src/php/tests/unit_tests/InterceptorTest.php (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1<?php
2/*
3 *
4 * Copyright 2018 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 */
19/**
20 * Interface exported by the server.
21 */
22require_once(dirname(__FILE__).'/../../lib/Grpc/BaseStub.php');
23require_once(dirname(__FILE__).'/../../lib/Grpc/AbstractCall.php');
24require_once(dirname(__FILE__).'/../../lib/Grpc/UnaryCall.php');
25require_once(dirname(__FILE__).'/../../lib/Grpc/ClientStreamingCall.php');
26require_once(dirname(__FILE__).'/../../lib/Grpc/Interceptor.php');
27require_once(dirname(__FILE__).'/../../lib/Grpc/CallInvoker.php');
28require_once(dirname(__FILE__).'/../../lib/Grpc/Internal/InterceptorChannel.php');
29
30class SimpleRequest
31{
32    private $data;
33    public function __construct($data)
34    {
35        $this->data = $data;
36    }
37    public function setData($data)
38    {
39        $this->data = $data;
40    }
41    public function serializeToString()
42    {
43        return $this->data;
44    }
45}
46
47class InterceptorClient extends Grpc\BaseStub
48{
49
50    /**
51     * @param string $hostname hostname
52     * @param array $opts channel options
53     * @param Channel|InterceptorChannel $channel (optional) re-use channel object
54     */
55    public function __construct($hostname, $opts, $channel = null)
56    {
57        parent::__construct($hostname, $opts, $channel);
58    }
59
60    /**
61     * A simple RPC.
62     * @param SimpleRequest $argument input argument
63     * @param array $metadata metadata
64     * @param array $options call options
65     */
66    public function UnaryCall(
67        SimpleRequest $argument,
68        $metadata = [],
69        $options = []
70    ) {
71        return $this->_simpleRequest(
72            '/phony_method',
73            $argument,
74            [],
75            $metadata,
76            $options
77        );
78    }
79
80    /**
81     * A client-to-server streaming RPC.
82     * @param array $metadata metadata
83     * @param array $options call options
84     */
85    public function StreamCall(
86        $metadata = [],
87        $options = []
88    ) {
89        return $this->_clientStreamRequest('/phony_method', [], $metadata, $options);
90    }
91}
92
93
94class ChangeMetadataInterceptor extends Grpc\Interceptor
95{
96    public function interceptUnaryUnary($method,
97                                        $argument,
98                                        $deserialize,
99                                        $continuation,
100                                        array $metadata = [],
101                                        array $options = [])
102    {
103        $metadata["foo"] = array('interceptor_from_unary_request');
104        return $continuation($method, $argument, $deserialize, $metadata, $options);
105    }
106    public function interceptStreamUnary($method,
107                                         $deserialize,
108                                         $continuation,
109                                         array $metadata = [],
110                                         array $options = [])
111    {
112        $metadata["foo"] = array('interceptor_from_stream_request');
113        return $continuation($method, $deserialize, $metadata, $options);
114    }
115}
116
117class ChangeMetadataInterceptor2 extends Grpc\Interceptor
118{
119    public function interceptUnaryUnary($method,
120                                        $argument,
121                                        $deserialize,
122                                        $continuation,
123                                        array $metadata = [],
124                                        array $options = [])
125    {
126        if (array_key_exists('foo', $metadata)) {
127            $metadata['bar'] = array('ChangeMetadataInterceptor should be executed first');
128        } else {
129            $metadata["bar"] = array('interceptor_from_unary_request');
130        }
131        return $continuation($method, $argument, $deserialize, $metadata, $options);
132    }
133    public function interceptStreamUnary($method,
134                                         $deserialize,
135                                         $continuation,
136                                         array $metadata = [],
137                                         array $options = [])
138    {
139        if (array_key_exists('foo', $metadata)) {
140            $metadata['bar'] = array('ChangeMetadataInterceptor should be executed first');
141        } else {
142            $metadata["bar"] = array('interceptor_from_stream_request');
143        }
144        return $continuation($method, $deserialize, $metadata, $options);
145    }
146}
147
148class ChangeRequestCall
149{
150    private $call;
151
152    public function __construct($call)
153    {
154        $this->call = $call;
155    }
156    public function getCall()
157    {
158        return $this->call;
159    }
160
161    public function write($request)
162    {
163        $request->setData('intercepted_stream_request');
164        $this->getCall()->write($request);
165    }
166
167    public function wait()
168    {
169        return $this->getCall()->wait();
170    }
171}
172
173class ChangeRequestInterceptor extends Grpc\Interceptor
174{
175    public function interceptUnaryUnary($method,
176                                        $argument,
177                                        $deserialize,
178                                        $continuation,
179                                        array $metadata = [],
180                                        array $options = [])
181    {
182        $argument->setData('intercepted_unary_request');
183        return $continuation($method, $argument, $deserialize, $metadata, $options);
184    }
185    public function interceptStreamUnary($method,
186                                         $deserialize,
187                                         $continuation,
188                                         array $metadata = [],
189                                         array $options = [])
190    {
191        return new ChangeRequestCall(
192            $continuation($method, $deserialize, $metadata, $options)
193        );
194    }
195}
196
197class StopCallInterceptor extends Grpc\Interceptor
198{
199    public function interceptUnaryUnary($method,
200                                        $argument,
201                                        $deserialize,
202                                        $continuation,
203                                        array $metadata = [],
204                                        array $options = [])
205    {
206        $metadata["foo"] = array('interceptor_from_request_response');
207    }
208    public function interceptStreamUnary($method,
209                                         $deserialize,
210                                         $continuation,
211                                         array $metadata = [],
212                                         array $options = [])
213    {
214        $metadata["foo"] = array('interceptor_from_request_response');
215    }
216}
217
218class InterceptorTest extends \PHPUnit\Framework\TestCase
219{
220    private $server;
221    private $port;
222    private $channel;
223
224    public function setUp(): void
225    {
226        $this->server = new Grpc\Server([]);
227        $this->port = $this->server->addHttp2Port('0.0.0.0:0');
228        $this->channel = new Grpc\Channel('localhost:'.$this->port, [
229            'force_new' => true,
230            'credentials' => Grpc\ChannelCredentials::createInsecure()]);
231        $this->server->start();
232    }
233
234    public function tearDown(): void
235    {
236        $this->channel->close();
237        unset($this->server);
238    }
239
240
241    public function testClientChangeMetadataOneInterceptor()
242    {
243        $req_text = 'client_request';
244        $channel_matadata_interceptor = new ChangeMetadataInterceptor();
245        $intercept_channel = Grpc\Interceptor::intercept($this->channel, $channel_matadata_interceptor);
246        $client = new InterceptorClient('localhost:'.$this->port, [
247            'force_new' => true,
248            'credentials' => Grpc\ChannelCredentials::createInsecure(),
249        ], $intercept_channel);
250        $req = new SimpleRequest($req_text);
251        $unary_call = $client->UnaryCall($req);
252        $event = $this->server->requestCall();
253        $this->assertSame('/phony_method', $event->method);
254        $this->assertSame(['interceptor_from_unary_request'], $event->metadata['foo']);
255
256        $stream_call = $client->StreamCall();
257        $stream_call->write($req);
258        $event = $this->server->requestCall();
259        $this->assertSame('/phony_method', $event->method);
260        $this->assertSame(['interceptor_from_stream_request'], $event->metadata['foo']);
261
262        unset($unary_call);
263        unset($stream_call);
264        unset($server_call);
265    }
266
267    public function testClientChangeMetadataTwoInterceptor()
268    {
269        $req_text = 'client_request';
270        $channel_matadata_interceptor = new ChangeMetadataInterceptor();
271        $channel_matadata_intercepto2 = new ChangeMetadataInterceptor2();
272        // test intercept separately.
273        $intercept_channel1 = Grpc\Interceptor::intercept($this->channel, $channel_matadata_interceptor);
274        $intercept_channel2 = Grpc\Interceptor::intercept($intercept_channel1, $channel_matadata_intercepto2);
275        $client = new InterceptorClient('localhost:'.$this->port, [
276            'force_new' => true,
277            'credentials' => Grpc\ChannelCredentials::createInsecure(),
278        ], $intercept_channel2);
279
280        $req = new SimpleRequest($req_text);
281        $unary_call = $client->UnaryCall($req);
282        $event = $this->server->requestCall();
283        $this->assertSame('/phony_method', $event->method);
284        $this->assertSame(['interceptor_from_unary_request'], $event->metadata['foo']);
285        $this->assertSame(['interceptor_from_unary_request'], $event->metadata['bar']);
286
287        $stream_call = $client->StreamCall();
288        $stream_call->write($req);
289        $event = $this->server->requestCall();
290        $this->assertSame('/phony_method', $event->method);
291        $this->assertSame(['interceptor_from_stream_request'], $event->metadata['foo']);
292        $this->assertSame(['interceptor_from_stream_request'], $event->metadata['bar']);
293
294        unset($unary_call);
295        unset($stream_call);
296        unset($server_call);
297
298        // test intercept by array.
299        $intercept_channel3 = Grpc\Interceptor::intercept($this->channel,
300            [$channel_matadata_intercepto2, $channel_matadata_interceptor]);
301        $client = new InterceptorClient('localhost:'.$this->port, [
302            'force_new' => true,
303            'credentials' => Grpc\ChannelCredentials::createInsecure(),
304        ], $intercept_channel3);
305
306        $req = new SimpleRequest($req_text);
307        $unary_call = $client->UnaryCall($req);
308        $event = $this->server->requestCall();
309        $this->assertSame('/phony_method', $event->method);
310        $this->assertSame(['interceptor_from_unary_request'], $event->metadata['foo']);
311        $this->assertSame(['interceptor_from_unary_request'], $event->metadata['bar']);
312
313        $stream_call = $client->StreamCall();
314        $stream_call->write($req);
315        $event = $this->server->requestCall();
316        $this->assertSame('/phony_method', $event->method);
317        $this->assertSame(['interceptor_from_stream_request'], $event->metadata['foo']);
318        $this->assertSame(['interceptor_from_stream_request'], $event->metadata['bar']);
319
320        unset($unary_call);
321        unset($stream_call);
322        unset($server_call);
323    }
324
325    public function testClientChangeRequestInterceptor()
326    {
327        $req_text = 'client_request';
328        $change_request_interceptor = new ChangeRequestInterceptor();
329        $intercept_channel = Grpc\Interceptor::intercept($this->channel,
330            $change_request_interceptor);
331        $client = new InterceptorClient('localhost:'.$this->port, [
332            'force_new' => true,
333            'credentials' => Grpc\ChannelCredentials::createInsecure(),
334        ], $intercept_channel);
335
336        $req = new SimpleRequest($req_text);
337        $unary_call = $client->UnaryCall($req);
338
339        $event = $this->server->requestCall();
340        $this->assertSame('/phony_method', $event->method);
341        $server_call = $event->call;
342        $event = $server_call->startBatch([
343            Grpc\OP_RECV_MESSAGE => true,
344        ]);
345        $this->assertSame('intercepted_unary_request', $event->message);
346        $event = $server_call->startBatch([
347            Grpc\OP_SEND_INITIAL_METADATA => [],
348            Grpc\OP_SEND_STATUS_FROM_SERVER => [
349                'metadata' => [],
350                'code' => Grpc\STATUS_OK,
351                'details' => '',
352            ],
353            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
354        ]);
355
356        $stream_call = $client->StreamCall();
357        $stream_call->write($req);
358        $event = $this->server->requestCall();
359        $this->assertSame('/phony_method', $event->method);
360        $server_call = $event->call;
361        $event = $server_call->startBatch([
362            Grpc\OP_RECV_MESSAGE => true,
363        ]);
364        $this->assertSame('intercepted_stream_request', $event->message);
365        $event = $server_call->startBatch([
366            Grpc\OP_SEND_INITIAL_METADATA => [],
367            Grpc\OP_SEND_STATUS_FROM_SERVER => [
368                'metadata' => [],
369                'code' => Grpc\STATUS_OK,
370                'details' => '',
371            ],
372            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
373        ]);
374
375        unset($unary_call);
376        unset($stream_call);
377        unset($server_call);
378    }
379
380    public function testClientChangeStopCallInterceptor()
381    {
382        $req_text = 'client_request';
383        $channel_request_interceptor = new StopCallInterceptor();
384        $intercept_channel = Grpc\Interceptor::intercept($this->channel,
385            $channel_request_interceptor);
386        $client = new InterceptorClient('localhost:'.$this->port, [
387            'force_new' => true,
388            'credentials' => Grpc\ChannelCredentials::createInsecure(),
389        ], $intercept_channel);
390
391        $req = new SimpleRequest($req_text);
392        $unary_call = $client->UnaryCall($req);
393        $this->assertNull($unary_call);
394
395
396        $stream_call = $client->StreamCall();
397        $this->assertNull($stream_call);
398
399        unset($unary_call);
400        unset($stream_call);
401        unset($server_call);
402    }
403
404    public function testGetInterceptorChannelConnectivityState()
405    {
406        $channel = new Grpc\Channel(
407            'localhost:0',
408            [
409                'force_new' => true,
410                'credentials' => Grpc\ChannelCredentials::createInsecure()
411            ]
412        );
413        $interceptor_channel = Grpc\Interceptor::intercept($channel, new Grpc\Interceptor());
414        $state = $interceptor_channel->getConnectivityState();
415        $this->assertEquals(0, $state);
416        $channel->close();
417    }
418
419    public function testInterceptorChannelWatchConnectivityState()
420    {
421        $channel = new Grpc\Channel(
422            'localhost:0',
423            [
424                'force_new' => true,
425                'credentials' => Grpc\ChannelCredentials::createInsecure()
426            ]
427        );
428        $interceptor_channel = Grpc\Interceptor::intercept($channel, new Grpc\Interceptor());
429        $now = Grpc\Timeval::now();
430        $deadline = $now->add(new Grpc\Timeval(100*1000));
431        $state = $interceptor_channel->watchConnectivityState(1, $deadline);
432        $this->assertTrue($state);
433        unset($time);
434        unset($deadline);
435        $channel->close();
436    }
437
438    public function testInterceptorChannelClose()
439    {
440        $channel = new Grpc\Channel(
441            'localhost:0',
442            [
443                'force_new' => true,
444                'credentials' => Grpc\ChannelCredentials::createInsecure()
445            ]
446        );
447        $interceptor_channel = Grpc\Interceptor::intercept($channel, new Grpc\Interceptor());
448        $this->assertNotNull($interceptor_channel);
449        $channel->close();
450    }
451
452    public function testInterceptorChannelGetTarget()
453    {
454        $channel = new Grpc\Channel(
455            'localhost:8888',
456            [
457                'force_new' => true,
458                'credentials' => Grpc\ChannelCredentials::createInsecure()
459            ]
460        );
461        $interceptor_channel = Grpc\Interceptor::intercept($channel, new Grpc\Interceptor());
462        $target = $interceptor_channel->getTarget();
463        $this->assertTrue(is_string($target));
464        $channel->close();
465    }
466}
467