package streamgate import ( "context" "errors" "testing" "time" ) func TestNoopFilterContract(t *testing.T) { t.Run("DefaultConstructor", func(t *testing.T) { filter, err := NewNoopFilter() if err != nil { t.Fatalf("NewNoopFilter failed: %v", err) } if filter.ID() != DefaultNoopFilterID { t.Errorf("ID() = %q, want %q", filter.ID(), DefaultNoopFilterID) } builder := NewFilterContextBuilder("gen-1", "att-1") fctx, err := builder.Build() if err != nil { t.Fatalf("Build FilterContext failed: %v", err) } if !filter.Applies(fctx) { t.Errorf("Applies() = false, want true") } holdReq := filter.HoldRequirement(fctx) if holdReq.Mode() != FilterHoldModeNone { t.Errorf("HoldRequirement.Mode() = %v, want %v", holdReq.Mode(), FilterHoldModeNone) } if holdReq.Channel() != DefaultNoopChannel { t.Errorf("HoldRequirement.Channel() = %q, want %q", holdReq.Channel(), DefaultNoopChannel) } }) t.Run("CustomChannelConstructor", func(t *testing.T) { filter, err := NewNoopFilterWithChannel("custom_noop", "custom_ch") if err != nil { t.Fatalf("NewNoopFilterWithChannel failed: %v", err) } if filter.ID() != "custom_noop" { t.Errorf("ID() = %q, want custom_noop", filter.ID()) } builder := NewFilterContextBuilder("gen-1", "att-1") fctx, _ := builder.Build() holdReq := filter.HoldRequirement(fctx) if holdReq.Channel() != "custom_ch" { t.Errorf("HoldRequirement.Channel() = %q, want custom_ch", holdReq.Channel()) } }) t.Run("EvaluatePassDecision", func(t *testing.T) { filter, _ := NewNoopFilter() builder := NewFilterContextBuilder("gen-1", "att-1") fctx, _ := builder.Build() ev, err := NewTextDeltaEvent("ch", "hello", time.Now()) if err != nil { t.Fatalf("NewTextDeltaEvent failed: %v", err) } batch, err := NewEvidenceBatch( []NormalizedEvent{ev}, nil, nil, nil, false, CommitStateTransportUncommitted, time.Now(), ) if err != nil { t.Fatalf("NewEvidenceBatch failed: %v", err) } ctx := context.Background() decision, err := filter.Evaluate(ctx, fctx, batch) if err != nil { t.Fatalf("Evaluate failed: %v", err) } if decision.Kind() != FilterDecisionKindPass { t.Errorf("Decision Kind = %v, want %v", decision.Kind(), FilterDecisionKindPass) } if decision.FilterID() != DefaultNoopFilterID { t.Errorf("Decision FilterID = %q, want %q", decision.FilterID(), DefaultNoopFilterID) } if decision.ConsumerID() != DefaultNoopConsumerID { t.Errorf("Decision ConsumerID = %q, want %q", decision.ConsumerID(), DefaultNoopConsumerID) } if decision.RuleID() != DefaultNoopRuleID { t.Errorf("Decision RuleID = %q, want %q", decision.RuleID(), DefaultNoopRuleID) } if decision.Intent() != nil { t.Errorf("Decision Intent must be nil for pass decision") } }) t.Run("EvaluateContextCancelled", func(t *testing.T) { filter, _ := NewNoopFilter() builder := NewFilterContextBuilder("gen-1", "att-1") fctx, _ := builder.Build() ev, _ := NewTextDeltaEvent("ch", "hello", time.Now()) batch, _ := NewEvidenceBatch( []NormalizedEvent{ev}, nil, nil, nil, false, CommitStateTransportUncommitted, time.Now(), ) ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := filter.Evaluate(ctx, fctx, batch) if err == nil { t.Errorf("Evaluate with cancelled context expected error, got nil") } }) } func TestRuntimeOptionsValidation(t *testing.T) { t.Run("DefaultOptionsValid", func(t *testing.T) { opts := DefaultRuntimeOptions() if err := opts.Validate(); err != nil { t.Fatalf("DefaultRuntimeOptions validation failed: %v", err) } if opts.MaxEvidenceRunes() != DefaultMaxEvidenceRunes { t.Errorf("MaxEvidenceRunes = %d, want %d", opts.MaxEvidenceRunes(), DefaultMaxEvidenceRunes) } if opts.MaxBufferRunes() != DefaultMaxBufferRunes { t.Errorf("MaxBufferRunes = %d, want %d", opts.MaxBufferRunes(), DefaultMaxBufferRunes) } if opts.MaxIngressSnapshotBytes() != DefaultMaxIngressSnapshotBytes { t.Errorf("MaxIngressSnapshotBytes = %d, want %d", opts.MaxIngressSnapshotBytes(), DefaultMaxIngressSnapshotBytes) } if opts.MaxRecoveryAttemptsTotal() != DefaultMaxRecoveryAttemptsTotal { t.Errorf("MaxRecoveryAttemptsTotal = %d, want %d", opts.MaxRecoveryAttemptsTotal(), DefaultMaxRecoveryAttemptsTotal) } }) t.Run("InvalidRunes", func(t *testing.T) { _, err := NewRuntimeOptions(0, 4096, 1024, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for 0 max evidence runes") } _, err = NewRuntimeOptions(500, 100, 1024, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for maxBuffer < maxEvidence") } }) t.Run("InvalidIngressBytes", func(t *testing.T) { _, err := NewRuntimeOptions(500, 4096, 0, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for 0 max ingress bytes") } }) t.Run("IngressAbsoluteCapBoundaries", func(t *testing.T) { limit := int64(DefaultMaxIngressSnapshotBytes) // limit-1 should succeed _, err := NewRuntimeOptions(500, 4096, limit-1, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err != nil { t.Errorf("NewRuntimeOptions(limit-1) unexpected error: %v", err) } // limit should succeed _, err = NewRuntimeOptions(500, 4096, limit, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err != nil { t.Errorf("NewRuntimeOptions(limit) unexpected error: %v", err) } // limit+1 should fail _, err = NewRuntimeOptions(500, 4096, limit+1, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for max ingress bytes > 16 MiB") } }) t.Run("DirectValidateRejectsIngressLimitPlusOne", func(t *testing.T) { opts := DefaultRuntimeOptions() opts.maxIngressSnapshotBytes = DefaultMaxIngressSnapshotBytes + 1 if err := opts.Validate(); err == nil { t.Errorf("Direct Validate() with limit+1 bytes should fail") } }) t.Run("InvalidRecoveryAttempts", func(t *testing.T) { _, err := NewRuntimeOptions(500, 4096, 1024, 4, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for max recovery attempts > 3") } _, err = NewRuntimeOptions(500, 4096, 1024, -1, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err == nil { t.Errorf("Expected error for negative max recovery attempts") } }) } type fakeDispatcher struct{} func (fakeDispatcher) DispatchAttempt(ctx context.Context, request RebuiltRequest) (AttemptBinding, error) { return AttemptBinding{}, errors.New("fake dispatch") } type fakeRebuilder struct{} func (fakeRebuilder) RebuildRequest(ctx context.Context, snapshot RecoveryRequestSnapshotRef, plan RecoveryPlan) (RebuiltRequestDraft, error) { return RebuiltRequestDraft{}, errors.New("fake rebuild") } type fakeSink struct{} func (fakeSink) CommitResponseStart(ctx context.Context, rs ResponseStart) (CommitState, error) { return CommitStateTransportUncommitted, nil } func (fakeSink) Release(ctx context.Context, ev ReleaseEvent) (CommitState, error) { return CommitStateStreamOpen, nil } func (fakeSink) CommitTerminal(ctx context.Context, tr TerminalResult) (CommitState, error) { return CommitStateTerminalCommitted, nil } type mockPreparer struct{} func (mockPreparer) PrepareRecoveryPlan(ctx context.Context, plan RecoveryPlan, snapshot RecoveryPreparationSnapshot) (RecoveryDirective, error) { return NewRecoveryDirectiveExact("req-ref-1") } type mockPrepFactory struct{} func (mockPrepFactory) CreatePreparationSnapshot(ctx context.Context, snapshot RequestRuntimeSnapshot, binding AttemptBinding) (RecoveryPreparationSnapshot, error) { return nil, nil } func TestRequestRuntimeSnapshotContract(t *testing.T) { regSnap, err := NewFilterRegistrySnapshot("gen-1", nil, nil) if err != nil { t.Fatalf("NewFilterRegistrySnapshot failed: %v", err) } snapRef, err := NewRecoveryRequestSnapshotRef("snap.ref.1", 100, 200, 1024) if err != nil { t.Fatalf("NewRecoveryRequestSnapshotRef failed: %v", err) } opts := DefaultRuntimeOptions() disp := fakeDispatcher{} rebuilder := fakeRebuilder{} sink := fakeSink{} t.Run("ValidConstruction", func(t *testing.T) { reqSnap, err := NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, sink, ) if err != nil { t.Fatalf("NewRequestRuntimeSnapshot failed: %v", err) } if reqSnap.RequestID() != "req-123" { t.Errorf("RequestID() = %q, want req-123", reqSnap.RequestID()) } if reqSnap.ConfigGeneration() != "gen-1" { t.Errorf("ConfigGeneration() = %q, want gen-1", reqSnap.ConfigGeneration()) } if reqSnap.Environment() != "prod" { t.Errorf("Environment() = %q, want prod", reqSnap.Environment()) } if reqSnap.Endpoint() != "v1/chat/completions" { t.Errorf("Endpoint() = %q, want v1/chat/completions", reqSnap.Endpoint()) } if reqSnap.Family() != "gpt4" { t.Errorf("Family() = %q, want gpt4", reqSnap.Family()) } if reqSnap.Dispatcher() == nil || reqSnap.Rebuilder() == nil || reqSnap.Sink() == nil { t.Errorf("Seam accessors returned nil") } if reqSnap.Preparer() != nil { t.Errorf("Preparer() expected nil") } if reqSnap.PreparationSnapshotFactory() != nil { t.Errorf("PreparationSnapshotFactory() expected nil") } // Test BuildAttemptFilterContext target, err := NewAttemptTarget("standard", "gpt-4-turbo", "openai", "primary", nil) if err != nil { t.Fatalf("NewAttemptTarget failed: %v", err) } fctx, err := reqSnap.BuildAttemptFilterContext("att-1", target, 1, CommitStateTransportUncommitted) if err != nil { t.Fatalf("BuildAttemptFilterContext failed: %v", err) } if fctx.AttemptID() != "att-1" { t.Errorf("FilterContext AttemptID() = %q, want att-1", fctx.AttemptID()) } if fctx.EpochID() != 1 { t.Errorf("FilterContext EpochID() = %d, want 1", fctx.EpochID()) } if fctx.StableCorrelation() != "req-123" { t.Errorf("FilterContext StableCorrelation() = %q, want req-123", fctx.StableCorrelation()) } if fctx.ActualModel() != "gpt-4-turbo" { t.Errorf("FilterContext ActualModel() = %q, want gpt-4-turbo", fctx.ActualModel()) } }) t.Run("PreparerFactoryPairingValidation", func(t *testing.T) { // Both non-nil should succeed p := mockPreparer{} f := mockPrepFactory{} _, err := NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, p, f, sink, ) if err != nil { t.Errorf("Both non-nil preparer/factory failed: %v", err) } // Preparer non-nil, factory nil should fail _, err = NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, p, nil, sink, ) if err == nil { t.Errorf("Expected error for preparer set without factory") } // Preparer nil, factory non-nil should fail _, err = NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, nil, f, sink, ) if err == nil { t.Errorf("Expected error for factory set without preparer") } }) t.Run("GenerationMismatch", func(t *testing.T) { // matching generation should succeed _, err := NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, sink, ) if err != nil { t.Fatalf("NewRequestRuntimeSnapshot with matching generation failed: %v", err) } // mismatching generation should fail _, err = NewRequestRuntimeSnapshot( "req-123", "gen-2", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, sink, ) if err == nil { t.Errorf("Expected error for config/registry generation mismatch") } }) t.Run("DirectValidateRejectsGenerationMismatch", func(t *testing.T) { reqSnap, err := NewRequestRuntimeSnapshot( "req-123", "gen-1", "prod", "v1/chat/completions", "gpt4", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, sink, ) if err != nil { t.Fatalf("NewRequestRuntimeSnapshot failed: %v", err) } // Tamper configGen to cause mismatch reqSnap.configGen = StableToken{value: "gen-999"} if err := reqSnap.Validate(); err == nil { t.Errorf("Direct Validate() with mismatched generation should fail") } }) t.Run("ValidationErrors", func(t *testing.T) { _, err := NewRequestRuntimeSnapshot( "", "gen-1", "prod", "ep", "fam", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, sink, ) if err == nil { t.Errorf("Expected error for empty requestID") } _, err = NewRequestRuntimeSnapshot( "req-1", "gen-1", "prod", "ep", "fam", opts, regSnap, nil, snapRef, nil, rebuilder, nil, nil, sink, ) if err == nil { t.Errorf("Expected error for nil dispatcher") } _, err = NewRequestRuntimeSnapshot( "req-1", "gen-1", "prod", "ep", "fam", opts, regSnap, nil, snapRef, disp, nil, nil, nil, sink, ) if err == nil { t.Errorf("Expected error for nil rebuilder") } _, err = NewRequestRuntimeSnapshot( "req-1", "gen-1", "prod", "ep", "fam", opts, regSnap, nil, snapRef, disp, rebuilder, nil, nil, nil, ) if err == nil { t.Errorf("Expected error for nil sink") } }) } func TestRuntimeOptionsRecoveryStrategyLimits(t *testing.T) { base, err := NewRuntimeOptions(500, 4096, 1024, 3, GateCoordinatorOptions{}, RecoveryCoordinatorOptions{}) if err != nil { t.Fatalf("NewRuntimeOptions: %v", err) } t.Run("omitted inherits total", func(t *testing.T) { if got := base.MaxRecoveryAttemptsByStrategy(); got != nil { t.Errorf("expected nil strategy map for omitted caps, got %v", got) } }) t.Run("explicit caps are snapshot and defensively copied", func(t *testing.T) { limits := map[RecoveryStrategy]int{ RecoveryStrategyExactReplay: 1, RecoveryStrategyContinuationRepair: 0, RecoveryStrategySchemaRepair: 2, } opts, err := base.WithRecoveryStrategyLimits(limits) if err != nil { t.Fatalf("WithRecoveryStrategyLimits: %v", err) } limits[RecoveryStrategyExactReplay] = 99 // mutate caller map after snapshot got := opts.MaxRecoveryAttemptsByStrategy() if got[RecoveryStrategyExactReplay] != 1 || got[RecoveryStrategyContinuationRepair] != 0 || got[RecoveryStrategySchemaRepair] != 2 { t.Errorf("strategy caps not snapshot defensively: %v", got) } got[RecoveryStrategyExactReplay] = 42 // mutate returned copy if again := opts.MaxRecoveryAttemptsByStrategy(); again[RecoveryStrategyExactReplay] != 1 { t.Errorf("accessor did not return a defensive copy: %v", again) } // The wired snapshot must build a valid recovery policy honoring the caps. if _, err := NewRecoveryPolicySnapshot(opts.MaxRecoveryAttemptsTotal(), opts.MaxRecoveryAttemptsByStrategy()); err != nil { t.Errorf("NewRecoveryPolicySnapshot from options: %v", err) } }) t.Run("cap above total rejected", func(t *testing.T) { if _, err := base.WithRecoveryStrategyLimits(map[RecoveryStrategy]int{RecoveryStrategyExactReplay: 4}); err == nil { t.Errorf("expected error for strategy cap above total") } }) t.Run("negative cap rejected", func(t *testing.T) { if _, err := base.WithRecoveryStrategyLimits(map[RecoveryStrategy]int{RecoveryStrategyExactReplay: -1}); err == nil { t.Errorf("expected error for negative strategy cap") } }) t.Run("non-fault strategy rejected", func(t *testing.T) { if _, err := base.WithRecoveryStrategyLimits(map[RecoveryStrategy]int{RecoveryStrategyManagedContinuation: 1}); err == nil { t.Errorf("expected error for non-fault strategy cap") } }) }