go.fuchsia.dev/infra@v0.0.0-20240507153436-9b593402251b/checkout/checkout_integration_test.go (about)

     1  // Copyright 2019 The Fuchsia 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.
     4  
     5  // This file implements integration tests for the checkout package. It depends on a real
     6  // gitiles project (fuchsia.googlesource.com/infra/testproject) with real Gerrit
     7  // patchsets. These tests are skipped on CQ. since they are integration tests. You can run
     8  // them locally by invoking `go test` without the -short flag.
     9  package checkout
    10  
    11  import (
    12  	"bytes"
    13  	"context"
    14  	"errors"
    15  	"fmt"
    16  	"net/url"
    17  	"os"
    18  	"os/exec"
    19  	"strings"
    20  	"testing"
    21  
    22  	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
    23  	"go.fuchsia.dev/infra/execution"
    24  )
    25  
    26  // Verifies that a repository is checked out via rebasing a patchset onto a commit when
    27  // the build input contains a Gerrit change and Gitiles commit for the input repository.
    28  // We always fail if there's a merge conflict when attempting to rebase, so this test only
    29  // verifies the case where there is no conflict.
    30  func TestCheckoutChange(t *testing.T) {
    31  	os.Chdir(t.TempDir())
    32  
    33  	ctx := context.Background()
    34  	repo := url.URL{
    35  		Scheme: "https",
    36  		Host:   "fuchsia.googlesource.com",
    37  		Path:   "infra/testproject",
    38  	}
    39  	input := &buildbucketpb.Build_Input{
    40  		GitilesCommit: &buildbucketpb.GitilesCommit{
    41  			Host:    "fuchsia.googlesource.com",
    42  			Project: "infra/testproject",
    43  			Id:      "813624618670bf1ae072a5e24d05b0bbda7240a0",
    44  		},
    45  		GerritChanges: []*buildbucketpb.GerritChange{{
    46  			Host:     "fuchsia-review.googlesource.com",
    47  			Project:  "infra/testproject",
    48  			Change:   284673,
    49  			Patchset: 3,
    50  		}},
    51  	}
    52  	if err := doCheckout(ctx, input, repo); err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	var stdout, stderr bytes.Buffer
    57  	executor := execution.NewExecutor(&stdout, &stderr, "")
    58  
    59  	// Use the path to git loaded in the checkout package's init() function.
    60  	if err := executor.Exec(ctx, git, "log", "--pretty=oneline", "--abbrev-commit"); err != nil {
    61  		t.Fatal(err, stderr.String())
    62  	}
    63  	t.Log(stdout.String())
    64  	t.Log(stderr.String())
    65  
    66  	actualLog := strings.TrimSpace(stdout.String())
    67  	expectedLog := "28d5d51 Add rebased.txt\n8136246 Add README.md"
    68  	if actualLog != expectedLog {
    69  		t.Errorf("expected commit log:\n%s\ngot:\n%s", expectedLog, actualLog)
    70  	}
    71  }
    72  
    73  // Verifies that a repository is checked out from a commit when the build input contains a
    74  // Gitiles commit for the input repository.
    75  func TestCheckoutCommit(t *testing.T) {
    76  	os.Chdir(t.TempDir())
    77  
    78  	ctx := context.Background()
    79  	repo := url.URL{
    80  		Scheme: "https",
    81  		Host:   "fuchsia.googlesource.com",
    82  		Path:   "infra/testproject",
    83  	}
    84  	input := &buildbucketpb.Build_Input{
    85  		GitilesCommit: &buildbucketpb.GitilesCommit{
    86  			Host:    "fuchsia.googlesource.com",
    87  			Project: "infra/testproject",
    88  			Id:      "813624618670bf1ae072a5e24d05b0bbda7240a0",
    89  		},
    90  	}
    91  	if err := doCheckout(ctx, input, repo); err != nil {
    92  		t.Fatal(err)
    93  	}
    94  
    95  	var stdout, stderr bytes.Buffer
    96  	executor := execution.NewExecutor(&stdout, &stderr, "")
    97  
    98  	// Use the path to git loaded in the checkout package's init() function.
    99  	if err := executor.Exec(ctx, git, "log", "--pretty=oneline", "--abbrev-commit"); err != nil {
   100  		t.Fatal(err, stderr.String())
   101  	}
   102  	t.Log(stdout.String())
   103  	t.Log(stderr.String())
   104  
   105  	actualLog := strings.TrimSpace(stdout.String())
   106  	expectedLog := "8136246 Add README.md"
   107  	if actualLog != expectedLog {
   108  		t.Errorf("expected commit log:\n%s\ngot:\n%s", expectedLog, actualLog)
   109  	}
   110  }
   111  
   112  func TestCheckoutHead(t *testing.T) {
   113  	os.Chdir(t.TempDir())
   114  
   115  	ctx := context.Background()
   116  	repo := url.URL{
   117  		Scheme: "https",
   118  		Host:   "fuchsia.googlesource.com",
   119  		Path:   "infra/testproject",
   120  	}
   121  	input := &buildbucketpb.Build_Input{
   122  		// Empty commit to force a checkout at HEAD.
   123  		GitilesCommit: &buildbucketpb.GitilesCommit{},
   124  	}
   125  	if err := doCheckout(ctx, input, repo); err != nil {
   126  		t.Fatal(err)
   127  	}
   128  }
   129  
   130  func doCheckout(ctx context.Context, input *buildbucketpb.Build_Input, repoURL url.URL) error {
   131  	// Verify the cwd is not a git checkout, but ends up being one after Checkout()
   132  	// completes.
   133  	inGitCheckout, err := isInGitCheckout(ctx)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	if inGitCheckout {
   138  		return errors.New("failed test precondition: already in a git checkout")
   139  	}
   140  
   141  	if err := Checkout(ctx, input, repoURL, "HEAD", ""); err != nil {
   142  		return fmt.Errorf("checkout failed: %w", err)
   143  	}
   144  
   145  	inGitCheckout, err = isInGitCheckout(ctx)
   146  	if err != nil {
   147  		return err
   148  	}
   149  	if !inGitCheckout {
   150  		return errors.New("expected to be in a git checkout after Checkout()")
   151  	}
   152  	return nil
   153  }
   154  
   155  func isInGitCheckout(ctx context.Context) (bool, error) {
   156  	executor := execution.NewExecutor(os.Stderr, os.Stderr, "")
   157  	if err := executor.Exec(ctx, git, "status"); err != nil {
   158  		var errExit *exec.ExitError
   159  		if errors.As(err, &errExit) && errExit.ExitCode() != 0 {
   160  			return false, nil
   161  		}
   162  		return false, err
   163  	}
   164  	return true, nil
   165  }