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, progress func(string, int, string)) (string, error) { siteCalls.Add(1) progress("checking", 10, "Checking for the newest release") progress("done", 100, "Already on the newest release") 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, progress func(string, int, string)) (string, error) { edgeCalls.Add(1) progress("downloading", 40, "Downloading blacktip_v0.2.0_linux_amd64.tar.gz") progress("downloading", 70, "Downloaded 28.0 of 40.0 MB (70%)") progress("restarting", 100, "Installed v0.2.0; restarting into it") 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()) } var log struct { Running bool Stage string Pct int Lines []string } w.admin.must("GET", "/api/edges/"+w.edge+"/update/log", nil, &log) text := strings.Join(log.Lines, "; ") if log.Running || log.Stage != "restarting" || log.Pct != 100 || !strings.Contains(text, "Update requested") || !strings.Contains(text, "Downloaded 28.0 of 40.0 MB") || !strings.Contains(text, "restarting into it") { t.Fatalf("edge update log: %+v (%s)", log, text) } 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()) } w.admin.must("GET", "/api/orgs/"+w.org+"/sites/"+w.site+"/update/log", nil, &log) if log.Running || log.Stage != "done" || !strings.Contains(strings.Join(log.Lines, "; "), "Already on the newest release") { t.Fatalf("site update log: %+v", log) } // 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) } }