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
@@ -1862,39 +1865,107 @@ public function testCommandNameMismatchWithCommandLoaderKeyThrows()
1862
1865
/**
1863
1866
* @requires extension pcntl
1864
1867
*/
1865
- public function testSignal ()
1868
+ public function testSignalListenerNotCalledByDefault ()
1866
1869
{
1867
- $ command = new SignableCommand ();
1870
+ $ command = new SignableCommand (false );
1868
1871
1869
1872
$ dispatcherCalled = false ;
1870
1873
$ dispatcher = new EventDispatcher ();
1871
1874
$ dispatcher ->addListener ('console.signal ' , function () use (&$ dispatcherCalled ) {
1872
1875
$ dispatcherCalled = true ;
1873
1876
});
1874
1877
1875
- $ application = new Application ();
1876
- $ application ->setAutoExit (false );
1877
- $ application ->setDispatcher ($ dispatcher );
1878
- $ application ->setSignalsToDispatchEvent (\SIGALRM );
1879
- $ application ->add (new LazyCommand ('signal ' , [], '' , false , function () use ($ command ) { return $ command ; }, true ));
1880
-
1881
- $ this ->assertFalse ($ command ->signaled );
1882
- $ this ->assertFalse ($ dispatcherCalled );
1878
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1883
1879
1884
1880
$ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1885
1881
$ this ->assertFalse ($ command ->signaled );
1886
1882
$ this ->assertFalse ($ dispatcherCalled );
1883
+ }
1884
+
1885
+ /**
1886
+ * @requires extension pcntl
1887
+ */
1888
+ public function testSignalListener ()
1889
+ {
1890
+ $ command = new SignableCommand ();
1891
+
1892
+ $ dispatcherCalled = false ;
1893
+ $ dispatcher = new EventDispatcher ();
1894
+ $ dispatcher ->addListener ('console.signal ' , function () use (&$ dispatcherCalled ) {
1895
+ $ dispatcherCalled = true ;
1896
+ });
1897
+
1898
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1887
1899
1888
- $ command ->loop = 100000 ;
1889
- pcntl_alarm (1 );
1890
1900
$ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1891
- $ this ->assertTrue ($ command ->signaled );
1892
1901
$ this ->assertTrue ($ dispatcherCalled );
1902
+ $ this ->assertTrue ($ command ->signaled );
1903
+ }
1904
+
1905
+ /**
1906
+ * @requires extension pcntl
1907
+ */
1908
+ public function testSignalSubscriberNotCalledByDefault ()
1909
+ {
1910
+ $ command = new BaseSignableCommand (false );
1911
+
1912
+ $ subscriber = new SignalEventSubscriber ();
1913
+ $ dispatcher = new EventDispatcher ();
1914
+ $ dispatcher ->addSubscriber ($ subscriber );
1915
+
1916
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1917
+
1918
+ $ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1919
+ $ this ->assertFalse ($ subscriber ->signaled );
1920
+ }
1921
+
1922
+ /**
1923
+ * @requires extension pcntl
1924
+ */
1925
+ public function testSignalSubscriber ()
1926
+ {
1927
+ $ command = new BaseSignableCommand ();
1928
+
1929
+ $ subscriber1 = new SignalEventSubscriber ();
1930
+ $ subscriber2 = new SignalEventSubscriber ();
1931
+
1932
+ $ dispatcher = new EventDispatcher ();
1933
+ $ dispatcher ->addSubscriber ($ subscriber1 );
1934
+ $ dispatcher ->addSubscriber ($ subscriber2 );
1935
+
1936
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1937
+
1938
+ $ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1939
+ $ this ->assertTrue ($ subscriber1 ->signaled );
1940
+ $ this ->assertTrue ($ subscriber2 ->signaled );
1941
+ }
1942
+
1943
+ /**
1944
+ * @requires extension pcntl
1945
+ */
1946
+ public function testSetSignalsToDispatchEvent ()
1947
+ {
1948
+ $ command = new BaseSignableCommand ();
1949
+
1950
+ $ subscriber = new SignalEventSubscriber ();
1951
+
1952
+ $ dispatcher = new EventDispatcher ();
1953
+ $ dispatcher ->addSubscriber ($ subscriber );
1954
+
1955
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1956
+ $ application ->setSignalsToDispatchEvent (\SIGUSR2 );
1957
+ $ this ->assertSame (0 , $ application ->run (new ArrayInput (['signal ' ])));
1958
+ $ this ->assertFalse ($ subscriber ->signaled );
1959
+
1960
+ $ application = $ this ->createSignalableApplication ($ command , $ dispatcher );
1961
+ $ application ->setSignalsToDispatchEvent (\SIGUSR1 );
1962
+ $ this ->assertSame (1 , $ application ->run (new ArrayInput (['signal ' ])));
1963
+ $ this ->assertTrue ($ subscriber ->signaled );
1893
1964
}
1894
1965
1895
1966
public function testSignalableCommandInterfaceWithoutSignals ()
1896
1967
{
1897
- $ command = new SignableCommand ();
1968
+ $ command = new SignableCommand (false );
1898
1969
1899
1970
$ dispatcher = new EventDispatcher ();
1900
1971
$ application = new Application ();
@@ -1936,6 +2007,18 @@ public function testSignalableRestoresStty()
1936
2007
1937
2008
$ this ->assertSame ($ previousSttyMode , $ sttyMode );
1938
2009
}
2010
+
2011
+ private function createSignalableApplication (Command $ command , ?EventDispatcherInterface $ dispatcher ): Application
2012
+ {
2013
+ $ application = new Application ();
2014
+ $ application ->setAutoExit (false );
2015
+ if ($ dispatcher ) {
2016
+ $ application ->setDispatcher ($ dispatcher );
2017
+ }
2018
+ $ application ->add (new LazyCommand ('signal ' , [], '' , false , function () use ($ command ) { return $ command ; }, true ));
2019
+
2020
+ return $ application ;
2021
+ }
1939
2022
}
1940
2023
1941
2024
class CustomApplication extends Application
@@ -1990,25 +2073,26 @@ public function isEnabled(): bool
1990
2073
}
1991
2074
}
1992
2075
1993
- class SignableCommand extends Command implements SignalableCommandInterface
2076
+ class BaseSignableCommand extends Command
1994
2077
{
1995
2078
public $ signaled = false ;
1996
- public $ loop = 100 ;
2079
+ public $ loop = 1000 ;
2080
+ private $ emitsSignal ;
1997
2081
1998
2082
protected static $ defaultName = 'signal ' ;
1999
2083
2000
- public function getSubscribedSignals (): array
2084
+ public function __construct ( bool $ emitsSignal = true )
2001
1241
2085
{
2002
- return SignalRegistry::isSupported () ? [\SIGALRM ] : [];
2003
- }
2004
-
2005
- public function handleSignal (int $ signal ): void
2006
- {
2007
- $ this ->signaled = true ;
2086
+ parent ::__construct ();
2087
+ $ this ->emitsSignal = $ emitsSignal ;
2008
2088
}
2009
2089
2010
2090
protected function execute (InputInterface $ input , OutputInterface $ output ): int
2011
2091
{
2092
+ if ($ this ->emitsSignal ) {
2093
+ posix_kill (posix_getpid (), SIGUSR1 );
2094
+ }
2095
+
2012
2096
for ($ i = 0 ; $ i < $ this ->loop ; ++$ i ) {
2013
2097
usleep (100 );
2014
2098
if ($ this ->signaled ) {
@@ -2019,3 +2103,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int
2019
2103
return 0 ;
2020
2104
}
2021
2105
}
2106
+
2107
+ class SignableCommand extends BaseSignableCommand implements SignalableCommandInterface
2108
+ {
2109
+ protected static $ defaultName = 'signal ' ;
2110
+
2111
+ public function getSubscribedSignals (): array
2112
+ {
2113
+ return SignalRegistry::isSupported () ? [\SIGUSR1 ] : [];
2114
+ }
2115
+
2116
+ public function handleSignal (int $ signal ): void
2117
+ {
2118
+ $ this ->signaled = true ;
2119
+ }
2120
+ }
2121
+
2122
+ class SignalEventSubscriber implements EventSubscriberInterface
2123
+ {
2124
+ public $ signaled = false ;
2125
+
2126
+ public function onSignal (ConsoleSignalEvent $ event ): void
2127
+ {
2128
+ $ this ->signaled = true ;
2129
+ $ event ->getCommand ()->signaled = true ;
2130
+ }
2131
+
2132
+ public static function getSubscribedEvents (): array
2133
+ {
2134
+ return ['console.signal ' => 'onSignal ' ];
2135
+ }
2136
+ }
0 commit comments