void waitUntilFinished() throws InterruptedException { lock.lock(); try { if (tail == null) { return; } tail.waitForCompletion(); } finally { lock.unlock(); } } }
@Test public void testRetryLogic() throws Exception { ParseHttpClient mockHttpClient = mock(ParseHttpClient.class); when(mockHttpClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); TestParseRequest request = new TestParseRequest(ParseHttpRequest.Method.GET, "http://parse.com"); Task<String> task = request.executeAsync(mockHttpClient); task.waitForCompletion(); verify(mockHttpClient, times(5)).execute(any(ParseHttpRequest.class)); }
@Test public void testSaveAsyncCancelled() throws Exception { ParseFileController controller = mock(ParseFileController.class); when(controller.isDataAvailable(any(ParseFile.State.class))).thenReturn(true); ParseCorePlugins.getInstance().registerFileController(controller); ParseFile.State state = new ParseFile.State.Builder().build(); ParseFile file = new ParseFile(state); Task<Void> task = file.saveAsync(null, null, Task.<Void>cancelled()); task.waitForCompletion(); assertTrue(task.isCancelled()); verify(controller, never()).saveAsync( any(ParseFile.State.class), any(byte[].class), any(String.class), any(ProgressCallback.class), Matchers.<Task<Void>>any()); }
@Test public void testCallFunctionInBackgroundFailure() throws Exception { // TODO(mengyan): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); ParseHttpClient restClient = mock(ParseHttpClient.class); when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); ParseCloudCodeController controller = new ParseCloudCodeController(restClient); Task<String> cloudCodeTask = controller.callFunctionInBackground("test", new HashMap<String, Object>(), "sessionToken"); // Do not use ParseTaskUtils.wait() since we do not want to throw the exception cloudCodeTask.waitForCompletion(); // TODO(mengyan): Abstract out command runner so we don't have to account for retries. verify(restClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(cloudCodeTask.isFaulted()); Exception error = cloudCodeTask.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); }
@Test public void testSaveAsyncAlreadyCancelled() throws Exception { ParseHttpClient restClient = mock(ParseHttpClient.class); ParseFileController controller = new ParseFileController(restClient, null); ParseFile.State state = new ParseFile.State.Builder().build(); Task<Void> cancellationToken = Task.cancelled(); Task<ParseFile.State> task = controller.saveAsync(state, (byte[]) null, null, null, cancellationToken); task.waitForCompletion(); verify(restClient, times(0)).execute(any(ParseHttpRequest.class)); assertTrue(task.isCancelled()); }
@Test public void testSubscribeInBackgroundFail() throws Exception { ParsePushChannelsController controller = mock(ParsePushChannelsController.class); ParseException exception = new ParseException(ParseException.OTHER_CAUSE, "error"); when(controller.subscribeInBackground(anyString())).thenReturn(Task.<Void>forError(exception)); ParseCorePlugins.getInstance().registerPushChannelsController(controller); Task<Void> pushTask = ParsePush.subscribeInBackground("test"); pushTask.waitForCompletion(); verify(controller, times(1)).subscribeInBackground("test"); assertTrue(pushTask.isFaulted()); assertSame(exception, pushTask.getError()); }
@Test public void testFetchAsyncAlreadyCancelled() throws Exception { ParseHttpClient fileClient = mock(ParseHttpClient.class); ParseFileController controller = new ParseFileController(null, null).fileClient(fileClient); ParseFile.State state = new ParseFile.State.Builder().build(); Task<Void> cancellationToken = Task.cancelled(); Task<File> task = controller.fetchAsync(state, null, null, cancellationToken); task.waitForCompletion(); verify(fileClient, times(0)).execute(any(ParseHttpRequest.class)); assertTrue(task.isCancelled()); }
@Test public void testUnsubscribeInBackgroundFail() throws Exception { ParsePushChannelsController controller = mock(ParsePushChannelsController.class); ParseException exception = new ParseException(ParseException.OTHER_CAUSE, "error"); when(controller.unsubscribeInBackground(anyString())) .thenReturn(Task.<Void>forError(exception)); ParseCorePlugins.getInstance().registerPushChannelsController(controller); Task<Void> pushTask = ParsePush.unsubscribeInBackground("test"); pushTask.waitForCompletion(); verify(controller, times(1)).unsubscribeInBackground("test"); assertTrue(pushTask.isFaulted()); assertSame(exception, pushTask.getError()); }
@Test public void testGetAsyncFailureWithConnectionFailure() throws Exception { // TODO(mengyan): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); // Make ParseConfigController and call getAsync ParseHttpClient restClient = mock(ParseHttpClient.class); when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); ParseCurrentConfigController currentConfigController = mockParseCurrentConfigController(); ParseConfigController configController = new ParseConfigController(restClient, currentConfigController); Task<ParseConfig> configTask = configController.getAsync(null); // Do not use ParseTaskUtils.wait() since we do not want to throw the exception configTask.waitForCompletion(); // Verify httpClient is tried enough times // TODO(mengyan): Abstract out command runner so we don't have to account for retries. verify(restClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(configTask.isFaulted()); Exception error = configTask.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); // Verify currentConfigController is not called verify(currentConfigController, times(0)).setCurrentConfigAsync(any(ParseConfig.class)); }
@Test public void testPermanentFailures() throws Exception { JSONObject json = new JSONObject(); json.put("code", 1337); json.put("error", "mock error"); ParseHttpResponse response = newMockParseHttpResponse(400, json); ParseHttpClient client = mock(ParseHttpClient.class); when(client.execute(any(ParseHttpRequest.class))).thenReturn(response); ParseRESTCommand command = new ParseRESTCommand.Builder() .method(ParseHttpRequest.Method.GET) .installationId("fake_installation_id") .build(); Task<JSONObject> task = command.executeAsync(client); task.waitForCompletion(); verify(client, times(1)).execute(any(ParseHttpRequest.class)); assertTrue(task.isFaulted()); assertEquals(1337, ((ParseException) task.getError()).getCode()); assertEquals("mock error", task.getError().getMessage()); }
@Test public void testSaveAsyncFailureWithByteArray() throws Exception { // TODO(grantland): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); ParseHttpClient restClient = mock(ParseHttpClient.class); when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); File root = temporaryFolder.getRoot(); ParseFileController controller = new ParseFileController(restClient, root); byte[] data = "hello".getBytes(); ParseFile.State state = new ParseFile.State.Builder() .build(); Task<ParseFile.State> task = controller.saveAsync(state, data, null, null, null); task.waitForCompletion(); // TODO(grantland): Abstract out command runner so we don't have to account for retries. verify(restClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(task.isFaulted()); Exception error = task.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); assertEquals(0, root.listFiles().length); }
@Test public void testSendInBackgroundFailWithIOException() throws Exception { // TODO(mengyan): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); ParseHttpClient restClient = mock(ParseHttpClient.class); when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); ParsePushController controller = new ParsePushController(restClient); JSONObject data = new JSONObject(); data.put(ParsePush.KEY_DATA_MESSAGE, "hello world"); ParsePush.State state = new ParsePush.State.Builder() .data(data) .build(); Task<Void> pushTask = controller.sendInBackground(state, "sessionToken"); // Do not use ParseTaskUtils.wait() since we do not want to throw the exception pushTask.waitForCompletion(); // Verify httpClient is tried enough times // TODO(mengyan): Abstract out command runner so we don't have to account for retries. verify(restClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(pushTask.isFaulted()); Exception error = pushTask.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); }
/** * Test to verify that handle 401 unauthorized */ @Test public void test401Unauthorized() throws Exception { JSONObject json = new JSONObject(); json.put("error", "unauthorized"); ParseHttpResponse response = newMockParseHttpResponse(401, json); ParseHttpClient client = mock(ParseHttpClient.class); when(client.execute(any(ParseHttpRequest.class))).thenReturn(response); ParseRESTCommand command = new ParseRESTCommand.Builder() .method(ParseHttpRequest.Method.GET) .installationId("fake_installation_id") .build(); Task<JSONObject> task = command.executeAsync(client); task.waitForCompletion(); verify(client, times(1)).execute(any(ParseHttpRequest.class)); assertTrue(task.isFaulted()); assertEquals(0, ((ParseException) task.getError()).getCode()); assertEquals("unauthorized", task.getError().getMessage()); }
@Test public void testSaveAsyncFailureWithFile() throws Exception { // TODO(grantland): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); ParseHttpClient restClient = mock(ParseHttpClient.class); when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); File root = temporaryFolder.getRoot(); ParseFileController controller = new ParseFileController(restClient, root); File file = temporaryFolder.newFile("test"); ParseFile.State state = new ParseFile.State.Builder() .build(); Task<ParseFile.State> task = controller.saveAsync(state, file, null, null, null); task.waitForCompletion(); // TODO(grantland): Abstract out command runner so we don't have to account for retries. verify(restClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(task.isFaulted()); Exception error = task.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); // Make sure the original file is not deleted and there is no cache file in the folder assertEquals(1, root.listFiles().length); assertTrue(file.exists()); }
@Test public void testFetchAsyncFailure() throws Exception { // TODO(grantland): Remove once we no longer rely on retry logic. ParseRequest.setDefaultInitialRetryDelay(1L); ParseHttpClient fileClient = mock(ParseHttpClient.class); when(fileClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException()); File root = temporaryFolder.getRoot(); ParseFileController controller = new ParseFileController(null, root).fileClient(fileClient); // We need to set url to make getTempFile() work and check it ParseFile.State state = new ParseFile.State.Builder() .url("test") .build(); Task<File> task = controller.fetchAsync(state, null, null, null); task.waitForCompletion(); // TODO(grantland): Abstract out command runner so we don't have to account for retries. verify(fileClient, times(5)).execute(any(ParseHttpRequest.class)); assertTrue(task.isFaulted()); Exception error = task.getError(); assertThat(error, instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode()); assertEquals(0, root.listFiles().length); assertFalse(controller.getTempFile(state).exists()); }
@Test public void testSaveAsyncNotDirty() throws Exception { ParseHttpClient restClient = mock(ParseHttpClient.class); ParseFileController controller = new ParseFileController(restClient, null); ParseFile.State state = new ParseFile.State.Builder() .url("http://example.com") .build(); Task<ParseFile.State> task = controller.saveAsync(state, (byte[]) null, null, null, null); task.waitForCompletion(); verify(restClient, times(0)).execute(any(ParseHttpRequest.class)); assertFalse(task.isFaulted()); assertFalse(task.isCancelled()); assertSame(state, task.getResult()); }
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @Test public void testGetInBackgroundFail() throws Exception { ParseException exception = new ParseException(ParseException.CONNECTION_FAILED, "error"); ParseConfigController controller = mockParseConfigControllerWithException(exception); ParseCorePlugins.getInstance().registerConfigController(controller); Task<ParseConfig> configTask = ParseConfig.getInBackground(); configTask.waitForCompletion(); verify(controller, times(1)).getAsync(anyString()); assertThat(configTask.getError(), instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) configTask.getError()).getCode()); assertEquals("error", configTask.getError().getMessage()); }
@Test public void testDownloadProgress() throws Exception { ParseHttpResponse mockResponse = new ParseHttpResponse.Builder() .setStatusCode(200) .setTotalSize((long) data.length) .setContent(new ByteArrayInputStream(data)) .build(); ParseHttpClient mockHttpClient = mock(ParseHttpClient.class); when(mockHttpClient.execute(any(ParseHttpRequest.class))).thenReturn(mockResponse); File tempFile = temporaryFolder.newFile("test"); ParseFileRequest request = new ParseFileRequest(ParseHttpRequest.Method.GET, "localhost", tempFile); TestProgressCallback downloadProgressCallback = new TestProgressCallback(); Task<Void> task = request.executeAsync(mockHttpClient, null, downloadProgressCallback); task.waitForCompletion(); assertFalse("Download failed: " + task.getError(), task.isFaulted()); assertEquals(data.length, ParseFileUtils.readFileToByteArray(tempFile).length); assertProgressCompletedSuccessfully(downloadProgressCallback); }
@Test public void testParcelWhileDeletingWithLDSEnabled() throws Exception { mockCurrentUserController(); TaskCompletionSource<Void> tcs = mockObjectControllerForDelete(); ParseObject object = new ParseObject("TestObject"); object.setObjectId("id"); OfflineStore lds = mock(OfflineStore.class); when(lds.getObject("TestObject", "id")).thenReturn(object); Parse.setLocalDatastore(lds); Task<Void> deleteTask = object.deleteInBackground(); assertTrue(object.isDeleting); Parcel parcel = Parcel.obtain(); object.writeToParcel(parcel, 0); parcel.setDataPosition(0); ParseObject other = ParseObject.CREATOR.createFromParcel(parcel); assertSame(object, other); assertTrue(other.isDeleting); // Still deleting tcs.setResult(null); deleteTask.waitForCompletion(); // complete deletion on original object. assertFalse(other.isDeleting); assertTrue(other.isDeleted); Parse.setLocalDatastore(null); }
@Test public void testParcelWhileDeleting() throws Exception { mockCurrentUserController(); TaskCompletionSource<Void> tcs = mockObjectControllerForDelete(); ParseObject object = new ParseObject("TestObject"); object.setObjectId("id"); Task<Void> deleteTask = object.deleteInBackground(); // ensure Log.w is called.. assertTrue(object.isDeleting); Parcel parcel = Parcel.obtain(); object.writeToParcel(parcel, 0); parcel.setDataPosition(0); ParseObject other = ParseObject.CREATOR.createFromParcel(parcel); // By design, when LDS is off, we assume that old operations failed even if // they are still running on the old instance. assertFalse(other.isDeleting); assertTrue(object.isDeleting); tcs.setResult(null); deleteTask.waitForCompletion(); assertFalse(object.isDeleting); assertTrue(object.isDeleted); }