diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 08accc8..bd9ee5d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,8 +42,6 @@ jobs: - name: Test run: PATH=$(pwd):$PATH gotestsum ./... -- --race - test-webui: runs-on - test-win: runs-on: windows-latest steps: diff --git a/.gitignore b/.gitignore index 3d7233f..68ff69c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -test* backrest-* dist __debug_bin @@ -6,4 +5,4 @@ cmd/backrest/backrest *.exe .DS_Store .idea/ -.pnpm-store/ \ No newline at end of file +.pnpm-store/ diff --git a/go.mod b/go.mod index 3ffeb7b..920a2ef 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( require ( github.com/akavel/rsrc v0.10.2 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bufbuild/connect-go v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dchest/jsmin v1.0.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect diff --git a/go.sum b/go.sum index e8fb01f..2869929 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bool64/dev v0.2.39 h1:kP8DnMGlWXhGYJEZE/J0l/gVBdbuhoPGL+MJG4QbofE= github.com/bool64/dev v0.2.39/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg= +github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec= diff --git a/test/e2e/first_run_test.go b/test/e2e/first_run_test.go new file mode 100644 index 0000000..e74f73b --- /dev/null +++ b/test/e2e/first_run_test.go @@ -0,0 +1,136 @@ +package e2e + +import ( + "context" + "fmt" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/garethgeorge/backrest/gen/go/types" + v1 "github.com/garethgeorge/backrest/gen/go/v1" + "github.com/garethgeorge/backrest/gen/go/v1/v1connect" + "github.com/garethgeorge/backrest/internal/testutil" + "google.golang.org/protobuf/types/known/emptypb" +) + +func TestFirstRun(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "backrest-e2e-test") + if err != nil { + t.Fatalf("failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + binPath := filepath.Join(tmpDir, "backrest") + if runtime.GOOS == "windows" { + binPath += ".exe" + } + + // Build backrest binary + buildCmd := exec.Command("go", "build", "-o", binPath, "../../cmd/backrest") + buildCmd.Stderr = os.Stderr + buildCmd.Stdout = os.Stdout + if err := buildCmd.Run(); err != nil { + t.Fatalf("failed to build backrest binary: %v", err) + } + + addr := testutil.AllocOpenBindAddr(t) + + // Run backrest + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, binPath, + "-data-dir", tmpDir, "-config-file", + filepath.Join(tmpDir, "config.json"), + "-bind-address", addr) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + if err := cmd.Start(); err != nil { + t.Fatalf("failed to start backrest: %v", err) + } + + testutil.TryNonfatal(t, ctx, func() error { + resp, err := http.Get(fmt.Sprintf("http://%s", addr)) + if err != nil { + return err + } + resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode) + } + return nil + }) + + t.Run("set instance ID", func(t *testing.T) { + client := v1connect.NewBackrestClient( + http.DefaultClient, + fmt.Sprintf("http://%s", addr), + ) + + req := connect.NewRequest(&v1.Config{ + Instance: "TestInstance", + }) + resp, err := client.SetConfig(context.Background(), req) + if err != nil { + t.Fatalf("SetConfig failed: %v", err) + } + + if resp.Msg.Instance != "TestInstance" { + t.Errorf("expected instance ID to be 'TestInstance', got %q", resp.Msg.Instance) + } + }) + + t.Run("get config", func(t *testing.T) { + client := v1connect.NewBackrestClient( + http.DefaultClient, + fmt.Sprintf("http://%s", addr), + ) + + req := connect.NewRequest(&emptypb.Empty{}) + resp, err := client.GetConfig(context.Background(), req) + if err != nil { + t.Fatalf("GetConfig failed: %v", err) + } + + if resp.Msg.Instance != "TestInstance" { + t.Errorf("expected instance ID to be 'TestInstance', got %q", resp.Msg.Instance) + } + }) + + t.Run("add repo", func(t *testing.T) { + client := v1connect.NewBackrestClient( + http.DefaultClient, + fmt.Sprintf("http://%s", addr), + ) + + req := connect.NewRequest(&v1.Repo{ + Id: "test-repo", + Uri: filepath.Join(tmpDir, "test-repo"), + }) + _, err := client.AddRepo(context.Background(), req) + if err != nil { + t.Fatalf("AddRepo failed: %v", err) + } + }) + + t.Run("trigger backup", func(t *testing.T) { + client := v1connect.NewBackrestClient( + http.DefaultClient, + fmt.Sprintf("http://%s", addr), + ) + + req := connect.NewRequest(&types.StringValue{ + Value: "test-repo", + }) + _, err := client.Backup(context.Background(), req) + if err != nil { + t.Fatalf("Backup failed: %v", err) + } + }) +}