package domain import ( "errors" "testing" rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1" ) func TestReconciliationMatrix_HP_SES_11(t *testing.T) { t.Parallel() tests := []struct { name string input ReconcileInput want ReconcileAction incident bool }{ {"queued absent", serverInput(rvboxv1.CommandLifecycle_COMMAND_QUEUED, ClientEvidenceAbsent), ReconcileRequeue, false}, {"dispatched absent", serverInput(rvboxv1.CommandLifecycle_COMMAND_DISPATCHED, ClientEvidenceAbsent), ReconcileRequeue, false}, {"accepted absent", serverInput(rvboxv1.CommandLifecycle_COMMAND_ACCEPTED, ClientEvidenceAbsent), ReconcileInterruptServerClientStateLoss, true}, {"running absent", serverInput(rvboxv1.CommandLifecycle_COMMAND_RUNNING, ClientEvidenceAbsent), ReconcileInterruptServerClientStateLoss, true}, {"dispatched retained", retainedInput(rvboxv1.CommandLifecycle_COMMAND_DISPATCHED, rvboxv1.CommandLifecycle_COMMAND_ACCEPTED), ReconcileResumeDelivery, false}, {"accepted retained", retainedInput(rvboxv1.CommandLifecycle_COMMAND_ACCEPTED, rvboxv1.CommandLifecycle_COMMAND_RUNNING), ReconcileResumeDelivery, false}, {"running retained", retainedInput(rvboxv1.CommandLifecycle_COMMAND_RUNNING, rvboxv1.CommandLifecycle_COMMAND_RUNNING), ReconcileResumeDelivery, false}, {"nonterminal tombstone", tombstoneInput(rvboxv1.CommandLifecycle_COMMAND_DISPATCHED), ReconcileInterruptServerSuppressReplay, true}, {"terminal retained", retainedInput(rvboxv1.CommandLifecycle_COMMAND_SUCCEEDED, rvboxv1.CommandLifecycle_COMMAND_SUCCEEDED), ReconcileDiscardLocalTerminal, false}, {"terminal active", retainedInput(rvboxv1.CommandLifecycle_COMMAND_SUCCEEDED, rvboxv1.CommandLifecycle_COMMAND_RUNNING), ReconcileTerminateLocal, true}, {"missing active", ReconcileInput{ClientEvidence: ClientEvidenceRetained, ClientLifecycle: rvboxv1.CommandLifecycle_COMMAND_RUNNING, ClientRevision: 1, ImmutableHashMatches: true}, ReconcileTerminateLocal, true}, {"missing terminal", ReconcileInput{ClientEvidence: ClientEvidenceRetained, ClientLifecycle: rvboxv1.CommandLifecycle_COMMAND_FAILED, ClientRevision: 1, ImmutableHashMatches: true}, ReconcileDiscardLocalTerminal, false}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() decision, err := DecideReconciliation(test.input) if err != nil { t.Fatalf("DecideReconciliation(): %v", err) } if decision.Action != test.want || decision.RecordIncident != test.incident { t.Fatalf("decision = %+v, want action=%v incident=%t", decision, test.want, test.incident) } }) } } func TestReconciliationContradictions_BH_SES_10(t *testing.T) { t.Parallel() tests := []ReconcileInput{ func() ReconcileInput { value := retainedInput(rvboxv1.CommandLifecycle_COMMAND_ACCEPTED, rvboxv1.CommandLifecycle_COMMAND_RUNNING) value.ImmutableHashMatches = false return value }(), func() ReconcileInput { value := retainedInput(rvboxv1.CommandLifecycle_COMMAND_ACCEPTED, rvboxv1.CommandLifecycle_COMMAND_RUNNING) value.ClientLastEventSeq = 0 value.ServerLastEventSeq = 1 return value }(), retainedInput(rvboxv1.CommandLifecycle_COMMAND_QUEUED, rvboxv1.CommandLifecycle_COMMAND_ACCEPTED), retainedInput(rvboxv1.CommandLifecycle_COMMAND_SUCCEEDED, rvboxv1.CommandLifecycle_COMMAND_FAILED), } for _, input := range tests { decision, err := DecideReconciliation(input) if !errors.Is(err, ErrReconcileContradiction) { t.Errorf("error = %v, decision=%+v", err, decision) } } } func TestReconciliationKeepsHighestRevision_HP_SES_11(t *testing.T) { t.Parallel() input := retainedInput(rvboxv1.CommandLifecycle_COMMAND_ACCEPTED, rvboxv1.CommandLifecycle_COMMAND_RUNNING) input.ServerRevision = 4 input.ClientRevision = 7 decision, err := DecideReconciliation(input) if err != nil || decision.EffectiveRevision != 7 { t.Fatalf("decision = %+v, error = %v", decision, err) } } func serverInput(state rvboxv1.CommandLifecycle, evidence ClientEvidenceKind) ReconcileInput { return ReconcileInput{ServerPresent: true, ServerLifecycle: state, ServerRevision: 1, ClientEvidence: evidence} } func retainedInput(server, client rvboxv1.CommandLifecycle) ReconcileInput { return ReconcileInput{ServerPresent: true, ServerLifecycle: server, ServerRevision: 1, ServerLastEventSeq: 1, ClientEvidence: ClientEvidenceRetained, ClientLifecycle: client, ClientRevision: 1, ClientLastEventSeq: 1, ImmutableHashMatches: true} } func tombstoneInput(server rvboxv1.CommandLifecycle) ReconcileInput { return ReconcileInput{ServerPresent: true, ServerLifecycle: server, ServerRevision: 1, ClientEvidence: ClientEvidenceTombstone, ClientRevision: 1, ImmutableHashMatches: true} }