Skip to content

Commit

Permalink
feat: improve hook UX and execution model (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
garethgeorge authored Jul 11, 2024
1 parent fe0e2b9 commit 4d0d13e
Show file tree
Hide file tree
Showing 46 changed files with 1,136 additions and 987 deletions.
72 changes: 41 additions & 31 deletions gen/go/v1/operations.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 93 additions & 0 deletions internal/api/backresthandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/garethgeorge/backrest/internal/config"
"github.com/garethgeorge/backrest/internal/oplog"
"github.com/garethgeorge/backrest/internal/orchestrator"
"github.com/garethgeorge/backrest/internal/orchestrator/tasks"
"github.com/garethgeorge/backrest/internal/resticinstaller"
"github.com/garethgeorge/backrest/internal/rotatinglog"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -334,6 +335,98 @@ func TestHookExecution(t *testing.T) {
}
}

func TestHookCancellation(t *testing.T) {
t.Parallel()

if runtime.GOOS == "windows" {
t.Skip("skipping test on windows")
}

sut := createSystemUnderTest(t, &config.MemoryStore{
Config: &v1.Config{
Modno: 1234,
Instance: "test",
Repos: []*v1.Repo{
{
Id: "local",
Uri: t.TempDir(),
Password: "test",
},
},
Plans: []*v1.Plan{
{
Id: "test",
Repo: "local",
Paths: []string{
t.TempDir(),
},
Schedule: &v1.Schedule{
Schedule: &v1.Schedule_Disabled{Disabled: true},
},
Hooks: []*v1.Hook{
{
Conditions: []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_START,
},
Action: &v1.Hook_ActionCommand{
ActionCommand: &v1.Hook_Command{
Command: "exit 123",
},
},
OnError: v1.Hook_ON_ERROR_CANCEL,
},
},
},
},
},
})

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
sut.orch.Run(ctx)
}()

_, err := sut.handler.Backup(context.Background(), connect.NewRequest(&types.StringValue{Value: "test"}))
if !errors.Is(err, tasks.ErrTaskCancelled) {
t.Fatalf("Backup() error = %v, want errors.Is(err, tasks.ErrTaskCancelled)", err)
}

// Wait for a hook operation to appear in the oplog
if err := retry(t, 10, 2*time.Second, func() error {
hookOps := slices.DeleteFunc(getOperations(t, sut.oplog), func(op *v1.Operation) bool {
_, ok := op.GetOp().(*v1.Operation_OperationRunHook)
return !ok
})
if len(hookOps) != 1 {
return fmt.Errorf("expected 1 hook operations, got %d", len(hookOps))
}
if hookOps[0].Status != v1.OperationStatus_STATUS_ERROR {
return fmt.Errorf("expected hook operation error status, got %v", hookOps[0].Status)
}
return nil
}); err != nil {
t.Fatalf("Couldn't find hooks in oplog: %v", err)
}

// assert that the backup operation is in the log and is cancelled
if err := retry(t, 10, 2*time.Second, func() error {
backupOps := slices.DeleteFunc(getOperations(t, sut.oplog), func(op *v1.Operation) bool {
_, ok := op.GetOp().(*v1.Operation_OperationBackup)
return !ok
})
if len(backupOps) != 1 {
return fmt.Errorf("expected 1 backup operation, got %d", len(backupOps))
}
if backupOps[0].Status != v1.OperationStatus_STATUS_USER_CANCELLED {
return fmt.Errorf("expected backup operation cancelled status, got %v", backupOps[0].Status)
}
return nil
}); err != nil {
t.Fatalf("Couldn't find hooks in oplog: %v", err)
}
}

func TestCancelBackup(t *testing.T) {
t.Parallel()

Expand Down
21 changes: 21 additions & 0 deletions internal/config/configutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package config

import v1 "github.com/garethgeorge/backrest/gen/go/v1"

func FindPlan(cfg *v1.Config, planID string) *v1.Plan {
for _, plan := range cfg.Plans {
if plan.Id == planID {
return plan
}
}
return nil
}

func FindRepo(cfg *v1.Config, repoID string) *v1.Repo {
for _, repo := range cfg.Repos {
if repo.Id == repoID {
return repo
}
}
return nil
}
Loading

0 comments on commit 4d0d13e

Please sign in to comment.