2020-06-23 19:02:54 +03:00
|
|
|
package repository
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2020-06-27 23:00:15 +03:00
|
|
|
"math/rand"
|
2020-06-23 19:02:54 +03:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2020-09-26 15:06:17 +03:00
|
|
|
|
|
|
|
"github.com/MichaelMure/git-bug/util/lamport"
|
2020-06-23 19:02:54 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func CleanupTestRepos(repos ...Repo) {
|
|
|
|
var firstErr error
|
|
|
|
for _, repo := range repos {
|
|
|
|
path := repo.GetPath()
|
|
|
|
if strings.HasSuffix(path, "/.git") {
|
|
|
|
// for a normal repository (not --bare), we want to remove everything
|
|
|
|
// including the parent directory where files are checked out
|
|
|
|
path = strings.TrimSuffix(path, "/.git")
|
|
|
|
|
|
|
|
// Testing non-bare repo should also check path is
|
|
|
|
// only .git (i.e. ./.git), but doing so, we should
|
|
|
|
// try to remove the current directory and hav some
|
|
|
|
// trouble. In the present case, this case should not
|
|
|
|
// occur.
|
|
|
|
// TODO consider warning or error when path == ".git"
|
|
|
|
}
|
|
|
|
// fmt.Println("Cleaning repo:", path)
|
|
|
|
err := os.RemoveAll(path)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
if firstErr == nil {
|
|
|
|
firstErr = err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if firstErr != nil {
|
|
|
|
log.Fatal(firstErr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type RepoCreator func(bare bool) TestedRepo
|
|
|
|
type RepoCleaner func(repos ...Repo)
|
|
|
|
|
|
|
|
// Test suite for a Repo implementation
|
|
|
|
func RepoTest(t *testing.T, creator RepoCreator, cleaner RepoCleaner) {
|
2020-09-26 15:06:17 +03:00
|
|
|
for bare, name := range map[bool]string{
|
|
|
|
false: "Plain",
|
|
|
|
true: "Bare",
|
|
|
|
} {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2020-09-27 01:54:14 +03:00
|
|
|
repo := creator(bare)
|
|
|
|
defer cleaner(repo)
|
2020-09-26 15:06:17 +03:00
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
t.Run("Data", func(t *testing.T) {
|
|
|
|
RepoDataTest(t, repo)
|
|
|
|
})
|
2020-09-26 15:06:17 +03:00
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
t.Run("Config", func(t *testing.T) {
|
|
|
|
RepoConfigTest(t, repo)
|
2020-09-26 15:06:17 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Clocks", func(t *testing.T) {
|
2020-09-27 01:54:14 +03:00
|
|
|
RepoClockTest(t, repo)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-06-27 23:00:15 +03:00
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
// helper to test a RepoConfig
|
|
|
|
func RepoConfigTest(t *testing.T, repo RepoConfig) {
|
|
|
|
testConfig(t, repo.LocalConfig())
|
|
|
|
}
|
2020-06-27 23:00:15 +03:00
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
// helper to test a RepoData
|
|
|
|
func RepoDataTest(t *testing.T, repo RepoData) {
|
|
|
|
// Blob
|
|
|
|
|
|
|
|
data := randomData()
|
|
|
|
|
|
|
|
blobHash1, err := repo.StoreData(data)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, blobHash1.IsValid())
|
|
|
|
|
|
|
|
blob1Read, err := repo.ReadData(blobHash1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, data, blob1Read)
|
|
|
|
|
|
|
|
// Tree
|
|
|
|
|
|
|
|
blobHash2, err := repo.StoreData(randomData())
|
|
|
|
require.NoError(t, err)
|
|
|
|
blobHash3, err := repo.StoreData(randomData())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tree1 := []TreeEntry{
|
|
|
|
{
|
|
|
|
ObjectType: Blob,
|
|
|
|
Hash: blobHash1,
|
|
|
|
Name: "blob1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectType: Blob,
|
|
|
|
Hash: blobHash2,
|
|
|
|
Name: "blob2",
|
|
|
|
},
|
|
|
|
}
|
2020-06-27 23:00:15 +03:00
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
treeHash1, err := repo.StoreTree(tree1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, treeHash1.IsValid())
|
|
|
|
|
|
|
|
tree1Read, err := repo.ReadTree(treeHash1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.ElementsMatch(t, tree1, tree1Read)
|
|
|
|
|
|
|
|
tree2 := []TreeEntry{
|
|
|
|
{
|
|
|
|
ObjectType: Tree,
|
|
|
|
Hash: treeHash1,
|
|
|
|
Name: "tree1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectType: Blob,
|
|
|
|
Hash: blobHash3,
|
|
|
|
Name: "blob3",
|
|
|
|
},
|
2020-09-26 15:06:17 +03:00
|
|
|
}
|
2020-09-27 01:54:14 +03:00
|
|
|
|
|
|
|
treeHash2, err := repo.StoreTree(tree2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, treeHash2.IsValid())
|
|
|
|
|
|
|
|
tree2Read, err := repo.ReadTree(treeHash2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.ElementsMatch(t, tree2, tree2Read)
|
|
|
|
|
|
|
|
// Commit
|
|
|
|
|
|
|
|
commit1, err := repo.StoreCommit(treeHash1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, commit1.IsValid())
|
|
|
|
|
|
|
|
treeHash1Read, err := repo.GetTreeHash(commit1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, treeHash1, treeHash1Read)
|
|
|
|
|
|
|
|
commit2, err := repo.StoreCommitWithParent(treeHash2, commit1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, commit2.IsValid())
|
|
|
|
|
|
|
|
treeHash2Read, err := repo.GetTreeHash(commit2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, treeHash2, treeHash2Read)
|
|
|
|
|
2020-09-27 23:56:53 +03:00
|
|
|
// ReadTree should accept tree and commit hashes
|
|
|
|
tree1read, err := repo.ReadTree(commit1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tree1read, tree1)
|
|
|
|
|
2020-09-27 01:54:14 +03:00
|
|
|
// Ref
|
|
|
|
|
|
|
|
exist1, err := repo.RefExist("refs/bugs/ref1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, exist1)
|
|
|
|
|
|
|
|
err = repo.UpdateRef("refs/bugs/ref1", commit2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
exist1, err = repo.RefExist("refs/bugs/ref1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, exist1)
|
|
|
|
|
|
|
|
ls, err := repo.ListRefs("refs/bugs")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.ElementsMatch(t, []string{"refs/bugs/ref1"}, ls)
|
|
|
|
|
|
|
|
err = repo.CopyRef("refs/bugs/ref1", "refs/bugs/ref2")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ls, err = repo.ListRefs("refs/bugs")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.ElementsMatch(t, []string{"refs/bugs/ref1", "refs/bugs/ref2"}, ls)
|
|
|
|
|
|
|
|
commits, err := repo.ListCommits("refs/bugs/ref2")
|
|
|
|
require.NoError(t, err)
|
2020-09-29 21:16:15 +03:00
|
|
|
require.Equal(t, []Hash{commit1, commit2}, commits)
|
2020-09-27 01:54:14 +03:00
|
|
|
|
|
|
|
// Graph
|
|
|
|
|
|
|
|
commit3, err := repo.StoreCommitWithParent(treeHash1, commit1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ancestorHash, err := repo.FindCommonAncestor(commit2, commit3)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, commit1, ancestorHash)
|
|
|
|
|
|
|
|
err = repo.RemoveRef("refs/bugs/ref1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper to test a RepoClock
|
|
|
|
func RepoClockTest(t *testing.T, repo RepoClock) {
|
|
|
|
clock, err := repo.GetOrCreateClock("foo")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, lamport.Time(1), clock.Time())
|
|
|
|
|
|
|
|
time, err := clock.Increment()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, lamport.Time(1), time)
|
|
|
|
require.Equal(t, lamport.Time(2), clock.Time())
|
|
|
|
|
|
|
|
clock2, err := repo.GetOrCreateClock("foo")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, lamport.Time(2), clock2.Time())
|
|
|
|
|
|
|
|
clock3, err := repo.GetOrCreateClock("bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, lamport.Time(1), clock3.Time())
|
2020-06-23 19:02:54 +03:00
|
|
|
}
|
2020-06-27 23:00:15 +03:00
|
|
|
|
|
|
|
func randomData() []byte {
|
|
|
|
var letterRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
b := make([]byte, 32)
|
|
|
|
for i := range b {
|
|
|
|
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|