clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/tinyagent
tinyrelay / internal / daemon / backup_git_http_acceptance_test.go
backup_git_http_acceptance_test.go 4.1K
1package daemon23import (4 "bytes"5 "context"6 "encoding/json"7 "net/http"8 "net/http/httptest"9 "os"10 "os/exec"11 "path/filepath"12 "strings"13 "testing"14 "time"1516 "github.com/FelineStateMachine/tinyrelay/internal/replication"17)1819func TestMountedHTTPBackupRestoreIncludesGitInventory(t *testing.T) {20 ctx := context.Background()21 _, source := testTenant(t)22 app, target := testTenant(t)23 repoPath := filepath.Join(source.meta.Paths.Git, source.Policy().Owner, "portable.git")24 if err := os.MkdirAll(filepath.Dir(repoPath), 0700); err != nil {25 t.Fatal(err)26 }27 if output, err := exec.Command("git", "init", "--bare", "--initial-branch=main", repoPath).CombinedOutput(); err != nil {28 t.Fatalf("git init: %v: %s", err, output)29 }30 work := filepath.Join(t.TempDir(), "work")31 if err := os.MkdirAll(work, 0700); err != nil {32 t.Fatal(err)33 }34 gitRun(t, work, "init")35 gitRun(t, work, "config", "user.email", "acceptance@example.com")36 gitRun(t, work, "config", "user.name", "Acceptance")37 if err := os.WriteFile(filepath.Join(work, "README.txt"), []byte("portable git text\n"), 0600); err != nil {38 t.Fatal(err)39 }40 binary := []byte{0, 1, 2, 127, 128, 255}41 if err := os.WriteFile(filepath.Join(work, "payload.bin"), binary, 0600); err != nil {42 t.Fatal(err)43 }44 gitRun(t, work, "add", "README.txt", "payload.bin")45 gitRun(t, work, "commit", "-m", "portable inventory")46 gitRun(t, work, "branch", "-M", "main")47 gitRun(t, work, "tag", "v1")48 gitRun(t, work, "remote", "add", "origin", repoPath)49 gitRun(t, work, "push", "--all", "origin")50 gitRun(t, work, "push", "--tags", "origin")51 commit := strings.TrimSpace(string(backupGitOutput(t, work, "rev-parse", "HEAD")))52 binaryOID := strings.TrimSpace(string(backupGitOutput(t, work, "rev-parse", "HEAD:payload.bin")))53 archive, err := replication.CreateBackupWithProvider(ctx, source.store, source.ReplicationBackupProvider(), time.Now().Unix())54 if err != nil {55 t.Fatal(err)56 }57 body, err := json.Marshal(archive)58 if err != nil {59 t.Fatal(err)60 }61 req := httptest.NewRequest(http.MethodPost, "http://relay.test/r/main/backups/restore", bytes.NewReader(body))62 signRequest(t, req, string(body))63 res := httptest.NewRecorder()64 app.ServeHTTP(res, req)65 if res.Code != http.StatusOK {66 t.Fatalf("mounted Git restore %d: %s", res.Code, res.Body.String())67 }68 restoredRepo := filepath.Join(target.meta.Paths.Git, source.Policy().Owner, "portable.git")69 if got := strings.TrimSpace(string(backupGitOutput(t, restoredRepo, "rev-parse", "refs/heads/main"))); got != commit {70 t.Fatalf("restored main ref = %s, want %s", got, commit)71 }72 if got := strings.TrimSpace(string(backupGitOutput(t, restoredRepo, "rev-parse", "refs/tags/v1"))); got != commit {73 t.Fatalf("restored tag ref = %s, want %s", got, commit)74 }75 if got := string(backupGitOutput(t, restoredRepo, "show", "HEAD:README.txt")); got != "portable git text\n" {76 t.Fatalf("restored text = %q", got)77 }78 if got := strings.TrimSpace(string(backupGitOutput(t, restoredRepo, "rev-parse", "HEAD:payload.bin"))); got != binaryOID {79 t.Fatalf("restored binary oid = %s, want %s", got, binaryOID)80 }81 if output, err := exec.Command("git", "--git-dir", restoredRepo, "cat-file", "blob", "HEAD:payload.bin").Output(); err != nil || string(output) != string(binary) {82 t.Fatalf("restored binary content mismatch: %v", err)83 }84 if output, err := exec.Command("git", "--git-dir", restoredRepo, "fsck", "--full", "--no-progress").CombinedOutput(); err != nil {85 t.Fatalf("restored Git fsck: %v: %s", err, output)86 }87}8889func gitRun(t *testing.T, dir string, args ...string) {90 t.Helper()91 command := exec.Command("git", append([]string{"-C", dir}, args...)...)92 if output, err := command.CombinedOutput(); err != nil {93 t.Fatalf("git %v: %v: %s", args, err, output)94 }95}9697func backupGitOutput(t *testing.T, dir string, args ...string) []byte {98 t.Helper()99 command := exec.Command("git", append([]string{"--git-dir", dir}, args...)...)100 if dir != "" && !strings.HasSuffix(dir, ".git") {101 command = exec.Command("git", append([]string{"-C", dir}, args...)...)102 }103 output, err := command.Output()104 if err != nil {105 t.Fatalf("git %v: %v", args, err)106 }107 return output108}