Skip to content

Commit 66f70e3

Browse files
committed
🤖 test: add unit tests for rename/streaming lock
Tests verify: - sendMessage returns error when workspace is being renamed - resumeStream returns error when workspace is being renamed - rename returns error when workspace is streaming _Generated with mux_
1 parent 5103bb0 commit 66f70e3

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { describe, expect, test, mock, beforeEach } from "bun:test";
2+
import { WorkspaceService } from "./workspaceService";
3+
import type { Config } from "@/node/config";
4+
import type { HistoryService } from "./historyService";
5+
import type { PartialService } from "./partialService";
6+
import type { AIService } from "./aiService";
7+
import type { InitStateManager } from "./initStateManager";
8+
import type { ExtensionMetadataService } from "./ExtensionMetadataService";
9+
10+
// Helper to access private renamingWorkspaces set
11+
function addToRenamingWorkspaces(service: WorkspaceService, workspaceId: string): void {
12+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
13+
(service as any).renamingWorkspaces.add(workspaceId);
14+
}
15+
16+
describe("WorkspaceService rename lock", () => {
17+
let workspaceService: WorkspaceService;
18+
let mockAIService: AIService;
19+
20+
beforeEach(() => {
21+
// Create minimal mocks for the services
22+
mockAIService = {
23+
isStreaming: mock(() => false),
24+
getWorkspaceMetadata: mock(() => Promise.resolve({ success: false, error: "not found" })),
25+
// eslint-disable-next-line @typescript-eslint/no-empty-function
26+
on: mock(() => {}),
27+
// eslint-disable-next-line @typescript-eslint/no-empty-function
28+
off: mock(() => {}),
29+
} as unknown as AIService;
30+
31+
const mockHistoryService: Partial<HistoryService> = {
32+
getHistory: mock(() => Promise.resolve({ success: true, data: [] })),
33+
appendToHistory: mock(() => Promise.resolve({ success: true })),
34+
};
35+
36+
const mockConfig: Partial<Config> = {
37+
srcDir: "/tmp/test",
38+
getSessionDir: mock(() => "/tmp/test/sessions"),
39+
generateStableId: mock(() => "test-id"),
40+
findWorkspace: mock(() => null),
41+
};
42+
43+
const mockPartialService: Partial<PartialService> = {
44+
commitToHistory: mock(() => Promise.resolve({ success: true })),
45+
};
46+
47+
const mockInitStateManager: Partial<InitStateManager> = {};
48+
const mockExtensionMetadataService: Partial<ExtensionMetadataService> = {};
49+
50+
workspaceService = new WorkspaceService(
51+
mockConfig as Config,
52+
mockHistoryService as HistoryService,
53+
mockPartialService as PartialService,
54+
mockAIService,
55+
mockInitStateManager as InitStateManager,
56+
mockExtensionMetadataService as ExtensionMetadataService
57+
);
58+
});
59+
60+
test("sendMessage returns error when workspace is being renamed", async () => {
61+
const workspaceId = "test-workspace";
62+
63+
addToRenamingWorkspaces(workspaceService, workspaceId);
64+
65+
const result = await workspaceService.sendMessage(workspaceId, "test message", {
66+
model: "test-model",
67+
});
68+
69+
expect(result.success).toBe(false);
70+
if (!result.success) {
71+
const error = result.error;
72+
// Error is SendMessageError which has a discriminated union
73+
expect(typeof error === "object" && error.type === "unknown").toBe(true);
74+
if (typeof error === "object" && error.type === "unknown") {
75+
expect(error.raw).toContain("being renamed");
76+
}
77+
}
78+
});
79+
80+
test("resumeStream returns error when workspace is being renamed", async () => {
81+
const workspaceId = "test-workspace";
82+
83+
addToRenamingWorkspaces(workspaceService, workspaceId);
84+
85+
const result = await workspaceService.resumeStream(workspaceId, {
86+
model: "test-model",
87+
});
88+
89+
expect(result.success).toBe(false);
90+
if (!result.success) {
91+
const error = result.error;
92+
// Error is SendMessageError which has a discriminated union
93+
expect(typeof error === "object" && error.type === "unknown").toBe(true);
94+
if (typeof error === "object" && error.type === "unknown") {
95+
expect(error.raw).toContain("being renamed");
96+
}
97+
}
98+
});
99+
100+
test("rename returns error when workspace is streaming", async () => {
101+
const workspaceId = "test-workspace";
102+
103+
// Mock isStreaming to return true
104+
(mockAIService.isStreaming as ReturnType<typeof mock>).mockReturnValue(true);
105+
106+
const result = await workspaceService.rename(workspaceId, "new-name");
107+
108+
expect(result.success).toBe(false);
109+
if (!result.success) {
110+
expect(result.error).toContain("stream is active");
111+
}
112+
});
113+
});

0 commit comments

Comments
 (0)