carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package release
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7 "time"
8)
9
10func seedRootBake(t *testing.T, h *RootHistory, b HistoryBinding, at time.Time) {
11 t.Helper()
12 r := rootBakeRecord{Schema: 1, Revision: 1, Observed: at,
13 Complete: map[string]uint64{prodKey(b.Account, b.App): 1},
14 Clock: FirstSeen{Channels: map[string]map[string]time.Time{}}}
15 if err := h.writeBake(r); err != nil {
16 t.Fatal(err)
17 }
18}
19
20func TestPlan14RootBakeRetainsHistory(t *testing.T) {
21 h, _, b := rootHistoryFixture(t)
22 start := time.Now().UTC().Add(-time.Hour)
23 seedRootBake(t, h, b, start)
24 clock, err := h.LoadBake([]HistoryBinding{b}, start)
25 if err != nil {
26 t.Fatal(err)
27 }
28 clock.Observe(b.Account, b.App, "stable", "new", start)
29 clock.Production = map[string]*prodMemory{prodKey(b.Account, b.App): {WasProduction: true}}
30 clock.Holds = map[string]*holdMemory{channelClockKey(b.Account, b.App, "stable"): {Window: 96 * time.Hour, SetAt: start}}
31 if err := clock.Save(); err != nil {
32 t.Fatal(err)
33 }
34 legacy := t.TempDir()
35 if err := os.WriteFile(FirstSeenPath(legacy), []byte(`{"jitter":0,"channels":{},"production":{},"holds":{}}`), 0600); err != nil {
36 t.Fatal(err)
37 }
38 if err := os.Rename(legacy, legacy+"-moved"); err != nil {
39 t.Fatal(err)
40 }
41 t.Cleanup(func() { _ = os.RemoveAll(legacy + "-moved") })
42 clock, err = h.LoadBake([]HistoryBinding{b}, start.Add(time.Hour))
43 if err != nil {
44 t.Fatal(err)
45 }
46 if !clock.Production[prodKey(b.Account, b.App)].WasProduction || clock.Holds[channelClockKey(b.Account, b.App, "stable")].Window != 96*time.Hour {
47 t.Fatal("legacy replacement removed root ratchets")
48 }
49 holds := map[string]time.Duration{"stable": 96 * time.Hour}
50 if Hold(clock, b.Account, b.App, "stable", "new", holds, false, start.Add(time.Hour)) == "" {
51 t.Fatal("hold shortened")
52 }
53 if Hold(clock, b.Account, b.App, "stable", "new", holds, false, start.Add(121*time.Hour)) != "" {
54 t.Fatal("root interval never elapsed")
55 }
56}
57
58func TestPlan14RootBakeUnknownAndDurability(t *testing.T) {
59 for _, attack := range []string{"missing", "malformed", "wrong-app", "sync", "backward"} {
60 t.Run(attack, func(t *testing.T) {
61 h, s, b := rootHistoryFixture(t)
62 now := time.Now().UTC()
63 seedRootBake(t, h, b, now)
64 switch attack {
65 case "missing":
66 if err := os.Remove(filepath.Join(s.dir, rootBakeKey)); err != nil {
67 t.Fatal(err)
68 }
69 case "malformed":
70 if err := s.Write(rootBakeKey, []byte(`{}`)); err != nil {
71 t.Fatal(err)
72 }
73 case "wrong-app":
74 b.App = "other"
75 case "sync":
76 s.fail = 1
77 case "backward":
78 now = now.Add(-time.Hour)
79 }
80 if _, err := h.LoadBake([]HistoryBinding{b}, now); err == nil {
81 t.Fatal("unavailable bake history granted adoption")
82 }
83 })
84 }
85}
86