95 lines
4.6 KiB
Go
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}
|
|
}
|