Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace React\Tests\EventLoop;
4
 
5
abstract class AbstractLoopTest extends TestCase
6
{
7
    /**
8
     * @var \React\EventLoop\LoopInterface
9
     */
10
    protected $loop;
11
 
12
    public function setUp()
13
    {
14
        $this->loop = $this->createLoop();
15
    }
16
 
17
    abstract public function createLoop();
18
 
19
    public function createStream()
20
    {
21
        return fopen('php://temp', 'r+');
22
    }
23
 
24
    public function writeToStream($stream, $content)
25
    {
26
        fwrite($stream, $content);
27
        rewind($stream);
28
    }
29
 
30
    public function testAddReadStream()
31
    {
32
        $input = $this->createStream();
33
 
34
        $this->loop->addReadStream($input, $this->expectCallableExactly(2));
35
 
36
        $this->writeToStream($input, "foo\n");
37
        $this->loop->tick();
38
 
39
        $this->writeToStream($input, "bar\n");
40
        $this->loop->tick();
41
    }
42
 
43
    public function testAddWriteStream()
44
    {
45
        $input = $this->createStream();
46
 
47
        $this->loop->addWriteStream($input, $this->expectCallableExactly(2));
48
        $this->loop->tick();
49
        $this->loop->tick();
50
    }
51
 
52
    public function testRemoveReadStreamInstantly()
53
    {
54
        $input = $this->createStream();
55
 
56
        $this->loop->addReadStream($input, $this->expectCallableNever());
57
        $this->loop->removeReadStream($input);
58
 
59
        $this->writeToStream($input, "bar\n");
60
        $this->loop->tick();
61
    }
62
 
63
    public function testRemoveReadStreamAfterReading()
64
    {
65
        $input = $this->createStream();
66
 
67
        $this->loop->addReadStream($input, $this->expectCallableOnce());
68
 
69
        $this->writeToStream($input, "foo\n");
70
        $this->loop->tick();
71
 
72
        $this->loop->removeReadStream($input);
73
 
74
        $this->writeToStream($input, "bar\n");
75
        $this->loop->tick();
76
    }
77
 
78
    public function testRemoveWriteStreamInstantly()
79
    {
80
        $input = $this->createStream();
81
 
82
        $this->loop->addWriteStream($input, $this->expectCallableNever());
83
        $this->loop->removeWriteStream($input);
84
        $this->loop->tick();
85
    }
86
 
87
    public function testRemoveWriteStreamAfterWriting()
88
    {
89
        $input = $this->createStream();
90
 
91
        $this->loop->addWriteStream($input, $this->expectCallableOnce());
92
        $this->loop->tick();
93
 
94
        $this->loop->removeWriteStream($input);
95
        $this->loop->tick();
96
    }
97
 
98
    public function testRemoveStreamInstantly()
99
    {
100
        $input = $this->createStream();
101
 
102
        $this->loop->addReadStream($input, $this->expectCallableNever());
103
        $this->loop->addWriteStream($input, $this->expectCallableNever());
104
        $this->loop->removeStream($input);
105
 
106
        $this->writeToStream($input, "bar\n");
107
        $this->loop->tick();
108
    }
109
 
110
    public function testRemoveStreamForReadOnly()
111
    {
112
        $input = $this->createStream();
113
 
114
        $this->loop->addReadStream($input, $this->expectCallableNever());
115
        $this->loop->addWriteStream($input, $this->expectCallableOnce());
116
        $this->loop->removeReadStream($input);
117
 
118
        $this->writeToStream($input, "foo\n");
119
        $this->loop->tick();
120
    }
121
 
122
    public function testRemoveStreamForWriteOnly()
123
    {
124
        $input = $this->createStream();
125
 
126
        $this->writeToStream($input, "foo\n");
127
 
128
        $this->loop->addReadStream($input, $this->expectCallableOnce());
129
        $this->loop->addWriteStream($input, $this->expectCallableNever());
130
        $this->loop->removeWriteStream($input);
131
 
132
        $this->loop->tick();
133
    }
134
 
135
    public function testRemoveStream()
136
    {
137
        $input = $this->createStream();
138
 
139
        $this->loop->addReadStream($input, $this->expectCallableOnce());
140
        $this->loop->addWriteStream($input, $this->expectCallableOnce());
141
 
142
        $this->writeToStream($input, "bar\n");
143
        $this->loop->tick();
144
 
145
        $this->loop->removeStream($input);
146
 
147
        $this->writeToStream($input, "bar\n");
148
        $this->loop->tick();
149
    }
150
 
151
    public function testRemoveInvalid()
152
    {
153
        $stream = $this->createStream();
154
 
155
        // remove a valid stream from the event loop that was never added in the first place
156
        $this->loop->removeReadStream($stream);
157
        $this->loop->removeWriteStream($stream);
158
        $this->loop->removeStream($stream);
159
    }
160
 
161
    /** @test */
162
    public function emptyRunShouldSimplyReturn()
163
    {
164
        $this->assertRunFasterThan(0.005);
165
    }
166
 
167
    /** @test */
168
    public function runShouldReturnWhenNoMoreFds()
169
    {
170
        $input = $this->createStream();
171
 
172
        $loop = $this->loop;
173
        $this->loop->addReadStream($input, function ($stream) use ($loop) {
174
            $loop->removeStream($stream);
175
        });
176
 
177
        $this->writeToStream($input, "foo\n");
178
 
179
        $this->assertRunFasterThan(0.015);
180
    }
181
 
182
    /** @test */
183
    public function stopShouldStopRunningLoop()
184
    {
185
        $input = $this->createStream();
186
 
187
        $loop = $this->loop;
188
        $this->loop->addReadStream($input, function ($stream) use ($loop) {
189
            $loop->stop();
190
        });
191
 
192
        $this->writeToStream($input, "foo\n");
193
 
194
        $this->assertRunFasterThan(0.005);
195
    }
196
 
197
    public function testStopShouldPreventRunFromBlocking($timeLimit = 0.005)
198
    {
199
        $this->loop->addTimer(
200
            1,
201
            function () {
202
                $this->fail('Timer was executed.');
203
            }
204
        );
205
 
206
        $this->loop->nextTick(
207
            function () {
208
                $this->loop->stop();
209
            }
210
        );
211
 
212
        $this->assertRunFasterThan($timeLimit);
213
    }
214
 
215
    public function testIgnoreRemovedCallback()
216
    {
217
        // two independent streams, both should be readable right away
218
        $stream1 = $this->createStream();
219
        $stream2 = $this->createStream();
220
 
221
        $loop = $this->loop;
222
        $loop->addReadStream($stream1, function ($stream) use ($loop, $stream2) {
223
            // stream1 is readable, remove stream2 as well => this will invalidate its callback
224
            $loop->removeReadStream($stream);
225
            $loop->removeReadStream($stream2);
226
        });
227
 
228
        // this callback would have to be called as well, but the first stream already removed us
229
        $loop->addReadStream($stream2, $this->expectCallableNever());
230
 
231
        $this->writeToStream($stream1, "foo\n");
232
        $this->writeToStream($stream2, "foo\n");
233
 
234
        $loop->run();
235
    }
236
 
237
    public function testNextTick()
238
    {
239
        $called = false;
240
 
241
        $callback = function ($loop) use (&$called) {
242
            $this->assertSame($this->loop, $loop);
243
            $called = true;
244
        };
245
 
246
        $this->loop->nextTick($callback);
247
 
248
        $this->assertFalse($called);
249
 
250
        $this->loop->tick();
251
 
252
        $this->assertTrue($called);
253
    }
254
 
255
    public function testNextTickFiresBeforeIO()
256
    {
257
        $stream = $this->createStream();
258
 
259
        $this->loop->addWriteStream(
260
            $stream,
261
            function () {
262
                echo 'stream' . PHP_EOL;
263
            }
264
        );
265
 
266
        $this->loop->nextTick(
267
            function () {
268
                echo 'next-tick' . PHP_EOL;
269
            }
270
        );
271
 
272
        $this->expectOutputString('next-tick' . PHP_EOL . 'stream' . PHP_EOL);
273
 
274
        $this->loop->tick();
275
    }
276
 
277
    public function testRecursiveNextTick()
278
    {
279
        $stream = $this->createStream();
280
 
281
        $this->loop->addWriteStream(
282
            $stream,
283
            function () {
284
                echo 'stream' . PHP_EOL;
285
            }
286
        );
287
 
288
        $this->loop->nextTick(
289
            function () {
290
                $this->loop->nextTick(
291
                    function () {
292
                        echo 'next-tick' . PHP_EOL;
293
                    }
294
                );
295
            }
296
        );
297
 
298
        $this->expectOutputString('next-tick' . PHP_EOL . 'stream' . PHP_EOL);
299
 
300
        $this->loop->tick();
301
    }
302
 
303
    public function testRunWaitsForNextTickEvents()
304
    {
305
        $stream = $this->createStream();
306
 
307
        $this->loop->addWriteStream(
308
            $stream,
309
            function () use ($stream) {
310
                $this->loop->removeStream($stream);
311
                $this->loop->nextTick(
312
                    function () {
313
                        echo 'next-tick' . PHP_EOL;
314
                    }
315
                );
316
            }
317
        );
318
 
319
        $this->expectOutputString('next-tick' . PHP_EOL);
320
 
321
        $this->loop->run();
322
    }
323
 
324
    public function testNextTickEventGeneratedByFutureTick()
325
    {
326
        $stream = $this->createStream();
327
 
328
        $this->loop->futureTick(
329
            function () {
330
                $this->loop->nextTick(
331
                    function () {
332
                        echo 'next-tick' . PHP_EOL;
333
                    }
334
                );
335
            }
336
        );
337
 
338
        $this->expectOutputString('next-tick' . PHP_EOL);
339
 
340
        $this->loop->run();
341
    }
342
 
343
    public function testNextTickEventGeneratedByTimer()
344
    {
345
        $this->loop->addTimer(
346
            0.001,
347
            function () {
348
                $this->loop->nextTick(
349
                    function () {
350
                        echo 'next-tick' . PHP_EOL;
351
                    }
352
                );
353
            }
354
        );
355
 
356
        $this->expectOutputString('next-tick' . PHP_EOL);
357
 
358
        $this->loop->run();
359
    }
360
 
361
    public function testFutureTick()
362
    {
363
        $called = false;
364
 
365
        $callback = function ($loop) use (&$called) {
366
            $this->assertSame($this->loop, $loop);
367
            $called = true;
368
        };
369
 
370
        $this->loop->futureTick($callback);
371
 
372
        $this->assertFalse($called);
373
 
374
        $this->loop->tick();
375
 
376
        $this->assertTrue($called);
377
    }
378
 
379
    public function testFutureTickFiresBeforeIO()
380
    {
381
        $stream = $this->createStream();
382
 
383
        $this->loop->addWriteStream(
384
            $stream,
385
            function () {
386
                echo 'stream' . PHP_EOL;
387
            }
388
        );
389
 
390
        $this->loop->futureTick(
391
            function () {
392
                echo 'future-tick' . PHP_EOL;
393
            }
394
        );
395
 
396
        $this->expectOutputString('future-tick' . PHP_EOL . 'stream' . PHP_EOL);
397
 
398
        $this->loop->tick();
399
    }
400
 
401
    public function testRecursiveFutureTick()
402
    {
403
        $stream = $this->createStream();
404
 
405
        $this->loop->addWriteStream(
406
            $stream,
407
            function () use ($stream) {
408
                echo 'stream' . PHP_EOL;
409
                $this->loop->removeWriteStream($stream);
410
            }
411
        );
412
 
413
        $this->loop->futureTick(
414
            function () {
415
                echo 'future-tick-1' . PHP_EOL;
416
                $this->loop->futureTick(
417
                    function () {
418
                        echo 'future-tick-2' . PHP_EOL;
419
                    }
420
                );
421
            }
422
        );
423
 
424
        $this->expectOutputString('future-tick-1' . PHP_EOL . 'stream' . PHP_EOL . 'future-tick-2' . PHP_EOL);
425
 
426
        $this->loop->run();
427
    }
428
 
429
    public function testRunWaitsForFutureTickEvents()
430
    {
431
        $stream = $this->createStream();
432
 
433
        $this->loop->addWriteStream(
434
            $stream,
435
            function () use ($stream) {
436
                $this->loop->removeStream($stream);
437
                $this->loop->futureTick(
438
                    function () {
439
                        echo 'future-tick' . PHP_EOL;
440
                    }
441
                );
442
            }
443
        );
444
 
445
        $this->expectOutputString('future-tick' . PHP_EOL);
446
 
447
        $this->loop->run();
448
    }
449
 
450
    public function testFutureTickEventGeneratedByNextTick()
451
    {
452
        $stream = $this->createStream();
453
 
454
        $this->loop->nextTick(
455
            function () {
456
                $this->loop->futureTick(
457
                    function () {
458
                        echo 'future-tick' . PHP_EOL;
459
                    }
460
                );
461
            }
462
        );
463
 
464
        $this->expectOutputString('future-tick' . PHP_EOL);
465
 
466
        $this->loop->run();
467
    }
468
 
469
    public function testFutureTickEventGeneratedByTimer()
470
    {
471
        $this->loop->addTimer(
472
            0.001,
473
            function () {
474
                $this->loop->futureTick(
475
                    function () {
476
                        echo 'future-tick' . PHP_EOL;
477
                    }
478
                );
479
            }
480
        );
481
 
482
        $this->expectOutputString('future-tick' . PHP_EOL);
483
 
484
        $this->loop->run();
485
    }
486
 
487
    private function assertRunFasterThan($maxInterval)
488
    {
489
        $start = microtime(true);
490
 
491
        $this->loop->run();
492
 
493
        $end = microtime(true);
494
        $interval = $end - $start;
495
 
496
        $this->assertLessThan($maxInterval, $interval);
497
    }
498
}