package commands import ( "fmt" "os" "testing" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5" gitcfg "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/cache" "github.com/go-git/go-git/v5/storage/filesystem" "github.com/go-git/go-git/v5/storage/memory" "gitlab.com/revalus/grm/config" ) type TestDir struct { rootFS billy.Filesystem baseRepository struct { fileSystem billy.Filesystem repo *git.Repository } } func getTestDirForTests() TestDir { checkError := func(err error) { if err != nil { fmt.Printf("During preparing repositories, an error occurred: %v\n", err) os.Exit(4) } } baseTMPPath := fmt.Sprintf("%v/grmTest", os.TempDir()) if _, ok := os.Stat(baseTMPPath); ok != nil { err := os.Mkdir(baseTMPPath, 0777) checkError(err) } tmpDir, err := os.MkdirTemp(baseTMPPath, "*") checkError(err) baseFileSystem := osfs.New(tmpDir) initRepositoryFileSystem, err := baseFileSystem.Chroot("worktree") checkError(err) directoryForGitMetadata, err := initRepositoryFileSystem.Chroot(".git") checkError(err) repository, err := git.Init(filesystem.NewStorage(directoryForGitMetadata, cache.NewObjectLRUDefault()), initRepositoryFileSystem) checkError(err) fileForFirstCommit, err := initRepositoryFileSystem.Create("TestFile.txt") checkError(err) _, err = fileForFirstCommit.Write([]byte("foo-conent")) checkError(err) repositoryWorkTree, err := repository.Worktree() checkError(err) repositoryWorkTree.Add(fileForFirstCommit.Name()) _, err = repositoryWorkTree.Commit("First commit", &git.CommitOptions{}) checkError(err) return TestDir{ baseRepository: struct { fileSystem billy.Filesystem repo *git.Repository }{ fileSystem: initRepositoryFileSystem, repo: repository, }, rootFS: baseFileSystem, } } func unexpectedError(err error, t *testing.T) { if err != nil { t.Errorf("Unexpected error %v", err) } } func makeCommit(wk *git.Worktree, commitMessage string, fileName string) error { wk.Commit(commitMessage, &git.CommitOptions{}) return nil } func TestIfBranchesAreEqual(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() fakeLocalRepo, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) currentReference, err := fakeLocalRepo.Head() unexpectedError(err, t) remote, err := fakeLocalRepo.Remote("origin") unexpectedError(err, t) remoteRevision, err := fakeLocalRepo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remote.Config().Name, currentReference.Name().Short()))) unexpectedError(err, t) currentBranchCommit, err := fakeLocalRepo.CommitObject(currentReference.Hash()) unexpectedError(err, t) remoteBranchCommit, err := fakeLocalRepo.CommitObject(*remoteRevision) unexpectedError(err, t) result := findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit) if result != 0 { t.Errorf("Expected to get 0 changes, instead of this got %v", result) } } func TestIfCurrentBranchIsAbove(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() tmpFileSystemForLocalRepository := memfs.New() fakeLocalRepo, err := git.Clone(memory.NewStorage(), tmpFileSystemForLocalRepository, &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) localWorktree, err := fakeLocalRepo.Worktree() unexpectedError(err, t) err = makeCommit(localWorktree, "commit 1", "Commit1") unexpectedError(err, t) localReference, err := fakeLocalRepo.Head() unexpectedError(err, t) remoteConnection, err := fakeLocalRepo.Remote("origin") unexpectedError(err, t) remoteRevision, err := fakeLocalRepo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remoteConnection.Config().Name, localReference.Name().Short()))) unexpectedError(err, t) currentBranchCommit, err := fakeLocalRepo.CommitObject(localReference.Hash()) unexpectedError(err, t) remoteBranchCommit, err := fakeLocalRepo.CommitObject(*remoteRevision) unexpectedError(err, t) result := findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit) if result != 1 { t.Errorf("Expected to get 1 changes, instead of this got %v", result) } for i := 1; i < 15; i++ { err = makeCommit(localWorktree, fmt.Sprintf("Commit +%v", i), fmt.Sprintf("Commit%v", i)) unexpectedError(err, t) } localReference, err = fakeLocalRepo.Head() unexpectedError(err, t) currentBranchCommit, err = fakeLocalRepo.CommitObject(localReference.Hash()) unexpectedError(err, t) result = findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit) if result != 15 { t.Errorf("Expected to get 5 changes, instead of this got %v", result) } } func TestCommandRepositoryDoesNotExists(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot("NotMatterValue") unexpectedError(err, t) directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git") unexpectedError(err, t) storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault()) _, err = git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) sc := StatusChecker{ workspace: tmpDirWithInitialRepository.rootFS.Root(), } repoCfg := config.RepositoryConfig{ Name: "test", Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), Dest: tmpDirWithInitialRepository.rootFS.Root(), } ch := make(chan CommandStatus) go sc.Command(repoCfg, ch) repoStatus := <-ch expectedMessage := "repository does not exist" if !repoStatus.Error { t.Errorf("Expected error") } if repoStatus.Changed { t.Errorf("Unexpected change value") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } } func TestCommandRepositoryNoRemoteBranch(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() dirNameForLocalRepository := "testRepo" fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository) unexpectedError(err, t) directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git") unexpectedError(err, t) storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault()) fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) err = fakeLocalRepository.DeleteRemote("origin") unexpectedError(err, t) sc := StatusChecker{ workspace: tmpDirWithInitialRepository.rootFS.Root(), } repoCfg := config.RepositoryConfig{ Name: "test", Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), Dest: dirNameForLocalRepository, } ch := make(chan CommandStatus) go sc.Command(repoCfg, ch) repoStatus := <-ch expectedMessage := "cannot find remote branches" if !repoStatus.Error { t.Errorf("Expected error") } if repoStatus.Changed { t.Errorf("Unexpected change value") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } } func TestCommandAllCorrect(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() dirNameForLocalRepository := "testRepo" fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository) unexpectedError(err, t) directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git") unexpectedError(err, t) storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault()) fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) sc := StatusChecker{ workspace: tmpDirWithInitialRepository.rootFS.Root(), } repoCfg := config.RepositoryConfig{ Name: "test", Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), Dest: dirNameForLocalRepository, } ch := make(chan CommandStatus) go sc.Command(repoCfg, ch) repoStatus := <-ch expectedMessage := "branch master - ( | origin | \u21910 \u21930 )" if repoStatus.Error { t.Errorf("Unexpected error") t.Errorf("Message %v", repoStatus.Message) } if repoStatus.Changed { t.Errorf("Expeected that changed will be true") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } fakeLocalWorkTree, err := fakeLocalRepository.Worktree() unexpectedError(err, t) err = makeCommit(fakeLocalWorkTree, "commit 1", "Commit1") unexpectedError(err, t) go sc.Command(repoCfg, ch) repoStatus = <-ch expectedMessage = "branch master - ( | origin | \u21911 \u21930 )" if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } if repoStatus.Error { t.Errorf("Unexpected error") t.Errorf("Message %v", repoStatus.Message) } if !repoStatus.Changed { t.Errorf("Expeected that changed will be true") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } } func TestCommandMultiRemote(t *testing.T) { tmpDirWithInitialRepository := getTestDirForTests() dirNameForLocalRepository := "testRepo" fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository) unexpectedError(err, t) directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git") unexpectedError(err, t) storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault()) fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{ URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), }) unexpectedError(err, t) fakeLocalRepository.CreateRemote(&gitcfg.RemoteConfig{ Name: "subremote", URLs: []string{tmpDirWithInitialRepository.baseRepository.fileSystem.Root()}, }) fakeLocalRepository.Fetch(&git.FetchOptions{ RemoteName: "subremote", }) sc := StatusChecker{ workspace: tmpDirWithInitialRepository.rootFS.Root(), } repoCfg := config.RepositoryConfig{ Name: "test", Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(), Dest: dirNameForLocalRepository, } ch := make(chan CommandStatus) go sc.Command(repoCfg, ch) repoStatus := <-ch expectedMessage := "branch master - ( | origin | \u21910 \u21930 ) - ( | subremote | \u21910 \u21930 )" if repoStatus.Error { t.Errorf("Unexpected error") t.Errorf("Message %v", repoStatus.Message) } if repoStatus.Changed { t.Errorf("Expeected that changed will be true") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } fakeLocalWorkTree, err := fakeLocalRepository.Worktree() unexpectedError(err, t) err = makeCommit(fakeLocalWorkTree, "commit 1", "Commit1") unexpectedError(err, t) go sc.Command(repoCfg, ch) repoStatus = <-ch expectedMessage = "branch master - ( | origin | \u21911 \u21930 ) - ( | subremote | \u21911 \u21930 )" if repoStatus.Error { t.Errorf("Unexpected error") t.Errorf("Message %v", repoStatus.Message) } if !repoStatus.Changed { t.Errorf("Expeected that changed will be true") } if repoStatus.Message != expectedMessage { t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message) } }