Skip to content

Commit 70a804e

Browse files
committed
test(auth): cover switch save race
1 parent 97f3933 commit 70a804e

2 files changed

Lines changed: 58 additions & 9 deletions

File tree

lib/codex-manager.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,6 +4294,7 @@ async function loadManageActionStorageSnapshot(): Promise<AccountStorageV3 | nul
42944294
}
42954295
}
42964296

4297+
// Unreachable in practice: the loop above either returns a snapshot or rethrows.
42974298
throw new Error("Manage action storage reload retry loop exhausted unexpectedly");
42984299
}
42994300

@@ -4344,15 +4345,6 @@ async function loadManageActionStorage(
43444345
return null;
43454346
}
43464347

4347-
if (!freshStorage.accounts[targetIndex]) {
4348-
reportUnavailableManageActionAccount(
4349-
displayAccountNumber,
4350-
targetIndex,
4351-
freshStorage.accounts.length,
4352-
);
4353-
return null;
4354-
}
4355-
43564348
return freshStorage;
43574349
}
43584350

test/codex-manager-cli.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,63 @@ describe("codex manager cli commands", () => {
31593159
expect(logSpy).toHaveBeenCalledWith("Cancelled.");
31603160
});
31613161

3162+
it.each(["EBUSY", "EPERM"])(
3163+
"does not report a successful switch when saving the validated selection fails with %s",
3164+
async (code) => {
3165+
const now = Date.now();
3166+
const storage = {
3167+
version: 3,
3168+
activeIndex: 0,
3169+
activeIndexByFamily: { codex: 0 },
3170+
accounts: [
3171+
{
3172+
email: "first@example.com",
3173+
accountId: "acc_first",
3174+
refreshToken: "refresh-first",
3175+
accessToken: "access-first",
3176+
expiresAt: now + 3_600_000,
3177+
addedAt: now - 2_000,
3178+
lastUsed: now - 2_000,
3179+
enabled: true,
3180+
},
3181+
{
3182+
email: "switch@example.com",
3183+
accountId: "acc_switch",
3184+
refreshToken: "refresh-switch",
3185+
accessToken: "access-switch",
3186+
expiresAt: now + 3_600_000,
3187+
addedAt: now - 1_000,
3188+
lastUsed: now - 1_000,
3189+
enabled: true,
3190+
},
3191+
],
3192+
};
3193+
loadAccountsMock.mockImplementation(async () => structuredClone(storage));
3194+
saveAccountsMock.mockRejectedValueOnce(
3195+
makeErrnoError("switch save failed", code),
3196+
);
3197+
promptLoginModeMock
3198+
.mockResolvedValueOnce({
3199+
mode: "manage",
3200+
switchAccountIndex: 1,
3201+
selectedAccountNumber: 1,
3202+
})
3203+
.mockResolvedValueOnce({ mode: "cancel" });
3204+
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
3205+
3206+
const { runCodexMultiAuthCli } = await import("../lib/codex-manager.js");
3207+
3208+
await expect(
3209+
runCodexMultiAuthCli(["auth", "login"]),
3210+
).rejects.toThrow(`switch save failed`);
3211+
expect(saveAccountsMock).toHaveBeenCalledTimes(1);
3212+
expect(setCodexCliActiveSelectionMock).not.toHaveBeenCalled();
3213+
expect(logSpy).not.toHaveBeenCalledWith(
3214+
expect.stringContaining("Switched to account"),
3215+
);
3216+
},
3217+
);
3218+
31623219
it("marks newly added login account active so smart sort reflects it immediately", async () => {
31633220
const now = Date.now();
31643221
let storageState: {

0 commit comments

Comments
 (0)