feat(cli): apply coordinated updates during maintenance
This commit is contained in:
21 files changed
+990
-457
No files matched your search
@@ -0,0 +1,126 @@
|
||||
package updater
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const installerTestSHA = "0123456789abcdef0123456789abcdef01234567"
|
||||
|
||||
func TestInstallerResolvesMovingRefsOnceAndPinsTheScript(t *testing.T) {
|
||||
for _, tc := range []struct{ name, release, ref, releasePath, commitRef string }{
|
||||
{"latest release", "", "", "releases/latest", "v0.2.0"},
|
||||
{"named release", "v0.2.0", "", "releases/tags/v0.2.0", "v0.2.0"},
|
||||
{"main", "", "main", "", "main"},
|
||||
{"branch with slash", "", "feature/example", "", "feature/example"},
|
||||
{"exact commit", "", installerTestSHA, "", installerTestSHA},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var calls []string
|
||||
const script = "#!/bin/bash\n# FELIS_RELEASE\necho example\n"
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" || r.Header.Get("Authorization") != "Bearer private-token" || r.Header.Get("User-Agent") == "" {
|
||||
t.Errorf("unexpected request headers/method: %v", r)
|
||||
}
|
||||
calls = append(calls, r.URL.Path)
|
||||
switch r.URL.Path {
|
||||
case "/repos/example/Felis/" + tc.releasePath:
|
||||
fmt.Fprint(w, `{"tag_name":"v0.2.0"}`)
|
||||
case "/repos/example/Felis/commits/" + tc.commitRef:
|
||||
fmt.Fprintf(w, `{"sha":%q}`, installerTestSHA)
|
||||
case "/repos/example/Felis/contents/deploy/bootstrap.sh":
|
||||
if r.URL.Query().Get("ref") != installerTestSHA || r.Header.Get("Accept") != "application/vnd.github.raw+json" {
|
||||
t.Errorf("script not pinned/raw: %v", r)
|
||||
}
|
||||
fmt.Fprint(w, script)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
gh := newTestGitHub(srv)
|
||||
gh.token = "private-token"
|
||||
target, err := (InstallerSource{github: gh, repo: "example/Felis"}).Prepare(context.Background(), tc.release, tc.ref)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantRelease := ""
|
||||
wantCalls := []string{}
|
||||
if tc.releasePath != "" {
|
||||
wantRelease = "v0.2.0"
|
||||
wantCalls = append(wantCalls, "/repos/example/Felis/"+tc.releasePath)
|
||||
}
|
||||
wantCalls = append(wantCalls, "/repos/example/Felis/commits/"+tc.commitRef, "/repos/example/Felis/contents/deploy/bootstrap.sh")
|
||||
if target.Release != wantRelease || target.Revision != installerTestSHA || target.Script != script || !reflect.DeepEqual(calls, wantCalls) {
|
||||
t.Fatalf("target %+v, calls %v; want %v", target, calls, wantCalls)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallerFailsClosedBeforeExecutingUnusableTargets(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, releaseBody, commitBody, script string
|
||||
status int
|
||||
}{
|
||||
{"prerelease", `{"tag_name":"v0.2.0","prerelease":true}`, "", "", 200},
|
||||
{"invalid tag", `{"tag_name":"latest"}`, "", "", 200},
|
||||
{"short commit", `{"tag_name":"v0.2.0"}`, `{"sha":"abcdef0"}`, "", 200},
|
||||
{"invalid commit", `{"tag_name":"v0.2.0"}`, `{"sha":"zz23456789abcdef0123456789abcdef01234567"}`, "", 200},
|
||||
{"non-script response", `{"tag_name":"v0.2.0"}`, fmt.Sprintf(`{"sha":%q}`, installerTestSHA), "<html>unavailable</html>", 200},
|
||||
{"oversized script", `{"tag_name":"v0.2.0"}`, fmt.Sprintf(`{"sha":%q}`, installerTestSHA), "#!/bin/bash\n" + strings.Repeat("#", 2<<20), 200},
|
||||
{"unavailable", "", "", "", 503},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(tc.status)
|
||||
switch {
|
||||
case strings.Contains(r.URL.Path, "/releases/"):
|
||||
fmt.Fprint(w, tc.releaseBody)
|
||||
case strings.Contains(r.URL.Path, "/commits/"):
|
||||
fmt.Fprint(w, tc.commitBody)
|
||||
default:
|
||||
fmt.Fprint(w, tc.script)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
got, err := (InstallerSource{github: newTestGitHub(srv), repo: officialRepo}).Prepare(context.Background(), "", "")
|
||||
if err == nil || got != (InstallTarget{}) {
|
||||
t.Fatalf("unsafe target %+v, err %v", got, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallerAcceptsGitHubReposWithoutEmbeddingCredentials(t *testing.T) {
|
||||
for _, repoURL := range []string{"", "https://github.com/FelisMC/Felis.git", "[email protected]:FelisMC/Felis.git", "ssh://[email protected]/FelisMC/Felis.git"} {
|
||||
s, err := NewInstallerSource(repoURL)
|
||||
if err != nil || s.RepoURL() != "https://github.com/FelisMC/Felis.git" {
|
||||
t.Errorf("%s: %v, %+v", repoURL, err, s)
|
||||
}
|
||||
}
|
||||
for _, repoURL := range []string{"https://example.com/FelisMC/Felis", "http://github.com/FelisMC/Felis", "https://github.com/FelisMC/Felis?token=secret", "[email protected]:../../bad"} {
|
||||
if _, err := NewInstallerSource(repoURL); err == nil {
|
||||
t.Errorf("accepted %s", repoURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallerRefusesACommitDifferentFromTheRequestedSHA(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.URL.Path, "/contents/") {
|
||||
t.Error("mismatched commit must not reach installer download")
|
||||
}
|
||||
fmt.Fprintf(w, `{"sha":%q}`, strings.Repeat("a", 40))
|
||||
}))
|
||||
defer srv.Close()
|
||||
target, err := (InstallerSource{github: newTestGitHub(srv), repo: officialRepo}).Prepare(context.Background(), "", installerTestSHA)
|
||||
if err == nil || target != (InstallTarget{}) {
|
||||
t.Fatalf("accepted a different commit: %+v / %v", target, err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user