infra/go/internal/git: Fix bug with GetGitRepoRevision and add new functions

Also moved git-specific assert functions from test_util package to git package
to avoid circular imports.

BUG=chromium:980346
TEST=run_tests.sh

Change-Id: I21890c4b4dff2c62af5b90a4bbe0921810c54bd3
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/infra/go/+/1742413
Reviewed-by: Benjamin Gordon <bmgordon@chromium.org>
Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
Commit-Queue: Jack Neus <jackneus@google.com>
Tested-by: Jack Neus <jackneus@google.com>
diff --git a/internal/git/git_test.go b/internal/git/git_test.go
index c02bac5..0a01b09 100644
--- a/internal/git/git_test.go
+++ b/internal/git/git_test.go
@@ -5,13 +5,15 @@
 
 import (
 	"fmt"
-	"go.chromium.org/chromiumos/infra/go/internal/cmd"
 	"gotest.tools/assert"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
 	"testing"
+
+	"go.chromium.org/chromiumos/infra/go/internal/cmd"
+	"go.chromium.org/chromiumos/infra/go/internal/test_util"
 )
 
 func TestRunGit_success(t *testing.T) {
@@ -463,3 +465,90 @@
 	}
 	assert.NilError(t, Clone(remote, dest))
 }
+
+func TestRemoteBranches(t *testing.T) {
+	CommandRunnerImpl = cmd.RealCommandRunner{}
+
+	local, err := ioutil.TempDir("", "gittest_tmp_dir")
+	defer os.RemoveAll(local)
+
+	remote, err := ioutil.TempDir("", "gittest_tmp_dir")
+	defer os.RemoveAll(remote)
+
+	assert.NilError(t, err)
+	// Create repos.
+	assert.NilError(t, Init(local, false))
+	assert.NilError(t, Init(remote, false))
+	// Create local master branch.
+	assert.NilError(t, CreateBranch(local, "master"))
+	// In order for the ref to be created, need to commit something.
+	assert.NilError(t, ioutil.WriteFile(filepath.Join(local, "foo"), []byte("foo"), 0644))
+	_, err = CommitAll(local, "init commit")
+	assert.NilError(t, err)
+	// Add remote.
+	assert.NilError(t, AddRemote(local, "remote", remote))
+	// Create remote branches.
+	remoteRef := RemoteRef{
+		Remote: "remote",
+		Ref:    "foo",
+	}
+	assert.NilError(t, PushRef(local, "HEAD", false, remoteRef))
+	remoteRef.Ref = "bar"
+	assert.NilError(t, PushRef(local, "HEAD", false, remoteRef))
+
+	branches, err := RemoteBranches(local, "remote")
+	assert.NilError(t, err)
+	assert.Assert(t, test_util.UnorderedEqual(branches, []string{"foo", "bar"}))
+	ok, err := RemoteHasBranch(local, "remote", "foo")
+	assert.NilError(t, err)
+	assert.Assert(t, ok)
+	ok, err = RemoteHasBranch(local, "remote", "baz")
+	assert.NilError(t, err)
+	assert.Assert(t, !ok)
+}
+
+func TestAssertGitBranches_success(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "assert_git_branches_test")
+	assert.NilError(t, err)
+	defer os.RemoveAll(tmpDir)
+
+	assert.NilError(t, Init(tmpDir, false))
+
+	branches := []string{"branch1", "branch2", "branch3", "extra"}
+	for _, branch := range branches {
+		assert.NilError(t, CreateBranch(tmpDir, branch))
+		// Empty commit so that branch is not "unborn".
+		_, err := RunGit(tmpDir, []string{"commit", "-m", "init", "--allow-empty"})
+		assert.NilError(t, err)
+	}
+
+	assert.NilError(t, AssertGitBranches(tmpDir, branches[:3]))
+}
+
+func TestAssertGitBranchesExact_success(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "assert_git_branches_test")
+	assert.NilError(t, err)
+	defer os.RemoveAll(tmpDir)
+
+	assert.NilError(t, Init(tmpDir, false))
+
+	branches := []string{"branch1", "branch2", "branch3", "branch4"}
+	for _, branch := range branches {
+		assert.NilError(t, CreateBranch(tmpDir, branch))
+		// Empty commit so that branch is not "unborn".
+		_, err := RunGit(tmpDir, []string{"commit", "-m", "init", "--allow-empty"})
+		assert.NilError(t, err)
+	}
+
+	assert.NilError(t, AssertGitBranchesExact(tmpDir, append(branches, "branch2")))
+	assert.ErrorContains(t, AssertGitBranchesExact(tmpDir, branches[:3]), "mismatch")
+}
+
+func TestAssertGitBranches_failure(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "assert_git_branches_test")
+	assert.NilError(t, err)
+	defer os.RemoveAll(tmpDir)
+
+	assert.NilError(t, Init(tmpDir, false))
+	assert.ErrorContains(t, AssertGitBranches(tmpDir, []string{"master", "foo"}), "mismatch")
+}