123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- <?php
- namespace Seld\Signal;
- use PHPUnit\Framework\TestCase;
- use Psr\Log\LoggerInterface;
- class SignalHandlerTest extends TestCase
- {
- /**
- * @requires extension pcntl
- * @requires extension posix
- */
- public function testLoggingAndDefault(): void
- {
- $log = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal = SignalHandler::create(null, $log);
- $log->expects(self::exactly(2))
- ->method('info')
- ->withConsecutive(
- ['Received SIGINT', []],
- ['Received SIGTERM', []]
- );
- posix_kill(posix_getpid(), SIGINT);
- posix_kill(posix_getpid(), SIGTERM);
- posix_kill(posix_getpid(), SIGURG);
- }
- /**
- * @requires extension pcntl
- * @requires extension posix
- * @requires PHP < 8.0
- */
- public function testNoAutoGCOnPHP7(): void
- {
- $log = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal = SignalHandler::create(null, $log);
- $log->expects(self::exactly(2))
- ->method('info')
- ->withConsecutive(
- ['Received SIGINT', []],
- ['Received SIGINT', []]
- );
- posix_kill(posix_getpid(), SIGINT);
- unset($signal);
- posix_kill(posix_getpid(), SIGINT);
- SignalHandler::unregisterAll();
- self::assertSame(SIG_DFL, pcntl_signal_get_handler(SIGINT));
- }
- /**
- * @requires extension pcntl
- * @requires extension posix
- * @requires PHP >= 8.0
- */
- public function testAutoGCOnPHP8(): void
- {
- $log1 = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal1 = SignalHandler::create(null, $log1);
- $log1->expects(self::exactly(1))
- ->method('info')
- ->withConsecutive(
- ['Received SIGINT', []]
- );
- $log2 = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal2 = SignalHandler::create(null, $log2);
- $log2->expects(self::exactly(1))
- ->method('info')
- ->withConsecutive(
- ['Received SIGINT', []]
- );
- posix_kill(posix_getpid(), SIGINT);
- unset($signal2);
- posix_kill(posix_getpid(), SIGINT);
- unset($signal1);
- self::assertSame(SIG_DFL, pcntl_signal_get_handler(SIGINT));
- }
- /**
- * @requires extension pcntl
- * @requires extension posix
- */
- public function testCallbackAndCustom(): void
- {
- pcntl_signal(SIGINT, function () {
- // ignore
- });
- $sigName = null;
- $signal = SignalHandler::create([SignalHandler::SIGHUP], function ($name) use (&$sigName) {
- $sigName = $name;
- });
- posix_kill(posix_getpid(), SIGINT);
- self::assertNull($sigName);
- posix_kill(posix_getpid(), SIGHUP);
- self::assertSame('SIGHUP', $sigName);
- $signal->unregister();
- }
- /**
- * @requires extension pcntl
- * @requires extension posix
- */
- public function testTriggerResetCycle(): void
- {
- $signal = SignalHandler::create([SignalHandler::SIGUSR1, SignalHandler::SIGUSR2]);
- self::assertFalse($signal->isTriggered());
- posix_kill(posix_getpid(), SIGUSR1);
- self::assertTrue($signal->isTriggered());
- $signal->reset();
- self::assertFalse($signal->isTriggered());
- posix_kill(posix_getpid(), SIGUSR2);
- self::assertTrue($signal->isTriggered());
- $signal->unregister();
- }
- /**
- * @requires extension pcntl
- * @requires extension posix
- */
- public function testNestingWorks(): void
- {
- $log1 = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal1 = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGHUP], $log1);
- $log1->expects(self::exactly(2))
- ->method('info')
- ->withConsecutive(
- ['Received SIGHUP', []],
- ['Received SIGINT', []]
- );
- $log2 = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal2 = SignalHandler::create([SignalHandler::SIGINT], $log2);
- $log2->expects(self::exactly(1))
- ->method('info')
- ->withConsecutive(
- ['Received SIGINT', []]
- );
- posix_kill(posix_getpid(), SIGINT);
- posix_kill(posix_getpid(), SIGHUP);
- $signal2->unregister();
- unset($signal2);
- self::assertNotSame(SIG_DFL, pcntl_signal_get_handler(SIGINT));
- self::assertNotSame(SIG_DFL, pcntl_signal_get_handler(SIGHUP));
- posix_kill(posix_getpid(), SIGINT);
- $signal1->unregister();
- unset($signal1);
- self::assertSame(SIG_DFL, pcntl_signal_get_handler(SIGINT));
- self::assertSame(SIG_DFL, pcntl_signal_get_handler(SIGHUP));
- }
- /**
- * @requires OSFAMILY Windows
- * @requires PHP >= 7.4
- */
- public function testLoggingAndDefaultOnWindows(): void
- {
- $log = $this->getMockBuilder(LoggerInterface::class)->getMock();
- $signal = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGBREAK], $log);
- $log->expects(self::atLeastOnce())
- ->method('info')
- ->with(self::equalTo('Received SIGBREAK'));
- $this->dispatchWindowsSignal($signal, PHP_WINDOWS_EVENT_CTRL_BREAK);
- $signal->unregister();
- }
- /**
- * @requires OSFAMILY Windows
- * @requires PHP >= 7.4
- */
- public function testCallbackAndCustomOnWindows(): void
- {
- $sigName = null;
- $signal = SignalHandler::create([SignalHandler::SIGBREAK], function ($name) use (&$sigName) {
- $sigName = $name;
- });
- $this->dispatchWindowsSignal($signal, PHP_WINDOWS_EVENT_CTRL_BREAK);
- self::assertSame(SignalHandler::SIGBREAK, $sigName);
- $signal->unregister();
- }
- /**
- * @requires OSFAMILY Windows
- * @requires PHP >= 7.4
- */
- public function testTriggerResetCycleOnWindows(): void
- {
- $signal = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGBREAK]);
- self::assertFalse($signal->isTriggered());
- $this->dispatchWindowsSignal($signal, PHP_WINDOWS_EVENT_CTRL_BREAK);
- self::assertTrue($signal->isTriggered());
- $signal->reset();
- self::assertFalse($signal->isTriggered());
- $this->dispatchWindowsSignal($signal, PHP_WINDOWS_EVENT_CTRL_BREAK);
- self::assertTrue($signal->isTriggered());
- $signal->unregister();
- }
- /**
- * @requires OSFAMILY Windows
- * @requires PHP >= 7.4
- */
- public function testNestingWorksOnWindows(): void
- {
- $signal1 = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGBREAK]);
- $signal2 = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGBREAK]);
- self::assertFalse($signal1->isTriggered());
- self::assertFalse($signal2->isTriggered());
- $this->dispatchWindowsSignal($signal2, PHP_WINDOWS_EVENT_CTRL_BREAK);
- self::assertFalse($signal1->isTriggered());
- self::assertTrue($signal2->isTriggered());
- $signal2->unregister();
- unset($signal2);
- $this->dispatchWindowsSignal($signal1, PHP_WINDOWS_EVENT_CTRL_BREAK);
- self::assertTrue($signal1->isTriggered());
- $signal1->unregister();
- unset($signal1);
- }
- private function dispatchWindowsSignal(SignalHandler $handler, int $signal): void
- {
- sapi_windows_generate_ctrl_event($signal);
- sapi_windows_generate_ctrl_event($signal);
- sapi_windows_generate_ctrl_event($signal);
- // waits to try and get the signal handler to trigger
- $tries = 10;
- while (!$handler->isTriggered() && $tries-- > 0) {
- sapi_windows_generate_ctrl_event($signal);
- usleep(500000);
- }
- }
- }
|