ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
SignalHandlerTest.php
Go to the documentation of this file.
1<?php
2
3/*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Monolog;
13
17
23{
24
28
29 protected function setUp()
30 {
31 $this->signalHandlers = array();
32 if (extension_loaded('pcntl')) {
33 if (function_exists('pcntl_async_signals')) {
34 $this->asyncSignalHandling = pcntl_async_signals();
35 }
36 if (function_exists('pcntl_sigprocmask')) {
37 pcntl_sigprocmask(SIG_BLOCK, array(), $this->blockedSignals);
38 }
39 }
40 }
41
42 protected function tearDown()
43 {
44 if ($this->asyncSignalHandling !== null) {
45 pcntl_async_signals($this->asyncSignalHandling);
46 }
47 if ($this->blockedSignals !== null) {
48 pcntl_sigprocmask(SIG_SETMASK, $this->blockedSignals);
49 }
50 if ($this->signalHandlers) {
51 pcntl_signal_dispatch();
52 foreach ($this->signalHandlers as $signo => $handler) {
53 pcntl_signal($signo, $handler);
54 }
55 }
56 }
57
58 private function setSignalHandler($signo, $handler = SIG_DFL) {
59 if (function_exists('pcntl_signal_get_handler')) {
60 $this->signalHandlers[$signo] = pcntl_signal_get_handler($signo);
61 } else {
62 $this->signalHandlers[$signo] = SIG_DFL;
63 }
64 $this->assertTrue(pcntl_signal($signo, $handler));
65 }
66
67 public function testHandleSignal()
68 {
69 $logger = new Logger('test', array($handler = new TestHandler));
70 $errHandler = new SignalHandler($logger);
71 $signo = 2; // SIGINT.
72 $siginfo = array('signo' => $signo, 'errno' => 0, 'code' => 0);
73 $errHandler->handleSignal($signo, $siginfo);
74 $this->assertCount(1, $handler->getRecords());
75 $this->assertTrue($handler->hasCriticalRecords());
76 $records = $handler->getRecords();
77 $this->assertSame($siginfo, $records[0]['context']);
78 }
79
89 public function testRegisterSignalHandler()
90 {
91 // SIGCONT and SIGURG should be ignored by default.
92 if (!defined('SIGCONT') || !defined('SIGURG')) {
93 $this->markTestSkipped('This test requires the SIGCONT and SIGURG pcntl constants.');
94 }
95
96 $this->setSignalHandler(SIGCONT, SIG_IGN);
97 $this->setSignalHandler(SIGURG, SIG_IGN);
98
99 $logger = new Logger('test', array($handler = new TestHandler));
100 $errHandler = new SignalHandler($logger);
101 $pid = posix_getpid();
102
103 $this->assertTrue(posix_kill($pid, SIGURG));
104 $this->assertTrue(pcntl_signal_dispatch());
105 $this->assertCount(0, $handler->getRecords());
106
107 $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, false);
108
109 $this->assertTrue(posix_kill($pid, SIGCONT));
110 $this->assertTrue(pcntl_signal_dispatch());
111 $this->assertCount(0, $handler->getRecords());
112
113 $this->assertTrue(posix_kill($pid, SIGURG));
114 $this->assertTrue(pcntl_signal_dispatch());
115 $this->assertCount(1, $handler->getRecords());
116 $this->assertTrue($handler->hasInfoThatContains('SIGURG'));
117 }
118
126 public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected)
127 {
128 $this->setSignalHandler($signo, SIG_DFL);
129
130 $path = tempnam(sys_get_temp_dir(), 'monolog-');
131 $this->assertNotFalse($path);
132
133 $pid = pcntl_fork();
134 if ($pid === 0) { // Child.
135 $streamHandler = new StreamHandler($path);
136 $streamHandler->setFormatter($this->getIdentityFormatter());
137 $logger = new Logger('test', array($streamHandler));
138 $errHandler = new SignalHandler($logger);
139 $errHandler->registerSignalHandler($signo, LogLevel::INFO, $callPrevious, false, false);
140 pcntl_sigprocmask(SIG_SETMASK, array(SIGCONT));
141 posix_kill(posix_getpid(), $signo);
142 pcntl_signal_dispatch();
143 // If $callPrevious is true, SIGINT should terminate by this line.
144 pcntl_sigprocmask(SIG_BLOCK, array(), $oldset);
145 file_put_contents($path, implode(' ', $oldset), FILE_APPEND);
146 posix_kill(posix_getpid(), $signo);
147 pcntl_signal_dispatch();
148 exit();
149 }
150
151 $this->assertNotSame(-1, $pid);
152 $this->assertNotSame(-1, pcntl_waitpid($pid, $status));
153 $this->assertNotSame(-1, $status);
154 $this->assertSame($expected, file_get_contents($path));
155 }
156
157 public function defaultPreviousProvider()
158 {
159 if (!defined('SIGCONT') || !defined('SIGINT') || !defined('SIGURG')) {
160 return array();
161 }
162
163 return array(
164 array(SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'),
165 array(SIGINT, true, 'Program received signal SIGINT'),
166 array(SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'),
167 array(SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'),
168 );
169 }
170
176 public function testRegisterCallablePreviousSignalHandler($callPrevious)
177 {
178 $this->setSignalHandler(SIGURG, SIG_IGN);
179
180 $logger = new Logger('test', array($handler = new TestHandler));
181 $errHandler = new SignalHandler($logger);
182 $previousCalled = 0;
183 pcntl_signal(SIGURG, function ($signo, array $siginfo = null) use (&$previousCalled) {
184 ++$previousCalled;
185 });
186 $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, $callPrevious, false, false);
187 $this->assertTrue(posix_kill(posix_getpid(), SIGURG));
188 $this->assertTrue(pcntl_signal_dispatch());
189 $this->assertCount(1, $handler->getRecords());
190 $this->assertTrue($handler->hasInfoThatContains('SIGURG'));
191 $this->assertSame($callPrevious ? 1 : 0, $previousCalled);
192 }
193
194 public function callablePreviousProvider()
195 {
196 return array(
197 array(false),
198 array(true),
199 );
200 }
201
208 public function testRegisterSyscallRestartingSignalHandler($restartSyscalls)
209 {
210 $this->setSignalHandler(SIGURG, SIG_IGN);
211
212 $parentPid = posix_getpid();
213 $microtime = microtime(true);
214
215 $pid = pcntl_fork();
216 if ($pid === 0) { // Child.
217 usleep(100000);
218 posix_kill($parentPid, SIGURG);
219 usleep(100000);
220 exit();
221 }
222
223 $this->assertNotSame(-1, $pid);
224 $logger = new Logger('test', array($handler = new TestHandler));
225 $errHandler = new SignalHandler($logger);
226 $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false);
227 if ($restartSyscalls) {
228 // pcntl_wait is expected to be restarted after the signal handler.
229 $this->assertNotSame(-1, pcntl_waitpid($pid, $status));
230 } else {
231 // pcntl_wait is expected to be interrupted when the signal handler is invoked.
232 $this->assertSame(-1, pcntl_waitpid($pid, $status));
233 }
234 $this->assertSame($restartSyscalls, microtime(true) - $microtime > 0.15);
235 $this->assertTrue(pcntl_signal_dispatch());
236 $this->assertCount(1, $handler->getRecords());
237 if ($restartSyscalls) {
238 // The child has already exited.
239 $this->assertSame(-1, pcntl_waitpid($pid, $status));
240 } else {
241 // The child has not exited yet.
242 $this->assertNotSame(-1, pcntl_waitpid($pid, $status));
243 }
244 }
245
246 public function restartSyscallsProvider()
247 {
248 return array(
249 array(false),
250 array(true),
251 array(false),
252 array(true),
253 );
254 }
255
261 public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $expectedBefore, $expectedAfter)
262 {
263 $this->setSignalHandler(SIGURG, SIG_IGN);
264 pcntl_async_signals($initialAsync);
265
266 $logger = new Logger('test', array($handler = new TestHandler));
267 $errHandler = new SignalHandler($logger);
268 $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, $desiredAsync);
269 $this->assertTrue(posix_kill(posix_getpid(), SIGURG));
270 $this->assertCount($expectedBefore, $handler->getRecords());
271 $this->assertTrue(pcntl_signal_dispatch());
272 $this->assertCount($expectedAfter, $handler->getRecords());
273 }
274
275 public function asyncProvider()
276 {
277 return array(
278 array(false, false, 0, 1),
279 array(false, null, 0, 1),
280 array(false, true, 1, 1),
281 array(true, false, 0, 1),
282 array(true, null, 1, 1),
283 array(true, true, 1, 1),
284 );
285 }
286
287}
$path
Definition: aliased.php:25
exit
Definition: backend.php:16
An exception for terminatinating execution or to throw for unit testing.
Stores to any stream resource.
Used for testing purposes.
Definition: TestHandler.php:67
Monolog log channel.
Definition: Logger.php:29
testRegisterSyscallRestartingSignalHandler($restartSyscalls)
@dataProvider restartSyscallsProvider @depends testRegisterDefaultPreviousSignalHandler @requires fun...
testRegisterCallablePreviousSignalHandler($callPrevious)
@dataProvider callablePreviousProvider @depends testRegisterSignalHandler @requires function pcntl_si...
testRegisterSignalHandler()
@depends testHandleSignal @requires extension pcntl @requires extension posix @requires function pcnt...
testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected)
@dataProvider defaultPreviousProvider @depends testRegisterSignalHandler @requires function pcntl_for...
setSignalHandler($signo, $handler=SIG_DFL)
testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $expectedBefore, $expectedAfter)
@dataProvider asyncProvider @depends testRegisterDefaultPreviousSignalHandler @requires function pcnt...
Monolog POSIX signal handler.
Describes log levels.
Definition: LogLevel.php:9
$handler
$records
Definition: simple_test.php:22