4848import okhttp3 .ResponseBody ;
4949import okio .Buffer ;
5050import org .datatransferproject .api .launcher .Monitor ;
51+ import org .datatransferproject .datatransfer .synology .exceptions .SynologyException ;
5152import org .datatransferproject .datatransfer .synology .exceptions .SynologyImportException ;
5253import org .datatransferproject .datatransfer .synology .exceptions .SynologyMaxRetriesExceededException ;
5354import org .datatransferproject .datatransfer .synology .utils .TestConfigs ;
5455import org .datatransferproject .spi .cloud .storage .JobStore ;
5556import org .datatransferproject .spi .cloud .storage .TemporaryPerJobDataStore .InputStreamWrapper ;
57+ import org .datatransferproject .spi .transfer .types .FailureReasons ;
5658import org .datatransferproject .types .common .DownloadableFile ;
5759import org .datatransferproject .types .common .models .media .MediaAlbum ;
5860import org .datatransferproject .types .common .models .photos .PhotoModel ;
@@ -85,7 +87,7 @@ public class SynologyDTPServiceTest {
8587 @ Mock private OkHttpClient client ;
8688
8789 @ BeforeEach
88- public void setUp () {
90+ public void setUp () throws SynologyImportException {
8991 lenient ().when (tokenManager .getAccessToken (jobId )).thenReturn ("mockAccessToken" );
9092 lenient ()
9193 .when (transferServiceConfig .getServiceConfig ())
@@ -102,7 +104,7 @@ public class AddItemToAlbum {
102104 private final String itemId = "testItem" ;
103105
104106 @ Test
105- public void shouldSendPostRequestWithCorrectFormBody () {
107+ public void shouldSendPostRequestWithCorrectFormBody () throws SynologyException {
106108 SynologyDTPService spyService = Mockito .spy (dtpService );
107109
108110 doReturn (Map .of ("success" , true )).when (spyService ).sendPostRequest (anyString (), any (), any ());
@@ -127,7 +129,7 @@ public void shouldSendPostRequestWithCorrectFormBody() {
127129 }
128130
129131 @ Test
130- public void shouldThrowExceptionIfSendPostRequestFailed () {
132+ public void shouldThrowExceptionIfSendPostRequestFailed () throws SynologyException {
131133 SynologyDTPService spyService = Mockito .spy (dtpService );
132134
133135 doThrow (
@@ -150,7 +152,7 @@ public class CreateAlbum {
150152 private final MediaAlbum album = new MediaAlbum (albumId , albumName , "" );
151153
152154 @ Test
153- public void shouldSendPostRequestWithCorrectFormBody () {
155+ public void shouldSendPostRequestWithCorrectFormBody () throws SynologyException {
154156 SynologyDTPService spyService = Mockito .spy (dtpService );
155157 Map <String , Object > dataMap = Map .of ("album_id" , albumId );
156158
@@ -179,7 +181,7 @@ public void shouldSendPostRequestWithCorrectFormBody() {
179181 }
180182
181183 @ Test
182- public void shouldThrowExceptionIfSendPostRequestFailed () {
184+ public void shouldThrowExceptionIfSendPostRequestFailed () throws SynologyException {
183185 SynologyDTPService spyService = Mockito .spy (dtpService );
184186
185187 doThrow (
@@ -207,8 +209,10 @@ public class CreateMedia {
207209 public Stream <Object > provideMediaObjectsInTempStore () {
208210 Date uploadedTime = new Date (uploadedTimestampInSeconds * 1000 );
209211 return Stream .of (
210- new PhotoModel (itemName , fetchUrl , description , "mediaType" , itemId , null , true , uploadedTime ),
211- new VideoModel (itemName , fetchUrl , description , "format" , itemId , null , true , uploadedTime ));
212+ new PhotoModel (
213+ itemName , fetchUrl , description , "mediaType" , itemId , null , true , uploadedTime ),
214+ new VideoModel (
215+ itemName , fetchUrl , description , "format" , itemId , null , true , uploadedTime ));
212216 }
213217
214218 public Stream <Object > provideMediaObjectsWithoutDescriptionAndUploadedTimeInTempStore () {
@@ -226,7 +230,7 @@ public Stream<Object> provideMediaObjectsNotInTempStore() {
226230 @ ParameterizedTest (name = "shouldGetStreamFromJobStoreIfMediaItemIsInTempStore [{index}] {0}" )
227231 @ MethodSource ("provideMediaObjectsInTempStore" )
228232 public void shouldGetStreamFromJobStoreIfMediaItemIsInTempStore (DownloadableFile item )
229- throws IOException {
233+ throws IOException , SynologyException {
230234 byte [] mockImage = new byte [] {1 , 2 , 3 };
231235 InputStream mockInputStream = new ByteArrayInputStream (mockImage );
232236 InputStreamWrapper streamWrapper = mock (InputStreamWrapper .class );
@@ -250,7 +254,7 @@ public void shouldGetStreamFromJobStoreIfMediaItemIsInTempStore(DownloadableFile
250254 @ ParameterizedTest (name = "shouldGetStreamFromUrlIfPhotoIsNotInTempStore [{index}] {0}" )
251255 @ MethodSource ("provideMediaObjectsNotInTempStore" )
252256 public void shouldGetStreamFromUrlIfPhotoIsNotInTempStore (DownloadableFile item )
253- throws IOException {
257+ throws IOException , SynologyException {
254258 byte [] mockImage = new byte [] {1 , 2 , 3 };
255259 SynologyDTPService spyService = Mockito .spy (dtpService );
256260 InputStream mockInputStream = new ByteArrayInputStream (mockImage );
@@ -271,7 +275,7 @@ public void shouldGetStreamFromUrlIfPhotoIsNotInTempStore(DownloadableFile item)
271275
272276 // VideoModel.contentUrl can't be null
273277 @ Test
274- public void shouldReturnNullWhenPhotoIsNotInTempStoreAndHasNoUrl () {
278+ public void shouldReturnNullWhenPhotoIsNotInTempStoreAndHasNoUrl () throws SynologyException {
275279 PhotoModel photo =
276280 new PhotoModel (itemName , null , description , "mediaType" , itemId , null , false );
277281 SynologyDTPService spyService = Mockito .spy (dtpService );
@@ -281,7 +285,8 @@ public void shouldReturnNullWhenPhotoIsNotInTempStoreAndHasNoUrl() {
281285
282286 @ ParameterizedTest (name = "shouldThrowExceptionIfNewURLFailed [{index}] {0}" )
283287 @ MethodSource ("provideMediaObjectsNotInTempStore" )
284- public void shouldThrowExceptionIfNewURLFailed (DownloadableFile item ) throws IOException {
288+ public void shouldThrowExceptionIfNewURLFailed (DownloadableFile item )
289+ throws IOException , SynologyException {
285290 SynologyDTPService spyService = Mockito .spy (dtpService );
286291 doThrow (new MalformedURLException ("Failed to create url for photo" ))
287292 .when (spyService )
@@ -305,7 +310,7 @@ public void shouldThrowExceptionIfNewURLFailed(DownloadableFile item) throws IOE
305310 @ ParameterizedTest (name = "shouldThrowExceptionIfFailedToGetStream [{index}] {0}" )
306311 @ MethodSource ("provideMediaObjectsInTempStore" )
307312 public void shouldThrowExceptionIfFailedToGetStream (DownloadableFile item )
308- throws IOException , SynologyMaxRetriesExceededException {
313+ throws IOException , SynologyMaxRetriesExceededException , SynologyException {
309314 SynologyDTPService spyService = Mockito .spy (dtpService );
310315 when (jobStore .getStream (jobId , fetchUrl )).thenThrow (new IOException ("Failed to get stream" ));
311316
@@ -324,10 +329,11 @@ public void shouldThrowExceptionIfFailedToGetStream(DownloadableFile item)
324329 }
325330
326331 @ ParameterizedTest (
327- name = "shouldSendPostRequestWithCorrectFormBodyWithDescriptionAndUploadedTime [{index}] {0}" )
332+ name =
333+ "shouldSendPostRequestWithCorrectFormBodyWithDescriptionAndUploadedTime [{index}] {0}" )
328334 @ MethodSource ("provideMediaObjectsInTempStore" )
329- public void shouldSendPostRequestWithCorrectFormBodyWithDescriptionAndUploadedTime (DownloadableFile item )
330- throws IOException {
335+ public void shouldSendPostRequestWithCorrectFormBodyWithDescriptionAndUploadedTime (
336+ DownloadableFile item ) throws IOException , SynologyException {
331337 byte [] mockImage = new byte [] {1 , 2 , 3 };
332338 InputStream mockInputStream = new ByteArrayInputStream (mockImage );
333339 InputStreamWrapper streamWrapper = mock (InputStreamWrapper .class );
@@ -383,10 +389,12 @@ public void shouldSendPostRequestWithCorrectFormBodyWithDescriptionAndUploadedTi
383389 }
384390
385391 @ ParameterizedTest (
386- name = "shouldSendPostRequestWithCorrectFormBodyWithoutDescriptionAndUploadedTime [{index}] {0}" )
392+ name =
393+ "shouldSendPostRequestWithCorrectFormBodyWithoutDescriptionAndUploadedTime [{index}]"
394+ + " {0}" )
387395 @ MethodSource ("provideMediaObjectsWithoutDescriptionAndUploadedTimeInTempStore" )
388396 public void shouldSendPostRequestWithCorrectFormBodyWithoutDescription (DownloadableFile item )
389- throws IOException {
397+ throws IOException , SynologyException {
390398 byte [] mockImage = new byte [] {1 , 2 , 3 };
391399 InputStream mockInputStream = new ByteArrayInputStream (mockImage );
392400 InputStreamWrapper streamWrapper = mock (InputStreamWrapper .class );
@@ -443,7 +451,7 @@ public void shouldSendPostRequestWithCorrectFormBodyWithoutDescription(Downloada
443451 @ ParameterizedTest (name = "shouldThrowExceptionIfSendPostRequestFailed [{index}] {0}" )
444452 @ MethodSource ("provideMediaObjectsInTempStore" )
445453 public void shouldThrowExceptionIfSendPostRequestFailed (DownloadableFile item )
446- throws IOException {
454+ throws IOException , SynologyException {
447455 byte [] mockImage = new byte [] {1 , 2 , 3 };
448456 InputStream mockInputStream = new ByteArrayInputStream (mockImage );
449457 InputStreamWrapper streamWrapper = mock (InputStreamWrapper .class );
@@ -474,7 +482,7 @@ public class SendPostRequestTest {
474482 private RequestBody requestBody = RequestBody .create (MediaType .parse ("application/json" ), "{}" );
475483
476484 @ Test
477- public void shouldRetryIfGotError () throws IOException {
485+ public void shouldRetryIfGotError () throws IOException , SynologyException {
478486 Call mockCall = mock (Call .class );
479487
480488 Response mockResponseFail = mock (Response .class );
@@ -522,7 +530,7 @@ public void shouldThrowExceptionIfReachMaxRetries() throws IOException {
522530
523531 @ Test
524532 public void shouldRefreshTokenAndRetryIfGotUnauthorizedHttpError ()
525- throws IOException , JsonProcessingException {
533+ throws IOException , JsonProcessingException , SynologyException {
526534 Call mockCall = mock (Call .class );
527535
528536 Response mockResponseFail = mock (Response .class );
@@ -597,7 +605,8 @@ public void shouldThrowExceptionIfParseResponseFailed() throws IOException {
597605 }
598606
599607 @ Test
600- public void shouldReturnResponseData () throws IOException , JsonProcessingException {
608+ public void shouldReturnResponseData ()
609+ throws IOException , JsonProcessingException , SynologyException {
601610 Response mockResponse = mock (Response .class );
602611 ResponseBody mockResponseBody = mock (ResponseBody .class );
603612 Call mockCall = mock (Call .class );
@@ -615,5 +624,104 @@ public void shouldReturnResponseData() throws IOException, JsonProcessingExcepti
615624 .refreshToken (any (UUID .class ), eq (client ), any (ObjectMapper .class ));
616625 verify (client , times (1 )).newCall (any (Request .class ));
617626 }
627+
628+ @ Test
629+ public void shouldThrowExceptionIfGot413 () throws IOException {
630+ Call mockCall = mock (Call .class );
631+
632+ Response mockResponseFail = mock (Response .class );
633+ when (mockResponseFail .code ()).thenReturn (413 );
634+ when (mockResponseFail .isSuccessful ()).thenReturn (false );
635+
636+ when (client .newCall (any (Request .class ))).thenReturn (mockCall );
637+ when (mockCall .execute ()).thenReturn (mockResponseFail );
638+
639+ SynologyImportException exception =
640+ assertThrows (
641+ SynologyImportException .class ,
642+ () -> dtpService .sendPostRequest (TestConfigs .TEST_C2_BASE_URL , requestBody , jobId ));
643+ assertEquals (FailureReasons .DESTINATION_FULL .toString (), exception .getFailureReason ());
644+ }
645+
646+ @ Test
647+ public void shouldCallCheckUnprocessableContentIfGot422 ()
648+ throws IOException , SynologyException {
649+ Call mockCall = mock (Call .class );
650+ SynologyDTPService spyService = Mockito .spy (dtpService );
651+
652+ Response mockResponseFail = mock (Response .class );
653+ ResponseBody mockResponseBody = mock (ResponseBody .class );
654+ when (mockResponseFail .code ()).thenReturn (422 );
655+ when (mockResponseFail .isSuccessful ()).thenReturn (false );
656+ when (mockResponseFail .body ()).thenReturn (mockResponseBody );
657+ when (mockResponseBody .string ())
658+ .thenReturn (
659+ "{\" error\" :{\" code\" :2000,\" message\" :\" User has not claimed C2 Storage"
660+ + " quota.\" }}" );
661+
662+ when (client .newCall (any (Request .class ))).thenReturn (mockCall );
663+ when (mockCall .execute ()).thenReturn (mockResponseFail );
664+
665+ SynologyImportException exception =
666+ assertThrows (
667+ SynologyImportException .class ,
668+ () -> spyService .sendPostRequest (TestConfigs .TEST_C2_BASE_URL , requestBody , jobId ));
669+ assertEquals (FailureReasons .NO_NAS_IN_ACCOUNT .toString (), exception .getFailureReason ());
670+ }
671+ }
672+
673+ @ Nested
674+ public class CheckUnprocessableContentTest {
675+ private Response mockResponse (String jsonBody ) {
676+ ResponseBody body = ResponseBody .create (MediaType .parse ("application/json" ), jsonBody );
677+ Response response = mock (Response .class );
678+ when (response .body ()).thenReturn (body );
679+ return response ;
680+ }
681+
682+ @ Test
683+ public void shouldThrowExceptionIfErrorCodeIs2000 () throws SynologyImportException {
684+ String jsonBody =
685+ "{\" error\" :{\" code\" : 2000,\" message\" :\" User has not claimed C2 Storage quota.\" }}" ;
686+ Response response = mockResponse (jsonBody );
687+
688+ SynologyImportException exception =
689+ assertThrows (
690+ SynologyImportException .class , () -> dtpService .checkUnprocessableContent (response ));
691+ assertEquals (FailureReasons .NO_NAS_IN_ACCOUNT .toString (), exception .getFailureReason ());
692+ }
693+
694+ @ Test
695+ public void shouldThrowExceptionIfErrorCodeIs2001 () throws SynologyImportException {
696+ String jsonBody =
697+ "{\" error\" :{\" code\" : 2001,\" message\" :\" C2 Storage quota is not enough.\" }}" ;
698+ Response response = mockResponse (jsonBody );
699+
700+ SynologyImportException exception =
701+ assertThrows (
702+ SynologyImportException .class , () -> dtpService .checkUnprocessableContent (response ));
703+ assertEquals (FailureReasons .NO_NAS_IN_ACCOUNT .toString (), exception .getFailureReason ());
704+ }
705+
706+ @ Test
707+ public void shouldNotThrowExceptionIfNoErrorCode () throws SynologyImportException {
708+ String jsonBody = "{\" data\" :{\" album_id\" :\" test_album_id\" }}" ;
709+ Response response = mockResponse (jsonBody );
710+ dtpService .checkUnprocessableContent (response );
711+ }
712+
713+ @ Test
714+ public void shouldNotThrowExceptionIfErrorCodeIsDifferent () throws SynologyImportException {
715+ String jsonBody = "{\" error\" :{\" code\" :\" 1000\" ,\" message\" :\" Some other error.\" }}" ;
716+ Response response = mockResponse (jsonBody );
717+ dtpService .checkUnprocessableContent (response );
718+ }
719+
720+ @ Test
721+ public void shouldNotThrowExceptionIfBodyIsInvalidJson () throws SynologyImportException {
722+ String jsonBody = "invalid-json" ;
723+ Response response = mockResponse (jsonBody );
724+ dtpService .checkUnprocessableContent (response );
725+ }
618726 }
619727}
0 commit comments