Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
const h = vi.hoisted(() => ({
captured: null as Record<string, unknown> | null,
updateSet: null as Record<string, unknown> | null,
updateReturning: [] as Array<{ id: string }>,
runResult: { changes: 0 } as { changes: number },
whereCalled: false,
}));

Expand All @@ -32,7 +32,7 @@ vi.mock('../../localDb/client/current.js', () => ({
return {
where: () => {
h.whereCalled = true;
return { returning: async () => h.updateReturning };
return { run: async () => h.runResult };
},
};
},
Expand Down Expand Up @@ -160,17 +160,27 @@ describe('DesktopSessionStorage.create workingDir 规范化', () => {
describe('DesktopSessionStorage.compareAndClearSdkSessionId', () => {
beforeEach(() => {
h.updateSet = null;
h.updateReturning = [];
h.runResult = { changes: 0 };
h.whereCalled = false;
});
it('用单条条件 update 清空旧 id,并按 returning 报告 CAS 是否命中', async () => {
it('CAS hit: .run() returns changes=1, method returns true', async () => {
const storage = new DesktopSessionStorage();
h.updateReturning = [{ id: 'session-1' }];
h.runResult = { changes: 1 };
await expect(storage.compareAndClearSdkSessionId('session-1', 'sdk-old')).resolves.toBe(true);
expect(h.updateSet?.sdkSessionId).toBeNull();
expect(h.updateSet?.updatedAt).toEqual(expect.any(Number));
expect(h.whereCalled).toBe(true);
h.updateReturning = [];
});
it('CAS miss: .run() returns changes=0, method returns false, preserves new ID', async () => {
const storage = new DesktopSessionStorage();
h.runResult = { changes: 0 };
await expect(storage.compareAndClearSdkSessionId('session-1', 'sdk-stale')).resolves.toBe(false);
});
it('concurrent path: hit then miss, each call correct', async () => {
const storage = new DesktopSessionStorage();
h.runResult = { changes: 1 };
await expect(storage.compareAndClearSdkSessionId('s1', 'sdk-a')).resolves.toBe(true);
h.runResult = { changes: 0 };
await expect(storage.compareAndClearSdkSessionId('s1', 'sdk-a')).resolves.toBe(false);
});
Comment on lines +179 to +185

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 并发测试未验证状态

当前用例通过手动切换 runResult 来决定两次调用的结果,且 mock 的 where() 不检查条件表达式,因此即使实现遗漏 sdkSessionId = expectedSdkSessionId 谓词,该测试仍会通过。建议让第一次调用实际改变模拟数据库状态,并由第二次调用的条件匹配自然返回未命中,以覆盖旧恢复请求不得清除并发写入的新 ID 这一 CAS 契约。

Context Used: 使用和PR描述相同的语言进行评论 (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/maker-host/__tests__/sessionStorageRemoteHostId.test.ts
Line: 179-185

Comment:
**并发测试未验证状态**

当前用例通过手动切换 `runResult` 来决定两次调用的结果,且 mock 的 `where()` 不检查条件表达式,因此即使实现遗漏 `sdkSessionId = expectedSdkSessionId` 谓词,该测试仍会通过。建议让第一次调用实际改变模拟数据库状态,并由第二次调用的条件匹配自然返回未命中,以覆盖旧恢复请求不得清除并发写入的新 ID 这一 CAS 契约。

**Context Used:** 使用和PR描述相同的语言进行评论 ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

});
6 changes: 3 additions & 3 deletions apps/desktop/src/main/maker-host/session-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,12 @@ export class DesktopSessionStorage implements SessionStorage {
expectedSdkSessionId: string,
): Promise<boolean> {
const db = getDbClient().drizzle;
const changed = await db
const result = await db
.update(sessions)
.set({ sdkSessionId: null, updatedAt: Date.now() })
.where(and(eq(sessions.id, id), eq(sessions.sdkSessionId, expectedSdkSessionId)))
.returning({ id: sessions.id });
return changed.length > 0;
.run();
return result.changes > 0;
}

async delete(id: string): Promise<void> {
Expand Down
Loading