| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file implements integration tests for the checkout package. It depends on a real |
| // gitiles project (fuchsia.googlesource.com/infra/testproject) with real Gerrit |
| // patchsets. These tests are skipped on CQ. since they are integration tests. You can run |
| // them locally by invoking `go test` without the -short flag. |
| package checkout |
| |
| import ( |
| "bytes" |
| "context" |
| "errors" |
| "fmt" |
| "net/url" |
| "os" |
| "os/exec" |
| "strings" |
| "testing" |
| |
| buildbucketpb "go.chromium.org/luci/buildbucket/proto" |
| "go.fuchsia.dev/infra/execution" |
| ) |
| |
| // Verifies that a repository is checked out via rebasing a patchset onto a commit when |
| // the build input contains a Gerrit change and Gitiles commit for the input repository. |
| // We always fail if there's a merge conflict when attempting to rebase, so this test only |
| // verifies the case where there is no conflict. |
| func TestCheckoutChange(t *testing.T) { |
| os.Chdir(t.TempDir()) |
| |
| ctx := context.Background() |
| repo := url.URL{ |
| Scheme: "https", |
| Host: "fuchsia.googlesource.com", |
| Path: "infra/testproject", |
| } |
| input := &buildbucketpb.Build_Input{ |
| GitilesCommit: &buildbucketpb.GitilesCommit{ |
| Host: "fuchsia.googlesource.com", |
| Project: "infra/testproject", |
| Id: "813624618670bf1ae072a5e24d05b0bbda7240a0", |
| }, |
| GerritChanges: []*buildbucketpb.GerritChange{{ |
| Host: "fuchsia-review.googlesource.com", |
| Project: "infra/testproject", |
| Change: 284673, |
| Patchset: 3, |
| }}, |
| } |
| if err := doCheckout(ctx, input, repo); err != nil { |
| t.Fatal(err) |
| } |
| |
| var stdout, stderr bytes.Buffer |
| executor := execution.NewExecutor(&stdout, &stderr, "") |
| |
| // Use the path to git loaded in the checkout package's init() function. |
| if err := executor.Exec(ctx, git, "log", "--pretty=oneline", "--abbrev-commit"); err != nil { |
| t.Fatal(err, stderr.String()) |
| } |
| t.Log(stdout.String()) |
| t.Log(stderr.String()) |
| |
| actualLog := strings.TrimSpace(stdout.String()) |
| expectedLog := "28d5d51 Add rebased.txt\n8136246 Add README.md" |
| if actualLog != expectedLog { |
| t.Errorf("expected commit log:\n%s\ngot:\n%s", expectedLog, actualLog) |
| } |
| } |
| |
| // Verifies that a repository is checked out from a commit when the build input contains a |
| // Gitiles commit for the input repository. |
| func TestCheckoutCommit(t *testing.T) { |
| os.Chdir(t.TempDir()) |
| |
| ctx := context.Background() |
| repo := url.URL{ |
| Scheme: "https", |
| Host: "fuchsia.googlesource.com", |
| Path: "infra/testproject", |
| } |
| input := &buildbucketpb.Build_Input{ |
| GitilesCommit: &buildbucketpb.GitilesCommit{ |
| Host: "fuchsia.googlesource.com", |
| Project: "infra/testproject", |
| Id: "813624618670bf1ae072a5e24d05b0bbda7240a0", |
| }, |
| } |
| if err := doCheckout(ctx, input, repo); err != nil { |
| t.Fatal(err) |
| } |
| |
| var stdout, stderr bytes.Buffer |
| executor := execution.NewExecutor(&stdout, &stderr, "") |
| |
| // Use the path to git loaded in the checkout package's init() function. |
| if err := executor.Exec(ctx, git, "log", "--pretty=oneline", "--abbrev-commit"); err != nil { |
| t.Fatal(err, stderr.String()) |
| } |
| t.Log(stdout.String()) |
| t.Log(stderr.String()) |
| |
| actualLog := strings.TrimSpace(stdout.String()) |
| expectedLog := "8136246 Add README.md" |
| if actualLog != expectedLog { |
| t.Errorf("expected commit log:\n%s\ngot:\n%s", expectedLog, actualLog) |
| } |
| } |
| |
| func TestCheckoutHead(t *testing.T) { |
| os.Chdir(t.TempDir()) |
| |
| ctx := context.Background() |
| repo := url.URL{ |
| Scheme: "https", |
| Host: "fuchsia.googlesource.com", |
| Path: "infra/testproject", |
| } |
| input := &buildbucketpb.Build_Input{ |
| // Empty commit to force a checkout at HEAD. |
| GitilesCommit: &buildbucketpb.GitilesCommit{}, |
| } |
| if err := doCheckout(ctx, input, repo); err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| func doCheckout(ctx context.Context, input *buildbucketpb.Build_Input, repoURL url.URL) error { |
| // Verify the cwd is not a git checkout, but ends up being one after Checkout() |
| // completes. |
| inGitCheckout, err := isInGitCheckout(ctx) |
| if err != nil { |
| return err |
| } |
| if inGitCheckout { |
| return errors.New("failed test precondition: already in a git checkout") |
| } |
| |
| if err := Checkout(ctx, input, repoURL, "HEAD", ""); err != nil { |
| return fmt.Errorf("checkout failed: %w", err) |
| } |
| |
| inGitCheckout, err = isInGitCheckout(ctx) |
| if err != nil { |
| return err |
| } |
| if !inGitCheckout { |
| return errors.New("expected to be in a git checkout after Checkout()") |
| } |
| return nil |
| } |
| |
| func isInGitCheckout(ctx context.Context) (bool, error) { |
| executor := execution.NewExecutor(os.Stderr, os.Stderr, "") |
| if err := executor.Exec(ctx, git, "status"); err != nil { |
| var errExit *exec.ExitError |
| if errors.As(err, &errExit) && errExit.ExitCode() != 0 { |
| return false, nil |
| } |
| return false, err |
| } |
| return true, nil |
| } |