gittuf/pkg/gitinterface/sync_test.go
dawgdevv 8374150f3f test: improve pkg/gitinterface coverage from 69.4% to 76.2%
This PR adds focused tests for error paths and edge cases across
pkg/gitinterface, raising coverage from 69.4% to 76.2%.
Files changed:
- references_test.go: TestAbsoluteReference with branch/tag/custom/ref lookups
- tag_test.go: TestEnsureIsTag, error paths for GetTagTarget and verifyTagSignature
- commit_test.go: TestEnsureIsCommit, error paths for commit inspection helpers
- object_test.go: Error paths for GetObjectType and GetObjectSize
- blob_test.go: Error path for ReadBlob with non-blob object
- status_test.go: Tests for Status errors and StatusCode helpers
- sync_test.go: Tests for WithFetchDepth, CreateRemote, push/fetch errors
- config_test.go: Error path for SetGitConfig
- utils_test.go: TestResetDueToError
Closes #1244

Signed-off-by: dawgdevv <nraj02415@gmail.com>
2026-04-25 02:44:19 +05:30

983 lines
28 KiB
Go

// Copyright The gittuf Authors
// SPDX-License-Identifier: Apache-2.0
package gitinterface
import (
"fmt"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPushRefSpecRepository(t *testing.T) {
remoteName := "origin"
refName := "refs/heads/main"
refSpecs := fmt.Sprintf("%s:%s", refName, refName)
t.Run("assert remote repo does not have object until it is pushed", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
// Check that the tree is not present on the remote repository
_, err = remoteRepo.GetAllFilesInTree(tree)
assert.Contains(t, err.Error(), "fatal: not a tree object") // tree doesn't exist
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.PushRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
expectedFiles := map[string]Hash{"foo": emptyBlobHash}
remoteEntries, err := remoteRepo.GetAllFilesInTree(tree)
assert.Nil(t, err)
assert.Equal(t, expectedFiles, remoteEntries)
})
t.Run("assert after push that src and dst refs match", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.PushRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
})
t.Run("assert no error when there are no updates to push", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.PushRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
// Push again; nothing to push
err = localRepo.PushRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
})
t.Run("push to non-existent remote", func(t *testing.T) {
localTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
err := localRepo.PushRefSpec("nonexistent", []string{refSpecs})
assert.ErrorContains(t, err, "unable to push")
})
}
func TestPushRepository(t *testing.T) {
remoteName := "origin"
refName := "refs/heads/main"
t.Run("assert remote repo does not have object until it is pushed", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
// Check that the tree is not present on the remote repository
_, err = remoteRepo.GetAllFilesInTree(tree)
assert.Contains(t, err.Error(), "fatal: not a tree object") // tree doesn't exist
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.Push(remoteName, []string{refName})
assert.Nil(t, err)
expectedFiles := map[string]Hash{"foo": emptyBlobHash}
remoteEntries, err := remoteRepo.GetAllFilesInTree(tree)
assert.Nil(t, err)
assert.Equal(t, expectedFiles, remoteEntries)
})
t.Run("assert after push that src and dst refs match", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.Push(remoteName, []string{refName})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
})
t.Run("assert no error when there are no updates to push", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, true)
localTreeBuilder := NewTreeBuilder(localRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the local repository
emptyBlobHash, err := localRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := localTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
if _, err := localRepo.Commit(tree, refName, "Test commit\n", false); err != nil {
t.Fatal(err)
}
err = localRepo.Push(remoteName, []string{refName})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
// Push again; nothing to push
err = localRepo.Push(remoteName, []string{refName})
assert.Nil(t, err)
})
t.Run("push to non-existent remote", func(t *testing.T) {
localTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
err := localRepo.Push("nonexistent", []string{refName})
assert.ErrorContains(t, err, "unable to push")
})
t.Run("push with invalid ref", func(t *testing.T) {
localTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, false)
err := localRepo.Push("origin", []string{"nonexistent-ref"})
assert.ErrorIs(t, err, ErrReferenceNotFound)
})
}
func TestFetchRefSpecRepository(t *testing.T) {
remoteName := "origin"
refName := "refs/heads/main"
refSpecs := fmt.Sprintf("+%s:%s", refName, refName)
t.Run("assert local repo does not have object until fetched", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
// Check that the tree is not present on the local repository
_, err = localRepo.GetAllFilesInTree(tree)
assert.Contains(t, err.Error(), "fatal: not a tree object") // tree doesn't exist
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.FetchRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
expectedFiles := map[string]Hash{"foo": emptyBlobHash}
localEntries, err := localRepo.GetAllFilesInTree(tree)
assert.Nil(t, err)
assert.Equal(t, expectedFiles, localEntries)
})
t.Run("assert after fetch that both refs match", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.FetchRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
})
t.Run("assert no error when there are no updates to fetch", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.FetchRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
// Fetch again, nothing to fetch
err = localRepo.FetchRefSpec(remoteName, []string{refSpecs})
assert.Nil(t, err)
newLocalRef, err := localRepo.GetReference(refName)
require.Nil(t, err)
assert.Equal(t, localRef, newLocalRef)
})
t.Run("fetch from non-existent remote", func(t *testing.T) {
localTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
err := localRepo.FetchRefSpec("nonexistent", []string{refSpecs})
assert.ErrorContains(t, err, "unable to fetch")
})
}
func TestFetchRepository(t *testing.T) {
remoteName := "origin"
refName := "refs/heads/main"
t.Run("assert local repo does not have object until fetched", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
// Check that the tree is not present on the local repository
_, err = localRepo.GetAllFilesInTree(tree)
assert.Contains(t, err.Error(), "fatal: not a tree object") // tree doesn't exist
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.Fetch(remoteName, []string{refName}, true)
assert.Nil(t, err)
expectedFiles := map[string]Hash{"foo": emptyBlobHash}
localEntries, err := localRepo.GetAllFilesInTree(tree)
assert.Nil(t, err)
assert.Equal(t, expectedFiles, localEntries)
})
t.Run("assert after fetch that both refs match", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.Fetch(remoteName, []string{refName}, true)
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
})
t.Run("assert no error when there are no updates to fetch", func(t *testing.T) {
// Create local and remote repositories
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
// Create the remote on the local repository
if err := localRepo.CreateRemote(remoteName, remoteTmpDir); err != nil {
t.Fatal(err)
}
// Create a tree in the remote repository
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
_, err = remoteRepo.Commit(tree, refName, "Test commit\n", false)
if err != nil {
t.Fatal(err)
}
err = localRepo.Fetch(remoteName, []string{refName}, true)
assert.Nil(t, err)
localRef, err := localRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
remoteRef, err := remoteRepo.GetReference(refName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, localRef, remoteRef)
// Fetch again, nothing to fetch
err = localRepo.Fetch(remoteName, []string{refName}, true)
assert.Nil(t, err)
newLocalRef, err := localRepo.GetReference(refName)
require.Nil(t, err)
assert.Equal(t, localRef, newLocalRef)
})
t.Run("fetch from non-existent remote", func(t *testing.T) {
localTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
err := localRepo.Fetch("nonexistent", []string{refName}, true)
assert.ErrorContains(t, err, "unable to fetch")
})
t.Run("fetch with invalid ref", func(t *testing.T) {
localTmpDir := t.TempDir()
remoteTmpDir := t.TempDir()
localRepo := CreateTestGitRepository(t, localTmpDir, true)
_ = CreateTestGitRepository(t, remoteTmpDir, false)
err := localRepo.CreateRemote(remoteName, remoteTmpDir)
require.Nil(t, err)
err = localRepo.Fetch(remoteName, []string{"nonexistent-ref"}, true)
assert.ErrorIs(t, err, ErrReferenceNotFound)
})
}
func TestFetchObject(t *testing.T) {
tmpDir1 := t.TempDir()
upstreamRepo := CreateTestGitRepository(t, tmpDir1, true)
err := upstreamRepo.SetGitConfig("uploadpack.allowReachableSHA1InWant", "true")
require.Nil(t, err)
treeBuilder := NewTreeBuilder(upstreamRepo)
treeID, err := treeBuilder.WriteTreeFromEntries(nil)
require.Nil(t, err)
commitID, err := upstreamRepo.Commit(treeID, "refs/heads/main", "Initial commit\n", false)
require.Nil(t, err)
tmpDir2 := t.TempDir()
downstreamRepo := CreateTestGitRepository(t, tmpDir2, false)
err = downstreamRepo.AddRemote("origin", tmpDir1)
require.Nil(t, err)
has := downstreamRepo.HasObject(commitID)
assert.False(t, has)
err = downstreamRepo.FetchObject("origin", commitID)
assert.Nil(t, err)
has = downstreamRepo.HasObject(commitID)
assert.True(t, has)
t.Run("fetch from non-existent remote", func(t *testing.T) {
err := downstreamRepo.FetchObject("nonexistent", ZeroHash)
assert.ErrorContains(t, err, "unable to fetch object")
})
}
func TestCloneAndFetchRepository(t *testing.T) {
refName := "refs/heads/main"
anotherRefName := "refs/heads/feature"
t.Run("clone and fetch remote repository, verify refs match, not bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
otherCommit, err := remoteRepo.Commit(tree, anotherRefName, "Commit to feature", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, refName, []string{anotherRefName}, false)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
localOtherCommit, err := localRepo.GetReference(anotherRefName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.Equal(t, otherCommit, localOtherCommit)
assert.True(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(strings.TrimSuffix(localRepo.gitDirPath, ".git"))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "foo", dirEntries[1].Name()) // [0] will be the entry for the .git directory
})
t.Run("clone and fetch remote repository without specifying initial branch, verify refs match, not bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
otherCommit, err := remoteRepo.Commit(tree, anotherRefName, "Commit to feature", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, "", []string{anotherRefName}, false)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
localOtherCommit, err := localRepo.GetReference(anotherRefName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.Equal(t, otherCommit, localOtherCommit)
assert.True(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(strings.TrimSuffix(localRepo.gitDirPath, ".git"))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "foo", dirEntries[1].Name()) // [0] will be the entry for the .git directory
})
t.Run("clone and fetch remote repository with only one ref, verify refs match, not bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, "", []string{}, false)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.True(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(strings.TrimSuffix(localRepo.gitDirPath, ".git"))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "foo", dirEntries[1].Name()) // [0] will be the entry for the .git directory
})
t.Run("clone and fetch remote repository, verify refs match, bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
otherCommit, err := remoteRepo.Commit(tree, anotherRefName, "Commit to feature", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, refName, []string{anotherRefName}, true)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
localOtherCommit, err := localRepo.GetReference(anotherRefName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.Equal(t, otherCommit, localOtherCommit)
assert.False(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(localRepo.gitDirPath)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "FETCH_HEAD", dirEntries[0].Name())
})
t.Run("clone and fetch remote repository without specifying initial branch, verify refs match, bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
otherCommit, err := remoteRepo.Commit(tree, anotherRefName, "Commit to feature", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, "", []string{anotherRefName}, true)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
localOtherCommit, err := localRepo.GetReference(anotherRefName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.Equal(t, otherCommit, localOtherCommit)
assert.False(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(localRepo.gitDirPath)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "FETCH_HEAD", dirEntries[0].Name())
})
t.Run("clone and fetch remote repository with only one ref, verify refs match, bare", func(t *testing.T) {
remoteTmpDir := t.TempDir()
localTmpDir := t.TempDir()
remoteRepo := CreateTestGitRepository(t, remoteTmpDir, false)
remoteTreeBuilder := NewTreeBuilder(remoteRepo)
emptyBlobHash, err := remoteRepo.WriteBlob(nil)
require.Nil(t, err)
entries := []TreeEntry{NewEntryBlob("foo", emptyBlobHash)}
tree, err := remoteTreeBuilder.WriteTreeFromEntries(entries)
if err != nil {
t.Fatal(err)
}
mainCommit, err := remoteRepo.Commit(tree, refName, "Commit to main", false)
if err != nil {
t.Fatal(err)
}
if err := remoteRepo.SetReference("HEAD", mainCommit); err != nil {
t.Fatal(err)
}
localRepo, err := CloneAndFetchRepository(remoteTmpDir, localTmpDir, "", []string{}, true)
if err != nil {
t.Fatal(err)
}
localMainCommit, err := localRepo.GetReference(refName)
assert.Nil(t, err)
assert.Equal(t, mainCommit, localMainCommit)
assert.False(t, strings.HasSuffix(localRepo.gitDirPath, ".git"))
dirEntries, err := os.ReadDir(localRepo.gitDirPath)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "FETCH_HEAD", dirEntries[0].Name())
})
}
func TestCreateRemote(t *testing.T) {
tmpDir := t.TempDir()
repo := CreateTestGitRepository(t, tmpDir, false)
err := repo.CreateRemote("origin", tmpDir)
assert.Nil(t, err)
err = repo.CreateRemote("origin", tmpDir)
assert.ErrorContains(t, err, "unable to add remote")
}