fix(connection): clear warnings after metadata recovery

This commit is contained in:
zipg authored and GitHub committed 2026-07-17 16:06:35 +08:00
1 parent 9ba61756db
commit d41a6d8944
10 files changed
+226 -9

No files matched your search

@@ -212,6 +212,187 @@ describe("connectionStore metadata loading", () => {
expect(schemaNode.children?.map((node) => node.label)).toEqual(["users"]);
});
it("clears a stale connection error after a schema metadata retry succeeds", async () => {
const listSchemaInfos = vi
.fn()
.mockRejectedValueOnce(new Error("connection slots exhausted"))
.mockResolvedValueOnce([{ name: "public", comment: null }]);
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
vi.doMock("@/lib/backend/api", () => ({
checkConnectionHealth: vi.fn().mockResolvedValue(undefined),
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
listInstalledAgents: vi.fn().mockResolvedValue([]),
listSchemaInfos,
loadSchemaCache: vi.fn().mockResolvedValue(null),
saveConnections: vi.fn().mockResolvedValue(undefined),
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
saveSidebarLayout: vi.fn().mockResolvedValue(undefined),
}));
const { useConnectionStore } = await import("@/stores/connectionStore");
const store = useConnectionStore();
const connection = postgresConnection();
store.connections = [connection];
store.connectedIds.add(connection.id);
store.treeNodes = [
{
id: connection.id,
label: connection.name,
type: "connection",
connectionId: connection.id,
isExpanded: true,
children: [
{
id: `${connection.id}:app`,
label: "app",
type: "database",
connectionId: connection.id,
database: "app",
isExpanded: false,
children: [],
},
],
},
];
await expect(store.loadSchemas(connection.id, "app", { force: true })).rejects.toThrow("connection slots exhausted");
expect(store.connectionErrors[connection.id]).toBe("connection slots exhausted");
await store.loadSchemas(connection.id, "app", { force: true });
expect(store.connectionErrors[connection.id]).toBeUndefined();
expect(store.treeNodes[0]?.children?.[0]?.children?.map((node) => node.label)).toEqual(["public"]);
});
it("clears a failed metadata warning when the driver hint finishes during retry", async () => {
let resolveAgents!: (drivers: Array<{ db_type: string; installed: boolean; update_available: boolean }>) => void;
let resolveSchemas!: (schemas: Array<{ name: string; comment: null }>) => void;
const listInstalledAgents = vi.fn(
() =>
new Promise<Array<{ db_type: string; installed: boolean; update_available: boolean }>>((resolve) => {
resolveAgents = resolve;
}),
);
const listSchemaInfos = vi
.fn()
.mockRejectedValueOnce(new Error("connection slots exhausted"))
.mockImplementationOnce(
() =>
new Promise<Array<{ name: string; comment: null }>>((resolve) => {
resolveSchemas = resolve;
}),
);
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
vi.doMock("@/lib/backend/api", () => ({
checkConnectionHealth: vi.fn().mockResolvedValue(undefined),
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
listInstalledAgents,
listSchemaInfos,
loadSchemaCache: vi.fn().mockResolvedValue(null),
saveConnections: vi.fn().mockResolvedValue(undefined),
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
saveSidebarLayout: vi.fn().mockResolvedValue(undefined),
}));
const { useConnectionStore } = await import("@/stores/connectionStore");
const store = useConnectionStore();
const connection = { ...postgresConnection(), db_type: "oracle" } as ConnectionConfig;
store.connections = [connection];
store.connectedIds.add(connection.id);
store.treeNodes = [
{
id: connection.id,
label: connection.name,
type: "connection",
connectionId: connection.id,
isExpanded: true,
children: [
{
id: `${connection.id}:app`,
label: "app",
type: "database",
connectionId: connection.id,
database: "app",
isExpanded: false,
children: [],
},
],
},
];
await expect(store.loadSchemas(connection.id, "app", { force: true })).rejects.toThrow("connection slots exhausted");
expect(store.connectionErrors[connection.id]).toBe("connection slots exhausted");
const retry = store.loadSchemas(connection.id, "app", { force: true });
await vi.waitFor(() => expect(listSchemaInfos).toHaveBeenCalledTimes(2));
resolveAgents([{ db_type: "oracle", installed: true, update_available: true }]);
await vi.waitFor(() => expect(store.connectionErrors[connection.id]).toContain("built-in driver update"));
resolveSchemas([{ name: "public", comment: null }]);
await retry;
expect(store.connectionErrors[connection.id]).toBeUndefined();
});
it("does not clear a newer error when an older metadata request succeeds", async () => {
let resolveSchemas!: (schemas: Array<{ name: string; comment: null }>) => void;
const listSchemaInfos = vi.fn(
() =>
new Promise<Array<{ name: string; comment: null }>>((resolve) => {
resolveSchemas = resolve;
}),
);
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
vi.doMock("@/lib/backend/api", () => ({
checkConnectionHealth: vi.fn().mockResolvedValue(undefined),
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
listSchemaInfos,
loadSchemaCache: vi.fn().mockResolvedValue(null),
saveConnections: vi.fn().mockResolvedValue(undefined),
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
saveSidebarLayout: vi.fn().mockResolvedValue(undefined),
}));
const { useConnectionStore } = await import("@/stores/connectionStore");
const store = useConnectionStore();
const connection = postgresConnection();
store.connections = [connection];
store.connectedIds.add(connection.id);
store.treeNodes = [
{
id: connection.id,
label: connection.name,
type: "connection",
connectionId: connection.id,
isExpanded: true,
children: [
{
id: `${connection.id}:app`,
label: "app",
type: "database",
connectionId: connection.id,
database: "app",
isExpanded: false,
children: [],
},
],
},
];
store.setConnectionError(connection.id, "old error");
const load = store.loadSchemas(connection.id, "app", { force: true });
await vi.waitFor(() => expect(listSchemaInfos).toHaveBeenCalledOnce());
store.setConnectionError(connection.id, "newer error");
resolveSchemas([{ name: "public", comment: null }]);
await load;
expect(store.connectionErrors[connection.id]).toBe("newer error");
});
it("keeps an expanding schema attached while its parent refreshes", async () => {
const listSchemaInfos = vi.fn().mockResolvedValue([{ name: "core", comment: null }]);