1
0
Fork 0
mirror of https://github.com/imjasonh/infinite-git synced 2026-07-08 09:05:06 +00:00
infinite-git/main_test.go
Jason Hall db0c5c91a5
Update to use single hello.txt file instead of creating new files
Instead of creating a new file for each pull (pull_1.txt, pull_2.txt, etc.),
now updates a single hello.txt file with the pull number and timestamp
with nanosecond precision.

Changes:
- Modified commit generator to update hello.txt instead of creating new files
- Added hello.txt to initial repository commit
- Updated tests to verify hello.txt content instead of checking for new files
- Fixed test expectations to account for counter increment during clone

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-23 22:56:40 -04:00

284 lines
6.8 KiB
Go

package main
import (
"fmt"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/imjasonh/infinite-git/internal/repo"
"github.com/imjasonh/infinite-git/internal/server"
)
func TestCloneAndPull(t *testing.T) {
// Create temporary directories
serverRepoDir := t.TempDir()
clientRepoDir := t.TempDir()
// Initialize server repository
serverRepo, err := repo.New(serverRepoDir)
if err != nil {
t.Fatalf("failed to create server repo: %v", err)
}
srv := server.New(serverRepo)
// Start test server
ts := httptest.NewServer(srv.Handler())
defer ts.Close()
// Clone the repository
gitRepo, err := git.PlainClone(clientRepoDir, false, &git.CloneOptions{
URL: ts.URL,
})
if err != nil {
t.Fatalf("failed to clone: %v", err)
}
// Get initial commit
ref, err := gitRepo.Head()
if err != nil {
t.Fatalf("failed to get HEAD: %v", err)
}
initialCommit := ref.Hash()
t.Logf("Initial commit: %s", initialCommit)
// Count initial commits
initialCount := countCommits(t, gitRepo)
t.Logf("Initial commit count: %d", initialCount)
// Perform multiple pulls
commits := []plumbing.Hash{initialCommit}
for i := 0; i < 3; i++ {
// Pull from origin
w, err := gitRepo.Worktree()
if err != nil {
t.Fatalf("failed to get worktree: %v", err)
}
err = w.Pull(&git.PullOptions{
RemoteName: "origin",
})
if err != nil && err != git.NoErrAlreadyUpToDate {
t.Fatalf("pull %d failed: %v", i+1, err)
}
// Get new HEAD
ref, err := gitRepo.Head()
if err != nil {
t.Fatalf("failed to get HEAD after pull %d: %v", i+1, err)
}
newCommit := ref.Hash()
// Verify we got a new commit
if newCommit == commits[len(commits)-1] {
t.Errorf("pull %d did not generate a new commit", i+1)
}
commits = append(commits, newCommit)
t.Logf("Pull %d got commit: %s", i+1, newCommit)
// Verify commit count increased
newCount := countCommits(t, gitRepo)
if newCount != initialCount+i+1 {
t.Errorf("expected %d commits after pull %d, got %d", initialCount+i+1, i+1, newCount)
}
// Verify hello.txt exists and has been updated
helloFile := filepath.Join(clientRepoDir, "hello.txt")
content, err := os.ReadFile(helloFile)
if err != nil {
t.Errorf("failed to read hello.txt: %v", err)
} else {
// Clone increments counter to 1, so first pull is #2, second is #3, etc.
expectedContent := fmt.Sprintf("Pull #%d\n", i+2)
if !strings.Contains(string(content), expectedContent) {
t.Errorf("hello.txt does not contain expected content %q, got: %s", expectedContent, content)
}
}
}
// Verify all commits are unique
uniqueCommits := make(map[plumbing.Hash]bool)
for _, commit := range commits {
if uniqueCommits[commit] {
t.Errorf("found duplicate commit: %s", commit)
}
uniqueCommits[commit] = true
}
}
func TestConcurrentPulls(t *testing.T) {
// Create temporary directories
serverRepoDir := t.TempDir()
// Initialize server repository
serverRepo, err := repo.New(serverRepoDir)
if err != nil {
t.Fatalf("failed to create server repo: %v", err)
}
srv := server.New(serverRepo)
// Start test server
ts := httptest.NewServer(srv.Handler())
defer ts.Close()
// Clone initial repository
baseClientDir := t.TempDir()
baseRepo, err := git.PlainClone(baseClientDir, false, &git.CloneOptions{
URL: ts.URL,
})
if err != nil {
t.Fatalf("failed to clone: %v", err)
}
initialCount := countCommits(t, baseRepo)
t.Logf("Initial commit count: %d", initialCount)
// Perform concurrent pulls
const numPulls = 5
var wg sync.WaitGroup
commits := make([]plumbing.Hash, numPulls)
errors := make([]error, numPulls)
for i := 0; i < numPulls; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
// Clone a fresh repo for this goroutine
clientDir := filepath.Join(t.TempDir(), fmt.Sprintf("client_%d", idx))
gitRepo, err := git.PlainClone(clientDir, false, &git.CloneOptions{
URL: ts.URL,
})
if err != nil {
errors[idx] = fmt.Errorf("clone failed: %w", err)
return
}
// Get the commit we received
ref, err := gitRepo.Head()
if err != nil {
errors[idx] = fmt.Errorf("get HEAD failed: %w", err)
return
}
commits[idx] = ref.Hash()
t.Logf("Concurrent pull %d got commit: %s", idx, commits[idx])
}(i)
}
wg.Wait()
// Check for errors
for i, err := range errors {
if err != nil {
t.Errorf("goroutine %d failed: %v", i, err)
}
}
// Verify all commits are unique
uniqueCommits := make(map[plumbing.Hash]bool)
for i, commit := range commits {
if uniqueCommits[commit] {
t.Errorf("concurrent pull %d got duplicate commit: %s", i, commit)
}
uniqueCommits[commit] = true
}
// All pulls should have generated unique commits
if len(uniqueCommits) != numPulls {
t.Errorf("expected %d unique commits, got %d", numPulls, len(uniqueCommits))
}
}
func TestPushRejection(t *testing.T) {
// Create temporary directories
serverRepoDir := t.TempDir()
clientRepoDir := t.TempDir()
// Initialize server repository
serverRepo, err := repo.New(serverRepoDir)
if err != nil {
t.Fatalf("failed to create server repo: %v", err)
}
srv := server.New(serverRepo)
// Start test server
ts := httptest.NewServer(srv.Handler())
defer ts.Close()
// Clone the repository
gitRepo, err := git.PlainClone(clientRepoDir, false, &git.CloneOptions{
URL: ts.URL,
})
if err != nil {
t.Fatalf("failed to clone: %v", err)
}
// Create a new file and commit
testFile := filepath.Join(clientRepoDir, "test-push.txt")
if err := os.WriteFile(testFile, []byte("test push content"), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
w, err := gitRepo.Worktree()
if err != nil {
t.Fatalf("failed to get worktree: %v", err)
}
if _, err := w.Add("test-push.txt"); err != nil {
t.Fatalf("failed to add file: %v", err)
}
if _, err := w.Commit("Test push commit", &git.CommitOptions{
Author: &object.Signature{
Name: "Test User",
Email: "test@example.com",
},
}); err != nil {
t.Fatalf("failed to commit: %v", err)
}
// Try to push - should fail
err = gitRepo.Push(&git.PushOptions{
RemoteName: "origin",
Auth: &http.BasicAuth{
Username: "test",
Password: "test",
},
})
if err == nil {
t.Fatal("push should have been rejected but succeeded")
}
// Verify the error indicates push was forbidden
t.Logf("Push rejected with error: %v", err)
}
// Helper function to count commits
func countCommits(t *testing.T, repo *git.Repository) int {
iter, err := repo.Log(&git.LogOptions{})
if err != nil {
t.Fatalf("failed to get log: %v", err)
}
defer iter.Close()
count := 0
err = iter.ForEach(func(c *object.Commit) error {
count++
return nil
})
if err != nil {
t.Fatalf("failed to iterate commits: %v", err)
}
return count
}