getodk / collect

ODK Collect is an Android app for filling out forms. It's been used to collect billions of data points in challenging environments around the world. Contribute and make the world a better place! ✨📋✨
https://docs.getodk.org/collect-intro
Other
717 stars 1.38k forks source link

Draft with no actual file is created when there is a crash during finalization #6522

Open seadowg opened 2 days ago

seadowg commented 2 days ago

This is challenging to reproduce as there are no known routes to causing a crash during form finalization. However, any future bugs that do end up causing a crash here will lead to a really confusing scenario.

The easiest way to simulate the scenario is to change the above linked line to throw new IllegalStateException(). Then carry out the following steps:

  1. Start a new form, go to the end screen and hit finalize
  2. Open Drafts
  3. Click on the new draft

You'll see that there is an error and the draft then disappears. This is because the instances DB gets updated with the new instance, but the submission XML itself is never written to disk so the (correct) error handling that accounts for this scenario (instance in the DB, but not on disk) kicks and fixes the mismatch.

Instead of this, if there is a crash while finalizing, no draft should be created.

lognaturel commented 1 day ago

If I start with a blank form and get into this state, I do get a savepoint. If I open the "ghost draft" before I open the savepoint, I get an error when trying to save a draft from that savepoint:

java.io.FileNotFoundException: /storage/emulated/0/Android/data/org.odk.collect.android/files/projects/DEMO/instances/All question types_2024-11-21_10-27-13/All question types_2024-11-21_10-27-13.xml: open failed: ENOENT (No such file or directory)
   at libcore.io.IoBridge.open(IoBridge.java:574)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:259)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:208)
   at org.odk.collect.shared.files.FileExt.saveToFile(FileExt.kt:49)
   at org.odk.collect.android.tasks.SaveFormToDisk.writeFile(SaveFormToDisk.java:489)

This feels like the worst part of this whole situation.

If I don't open the "ghost draft" first, I can open the savepoint and save it as draft.

What I was most worried about was if you had saved a draft, made edits to that draft, and then attempted to finalize. It looks like that does save the updates as draft which is good.