tka: reduce boilerplate code in the tests

Updates #cleanup

Change-Id: Id69d509f5e470fb5fb50b5c5c4ca61f000389c53
Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
Alex Chan
2026-04-28 10:25:55 +01:00
committed by Alex Chan
parent cb239808a6
commit 0ac09721df
7 changed files with 63 additions and 109 deletions
+16
View File
@@ -320,6 +320,22 @@ func optTemplate(name string, template AUM) testchainOpt {
} }
} }
func genesisTemplate(key Key) testchainOpt {
return optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}})
}
func checkpointTemplate() testchainOpt {
fakeState := &State{
Keys: []Key{{Kind: Key25519, Votes: 1}},
DisablementValues: [][]byte{bytes.Repeat([]byte{1}, 32)},
}
return optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})
}
func optKey(name string, key Key, priv ed25519.PrivateKey) testchainOpt { func optKey(name string, key Key, priv ed25519.PrivateKey) testchainOpt {
return testchainOpt{ return testchainOpt{
Name: name, Name: name,
+1 -5
View File
@@ -14,11 +14,7 @@ func TestGenerateDeeplink(t *testing.T) {
G1 -> L1 G1 -> L1
G1.template = genesis G1.template = genesis
`, `, genesisTemplate(key),
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
) )
a, _ := Open(c.Chonk()) a, _ := Open(c.Chonk())
+1 -4
View File
@@ -147,10 +147,7 @@ func testScenario(t *testing.T, sharedChain string, sharedOptions ...testchainOp
pub, priv := testingKey25519(t, 1) pub, priv := testingKey25519(t, 1)
key := Key{Kind: Key25519, Public: pub, Votes: 1} key := Key{Kind: Key25519, Public: pub, Votes: 1}
sharedOptions = append(sharedOptions, sharedOptions = append(sharedOptions,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optKey("key", key, priv), optKey("key", key, priv),
optSignAllUsing("key")) optSignAllUsing("key"))
+4 -10
View File
@@ -173,11 +173,8 @@ func TestSigNested_DeepNesting(t *testing.T) {
} }
// Test this works with our public API // Test this works with our public API
a, _ := Open(newTestchain(t, "G1\nG1.template = genesis", c := newTestchain(t, "G1\nG1.template = genesis", genesisTemplate(k))
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ a, _ := Open(c.Chonk())
Keys: []Key{k},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}})).Chonk())
if err := a.NodeKeyAuthorized(lastNodeKey.Public(), outer.Serialize()); err != nil { if err := a.NodeKeyAuthorized(lastNodeKey.Public(), outer.Serialize()); err != nil {
t.Errorf("NodeKeyAuthorized(lastNodeKey) failed: %v", err) t.Errorf("NodeKeyAuthorized(lastNodeKey) failed: %v", err)
} }
@@ -238,11 +235,8 @@ func TestSigCredential(t *testing.T) {
} }
// Test someone can't misuse our public API for verifying node-keys // Test someone can't misuse our public API for verifying node-keys
a, _ := Open(newTestchain(t, "G1\nG1.template = genesis", c := newTestchain(t, "G1\nG1.template = genesis", genesisTemplate(k))
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ a, _ := Open(c.Chonk())
Keys: []Key{k},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}})).Chonk())
if err := a.NodeKeyAuthorized(node.Public(), nestedSig.Serialize()); err == nil { if err := a.NodeKeyAuthorized(node.Public(), nestedSig.Serialize()); err == nil {
t.Error("NodeKeyAuthorized(SigCredential, node) did not fail") t.Error("NodeKeyAuthorized(SigCredential, node) did not fail")
} }
+28 -49
View File
@@ -11,21 +11,29 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
// getSyncOffer returns a SyncOffer for the given Chonk.
func getSyncOffer(t *testing.T, storage Chonk) SyncOffer {
t.Helper()
a, err := Open(storage)
if err != nil {
t.Fatal(err)
}
offer, err := a.SyncOffer(storage)
if err != nil {
t.Fatal(err)
}
return offer
}
func TestSyncOffer(t *testing.T) { func TestSyncOffer(t *testing.T) {
c := newTestchain(t, ` c := newTestchain(t, `
A1 -> A2 -> A3 -> A4 -> A5 -> A6 -> A7 -> A8 -> A9 -> A10 A1 -> A2 -> A3 -> A4 -> A5 -> A6 -> A7 -> A8 -> A9 -> A10
A10 -> A11 -> A12 -> A13 -> A14 -> A15 -> A16 -> A17 -> A18 A10 -> A11 -> A12 -> A13 -> A14 -> A15 -> A16 -> A17 -> A18
A18 -> A19 -> A20 -> A21 -> A22 -> A23 -> A24 -> A25 A18 -> A19 -> A20 -> A21 -> A22 -> A23 -> A24 -> A25
`) `)
storage := c.Chonk() got := getSyncOffer(t, c.Chonk())
a, err := Open(storage)
if err != nil {
t.Fatal(err)
}
got, err := a.SyncOffer(storage)
if err != nil {
t.Fatal(err)
}
// A SyncOffer includes a selection of AUMs going backwards in the tree, // A SyncOffer includes a selection of AUMs going backwards in the tree,
// progressively skipping more and more each iteration. // progressively skipping more and more each iteration.
@@ -52,24 +60,10 @@ func TestComputeSyncIntersection_FastForward(t *testing.T) {
a1H, a2H := c.AUMHashes["A1"], c.AUMHashes["A2"] a1H, a2H := c.AUMHashes["A1"], c.AUMHashes["A2"]
chonk1 := c.ChonkWith("A1", "A2") chonk1 := c.ChonkWith("A1", "A2")
n1, err := Open(chonk1) offer1 := getSyncOffer(t, chonk1)
if err != nil {
t.Fatal(err)
}
offer1, err := n1.SyncOffer(chonk1)
if err != nil {
t.Fatal(err)
}
chonk2 := c.Chonk() // All AUMs chonk2 := c.Chonk() // All AUMs
n2, err := Open(chonk2) offer2 := getSyncOffer(t, chonk2)
if err != nil {
t.Fatal(err)
}
offer2, err := n2.SyncOffer(chonk2)
if err != nil {
t.Fatal(err)
}
// Node 1 only knows about the first two nodes, so the head of n2 is // Node 1 only knows about the first two nodes, so the head of n2 is
// alien to it. // alien to it.
@@ -123,40 +117,28 @@ func TestComputeSyncIntersection_ForkSmallDiff(t *testing.T) {
} }
chonk1 := c.ChonkWith("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "F1") chonk1 := c.ChonkWith("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "F1")
n1, err := Open(chonk1) offer1 := getSyncOffer(t, chonk1)
if err != nil { want1 := SyncOffer{
t.Fatal(err)
}
offer1, err := n1.SyncOffer(chonk1)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(SyncOffer{
Head: c.AUMHashes["F1"], Head: c.AUMHashes["F1"],
Ancestors: []AUMHash{ Ancestors: []AUMHash{
c.AUMHashes["A"+strconv.Itoa(9-ancestorsSkipStart)], c.AUMHashes["A"+strconv.Itoa(9-ancestorsSkipStart)],
c.AUMHashes["A1"], c.AUMHashes["A1"],
}, },
}, offer1); diff != "" { }
if diff := cmp.Diff(want1, offer1); diff != "" {
t.Errorf("offer1 diff (-want, +got):\n%s", diff) t.Errorf("offer1 diff (-want, +got):\n%s", diff)
} }
chonk2 := c.ChonkWith("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10") chonk2 := c.ChonkWith("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10")
n2, err := Open(chonk2) offer2 := getSyncOffer(t, chonk2)
if err != nil { want2 := SyncOffer{
t.Fatal(err)
}
offer2, err := n2.SyncOffer(chonk2)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(SyncOffer{
Head: c.AUMHashes["A10"], Head: c.AUMHashes["A10"],
Ancestors: []AUMHash{ Ancestors: []AUMHash{
c.AUMHashes["A"+strconv.Itoa(10-ancestorsSkipStart)], c.AUMHashes["A"+strconv.Itoa(10-ancestorsSkipStart)],
c.AUMHashes["A1"], c.AUMHashes["A1"],
}, },
}, offer2); diff != "" { }
if diff := cmp.Diff(want2, offer2); diff != "" {
t.Errorf("offer2 diff (-want, +got):\n%s", diff) t.Errorf("offer2 diff (-want, +got):\n%s", diff)
} }
@@ -339,10 +321,7 @@ func TestSyncSimpleE2E(t *testing.T) {
G1 -> L1 -> L2 -> L3 G1 -> L1 -> L2 -> L3
G1.template = genesis G1.template = genesis
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optKey("key", key, priv), optKey("key", key, priv),
optSignAllUsing("key")) optSignAllUsing("key"))
+7 -17
View File
@@ -315,11 +315,6 @@ func TestMarkDescendantAUMs(t *testing.T) {
} }
func TestMarkAncestorIntersectionAUMs(t *testing.T) { func TestMarkAncestorIntersectionAUMs(t *testing.T) {
fakeState := &State{
Keys: []Key{{Kind: Key25519, Votes: 1}},
DisablementValues: [][]byte{bytes.Repeat([]byte{1}, 32)},
}
tcs := []struct { tcs := []struct {
name string name string
chain *testChain chain *testChain
@@ -333,7 +328,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
name: "genesis", name: "genesis",
chain: newTestchain(t, ` chain: newTestchain(t, `
A A
A.template = checkpoint`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), A.template = checkpoint`, checkpointTemplate()),
initialAncestor: "A", initialAncestor: "A",
wantAncestor: "A", wantAncestor: "A",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -346,7 +341,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
chain: newTestchain(t, ` chain: newTestchain(t, `
DEAD -> A -> B -> C DEAD -> A -> B -> C
A.template = checkpoint A.template = checkpoint
B.template = checkpoint`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), B.template = checkpoint`, checkpointTemplate()),
initialAncestor: "A", initialAncestor: "A",
wantAncestor: "A", wantAncestor: "A",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -366,7 +361,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
A.template = checkpoint A.template = checkpoint
C.template = checkpoint C.template = checkpoint
D.template = checkpoint D.template = checkpoint
FORK.hashSeed = 2`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), FORK.hashSeed = 2`, checkpointTemplate()),
initialAncestor: "D", initialAncestor: "D",
wantAncestor: "C", wantAncestor: "C",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -387,7 +382,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
A.template = checkpoint A.template = checkpoint
B.template = checkpoint B.template = checkpoint
E.template = checkpoint E.template = checkpoint
FORK.hashSeed = 2`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), FORK.hashSeed = 2`, checkpointTemplate()),
initialAncestor: "E", initialAncestor: "E",
wantAncestor: "B", wantAncestor: "B",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -413,7 +408,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
D.template = checkpoint D.template = checkpoint
E.template = checkpoint E.template = checkpoint
FORK.hashSeed = 2 FORK.hashSeed = 2
DEADFORK.hashSeed = 3`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), DEADFORK.hashSeed = 3`, checkpointTemplate()),
initialAncestor: "D", initialAncestor: "D",
wantAncestor: "C", wantAncestor: "C",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -443,7 +438,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
F.template = checkpoint F.template = checkpoint
F1.hashSeed = 2 F1.hashSeed = 2
F2.hashSeed = 3 F2.hashSeed = 3
F3.hashSeed = 4`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})), F3.hashSeed = 4`, checkpointTemplate()),
initialAncestor: "F", initialAncestor: "F",
wantAncestor: "B", wantAncestor: "B",
verdicts: map[string]retainState{ verdicts: map[string]retainState{
@@ -541,11 +536,6 @@ func cloneMem(src, dst *Mem) {
} }
func TestCompact(t *testing.T) { func TestCompact(t *testing.T) {
fakeState := &State{
Keys: []Key{{Kind: Key25519, Votes: 1}},
DisablementValues: [][]byte{bytes.Repeat([]byte{1}, 32)},
}
// A & B are deleted because the new lastActiveAncestor advances beyond them. // A & B are deleted because the new lastActiveAncestor advances beyond them.
// OLD is deleted because it does not match retention criteria, and // OLD is deleted because it does not match retention criteria, and
// though it is a descendant of the new lastActiveAncestor (C), it is not a // though it is a descendant of the new lastActiveAncestor (C), it is not a
@@ -578,7 +568,7 @@ func TestCompact(t *testing.T) {
F1.hashSeed = 1 F1.hashSeed = 1
OLD.hashSeed = 2 OLD.hashSeed = 2
G2.hashSeed = 3 G2.hashSeed = 3
`, optTemplate("checkpoint", AUM{MessageKind: AUMCheckpoint, State: fakeState})) `, checkpointTemplate())
storage := &compactingChonkFake{ storage := &compactingChonkFake{
aumAge: map[AUMHash]time.Time{(c.AUMHashes["F1"]): time.Now()}, aumAge: map[AUMHash]time.Time{(c.AUMHashes["F1"]): time.Now()},
+6 -24
View File
@@ -304,10 +304,7 @@ func TestAuthorityValidDisablement(t *testing.T) {
G1.template = genesis G1.template = genesis
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
) )
a, _ := Open(c.Chonk()) a, _ := Open(c.Chonk())
@@ -419,10 +416,7 @@ func TestAuthorityInformNonLinear(t *testing.T) {
L2.hashSeed = 2 L2.hashSeed = 2
L4.hashSeed = 2 L4.hashSeed = 2
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optKey("key", key, priv), optKey("key", key, priv),
optSignAllUsing("key")) optSignAllUsing("key"))
@@ -464,10 +458,7 @@ func TestAuthorityInformLinear(t *testing.T) {
G1.template = genesis G1.template = genesis
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optKey("key", key, priv), optKey("key", key, priv),
optSignAllUsing("key")) optSignAllUsing("key"))
@@ -545,10 +536,7 @@ func TestAuthorityCompact(t *testing.T) {
G.template = genesis G.template = genesis
C.template = checkpoint2 C.template = checkpoint2
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(key),
Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &State{ optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &State{
Keys: []Key{key}, Keys: []Key{key},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})}, DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
@@ -602,10 +590,7 @@ func TestFindParentForRewrite(t *testing.T) {
C.template = add3 C.template = add3
D.template = remove2 D.template = remove2
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(k1),
Keys: []Key{k1},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optTemplate("add2", AUM{MessageKind: AUMAddKey, Key: &k2}), optTemplate("add2", AUM{MessageKind: AUMAddKey, Key: &k2}),
optTemplate("add3", AUM{MessageKind: AUMAddKey, Key: &k3}), optTemplate("add3", AUM{MessageKind: AUMAddKey, Key: &k3}),
optTemplate("remove2", AUM{MessageKind: AUMRemoveKey, KeyID: k2ID})) optTemplate("remove2", AUM{MessageKind: AUMRemoveKey, KeyID: k2ID}))
@@ -671,10 +656,7 @@ func TestMakeRetroactiveRevocation(t *testing.T) {
C.template = add2 C.template = add2
D.template = add3 D.template = add3
`, `,
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ genesisTemplate(k1),
Keys: []Key{k1},
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
}}),
optTemplate("add2", AUM{MessageKind: AUMAddKey, Key: &k2}), optTemplate("add2", AUM{MessageKind: AUMAddKey, Key: &k2}),
optTemplate("add3", AUM{MessageKind: AUMAddKey, Key: &k3})) optTemplate("add3", AUM{MessageKind: AUMAddKey, Key: &k3}))