Edges and sites report their version and whether auto-update is on. Hammerhead can ask a machine that has auto-update on to install the newest release, and shows the outcome. Requests carry an ID so a stale result can't answer a new one. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.veillax.com/Veillax/bamboo"
|
|
"git.veillax.com/Veillax/blacktip"
|
|
"git.veillax.com/Veillax/reef/model"
|
|
)
|
|
|
|
type edgeRow struct {
|
|
ID, Version, UpdateMsg string
|
|
AutoUpdate bool
|
|
UpdatePending bool
|
|
Online bool
|
|
}
|
|
|
|
func (w *world) edgeRow() edgeRow {
|
|
var edges []edgeRow
|
|
w.admin.must("GET", "/api/edges", nil, &edges)
|
|
for _, e := range edges {
|
|
if e.ID == w.edge {
|
|
return e
|
|
}
|
|
}
|
|
w.t.Fatal("edge not listed")
|
|
return edgeRow{}
|
|
}
|
|
|
|
func (w *world) siteRow() model.Site {
|
|
var st struct{ Sites []model.Site }
|
|
w.admin.must("GET", "/api/orgs/"+w.org+"/state", nil, &st)
|
|
for _, s := range st.Sites {
|
|
if s.ID == w.site {
|
|
return s
|
|
}
|
|
}
|
|
w.t.Fatal("site not listed")
|
|
return model.Site{}
|
|
}
|
|
|
|
func waitFor(t *testing.T, what string, ok func() bool) {
|
|
t.Helper()
|
|
for i := 0; i < 150; i++ {
|
|
if ok() {
|
|
return
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
t.Fatalf("timed out waiting for %s", what)
|
|
}
|
|
|
|
func TestEdgesAndSitesReportVersionsAndUpdateOnRequest(t *testing.T) {
|
|
var edgeCalls, siteCalls atomic.Int32
|
|
siteCfgHook = func(c *bamboo.Config) {
|
|
c.Version, c.AutoUpdate = "v0.1.0", true
|
|
c.UpdateNow = func(ctx context.Context) (string, error) { siteCalls.Add(1); return "", nil }
|
|
}
|
|
defer func() { siteCfgHook = nil }()
|
|
w := setup(t, blacktip.TraefikConfig{}, func(c *blacktip.Config) {
|
|
c.Version, c.AutoUpdate = "v0.1.0", true
|
|
c.UpdateNow = func(ctx context.Context) (string, error) { edgeCalls.Add(1); return "v0.2.0", nil }
|
|
})
|
|
|
|
waitFor(t, "the edge to report its version", func() bool { e := w.edgeRow(); return e.Version == "v0.1.0" && e.AutoUpdate })
|
|
waitFor(t, "the site to report its version", func() bool { s := w.siteRow(); return s.Version == "v0.1.0" && s.AutoUpdate })
|
|
|
|
w.admin.must("POST", "/api/edges/"+w.edge+"/update", nil, nil)
|
|
waitFor(t, "the edge to answer the update request", func() bool {
|
|
e := w.edgeRow()
|
|
return !e.UpdatePending && e.UpdateMsg == "updated to v0.2.0, restarting"
|
|
})
|
|
if edgeCalls.Load() != 1 {
|
|
t.Fatalf("the edge ran its update %d times, want 1", edgeCalls.Load())
|
|
}
|
|
|
|
w.admin.must("POST", "/api/orgs/"+w.org+"/sites/"+w.site+"/update", nil, nil)
|
|
waitFor(t, "the site to answer the update request", func() bool {
|
|
s := w.siteRow()
|
|
return s.UpdateID == "" && s.UpdateMsg == "already on the newest release"
|
|
})
|
|
if siteCalls.Load() != 1 {
|
|
t.Fatalf("the site ran its update %d times, want 1", siteCalls.Load())
|
|
}
|
|
|
|
// asking again works and is a fresh request, not a leftover answer
|
|
w.admin.must("POST", "/api/edges/"+w.edge+"/update", nil, nil)
|
|
waitFor(t, "a second update request to be answered", func() bool { return edgeCalls.Load() == 2 && !w.edgeRow().UpdatePending })
|
|
}
|
|
|
|
func TestUpdatesNeedAutoUpdateOnTheMachine(t *testing.T) {
|
|
w := setup(t, blacktip.TraefikConfig{}) // no version, auto-update off
|
|
waitFor(t, "the edge to be online", func() bool { return w.edgeRow().Online })
|
|
code, body := w.admin.do("POST", "/api/edges/"+w.edge+"/update", nil, nil)
|
|
if code != 400 || !strings.Contains(body, "BLACKTIP_AUTO_UPDATE") {
|
|
t.Fatalf("update on an edge without auto-update: %d %s", code, body)
|
|
}
|
|
code, body = w.admin.do("POST", "/api/orgs/"+w.org+"/sites/"+w.local+"/update", nil, nil)
|
|
if code != 400 {
|
|
t.Fatalf("update on a local site: %d %s", code, body)
|
|
}
|
|
}
|