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 "testing"
5 "time"
6)
7
8func TestCanaryExpiredFalseForFreshPromotion(t *testing.T) {
9 p := &ChannelPointer{App: "myapp", Channel: "canary/x", Version: "v1", PromotedAt: time.Now()}
10 if CanaryExpired(p, time.Now()) {
11 t.Error("a canary promoted moments ago must not be expired")
12 }
13}
14
15func TestCanaryExpiredTrueAfterTTL(t *testing.T) {
16 old := time.Now().Add(-(CanaryTTL + time.Hour))
17 p := &ChannelPointer{App: "myapp", Channel: "canary/x", Version: "v1", PromotedAt: old}
18 if !CanaryExpired(p, time.Now()) {
19 t.Error("a canary promoted more than CanaryTTL ago must be expired")
20 }
21}
22
23// Right at the boundary: exactly CanaryTTL old is NOT yet expired — the TTL
24// names the lease's length, not a moment strictly before it.
25func TestCanaryExpiredBoundary(t *testing.T) {
26 now := time.Now()
27 atBoundary := &ChannelPointer{Channel: "canary/x", PromotedAt: now.Add(-CanaryTTL)}
28 if CanaryExpired(atBoundary, now) {
29 t.Error("exactly CanaryTTL old must not be expired yet")
30 }
31 pastBoundary := &ChannelPointer{Channel: "canary/x", PromotedAt: now.Add(-CanaryTTL - time.Second)}
32 if !CanaryExpired(pastBoundary, now) {
33 t.Error("one second past CanaryTTL must be expired")
34 }
35}
36
37// Re-promoting a canary refreshes PromotedAt, which is the whole point of
38// keying age off the pointer's own lease timestamp: an actively-updated
39// canary never expires, however old the channel name itself is.
40func TestCanaryExpiredRefreshesOnRepromotion(t *testing.T) {
41 now := time.Now()
42 stale := &ChannelPointer{Channel: "canary/x", PromotedAt: now.Add(-(CanaryTTL + 24*time.Hour))}
43 if !CanaryExpired(stale, now) {
44 t.Fatal("setup: this pointer should read as expired before the repromotion")
45 }
46 refreshed := &ChannelPointer{Channel: "canary/x", PromotedAt: now}
47 if CanaryExpired(refreshed, now) {
48 t.Error("a freshly re-promoted canary must not be expired, however old the channel is")
49 }
50}
51
52// Only canary/* channels carry a TTL at all — edge, beta and stable are
53// never flagged, however old their PromotedAt is.
54func TestCanaryExpiredFalseForNonCanaryChannels(t *testing.T) {
55 now := time.Now()
56 ancient := now.Add(-365 * 24 * time.Hour)
57 for _, ch := range []string{"stable", "beta", "edge", "canary"} {
58 p := &ChannelPointer{Channel: ch, PromotedAt: ancient}
59 if CanaryExpired(p, now) {
60 t.Errorf("channel %q must never be flagged expired (not a canary/* channel)", ch)
61 }
62 }
63}
64
65// A pointer written before PromotedAt existed (or any zero value) must not
66// be flagged expired — unknown age is not proof of age, and validatePointer
67// already refuses a zero PromotedAt on anything read off the wire, so this
68// is defense for a directly-constructed pointer, not a live-fleet case.
69func TestCanaryExpiredFalseForZeroPromotedAt(t *testing.T) {
70 p := &ChannelPointer{Channel: "canary/x"}
71 if CanaryExpired(p, time.Now()) {
72 t.Error("a zero PromotedAt must not be flagged expired")
73 }
74}
75
76func TestCanaryExpiredNilPointer(t *testing.T) {
77 if CanaryExpired(nil, time.Now()) {
78 t.Error("a nil pointer must not be flagged expired")
79 }
80}
81
82// ---- CanaryAge / FormatCanaryAge (2026-08-03 review, IMPORTANT 2) ---------
83
84// CanaryAge must report time PAST the TTL, not total age — a pointer
85// CanaryTTL+1h old has been expired for about an hour, not 7 days 1 hour.
86func TestCanaryAgeIsTimePastTTLNotTotalAge(t *testing.T) {
87 now := time.Now()
88 p := &ChannelPointer{Channel: "canary/x", PromotedAt: now.Add(-(CanaryTTL + time.Hour))}
89 got := CanaryAge(p, now)
90 if got < 59*time.Minute || got > 61*time.Minute {
91 t.Errorf("CanaryAge = %s, want ~1h (total age minus CanaryTTL, not the 169h total age)", got)
92 }
93}
94
95func TestFormatCanaryAge(t *testing.T) {
96 cases := []struct {
97 d time.Duration
98 want string
99 }{
100 {0, "<1h"}, // the instant it expires
101 {24 * time.Minute, "<1h"}, // MINOR 7: must not read "0h"
102 {59 * time.Minute, "<1h"},
103 {time.Hour, "1h"}, // review's own example: 7d1h old -> "1h"
104 {90 * time.Minute, "2h"}, // rounds to nearest hour
105 {23 * time.Hour, "23h"},
106 {24 * time.Hour, "1d"},
107 {47 * time.Hour, "1d"}, // deliberate coarseness: truncates, not rounds
108 {8 * 24 * time.Hour, "8d"},
109 {30 * 24 * time.Hour, "30d"},
110 }
111 for _, c := range cases {
112 if got := FormatCanaryAge(c.d); got != c.want {
113 t.Errorf("FormatCanaryAge(%s) = %q, want %q", c.d, got, c.want)
114 }
115 }
116}
117