Files
orbit/weave/recovery/service_test.go

78 lines
3.4 KiB
Go

package recovery
import (
"context"
"encoding/json"
"strings"
"testing"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
)
type captureStore struct{ calls int }
func (s *captureStore) ReviewTask(context.Context, auth.Token, core.ID, string, ReviewTaskInput) (Result, error) {
s.calls++
return Result{}, nil
}
func (s *captureStore) ResolveStep(context.Context, auth.Token, core.ID, string, ResolveStepInput) (Result, error) {
s.calls++
return Result{}, nil
}
func (s *captureStore) Continue(context.Context, auth.Token, core.ID, string, ContinueInput) (Result, error) {
s.calls++
return Result{}, nil
}
func (s *captureStore) RetryStep(context.Context, auth.Token, core.ID, string, RetryStepInput) (Result, error) {
s.calls++
return Result{}, nil
}
func TestRecoveryValidation(t *testing.T) {
id := core.ID(strings.Repeat("a", 32))
d := Decision{ExpectedRevision: 2, Reason: "核实外部结果", EvidenceRef: "evidence://case/1"}
step := StepDecision{Decision: d, StepKey: "stage-1.v2", ActivationID: id, ExpectedStepRevision: 3}
store := &captureStore{}
s := New(store)
ctx := context.Background()
token := auth.Token{}
if _, err := s.ReviewTask(ctx, token, id, "operation", ReviewTaskInput{Decision: d, TaskID: id, ExpectedTaskRevision: 4, ExecutionSettled: true, Outcome: "SUCCEEDED", Result: json.RawMessage(`{"n":9007199254740993}`)}); err != nil {
t.Fatal(err)
}
if _, err := s.ResolveStep(ctx, token, id, "operation", ResolveStepInput{StepDecision: step, ExecutionSettled: true, Outcome: "SUCCEEDED", Result: json.RawMessage(`null`)}); err != nil {
t.Fatal(err)
}
if _, err := s.Continue(ctx, token, id, "operation", ContinueInput{Decision: d, ReviewResolved: true}); err != nil {
t.Fatal(err)
}
if _, err := s.RetryStep(ctx, token, id, "operation", RetryStepInput{StepDecision: step, SafeToRetry: true}); err != nil {
t.Fatal(err)
}
for _, change := range []func(*Decision){func(v *Decision) { v.ExpectedRevision = 0 }, func(v *Decision) { v.Reason = " " }, func(v *Decision) { v.Reason = string([]byte{255}) }, func(v *Decision) { v.EvidenceRef = "secret bad" }, func(v *Decision) { v.EvidenceRef = "" }} {
bad := d
change(&bad)
if _, err := s.Continue(ctx, token, id, "operation", ContinueInput{Decision: bad, ReviewResolved: true}); err == nil {
t.Fatal("invalid decision accepted")
}
}
for _, bad := range []ReviewTaskInput{
{Decision: d, TaskID: id, ExpectedTaskRevision: 4, Outcome: "SUCCEEDED", Result: json.RawMessage(`{}`)},
{Decision: d, TaskID: id, ExpectedTaskRevision: 4, ExecutionSettled: true, Outcome: "UNKNOWN", Result: json.RawMessage(`{}`)},
{Decision: d, TaskID: id, ExpectedTaskRevision: 4, ExecutionSettled: true, Outcome: "SUCCEEDED", Result: json.RawMessage(`null`)},
{Decision: d, TaskID: id, ExpectedTaskRevision: 4, ExecutionSettled: true, Outcome: "SUCCEEDED", Result: json.RawMessage(`{"n":1,"n":2}`)},
} {
if _, err := s.ReviewTask(ctx, token, id, "operation", bad); err == nil {
t.Fatal("unsafe execution review accepted")
}
}
if _, err := s.Continue(ctx, token, id, "operation", ContinueInput{Decision: d}); err == nil {
t.Fatal("unresolved review continued")
}
if _, err := s.RetryStep(ctx, token, id, "operation", RetryStepInput{StepDecision: step}); err == nil {
t.Fatal("unsafe retry accepted")
}
if store.calls != 4 {
t.Fatal("invalid inputs reached storage", store.calls)
}
}