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
use React\EventLoop\LoopInterface;
6
use React\EventLoop\StreamSelectLoop;
7
 
8
class StreamSelectLoopTest extends AbstractLoopTest
9
{
10
    protected function tearDown()
11
    {
12
        parent::tearDown();
13
        if (strncmp($this->getName(false), 'testSignal', 10) === 0 && extension_loaded('pcntl')) {
14
            $this->resetSignalHandlers();
15
        }
16
    }
17
 
18
    public function createLoop()
19
    {
20
        return new StreamSelectLoop();
21
    }
22
 
23
    public function testStreamSelectTimeoutEmulation()
24
    {
25
        $this->loop->addTimer(
26
            0.05,
27
            $this->expectCallableOnce()
28
        );
29
 
30
        $start = microtime(true);
31
 
32
        $this->loop->run();
33
 
34
        $end = microtime(true);
35
        $interval = $end - $start;
36
 
37
        $this->assertGreaterThan(0.04, $interval);
38
    }
39
 
40
    public function testStopShouldPreventRunFromBlocking($timeLimit = 0.005)
41
    {
42
        if (defined('HHVM_VERSION')) {
43
            // HHVM is a bit slow, so give it more time
44
            parent::testStopShouldPreventRunFromBlocking(0.5);
45
        } else {
46
            parent::testStopShouldPreventRunFromBlocking($timeLimit);
47
        }
48
    }
49
 
50
 
51
    public function signalProvider()
52
    {
53
        return [
54
            ['SIGUSR1', SIGUSR1],
55
            ['SIGHUP', SIGHUP],
56
            ['SIGTERM', SIGTERM],
57
        ];
58
    }
59
 
60
    private $_signalHandled = false;
61
 
62
    /**
63
     * Test signal interrupt when no stream is attached to the loop
64
     * @dataProvider signalProvider
65
     */
66
    public function testSignalInterruptNoStream($sigName, $signal)
67
    {
68
        if (!extension_loaded('pcntl')) {
69
            $this->markTestSkipped('"pcntl" extension is required to run this test.');
70
        }
71
 
72
        // dispatch signal handler once before signal is sent and once after
73
        $this->loop->addTimer(0.01, function() { pcntl_signal_dispatch(); });
74
        $this->loop->addTimer(0.03, function() { pcntl_signal_dispatch(); });
75
        if (defined('HHVM_VERSION')) {
76
            // hhvm startup is slow so we need to add another handler much later
77
            $this->loop->addTimer(0.5, function() { pcntl_signal_dispatch(); });
78
        }
79
 
80
        $this->setUpSignalHandler($signal);
81
 
82
        // spawn external process to send signal to current process id
83
        $this->forkSendSignal($signal);
84
        $this->loop->run();
85
        $this->assertTrue($this->_signalHandled);
86
    }
87
 
88
    /**
89
     * Test signal interrupt when a stream is attached to the loop
90
     * @dataProvider signalProvider
91
     */
92
    public function testSignalInterruptWithStream($sigName, $signal)
93
    {
94
        if (!extension_loaded('pcntl')) {
95
            $this->markTestSkipped('"pcntl" extension is required to run this test.');
96
        }
97
 
98
        // dispatch signal handler every 10ms
99
        $this->loop->addPeriodicTimer(0.01, function() { pcntl_signal_dispatch(); });
100
 
101
        // add stream to the loop
102
        list($writeStream, $readStream) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
103
        $this->loop->addReadStream($readStream, function($stream, $loop) {
104
            /** @var $loop LoopInterface */
105
            $read = fgets($stream);
106
            if ($read === "end loop\n") {
107
                $loop->stop();
108
            }
109
        });
110
        $this->loop->addTimer(0.05, function() use ($writeStream) {
111
            fwrite($writeStream, "end loop\n");
112
        });
113
 
114
        $this->setUpSignalHandler($signal);
115
 
116
        // spawn external process to send signal to current process id
117
        $this->forkSendSignal($signal);
118
 
119
        $this->loop->run();
120
 
121
        $this->assertTrue($this->_signalHandled);
122
    }
123
 
124
    /**
125
     * add signal handler for signal
126
     */
127
    protected function setUpSignalHandler($signal)
128
    {
129
        $this->_signalHandled = false;
130
        $this->assertTrue(pcntl_signal($signal, function() { $this->_signalHandled = true; }));
131
    }
132
 
133
    /**
134
     * reset all signal handlers to default
135
     */
136
    protected function resetSignalHandlers()
137
    {
138
        foreach($this->signalProvider() as $signal) {
139
            pcntl_signal($signal[1], SIG_DFL);
140
        }
141
    }
142
 
143
    /**
144
     * fork child process to send signal to current process id
145
     */
146
    protected function forkSendSignal($signal)
147
    {
148
        $currentPid = posix_getpid();
149
        $childPid = pcntl_fork();
150
        if ($childPid == -1) {
151
            $this->fail("Failed to fork child process!");
152
        } else if ($childPid === 0) {
153
            // this is executed in the child process
154
            usleep(20000);
155
            posix_kill($currentPid, $signal);
156
            die();
157
        }
158
    }
159
}