fix(protocol): fence gateway work recovery
This commit is contained in:
@@ -89,11 +89,125 @@ func TestRC6BitratePreferenceTaggedBounds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRC6GatewayQualityDiscoveryAndLeaseFencing(t *testing.T) {
|
||||
operationID := "12345678-1234-1234-1234-123456789abc"
|
||||
revision := int64(7)
|
||||
leaseGeneration := int64(3)
|
||||
currentRevision := int64(6)
|
||||
|
||||
poll := protocol.GatewayQualityWorkRequest{Version: "1", SessionID: "session-1", GatewayID: "gateway-1", ReconnectSequence: 2, Acquisition: "poll"}
|
||||
if err := poll.Validate(); err != nil {
|
||||
t.Fatalf("session-bound lost-prompt poll rejected: %v", err)
|
||||
}
|
||||
prompt := poll
|
||||
prompt.Acquisition = "prompt"
|
||||
prompt.OperationID = operationID
|
||||
prompt.Revision = &revision
|
||||
if err := prompt.Validate(); err != nil {
|
||||
t.Fatalf("prompt-bound acquisition rejected: %v", err)
|
||||
}
|
||||
observation := prompt
|
||||
observation.Acquisition = "observation"
|
||||
observation.LeaseGeneration = &leaseGeneration
|
||||
observation.CurrentAppliedRevision = ¤tRevision
|
||||
if err := observation.Validate(); err != nil {
|
||||
t.Fatalf("lease-bound applied-revision observation rejected: %v", err)
|
||||
}
|
||||
|
||||
for name, invalid := range map[string]protocol.GatewayQualityWorkRequest{
|
||||
"poll with unknown coordinates": prompt,
|
||||
"prompt missing revision": {Version: "1", SessionID: "session-1", GatewayID: "gateway-1", Acquisition: "prompt", OperationID: operationID},
|
||||
"observation missing lease": {Version: "1", SessionID: "session-1", GatewayID: "gateway-1", Acquisition: "observation", OperationID: operationID, Revision: &revision, CurrentAppliedRevision: ¤tRevision},
|
||||
} {
|
||||
if name == "poll with unknown coordinates" {
|
||||
invalid.Acquisition = "poll"
|
||||
}
|
||||
if invalid.Validate() == nil {
|
||||
t.Fatalf("accepted invalid %s: %+v", name, invalid)
|
||||
}
|
||||
}
|
||||
|
||||
stopPoll := protocol.GatewayStopWorkRequest{Version: "1", SessionID: "session-1", GatewayID: "gateway-1", ReconnectSequence: 2, Acquisition: "poll"}
|
||||
if err := stopPoll.Validate(); err != nil {
|
||||
t.Fatalf("session-bound Stop poll rejected: %v", err)
|
||||
}
|
||||
stopPrompt := stopPoll
|
||||
stopPrompt.Acquisition = "prompt"
|
||||
stopPrompt.OperationID = operationID
|
||||
if err := stopPrompt.Validate(); err != nil {
|
||||
t.Fatalf("prompt-bound Stop acquisition rejected: %v", err)
|
||||
}
|
||||
stopPoll.OperationID = operationID
|
||||
if stopPoll.Validate() == nil {
|
||||
t.Fatal("Stop poll accepted unknown operation coordinates")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRC6GatewayQualityAckHasUnambiguousObservation(t *testing.T) {
|
||||
revision := int64(7)
|
||||
prior := int64(6)
|
||||
base := protocol.GatewayQualityAck{
|
||||
Version: "1", SessionID: "session-1", GatewayID: "gateway-1", ReconnectSequence: 2,
|
||||
OperationID: "12345678-1234-1234-1234-123456789abc", Revision: revision, LeaseGeneration: 3,
|
||||
}
|
||||
for _, valid := range []protocol.GatewayQualityAck{
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "applied"
|
||||
value.CurrentAppliedRevision = &revision
|
||||
return value
|
||||
}(),
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "proven_prior"
|
||||
value.CurrentAppliedRevision = &prior
|
||||
return value
|
||||
}(),
|
||||
func() protocol.GatewayQualityAck { value := base; value.Outcome = "unknown"; return value }(),
|
||||
} {
|
||||
if err := valid.Validate(); err != nil {
|
||||
t.Fatalf("valid quality acknowledgement rejected: %+v: %v", valid, err)
|
||||
}
|
||||
}
|
||||
for _, invalid := range []protocol.GatewayQualityAck{
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "applied"
|
||||
value.CurrentAppliedRevision = &prior
|
||||
return value
|
||||
}(),
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "proven_prior"
|
||||
value.CurrentAppliedRevision = &revision
|
||||
return value
|
||||
}(),
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "unknown"
|
||||
value.CurrentAppliedRevision = &prior
|
||||
return value
|
||||
}(),
|
||||
func() protocol.GatewayQualityAck {
|
||||
value := base
|
||||
value.Outcome = "unknown"
|
||||
value.LeaseGeneration = 0
|
||||
return value
|
||||
}(),
|
||||
} {
|
||||
if invalid.Validate() == nil {
|
||||
t.Fatalf("contradictory or unfenced quality acknowledgement accepted: %+v", invalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRC6JSONFixturesAndCanonicalOperationFields(t *testing.T) {
|
||||
validFixtures := map[string]func([]byte) error{
|
||||
"../../fixtures/valid/session-request.json": func(raw []byte) error { _, err := protocol.DecodeSessionRequest(raw); return err },
|
||||
"../../fixtures/valid/selected-session-descriptor.json": func(raw []byte) error { _, err := protocol.DecodeSelectedSessionDescriptor(raw); return err },
|
||||
"../../fixtures/valid/session-quality-limits.json": func(raw []byte) error { _, err := protocol.DecodeSessionQualityLimits(raw); return err },
|
||||
"../../fixtures/valid/gateway-quality-poll.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityWorkRequest(raw); return err },
|
||||
"../../fixtures/valid/gateway-quality-ack-applied.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityAck(raw); return err },
|
||||
}
|
||||
for path, decode := range validFixtures {
|
||||
raw, err := os.ReadFile(path)
|
||||
@@ -111,6 +225,12 @@ func TestRC6JSONFixturesAndCanonicalOperationFields(t *testing.T) {
|
||||
"../../fixtures/invalid/video-profile-unknown.json": func(raw []byte) error { _, err := protocol.DecodeVideoProfile(raw); return err },
|
||||
"../../fixtures/invalid/bitrate-preference-auto-target.json": func(raw []byte) error { _, err := protocol.DecodeBitratePreference(raw); return err },
|
||||
"../../fixtures/invalid/selected-session-descriptor-provider-field.json": func(raw []byte) error { _, err := protocol.DecodeSelectedSessionDescriptor(raw); return err },
|
||||
"../../fixtures/invalid/gateway-quality-poll-coordinates.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityWorkRequest(raw); return err },
|
||||
"../../fixtures/invalid/gateway-quality-ack-contradictory.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityAck(raw); return err },
|
||||
"../../fixtures/invalid/gateway-quality-ack-uppercase-uuid.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityAck(raw); return err },
|
||||
"../../fixtures/invalid/gateway-quality-ack-zero-uuid.json": func(raw []byte) error { _, err := protocol.DecodeGatewayQualityAck(raw); return err },
|
||||
"../../fixtures/invalid/quality-operation-offset-time.json": func(raw []byte) error { _, err := protocol.DecodeQualityChangeOperation(raw); return err },
|
||||
"../../fixtures/invalid/quality-operation-noncanonical-fraction.json": func(raw []byte) error { _, err := protocol.DecodeQualityChangeOperation(raw); return err },
|
||||
}
|
||||
for path, decode := range invalidFixtures {
|
||||
raw, err := os.ReadFile(path)
|
||||
|
||||
Reference in New Issue
Block a user