/* * Copyright (c) 2015-present, Parse, LLC. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.parse; import com.parse.http.ParseHttpBody; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; import bolts.Task; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class ParseRequestTest { private static byte[] data; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @BeforeClass public static void setUpClass() { char[] chars = new char[64 << 10]; // 64KB data = new String(chars).getBytes(); } @AfterClass public static void tearDownClass() { data = null; } @Before public void setUp() { ParseRequest.setDefaultInitialRetryDelay(1L); } @After public void tearDown() { ParseRequest.setDefaultInitialRetryDelay(ParseRequest.DEFAULT_INITIAL_RETRY_DELAY); } @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)); } // TODO(grantland): Move to ParseFileRequestTest or ParseCountingByteArrayHttpBodyTest @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); } private static void assertProgressCompletedSuccessfully(TestProgressCallback callback) { int lastPercentDone = 0; boolean incrementalPercentage = false; for (int percentDone : callback.history) { assertTrue("Progress went backwards", percentDone >= lastPercentDone); assertTrue("Invalid percentDone: " + percentDone, percentDone >= 0 && percentDone <= 100); if (percentDone > 0 || percentDone < 100) { incrementalPercentage = true; } lastPercentDone = percentDone; } assertTrue("ProgressCallback was not called with a value between 0 and 100: " + callback.history, incrementalPercentage); assertEquals(100, callback.history.get(callback.history.size() - 1).intValue()); } private static class TestProgressCallback implements ProgressCallback { List<Integer> history = new LinkedList<>(); @Override public void done(Integer percentDone) { history.add(percentDone); } } private static class TestParseRequest extends ParseRequest<String> { public TestParseRequest(ParseHttpRequest.Method method, String url) { super(method, url); } byte[] data; @Override protected Task<String> onResponseAsync( ParseHttpResponse response, ProgressCallback downloadProgressCallback) { return Task.forResult(null); } @Override protected ParseHttpBody newBody(ProgressCallback uploadProgressCallback) { if (uploadProgressCallback != null) { return new ParseCountingByteArrayHttpBody(data, null, uploadProgressCallback); } return super.newBody(null); } } }