1<?php
2/*
3 *
4 * Copyright 2015 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 */
19class EndToEndTest extends PHPUnit_Framework_TestCase
20{
21    public function setUp()
22    {
23        $this->server = new Grpc\Server([]);
24        $this->port = $this->server->addHttp2Port('0.0.0.0:0');
25        $this->channel = new Grpc\Channel('localhost:'.$this->port, [
26            "force_new" => true,
27        ]);
28        $this->server->start();
29    }
30
31    public function tearDown()
32    {
33        $this->channel->close();
34        unset($this->server);
35    }
36
37    public function testSimpleRequestBody()
38    {
39        $deadline = Grpc\Timeval::infFuture();
40        $status_text = 'xyz';
41        $call = new Grpc\Call($this->channel,
42                              'dummy_method',
43                              $deadline);
44
45        $event = $call->startBatch([
46            Grpc\OP_SEND_INITIAL_METADATA => [],
47            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
48        ]);
49
50        $this->assertTrue($event->send_metadata);
51        $this->assertTrue($event->send_close);
52
53        $event = $this->server->requestCall();
54        $this->assertSame('dummy_method', $event->method);
55        $server_call = $event->call;
56
57        $event = $server_call->startBatch([
58            Grpc\OP_SEND_INITIAL_METADATA => [],
59            Grpc\OP_SEND_STATUS_FROM_SERVER => [
60                'metadata' => [],
61                'code' => Grpc\STATUS_OK,
62                'details' => $status_text,
63            ],
64            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
65        ]);
66
67        $this->assertTrue($event->send_metadata);
68        $this->assertTrue($event->send_status);
69        $this->assertFalse($event->cancelled);
70
71        $event = $call->startBatch([
72            Grpc\OP_RECV_INITIAL_METADATA => true,
73            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
74        ]);
75
76        $status = $event->status;
77        $this->assertSame([], $status->metadata);
78        $this->assertSame(Grpc\STATUS_OK, $status->code);
79        $this->assertSame($status_text, $status->details);
80
81        unset($call);
82        unset($server_call);
83    }
84
85    public function testMessageWriteFlags()
86    {
87        $deadline = Grpc\Timeval::infFuture();
88        $req_text = 'message_write_flags_test';
89        $status_text = 'xyz';
90        $call = new Grpc\Call($this->channel,
91                              'dummy_method',
92                              $deadline);
93
94        $event = $call->startBatch([
95            Grpc\OP_SEND_INITIAL_METADATA => [],
96            Grpc\OP_SEND_MESSAGE => ['message' => $req_text,
97                                     'flags' => Grpc\WRITE_NO_COMPRESS, ],
98            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
99        ]);
100
101        $this->assertTrue($event->send_metadata);
102        $this->assertTrue($event->send_close);
103
104        $event = $this->server->requestCall();
105        $this->assertSame('dummy_method', $event->method);
106        $server_call = $event->call;
107
108        $event = $server_call->startBatch([
109            Grpc\OP_SEND_INITIAL_METADATA => [],
110            Grpc\OP_SEND_STATUS_FROM_SERVER => [
111                'metadata' => [],
112                'code' => Grpc\STATUS_OK,
113                'details' => $status_text,
114            ],
115        ]);
116
117        $event = $call->startBatch([
118            Grpc\OP_RECV_INITIAL_METADATA => true,
119            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
120        ]);
121
122        $status = $event->status;
123        $this->assertSame([], $status->metadata);
124        $this->assertSame(Grpc\STATUS_OK, $status->code);
125        $this->assertSame($status_text, $status->details);
126
127        unset($call);
128        unset($server_call);
129    }
130
131    public function testClientServerFullRequestResponse()
132    {
133        $deadline = Grpc\Timeval::infFuture();
134        $req_text = 'client_server_full_request_response';
135        $reply_text = 'reply:client_server_full_request_response';
136        $status_text = 'status:client_server_full_response_text';
137
138        $call = new Grpc\Call($this->channel,
139                              'dummy_method',
140                              $deadline);
141
142        $event = $call->startBatch([
143            Grpc\OP_SEND_INITIAL_METADATA => [],
144            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
145            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
146        ]);
147
148        $this->assertTrue($event->send_metadata);
149        $this->assertTrue($event->send_close);
150        $this->assertTrue($event->send_message);
151
152        $event = $this->server->requestCall();
153        $this->assertSame('dummy_method', $event->method);
154        $server_call = $event->call;
155
156        $event = $server_call->startBatch([
157            Grpc\OP_SEND_INITIAL_METADATA => [],
158            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
159            Grpc\OP_SEND_STATUS_FROM_SERVER => [
160                'metadata' => [],
161                'code' => Grpc\STATUS_OK,
162                'details' => $status_text,
163            ],
164            Grpc\OP_RECV_MESSAGE => true,
165            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
166        ]);
167
168        $this->assertTrue($event->send_metadata);
169        $this->assertTrue($event->send_status);
170        $this->assertTrue($event->send_message);
171        $this->assertFalse($event->cancelled);
172        $this->assertSame($req_text, $event->message);
173
174        $event = $call->startBatch([
175            Grpc\OP_RECV_INITIAL_METADATA => true,
176            Grpc\OP_RECV_MESSAGE => true,
177            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
178        ]);
179
180        $this->assertSame([], $event->metadata);
181        $this->assertSame($reply_text, $event->message);
182        $status = $event->status;
183        $this->assertSame([], $status->metadata);
184        $this->assertSame(Grpc\STATUS_OK, $status->code);
185        $this->assertSame($status_text, $status->details);
186
187        unset($call);
188        unset($server_call);
189    }
190
191    /**
192     * @expectedException InvalidArgumentException
193     */
194    public function testInvalidClientMessageArray()
195    {
196        $deadline = Grpc\Timeval::infFuture();
197        $req_text = 'client_server_full_request_response';
198        $reply_text = 'reply:client_server_full_request_response';
199        $status_text = 'status:client_server_full_response_text';
200
201        $call = new Grpc\Call($this->channel,
202                              'dummy_method',
203                              $deadline);
204
205        $event = $call->startBatch([
206            Grpc\OP_SEND_INITIAL_METADATA => [],
207            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
208            Grpc\OP_SEND_MESSAGE => 'invalid',
209        ]);
210    }
211
212    /**
213     * @expectedException InvalidArgumentException
214     */
215    public function testInvalidClientMessageString()
216    {
217        $deadline = Grpc\Timeval::infFuture();
218        $req_text = 'client_server_full_request_response';
219        $reply_text = 'reply:client_server_full_request_response';
220        $status_text = 'status:client_server_full_response_text';
221
222        $call = new Grpc\Call($this->channel,
223                              'dummy_method',
224                              $deadline);
225
226        $event = $call->startBatch([
227            Grpc\OP_SEND_INITIAL_METADATA => [],
228            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
229            Grpc\OP_SEND_MESSAGE => ['message' => 0],
230        ]);
231    }
232
233    /**
234     * @expectedException InvalidArgumentException
235     */
236    public function testInvalidClientMessageFlags()
237    {
238        $deadline = Grpc\Timeval::infFuture();
239        $req_text = 'client_server_full_request_response';
240        $reply_text = 'reply:client_server_full_request_response';
241        $status_text = 'status:client_server_full_response_text';
242
243        $call = new Grpc\Call($this->channel,
244                              'dummy_method',
245                              $deadline);
246
247        $event = $call->startBatch([
248            Grpc\OP_SEND_INITIAL_METADATA => [],
249            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
250            Grpc\OP_SEND_MESSAGE => ['message' => 'abc',
251                                     'flags' => 'invalid',
252                                     ],
253        ]);
254    }
255
256    /**
257     * @expectedException InvalidArgumentException
258     */
259    public function testInvalidServerStatusMetadata()
260    {
261        $deadline = Grpc\Timeval::infFuture();
262        $req_text = 'client_server_full_request_response';
263        $reply_text = 'reply:client_server_full_request_response';
264        $status_text = 'status:client_server_full_response_text';
265
266        $call = new Grpc\Call($this->channel,
267                              'dummy_method',
268                              $deadline);
269
270        $event = $call->startBatch([
271            Grpc\OP_SEND_INITIAL_METADATA => [],
272            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
273            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
274        ]);
275
276        $this->assertTrue($event->send_metadata);
277        $this->assertTrue($event->send_close);
278        $this->assertTrue($event->send_message);
279
280        $event = $this->server->requestCall();
281        $this->assertSame('dummy_method', $event->method);
282        $server_call = $event->call;
283
284        $event = $server_call->startBatch([
285            Grpc\OP_SEND_INITIAL_METADATA => [],
286            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
287            Grpc\OP_SEND_STATUS_FROM_SERVER => [
288                'metadata' => 'invalid',
289                'code' => Grpc\STATUS_OK,
290                'details' => $status_text,
291            ],
292            Grpc\OP_RECV_MESSAGE => true,
293            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
294        ]);
295    }
296
297    /**
298     * @expectedException InvalidArgumentException
299     */
300    public function testInvalidServerStatusCode()
301    {
302        $deadline = Grpc\Timeval::infFuture();
303        $req_text = 'client_server_full_request_response';
304        $reply_text = 'reply:client_server_full_request_response';
305        $status_text = 'status:client_server_full_response_text';
306
307        $call = new Grpc\Call($this->channel,
308                              'dummy_method',
309                              $deadline);
310
311        $event = $call->startBatch([
312            Grpc\OP_SEND_INITIAL_METADATA => [],
313            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
314            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
315        ]);
316
317        $this->assertTrue($event->send_metadata);
318        $this->assertTrue($event->send_close);
319        $this->assertTrue($event->send_message);
320
321        $event = $this->server->requestCall();
322        $this->assertSame('dummy_method', $event->method);
323        $server_call = $event->call;
324
325        $event = $server_call->startBatch([
326            Grpc\OP_SEND_INITIAL_METADATA => [],
327            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
328            Grpc\OP_SEND_STATUS_FROM_SERVER => [
329                'metadata' => [],
330                'code' => 'invalid',
331                'details' => $status_text,
332            ],
333            Grpc\OP_RECV_MESSAGE => true,
334            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
335        ]);
336    }
337
338    /**
339     * @expectedException InvalidArgumentException
340     */
341    public function testMissingServerStatusCode()
342    {
343        $deadline = Grpc\Timeval::infFuture();
344        $req_text = 'client_server_full_request_response';
345        $reply_text = 'reply:client_server_full_request_response';
346        $status_text = 'status:client_server_full_response_text';
347
348        $call = new Grpc\Call($this->channel,
349                              'dummy_method',
350                              $deadline);
351
352        $event = $call->startBatch([
353            Grpc\OP_SEND_INITIAL_METADATA => [],
354            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
355            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
356        ]);
357
358        $this->assertTrue($event->send_metadata);
359        $this->assertTrue($event->send_close);
360        $this->assertTrue($event->send_message);
361
362        $event = $this->server->requestCall();
363        $this->assertSame('dummy_method', $event->method);
364        $server_call = $event->call;
365
366        $event = $server_call->startBatch([
367            Grpc\OP_SEND_INITIAL_METADATA => [],
368            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
369            Grpc\OP_SEND_STATUS_FROM_SERVER => [
370                'metadata' => [],
371                'details' => $status_text,
372            ],
373            Grpc\OP_RECV_MESSAGE => true,
374            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
375        ]);
376    }
377
378    /**
379     * @expectedException InvalidArgumentException
380     */
381    public function testInvalidServerStatusDetails()
382    {
383        $deadline = Grpc\Timeval::infFuture();
384        $req_text = 'client_server_full_request_response';
385        $reply_text = 'reply:client_server_full_request_response';
386        $status_text = 'status:client_server_full_response_text';
387
388        $call = new Grpc\Call($this->channel,
389                              'dummy_method',
390                              $deadline);
391
392        $event = $call->startBatch([
393            Grpc\OP_SEND_INITIAL_METADATA => [],
394            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
395            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
396        ]);
397
398        $this->assertTrue($event->send_metadata);
399        $this->assertTrue($event->send_close);
400        $this->assertTrue($event->send_message);
401
402        $event = $this->server->requestCall();
403        $this->assertSame('dummy_method', $event->method);
404        $server_call = $event->call;
405
406        $event = $server_call->startBatch([
407            Grpc\OP_SEND_INITIAL_METADATA => [],
408            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
409            Grpc\OP_SEND_STATUS_FROM_SERVER => [
410                'metadata' => [],
411                'code' => Grpc\STATUS_OK,
412                'details' => 0,
413            ],
414            Grpc\OP_RECV_MESSAGE => true,
415            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
416        ]);
417    }
418
419    /**
420     * @expectedException InvalidArgumentException
421     */
422    public function testMissingServerStatusDetails()
423    {
424        $deadline = Grpc\Timeval::infFuture();
425        $req_text = 'client_server_full_request_response';
426        $reply_text = 'reply:client_server_full_request_response';
427        $status_text = 'status:client_server_full_response_text';
428
429        $call = new Grpc\Call($this->channel,
430                              'dummy_method',
431                              $deadline);
432
433        $event = $call->startBatch([
434            Grpc\OP_SEND_INITIAL_METADATA => [],
435            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
436            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
437        ]);
438
439        $this->assertTrue($event->send_metadata);
440        $this->assertTrue($event->send_close);
441        $this->assertTrue($event->send_message);
442
443        $event = $this->server->requestCall();
444        $this->assertSame('dummy_method', $event->method);
445        $server_call = $event->call;
446
447        $event = $server_call->startBatch([
448            Grpc\OP_SEND_INITIAL_METADATA => [],
449            Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
450            Grpc\OP_SEND_STATUS_FROM_SERVER => [
451                'metadata' => [],
452                'code' => Grpc\STATUS_OK,
453            ],
454            Grpc\OP_RECV_MESSAGE => true,
455            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
456        ]);
457    }
458
459    /**
460     * @expectedException InvalidArgumentException
461     */
462    public function testInvalidStartBatchKey()
463    {
464        $deadline = Grpc\Timeval::infFuture();
465        $req_text = 'client_server_full_request_response';
466        $reply_text = 'reply:client_server_full_request_response';
467        $status_text = 'status:client_server_full_response_text';
468
469        $call = new Grpc\Call($this->channel,
470                              'dummy_method',
471                              $deadline);
472
473        $event = $call->startBatch([
474            9999999 => [],
475        ]);
476    }
477
478    /**
479     * @expectedException LogicException
480     */
481    public function testInvalidStartBatch()
482    {
483        $deadline = Grpc\Timeval::infFuture();
484        $req_text = 'client_server_full_request_response';
485        $reply_text = 'reply:client_server_full_request_response';
486        $status_text = 'status:client_server_full_response_text';
487
488        $call = new Grpc\Call($this->channel,
489                              'dummy_method',
490                              $deadline);
491
492        $event = $call->startBatch([
493            Grpc\OP_SEND_INITIAL_METADATA => [],
494            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
495            Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
496            Grpc\OP_SEND_STATUS_FROM_SERVER => [
497                'metadata' => [],
498                'code' => Grpc\STATUS_OK,
499                'details' => 'abc',
500            ],
501        ]);
502    }
503
504    public function testGetTarget()
505    {
506        $this->assertTrue(is_string($this->channel->getTarget()));
507    }
508
509    public function testGetConnectivityState()
510    {
511        $this->assertTrue($this->channel->getConnectivityState() ==
512                          Grpc\CHANNEL_IDLE);
513    }
514
515    public function testWatchConnectivityStateFailed()
516    {
517        $idle_state = $this->channel->getConnectivityState();
518        $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
519
520        $now = Grpc\Timeval::now();
521        $delta = new Grpc\Timeval(50000); // should timeout
522        $deadline = $now->add($delta);
523
524        $this->assertFalse($this->channel->watchConnectivityState(
525        $idle_state, $deadline));
526    }
527
528    public function testWatchConnectivityStateSuccess()
529    {
530        $idle_state = $this->channel->getConnectivityState(true);
531        $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
532
533        $now = Grpc\Timeval::now();
534        $delta = new Grpc\Timeval(3000000); // should finish well before
535        $deadline = $now->add($delta);
536
537        $this->assertTrue($this->channel->watchConnectivityState(
538        $idle_state, $deadline));
539
540        $new_state = $this->channel->getConnectivityState();
541        $this->assertTrue($idle_state != $new_state);
542    }
543
544    public function testWatchConnectivityStateDoNothing()
545    {
546        $idle_state = $this->channel->getConnectivityState();
547        $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
548
549        $now = Grpc\Timeval::now();
550        $delta = new Grpc\Timeval(50000);
551        $deadline = $now->add($delta);
552
553        $this->assertFalse($this->channel->watchConnectivityState(
554        $idle_state, $deadline));
555
556        $new_state = $this->channel->getConnectivityState();
557        $this->assertTrue($new_state == Grpc\CHANNEL_IDLE);
558    }
559
560    /**
561     * @expectedException InvalidArgumentException
562     */
563    public function testGetConnectivityStateInvalidParam()
564    {
565        $this->assertTrue($this->channel->getConnectivityState(
566            new Grpc\Timeval()));
567    }
568
569    /**
570     * @expectedException InvalidArgumentException
571     */
572    public function testWatchConnectivityStateInvalidParam()
573    {
574        $this->assertTrue($this->channel->watchConnectivityState(
575            0, 1000));
576    }
577
578    /**
579     * @expectedException InvalidArgumentException
580     */
581    public function testChannelConstructorInvalidParam()
582    {
583        $this->channel = new Grpc\Channel('localhost:'.$this->port, null);
584    }
585
586    public function testClose()
587    {
588        $this->assertNull($this->channel->close());
589    }
590}
591