21
21
use Symfony \Component \Console \DependencyInjection \AddConsoleCommandPass ;
22
22
use Symfony \Component \Console \Event \ConsoleCommandEvent ;
23
23
use Symfony \Component \Console \Event \ConsoleErrorEvent ;
24
+ use Symfony \Component \Console \Event \ConsoleSignalEvent ;
24
25
use Symfony \Component \Console \Event \ConsoleTerminateEvent ;
25
26
use Symfony \Component \Console \Exception \CommandNotFoundException ;
26
27
use Symfony \Component \Console \Exception \NamespaceNotFoundException ;
42
43
use Symfony \Component \Console \Tester \ApplicationTester ;
43
44
use Symfony \Component \DependencyInjection \ContainerBuilder ;
44
45
use Symfony \Component \EventDispatcher \EventDispatcher ;
46
+ use Symfony \Component \EventDispatcher \EventDispatcherInterface ;
47
+ use Symfony \Component \EventDispatcher \EventSubscriberInterface ;
45
48
use Symfony \Component \Process \Process ;
46
49
47
50
class ApplicationTest extends TestCase
@@ -1843,39 +1846,107 @@ public function testCommandNameMismatchWithCommandLoaderKeyThrows()
1843
1846
/**
1844
1847
* @requires extension pcntl
1845
1848
*/
1846
- public function testSignal ()
1849
+ public function testSignalListenerNotCalledByDefault (): void
1847
1850
{
1848
- $ command = new SignableCommand ();
1851
+ $ command = new SignableCommand (false );
1849
1852
1850
1853
$ dispatcherCalled = false ;
1851
1854
$ dispatcher = new EventDispatcher ();
1852
1855
$ dispatcher ->addListener ('console.signal ' , function () use (&$ dispatcherCalled ) {
1853
1856
$ dispatcherCalled = true ;
1854
1857
});
1855
1858
1856
- $ application = new Application ();
1857
- $ application ->setAutoExit (false );
1858
- $ application ->setDispatcher ($ dispatcher );
1859
- $ application ->setSignalsToDispatchEvent (\SIGALRM );
1860
- $ application ->add (new LazyCommand ('signal ' , [], '' , false , function () use ($ command ) { return $ command ; }, true ));
1861
-
1862
- $ this ->assertFalse ($ command ->signaled );
1863
- $ this ->assertFalse ($ dispatcherCalled );
1859
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1864
1860
1865
1861
$ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1866
1862
$ this ->assertFalse ($ command ->signaled );
1867
1863
$ this ->assertFalse ($ dispatcherCalled );
1864
+ }
1865
+
1866
+ /**
1867
+ * @requires extension pcntl
1868
+ */
1869
+ public function testSignalListener (): void
1870
+ {
1871
+ $ command = new SignableCommand ();
1872
+
1873
+ $ dispatcherCalled = false ;
1874
+ $ dispatcher = new EventDispatcher ();
1875
+ $ dispatcher ->addListener ('console.signal ' , function () use (&$ dispatcherCalled ) {
1876
+ $ dispatcherCalled = true ;
1877
+ });
1878
+
1879
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1868
1880
1869
- $ command ->loop = 100000 ;
1870
- pcntl_alarm (1 );
1871
1881
$ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1872
- $ this ->assertTrue ($ command ->signaled );
1873
1882
$ this ->assertTrue ($ dispatcherCalled );
1883
+ $ this ->assertTrue ($ command ->signaled );
1884
+ }
1885
+
1886
+ /**
1887
+ * @requires extension pcntl
1888
+ */
1889
+ public function testSignalSubscriberNotCalledByDefault (): void
1890
+ {
1891
+ $ command = new BaseSignableCommand (false );
1892
+
1893
+ $ subscriber = new SignalEventSubscriber ();
1894
+ $ dispatcher = new EventDispatcher ();
1895
+ $ dispatcher ->addSubscriber ($ subscriber );
1896
+
1897
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1898
+
1899
+ $ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1900
+ $ this ->assertFalse ($ subscriber ->signaled );
1901
+ }
1902
+
1903
+ /**
1904
+ * @requires extension pcntl
1905
+ */
1906
+ public function testSignalSubscriber (): void
1907
+ {
1908
+ $ command = new BaseSignableCommand ();
1909
+
1910
+ $ subscriber1 = new SignalEventSubscriber ();
1911
+ $ subscriber2 = new SignalEventSubscriber ();
1912
+
1913
+ $ dispatcher = new EventDispatcher ();
1914
+ $ dispatcher ->addSubscriber ($ subscriber1 );
1915
+ $ dispatcher ->addSubscriber ($ subscriber2 );
1916
+
1917
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1918
+
1919
+ $ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1920
+ $ this ->assertTrue ($ subscriber1 ->signaled );
1921
+ $ this ->assertTrue ($ subscriber2 ->signaled );
1922
+ }
1923
+
1924
+ /**
1925
+ * @requires extension pcntl
1926
+ */
1927
+ public function testSetSignalsToDispatchEvent (): void
1928
+ {
1929
+ $ command = new BaseSignableCommand ();
1930
+
1931
+ $ subscriber = new SignalEventSubscriber ();
1932
+
1933
+ $ dispatcher = new EventDispatcher ();
1934
+ $ dispatcher ->addSubscriber ($ subscriber );
1935
+
1936
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1937
+ $ application ->setSignalsToDispatchEvent (\SIGUSR2 );
1938
+ $ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1939
+ $ this ->assertFalse ($ subscriber ->signaled );
1940
+
1941
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1942
+ $ application ->setSignalsToDispatchEvent (\SIGUSR1 );
1943
+ $ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1944
+ $ this ->assertTrue ($ subscriber ->signaled );
1874
1945
}
1875
1946
1876
1947
public function testSignalableCommandInterfaceWithoutSignals ()
1877
1948
{
1878
- $ command = new SignableCommand ();
1949
+ $ command = new SignableCommand (false );
1879
1950
1880
1951
$ dispatcher = new EventDispatcher ();
1881
1952
$ application = new Application ();
@@ -1917,6 +1988,18 @@ public function testSignalableRestoresStty()
1917
1988
1918
1989
$ this ->assertSame ($ previousSttyMode , $ sttyMode );
1919
1990
}
1991
+
1992
+ private function createSignalableApplication (Command $ command , ?EventDispatcherInterface $ dispatcher ): Application
1993
+ {
1994
+ $ application = new Application ();
1995
+ $ application ->setAutoExit (false );
1996
+ if ($ dispatcher ) {
1997
+ $ application ->setDispatcher ($ dispatcher );
1998
+ }
1999
+ $ application ->add (new LazyCommand ('signal ' , [], '' , false , function () use ($ command ) { return $ command ; }, true ));
2000
+
2001
+ return $ application ;
2002
+ }
1920
2003
}
1921
2004
1922
2005
class CustomApplication extends Application
@@ -1971,25 +2054,26 @@ public function isEnabled(): bool
1971
2054
}
1972
2055
}
1973
2056
1974
- class SignableCommand extends Command implements SignalableCommandInterface
2057
+ class BaseSignableCommand extends Command
1975
2058
{
1976
2059
public $ signaled = false ;
1977
- public $ loop = 100 ;
2060
+ public $ loop = 1000 ;
2061
+ private $ emitsSignal ;
1978
2062
1979
2063
protected static $ defaultName = 'signal ' ;
1980
2064
1981
- public function getSubscribedSignals (): array
1982
- {
1983
- return SignalRegistry::isSupported () ? [\SIGALRM ] : [];
1984
- }
1985
-
1986
- public function handleSignal (int $ signal ): void
2065
+ public function __construct (bool $ emitsSignal = true )
1987
2066
{
1988
- $ this ->signaled = true ;
2067
+ parent ::__construct ();
2068
+ $ this ->emitsSignal = $ emitsSignal ;
1989
2069
}
1990
2070
1991
2071
protected function execute (InputInterface $ input , OutputInterface $ output ): int
1992
2072
{
2073
+ if ($ this ->emitsSignal ) {
2074
+ posix_kill (posix_getpid (), SIGUSR1 );
2075
+ }
2076
+
1993
2077
for ($ i = 0 ; $ i < $ this ->loop ; ++$ i ) {
1994
2078
usleep (100 );
1995
2079
if ($ this ->signaled ) {
@@ -2000,3 +2084,33 @@ protected function execute(InputInterface $input, OutputInterface $output): int
2000
2084
return 0 ;
2001
2085
}
2002
2086
}
2087
+
2088
+ class SignableCommand extends BaseSignableCommand implements SignalableCommandInterface
2089
+ {
2090
+ protected static $ defaultName = 'signal ' ;
2091
+
2092
+ public function getSubscribedSignals (): array
2093
+ {
2094
+ return SignalRegistry::isSupported () ? [\SIGUSR1 ] : [];
2095
+ }
2096
+
2097
+ public function handleSignal (int $ signal ): void
2098
+ {
2099
+ $ this ->signaled = true ;
2100
+ }
2101
+ }
2102
+
2103
+ class SignalEventSubscriber implements EventSubscriberInterface {
2104
+ public $ signaled = false ;
2105
+
2106
+ public function onSignal (ConsoleSignalEvent $ event ): void
2107
+ {
2108
+ $ this ->signaled = true ;
2109
+ $ event ->getCommand ()->signaled = true ;
2110
+ }
2111
+
2112
+ public static function getSubscribedEvents (): array
2113
+ {
2114
+ return ['console.signal ' => 'onSignal ' ];
2115
+ }
2116
+ }
0 commit comments