138 lines
5.0 KiB
Go
138 lines
5.0 KiB
Go
package buildstep
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
|
)
|
|
|
|
const sha = "0123456789abcdef0123456789abcdef01234567"
|
|
|
|
// fakeGit records every command and answers by a rule.
|
|
type fakeGit struct {
|
|
calls []string
|
|
envs [][]string
|
|
rule func(args string) forgekey.Ran
|
|
}
|
|
|
|
func (f *fakeGit) run(ctx context.Context, env []string, name string, args ...string) forgekey.Ran {
|
|
line := name + " " + strings.Join(args, " ")
|
|
f.calls = append(f.calls, line)
|
|
f.envs = append(f.envs, env)
|
|
if f.rule != nil {
|
|
if r := f.rule(line); r.Status != 0 || r.Stdout != "" || r.Err != "" {
|
|
return r
|
|
}
|
|
}
|
|
if len(args) > 4 && args[4] == "rev-parse" {
|
|
return forgekey.Ran{Stdout: sha + "\n"}
|
|
}
|
|
return forgekey.Ran{}
|
|
}
|
|
|
|
const pre = "git -c credential.helper= -C /w "
|
|
|
|
// 1474/AC1: the git commands are exactly the sequence, none with a credential or an https remote.
|
|
func TestFetchCommitRunsTheSequence(t *testing.T) {
|
|
f := &fakeGit{}
|
|
if err := FetchCommit(context.Background(), f.run, "/w", "ssh://mesh-forge/novox/mesh-sdk.git", sha, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []string{
|
|
pre + "init -q",
|
|
pre + "remote add origin ssh://mesh-forge/novox/mesh-sdk.git",
|
|
pre + "fetch --no-tags --depth 1 origin " + sha,
|
|
pre + "checkout -q --detach " + sha,
|
|
pre + "rev-parse HEAD",
|
|
}
|
|
if strings.Join(f.calls, "\n") != strings.Join(want, "\n") {
|
|
t.Errorf("commands:\n%s\nwant:\n%s", strings.Join(f.calls, "\n"), strings.Join(want, "\n"))
|
|
}
|
|
for i, c := range f.calls {
|
|
if strings.Contains(c, "https://") || strings.Contains(c, "@") || !strings.Contains(c, "credential.helper= ") {
|
|
t.Errorf("command %q carries a credential or https", c)
|
|
}
|
|
if len(f.envs[i]) != 1 || f.envs[i][0] != "GIT_TERMINAL_PROMPT=0" {
|
|
t.Errorf("env %v", f.envs[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1474/AC2: the depth-1 fetch fails and a pull ref is given: the ref is fetched and the commit verified; with no
|
|
// ref, the fetch's failure is the answer.
|
|
func TestFetchCommitFallsBackToThePullRef(t *testing.T) {
|
|
f := &fakeGit{rule: func(l string) forgekey.Ran {
|
|
if strings.Contains(l, "--depth 1") {
|
|
return forgekey.Ran{Status: 128, Stderr: "fatal: couldn't find remote ref " + sha + "\n"}
|
|
}
|
|
return forgekey.Ran{}
|
|
}}
|
|
if err := FetchCommit(context.Background(), f.run, "/w", "ssh://mesh-forge/o/r.git", sha, "refs/pull/1/head"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []string{pre + "fetch --no-tags origin refs/pull/1/head", pre + "cat-file -e " + sha + "^{commit}", pre + "checkout -q --detach " + sha}
|
|
got := strings.Join(f.calls[3:6], "\n")
|
|
if got != strings.Join(want, "\n") {
|
|
t.Errorf("after the failed fetch:\n%s\nwant:\n%s", got, strings.Join(want, "\n"))
|
|
}
|
|
|
|
g := &fakeGit{rule: f.rule}
|
|
err := FetchCommit(context.Background(), g.run, "/w", "ssh://mesh-forge/o/r.git", sha, "")
|
|
if err == nil || !strings.Contains(err.Error(), "couldn't find remote ref") || len(g.calls) != 3 {
|
|
t.Errorf("without a ref: %v after %d commands", err, len(g.calls))
|
|
}
|
|
|
|
h := &fakeGit{rule: func(l string) forgekey.Ran {
|
|
if strings.Contains(l, "--depth 1") || strings.Contains(l, "cat-file") {
|
|
return forgekey.Ran{Status: 1, Stderr: "no"}
|
|
}
|
|
return forgekey.Ran{}
|
|
}}
|
|
if err := FetchCommit(context.Background(), h.run, "/w", "ssh://mesh-forge/o/r.git", sha, "refs/pull/1/head"); err == nil {
|
|
t.Error("a commit that is not in the ref was accepted")
|
|
}
|
|
}
|
|
|
|
// 1474/AC3: HEAD differs from the commit after the checkout: an error naming both.
|
|
func TestFetchCommitAnswersAHeadThatIsNotTheCommit(t *testing.T) {
|
|
other := strings.Repeat("a", 40)
|
|
f := &fakeGit{rule: func(l string) forgekey.Ran {
|
|
if strings.HasSuffix(l, "rev-parse HEAD") {
|
|
return forgekey.Ran{Stdout: other + "\n"}
|
|
}
|
|
return forgekey.Ran{}
|
|
}}
|
|
err := FetchCommit(context.Background(), f.run, "/w", "ssh://mesh-forge/o/r.git", sha, "")
|
|
if err == nil || !strings.Contains(err.Error(), other) || !strings.Contains(err.Error(), sha) {
|
|
t.Errorf("error = %v, want both shas", err)
|
|
}
|
|
}
|
|
|
|
// 1474/AC4: an https remote, user information, a file remote without the option, or a commit that is not 40
|
|
// hex digits is refused before anything runs.
|
|
func TestFetchCommitRefusesBeforeRunningAnything(t *testing.T) {
|
|
for _, c := range []struct{ remote, commit, ref string }{
|
|
{"https://forge.example/o/r.git", sha, ""},
|
|
{"http://forge.example/o/r.git", sha, ""},
|
|
{"ssh://git@mesh-forge/o/r.git", sha, ""},
|
|
{"ssh://user:pw@mesh-forge/o/r.git", sha, ""},
|
|
{"file:///tmp/r.git", sha, ""},
|
|
{"/tmp/r.git", sha, ""},
|
|
{"ssh://mesh-forge/o/r.git", "abc123", ""},
|
|
{"ssh://mesh-forge/o/r.git", strings.ToUpper(sha), ""},
|
|
{"ssh://mesh-forge/o/r.git", "main", ""},
|
|
{"ssh://mesh-forge/o/r.git", sha, "--upload-pack=x"},
|
|
} {
|
|
f := &fakeGit{}
|
|
if err := FetchCommit(context.Background(), f.run, "/w", c.remote, c.commit, c.ref); err == nil || len(f.calls) != 0 {
|
|
t.Errorf("%+v: err %v, %d commands", c, err, len(f.calls))
|
|
}
|
|
}
|
|
f := &fakeGit{}
|
|
if err := FetchCommit(context.Background(), f.run, "/w", "file:///tmp/r.git", sha, "", AllowFileRemote()); err != nil {
|
|
t.Errorf("a file remote with the option: %v", err)
|
|
}
|
|
}
|