aboutsummaryrefslogtreecommitdiff
path: root/test/storage/MigrationTest.mc
diff options
context:
space:
mode:
Diffstat (limited to 'test/storage/MigrationTest.mc')
-rw-r--r--test/storage/MigrationTest.mc69
1 files changed, 69 insertions, 0 deletions
diff --git a/test/storage/MigrationTest.mc b/test/storage/MigrationTest.mc
new file mode 100644
index 0000000..046ee04
--- /dev/null
+++ b/test/storage/MigrationTest.mc
@@ -0,0 +1,69 @@
+// Author: cirakg & claude ai
+// Summary: Tests for schema migration: fresh store, the v0 fixture to v1, idempotency, newer and damaged metadata.
+
+import Toybox.Application;
+import Toybox.Lang;
+import Toybox.Test;
+
+(:test)
+function migrationCreatesFreshMetadata(logger as Test.Logger) as Boolean {
+ var store = new MemoryBackend();
+ var vault = new Vault(store, new FakeTime());
+ var meta = store.getValue(Migration.META_KEY) as Dictionary<Application.Storage.KeyType, Application.Storage.ValueType>;
+ return vault.ids().size() == 0 && (meta["schema"] as Number) == Migration.CURRENT;
+}
+
+// The v0 fixture: entries written in the current record format, listed by
+// the old "order" key. After migration they open as before, and running the
+// migration again changes nothing.
+(:test)
+function migrationV0ToV1(logger as Test.Logger) as Boolean {
+ var store = new MemoryBackend();
+ var vault = new Vault(store, new FakeTime());
+ var a = vault.add(StorageFixtures.totp("A"));
+ var b = vault.add(StorageFixtures.code("B"));
+ store.setValue(Migration.META_KEY, {"order" => [b, a]});
+ var migrated = new Vault(store, new FakeTime());
+ var ids = migrated.ids();
+ var meta = store.getValue(Migration.META_KEY) as Dictionary<Application.Storage.KeyType, Application.Storage.ValueType>;
+ var opened = migrated.open(a);
+ opened.wipeSecrets();
+ var again = new Vault(store, new FakeTime());
+ return ids.size() == 2 && ids[0].equals(b) && ids[1].equals(a) && (meta["schema"] as Number) == 1
+ && !meta.hasKey("order") && again.ids().size() == 2 && again.pendingIds().size() == 0;
+}
+
+(:test)
+function migrationRefusesNewerAndDamagedMetadata(logger as Test.Logger) as Boolean {
+ var cases = [
+ {"schema" => Migration.CURRENT + 1, "ids" => [], "pending" => []},
+ "not a dictionary",
+ {"schema" => "1", "ids" => [], "pending" => []},
+ {"schema" => 1, "ids" => ["K7F2", "K7F2"], "pending" => []},
+ {"schema" => 1, "ids" => ["bad"], "pending" => []},
+ {"schema" => 1, "ids" => [], "pending" => 5}
+ ];
+ var expected = [VaultError.NEWER_SCHEMA, VaultError.DAMAGED, VaultError.DAMAGED, VaultError.DAMAGED,
+ VaultError.DAMAGED, VaultError.DAMAGED];
+ for (var i = 0; i < cases.size(); i++) {
+ var store = new MemoryBackend();
+ store.setValue(Migration.META_KEY, cases[i] as Application.Storage.ValueType);
+ var code = 0;
+ try {
+ new Vault(store, new FakeTime());
+ } catch (err instanceof VaultError) {
+ code = err.code;
+ }
+ if (code != expected[i]) {
+ logger.error("case " + i + ": got " + code);
+ return false;
+ }
+ // Newer or damaged data is never modified.
+ var after = store.getValue(Migration.META_KEY);
+ if (cases[i] instanceof String ? !(after as String).equals(cases[i] as String) : MemoryBackend.sizeOf(after) != MemoryBackend.sizeOf(cases[i] as Application.Storage.ValueType)) {
+ logger.error("case " + i + ": metadata was modified");
+ return false;
+ }
+ }
+ return true;
+}