返回 DeepSeek-Reasonix
stream_router_stage_test.go
根目录 / internal / boot / stream_router_stage_test.go
1 package boot
2
3 import (
4 "fmt"
5 "testing"
6
7 "reasonix/internal/extension/protocol"
8 "reasonix/internal/extension/providerext"
9 "reasonix/internal/extension/sidecar"
10 "reasonix/internal/provider"
11 )
12
13 type baseResolver struct{}
14
15 func (baseResolver) Catalog() []provider.Descriptor { return nil }
16 func (baseResolver) Resolve(provider.Selection) (provider.Provider, error) {
17 return nil, fmt.Errorf("no model")
18 }
19
20 // namedRouter is a distinct StreamRouter identity for before/after assertions.
21 type namedRouter struct{ name string }
22
23 func (n *namedRouter) RouteStreamChunk(protocol.StreamChunkParams) {}
24 func (n *namedRouter) RouteStreamEnd(protocol.StreamEndParams) {}
25
26 func TestMergeDoesNotInstallStreamRouterCommitDoes(t *testing.T) {
27 old := &namedRouter{name: "old-generation"}
28 client := sidecar.NewProbeClient("demo", []protocol.ProviderDescriptor{{
29 Ref: "plugin/demo/fake/x",
30 Model: "x",
31 }}, old)
32 if client.StreamRouter() != old {
33 t.Fatal("precondition: client must start with old router")
34 }
35
36 mgr := &sidecar.Manager{}
37 if err := mgr.Adopt("demo", client); err != nil {
38 t.Fatal(err)
39 }
40
41 // Stage merge: construct resolver only — must not touch client router.
42 merged, err := mergeSidecarProviders(baseResolver{}, mgr, nil)
43 if err != nil {
44 t.Fatalf("mergeSidecarProviders: %v", err)
45 }
46 if merged == nil {
47 t.Fatal("expected merged resolver when client declares providers")
48 }
49 if got := client.StreamRouter(); got != old {
50 t.Fatalf("after merge router = %T, want old generation router", got)
51 }
52
53 // Commit install: only then switch away from the old router.
54 installSidecarStreamRouters(mgr, merged)
55 got := client.StreamRouter()
56 if got == old {
57 t.Fatal("after commit install, router must not still be the old generation")
58 }
59 newRouter, ok := any(merged).(sidecar.StreamRouter)
60 if !ok {
61 t.Fatal("merged resolver must implement sidecar.StreamRouter")
62 }
63 if got != newRouter {
64 t.Fatalf("after commit router = %T, want merged providerext resolver", got)
65 }
66 }
67
68 func TestFailedStageLeavesOldRouterForAdoptedClient(t *testing.T) {
69 // Stage merge + fail before commit: router stays pre-stage. Real wire
70 // chunk/end after rollback: sidecar.TestRollbackAfterStageKeepsOldRouterConsumingRealStream.
71 old := &namedRouter{name: "old-gen"}
72 client := sidecar.NewProbeClient("keep", []protocol.ProviderDescriptor{{
73 Ref: "plugin/keep/fake/x", Model: "x",
74 }}, old)
75
76 prev := &sidecar.Manager{}
77 _ = prev.Adopt("keep", client)
78
79 next := &sidecar.Manager{}
80 // Adopt unchanged (as StartPackagesWithPlan does).
81 if c := prev.Detach("keep"); c != nil {
82 _ = next.Adopt("keep", c)
83 // record as planAdopted via Rollback path: set by StartPackagesWithPlan;
84 // for unit test call merge on next then rollback without install.
85 }
86 if _, err := mergeSidecarProviders(baseResolver{}, next, nil); err != nil {
87 t.Fatal(err)
88 }
89 if client.StreamRouter() != old {
90 t.Fatal("stage merge must not rewrite adopted client router")
91 }
92 // Failure: reattach without ever calling installSidecarStreamRouters.
93 if c := next.Detach("keep"); c != nil {
94 _ = prev.Adopt("keep", c)
95 }
96 if prev.Client("keep") != client {
97 t.Fatal("client should be back on previous manager")
98 }
99 if client.StreamRouter() != old {
100 t.Fatal("after rollback, router must still be old generation")
101 }
102 }
103
104 func TestMergeSidecarProvidersDoesNotInstallRouter(t *testing.T) {
105 installSidecarStreamRouters(nil, nil)
106 installSidecarStreamRouters(&sidecar.Manager{}, nil)
107 installSidecarStreamRouters(nil, baseResolver{})
108 }
109
110 func TestInstallSidecarStreamRoutersAcceptsProviderext(t *testing.T) {
111 r, err := providerext.New(baseResolver{}, func() []providerext.ProviderClient { return nil }, nil)
112 if err != nil {
113 t.Fatal(err)
114 }
115 installSidecarStreamRouters(&sidecar.Manager{}, r)
116 if _, ok := any(r).(sidecar.StreamRouter); !ok {
117 t.Fatal("providerext.Resolver must implement sidecar.StreamRouter")
118 }
119 }
120
120 lines GO