2424use OCP \IDateTimeFormatter ;
2525use OCP \ITempManager ;
2626use OCP \IURLGenerator ;
27+ use PHPUnit \Framework \Attributes \DataProvider ;
2728use PHPUnit \Framework \MockObject \MockObject ;
2829use Psr \Log \LoggerInterface ;
2930
@@ -60,25 +61,88 @@ public function testScopedProcessClassIsAvailable(): void {
6061 $ this ->assertTrue (class_exists (Process::class));
6162 }
6263
63- public function testCheckBinariesReturnsErrorWhenProcessFails (): void {
64+ public function testStopIfRunningKillsRegisteredAndPortListenerPids (): void {
65+ $ unregisteredPids = [];
66+ $ stoppedPids = [];
67+ $ uri = CfsslHandler::CFSSL_URI ;
68+ $ port = 8888 ;
69+
70+ $ this ->processManager ->expects ($ this ->once ())
71+ ->method ('setSourceHint ' )
72+ ->with (self ::PROCESS_SOURCE , [
73+ 'uri ' => $ uri ,
74+ 'port ' => $ port ,
75+ ]);
76+
77+ $ this ->processManager ->expects ($ this ->once ())
78+ ->method ('findRunningPid ' )
79+ ->with (self ::PROCESS_SOURCE , $ this ->callback ('is_callable ' ))
80+ ->willReturn (321 );
81+
82+ $ this ->processManager ->expects ($ this ->once ())
83+ ->method ('listRunning ' )
84+ ->with (self ::PROCESS_SOURCE )
85+ ->willReturn ([
86+ ['pid ' => 321 , 'context ' => ['uri ' => $ uri ], 'createdAt ' => 1 ],
87+ ['pid ' => 654 , 'context ' => ['uri ' => $ uri ], 'createdAt ' => 2 ],
88+ ]);
89+
90+ $ this ->processManager ->expects ($ this ->exactly (2 ))
91+ ->method ('unregister ' )
92+ ->willReturnCallback (function (string $ source , int $ pid ) use (&$ unregisteredPids ): void {
93+ $ this ->assertSame (self ::PROCESS_SOURCE , $ source );
94+ $ unregisteredPids [] = $ pid ;
95+ });
96+
97+ $ this ->processManager ->expects ($ this ->exactly (2 ))
98+ ->method ('stopPid ' )
99+ ->withAnyParameters ()
100+ ->willReturnCallback (function (int $ pid , int $ signal ) use (&$ stoppedPids ): bool {
101+ $ this ->assertSame (SIGKILL , $ signal );
102+ $ stoppedPids [] = $ pid ;
103+ return true ;
104+ });
105+
106+ $ handler = $ this ->getMockBuilder (CfsslHandler::class)
107+ ->setConstructorArgs ($ this ->getConstructorArgs ())
108+ ->onlyMethods (['createProcess ' ])
109+ ->getMock ();
110+
111+ $ handler ->method ('createProcess ' )
112+ ->willReturn ($ this ->createMock (Process::class));
113+
114+ self ::invokePrivate ($ handler , 'stopIfRunning ' );
115+
116+ sort ($ unregisteredPids );
117+ sort ($ stoppedPids );
118+ $ this ->assertSame ([321 , 654 ], $ unregisteredPids );
119+ $ this ->assertSame ([321 , 654 ], $ stoppedPids );
120+ }
121+
122+ #[DataProvider('provideCheckBinariesErrorCases ' )]
123+ public function testCheckBinariesReturnsErrorForInvalidProcessState (
124+ bool $ isSuccessful ,
125+ string $ output ,
126+ string $ expectedMessage ,
127+ ): void {
64128 $ binary = tempnam (sys_get_temp_dir (), 'cfssl-bin- ' );
65129 $ this ->assertNotFalse ($ binary );
66130
67131 $ process = $ this ->createMock (Process::class);
68132 $ process ->expects ($ this ->once ())
69133 ->method ('run ' );
70- $ process ->expects ($ this ->once ())
71- ->method ('getOutput ' )
72- ->willReturn ('' );
73134 $ process ->expects ($ this ->once ())
74135 ->method ('isSuccessful ' )
75- ->willReturn (false );
136+ ->willReturn ($ isSuccessful );
137+ $ process ->expects ($ this ->once ())
138+ ->method ('getOutput ' )
139+ ->willReturn ($ output );
76140
77141 $ handler = $ this ->createHandler ($ process , (string )$ binary );
78142 $ result = self ::invokePrivate ($ handler , 'checkBinaries ' );
79143
80144 $ this ->assertSame ('error ' , $ result [0 ]->jsonSerialize ()['status ' ]);
81- $ this ->assertStringContainsString (' Failed to run the command ' , $ result [0 ]->jsonSerialize ()['message ' ]);
145+ $ this ->assertStringContainsString ($ expectedMessage , $ result [0 ]->jsonSerialize ()['message ' ]);
82146
83147 @unlink ((string )$ binary );
84148 }
@@ -108,53 +172,49 @@ public function testCheckBinariesReturnsSuccessWhenProcessOutputIsValid(): void
108172 @unlink ((string )$ binary );
109173 }
110174
111- public function testCheckBinariesReturnsErrorWhenVersionOutputFormatIsInvalid (): void {
112- $ binary = tempnam (sys_get_temp_dir (), 'cfssl-bin- ' );
113- $ this ->assertNotFalse ($ binary );
114175
115- $ process = $ this ->createMock (Process::class);
116- $ process ->expects ($ this ->once ())
117- ->method ('run ' );
118- $ process ->expects ($ this ->once ())
119- ->method ('isSuccessful ' )
120- ->willReturn (true );
121- $ process ->expects ($ this ->once ())
122- ->method ('getOutput ' )
123- ->willReturn ('cfssl version output without expected separators ' );
124-
125- $ handler = $ this ->createHandler ($ process , (string )$ binary );
126- $ result = self ::invokePrivate ($ handler , 'checkBinaries ' );
127-
128- $ this ->assertSame ('error ' , $ result [0 ]->jsonSerialize ()['status ' ]);
129- $ this ->assertStringContainsString ('Failed to identify cfssl version ' , $ result [0 ]->jsonSerialize ()['message ' ]);
130-
131- @unlink ((string )$ binary );
176+ /**
177+ * @return array<string, array{0: bool, 1: string, 2: string}>
178+ */
179+ public static function provideCheckBinariesErrorCases (): array {
180+ return [
181+ 'process failure without output ' => [
182+ false ,
183+ '' ,
184+ 'Failed to run the command ' ,
185+ ],
186+ 'invalid version output format ' => [
187+ true ,
188+ 'cfssl version output without expected separators ' ,
189+ 'Failed to identify cfssl version ' ,
190+ ],
191+ 'version mismatch ' => [
192+ true ,
193+ "Version: 0.0.1 \nRuntime: go1.22 \n" ,
194+ 'Invalid version. Expected: ' ,
195+ ],
196+ ];
132197 }
133198
134- public function testCheckBinariesReturnsErrorWhenCfsslVersionDoesNotMatchExpected (): void {
135- $ binary = tempnam (sys_get_temp_dir (), 'cfssl-bin- ' );
136- $ this ->assertNotFalse ($ binary );
137-
138- $ process = $ this ->createMock (Process::class);
139- $ process ->expects ($ this ->once ())
140- ->method ('run ' );
141- $ process ->expects ($ this ->once ())
142- ->method ('isSuccessful ' )
143- ->willReturn (true );
144- $ process ->expects ($ this ->once ())
145- ->method ('getOutput ' )
146- ->willReturn ("Version: 0.0.1 \nRuntime: go1.22 \n" );
199+ private function createHandler (?Process $ process = null , ?string $ binary = null ): CfsslHandler {
200+ $ constructorArgs = $ this ->getConstructorArgs ($ binary );
201+ $ process ??= $ this ->createMock (Process::class);
147202
148- $ handler = $ this ->createHandler ($ process , (string )$ binary );
149- $ result = self ::invokePrivate ($ handler , 'checkBinaries ' );
203+ $ handler = $ this ->getMockBuilder (CfsslHandler::class)
204+ ->setConstructorArgs ($ constructorArgs )
205+ ->onlyMethods (['createProcess ' ])
206+ ->getMock ();
150207
151- $ this -> assertSame ( ' error ' , $ result [ 0 ]-> jsonSerialize ()[ ' status ' ]);
152- $ this -> assertStringContainsString ( ' Invalid version. Expected: ' , $ result [ 0 ]-> jsonSerialize ()[ ' message ' ] );
208+ $ handler -> method ( ' createProcess ' )
209+ -> willReturn ( $ process );
153210
154- @ unlink (( string ) $ binary ) ;
211+ return $ handler ;
155212 }
156213
157- private function createHandler (?Process $ process = null , ?string $ binary = null ): CfsslHandler {
214+ /**
215+ * @return array<int, mixed>
216+ */
217+ private function getConstructorArgs (?string $ binary = null ): array {
158218 $ config = \OCP \Server::get (IConfig::class);
159219 $ appConfig = $ this ->getMockAppConfigWithReset ();
160220 if ($ binary !== null ) {
@@ -180,30 +240,21 @@ private function createHandler(?Process $process = null, ?string $binary = null)
180240 $ cfsslServerHandler = $ this ->createMock (CfsslServerHandler::class);
181241 $ cfsslServerHandler ->expects ($ this ->once ())
182242 ->method ('configCallback ' );
183- $ process ??= $ this ->createMock (Process::class);
184-
185- $ handler = $ this ->getMockBuilder (CfsslHandler::class)
186- ->setConstructorArgs ([
187- $ config ,
188- $ appConfig ,
189- $ appDataFactory ,
190- $ dateTimeFormatter ,
191- $ tempManager ,
192- $ cfsslServerHandler ,
193- $ certificatePolicyService ,
194- $ urlGenerator ,
195- $ caIdentifierService ,
196- $ crlMapper ,
197- $ logger ,
198- $ crlRevocationChecker ,
199- $ this ->processManager ,
200- ])
201- ->onlyMethods (['createProcess ' ])
202- ->getMock ();
203243
204- $ handler ->method ('createProcess ' )
205- ->willReturn ($ process );
206-
207- return $ handler ;
244+ return [
245+ $ config ,
246+ $ appConfig ,
247+ $ appDataFactory ,
248+ $ dateTimeFormatter ,
249+ $ tempManager ,
250+ $ cfsslServerHandler ,
251+ $ certificatePolicyService ,
252+ $ urlGenerator ,
253+ $ caIdentifierService ,
254+ $ crlMapper ,
255+ $ logger ,
256+ $ crlRevocationChecker ,
257+ $ this ->processManager ,
258+ ];
208259 }
209260}
0 commit comments