golang.org/x/build@v0.0.0-20240506185731-218518f32b70/cmd/gitmirror/gitmirror_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "io" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "strings" 16 "testing" 17 18 "golang.org/x/build/internal/envutil" 19 repospkg "golang.org/x/build/repos" 20 ) 21 22 func TestHomepage(t *testing.T) { 23 tm := newTestMirror(t) 24 if body := tm.get("/"); !strings.Contains(body, "build") { 25 t.Errorf("expected body to contain \"build\", didn't: %q", body) 26 } 27 } 28 29 func TestDebugWatcher(t *testing.T) { 30 tm := newTestMirror(t) 31 tm.commit("hello world") 32 tm.loopOnce() 33 34 body := tm.get("/debug/watcher/build") 35 if substr := `watcher status for repo: "build"`; !strings.Contains(body, substr) { 36 t.Fatalf("GET /debug/watcher/build: want %q in body, got %s", substr, body) 37 } 38 if substr := "waiting"; !strings.Contains(body, substr) { 39 t.Fatalf("GET /debug/watcher/build: want %q in body, got %s", substr, body) 40 } 41 } 42 43 func TestArchive(t *testing.T) { 44 tm := newTestMirror(t) 45 46 // Start with a revision we know about. 47 tm.commit("hello world") 48 initialRev := strings.TrimSpace(tm.git(tm.gerrit, "rev-parse", "HEAD")) 49 tm.loopOnce() // fetch the commit. 50 tm.get("/build.tar.gz?rev=" + initialRev) 51 52 // Now test one we don't see yet. It will be fetched automatically. 53 tm.commit("round two") 54 secondRev := strings.TrimSpace(tm.git(tm.gerrit, "rev-parse", "HEAD")) 55 // As of writing, the git version installed on the builders has some kind 56 // of bug that prevents the "git fetch" this triggers from working. Skip. 57 if strings.HasPrefix(tm.git(tm.gerrit, "version"), "git version 2.11") { 58 t.Skip("known-buggy git version") 59 } 60 tm.get("/build.tar.gz?rev=" + secondRev) 61 62 // Pick it up normally and re-fetch it to make sure we don't get confused. 63 tm.loopOnce() 64 tm.get("/build.tar.gz?rev=" + secondRev) 65 } 66 67 func TestMirror(t *testing.T) { 68 tm := newTestMirror(t) 69 for i := 0; i < 2; i++ { 70 tm.commit(fmt.Sprintf("revision %v", i)) 71 rev := tm.git(tm.gerrit, "rev-parse", "HEAD") 72 tm.loopOnce() 73 if githubRev := tm.git(tm.github, "rev-parse", "HEAD"); rev != githubRev { 74 t.Errorf("github HEAD is %v, want %v", githubRev, rev) 75 } 76 if csrRev := tm.git(tm.csr, "rev-parse", "HEAD"); rev != csrRev { 77 t.Errorf("csr HEAD is %v, want %v", csrRev, rev) 78 } 79 } 80 } 81 82 // Tests that mirroring an initially empty repository works. See golang/go#39597. 83 // The repository still has to exist. 84 func TestMirrorInitiallyEmpty(t *testing.T) { 85 tm := newTestMirror(t) 86 if err := tm.m.repos["build"].loopOnce(); err == nil { 87 t.Error("expected error mirroring empty repository, got none") 88 } 89 tm.commit("first commit") 90 tm.loopOnce() 91 rev := tm.git(tm.gerrit, "rev-parse", "HEAD") 92 if githubRev := tm.git(tm.github, "rev-parse", "HEAD"); rev != githubRev { 93 t.Errorf("github HEAD is %v, want %v", githubRev, rev) 94 } 95 } 96 97 type testMirror struct { 98 // Local paths to the copies of the build repo. 99 gerrit, github, csr string 100 m *gitMirror 101 server *httptest.Server 102 buildRepo *repo 103 t *testing.T 104 } 105 106 // newTestMirror returns a mirror configured to watch the "build" repository 107 // and mirror it to GitHub and CSR. All repositories are faked out with local 108 // versions created hermetically. The mirror is idle and must be pumped with 109 // loopOnce. 110 func newTestMirror(t *testing.T) *testMirror { 111 if _, err := exec.LookPath("git"); err != nil { 112 t.Skip("skipping; git not in PATH") 113 } 114 115 goBase := t.TempDir() 116 gerrit := filepath.Join(goBase, "build") 117 if err := os.Mkdir(gerrit, 0755); err != nil { 118 t.Fatalf("error creating gerrit build directory: %v", err) 119 } 120 121 tm := &testMirror{ 122 gerrit: gerrit, 123 github: t.TempDir(), 124 csr: t.TempDir(), 125 m: &gitMirror{ 126 mux: http.NewServeMux(), 127 cacheDir: t.TempDir(), 128 homeDir: t.TempDir(), 129 // gitMirror generally expects goBase to be a URL, not 130 // a path, but git handles local paths just fine. As a 131 // result, gitMirror uses standard string concatenation 132 // rather than path.Join. Ensure the path ends in / to 133 // make sure concatenation is OK. 134 goBase: goBase + "/", 135 repos: map[string]*repo{}, 136 mirrorGitHub: true, 137 mirrorCSR: true, 138 timeoutScale: 0, 139 }, 140 t: t, 141 } 142 tm.m.mux.HandleFunc("/", tm.m.handleRoot) 143 tm.server = httptest.NewServer(tm.m.mux) 144 t.Cleanup(tm.server.Close) 145 146 // The origin is non-bare so we can commit to it; the destinations are 147 // bare so we can push to them. 148 initRepo := func(dir string, bare bool) { 149 initArgs := []string{"init"} 150 if bare { 151 initArgs = append(initArgs, "--bare") 152 } 153 for _, args := range [][]string{ 154 initArgs, 155 {"config", "user.name", "Gopher"}, 156 {"config", "user.email", "gopher@golang.org"}, 157 } { 158 cmd := exec.Command("git", args...) 159 envutil.SetDir(cmd, dir) 160 if out, err := cmd.CombinedOutput(); err != nil { 161 t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) 162 } 163 } 164 } 165 initRepo(tm.gerrit, false) 166 initRepo(tm.github, true) 167 initRepo(tm.csr, true) 168 169 tm.buildRepo = tm.m.addRepo(&repospkg.Repo{ 170 GoGerritProject: "build", 171 ImportPath: "golang.org/x/build", 172 MirrorToGitHub: true, 173 GitHubRepo: "golang/build", 174 MirrorToCSRProject: "golang-org", 175 }) 176 if err := tm.buildRepo.init(); err != nil { 177 t.Fatal(err) 178 } 179 180 // Manually add mirror repos. We can't use tm.m.addMirrors, as they 181 // hard-codes the real remotes, but we need to use local test 182 // directories. 183 tm.buildRepo.addRemote("github", tm.github, "") 184 tm.buildRepo.addRemote("csr", tm.csr, "") 185 186 return tm 187 } 188 189 func (tm *testMirror) loopOnce() { 190 tm.t.Helper() 191 if err := tm.buildRepo.loopOnce(); err != nil { 192 tm.t.Fatal(err) 193 } 194 } 195 196 func (tm *testMirror) commit(content string) { 197 tm.t.Helper() 198 if err := os.WriteFile(filepath.Join(tm.gerrit, "README"), []byte(content), 0777); err != nil { 199 tm.t.Fatal(err) 200 } 201 tm.git(tm.gerrit, "add", ".") 202 tm.git(tm.gerrit, "commit", "-m", content) 203 } 204 205 func (tm *testMirror) git(dir string, args ...string) string { 206 tm.t.Helper() 207 cmd := exec.Command("git", args...) 208 envutil.SetDir(cmd, dir) 209 out, err := cmd.CombinedOutput() 210 if err != nil { 211 tm.t.Fatalf("git: %v, %s", err, out) 212 } 213 return string(out) 214 } 215 216 func (tm *testMirror) get(path string) string { 217 tm.t.Helper() 218 resp, err := http.Get(tm.server.URL + path) 219 if err != nil { 220 tm.t.Fatal(err) 221 } 222 body, err := io.ReadAll(resp.Body) 223 resp.Body.Close() 224 if err != nil { 225 tm.t.Fatal(err) 226 } 227 if resp.StatusCode != http.StatusOK { 228 tm.t.Fatalf("request for %q failed", path) 229 } 230 return string(body) 231 }