sensorium-mcp 3.0.4 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/routes/data.d.ts.map +1 -1
- package/dist/dashboard/routes/data.js +2 -1
- package/dist/dashboard/routes/data.js.map +1 -1
- package/dist/dashboard/routes/threads.js +1 -1
- package/dist/dashboard/routes/threads.js.map +1 -1
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +1 -3
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/data/memory/migration-runner.d.ts +1 -1
- package/dist/data/memory/migration-runner.d.ts.map +1 -1
- package/dist/data/memory/migration-runner.js +59 -3
- package/dist/data/memory/migration-runner.js.map +1 -1
- package/dist/data/memory/schema-ddl.d.ts +1 -1
- package/dist/data/memory/schema-ddl.d.ts.map +1 -1
- package/dist/data/memory/schema-ddl.js +2 -1
- package/dist/data/memory/schema-ddl.js.map +1 -1
- package/dist/data/memory/thread-registry.js +1 -1
- package/dist/data/memory/thread-registry.js.map +1 -1
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +1 -9
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/server/factory.js +1 -1
- package/dist/server/factory.js.map +1 -1
- package/dist/services/agent-spawn.service.d.ts +7 -1
- package/dist/services/agent-spawn.service.d.ts.map +1 -1
- package/dist/services/agent-spawn.service.js +69 -45
- package/dist/services/agent-spawn.service.js.map +1 -1
- package/dist/services/consolidation.service.d.ts.map +1 -1
- package/dist/services/consolidation.service.js +49 -35
- package/dist/services/consolidation.service.js.map +1 -1
- package/dist/services/keeper.service.d.ts +21 -0
- package/dist/services/keeper.service.d.ts.map +1 -0
- package/dist/services/keeper.service.js +195 -0
- package/dist/services/keeper.service.js.map +1 -0
- package/dist/services/maintenance-signal.d.ts +2 -0
- package/dist/services/maintenance-signal.d.ts.map +1 -1
- package/dist/services/maintenance-signal.js +7 -1
- package/dist/services/maintenance-signal.js.map +1 -1
- package/dist/services/process.service.d.ts +19 -2
- package/dist/services/process.service.d.ts.map +1 -1
- package/dist/services/process.service.js +104 -10
- package/dist/services/process.service.js.map +1 -1
- package/dist/services/thread-lifecycle.service.d.ts +5 -0
- package/dist/services/thread-lifecycle.service.d.ts.map +1 -1
- package/dist/services/thread-lifecycle.service.js +33 -8
- package/dist/services/thread-lifecycle.service.js.map +1 -1
- package/dist/services/worker-cleanup.service.d.ts +14 -1
- package/dist/services/worker-cleanup.service.d.ts.map +1 -1
- package/dist/services/worker-cleanup.service.js +36 -38
- package/dist/services/worker-cleanup.service.js.map +1 -1
- package/dist/sessions.d.ts +0 -5
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +0 -7
- package/dist/sessions.js.map +1 -1
- package/dist/stdio-server.d.ts.map +1 -1
- package/dist/stdio-server.js +1 -7
- package/dist/stdio-server.js.map +1 -1
- package/dist/tools/delegate-tool.d.ts.map +1 -1
- package/dist/tools/delegate-tool.js +2 -2
- package/dist/tools/delegate-tool.js.map +1 -1
- package/dist/tools/session-tools.js +1 -1
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/tools/start-session-tool.d.ts.map +1 -1
- package/dist/tools/start-session-tool.js +8 -9
- package/dist/tools/start-session-tool.js.map +1 -1
- package/dist/tools/wait/message-processing.d.ts.map +1 -1
- package/dist/tools/wait/message-processing.js +28 -0
- package/dist/tools/wait/message-processing.js.map +1 -1
- package/dist/tools/wait/poll-loop.js +1 -1
- package/dist/tools/wait/poll-loop.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/thread-lifecycle.d.ts +0 -6
- package/dist/tools/thread-lifecycle.d.ts.map +0 -1
- package/dist/tools/thread-lifecycle.js +0 -6
- package/dist/tools/thread-lifecycle.js.map +0 -1
- package/supervisor/config.go +0 -253
- package/supervisor/config_test.go +0 -78
- package/supervisor/go.mod +0 -15
- package/supervisor/go.sum +0 -20
- package/supervisor/health.go +0 -433
- package/supervisor/health_test.go +0 -93
- package/supervisor/keeper.go +0 -309
- package/supervisor/keeper_test.go +0 -27
- package/supervisor/lock.go +0 -57
- package/supervisor/lock_test.go +0 -54
- package/supervisor/log.go +0 -195
- package/supervisor/log_test.go +0 -125
- package/supervisor/main.go +0 -475
- package/supervisor/main_test.go +0 -130
- package/supervisor/notify.go +0 -53
- package/supervisor/process.go +0 -294
- package/supervisor/process_test.go +0 -108
- package/supervisor/process_unix.go +0 -14
- package/supervisor/process_windows.go +0 -15
- package/supervisor/secrets.go +0 -95
- package/supervisor/secrets_securevault_test.go +0 -98
- package/supervisor/secrets_test.go +0 -119
- package/supervisor/self_update.go +0 -282
- package/supervisor/self_update_test.go +0 -177
- package/supervisor/service_restart_stub.go +0 -9
- package/supervisor/service_restart_windows.go +0 -63
- package/supervisor/service_stub.go +0 -15
- package/supervisor/service_windows.go +0 -194
- package/supervisor/update_state.go +0 -264
- package/supervisor/update_state_test.go +0 -306
- package/supervisor/updater.go +0 -613
- package/supervisor/updater_test.go +0 -64
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"errors"
|
|
6
|
-
"os"
|
|
7
|
-
"path/filepath"
|
|
8
|
-
"testing"
|
|
9
|
-
"time"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
func TestUpdateStateStore_TransitionAndLoad(t *testing.T) {
|
|
13
|
-
dir := t.TempDir()
|
|
14
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
15
|
-
defer log.Close()
|
|
16
|
-
|
|
17
|
-
store := NewUpdateStateStore(filepath.Join(dir, "update-state.json"), log)
|
|
18
|
-
store.Transition(updateScopeMCP, updatePhaseApplying, "2.0.0", "1.0.0", "")
|
|
19
|
-
|
|
20
|
-
state, err := store.Load()
|
|
21
|
-
if err != nil {
|
|
22
|
-
t.Fatalf("Load() after applying transition failed: %v", err)
|
|
23
|
-
}
|
|
24
|
-
if state.Scope != updateScopeMCP {
|
|
25
|
-
t.Fatalf("Scope = %q, want %q", state.Scope, updateScopeMCP)
|
|
26
|
-
}
|
|
27
|
-
if state.Phase != updatePhaseApplying {
|
|
28
|
-
t.Fatalf("Phase = %q, want %q", state.Phase, updatePhaseApplying)
|
|
29
|
-
}
|
|
30
|
-
if state.TargetVersion != "2.0.0" {
|
|
31
|
-
t.Fatalf("TargetVersion = %q, want 2.0.0", state.TargetVersion)
|
|
32
|
-
}
|
|
33
|
-
if state.PreviousVersion != "1.0.0" {
|
|
34
|
-
t.Fatalf("PreviousVersion = %q, want 1.0.0", state.PreviousVersion)
|
|
35
|
-
}
|
|
36
|
-
if !state.UpdatedAt.UTC().Equal(state.UpdatedAt) {
|
|
37
|
-
t.Fatal("UpdatedAt must be UTC")
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
store.Transition(updateScopeMCP, updatePhaseFailed, "2.0.0", "1.0.0", "boom")
|
|
41
|
-
state, err = store.Load()
|
|
42
|
-
if err != nil {
|
|
43
|
-
t.Fatalf("Load() after failed transition failed: %v", err)
|
|
44
|
-
}
|
|
45
|
-
if state.Phase != updatePhaseFailed {
|
|
46
|
-
t.Fatalf("Phase = %q, want %q", state.Phase, updatePhaseFailed)
|
|
47
|
-
}
|
|
48
|
-
if state.LastError != "boom" {
|
|
49
|
-
t.Fatalf("LastError = %q, want boom", state.LastError)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
store.Transition(updateScopeMCP, updatePhaseIdle, "2.0.0", "1.0.0", "")
|
|
53
|
-
state, err = store.Load()
|
|
54
|
-
if err != nil {
|
|
55
|
-
t.Fatalf("Load() after idle transition failed: %v", err)
|
|
56
|
-
}
|
|
57
|
-
if state.Phase != updatePhaseIdle {
|
|
58
|
-
t.Fatalf("Phase = %q, want %q", state.Phase, updatePhaseIdle)
|
|
59
|
-
}
|
|
60
|
-
if state.LastError != "" {
|
|
61
|
-
t.Fatalf("LastError = %q, want empty", state.LastError)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
func TestAcquireUpdateCoordinatorLock_SerializesScopes(t *testing.T) {
|
|
66
|
-
dir := t.TempDir()
|
|
67
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
68
|
-
defer log.Close()
|
|
69
|
-
|
|
70
|
-
lockPath := filepath.Join(dir, "update-apply.lock")
|
|
71
|
-
|
|
72
|
-
mcpLock, ok := AcquireUpdateCoordinatorLock(lockPath, updateScopeMCP, log)
|
|
73
|
-
if !ok || mcpLock == nil {
|
|
74
|
-
t.Fatal("expected MCP scope lock acquisition to succeed")
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
supervisorLock, ok := AcquireUpdateCoordinatorLock(lockPath, updateScopeSupervisor, log)
|
|
78
|
-
if ok || supervisorLock != nil {
|
|
79
|
-
t.Fatal("expected supervisor scope lock acquisition to fail while MCP lock is held")
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
mcpLock.Release()
|
|
83
|
-
|
|
84
|
-
supervisorLock, ok = AcquireUpdateCoordinatorLock(lockPath, updateScopeSupervisor, log)
|
|
85
|
-
if !ok || supervisorLock == nil {
|
|
86
|
-
t.Fatal("expected supervisor scope lock acquisition to succeed after release")
|
|
87
|
-
}
|
|
88
|
-
supervisorLock.Release()
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
type fakeUpdateLockFile struct {
|
|
92
|
-
writeErr error
|
|
93
|
-
closeErr error
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
func (f *fakeUpdateLockFile) Write(_ []byte) (int, error) {
|
|
97
|
-
if f.writeErr != nil {
|
|
98
|
-
return 0, f.writeErr
|
|
99
|
-
}
|
|
100
|
-
return 1, nil
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
func (f *fakeUpdateLockFile) Close() error {
|
|
104
|
-
return f.closeErr
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
func TestWriteUpdateLockMetadata_CleansUpOnWriteError(t *testing.T) {
|
|
108
|
-
dir := t.TempDir()
|
|
109
|
-
lockPath := filepath.Join(dir, "update-apply.lock")
|
|
110
|
-
if err := os.WriteFile(lockPath, []byte("partial"), 0644); err != nil {
|
|
111
|
-
t.Fatalf("seed lock file: %v", err)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
originalOpen := openUpdateLockFile
|
|
115
|
-
defer func() { openUpdateLockFile = originalOpen }()
|
|
116
|
-
openUpdateLockFile = func(string) (updateLockFile, error) {
|
|
117
|
-
return &fakeUpdateLockFile{writeErr: errors.New("write fail")}, nil
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
err := writeUpdateLockMetadata(lockPath, []byte(`{"pid":1}`))
|
|
121
|
-
if err == nil {
|
|
122
|
-
t.Fatal("expected writeUpdateLockMetadata to fail")
|
|
123
|
-
}
|
|
124
|
-
if _, statErr := os.Stat(lockPath); !errors.Is(statErr, os.ErrNotExist) {
|
|
125
|
-
t.Fatalf("expected lock file to be removed after write error, statErr=%v", statErr)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
func TestWriteUpdateLockMetadata_CleansUpOnCloseError(t *testing.T) {
|
|
130
|
-
dir := t.TempDir()
|
|
131
|
-
lockPath := filepath.Join(dir, "update-apply.lock")
|
|
132
|
-
if err := os.WriteFile(lockPath, []byte("partial"), 0644); err != nil {
|
|
133
|
-
t.Fatalf("seed lock file: %v", err)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
originalOpen := openUpdateLockFile
|
|
137
|
-
defer func() { openUpdateLockFile = originalOpen }()
|
|
138
|
-
openUpdateLockFile = func(string) (updateLockFile, error) {
|
|
139
|
-
return &fakeUpdateLockFile{closeErr: errors.New("close fail")}, nil
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
err := writeUpdateLockMetadata(lockPath, []byte(`{"pid":1}`))
|
|
143
|
-
if err == nil {
|
|
144
|
-
t.Fatal("expected writeUpdateLockMetadata to fail")
|
|
145
|
-
}
|
|
146
|
-
if _, statErr := os.Stat(lockPath); !errors.Is(statErr, os.ErrNotExist) {
|
|
147
|
-
t.Fatalf("expected lock file to be removed after close error, statErr=%v", statErr)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
func TestAcquireUpdateCoordinatorLock_ReclaimsWhenOwnerDead(t *testing.T) {
|
|
152
|
-
dir := t.TempDir()
|
|
153
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
154
|
-
defer log.Close()
|
|
155
|
-
|
|
156
|
-
lockPath := filepath.Join(dir, "update-apply.lock")
|
|
157
|
-
owner := updateLockOwner{
|
|
158
|
-
Scope: updateScopeMCP,
|
|
159
|
-
PID: 999999,
|
|
160
|
-
UpdatedAt: time.Now().UTC(),
|
|
161
|
-
}
|
|
162
|
-
data, _ := json.Marshal(owner)
|
|
163
|
-
if err := os.WriteFile(lockPath, data, 0644); err != nil {
|
|
164
|
-
t.Fatalf("seed lock owner: %v", err)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
lock, ok := AcquireUpdateCoordinatorLock(lockPath, updateScopeSupervisor, log)
|
|
168
|
-
if !ok || lock == nil {
|
|
169
|
-
t.Fatal("expected lock to be reclaimed for dead owner PID")
|
|
170
|
-
}
|
|
171
|
-
lock.Release()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
func TestAcquireUpdateCoordinatorLock_DoesNotReclaimFromAliveOwnerEvenWhenStaleByAge(t *testing.T) {
|
|
175
|
-
dir := t.TempDir()
|
|
176
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
177
|
-
defer log.Close()
|
|
178
|
-
|
|
179
|
-
lockPath := filepath.Join(dir, "update-apply.lock")
|
|
180
|
-
owner := updateLockOwner{
|
|
181
|
-
Scope: updateScopeMCP,
|
|
182
|
-
PID: os.Getpid(),
|
|
183
|
-
UpdatedAt: time.Now().UTC().Add(-updateCoordinatorLockMaxAge - time.Minute),
|
|
184
|
-
}
|
|
185
|
-
data, _ := json.Marshal(owner)
|
|
186
|
-
if err := os.WriteFile(lockPath, data, 0644); err != nil {
|
|
187
|
-
t.Fatalf("seed lock owner: %v", err)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
lock, ok := AcquireUpdateCoordinatorLock(lockPath, updateScopeSupervisor, log)
|
|
191
|
-
if ok || lock != nil {
|
|
192
|
-
t.Fatal("expected lock acquisition to fail while alive owner still holds lock")
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
raw, err := os.ReadFile(lockPath)
|
|
196
|
-
if err != nil {
|
|
197
|
-
t.Fatalf("read original lock: %v", err)
|
|
198
|
-
}
|
|
199
|
-
var current updateLockOwner
|
|
200
|
-
if err := json.Unmarshal(raw, ¤t); err != nil {
|
|
201
|
-
t.Fatalf("unmarshal lock owner: %v", err)
|
|
202
|
-
}
|
|
203
|
-
if current.Scope != updateScopeMCP {
|
|
204
|
-
t.Fatalf("scope = %q, want %q", current.Scope, updateScopeMCP)
|
|
205
|
-
}
|
|
206
|
-
if current.PID != os.Getpid() {
|
|
207
|
-
t.Fatalf("pid = %d, want %d", current.PID, os.Getpid())
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
func TestRecoverPersistedUpdateStateOnStartup_StaleNonIdleBecomesFailed(t *testing.T) {
|
|
212
|
-
dir := t.TempDir()
|
|
213
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
214
|
-
defer log.Close()
|
|
215
|
-
|
|
216
|
-
cfg := Config{Paths: Paths{UpdateState: filepath.Join(dir, "update-state.json")}}
|
|
217
|
-
store := NewUpdateStateStore(cfg.Paths.UpdateState, log)
|
|
218
|
-
store.Transition(updateScopeMCP, updatePhaseApplying, "2.0.0", "1.0.0", "")
|
|
219
|
-
|
|
220
|
-
recoverPersistedUpdateStateOnStartup(cfg, log)
|
|
221
|
-
|
|
222
|
-
state, err := store.Load()
|
|
223
|
-
if err != nil {
|
|
224
|
-
t.Fatalf("load recovered state: %v", err)
|
|
225
|
-
}
|
|
226
|
-
if state.Phase != updatePhaseFailed {
|
|
227
|
-
t.Fatalf("phase = %q, want %q", state.Phase, updatePhaseFailed)
|
|
228
|
-
}
|
|
229
|
-
if state.Scope != updateScopeMCP {
|
|
230
|
-
t.Fatalf("scope = %q, want %q", state.Scope, updateScopeMCP)
|
|
231
|
-
}
|
|
232
|
-
if state.LastError == "" {
|
|
233
|
-
t.Fatal("expected recovery reason in LastError")
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
func TestRecoverPersistedUpdateStateOnStartup_SupervisorRestartingReachesIdleWhenVersionApplied(t *testing.T) {
|
|
238
|
-
dir := t.TempDir()
|
|
239
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
240
|
-
defer log.Close()
|
|
241
|
-
|
|
242
|
-
target := "2.0.0"
|
|
243
|
-
cfg := Config{Paths: Paths{
|
|
244
|
-
UpdateState: filepath.Join(dir, "update-state.json"),
|
|
245
|
-
SupervisorVersion: filepath.Join(dir, "supervisor-version.txt"),
|
|
246
|
-
}}
|
|
247
|
-
if err := os.WriteFile(cfg.Paths.SupervisorVersion, []byte(target), 0644); err != nil {
|
|
248
|
-
t.Fatalf("seed supervisor version: %v", err)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
store := NewUpdateStateStore(cfg.Paths.UpdateState, log)
|
|
252
|
-
store.Transition(updateScopeSupervisor, updatePhaseRestarting, target, "1.0.0", "")
|
|
253
|
-
|
|
254
|
-
recoverPersistedUpdateStateOnStartup(cfg, log)
|
|
255
|
-
|
|
256
|
-
state, err := store.Load()
|
|
257
|
-
if err != nil {
|
|
258
|
-
t.Fatalf("load recovered state: %v", err)
|
|
259
|
-
}
|
|
260
|
-
if state.Scope != updateScopeSupervisor {
|
|
261
|
-
t.Fatalf("scope = %q, want %q", state.Scope, updateScopeSupervisor)
|
|
262
|
-
}
|
|
263
|
-
if state.Phase != updatePhaseIdle {
|
|
264
|
-
t.Fatalf("phase = %q, want %q", state.Phase, updatePhaseIdle)
|
|
265
|
-
}
|
|
266
|
-
if state.TargetVersion != target {
|
|
267
|
-
t.Fatalf("target version = %q, want %q", state.TargetVersion, target)
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
func TestRecoverPersistedUpdateStateOnStartup_SupervisorFailedReachesIdleWhenVersionApplied(t *testing.T) {
|
|
272
|
-
dir := t.TempDir()
|
|
273
|
-
log := NewLogger(filepath.Join(dir, "test.log"))
|
|
274
|
-
defer log.Close()
|
|
275
|
-
|
|
276
|
-
target := "2.1.0"
|
|
277
|
-
cfg := Config{Paths: Paths{
|
|
278
|
-
UpdateState: filepath.Join(dir, "update-state.json"),
|
|
279
|
-
SupervisorVersion: filepath.Join(dir, "supervisor-version.txt"),
|
|
280
|
-
}}
|
|
281
|
-
if err := os.WriteFile(cfg.Paths.SupervisorVersion, []byte(target), 0644); err != nil {
|
|
282
|
-
t.Fatalf("seed supervisor version: %v", err)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
store := NewUpdateStateStore(cfg.Paths.UpdateState, log)
|
|
286
|
-
store.Transition(updateScopeSupervisor, updatePhaseFailed, target, "2.0.0", "previous helper failure")
|
|
287
|
-
|
|
288
|
-
recoverPersistedUpdateStateOnStartup(cfg, log)
|
|
289
|
-
|
|
290
|
-
state, err := store.Load()
|
|
291
|
-
if err != nil {
|
|
292
|
-
t.Fatalf("load recovered state: %v", err)
|
|
293
|
-
}
|
|
294
|
-
if state.Scope != updateScopeSupervisor {
|
|
295
|
-
t.Fatalf("scope = %q, want %q", state.Scope, updateScopeSupervisor)
|
|
296
|
-
}
|
|
297
|
-
if state.Phase != updatePhaseIdle {
|
|
298
|
-
t.Fatalf("phase = %q, want %q", state.Phase, updatePhaseIdle)
|
|
299
|
-
}
|
|
300
|
-
if state.TargetVersion != target {
|
|
301
|
-
t.Fatalf("target version = %q, want %q", state.TargetVersion, target)
|
|
302
|
-
}
|
|
303
|
-
if state.LastError != "" {
|
|
304
|
-
t.Fatalf("last error = %q, want empty", state.LastError)
|
|
305
|
-
}
|
|
306
|
-
}
|