Skip to content

Commit 8db09f6

Browse files
committed
test: update Synology tests for new exception handling and add error cases
- Update tests to declare throws SynologyException or SynologyImportException where necessary. - Add test cases to SynologyDTPServiceTest for handling HTTP 413 (Payload Too Large) and mapping it to DESTINATION_FULL. - Add test cases to SynologyDTPServiceTest for handling HTTP 422 (Unprocessable Content) and mapping specific Synology error codes (2000, 2001) to NO_NAS_IN_ACCOUNT.
1 parent 625a054 commit 8db09f6

5 files changed

Lines changed: 164 additions & 40 deletions

File tree

extensions/data-transfer/portability-data-transfer-synology/src/test/java/org/datatransferproject/datatransfer/synology/service/SynologyDTPServiceTest.java

Lines changed: 129 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@
4848
import okhttp3.ResponseBody;
4949
import okio.Buffer;
5050
import org.datatransferproject.api.launcher.Monitor;
51+
import org.datatransferproject.datatransfer.synology.exceptions.SynologyException;
5152
import org.datatransferproject.datatransfer.synology.exceptions.SynologyImportException;
5253
import org.datatransferproject.datatransfer.synology.exceptions.SynologyMaxRetriesExceededException;
5354
import org.datatransferproject.datatransfer.synology.utils.TestConfigs;
5455
import org.datatransferproject.spi.cloud.storage.JobStore;
5556
import org.datatransferproject.spi.cloud.storage.TemporaryPerJobDataStore.InputStreamWrapper;
57+
import org.datatransferproject.spi.transfer.types.FailureReasons;
5658
import org.datatransferproject.types.common.DownloadableFile;
5759
import org.datatransferproject.types.common.models.media.MediaAlbum;
5860
import 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
}

extensions/data-transfer/portability-data-transfer-synology/src/test/java/org/datatransferproject/datatransfer/synology/service/SynologyOAuthTokenManagerTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void setUp() throws Exception {
6060
@Nested
6161
class OAuthTokenManagerBasicTest {
6262
@Test
63-
void shouldGetAccessTokenIfExist() {
63+
void shouldGetAccessTokenIfExist() throws SynologyImportException {
6464
UUID jobId = UUID.randomUUID();
6565
TokensAndUrlAuthData authData =
6666
new TokensAndUrlAuthData("accessToken", "refreshToken", "http://mock.token.url");
@@ -80,7 +80,7 @@ void shouldThrowExceptionIfJobIdNotFound() {
8080
}
8181

8282
@Test
83-
void shouldNotReplaceExistingAuthData() {
83+
void shouldNotReplaceExistingAuthData() throws SynologyImportException {
8484
UUID jobId = UUID.randomUUID();
8585
TokensAndUrlAuthData authData1 =
8686
new TokensAndUrlAuthData("accessToken1", "refreshToken1", "url1");
@@ -204,7 +204,8 @@ void shouldReturnFalseIfParseJsonFailed() throws IOException, JsonProcessingExce
204204
}
205205

206206
@Test
207-
void shouldUpdateTokenAndReturnTrue() throws IOException, JsonProcessingException {
207+
void shouldUpdateTokenAndReturnTrue()
208+
throws IOException, JsonProcessingException, SynologyImportException {
208209
UUID jobId = UUID.randomUUID();
209210
TokensAndUrlAuthData authData =
210211
new TokensAndUrlAuthData("oldAccessToken", "oldRefreshToken", "http://mock.token.url");

0 commit comments

Comments
 (0)