package org.commcare.android.tests; import org.commcare.CommCareApp; import org.commcare.CommCareApplication; import org.commcare.CommCareTestApplication; import org.commcare.android.CommCareTestRunner; import org.commcare.network.HttpRequestEndpointsMock; import org.commcare.android.util.TestAppInstaller; import org.commcare.network.LocalReferencePullResponseFactory; import org.commcare.tasks.DataPullTask; import org.commcare.tasks.ResultAndError; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; /** * Coverage for different DataPullTask codepaths. * Doesn't yet check logical correctness of any actions. * * @author Phillip Mates (pmates@dimagi.com) */ @Config(application = CommCareTestApplication.class) @RunWith(CommCareTestRunner.class) public class DataPullTaskTest { private final static String APP_BASE = "jr://resource/commcare-apps/form_nav_tests/"; private final static String GOOD_RESTORE = APP_BASE + "simple_data_restore.xml"; private final static String BAD_RESTORE_XML = APP_BASE + "bad_xml_data_restore.xml"; private final static String SELF_INDEXING_CASE_RESTORE = APP_BASE + "self_indexing_case_data_restore.xml"; private final static String RETRY_RESPONSE = APP_BASE + "async_restore_response.xml"; /** * Stores the result of the data pull task */ private static ResultAndError<DataPullTask.PullTaskResult> dataPullResult; private static DataPullTask pullTask; @Test public void dataPullWithMissingRemoteKeyRecordTest() { TestAppInstaller.installApp(APP_BASE + "profile.ccpr"); runDataPull(200, GOOD_RESTORE); Assert.assertEquals(DataPullTask.PullTaskResult.UNKNOWN_FAILURE, dataPullResult.data); Assert.assertEquals("Unable to get or generate encryption key", dataPullResult.errorMessage); } @Test public void dataPullWithLocalKeysTest() { installAndUseLocalKeys(); runDataPull(200, GOOD_RESTORE); } @Test public void dataPullServerErrorTest() { installAndUseLocalKeys(); runDataPull(500, GOOD_RESTORE); Assert.assertEquals(DataPullTask.PullTaskResult.SERVER_ERROR, dataPullResult.data); } @Test public void dataPullAuthFailedTest() { installAndUseLocalKeys(); runDataPull(401, GOOD_RESTORE); Assert.assertEquals(DataPullTask.PullTaskResult.AUTH_FAILED, dataPullResult.data); } @Test public void dataPullRecoverTest() { installLoginAndUseLocalKeys(); runDataPull(new Integer[]{412, 200}, new String[]{GOOD_RESTORE, GOOD_RESTORE}); Assert.assertEquals(DataPullTask.PullTaskResult.DOWNLOAD_SUCCESS, dataPullResult.data); } @Test public void dataPullRecoverFailTest() { installLoginAndUseLocalKeys(); runDataPull(new Integer[]{412, 500}, new String[]{GOOD_RESTORE, GOOD_RESTORE}); Assert.assertEquals(DataPullTask.PullTaskResult.UNKNOWN_FAILURE, dataPullResult.data); } @Test public void dataPullFailWithMessage() { installLoginAndUseLocalKeys(); HttpRequestEndpointsMock.setErrorResponseBody("{\"error\": \"some.fake.locale.key\", \"default_response\": \"hello world\"}"); runDataPull(406, GOOD_RESTORE); Assert.assertEquals(DataPullTask.PullTaskResult.ACTIONABLE_FAILURE, dataPullResult.data); Assert.assertEquals("hello world", dataPullResult.errorMessage); } @Test public void dataPullRecoverFailLoginNeededTest() { installWithUserAndUseLocalKeys(); runDataPull(new Integer[]{412, 500}, new String[]{GOOD_RESTORE, GOOD_RESTORE}); Assert.assertEquals(DataPullTask.PullTaskResult.UNKNOWN_FAILURE, dataPullResult.data); } @Test public void dataPullBadRecoverPayloadTest() { installLoginAndUseLocalKeys(); runDataPull(new Integer[]{412, 200}, new String[]{GOOD_RESTORE, BAD_RESTORE_XML}); Assert.assertEquals(DataPullTask.PullTaskResult.UNKNOWN_FAILURE, dataPullResult.data); } @Test public void dataPullBadRestoreXMLTest() { installAndUseLocalKeys(); runDataPull(200, BAD_RESTORE_XML); Assert.assertEquals(DataPullTask.PullTaskResult.BAD_DATA, dataPullResult.data); } @Test public void dataPullSelfIndexingCaseTest() { installAndUseLocalKeys(); runDataPull(200, SELF_INDEXING_CASE_RESTORE); Assert.assertEquals(DataPullTask.PullTaskResult.BAD_DATA_REQUIRES_INTERVENTION, dataPullResult.data); } @Test public void asyncRestoreTest() { installAndUseLocalKeys(); runDataPullWithAsyncRestore(); Assert.assertEquals(DataPullTask.PullTaskResult.DOWNLOAD_SUCCESS, dataPullResult.data); // Indicates that the task executed all of the retries we indicated, and then successfully // parsed the final success response Assert.assertEquals(4, LocalReferencePullResponseFactory.getNumRequestsMade()); // Indicates that the mock retry result was parsed correctly Assert.assertTrue(pullTask.getAsyncRestoreHelper().serverProgressCompletedSoFar == 55); } private static void runDataPullWithAsyncRestore() { runDataPull(new Integer[]{202, 202, 202, 200}, new String[]{RETRY_RESPONSE, RETRY_RESPONSE, RETRY_RESPONSE, GOOD_RESTORE}); } private static void runDataPull(Integer resultCode, String payloadResource) { runDataPull(new Integer[]{resultCode}, new String[]{payloadResource}); } private static void runDataPull(Integer[] resultCodes, String[] payloadResources) { HttpRequestEndpointsMock.setCaseFetchResponseCodes(resultCodes); LocalReferencePullResponseFactory.setRequestPayloads(payloadResources); DataPullTask<Object> task = new DataPullTask<Object>("test", "123", null, "fake.server.com", RuntimeEnvironment.application, LocalReferencePullResponseFactory.INSTANCE, false) { @Override protected void deliverResult(Object o, ResultAndError<PullTaskResult> pullTaskResultResultAndError) { dataPullResult = pullTaskResultResultAndError; } @Override protected void deliverUpdate(Object o, Integer... update) { } @Override protected void deliverError(Object o, Exception e) { } }; task.connect(TestAppInstaller.fakeConnector); task.execute(); pullTask = task; Robolectric.flushBackgroundThreadScheduler(); Robolectric.flushForegroundThreadScheduler(); } private void installAndUseLocalKeys() { TestAppInstaller.installApp(APP_BASE + "profile.ccpr"); useLocalKeys(); } private void installLoginAndUseLocalKeys() { TestAppInstaller.installAppAndLogin(APP_BASE + "profile.ccpr", "test", "123"); useLocalKeys(); } private void installWithUserAndUseLocalKeys() { TestAppInstaller.installAppAndUser(APP_BASE + "profile.ccpr", "test", "123"); useLocalKeys(); } private static void useLocalKeys() { CommCareApp app = CommCareApplication.instance().getCurrentApp(); app.getAppPreferences().edit().putString("key_server", null).commit(); } }