Files
2026-07-13 13:00:08 +08:00

47 lines
1.3 KiB
Go

package main
import (
"context"
"sync"
"testing"
"reasonix/internal/event"
)
// All tabEventSink context mutations go through the locked setContext /
// clearContext accessors (no bare s.ctx = ... writes that data-race the
// s.context() reads in emitRuntimeEvent). After clearContext the sink stops
// emitting — emitRuntimeEvent sees a nil ctx and no-ops — and the queued
// emitter is drained, so a detached/backgrounded session can't flush stale
// events onto the now-rebound tab (#5352: stale "AI 不断输出" on the visible
// session after rapid session switching).
func TestTabEventSinkClearContextStopsEmission(t *testing.T) {
var mu sync.Mutex
var emitted int
s := &tabEventSink{tabID: "t"}
s.runtimeEvents.emit = func(context.Context, string, ...interface{}) {
mu.Lock()
emitted++
mu.Unlock()
}
s.setContext(context.Background())
if s.context() == nil {
t.Fatal("setContext did not install the context")
}
s.clearContext()
if s.context() != nil {
t.Fatal("clearContext did not clear the context")
}
// An emit after clearContext must not reach the runtime bridge.
s.emitRuntimeEvent(eventChannel, toWireTab(event.Event{}, s.tabID))
mu.Lock()
defer mu.Unlock()
if emitted != 0 {
t.Fatalf("sink emitted %d events after clearContext, want 0", emitted)
}
}