2323use ILIAS \FileUpload \Collection \EntryLockingStringMap ;
2424use ILIAS \FileUpload \DTO \ProcessingStatus ;
2525use ILIAS \FileUpload \DTO \UploadResult ;
26+ use ILIAS \Filesystem \Stream \FileStream ;
2627use ILIAS \ResourceStorage \Collection \Collections ;
2728use ILIAS \ResourceStorage \Collection \ResourceCollection ;
2829use ILIAS \ResourceStorage \Identification \ResourceIdentification ;
@@ -47,6 +48,7 @@ final class UploadStorerTest extends TestCase
4748 private ResourceCollection &MockObject $ collection ;
4849 private ResourceStakeholder &MockObject $ stakeholder ;
4950 private UploadResult $ result ;
51+ private FileStream &MockObject $ stream ;
5052 private UploadStorer $ storer ;
5153
5254 protected function setUp (): void
@@ -64,6 +66,7 @@ protected function setUp(): void
6466 new ProcessingStatus (ProcessingStatus::OK , 'ok ' ),
6567 'dummy/path '
6668 );
69+ $ this ->stream = $ this ->createMock (FileStream::class);
6770 $ this ->storer = new UploadStorer ($ this ->manage , $ this ->collections );
6871 }
6972
@@ -195,6 +198,98 @@ public function testAppendRevisionStoresNewResourceWhenNoNameClash(): void
195198 );
196199 }
197200
201+ // storeStream(): the twin used for a reassembled chunked upload. It has to
202+ // reach the same decision as store() in every mode, only writing the resource
203+ // from a stream instead of from an UploadResult.
204+
205+ public function testStreamAllowStoresNewResourceWithoutLookupEvenWhenNameExists (): void
206+ {
207+ $ new_rid = new ResourceIdentification ('new ' );
208+
209+ $ this ->collections ->expects ($ this ->never ())->method ('findIdentificationByNameIn ' );
210+ $ this ->manage ->expects ($ this ->never ())->method ('replaceWithStream ' );
211+ $ this ->manage ->expects ($ this ->never ())->method ('appendNewRevisionFromStream ' );
212+
213+ $ this ->manage ->expects ($ this ->once ())
214+ ->method ('stream ' )
215+ ->with ($ this ->stream , $ this ->stakeholder , self ::FILE_NAME )
216+ ->willReturn ($ new_rid );
217+ $ this ->collection ->expects ($ this ->once ())->method ('add ' )->with ($ new_rid );
218+
219+ $ this ->assertSame ($ new_rid , $ this ->storeStream (OnDuplicate::ALLOW ));
220+ }
221+
222+ public function testStreamRejectLeavesExistingResourceUntouchedAndStoresNothing (): void
223+ {
224+ $ this ->givenExistingResource (new ResourceIdentification ('existing ' ));
225+
226+ $ this ->manage ->expects ($ this ->never ())->method ('stream ' );
227+ $ this ->manage ->expects ($ this ->never ())->method ('replaceWithStream ' );
228+ $ this ->manage ->expects ($ this ->never ())->method ('appendNewRevisionFromStream ' );
229+ $ this ->collection ->expects ($ this ->never ())->method ('add ' );
230+
231+ $ this ->assertNull ($ this ->storeStream (OnDuplicate::REJECT ));
232+ }
233+
234+ public function testStreamReplaceOverwritesExistingResource (): void
235+ {
236+ $ existing_rid = new ResourceIdentification ('existing ' );
237+ $ this ->givenExistingResource ($ existing_rid );
238+
239+ $ this ->manage ->expects ($ this ->never ())->method ('stream ' );
240+ $ this ->manage ->expects ($ this ->never ())->method ('appendNewRevisionFromStream ' );
241+ $ this ->collection ->expects ($ this ->never ())->method ('add ' );
242+ $ this ->manage ->expects ($ this ->once ())
243+ ->method ('replaceWithStream ' )
244+ ->with ($ existing_rid , $ this ->stream , $ this ->stakeholder , self ::FILE_NAME )
245+ ->willReturn ($ this ->createStub (Revision::class));
246+
247+ $ this ->assertSame ($ existing_rid , $ this ->storeStream (OnDuplicate::REPLACE ));
248+ }
249+
250+ public function testStreamAppendRevisionAddsRevisionToExistingResource (): void
251+ {
252+ $ existing_rid = new ResourceIdentification ('existing ' );
253+ $ this ->givenExistingResource ($ existing_rid );
254+
255+ $ this ->manage ->expects ($ this ->never ())->method ('stream ' );
256+ $ this ->manage ->expects ($ this ->never ())->method ('replaceWithStream ' );
257+ $ this ->collection ->expects ($ this ->never ())->method ('add ' );
258+ $ this ->manage ->expects ($ this ->once ())
259+ ->method ('appendNewRevisionFromStream ' )
260+ ->with ($ existing_rid , $ this ->stream , $ this ->stakeholder , self ::FILE_NAME )
261+ ->willReturn ($ this ->createStub (Revision::class));
262+
263+ $ this ->assertSame ($ existing_rid , $ this ->storeStream (OnDuplicate::APPEND_REVISION ));
264+ }
265+
266+ public function testStreamStoresNewResourceWhenNoNameClash (): void
267+ {
268+ foreach ([OnDuplicate::REJECT , OnDuplicate::REPLACE , OnDuplicate::APPEND_REVISION ] as $ on_duplicate ) {
269+ $ this ->setUp ();
270+ $ new_rid = new ResourceIdentification ('new ' );
271+ $ this ->givenNoExistingResource ();
272+
273+ $ this ->manage ->expects ($ this ->never ())->method ('replaceWithStream ' );
274+ $ this ->manage ->expects ($ this ->never ())->method ('appendNewRevisionFromStream ' );
275+ $ this ->manage ->expects ($ this ->once ())->method ('stream ' )->willReturn ($ new_rid );
276+ $ this ->collection ->expects ($ this ->once ())->method ('add ' )->with ($ new_rid );
277+
278+ $ this ->assertSame ($ new_rid , $ this ->storeStream ($ on_duplicate ), $ on_duplicate ->name );
279+ }
280+ }
281+
282+ private function storeStream (OnDuplicate $ on_duplicate ): ?ResourceIdentification
283+ {
284+ return $ this ->storer ->storeStream (
285+ $ this ->collection ,
286+ $ this ->stakeholder ,
287+ $ on_duplicate ,
288+ $ this ->stream ,
289+ self ::FILE_NAME
290+ );
291+ }
292+
198293 private function givenExistingResource (ResourceIdentification $ existing_rid ): void
199294 {
200295 $ this ->collections ->method ('findIdentificationByNameIn ' )
0 commit comments