From afc0740e4e00cb72542c84ef1ac48aab72aea493 Mon Sep 17 00:00:00 2001 From: MMinasyan Date: Mon, 19 Oct 2026 15:34:33 +0400 Subject: [PATCH 1/4] test(harness): consolidate record and graph scenarios --- harness/compact_manual_test.go | 32 +++-- harness/graph_test.go | 226 ++++++++++++++------------------- harness/public_test.go | 72 +---------- 3 files changed, 125 insertions(+), 205 deletions(-) diff --git a/harness/compact_manual_test.go b/harness/compact_manual_test.go index bc8cc62e..794df1ab 100644 --- a/harness/compact_manual_test.go +++ b/harness/compact_manual_test.go @@ -396,11 +396,6 @@ func TestCompactAdmissionCodecRules(t *testing.T) { admission := wireObject(t, raw)["admission"] mutatedAdmission := setKey(admission, "admitted_entry", json.RawMessage(`{"session_id":"`+testSessionID+`","entry_id":"`+hexID(1)+`"}`)) mutated := setKey(raw, "admission", mutatedAdmission) - if _, err := decodeOperationRegister(Register{Key: RegisterKey{SessionID: testSessionID, Kind: RegisterOperation, OperationID: testOpID}, Payload: mutated}); err == nil { - t.Fatalf("compact payload with an admitted entry decoded") - } else if !strings.Contains(err.Error(), "admitted_entry") { - t.Fatalf("error %v, want the admitted_entry member named", err) - } // A message payload without the member rejects. messageRaw, err := encodeOperationRegister(validOperationRecord()) @@ -408,9 +403,6 @@ func TestCompactAdmissionCodecRules(t *testing.T) { t.Fatalf("encode message register: %v", err) } messageless := setKey(messageRaw, "admission", deleteKey(t, wireObject(t, messageRaw)["admission"], "admitted_entry")) - if _, err := decodeOperationRegister(Register{Key: RegisterKey{SessionID: testSessionID, Kind: RegisterOperation, OperationID: testOpID}, Payload: messageless}); err == nil { - t.Fatalf("message payload without its admitted entry decoded") - } // An unknown kind rejects on both directions. unknown := compactOperationRecord(testOpID) @@ -419,8 +411,28 @@ func TestCompactAdmissionCodecRules(t *testing.T) { t.Fatalf("unknown request kind encoded") } unknownWire := setKey(raw, "admission", setKey(admission, "request_kind", json.RawMessage(`"bogus"`))) - if _, err := decodeOperationRegister(Register{Key: RegisterKey{SessionID: testSessionID, Kind: RegisterOperation, OperationID: testOpID}, Payload: unknownWire}); err == nil { - t.Fatalf("unknown request kind decoded") + + // The raw payloads above bypass the production encoder: each names one + // invalid persisted state the decoder must refuse. + rejections := []struct { + name string + payload json.RawMessage + wantText string + }{ + {"compact payload carrying the admitted entry", mutated, "admitted_entry"}, + {"message payload without the admitted entry", messageless, ""}, + {"unknown request kind", unknownWire, ""}, + } + for _, tc := range rejections { + t.Run(tc.name, func(t *testing.T) { + _, err := decodeOperationRegister(Register{Key: RegisterKey{SessionID: testSessionID, Kind: RegisterOperation, OperationID: testOpID}, Payload: tc.payload}) + if err == nil { + t.Fatalf("%s decoded", tc.name) + } + if tc.wantText != "" && !strings.Contains(err.Error(), tc.wantText) { + t.Fatalf("error %v, want the %s member named", err, tc.wantText) + } + }) } } diff --git a/harness/graph_test.go b/harness/graph_test.go index 9ea1e9e5..f90fd66e 100644 --- a/harness/graph_test.go +++ b/harness/graph_test.go @@ -426,6 +426,24 @@ func wantCorruption(t *testing.T, err error) *CorruptionError { // coherent durable shapes and returns the owned decoded view: the Session // record, Operation records in read order, and committed-order typed entries. func TestGraphValidatorAcceptsCoherentSessions(t *testing.T) { + // singleCallGraph builds the coherent fixture whose one published + // assistant call stays pending with the supplied reserved result entry ID. + singleCallGraph := func(resultEntryID string) *testGraph { + fixture := validTestGraph() + assistant := validAssistantEntry(testOpID) + assistant.EntryID = hexID(2) + call := validToolCallRecord() + call.ResultEntryID = resultEntryID + assistant.ToolCalls = []toolCallRecord{call} + fixture.entries[1].assistant = &assistant + fixture.ops[0].State.PendingToolCalls = []PendingToolCall{{ + AssistantEntry: EntryRef{SessionID: testSessionID, EntryID: hexID(2)}, + CallID: "call-1", + ResultEntryID: resultEntryID, + }} + return fixture + } + t.Run("running session", func(t *testing.T) { fixture := validTestGraph() view, err := validateFixture(t, fixture.storage(t), testSessionID) @@ -464,19 +482,7 @@ func TestGraphValidatorAcceptsCoherentSessions(t *testing.T) { }) t.Run("pending tool call", func(t *testing.T) { - fixture := validTestGraph() - assistant := validAssistantEntry(testOpID) - assistant.EntryID = hexID(2) - call := validToolCallRecord() - call.ResultEntryID = hexID(3) - assistant.ToolCalls = []toolCallRecord{call} - fixture.entries[1].assistant = &assistant - op := &fixture.ops[0] - op.State.PendingToolCalls = []PendingToolCall{{ - AssistantEntry: EntryRef{SessionID: testSessionID, EntryID: hexID(2)}, - CallID: "call-1", - ResultEntryID: hexID(3), - }} + fixture := singleCallGraph(hexID(3)) view, err := validateFixture(t, fixture.storage(t), testSessionID) if err != nil { t.Fatalf("valid pending shape rejected: %v", err) @@ -565,19 +571,7 @@ func TestGraphValidatorAcceptsCoherentSessions(t *testing.T) { }) t.Run("settled hook results", func(t *testing.T) { - fixture := validTestGraph() - assistant := validAssistantEntry(testOpID) - assistant.EntryID = hexID(2) - call := validToolCallRecord() - call.ResultEntryID = hexID(4) - assistant.ToolCalls = []toolCallRecord{call} - fixture.entries[1].assistant = &assistant - op := &fixture.ops[0] - op.State.PendingToolCalls = []PendingToolCall{{ - AssistantEntry: EntryRef{SessionID: testSessionID, EntryID: hexID(2)}, - CallID: "call-1", - ResultEntryID: hexID(4), - }} + fixture := singleCallGraph(hexID(4)) first := hookResultEntry{ SessionID: testSessionID, EntryID: hexID(3), OperationID: testOpID, HookID: "cap.hook.one", ToolCallID: "call-1", Status: hookSucceeded, @@ -602,20 +596,8 @@ func TestGraphValidatorAcceptsCoherentSessions(t *testing.T) { }) t.Run("running hook effect", func(t *testing.T) { - fixture := validTestGraph() - assistant := validAssistantEntry(testOpID) - assistant.EntryID = hexID(2) - call := validToolCallRecord() - call.ResultEntryID = hexID(3) - assistant.ToolCalls = []toolCallRecord{call} - fixture.entries[1].assistant = &assistant - op := &fixture.ops[0] - op.State.PendingToolCalls = []PendingToolCall{{ - AssistantEntry: EntryRef{SessionID: testSessionID, EntryID: hexID(2)}, - CallID: "call-1", - ResultEntryID: hexID(3), - }} - op.State.ActiveEffect = &ActiveEffect{Kind: EffectHook, ResultEntryID: hexID(9), ToolCallID: "call-1", HookID: "cap.hook.one"} + fixture := singleCallGraph(hexID(3)) + fixture.ops[0].State.ActiveEffect = &ActiveEffect{Kind: EffectHook, ResultEntryID: hexID(9), ToolCallID: "call-1", HookID: "cap.hook.one"} view, err := validateFixture(t, fixture.storage(t), testSessionID) if err != nil { t.Fatalf("valid hook-effect shape rejected: %v", err) @@ -1449,9 +1431,6 @@ func TestGraphValidatorSurfacesCorruption(t *testing.T) { fixture := validTestGraph() tc.mutate(t, fixture) store := fixture.storage(t) - if tc.name == "orphan entries without session register" { - delete(store.registers, testSessionID) - } corrupt := wantCorruption(t, func() error { _, err := validateFixture(t, store, testSessionID) return err @@ -1614,10 +1593,8 @@ func TestGraphValidatorForkReferenceRules(t *testing.T) { env: Entry{SessionID: testSessionID, ID: hexID(4), Kind: EntryToolResult, Sequence: 4, CommittedAt: testTime}, toolResult: &copiedResult, }) - wantCorruption(t, func() error { - _, err := validateFixture(t, fork.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fork.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("copied tool result pointing at an owned assistant", func(t *testing.T) { @@ -1633,10 +1610,8 @@ func TestGraphValidatorForkReferenceRules(t *testing.T) { env: Entry{SessionID: testSessionID, ID: hexID(4), Kind: EntryToolResult, Sequence: 4, CommittedAt: testTime}, toolResult: &copiedResult, }) - wantCorruption(t, func() error { - _, err := validateFixture(t, fork.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fork.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("owned signal resolves its related operation", func(t *testing.T) { @@ -1661,10 +1636,8 @@ func TestGraphValidatorForkReferenceRules(t *testing.T) { env: Entry{SessionID: testSessionID, ID: hexID(3), OperationID: testOpID, Kind: EntrySignal, Sequence: 3, CommittedAt: testTime}, signal: &owned, }) - wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + wantCorruption(t, err) }) } @@ -1715,10 +1688,8 @@ func TestGraphValidatorBackgroundCompletionOwnership(t *testing.T) { fixture.entries = []testEntry{ {env: Entry{SessionID: testSessionID, ID: hexID(9), Kind: EntrySignal, Sequence: 1, CommittedAt: testTime}, signal: &copied}, } - corrupt := wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + corrupt := wantCorruption(t, err) if !strings.Contains(corrupt.Detail, "root Session carries independently copied entry") { t.Fatalf("corruption detail = %q, want the copied-entry rule", corrupt.Detail) } @@ -1784,10 +1755,8 @@ func TestGraphValidatorCompactionRules(t *testing.T) { t.Run("dangling projection reference corrupts", func(t *testing.T) { fixture := validTestGraph() fixture.session.State.CompactionEntryID = otherEntry() - corrupt := wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + corrupt := wantCorruption(t, err) if !strings.Contains(corrupt.Detail, "compaction") { t.Fatalf("corruption detail = %q, want the compaction rule", corrupt.Detail) } @@ -1796,28 +1765,22 @@ func TestGraphValidatorCompactionRules(t *testing.T) { t.Run("projection naming a non-compaction entry corrupts", func(t *testing.T) { fixture := validTestGraph() fixture.session.State.CompactionEntryID = hexID(2) - wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("boundary naming no in-session entry corrupts", func(t *testing.T) { fixture := validTestGraph() fixture.entries = append(fixture.entries, compactionAt(hexID(3), otherEntry(), testOpID, 3)) - wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("boundary at the compaction sequence corrupts", func(t *testing.T) { fixture := validTestGraph() fixture.entries = append(fixture.entries, compactionAt(hexID(3), hexID(3), testOpID, 3)) - wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("boundary after the compaction sequence corrupts", func(t *testing.T) { @@ -1828,10 +1791,8 @@ func TestGraphValidatorCompactionRules(t *testing.T) { compactionAt(hexID(3), hexID(4), testOpID, 3), testEntry{env: Entry{SessionID: testSessionID, ID: hexID(4), OperationID: testOpID, Kind: EntrySignal, Sequence: 4, CommittedAt: testTime}, signal: &signal}, ) - wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + wantCorruption(t, err) }) t.Run("two compaction entries of one operation validate", func(t *testing.T) { @@ -1903,10 +1864,8 @@ func TestGraphValidatorCompactionRules(t *testing.T) { t.Run("root session rejects an operationless compaction entry", func(t *testing.T) { fixture := &testGraph{session: validSessionRecord()} fixture.entries = []testEntry{compactionAt(hexID(3), hexID(2), "", 1)} - corrupt := wantCorruption(t, func() error { - _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) + _, err := validateFixture(t, fixture.storage(t), testSessionID) + corrupt := wantCorruption(t, err) if !strings.Contains(corrupt.Detail, "root Session carries independently copied entry") { t.Fatalf("corruption detail = %q, want the copied-entry rule", corrupt.Detail) } @@ -1919,53 +1878,62 @@ func TestGraphValidatorCompactionRules(t *testing.T) { func TestGraphValidatorCompactionUsage(t *testing.T) { otherRef := model.ModelRef{Provider: "other", Model: "m2"} - t.Run("compaction usage joins the totals", func(t *testing.T) { - assistantUsage := UsageCount{InputTokens: 1, CachedInputTokens: 2, OutputTokens: 3} - compactionUsage := UsageCount{InputTokens: 4, CachedInputTokens: 5, OutputTokens: 6} - fixture := validTestGraph() - assistant := validAssistantEntry(testOpID) - assistant.EntryID = hexID(2) - assistant.Usage = &assistantUsage - fixture.entries[1].assistant = &assistant - compaction := validCompactionEntry(testOpID) - compaction.EntryID = hexID(3) - compaction.BoundaryEntryID = hexID(2) - compaction.Model = otherRef - compaction.Usage = &compactionUsage - fixture.entries = append(fixture.entries, testEntry{ - env: Entry{SessionID: testSessionID, ID: hexID(3), OperationID: testOpID, Kind: EntryCompaction, Sequence: 3, CommittedAt: testTime}, - compaction: &compaction, - }) - merged, err := addUsageTotals( - UsageTotals{ByModel: []ModelUsage{{Model: testModelRef(), Usage: assistantUsage}}}, - UsageTotals{ByModel: []ModelUsage{{Model: otherRef, Usage: compactionUsage}}}, - ) - if err != nil { - t.Fatalf("merge: %v", err) - } - fixture.ops[0].State.Usage = merged - fixture.session.State.Usage = merged - if _, err := validateFixture(t, fixture.storage(t), testSessionID); err != nil { - t.Fatalf("valid compaction usage rejected: %v", err) - } - }) - - t.Run("compaction usage missing from the totals corrupts", func(t *testing.T) { - fixture := validTestGraph() - compaction := validCompactionEntry(testOpID) - compaction.EntryID = hexID(3) - compaction.BoundaryEntryID = hexID(2) - compaction.Model = otherRef - compaction.Usage = testUsage(5) - fixture.entries = append(fixture.entries, testEntry{ - env: Entry{SessionID: testSessionID, ID: hexID(3), OperationID: testOpID, Kind: EntryCompaction, Sequence: 3, CommittedAt: testTime}, - compaction: &compaction, - }) - wantCorruption(t, func() error { + cases := []struct { + name string + mutate func(t *testing.T, fixture *testGraph, compaction *compactionEntry) + corrupt bool + }{ + { + name: "compaction usage joins the totals", + mutate: func(t *testing.T, fixture *testGraph, compaction *compactionEntry) { + assistantUsage := UsageCount{InputTokens: 1, CachedInputTokens: 2, OutputTokens: 3} + compactionUsage := UsageCount{InputTokens: 4, CachedInputTokens: 5, OutputTokens: 6} + assistant := validAssistantEntry(testOpID) + assistant.EntryID = hexID(2) + assistant.Usage = &assistantUsage + fixture.entries[1].assistant = &assistant + compaction.Usage = &compactionUsage + merged, err := addUsageTotals( + UsageTotals{ByModel: []ModelUsage{{Model: testModelRef(), Usage: assistantUsage}}}, + UsageTotals{ByModel: []ModelUsage{{Model: otherRef, Usage: compactionUsage}}}, + ) + if err != nil { + t.Fatalf("merge: %v", err) + } + fixture.ops[0].State.Usage = merged + fixture.session.State.Usage = merged + }, + }, + { + name: "compaction usage missing from the totals corrupts", + mutate: func(t *testing.T, fixture *testGraph, compaction *compactionEntry) { + compaction.Usage = testUsage(5) + }, + corrupt: true, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + fixture := validTestGraph() + compaction := validCompactionEntry(testOpID) + compaction.EntryID = hexID(3) + compaction.BoundaryEntryID = hexID(2) + compaction.Model = otherRef + tc.mutate(t, fixture, &compaction) + fixture.entries = append(fixture.entries, testEntry{ + env: Entry{SessionID: testSessionID, ID: hexID(3), OperationID: testOpID, Kind: EntryCompaction, Sequence: 3, CommittedAt: testTime}, + compaction: &compaction, + }) _, err := validateFixture(t, fixture.storage(t), testSessionID) - return err - }()) - }) + if tc.corrupt { + wantCorruption(t, err) + return + } + if err != nil { + t.Fatalf("valid compaction usage rejected: %v", err) + } + }) + } } // TestForkCopyCompactionEntries proves the fork copy of compaction entries: diff --git a/harness/public_test.go b/harness/public_test.go index 3eac37f9..e07d6ba0 100644 --- a/harness/public_test.go +++ b/harness/public_test.go @@ -5368,17 +5368,7 @@ func TestPublicForkCopiesPrefixAndAdmits(t *testing.T) { func TestPublicForkArchivedSource(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") f2 := newPublicFixture(t, store, newScriptModel(), nil) defer f2.close() @@ -5502,17 +5492,7 @@ func TestPublicForkBoundaryValidation(t *testing.T) { func TestPublicForkExistingLookup(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") boundary := forkEntryOf(t, store, source, harness.EntryInput, "op-1").ID forkReq := harness.ForkRequest{ SourceSessionID: source, @@ -5699,17 +5679,7 @@ func TestPublicForkExistingLookup(t *testing.T) { func TestPublicForkFirstWriterRace(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") boundary := forkEntryOf(t, store, source, harness.EntryInput, "op-1").ID t.Run("matching first destination is returned", func(t *testing.T) { @@ -5792,17 +5762,7 @@ func TestPublicForkFirstWriterRace(t *testing.T) { func TestPublicForkSourceRevisionRace(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") boundary := forkEntryOf(t, store, source, harness.EntryInput, "op-1").ID before := snapshotSession(t, store, source) @@ -5865,17 +5825,7 @@ func mustForeignPayload(t *testing.T, snap sessionSnapshot) json.RawMessage { func TestPublicForkIndependentSourceDeletion(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") boundary := forkEntryOf(t, store, source, harness.EntryInput, "op-1").ID f2 := newPublicFixture(t, store, newScriptModel(), nil) @@ -5945,17 +5895,7 @@ func TestPublicForkIndependentSourceDeletion(t *testing.T) { func TestPublicForkRollbackOnTransactionFailure(t *testing.T) { eachStore(t, func(t *testing.T, store harness.Storage) { ctx := context.Background() - script := newScriptModel() - f := newPublicFixture(t, store, script, nil) - defer f.close() - source := createSession(t, f.h) - if _, err := submit(t, f.h, source, "op-1", harness.MessageModeRegular, "hello"); err != nil { - t.Fatalf("first submit: %v", err) - } - <-script.arrived - if err := converge(t, f); err != nil { - t.Fatalf("Wait: %v", err) - } + source := seedIdleSource(t, store, "op-1") boundary := forkEntryOf(t, store, source, harness.EntryInput, "op-1").ID before := snapshotSession(t, store, source) From ea4a3c2fce4a3f622230a70bfa7ea739f0e870d5 Mon Sep 17 00:00:00 2001 From: MMinasyan Date: Mon, 19 Oct 2026 16:10:11 +0400 Subject: [PATCH 2/4] test(harness): share execution and lifecycle fixture construction --- harness/attempt_public_table_test.go | 12 ++------ harness/compact_manual_public_test.go | 9 +----- harness/effect_test.go | 42 ++++++++++++--------------- harness/observe_public_test.go | 9 ++---- harness/public_test.go | 41 +++++++++++--------------- harness/snapshot_public_test.go | 30 ++++++------------- 6 files changed, 52 insertions(+), 91 deletions(-) diff --git a/harness/attempt_public_table_test.go b/harness/attempt_public_table_test.go index ac4200f8..5ee6901e 100644 --- a/harness/attempt_public_table_test.go +++ b/harness/attempt_public_table_test.go @@ -44,15 +44,9 @@ func newAttemptTableFixture(t *testing.T, store harness.Storage, conversationFn, return harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: conversationFn, - CompactModel: compactFn, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} - }, - Retry: retry, - }, nil + exec := publicExecution(conversationFn, compactFn) + exec.Retry = retry + return exec, nil }, }, nil }}) diff --git a/harness/compact_manual_public_test.go b/harness/compact_manual_public_test.go index 97fe448c..ab08bf1e 100644 --- a/harness/compact_manual_public_test.go +++ b/harness/compact_manual_public_test.go @@ -48,14 +48,7 @@ func newCompactManualFixture(t *testing.T, store harness.Storage, conversation, f.defaultPrep = harness.PreparedExecution{ Capture: compactManualCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: conversation.effect, - CompactModel: compact.effect, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} - }, - }, nil + return publicExecution(conversation.effect, compact.effect), nil }, } ctx, cancel := context.WithCancel(context.Background()) diff --git a/harness/effect_test.go b/harness/effect_test.go index 68af3e70..333e782d 100644 --- a/harness/effect_test.go +++ b/harness/effect_test.go @@ -25,16 +25,18 @@ func executeDirect(h *Harness, c *coordinator, execCtx context.Context, operatio return h.finishExecution(c, run, operationID, res, err, closeExecution) } -// newEffectHarness admits one running Operation ("op-1") with the given -// prepared physical model request function and returns the pieces the effect -// fixtures need. -func newEffectHarness(t *testing.T, modelFn func(context.Context, model.Request) (model.Stream, error)) (*Harness, *graphStorage, *coordinator, string) { +// newAdmittedHarness admits one running Operation ("op-1") over a fresh empty +// store under the given Harness context and prepared execution: the shared +// admission construction of the effect and opener fixtures. +func newAdmittedHarness(t *testing.T, hctx context.Context, prepared PreparedExecution) (*Harness, *graphStorage, *coordinator, string) { t.Helper() store := emptyStore(t) - prepared := modelPrepared(modelFn) - h := newTestHarness(t, store, func(context.Context, PreparationRequest) (PreparedExecution, error) { + h, err := New(hctx, Dependencies{Storage: store, Prepare: func(context.Context, PreparationRequest) (PreparedExecution, error) { return prepared, nil - }) + }}) + if err != nil { + t.Fatalf("New: %v", err) + } session, err := h.CreateSession(context.Background(), CreateSessionRequest{Workspace: "/tmp/works", AgentType: "coder"}) if err != nil { t.Fatalf("CreateSession: %v", err) @@ -46,6 +48,14 @@ func newEffectHarness(t *testing.T, modelFn func(context.Context, model.Request) return h, store, c, session.Identity.SessionID } +// newEffectHarness admits one running Operation ("op-1") with the given +// prepared physical model request function and returns the pieces the effect +// fixtures need. +func newEffectHarness(t *testing.T, modelFn func(context.Context, model.Request) (model.Stream, error)) (*Harness, *graphStorage, *coordinator, string) { + t.Helper() + return newAdmittedHarness(t, context.Background(), modelPrepared(modelFn)) +} + // invokeModelEffect drives one model effect with a validated request; a nil // assemble callback runs the real Agent assembly. func invokeModelEffect(t *testing.T, me agent.ModelEffect, assemble agent.AssemblyCallback) (agent.ModelSettlement, error) { @@ -1004,24 +1014,10 @@ func (s *toolSpy) dispatched() []string { // pieces the execution fixtures need. func newOpenerHarness(t *testing.T, open func(context.Context, OperationAdmission) (Execution, error)) (*Harness, *graphStorage, *coordinator, string, PreparedExecution, context.CancelFunc) { t.Helper() - store := emptyStore(t) prepared := PreparedExecution{Capture: testCapture(), Open: open} hctx, cancel := context.WithCancel(context.Background()) - h, err := New(hctx, Dependencies{Storage: store, Prepare: func(context.Context, PreparationRequest) (PreparedExecution, error) { - return prepared, nil - }}) - if err != nil { - t.Fatalf("New: %v", err) - } - session, err := h.CreateSession(context.Background(), CreateSessionRequest{Workspace: "/tmp/works", AgentType: "coder"}) - if err != nil { - t.Fatalf("CreateSession: %v", err) - } - if _, disposition := mustAdmitWithoutExecution(t, h, session.Identity.SessionID, testOpID, admissionContent("hello")); disposition != DispositionAdmitted { - t.Fatalf("disposition %q, want admitted", disposition) - } - c := leaseCoordinator(t, h, session.Identity.SessionID) - return h, store, c, session.Identity.SessionID, prepared, cancel + h, store, c, sessionID := newAdmittedHarness(t, hctx, prepared) + return h, store, c, sessionID, prepared, cancel } // newExecutionHarness admits one running Operation ("op-1") under a cancelable diff --git a/harness/observe_public_test.go b/harness/observe_public_test.go index 03dd9e33..ab2c96b3 100644 --- a/harness/observe_public_test.go +++ b/harness/observe_public_test.go @@ -88,12 +88,9 @@ func newObservedPublicHarnessWithTool(t *testing.T, store harness.Storage, scrip return harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: script.effect, - CompactModel: script.effect, - NormalizeTool: publicNormalize, - Tool: tool, - }, nil + exec := publicExecution(script.effect, script.effect) + exec.Tool = tool + return exec, nil }, }, nil }, diff --git a/harness/public_test.go b/harness/public_test.go index e07d6ba0..18cf945b 100644 --- a/harness/public_test.go +++ b/harness/public_test.go @@ -65,6 +65,20 @@ func publicNormalize(call model.ToolCall) (json.RawMessage, error) { return json.Marshal(obj) } +// publicExecution is the suite's ordinary opened execution: the two actual +// model callbacks, the suite's required normalizer, and the immediate +// "no tools" result plan. +func publicExecution(conversation, compact func(context.Context, model.Request) (model.Stream, error)) harness.Execution { + return harness.Execution{ + Model: conversation, + CompactModel: compact, + NormalizeTool: publicNormalize, + Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { + return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} + }, + } +} + // publicPermission is one built-in-allowed declaration for the suite's // effect-producing fixture plans: command.run allows any target. var publicPermission = []harness.PermissionRequest{{Permission: "command.run", Target: "fixture"}} @@ -262,14 +276,7 @@ func newPublicFixtureWithJobs(t *testing.T, store harness.Storage, stopper harne prepared := harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: modelFn, - CompactModel: modelFn, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} - }, - }, nil + return publicExecution(modelFn, modelFn), nil }, } ctx, cancel := context.WithCancel(context.Background()) @@ -622,14 +629,7 @@ func scriptPrepared(script *scriptModel) harness.PreparedExecution { return harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: script.effect, - CompactModel: script.effect, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} - }, - }, nil + return publicExecution(script.effect, script.effect), nil }, } } @@ -5085,14 +5085,7 @@ func racePrepared(f *publicFixture) harness.PreparedExecution { Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { f.opens.Add(1) - return harness.Execution{ - Model: f.model.effect, - CompactModel: f.model.effect, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}}} - }, - }, nil + return publicExecution(f.model.effect, f.model.effect), nil }, } } diff --git a/harness/snapshot_public_test.go b/harness/snapshot_public_test.go index 8c7434a0..cfd52237 100644 --- a/harness/snapshot_public_test.go +++ b/harness/snapshot_public_test.go @@ -50,17 +50,14 @@ func snapshotTurnPrepared(script *scriptModel) harness.PreparedExecution { return harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: script.effect, - CompactModel: script.effect, - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Permissions: publicPermission, Immediate: &harness.ToolOutcome{ - Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: "ran call"}, - Metadata: json.RawMessage(`{"n":[1,1.0],"s":"<>&"}`), - }} - }, - }, nil + exec := publicExecution(script.effect, script.effect) + exec.Tool = func(_ context.Context, call model.ToolCall) harness.PreparedTool { + return harness.PreparedTool{Permissions: publicPermission, Immediate: &harness.ToolOutcome{ + Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: "ran call"}, + Metadata: json.RawMessage(`{"n":[1,1.0],"s":"<>&"}`), + }} + } + return exec, nil }, } } @@ -1046,16 +1043,7 @@ func backgroundPrepared(gate, arrived chan struct{}) harness.PreparedExecution { return harness.PreparedExecution{ Capture: publicCapture(), Open: func(context.Context, harness.OperationAdmission) (harness.Execution, error) { - return harness.Execution{ - Model: parkingModelFn(gate, arrived), - CompactModel: parkingModelFn(gate, arrived), - NormalizeTool: publicNormalize, - Tool: func(_ context.Context, call model.ToolCall) harness.PreparedTool { - return harness.PreparedTool{Immediate: &harness.ToolOutcome{ - Result: model.ToolResult{CallID: call.ID, Status: model.ResultError, Content: "no tools"}, - }} - }, - }, nil + return publicExecution(parkingModelFn(gate, arrived), parkingModelFn(gate, arrived)), nil }, } } From 3a7de0709c4375aea8047ced0d34d1c59a16bba3 Mon Sep 17 00:00:00 2001 From: MMinasyan Date: Mon, 19 Oct 2026 16:50:47 +0400 Subject: [PATCH 3/4] test(runtime): consolidate configuration and protocol scenarios --- runtime/configuration_connection_test.go | 547 ++++++++++------------- runtime/configuration_metadata_test.go | 86 +--- runtime/protocol_conversation_test.go | 89 ++-- runtime/protocol_paging_test.go | 85 +--- 4 files changed, 316 insertions(+), 491 deletions(-) diff --git a/runtime/configuration_connection_test.go b/runtime/configuration_connection_test.go index 0c261523..36958020 100644 --- a/runtime/configuration_connection_test.go +++ b/runtime/configuration_connection_test.go @@ -1362,77 +1362,74 @@ func TestConnectProviderOwnerCloseDuringFetchRefuses(t *testing.T) { }) } -// TestDisconnectProviderUnusableRemovesManagedKey is the nearest forbidden -// sibling of the connect usability rule: an unusable provider (the -// windowless discovery-backed discp) still disconnects, removing its managed -// key through the ready-publication path over untouched bytes. -func TestDisconnectProviderUnusableRemovesManagedKey(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - if err := r.managedEnv.TrySet("CONNECTION_DISC_KEY", "managed-secret"); err != nil { - t.Fatalf("seed TrySet: %v", err) - } - before, _, _ := runtimeMutationBaseline(t, r) - - mutation, err := r.disconnectProvider(ctx, "discp") - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("unusable disconnect = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if os.Getenv("CONNECTION_DISC_KEY") != "" || r.managedEnv.IsManaged("CONNECTION_DISC_KEY") { - t.Fatal("the managed key survived the unusable provider's disconnect") - } - after, rerr := os.ReadFile(r.config.configPath) - if rerr != nil || string(after) != string(before) { - t.Fatalf("disconnect changed the owning config (%v)", rerr) - } - }) -} - -func TestDisconnectProviderManagedKey(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - if err := r.managedEnv.TrySet("CONNECTION_USABLE_KEY", "managed-secret"); err != nil { - t.Fatalf("seed TrySet: %v", err) - } - before, _, _ := runtimeMutationBaseline(t, r) +// TestDisconnectProviderManagedKeyTable pins the disconnect's managed-key +// removal on both provider shapes. The unusable row is the nearest forbidden +// sibling of the connect usability rule: the windowless discovery-backed +// discp still disconnects, removing its managed key through the +// ready-publication path over untouched bytes. The usable row additionally +// pins the disconnected view — no key source, not connected — and its +// removed .env line. +func TestDisconnectProviderManagedKeyTable(t *testing.T) { + rows := []struct { + name string + providerID string + envName string + seed string + check func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) + }{ + { + name: "TestDisconnectProviderUnusableRemovesManagedKey", providerID: "discp", + envName: "CONNECTION_DISC_KEY", seed: "managed-secret", + }, + { + name: "TestDisconnectProviderManagedKey", providerID: "usablep", + envName: "CONNECTION_USABLE_KEY", seed: "managed-secret", + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { + if mutation.Result.Connected || mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceNone) { + t.Fatalf("disconnected provider view = %+v, want the disconnected status", mutation.Result) + } + envData, err := os.ReadFile(r.managedEnv.Path()) + if err != nil || strings.Contains(string(envData), "CONNECTION_USABLE_KEY=") { + t.Fatalf(".env after disconnect = (%q, %v), want the line removed", envData, err) + } + }, + }, + } + for _, row := range rows { + t.Run(row.name, func(t *testing.T) { + eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { + server := newConnectionDiscoveryServer(t, connectionFullDiscovery) + r, _ := openConnectionRuntime(t, store, server.URL) + defer closeProjectionRuntime(r) + ctx := context.Background() + sub, err := r.Subscribe(8) + if err != nil { + t.Fatalf("Subscribe: %v", err) + } + defer sub.Close() + if err := r.managedEnv.TrySet(row.envName, row.seed); err != nil { + t.Fatalf("seed TrySet: %v", err) + } + before, _, _ := runtimeMutationBaseline(t, r) - mutation, err := r.disconnectProvider(ctx, "usablep") - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("disconnectProvider = (%v, %+v), want generation 2", err, mutation) - } - if mutation.Result.Connected || mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceNone) { - t.Fatalf("disconnected provider view = %+v, want the disconnected status", mutation.Result) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if os.Getenv("CONNECTION_USABLE_KEY") != "" || r.managedEnv.IsManaged("CONNECTION_USABLE_KEY") { - t.Fatal("the managed key survived the disconnect") - } - envData, err := os.ReadFile(r.managedEnv.Path()) - if err != nil || strings.Contains(string(envData), "CONNECTION_USABLE_KEY=") { - t.Fatalf(".env after disconnect = (%q, %v), want the line removed", envData, err) - } - after, err := os.ReadFile(r.config.configPath) - if err != nil || string(after) != string(before) { - t.Fatalf("disconnect changed the owning config (%v)", err) - } - }) + mutation, err := r.disconnectProvider(ctx, row.providerID) + if err != nil || mutation.ConfigurationRevision.Generation != "2" { + t.Fatalf("disconnectProvider = (%v, %+v), want generation 2", err, mutation) + } + drainConnectionEvent(t, r.warnings, sub, "2") + if os.Getenv(row.envName) != "" || r.managedEnv.IsManaged(row.envName) { + t.Fatal("the managed key survived the disconnect") + } + after, rerr := os.ReadFile(r.config.configPath) + if rerr != nil || string(after) != string(before) { + t.Fatalf("disconnect changed the owning config (%v)", rerr) + } + if row.check != nil { + row.check(t, r, mutation) + } + }) + }) + } } // awaitStackMatch polls the process stacks until one stack satisfies match, @@ -2062,169 +2059,171 @@ func TestCreateProviderExplicitEmptyEnvKeylessRefuses(t *testing.T) { }) } -// TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites pins the -// supplied-key rule: an explicitly named externally defined variable refuses -// the create before any configuration or cache side effect, leaving its -// value intact — it is not silently substituted for the supplied key. -func TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_SHELL_KEY") - t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") - envBefore, err := os.ReadFile(r.managedEnv.Path()) - if err != nil { - t.Fatalf("read .env: %v", err) - } - before, generation, warnRev := runtimeMutationBaseline(t, r) - - key := connectionKey - window := 4096 - baseURL := "https://new.test/v1" - shellEnv := "CONNECTION_SHELL_KEY" - _, err = r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &shellEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, &key) - // The refusal oracle already pins the owning file, generation, - // warnings, and events; the external sibling and the .env silence are - // this row's own axes. - assertRuntimeMutationRefused(t, r, sub, before, generation, warnRev, err, ErrConfiguration) - if os.Getenv("CONNECTION_SHELL_KEY") != "shell-exported-value" || r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { - t.Fatalf("external sibling state = (%q, %v), want it untouched and unmanaged", os.Getenv("CONNECTION_SHELL_KEY"), r.managedEnv.IsManaged("CONNECTION_SHELL_KEY")) - } - assertDotenvUnchanged(t, r, envBefore, "the external-sibling create") - }) -} - -// TestCreateProviderManagedOrphanKeyUpdatedBySuppliedValue is the create-side -// ownership regression: a managed orphan name — Lightcode owns it, no -// provider references it — must be updated by a supplied nonempty value -// instead of being mistaken for a shell key and having the replacement -// discarded. The exact value reaches only the .env and never a response byte. -func TestCreateProviderManagedOrphanKeyUpdatedBySuppliedValue(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_ORPHAN_KEY") - if err := r.managedEnv.TrySet("CONNECTION_ORPHAN_KEY", "stale-managed-value"); err != nil { - t.Fatalf("seed managed orphan: %v", err) - } - - key := "sk-live-orphan-replacement" - window := 4096 - baseURL := "https://new.test/v1" - orphanEnv := "CONNECTION_ORPHAN_KEY" - mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &orphanEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, &key) - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("managed-orphan create = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if os.Getenv("CONNECTION_ORPHAN_KEY") != key || !r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY") { - t.Fatalf("managed orphan state = (%q, %v), want the supplied replacement", os.Getenv("CONNECTION_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY")) - } - envData, rerr := os.ReadFile(r.managedEnv.Path()) - if rerr != nil || !strings.Contains(string(envData), "CONNECTION_ORPHAN_KEY="+key+"\n") || strings.Contains(string(envData), "stale-managed-value") { - t.Fatalf(".env = (%q, %v), want the replacement line only", envData, rerr) - } - raw, rerr := os.ReadFile(r.config.configPath) - if rerr != nil || !strings.Contains(string(raw), `"api_key_env": "CONNECTION_ORPHAN_KEY"`) || strings.Contains(string(raw), key) { - t.Fatalf("raw config = (%q, %v), want the name only and never the value", raw, rerr) - } - mutBytes, merr := json.Marshal(mutation) - if merr != nil || strings.Contains(string(mutBytes), key) { - t.Fatalf("mutation bytes carry the key value (%v)", merr) - } - }) -} - -// TestCreateProviderManagedEmptyKeyFilledBySuppliedValue pins the -// managed-empty union: Lightcode owns the name with no value, and a supplied -// nonempty value fills it instead of tripping the external-empty refusal. -func TestCreateProviderManagedEmptyKeyFilledBySuppliedValue(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_EMPTY_ORPHAN_KEY") - if err := r.managedEnv.TrySet("CONNECTION_EMPTY_ORPHAN_KEY", ""); err != nil { - t.Fatalf("seed managed-empty name: %v", err) - } - - key := "sk-live-empty-orphan-replacement" - window := 4096 - baseURL := "https://new.test/v1" - emptyEnv := "CONNECTION_EMPTY_ORPHAN_KEY" - if _, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &emptyEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, &key); err != nil { - t.Fatalf("managed-empty create = %v, want the supplied value to fill the managed name", err) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY") != key || !r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY") { - t.Fatalf("managed-empty state = (%q, %v), want the supplied value", os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY")) - } - }) -} - -// TestCreateProviderManagedNameWithoutSuppliedKeyUsesExisting pins the -// no-supplied-value union: an existing nonempty managed value is used as-is -// and the create publishes without a key write. -func TestCreateProviderManagedNameWithoutSuppliedKeyUsesExisting(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_EXISTING_KEY") - if err := r.managedEnv.TrySet("CONNECTION_EXISTING_KEY", "existing-managed-value"); err != nil { - t.Fatalf("seed managed name: %v", err) - } - envBefore, err := os.ReadFile(r.managedEnv.Path()) - if err != nil { - t.Fatalf("read .env: %v", err) - } - - window := 4096 - baseURL := "https://new.test/v1" - existingEnv := "CONNECTION_EXISTING_KEY" - mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &existingEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, nil) - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("managed-existing create = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceManaged) { - t.Fatalf("created provider key source = %q, want managed", mutation.Result.KeySource) - } - if os.Getenv("CONNECTION_EXISTING_KEY") != "existing-managed-value" || !r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY") { - t.Fatalf("managed value changed without a supplied key: (%q, %v)", os.Getenv("CONNECTION_EXISTING_KEY"), r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY")) - } - assertDotenvUnchanged(t, r, envBefore, "the create without a supplied key") - }) +// TestCreateProviderKeySourceTable pins the ordinary provider-create +// key-source unions over the connection fixture. The external-binding row +// with a supplied key refuses the create before any configuration or cache +// side effect, leaving the explicitly named externally defined variable +// intact — it is not silently substituted for the supplied key. The +// managed-orphan row updates a managed orphan name by the supplied nonempty +// value; the managed-empty row fills a managed empty name instead of +// tripping the external-empty refusal; the existing-managed row uses an +// existing nonempty managed value as-is without a key write; the +// external-binding row without a supplied key registers as-is and stays +// external; and the missing-key row performs no credential action and no +// resolution refusal. +func TestCreateProviderKeySourceTable(t *testing.T) { + rows := []struct { + name string + envName string + key *string + arrange func(t *testing.T, r *Runtime) + refuse error + check func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) + }{ + { + name: "TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites", envName: "CONNECTION_SHELL_KEY", + key: ptrTo(connectionKey), refuse: ErrConfiguration, + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_SHELL_KEY") + t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if os.Getenv("CONNECTION_SHELL_KEY") != "shell-exported-value" || r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { + t.Fatalf("external sibling state = (%q, %v), want it untouched and unmanaged", os.Getenv("CONNECTION_SHELL_KEY"), r.managedEnv.IsManaged("CONNECTION_SHELL_KEY")) + } + assertDotenvUnchanged(t, r, envBefore, "the external-sibling create") + }, + }, + { + name: "TestCreateProviderManagedOrphanKeyUpdatedBySuppliedValue", envName: "CONNECTION_ORPHAN_KEY", + key: ptrTo("sk-live-orphan-replacement"), + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_ORPHAN_KEY") + if err := r.managedEnv.TrySet("CONNECTION_ORPHAN_KEY", "stale-managed-value"); err != nil { + t.Fatalf("seed managed orphan: %v", err) + } + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if os.Getenv("CONNECTION_ORPHAN_KEY") != *key || !r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY") { + t.Fatalf("managed orphan state = (%q, %v), want the supplied replacement", os.Getenv("CONNECTION_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY")) + } + envData, rerr := os.ReadFile(r.managedEnv.Path()) + if rerr != nil || !strings.Contains(string(envData), "CONNECTION_ORPHAN_KEY="+*key+"\n") || strings.Contains(string(envData), "stale-managed-value") { + t.Fatalf(".env = (%q, %v), want the replacement line only", envData, rerr) + } + raw, rerr := os.ReadFile(r.config.configPath) + if rerr != nil || !strings.Contains(string(raw), `"api_key_env": "CONNECTION_ORPHAN_KEY"`) || strings.Contains(string(raw), *key) { + t.Fatalf("raw config = (%q, %v), want the name only and never the value", raw, rerr) + } + mutBytes, merr := json.Marshal(mutation) + if merr != nil || strings.Contains(string(mutBytes), *key) { + t.Fatalf("mutation bytes carry the key value (%v)", merr) + } + }, + }, + { + name: "TestCreateProviderManagedEmptyKeyFilledBySuppliedValue", envName: "CONNECTION_EMPTY_ORPHAN_KEY", + key: ptrTo("sk-live-empty-orphan-replacement"), + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_EMPTY_ORPHAN_KEY") + if err := r.managedEnv.TrySet("CONNECTION_EMPTY_ORPHAN_KEY", ""); err != nil { + t.Fatalf("seed managed-empty name: %v", err) + } + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY") != *key || !r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY") { + t.Fatalf("managed-empty state = (%q, %v), want the supplied value", os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY")) + } + }, + }, + { + name: "TestCreateProviderManagedNameWithoutSuppliedKeyUsesExisting", envName: "CONNECTION_EXISTING_KEY", + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_EXISTING_KEY") + if err := r.managedEnv.TrySet("CONNECTION_EXISTING_KEY", "existing-managed-value"); err != nil { + t.Fatalf("seed managed name: %v", err) + } + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceManaged) { + t.Fatalf("created provider key source = %q, want managed", mutation.Result.KeySource) + } + if os.Getenv("CONNECTION_EXISTING_KEY") != "existing-managed-value" || !r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY") { + t.Fatalf("managed value changed without a supplied key: (%q, %v)", os.Getenv("CONNECTION_EXISTING_KEY"), r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY")) + } + assertDotenvUnchanged(t, r, envBefore, "the create without a supplied key") + }, + }, + { + name: "TestCreateProviderExternalBindingWithoutKeyRegisters", envName: "CONNECTION_SHELL_KEY", + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_SHELL_KEY") + t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceExternal) { + t.Fatalf("created provider key source = %q, want external", mutation.Result.KeySource) + } + assertDotenvUnchanged(t, r, envBefore, "the no-key create") + if r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { + t.Fatal("the no-key create managed the external variable") + } + }, + }, + { + name: "TestCreateProviderMissingKeyRegistersNoAction", envName: "CONNECTION_MISSING_KEY", + arrange: func(t *testing.T, r *Runtime) { + reserveEnvKey(t, "CONNECTION_MISSING_KEY") + }, + check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceNone) || mutation.Result.ApiKeyEnv != "CONNECTION_MISSING_KEY" { + t.Fatalf("created provider = (%q, %q), want the none source with the named binding", mutation.Result.KeySource, mutation.Result.ApiKeyEnv) + } + assertDotenvUnchanged(t, r, envBefore, "the absent-binding create") + if _, present := metadataRawProvider(t, e.configPath, "newp")["transport"]; !present { + t.Fatal("the created provider missing from the raw layer") + } + }, + }, + } + for _, row := range rows { + t.Run(row.name, func(t *testing.T) { + eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { + server := newConnectionDiscoveryServer(t, connectionFullDiscovery) + r, e := openConnectionRuntime(t, store, server.URL) + defer closeProjectionRuntime(r) + ctx := context.Background() + sub, err := r.Subscribe(8) + if err != nil { + t.Fatalf("Subscribe: %v", err) + } + defer sub.Close() + row.arrange(t, r) + envBefore, err := os.ReadFile(r.managedEnv.Path()) + if err != nil { + t.Fatalf("read .env: %v", err) + } + before, generation, warnRev := runtimeMutationBaseline(t, r) + + window := 4096 + baseURL := "https://new.test/v1" + mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &row.envName}, + map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, row.key) + // The refusal oracle already pins the owning file, generation, + // warnings, and events; the success rows share the one + // generation-2 publication rule. + if row.refuse != nil { + assertRuntimeMutationRefused(t, r, sub, before, generation, warnRev, err, row.refuse) + } else { + if err != nil || mutation.ConfigurationRevision.Generation != "2" { + t.Fatalf("key-source create = (%v, %+v), want generation 2", err, mutation) + } + drainConnectionEvent(t, r.warnings, sub, "2") + } + row.check(t, r, e, mutation, row.key, envBefore) + }) + }) + } } // TestCreateProviderGeneratedNameSkipsOccupiedNames pins the allocation @@ -2334,88 +2333,6 @@ func TestCreateProviderGeneratedNameSkipsOccupiedNames(t *testing.T) { }) } -// TestCreateProviderExternalBindingWithoutKeyRegisters pins the no-supplied -// key sibling of the allocation rule: an external shell key's variable is -// occupied for allocation, but a create without a supplied key performs no -// credential action at all — the binding registers as-is and stays external. -func TestCreateProviderExternalBindingWithoutKeyRegisters(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, _ := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_SHELL_KEY") - t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") - envBefore, err := os.ReadFile(r.managedEnv.Path()) - if err != nil { - t.Fatalf("read .env: %v", err) - } - - window := 4096 - baseURL := "https://new.test/v1" - shellEnv := "CONNECTION_SHELL_KEY" - mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &shellEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, nil) - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("no-key external-binding create = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceExternal) { - t.Fatalf("created provider key source = %q, want external", mutation.Result.KeySource) - } - assertDotenvUnchanged(t, r, envBefore, "the no-key create") - if r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { - t.Fatal("the no-key create managed the external variable") - } - }) -} - -// TestCreateProviderMissingKeyRegistersNoAction pins the clarification's -// headline: a create whose configured binding is absent performs no -// credential action and no resolution refusal — the disconnected valid -// registration is representable, and the named binding lands in the raw -// transport and in the result. -func TestCreateProviderMissingKeyRegistersNoAction(t *testing.T) { - eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { - server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, e := openConnectionRuntime(t, store, server.URL) - defer closeProjectionRuntime(r) - ctx := context.Background() - sub, err := r.Subscribe(8) - if err != nil { - t.Fatalf("Subscribe: %v", err) - } - defer sub.Close() - reserveEnvKey(t, "CONNECTION_MISSING_KEY") - envBefore, err := os.ReadFile(r.managedEnv.Path()) - if err != nil { - t.Fatalf("read .env: %v", err) - } - - window := 4096 - baseURL := "https://new.test/v1" - missingEnv := "CONNECTION_MISSING_KEY" - mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &missingEnv}, - map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, nil) - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("absent-binding create = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") - if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceNone) || mutation.Result.ApiKeyEnv != missingEnv { - t.Fatalf("created provider = (%q, %q), want the none source with the named binding", mutation.Result.KeySource, mutation.Result.ApiKeyEnv) - } - assertDotenvUnchanged(t, r, envBefore, "the absent-binding create") - if _, present := metadataRawProvider(t, e.configPath, "newp")["transport"]; !present { - t.Fatal("the created provider missing from the raw layer") - } - }) -} - func TestCreateProviderInvalidCandidateNoWrites(t *testing.T) { eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { server := newConnectionDiscoveryServer(t, connectionFullDiscovery) diff --git a/runtime/configuration_metadata_test.go b/runtime/configuration_metadata_test.go index efe1fca1..853f1531 100644 --- a/runtime/configuration_metadata_test.go +++ b/runtime/configuration_metadata_test.go @@ -307,16 +307,13 @@ func TestMetadataEditCreateCustomProvider(t *testing.T) { t.Fatalf("empty-headers create: %v", err) } drainMutationEvent(t, sub, "3") - var rawProviders map[string]map[string]json.RawMessage - if err := json.Unmarshal(fileRoot(t, h.configPath)["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } + createdProvider := metadataRawProvider(t, h.configPath, "noheaders") var createdTransport map[string]json.RawMessage - if err := json.Unmarshal(rawProviders["noheaders"]["transport"], &createdTransport); err != nil { + if err := json.Unmarshal(createdProvider["transport"], &createdTransport); err != nil { t.Fatalf("decode created transport: %v", err) } if _, present := createdTransport["headers"]; present { - t.Fatalf("created transport = %s, want the empty provided headers member absent", rawProviders["noheaders"]["transport"]) + t.Fatalf("created transport = %s, want the empty provided headers member absent", createdProvider["transport"]) } } @@ -421,11 +418,7 @@ func TestMetadataEditCreateRegistersIncompleteMetadata(t *testing.T) { var transport struct { APIKeyEnv string `json:"api_key_env"` } - var rawProviders map[string]map[string]json.RawMessage - if err := json.Unmarshal(fileRoot(t, h.configPath)["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } - if err := json.Unmarshal(rawProviders[row.id]["transport"], &transport); err != nil { + if err := json.Unmarshal(metadataRawProvider(t, h.configPath, row.id)["transport"], &transport); err != nil { t.Fatalf("decode created transport: %v", err) } wantEnv := "" @@ -524,17 +517,13 @@ func TestMetadataEditUpdateCustomProviderPatchSemantics(t *testing.T) { t.Fatalf("empty headers patch: %v", err) } drainMutationEvent(t, sub, "4") - root := fileRoot(t, h.configPath) + rawProvider := metadataRawProvider(t, h.configPath, "prov") var transport map[string]json.RawMessage - var rawProviders map[string]map[string]json.RawMessage - if err := json.Unmarshal(root["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } - if err := json.Unmarshal(rawProviders["prov"]["transport"], &transport); err != nil { + if err := json.Unmarshal(rawProvider["transport"], &transport); err != nil { t.Fatalf("decode transport: %v", err) } if _, present := transport["headers"]; present { - t.Fatalf("raw transport = %s, want the headers member deleted", rawProviders["prov"]["transport"]) + t.Fatalf("raw transport = %s, want the headers member deleted", rawProvider["transport"]) } // The wholesale header replacement: a provided map replaces the whole @@ -544,11 +533,9 @@ func TestMetadataEditUpdateCustomProviderPatchSemantics(t *testing.T) { t.Fatalf("wholesale headers patch: %v", err) } drainMutationEvent(t, sub, "5") - if err := json.Unmarshal(fileRoot(t, h.configPath)["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } transport = nil - if err := json.Unmarshal(rawProviders["prov"]["transport"], &transport); err != nil { + rawProvider = metadataRawProvider(t, h.configPath, "prov") + if err := json.Unmarshal(rawProvider["transport"], &transport); err != nil { t.Fatalf("decode transport: %v", err) } var headersMember map[string]string @@ -915,17 +902,9 @@ func TestMetadataEditResetProviderFields(t *testing.T) { } generation++ drainMutationEvent(t, sub, strconv.Itoa(generation)) - root := fileRoot(t, h.configPath) - var prov map[string]json.RawMessage - var providers map[string]json.RawMessage - if err := json.Unmarshal(root["providers"], &providers); err != nil { - t.Fatalf("decode providers: %v", err) - } - if err := json.Unmarshal(providers["prov"], &prov); err != nil { - t.Fatalf("decode prov: %v", err) - } + prov := metadataRawProvider(t, h.configPath, "prov") if _, present := prov[string(field)]; present { - t.Fatalf("reset %q left the raw override: %s", field, providers["prov"]) + t.Fatalf("reset %q left the raw override: %s", field, prov) } } @@ -938,17 +917,13 @@ func TestMetadataEditResetProviderFields(t *testing.T) { } generation++ drainMutationEvent(t, sub, strconv.Itoa(generation)) - root := fileRoot(t, h.configPath) - var rawProviders map[string]map[string]json.RawMessage - if err := json.Unmarshal(root["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } + rawProvider := metadataRawProvider(t, h.configPath, "prov") var transport map[string]json.RawMessage - if err := json.Unmarshal(rawProviders["prov"]["transport"], &transport); err != nil { + if err := json.Unmarshal(rawProvider["transport"], &transport); err != nil { t.Fatalf("decode transport: %v", err) } if _, present := transport[string(field)]; present { - t.Fatalf("reset %q left the raw transport override: %s", field, rawProviders["prov"]["transport"]) + t.Fatalf("reset %q left the raw transport override: %s", field, rawProvider["transport"]) } } @@ -1285,11 +1260,7 @@ func TestMetadataEditModelDelete(t *testing.T) { // owning file and publishes the next generation under the one shared // successful-edit rule. func TestMetadataEditResetModelFields(t *testing.T) { - h := newMetadataHarness(t) - unsetenv(t, "DISCO_TEST_KEY") // never ready: no network anywhere below - seedDiscoveredModel(t, h) - writeServiceFile(t, h.configPath, metadataConfigDocument) - svc, sub := metadataService(t, h) + h, svc, sub := newOverlayFixture(t) // The user-model context_window reset lands: removing the sole window // leaves a valid incomplete model that cannot make a new admission @@ -1341,13 +1312,8 @@ func TestMetadataEditResetModelFields(t *testing.T) { } generation++ drainMutationEvent(t, sub, strconv.Itoa(generation)) - root := fileRoot(t, h.configPath) - var rawProviders map[string]map[string]json.RawMessage - if err := json.Unmarshal(root["providers"], &rawProviders); err != nil { - t.Fatalf("decode providers: %v", err) - } var rawModels map[string]json.RawMessage - if err := json.Unmarshal(rawProviders["prov"]["models"], &rawModels); err != nil { + if err := json.Unmarshal(metadataRawProvider(t, h.configPath, "prov")["models"], &rawModels); err != nil { t.Fatalf("decode models: %v", err) } var rawModel map[string]json.RawMessage @@ -1434,11 +1400,7 @@ func seedDiscoveredModel(t *testing.T, h *serviceHarness) { // identity members are locked and which is not deletable, while its // correctable members land and its overrides reset to the discovered value. func TestMetadataEditDiscoveredModelSource(t *testing.T) { - h := newMetadataHarness(t) - unsetenv(t, "DISCO_TEST_KEY") // never ready: no network anywhere below - seedDiscoveredModel(t, h) - writeServiceFile(t, h.configPath, metadataConfigDocument) - svc, sub := metadataService(t, h) + _, svc, sub := newOverlayFixture(t) entry := svc.current().catalog.Providers["disco"].Models["disc-model"] if entry == nil || entry.Source != catalog.SourceDiscovered { @@ -1885,11 +1847,7 @@ func metadataRawModel(t *testing.T, configPath, providerID, modelID string) map[ // stays invalid. The connected keyless provider's model leaves and rejoins // the visible picker while staying in the full list. func TestMetadataEditHiddenVisibility(t *testing.T) { - h := newMetadataHarness(t) - unsetenv(t, "DISCO_TEST_KEY") // never ready: no network anywhere below - seedDiscoveredModel(t, h) - writeServiceFile(t, h.configPath, metadataConfigDocument) - svc, sub := metadataService(t, h) + h, svc, sub := newOverlayFixture(t) // Provider custom + builtin, TRUE and FALSE: every completed synchronous // mutation publishes exactly its own generation's event and nothing is @@ -2247,10 +2205,10 @@ func TestRuntimeMetadataCorruptRawTypesTypedFailure(t *testing.T) { // --- supplied field values: exact truth and file/API equality --- -// newOverlayFixture seeds one identically configured service over the -// metadata fixture and its discovered record, so one instance can receive -// an overlay through the edit API and the other through a hand-edited file -// plus reload over the same input. +// newOverlayFixture seeds the metadata fixture with its discovered record and +// publishes one identically configured service: the metadata document, the +// bundled disco record, and the subscribed service with its attached warning +// store. func newOverlayFixture(t *testing.T) (*serviceHarness, *configurationService, *Subscription) { t.Helper() h := newMetadataHarness(t) diff --git a/runtime/protocol_conversation_test.go b/runtime/protocol_conversation_test.go index cf77bc79..3a55881d 100644 --- a/runtime/protocol_conversation_test.go +++ b/runtime/protocol_conversation_test.go @@ -718,25 +718,6 @@ func TestConversationProjectionToolCallLifecycle(t *testing.T) { }) } -// awaitArrival waits for the scripted model function's attempt counter to -// reach want: the barrier proving every earlier effect committed. -func awaitArrival(t *testing.T, arrivals <-chan int, want int, name string) { - t.Helper() - deadline := time.After(10 * time.Second) - last := 0 - for { - select { - case attempt := <-arrivals: - last = attempt - if attempt >= want { - return - } - case <-deadline: - t.Fatalf("%s never arrived (last attempt %d)", name, last) - } - } -} - // projectSessionItems reads one Session through the Runtime and projects its // complete conversation. func projectSessionItems(t *testing.T, r *Runtime, sessionID string) []protocol.ConversationItem { @@ -859,6 +840,47 @@ func TestConversationProjectionSyntheticToolResult(t *testing.T) { }) } +// twoReadCallTurnEvents returns the two-call assistant turn shared by the +// interrupted projection and the paging attachment rows: one assistant turn +// publishing read calls call-1 and call-2 indivisibly. +func twoReadCallTurnEvents() []string { + return []string{ + `{"choices":[{"delta":{"role":"assistant","tool_calls":[{"index":0,"id":"call-1","type":"function","function":{"name":"read","arguments":"{}"}},{"index":1,"id":"call-2","type":"function","function":{"name":"read","arguments":"{}"}}]},"finish_reason":null}]}`, + `{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}`, + } +} + +// parkedReadCallPrepare builds the prepared-tool callback shared by the +// interrupted projection and the paging attachment rows: the started call-1 +// parks its execution until the release channel or the run's cancellation +// releases it — the returned real outcome wins the cancellation race — while +// every other call settles immediately. +func parkedReadCallPrepare(releaseTool <-chan struct{}, toolStarted chan<- struct{}) func(context.Context, model.ToolCall) harness.PreparedTool { + return func(_ context.Context, call model.ToolCall) harness.PreparedTool { + if call.ID != "call-1" { + return harness.PreparedTool{ + Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, + Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: call.ID + " ran"}}, + } + } + return harness.PreparedTool{ + Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, + Execute: func(execCtx context.Context) harness.ToolOutcome { + select { + case toolStarted <- struct{}{}: + default: + } + select { + case <-releaseTool: // never released on the main path + case <-execCtx.Done(): // the interrupt releases the started call + } + // A returned real outcome wins the cancellation race. + return harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: "first ran"}} + }, + } + } +} + // TestConversationProjectionSyntheticInterruptedResult proves, over real // facts, the interrupted synthetic terminal result: an unstarted published // call's reserved identity receives the fixed interrupted outcome — present @@ -879,37 +901,12 @@ func TestConversationProjectionSyntheticInterruptedResult(t *testing.T) { if lastMessageRole(body) == "tool" { return textTurnEvents("never reached") } - return []string{ - `{"choices":[{"delta":{"role":"assistant","tool_calls":[{"index":0,"id":"call-1","type":"function","function":{"name":"read","arguments":"{}"}},{"index":1,"id":"call-2","type":"function","function":{"name":"read","arguments":"{}"}}]},"finish_reason":null}]}`, - `{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}`, - } + return twoReadCallTurnEvents() }) // The started call parks its execution until the run's cancellation // releases it and returns its real outcome; the unstarted call never // begins. - bg.tools.setPrepare(func(_ context.Context, call model.ToolCall) harness.PreparedTool { - if call.ID != "call-1" { - return harness.PreparedTool{ - Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, - Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: call.ID + " ran"}}, - } - } - return harness.PreparedTool{ - Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, - Execute: func(execCtx context.Context) harness.ToolOutcome { - select { - case toolStarted <- struct{}{}: - default: - } - select { - case <-releaseTool: // never released on the main path - case <-execCtx.Done(): // the interrupt releases the started call - } - // A returned real outcome wins the cancellation race. - return harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: "first ran"}} - }, - } - }) + bg.tools.setPrepare(parkedReadCallPrepare(releaseTool, toolStarted)) submitThroughRuntime(t, bg.r, session, "op-1", "work") select { case <-toolStarted: diff --git a/runtime/protocol_paging_test.go b/runtime/protocol_paging_test.go index 27ab1ca5..b368730d 100644 --- a/runtime/protocol_paging_test.go +++ b/runtime/protocol_paging_test.go @@ -627,6 +627,19 @@ func TestHistoryPagingAppendStableAnchors(t *testing.T) { }) } +// sessionReadCalls builds the four independent reads of one Session over one +// owner — the page, the hydration, and the two history-error probes — each +// invoked with the caller's own context, so archived, deleted, closed, and +// canceled callers share the same read set. +func sessionReadCalls(ctx context.Context, r *Runtime, sessionID string) []func() error { + return []func() error{ + func() error { _, err := r.getHistory(ctx, sessionID, nil); return err }, + func() error { _, err := r.buildHydration(ctx, sessionID); return err }, + func() error { return headerErrorThroughRuntime(ctx, r, sessionID) }, + func() error { return historyErrorThroughRuntime(ctx, r, sessionID) }, + } +} + // TestHistoryReadsArchivedDeletedSessions proves archived Sessions stay // fully readable and deleted Sessions fail every read with the typed // not-found. @@ -652,31 +665,13 @@ func TestHistoryReadsArchivedDeletedSessions(t *testing.T) { t.Fatalf("DeleteSession: %v", err) } - archivedReads := []func() error{ - func() error { _, err := r.getHistory(context.Background(), archived, nil); return err }, - func() error { _, err := r.buildHydration(context.Background(), archived); return err }, - func() error { - return headerErrorThroughRuntime(context.Background(), r, archived) - }, - func() error { - return historyErrorThroughRuntime(context.Background(), r, archived) - }, - } + archivedReads := sessionReadCalls(context.Background(), r, archived) for i, read := range archivedReads { if err := read(); err != nil { t.Fatalf("archived read %d: %v", i, err) } } - deletedReads := []func() error{ - func() error { _, err := r.getHistory(context.Background(), deleted, nil); return err }, - func() error { _, err := r.buildHydration(context.Background(), deleted); return err }, - func() error { - return headerErrorThroughRuntime(context.Background(), r, deleted) - }, - func() error { - return historyErrorThroughRuntime(context.Background(), r, deleted) - }, - } + deletedReads := sessionReadCalls(context.Background(), r, deleted) for i, read := range deletedReads { if err := read(); !errors.Is(err, harness.ErrNotFound) { t.Fatalf("deleted read %d = %v, want harness.ErrNotFound", i, err) @@ -954,35 +949,11 @@ func TestHistoryPageAttachesResultsBeyondTheBaseRange(t *testing.T) { defer releaseToolOnce() toolStarted := make(chan struct{}, 1) bg.e.server.setScript(func(_ context.Context, body string) []string { - return []string{ - `{"choices":[{"delta":{"role":"assistant","tool_calls":[{"index":0,"id":"call-1","type":"function","function":{"name":"read","arguments":"{}"}},{"index":1,"id":"call-2","type":"function","function":{"name":"read","arguments":"{}"}}]},"finish_reason":null}]}`, - `{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}`, - } + return twoReadCallTurnEvents() }) // The started call parks until the run's cancellation releases it; the // unstarted call never begins and settles synthetically. - bg.tools.setPrepare(func(_ context.Context, call model.ToolCall) harness.PreparedTool { - if call.ID != "call-1" { - return harness.PreparedTool{ - Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, - Immediate: &harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: call.ID + " ran"}}, - } - } - return harness.PreparedTool{ - Permissions: []harness.PermissionRequest{{Permission: "command.run", Target: "test"}}, - Execute: func(execCtx context.Context) harness.ToolOutcome { - select { - case toolStarted <- struct{}{}: - default: - } - select { - case <-releaseTool: - case <-execCtx.Done(): // the interrupt releases the started call - } - return harness.ToolOutcome{Result: model.ToolResult{CallID: call.ID, Status: model.ResultSuccess, Content: "first ran"}} - }, - } - }) + bg.tools.setPrepare(parkedReadCallPrepare(releaseTool, toolStarted)) submitThroughRuntime(t, bg.r, session, "op-1", "work") select { case <-toolStarted: @@ -1548,16 +1519,7 @@ func TestProjectionReadsClosedAndCanceledCallers(t *testing.T) { if err := r.Close(context.Background()); err != nil { t.Fatalf("Close: %v", err) } - closed := []func() error{ - func() error { _, err := r.getHistory(context.Background(), sessionID, nil); return err }, - func() error { _, err := r.buildHydration(context.Background(), sessionID); return err }, - func() error { - return headerErrorThroughRuntime(context.Background(), r, sessionID) - }, - func() error { - return historyErrorThroughRuntime(context.Background(), r, sessionID) - }, - } + closed := sessionReadCalls(context.Background(), r, sessionID) for i, call := range closed { if err := call(); !errors.Is(err, ErrClosed) { t.Fatalf("closed caller %d = %v, want ErrClosed", i, err) @@ -1568,16 +1530,7 @@ func TestProjectionReadsClosedAndCanceledCallers(t *testing.T) { defer closeProjectionRuntime(r2) canceled, cancel := context.WithCancel(context.Background()) cancel() - canceledCalls := []func() error{ - func() error { _, err := r2.getHistory(canceled, sessionID, nil); return err }, - func() error { _, err := r2.buildHydration(canceled, sessionID); return err }, - func() error { - return headerErrorThroughRuntime(canceled, r2, sessionID) - }, - func() error { - return historyErrorThroughRuntime(canceled, r2, sessionID) - }, - } + canceledCalls := sessionReadCalls(canceled, r2, sessionID) for i, call := range canceledCalls { if err := call(); !errors.Is(err, context.Canceled) { t.Fatalf("canceled caller %d = %v, want context.Canceled", i, err) From 4619b768c34dd05aa6e0ffec7d1bfd5fd4f7eafd Mon Sep 17 00:00:00 2001 From: MMinasyan Date: Mon, 19 Oct 2026 17:26:18 +0400 Subject: [PATCH 4/4] test(runtime): simplify provider create scenario setup --- runtime/configuration_connection_test.go | 143 +++++++++++++---------- 1 file changed, 84 insertions(+), 59 deletions(-) diff --git a/runtime/configuration_connection_test.go b/runtime/configuration_connection_test.go index 36958020..96f31a15 100644 --- a/runtime/configuration_connection_test.go +++ b/runtime/configuration_connection_test.go @@ -2059,79 +2059,106 @@ func TestCreateProviderExplicitEmptyEnvKeylessRefuses(t *testing.T) { }) } +// TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites pins the +// supplied-key rule: an explicitly named externally defined variable refuses +// the create before any configuration or cache side effect, leaving its +// value intact — it is not silently substituted for the supplied key. +func TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites(t *testing.T) { + eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { + server := newConnectionDiscoveryServer(t, connectionFullDiscovery) + r, _ := openConnectionRuntime(t, store, server.URL) + defer closeProjectionRuntime(r) + ctx := context.Background() + sub, err := r.Subscribe(8) + if err != nil { + t.Fatalf("Subscribe: %v", err) + } + defer sub.Close() + reserveEnvKey(t, "CONNECTION_SHELL_KEY") + t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") + envBefore, err := os.ReadFile(r.managedEnv.Path()) + if err != nil { + t.Fatalf("read .env: %v", err) + } + before, generation, warnRev := runtimeMutationBaseline(t, r) + + key := connectionKey + window := 4096 + baseURL := "https://new.test/v1" + shellEnv := "CONNECTION_SHELL_KEY" + _, err = r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &shellEnv}, + map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, &key) + // The refusal oracle already pins the owning file, generation, + // warnings, and events; the external sibling and the .env silence are + // this row's own axes. + assertRuntimeMutationRefused(t, r, sub, before, generation, warnRev, err, ErrConfiguration) + if os.Getenv("CONNECTION_SHELL_KEY") != "shell-exported-value" || r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { + t.Fatalf("external sibling state = (%q, %v), want it untouched and unmanaged", os.Getenv("CONNECTION_SHELL_KEY"), r.managedEnv.IsManaged("CONNECTION_SHELL_KEY")) + } + assertDotenvUnchanged(t, r, envBefore, "the external-sibling create") + }) +} + // TestCreateProviderKeySourceTable pins the ordinary provider-create -// key-source unions over the connection fixture. The external-binding row -// with a supplied key refuses the create before any configuration or cache -// side effect, leaving the explicitly named externally defined variable -// intact — it is not silently substituted for the supplied key. The -// managed-orphan row updates a managed orphan name by the supplied nonempty -// value; the managed-empty row fills a managed empty name instead of -// tripping the external-empty refusal; the existing-managed row uses an -// existing nonempty managed value as-is without a key write; the -// external-binding row without a supplied key registers as-is and stays -// external; and the missing-key row performs no credential action and no -// resolution refusal. +// key-source unions over the connection fixture. The managed-orphan row +// updates a managed orphan name by the supplied nonempty value; the +// managed-empty row fills a managed empty name instead of tripping the +// external-empty refusal; the existing-managed row uses an existing +// nonempty managed value as-is without a key write; the external-binding +// row without a supplied key registers as-is and stays external; and the +// missing-key row performs no credential action and no resolution refusal. +// Each row keeps its own Runtime, environment seed, and subscription, and +// every create without a supplied key also requires unchanged .env bytes. func TestCreateProviderKeySourceTable(t *testing.T) { + const ( + orphanReplacement = "sk-live-orphan-replacement" + emptyOrphanReplacement = "sk-live-empty-orphan-replacement" + ) rows := []struct { name string envName string key *string arrange func(t *testing.T, r *Runtime) - refuse error - check func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) + check func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) }{ - { - name: "TestCreateProviderExternalBindingWithKeyRefusesBeforeWrites", envName: "CONNECTION_SHELL_KEY", - key: ptrTo(connectionKey), refuse: ErrConfiguration, - arrange: func(t *testing.T, r *Runtime) { - reserveEnvKey(t, "CONNECTION_SHELL_KEY") - t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") - }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { - if os.Getenv("CONNECTION_SHELL_KEY") != "shell-exported-value" || r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { - t.Fatalf("external sibling state = (%q, %v), want it untouched and unmanaged", os.Getenv("CONNECTION_SHELL_KEY"), r.managedEnv.IsManaged("CONNECTION_SHELL_KEY")) - } - assertDotenvUnchanged(t, r, envBefore, "the external-sibling create") - }, - }, { name: "TestCreateProviderManagedOrphanKeyUpdatedBySuppliedValue", envName: "CONNECTION_ORPHAN_KEY", - key: ptrTo("sk-live-orphan-replacement"), + key: ptrTo(orphanReplacement), arrange: func(t *testing.T, r *Runtime) { reserveEnvKey(t, "CONNECTION_ORPHAN_KEY") if err := r.managedEnv.TrySet("CONNECTION_ORPHAN_KEY", "stale-managed-value"); err != nil { t.Fatalf("seed managed orphan: %v", err) } }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { - if os.Getenv("CONNECTION_ORPHAN_KEY") != *key || !r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY") { + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { + if os.Getenv("CONNECTION_ORPHAN_KEY") != orphanReplacement || !r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY") { t.Fatalf("managed orphan state = (%q, %v), want the supplied replacement", os.Getenv("CONNECTION_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_ORPHAN_KEY")) } envData, rerr := os.ReadFile(r.managedEnv.Path()) - if rerr != nil || !strings.Contains(string(envData), "CONNECTION_ORPHAN_KEY="+*key+"\n") || strings.Contains(string(envData), "stale-managed-value") { + if rerr != nil || !strings.Contains(string(envData), "CONNECTION_ORPHAN_KEY="+orphanReplacement+"\n") || strings.Contains(string(envData), "stale-managed-value") { t.Fatalf(".env = (%q, %v), want the replacement line only", envData, rerr) } raw, rerr := os.ReadFile(r.config.configPath) - if rerr != nil || !strings.Contains(string(raw), `"api_key_env": "CONNECTION_ORPHAN_KEY"`) || strings.Contains(string(raw), *key) { + if rerr != nil || !strings.Contains(string(raw), `"api_key_env": "CONNECTION_ORPHAN_KEY"`) || strings.Contains(string(raw), orphanReplacement) { t.Fatalf("raw config = (%q, %v), want the name only and never the value", raw, rerr) } mutBytes, merr := json.Marshal(mutation) - if merr != nil || strings.Contains(string(mutBytes), *key) { + if merr != nil || strings.Contains(string(mutBytes), orphanReplacement) { t.Fatalf("mutation bytes carry the key value (%v)", merr) } }, }, { name: "TestCreateProviderManagedEmptyKeyFilledBySuppliedValue", envName: "CONNECTION_EMPTY_ORPHAN_KEY", - key: ptrTo("sk-live-empty-orphan-replacement"), + key: ptrTo(emptyOrphanReplacement), arrange: func(t *testing.T, r *Runtime) { reserveEnvKey(t, "CONNECTION_EMPTY_ORPHAN_KEY") if err := r.managedEnv.TrySet("CONNECTION_EMPTY_ORPHAN_KEY", ""); err != nil { t.Fatalf("seed managed-empty name: %v", err) } }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { - if os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY") != *key || !r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY") { + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { + if os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY") != emptyOrphanReplacement || !r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY") { t.Fatalf("managed-empty state = (%q, %v), want the supplied value", os.Getenv("CONNECTION_EMPTY_ORPHAN_KEY"), r.managedEnv.IsManaged("CONNECTION_EMPTY_ORPHAN_KEY")) } }, @@ -2144,14 +2171,13 @@ func TestCreateProviderKeySourceTable(t *testing.T) { t.Fatalf("seed managed name: %v", err) } }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceManaged) { t.Fatalf("created provider key source = %q, want managed", mutation.Result.KeySource) } if os.Getenv("CONNECTION_EXISTING_KEY") != "existing-managed-value" || !r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY") { t.Fatalf("managed value changed without a supplied key: (%q, %v)", os.Getenv("CONNECTION_EXISTING_KEY"), r.managedEnv.IsManaged("CONNECTION_EXISTING_KEY")) } - assertDotenvUnchanged(t, r, envBefore, "the create without a supplied key") }, }, { @@ -2160,11 +2186,10 @@ func TestCreateProviderKeySourceTable(t *testing.T) { reserveEnvKey(t, "CONNECTION_SHELL_KEY") t.Setenv("CONNECTION_SHELL_KEY", "shell-exported-value") }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceExternal) { t.Fatalf("created provider key source = %q, want external", mutation.Result.KeySource) } - assertDotenvUnchanged(t, r, envBefore, "the no-key create") if r.managedEnv.IsManaged("CONNECTION_SHELL_KEY") { t.Fatal("the no-key create managed the external variable") } @@ -2175,12 +2200,11 @@ func TestCreateProviderKeySourceTable(t *testing.T) { arrange: func(t *testing.T, r *Runtime) { reserveEnvKey(t, "CONNECTION_MISSING_KEY") }, - check: func(t *testing.T, r *Runtime, e *ownerEnv, mutation protocol.ProviderMutation, key *string, envBefore []byte) { + check: func(t *testing.T, r *Runtime, mutation protocol.ProviderMutation) { if mutation.Result.KeySource != protocol.ProviderKeySource(config.KeySourceNone) || mutation.Result.ApiKeyEnv != "CONNECTION_MISSING_KEY" { t.Fatalf("created provider = (%q, %q), want the none source with the named binding", mutation.Result.KeySource, mutation.Result.ApiKeyEnv) } - assertDotenvUnchanged(t, r, envBefore, "the absent-binding create") - if _, present := metadataRawProvider(t, e.configPath, "newp")["transport"]; !present { + if _, present := metadataRawProvider(t, r.config.configPath, "newp")["transport"]; !present { t.Fatal("the created provider missing from the raw layer") } }, @@ -2190,7 +2214,7 @@ func TestCreateProviderKeySourceTable(t *testing.T) { t.Run(row.name, func(t *testing.T) { eachPrepStoreOnce(t, func(t *testing.T, store harness.Storage) { server := newConnectionDiscoveryServer(t, connectionFullDiscovery) - r, e := openConnectionRuntime(t, store, server.URL) + r, _ := openConnectionRuntime(t, store, server.URL) defer closeProjectionRuntime(r) ctx := context.Background() sub, err := r.Subscribe(8) @@ -2199,28 +2223,29 @@ func TestCreateProviderKeySourceTable(t *testing.T) { } defer sub.Close() row.arrange(t, r) - envBefore, err := os.ReadFile(r.managedEnv.Path()) - if err != nil { - t.Fatalf("read .env: %v", err) + + // Only the creates without a supplied key promise silence: the + // supplied-key rows write a value by design. + var envBefore []byte + if row.key == nil { + envBefore, err = os.ReadFile(r.managedEnv.Path()) + if err != nil { + t.Fatalf("read .env: %v", err) + } } - before, generation, warnRev := runtimeMutationBaseline(t, r) window := 4096 baseURL := "https://new.test/v1" mutation, err := r.addProvider(ctx, "newp", protocol.ProviderEdit{BaseUrl: &baseURL, ApiKeyEnv: &row.envName}, map[string]protocol.ModelEdit{"m": {ContextWindow: &window}}, row.key) - // The refusal oracle already pins the owning file, generation, - // warnings, and events; the success rows share the one - // generation-2 publication rule. - if row.refuse != nil { - assertRuntimeMutationRefused(t, r, sub, before, generation, warnRev, err, row.refuse) - } else { - if err != nil || mutation.ConfigurationRevision.Generation != "2" { - t.Fatalf("key-source create = (%v, %+v), want generation 2", err, mutation) - } - drainConnectionEvent(t, r.warnings, sub, "2") + if err != nil || mutation.ConfigurationRevision.Generation != "2" { + t.Fatalf("key-source create = (%v, %+v), want generation 2", err, mutation) + } + drainConnectionEvent(t, r.warnings, sub, "2") + if row.key == nil { + assertDotenvUnchanged(t, r, envBefore, row.name) } - row.check(t, r, e, mutation, row.key, envBefore) + row.check(t, r, mutation) }) }) }