1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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;
}
|