blob: c02bac5b923e17f7b17acb53fce23406d090eeec [file] [log] [blame]
Jack Neusfc3b5772019-07-03 11:18:42 -06001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4package git
5
6import (
Jack Neusabdbe192019-07-15 12:23:22 -06007 "fmt"
Jack Neus07511722019-07-12 15:41:10 -06008 "go.chromium.org/chromiumos/infra/go/internal/cmd"
Jack Neusfc3b5772019-07-03 11:18:42 -06009 "gotest.tools/assert"
Jack Neus0296c732019-07-17 09:35:01 -060010 "io/ioutil"
11 "os"
12 "path/filepath"
Jack Neusfc3b5772019-07-03 11:18:42 -060013 "regexp"
Jack Neusfc3b5772019-07-03 11:18:42 -060014 "testing"
15)
16
Jack Neus07511722019-07-12 15:41:10 -060017func TestRunGit_success(t *testing.T) {
18 CommandRunnerImpl = cmd.FakeCommandRunner{
19 ExpectedDir: "myrepo",
20 ExpectedCmd: []string{"git", "log"},
21 Stdout: "success",
22 }
23
24 output, err := RunGit("myrepo", []string{"log"})
25 assert.NilError(t, err)
26 assert.Equal(t, output.Stdout, "success")
Jack Neusfc3b5772019-07-03 11:18:42 -060027}
28
Jack Neus07511722019-07-12 15:41:10 -060029func TestRunGit_error(t *testing.T) {
30 CommandRunnerImpl = cmd.FakeCommandRunner{
31 ExpectedDir: "myrepo",
32 ExpectedCmd: []string{"git", "log"},
33 Stdout: "I don't feel so go--",
34 Stderr: "sudden death",
35 FailCommand: true,
Jack Neusfc3b5772019-07-03 11:18:42 -060036 }
Jack Neusfc3b5772019-07-03 11:18:42 -060037
Jack Neus07511722019-07-12 15:41:10 -060038 output, err := RunGit("myrepo", []string{"log"})
39 assert.Assert(t, err != nil)
40 assert.Equal(t, output.Stderr, "sudden death")
Jack Neusfc3b5772019-07-03 11:18:42 -060041}
42
43func TestStripRefsHead(t *testing.T) {
44 assert.Equal(t, StripRefsHead("refs/heads/foo"), "foo")
45 assert.Equal(t, StripRefsHead("foo"), "foo")
46}
47
48func TestStripRefs(t *testing.T) {
49 assert.Equal(t, StripRefs("refs/remotes/origin/foo"), "foo")
50 assert.Equal(t, StripRefs("refs/heads/foo"), "foo")
51 assert.Equal(t, StripRefs("foo"), "foo")
52}
53
54func TestNormalizeRef(t *testing.T) {
55 assert.Equal(t, NormalizeRef("refs/heads/foo"), "refs/heads/foo")
56 assert.Equal(t, NormalizeRef("foo"), "refs/heads/foo")
57}
58
59func TestGetCurrentBranch_success(t *testing.T) {
60 fakeGitRepo := "top-secret-project"
61 fakeGitData := "refs/heads/current-branch"
62
Jack Neus07511722019-07-12 15:41:10 -060063 CommandRunnerImpl = cmd.FakeCommandRunner{
64 ExpectedDir: fakeGitRepo,
65 Stdout: fakeGitData,
Jack Neusfc3b5772019-07-03 11:18:42 -060066 }
67 assert.Equal(t, GetCurrentBranch(fakeGitRepo), "current-branch")
68}
69
70func TestGetCurrentBranch_failure(t *testing.T) {
Jack Neus07511722019-07-12 15:41:10 -060071 CommandRunnerImpl = cmd.FakeCommandRunner{
72 FailCommand: true,
Jack Neusfc3b5772019-07-03 11:18:42 -060073 }
74 assert.Equal(t, GetCurrentBranch("project"), "")
75}
76
77func TestMatchBranchName_success(t *testing.T) {
78 fakeGitRepo := "top-secret-project"
79 fakeGitData := "e9cb56bd9af9365b43f82cecf28cc76d49df1f72 refs/heads/foo\n" +
80 "f9c1bb630f4475058d4a9db4aea52fc89d8f7b0d refs/heads/bar\n" +
81 "2102915989de21d9251c11f0a7b5307e175e7677 refs/heads/foobar\n" +
82 "04975f9439ff75502b33d9491155692736e05b07 refs/heads/baz\n"
83
Jack Neus07511722019-07-12 15:41:10 -060084 CommandRunnerImpl = cmd.FakeCommandRunner{
Jack Neus901a6bf2019-07-22 08:30:07 -060085 ExpectedCmd: []string{"git", "show-ref"},
Jack Neus07511722019-07-12 15:41:10 -060086 ExpectedDir: fakeGitRepo,
87 Stdout: fakeGitData,
Jack Neusfc3b5772019-07-03 11:18:42 -060088 }
89
90 expectedMatches := []string{"refs/heads/foo", "refs/heads/foobar"}
91 branches, err := MatchBranchName(fakeGitRepo, regexp.MustCompile("Foo"))
92 assert.NilError(t, err)
93 assert.DeepEqual(t, expectedMatches, branches)
94
95 expectedMatches = []string{"refs/heads/foo"}
96 branches, err = MatchBranchName(fakeGitRepo, regexp.MustCompile("Foo$"))
97 assert.NilError(t, err)
98 assert.DeepEqual(t, expectedMatches, branches)
99}
100
Jack Neus10e6a122019-07-18 10:17:44 -0600101func TestMatchBranchNameWithNamespace_success(t *testing.T) {
102 fakeGitRepo := "top-secret-project"
103 fakeGitData := "e9cb56bd9af9365b43f82cecf28cc76d49df1f72 refs/changes/foo\n" +
104 "f9c1bb630f4475058d4a9db4aea52fc89d8f7b0d refs/changes/bar\n" +
105 "2102915989de21d9251c11f0a7b5307e175e7677 refs/heads/foobar\n" +
106 "04975f9439ff75502b33d9491155692736e05b07 refs/heads/baz\n"
107
108 CommandRunnerImpl = cmd.FakeCommandRunner{
Jack Neus901a6bf2019-07-22 08:30:07 -0600109 ExpectedCmd: []string{"git", "show-ref"},
Jack Neus10e6a122019-07-18 10:17:44 -0600110 ExpectedDir: fakeGitRepo,
111 Stdout: fakeGitData,
112 }
113
114 expectedMatches := []string{"foobar"}
115 pattern := regexp.MustCompile("FOO")
116 namespace := regexp.MustCompile("refs/heads/")
117 branches, err := MatchBranchNameWithNamespace(fakeGitRepo, pattern, namespace)
118 assert.NilError(t, err)
119 assert.DeepEqual(t, expectedMatches, branches)
120}
121
Jack Neusfc3b5772019-07-03 11:18:42 -0600122func TestGetRepoRevision(t *testing.T) {
123 sha := "6446dfef4b55689046395c2db7ba7c35377927fe"
Jack Neus07511722019-07-12 15:41:10 -0600124 CommandRunnerImpl = cmd.FakeCommandRunner{
125 ExpectedCmd: []string{"git", "rev-parse", "HEAD"},
126 ExpectedDir: "project",
127 Stdout: sha,
Jack Neusfc3b5772019-07-03 11:18:42 -0600128 }
Jack Neusa7287522019-07-23 16:36:18 -0600129 res, err := GetGitRepoRevision("project", "")
Jack Neusfc3b5772019-07-03 11:18:42 -0600130 assert.NilError(t, err)
131 assert.Equal(t, res, sha)
132}
Jack Neusabdbe192019-07-15 12:23:22 -0600133
Jack Neusa7287522019-07-23 16:36:18 -0600134func TestIsReachable_true(t *testing.T) {
135 fakeGitRepo := "gitRepo"
136 toRef := "beef"
137 fromRef := "deaf"
138
139 CommandRunnerImpl = cmd.FakeCommandRunner{
140 ExpectedCmd: []string{"git", "merge-base", "--is-ancestor", toRef, fromRef},
141 ExpectedDir: fakeGitRepo,
142 }
143
144 ok, err := IsReachable(fakeGitRepo, toRef, fromRef)
145 assert.NilError(t, err)
146 assert.Assert(t, ok)
147}
148
149func TestIsReachable_false(t *testing.T) {
150 fakeGitRepo := "gitRepo"
151 toRef := "beef"
152 fromRef := "deaf"
153
154 CommandRunnerImpl = cmd.FakeCommandRunner{
155 ExpectedCmd: []string{"git", "merge-base", "--is-ancestor", toRef, fromRef},
156 ExpectedDir: fakeGitRepo,
157 FailCommand: true,
158 FailError: "exit status 1",
159 }
160
161 ok, err := IsReachable(fakeGitRepo, toRef, fromRef)
162 assert.NilError(t, err)
163 assert.Assert(t, !ok)
164}
165
Jack Neus04f4edc2019-07-31 16:42:00 -0600166func TestIsReachable_self(t *testing.T) {
167 CommandRunnerImpl = cmd.RealCommandRunner{}
168
169 tmpDir := "gittest_tmp_dir"
170 tmpDir, err := ioutil.TempDir("", tmpDir)
171 defer os.RemoveAll(tmpDir)
172
173 assert.NilError(t, err)
174 // Create repo.
175 assert.NilError(t, Init(tmpDir, false))
176 // Make commit.
177 commit, err := CommitEmpty(tmpDir, "empty commit")
178 assert.NilError(t, err)
179 // Check that a SHA is reachable from itself.
180 ok, err := IsReachable(tmpDir, commit, commit)
181 assert.NilError(t, err)
182 assert.Assert(t, ok)
183}
184
Jack Neusabdbe192019-07-15 12:23:22 -0600185func TestCreateBranch(t *testing.T) {
186 fakeGitRepo := "top-secret-project"
187 branchName := "project z"
188
189 CommandRunnerImpl = cmd.FakeCommandRunner{
190 ExpectedDir: fakeGitRepo,
Jack Neus0296c732019-07-17 09:35:01 -0600191 ExpectedCmd: []string{"git", "checkout", "-B", branchName},
Jack Neusabdbe192019-07-15 12:23:22 -0600192 }
193 assert.NilError(t, CreateBranch(fakeGitRepo, branchName))
194}
195
Jack Neus0296c732019-07-17 09:35:01 -0600196func TestCreateTrackingBranch(t *testing.T) {
197 fakeGitRepo := "repo"
198 branchName := "branch"
199 remoteRef := RemoteRef{
200 Remote: "remote",
201 Ref: "master",
202 }
203 refspec := fmt.Sprintf("%s/%s", remoteRef.Remote, remoteRef.Ref)
204
205 CommandRunnerImpl = &cmd.FakeCommandRunnerMulti{
206 CommandRunners: []cmd.FakeCommandRunner{
207 {
208 ExpectedDir: fakeGitRepo,
209 ExpectedCmd: []string{"git", "fetch", remoteRef.Remote, remoteRef.Ref},
210 },
211 {
212 ExpectedDir: fakeGitRepo,
213 ExpectedCmd: []string{"git", "checkout", "-b", branchName, "-t", refspec},
214 },
215 },
216 }
217
218 err := CreateTrackingBranch(fakeGitRepo, branchName, remoteRef)
219 assert.NilError(t, err)
220}
221
Jack Neusabdbe192019-07-15 12:23:22 -0600222func TestCommitAll(t *testing.T) {
223 fakeGitRepo := "repo"
224 commitMsg := "commit"
225
226 CommandRunnerImpl = &cmd.FakeCommandRunnerMulti{
227 CommandRunners: []cmd.FakeCommandRunner{
228 {
229 ExpectedDir: fakeGitRepo,
230 ExpectedCmd: []string{"git", "add", "-A"},
231 },
232 {
233 ExpectedDir: fakeGitRepo,
234 ExpectedCmd: []string{"git", "commit", "-m", commitMsg},
235 },
Jack Neusf116fae2019-07-24 15:05:03 -0600236 {
237 ExpectedDir: fakeGitRepo,
238 ExpectedCmd: []string{"git", "rev-parse", "HEAD"},
239 Stdout: "abcde12345\n\n\t\n",
240 },
Jack Neusabdbe192019-07-15 12:23:22 -0600241 },
242 }
243
Jack Neusf116fae2019-07-24 15:05:03 -0600244 commit, err := CommitAll(fakeGitRepo, commitMsg)
Jack Neusabdbe192019-07-15 12:23:22 -0600245 assert.NilError(t, err)
Jack Neusf116fae2019-07-24 15:05:03 -0600246 assert.Equal(t, commit, "abcde12345")
Jack Neusabdbe192019-07-15 12:23:22 -0600247}
248
Jack Neus7440c762019-07-22 10:45:18 -0600249func TestCommitEmpty(t *testing.T) {
250 fakeGitRepo := "repo"
251 commitMsg := "commit"
252
Jack Neusf116fae2019-07-24 15:05:03 -0600253 CommandRunnerImpl = &cmd.FakeCommandRunnerMulti{
254 CommandRunners: []cmd.FakeCommandRunner{
255 {
256 ExpectedDir: fakeGitRepo,
257 ExpectedCmd: []string{"git", "commit", "-m", commitMsg, "--allow-empty"},
258 },
259 {
260 ExpectedDir: fakeGitRepo,
261 ExpectedCmd: []string{"git", "rev-parse", "HEAD"},
262 Stdout: "abcde12345\n\n\t\n",
263 },
264 },
Jack Neus7440c762019-07-22 10:45:18 -0600265 }
266
Jack Neusf116fae2019-07-24 15:05:03 -0600267 commit, err := CommitEmpty(fakeGitRepo, commitMsg)
Jack Neus7440c762019-07-22 10:45:18 -0600268 assert.NilError(t, err)
Jack Neusf116fae2019-07-24 15:05:03 -0600269 assert.Equal(t, commit, "abcde12345")
Jack Neus7440c762019-07-22 10:45:18 -0600270}
271
Jack Neusabdbe192019-07-15 12:23:22 -0600272func TestPushChanges(t *testing.T) {
273 fakeGitRepo := "da-bank"
274 commitMsg := "da-money"
275 localRef := "da-vault"
276
277 remoteRef := RemoteRef{
278 Remote: "da-family",
279 Ref: "da-van",
280 }
281
282 pushStr := fmt.Sprintf("%s:%s", localRef, remoteRef.Ref)
283 CommandRunnerImpl = &cmd.FakeCommandRunnerMulti{
284 CommandRunners: []cmd.FakeCommandRunner{
285 {
286 ExpectedDir: fakeGitRepo,
287 ExpectedCmd: []string{"git", "add", "-A"},
288 },
289 {
290 ExpectedDir: fakeGitRepo,
291 ExpectedCmd: []string{"git", "commit", "-m", commitMsg},
292 },
293 {
294 ExpectedDir: fakeGitRepo,
Jack Neusf116fae2019-07-24 15:05:03 -0600295 ExpectedCmd: []string{"git", "rev-parse", "HEAD"},
296 Stdout: "abcde\n",
297 },
298 {
299 ExpectedDir: fakeGitRepo,
Jack Neusabdbe192019-07-15 12:23:22 -0600300 ExpectedCmd: []string{"git", "push", remoteRef.Remote, pushStr, "--dry-run"},
301 },
302 },
303 }
304
Jack Neusf116fae2019-07-24 15:05:03 -0600305 commit, err := PushChanges(fakeGitRepo, localRef, commitMsg, true, remoteRef)
Jack Neusabdbe192019-07-15 12:23:22 -0600306 assert.NilError(t, err)
Jack Neusf116fae2019-07-24 15:05:03 -0600307 assert.Equal(t, commit, "abcde")
Jack Neusabdbe192019-07-15 12:23:22 -0600308}
Jack Neus0296c732019-07-17 09:35:01 -0600309
Jack Neuseb25f722019-07-19 16:33:20 -0600310func TestPushRef(t *testing.T) {
Jack Neus7440c762019-07-22 10:45:18 -0600311 fakeGitRepo := "repo"
312 localRef := "commitId"
313
314 remoteRef := RemoteRef{
315 Remote: "remote",
316 Ref: "ref",
317 }
318
319 pushStr := fmt.Sprintf("%s:%s", localRef, remoteRef.Ref)
320 CommandRunnerImpl = cmd.FakeCommandRunner{
321 ExpectedDir: fakeGitRepo,
322 ExpectedCmd: []string{"git", "push", remoteRef.Remote, pushStr, "--dry-run"},
323 }
324
Jack Neuseb25f722019-07-19 16:33:20 -0600325 err := PushRef(fakeGitRepo, localRef, true, remoteRef)
Jack Neus7440c762019-07-22 10:45:18 -0600326 assert.NilError(t, err)
327}
328
Jack Neus0296c732019-07-17 09:35:01 -0600329func TestInit(t *testing.T) {
330 fakeGitRepo := "top-secret-project"
331
332 CommandRunnerImpl = cmd.FakeCommandRunner{
333 ExpectedDir: fakeGitRepo,
334 ExpectedCmd: []string{"git", "init"},
335 }
336 assert.NilError(t, Init(fakeGitRepo, false))
337}
338
339func TestInit_bare(t *testing.T) {
340 fakeGitRepo := "top-secret-project"
341
342 CommandRunnerImpl = cmd.FakeCommandRunner{
343 ExpectedDir: fakeGitRepo,
344 ExpectedCmd: []string{"git", "init", "--bare"},
345 }
346 assert.NilError(t, Init(fakeGitRepo, true))
347}
348
349func TestAddRemote(t *testing.T) {
350 fakeGitRepo := "repo"
351 remoteName := "remote"
352 remoteLoc := "remote/"
353
354 CommandRunnerImpl = cmd.FakeCommandRunner{
355 ExpectedDir: fakeGitRepo,
356 ExpectedCmd: []string{"git", "remote", "add", remoteName, remoteLoc},
357 }
358 assert.NilError(t, AddRemote(fakeGitRepo, remoteName, remoteLoc))
359}
360
361func TestCheckout(t *testing.T) {
362 CommandRunnerImpl = cmd.RealCommandRunner{}
363
364 tmpDir := "gittest_tmp_dir"
365 tmpDir, err := ioutil.TempDir("", tmpDir)
366 defer os.RemoveAll(tmpDir)
367
368 assert.NilError(t, err)
369 // Create repo.
370 assert.NilError(t, Init(tmpDir, false))
371 // Create first branch.
372 assert.NilError(t, CreateBranch(tmpDir, "branch1"))
373 // In order for the ref to be created, need to commit something.
374 assert.NilError(t, ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("foo"), 0644))
Jack Neusf116fae2019-07-24 15:05:03 -0600375 _, err = CommitAll(tmpDir, "init commit")
376 assert.NilError(t, err)
Jack Neus0296c732019-07-17 09:35:01 -0600377 // Create second branch (will switch to this branch).
378 assert.NilError(t, CreateBranch(tmpDir, "branch2"))
379 // Try checking out a nonexistent branch.
380 assert.ErrorContains(t, Checkout(tmpDir, "branch3"), "did not match any")
381 // Try checking out the first branch.
382 assert.NilError(t, Checkout(tmpDir, "branch1"))
383}
384
385func TestDeleteBranch_success(t *testing.T) {
386 CommandRunnerImpl = cmd.RealCommandRunner{}
387
388 tmpDir := "gittest_tmp_dir"
389 tmpDir, err := ioutil.TempDir("", tmpDir)
390 defer os.RemoveAll(tmpDir)
391 branchName := "newbranch"
392
393 assert.NilError(t, err)
394 // Create repo.
395 assert.NilError(t, Init(tmpDir, false))
396 // Create master branch.
397 assert.NilError(t, CreateBranch(tmpDir, "master"))
398 // In order for the ref to be created, need to commit something.
399 assert.NilError(t, ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("foo"), 0644))
Jack Neusf116fae2019-07-24 15:05:03 -0600400 _, err = CommitAll(tmpDir, "init commit")
401 assert.NilError(t, err)
Jack Neus0296c732019-07-17 09:35:01 -0600402 // Create branch to be deleted.
403 assert.NilError(t, CreateBranch(tmpDir, branchName))
404 // Switch back to master.
405 assert.NilError(t, Checkout(tmpDir, "master"))
406 err = DeleteBranch(tmpDir, branchName, true)
407 assert.NilError(t, err)
408}
409
410func TestDeleteBranch_inBranch(t *testing.T) {
411 CommandRunnerImpl = cmd.RealCommandRunner{}
412
413 tmpDir := "gittest_tmp_dir"
414 tmpDir, err := ioutil.TempDir("", tmpDir)
415 defer os.RemoveAll(tmpDir)
416 branchName := "newbranch"
417
418 assert.NilError(t, err)
419 // Create repo.
420 assert.NilError(t, Init(tmpDir, false))
421 // Create branch.
422 assert.NilError(t, CreateBranch(tmpDir, branchName))
423 err = DeleteBranch(tmpDir, branchName, true)
424 assert.ErrorContains(t, err, "checked out")
425}
426
427func TestDeleteBranch_unmerged(t *testing.T) {
428 CommandRunnerImpl = cmd.RealCommandRunner{}
429
430 tmpDir := "gittest_tmp_dir"
431 tmpDir, err := ioutil.TempDir("", tmpDir)
432 defer os.RemoveAll(tmpDir)
433 branchName := "newbranch"
434
435 assert.NilError(t, err)
436 // Create repo.
437 assert.NilError(t, Init(tmpDir, false))
438 // Create master branch.
439 assert.NilError(t, CreateBranch(tmpDir, "master"))
440 // In order for the ref to be created, need to commit something.
441 assert.NilError(t, ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("foo"), 0644))
Jack Neusf116fae2019-07-24 15:05:03 -0600442 _, err = CommitAll(tmpDir, "init commit")
443 assert.NilError(t, err)
Jack Neus0296c732019-07-17 09:35:01 -0600444 // Create test branch.
445 assert.NilError(t, CreateBranch(tmpDir, branchName))
446 // Make a change to branch.
447 assert.NilError(t, ioutil.WriteFile(filepath.Join(tmpDir, "bar"), []byte("bar"), 0644))
Jack Neusf116fae2019-07-24 15:05:03 -0600448 _, err = CommitAll(tmpDir, "init commit")
449 assert.NilError(t, err)
Jack Neus0296c732019-07-17 09:35:01 -0600450 // Switch back to master.
451 assert.NilError(t, Checkout(tmpDir, "master"))
452 // Should not be able to delete.
453 assert.ErrorContains(t, DeleteBranch(tmpDir, branchName, false), "fully merged")
454}
455
456func TestClone(t *testing.T) {
457 dest := "foo/bar"
458 remote := "remote"
459
460 CommandRunnerImpl = cmd.FakeCommandRunner{
461 ExpectedDir: "foo",
462 ExpectedCmd: []string{"git", "clone", remote, "bar"},
463 }
464 assert.NilError(t, Clone(remote, dest))
465}