From 8cf76590505fa59aeefa96ddcb0e54faedbfb8d8 Mon Sep 17 00:00:00 2001 From: Callum Stott Date: Thu, 5 Oct 2023 13:16:17 +0100 Subject: [PATCH] Fail to finalize instances with save points --- .../formmanagement/BulkFinalizationTest.kt | 25 ++++++++++++++++++- .../odk/collect/android/support/pages/Page.kt | 24 ++++++++++++++++++ .../android/formentry/FormEntryUseCases.kt | 17 ++++++++++++- .../formmanagement/InstancesDataService.kt | 22 ++++++++++------ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/BulkFinalizationTest.kt b/collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/BulkFinalizationTest.kt index 0ce753c1c60..e4e76603bd9 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/BulkFinalizationTest.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/BulkFinalizationTest.kt @@ -86,7 +86,30 @@ class BulkFinalizationTest { } @Test - fun doesNotFinalizeOtherTypesOfInstance() { + fun doesNotFinalizeInstancesWithSavePoints() { + rule.startAtMainMenu() + .copyForm("one-question.xml") + .startBlankForm("One Question") + .swipeToEndScreen() + .clickSaveAsDraft() + + .clickEditSavedForm() + .clickOnForm("One Question") + .killAndReopenApp(MainMenuPage()) + + .clickEditSavedForm() + .clickOptionsIcon(string.finalize_all_forms) + .clickOnString(string.finalize_all_forms) + .checkIsSnackbarWithQuantityDisplayed(plurals.bulk_finalize_failure, 1) + .assertText("One Question") + .pressBack(MainMenuPage()) + + .assertNumberOfEditableForms(1) + .assertNumberOfFinalizedForms(0) + } + + @Test + fun doesNotFinalizeAlreadyFinalizedInstances() { rule.startAtMainMenu() .copyForm("one-question.xml") .startBlankForm("One Question") diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/Page.kt b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/Page.kt index fb4839ba74a..138f5dd2ac3 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/Page.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/Page.kt @@ -30,15 +30,20 @@ import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withHint import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector import org.hamcrest.CoreMatchers.not import org.hamcrest.Matchers.allOf import org.hamcrest.core.StringContains.containsString import org.hamcrest.core.StringEndsWith.endsWith import org.junit.Assert +import org.odk.collect.android.BuildConfig import org.odk.collect.android.R import org.odk.collect.android.application.Collect import org.odk.collect.android.storage.StoragePathProvider import org.odk.collect.android.support.ActivityHelpers +import org.odk.collect.android.support.CollectHelpers import org.odk.collect.android.support.WaitFor.wait250ms import org.odk.collect.android.support.WaitFor.waitFor import org.odk.collect.android.support.actions.RotateAction @@ -450,6 +455,25 @@ abstract class Page> { return this as T } + fun ?> killAndReopenApp(destination: D): D { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + // kill + device.pressRecentApps() + device + .findObject(UiSelector().descriptionContains("Collect")) + .swipeUp(10).also { + CollectHelpers.simulateProcessRestart() // the process is not restarted automatically (probably to keep the test running) so we have simulate it + } + + // reopen + InstrumentationRegistry.getInstrumentation().targetContext.apply { + val intent = packageManager.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID)!! + startActivity(intent) + } + return destination!!.assertOnPage() + } + companion object { private fun rotateToLandscape(): ViewAction { return RotateAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) diff --git a/collect_app/src/main/java/org/odk/collect/android/formentry/FormEntryUseCases.kt b/collect_app/src/main/java/org/odk/collect/android/formentry/FormEntryUseCases.kt index 54384fca25b..a93854a4177 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formentry/FormEntryUseCases.kt +++ b/collect_app/src/main/java/org/odk/collect/android/formentry/FormEntryUseCases.kt @@ -25,7 +25,11 @@ object FormEntryUseCases { @JvmStatic fun loadFormDef(xForm: File, projectRootDir: File, formMediaDir: File): FormDef? { - FormUtils.setupReferenceManagerForForm(ReferenceManager.instance(), projectRootDir, formMediaDir) + FormUtils.setupReferenceManagerForForm( + ReferenceManager.instance(), + projectRootDir, + formMediaDir + ) return createFormDefFromCacheOrXml(xForm) } @@ -62,6 +66,17 @@ object FormEntryUseCases { ) } + fun getSavePoint(formController: FormController, cacheDir: File): File? { + val instanceXml = formController.getInstanceFile()!! + val savepointFile = File(cacheDir, "${instanceXml.name}.save") + + return if (savepointFile.exists() && savepointFile.lastModified() > instanceXml.lastModified()) { + savepointFile + } else { + null + } + } + fun saveDraft( formController: JavaRosaFormController, instancesRepository: InstancesRepository, diff --git a/collect_app/src/main/java/org/odk/collect/android/formmanagement/InstancesDataService.kt b/collect_app/src/main/java/org/odk/collect/android/formmanagement/InstancesDataService.kt index 024acd2c82a..e42c8749404 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formmanagement/InstancesDataService.kt +++ b/collect_app/src/main/java/org/odk/collect/android/formmanagement/InstancesDataService.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import org.odk.collect.android.entities.EntitiesRepositoryProvider import org.odk.collect.android.formentry.FormEntryUseCases import org.odk.collect.android.storage.StoragePathProvider +import org.odk.collect.android.storage.StorageSubdirectory import org.odk.collect.android.utilities.FileUtils import org.odk.collect.android.utilities.FormsRepositoryProvider import org.odk.collect.android.utilities.InstancesRepositoryProvider @@ -70,16 +71,21 @@ class InstancesDataService( val formController = FormEntryUseCases.loadDraft(formEntryController, formMediaDir, instanceFile) - val instance = FormEntryUseCases.finalizeDraft( - formController, - instancesRepository, - entitiesRepository - ) + val cacheDir = storagePathProvider.getOdkDirPath(StorageSubdirectory.CACHE) + if (FormEntryUseCases.getSavePoint(formController, File(cacheDir)) == null) { + val finalizedInstance = FormEntryUseCases.finalizeDraft( + formController, + instancesRepository, + entitiesRepository + ) - if (instance == null) { - failCount + 1 + if (finalizedInstance == null) { + failCount + 1 + } else { + failCount + } } else { - failCount + failCount + 1 } }