Files
rvbox/internal/domain/reconcile_test.go
T

95 lines
4.6 KiB
Go

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}
}