package main import ( "strings" "testing" ) func TestReleaseAlertText(t *testing.T) { e := releaseEntry{Version: "abc1234", Semver: "0.12.0"} // stable + auto-update on: the safety-hold variant, semver-labelled. title, body, ok := releaseAlertText("Familia", "stable", e, true, "") if !ok { t.Fatal("stable sighting should alert") } if !strings.Contains(title, "Familia") { t.Fatalf("title misses the space name: %q", title) } if !strings.Contains(body, "v0.12.0 (abc1234)") || !strings.Contains(body, "72 hours") { t.Fatalf("hold body = %q", body) } // Automatic updates off: no "installs automatically" promise. _, body, ok = releaseAlertText("Familia", "stable", e, false, "") if !ok || strings.Contains(body, "installs automatically") || !strings.Contains(body, "Automatic updates are off") { t.Fatalf("updates-off body = %q (ok=%v)", body, ok) } // A major hold wins over the bake copy — the admin's action is different. held := releaseEntry{Version: "abc1234", Semver: "1.0.0"} _, body, ok = releaseAlertText("Familia", "stable", held, true, "0") if !ok || !strings.Contains(body, "major version") { t.Fatalf("major-held body = %q (ok=%v)", body, ok) } // edge never alerts: its riders are the operators doing the publishing. if _, _, ok = releaseAlertText("Familia", "edge", e, true, ""); ok { t.Fatal("edge sighting alerted") } // ...unless a major pin holds even edge — that waits on the admin. if _, _, ok = releaseAlertText("Familia", "edge", held, true, "0"); !ok { t.Fatal("major-held edge sighting should alert") } } func TestNoteReleaseSightings(t *testing.T) { _, s := newTestServer(t) stable := func(ver, sv string) *releaseManifest { return &releaseManifest{Channels: map[string]releaseEntry{"stable": {Version: ver, Semver: sv}}} } // First sighting on the channel baselines silently. if alerted, _ := s.noteReleaseSightings(stable("aaa1111", "")); alerted { t.Fatal("first sighting should baseline, not alert") } // The same head again is quiet. if alerted, _ := s.noteReleaseSightings(stable("aaa1111", "")); alerted { t.Fatal("unchanged head alerted") } // The head moving is the alert (sent stays 0 — no push subscriptions here). alerted, sent := s.noteReleaseSightings(stable("bbb2222", "0.12.0")) if !alerted || sent != 0 { t.Fatalf("moved head: alerted=%v sent=%d", alerted, sent) } // At-most-once: the watermark advanced, so the same move doesn't replay. if alerted, _ := s.noteReleaseSightings(stable("bbb2222", "0.12.0")); alerted { t.Fatal("alert replayed for the same head") } // A head we're already running (a ship landed, or a pull-back onto us) is // not "on the way" — buildVersion is "dev" under test. if alerted, _ := s.noteReleaseSightings(stable(buildVersion, "")); alerted { t.Fatal("alerted for the build we already run") } // A corrupt watermark re-baselines rather than announcing a backlog. if err := s.db.setConfig(releaseSeenKey, "not-json"); err != nil { t.Fatal(err) } if alerted, _ := s.noteReleaseSightings(stable("ccc3333", "")); alerted { t.Fatal("corrupt watermark should re-baseline silently") } if alerted, _ := s.noteReleaseSightings(stable("ddd4444", "")); !alerted { t.Fatal("post-re-baseline move should alert") } // An edge-riding space stays quiet through head moves. if err := s.db.setUpdateChannel("edge"); err != nil { t.Fatal(err) } edge := func(ver string) *releaseManifest { return &releaseManifest{Channels: map[string]releaseEntry{"edge": {Version: ver}}} } s.noteReleaseSightings(edge("eee5555")) // baseline the edge channel if alerted, _ := s.noteReleaseSightings(edge("fff6666")); alerted { t.Fatal("edge head move alerted") } }