127 lines
5.1 KiB
Go
127 lines
5.1 KiB
Go
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)
|
|
}
|
|
}
|