返回 DeepSeek-Reasonix
turn_model_settings_test.go
根目录 / internal / cli / turn_model_settings_test.go
1 package cli
2
3 import (
4 "errors"
5 "testing"
6
7 "reasonix/internal/control"
8 "reasonix/internal/provider"
9 )
10
11 func TestTurnAppliesExternalCredentialSaveBeforeAuthentication(t *testing.T) {
12 for _, failBuild := range []bool{false, true} {
13 t.Run(map[bool]string{false: "success", true: "failure"}[failBuild], func(t *testing.T) {
14 reads := 0
15 old := control.New(control.Options{ModelSettingsRevision: "old", ModelSettingsCurrent: func() (string, error) { reads++; return "new", nil }, Authentication: control.AuthenticationState{Status: control.AuthenticationMissingCredential}})
16 defer old.Close()
17 fresh := control.New(control.Options{ModelSettingsRevision: "new", ModelSettingsCurrent: func() (string, error) { return "new", nil }})
18 defer fresh.Close()
19 m := newTestChatTUI()
20 m.ctrl = old
21 m.buildController = func(controllerBuildSpec, []provider.Message, string, control.SessionAPI) (*control.Controller, error) {
22 if failBuild {
23 return nil, errors.New("fixture build failure")
24 }
25 return fresh, nil
26 }
27 var started control.SessionAPI
28 cmd := m.startControllerTurn("draft", "draft", func(c control.SessionAPI) { started = c })
29 if cmd == nil || reads != 0 {
30 t.Fatal("settings must be checked asynchronously")
31 }
32 cmd = m.handleTurnModelSettings(cmd().(turnModelSettingsMsg))
33 if reads != 1 || cmd == nil || started != nil {
34 t.Fatal("old missing-key controller prevented rebuild")
35 }
36 switchMsg := cmd().(modelSwitchMsg)
37 if failBuild {
38 if switchMsg.err == nil || m.input.Value() != "draft" || m.ctrl != old {
39 t.Fatal("failed rebuild lost original work")
40 }
41 return
42 }
43 // Exercise the same activation and next-admission sequence without
44 // unrelated terminal, wallet, or filesystem commands from Update.
45 m.ctrl = switchMsg.ctrl
46 m.modelSwitchPending = false
47 cmd = m.resumeControllerTurn(*switchMsg.resumeTurn, false)
48 m.handleTurnModelSettings(cmd().(turnModelSettingsMsg))
49 if started != fresh || m.input.Value() != "" {
50 t.Fatal("submission did not use replacement controller")
51 }
52 })
53 }
54 }
55
56 func TestTurnSettingsCompletionCannotStartAnotherSession(t *testing.T) {
57 old := control.New(control.Options{ModelSettingsRevision: "one", ModelSettingsCurrent: func() (string, error) { return "one", nil }})
58 defer old.Close()
59 fresh := control.New(control.Options{})
60 defer fresh.Close()
61 m := newTestChatTUI()
62 m.ctrl = old
63 cmd := m.startControllerTurn("draft", "draft", func(control.SessionAPI) { t.Fatal("stale submission started") })
64 m.ctrl = fresh
65 if got := m.handleTurnModelSettings(cmd().(turnModelSettingsMsg)); got != nil {
66 t.Fatal("stale completion scheduled work")
67 }
68 }
69
70 func TestTurnSettingsCompletionCannotRaceAnotherRuntimeSwitch(t *testing.T) {
71 ctrl := control.New(control.Options{ModelSettingsRevision: "one", ModelSettingsCurrent: func() (string, error) { return "one", nil }})
72 defer ctrl.Close()
73 m := newTestChatTUI()
74 m.ctrl = ctrl
75 cmd := m.startControllerTurn("draft", "draft", func(control.SessionAPI) { t.Fatal("submission raced runtime switch") })
76 m.modelSwitchPending = true
77 if got := m.handleTurnModelSettings(cmd().(turnModelSettingsMsg)); got != nil || m.input.Value() != "draft" {
78 t.Fatal("switch discarded draft or admitted stale turn")
79 }
80 }
81
81 lines GO