| @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from "@effect/vitest"; · 1 unmodified line |
| 2 | 2 | import { Database } from "bun:sqlite"; |
| 3 | 3 | import { migrate } from "drizzle-orm/bun-sqlite/migrator"; |
| 4 | 4 | import { drizzle } from "drizzle-orm/bun-sqlite"; |
| 5 | +import { Schema } from "effect"; |
| 5 | 6 | import { mkdtempSync, rmSync } from "node:fs"; |
| 6 | 7 | import { tmpdir } from "node:os"; |
| 7 | 8 | import { join } from "node:path"; |
| @@ -9,15 +10,26 @@ import { join } from "node:path"; · 1 unmodified line |
| 9 | 10 | import { migrateLegacyConnections } from "./migrate-connections"; |
| 10 | 11 | |
| 11 | 12 | let workDir: string; |
| 13 | +let databases: Array<Database>; |
| 12 | 14 | |
| 13 | 15 | beforeEach(() => { |
| 14 | 16 | workDir = mkdtempSync(join(tmpdir(), "executor-migrate-connections-")); |
| 17 | + databases = []; |
| 15 | 18 | }); |
| 16 | 19 | |
| 17 | 20 | afterEach(() => { |
| 21 | + for (const db of databases) { |
| 22 | + db.close(); |
| 23 | + } |
| 18 | 24 | rmSync(workDir, { recursive: true, force: true }); |
| 19 | 25 | }); |
| 20 | 26 | |
| 27 | +const openDatabase = (): Database => { |
| 28 | + const db = new Database(join(workDir, "data.db")); |
| 29 | + databases.push(db); |
| 30 | + return db; |
| 31 | +}; |
| 32 | + |
| 21 | 33 | const columnNames = (db: Database, table: string): ReadonlyArray<string> => |
| 22 | 34 | ( |
| 23 | 35 | db.prepare(`PRAGMA table_info('${table}')`).all() as ReadonlyArray<{ |
| @@ -25,9 +37,24 @@ const columnNames = (db: Database, table: string): ReadonlyArray<string> => · 1 unmodified line |
| 25 | 37 | }> |
| 26 | 38 | ).map((column) => column.name); |
| 27 | 39 | |
| 40 | +const MigratedMcpConfig = Schema.Struct({ |
| 41 | + auth: Schema.optional(Schema.Unknown), |
| 42 | +}); |
| 43 | +const decodeMigratedMcpConfig = Schema.decodeUnknownSync( |
| 44 | + Schema.fromJsonString(MigratedMcpConfig), |
| 45 | +); |
| 46 | + |
| 47 | +const MigratedOpenApiOAuth2 = Schema.Struct({ |
| 48 | + kind: Schema.Literal("oauth2"), |
| 49 | + connectionId: Schema.String, |
| 50 | +}); |
| 51 | +const decodeMigratedOpenApiOAuth2 = Schema.decodeUnknownSync( |
| 52 | + Schema.fromJsonString(MigratedOpenApiOAuth2), |
| 53 | +); |
| 54 | + |
| 28 | 55 | describe("migrateLegacyConnections", () => { |
| 29 | 56 | it("backfills legacy MCP OAuth rows after connection.kind has been dropped", async () => { |
| 30 | | − const db = new Database(join(workDir, "data.db")); |
| 57 | + const db = openDatabase(); |
| 31 | 58 | migrate(drizzle(db), { |
| 32 | 59 | migrationsFolder: join(import.meta.dirname, "../../drizzle"), |
| 33 | 60 | }); |
| @@ -98,7 +125,7 @@ describe("migrateLegacyConnections", () => { · 64 unmodified lines |
| 98 | 125 | readonly auth_kind: string; |
| 99 | 126 | readonly auth_connection_id: string; |
| 100 | 127 | }; |
| 101 | | − expect(JSON.parse(source.config).auth).toBeUndefined(); |
| 128 | + expect(decodeMigratedMcpConfig(source.config).auth).toBeUndefined(); |
| 102 | 129 | expect(source.auth_kind).toBe("oauth2"); |
| 103 | 130 | expect(source.auth_connection_id).toBe("mcp-oauth2-remote-mcp"); |
| 104 | 131 | |
| @@ -117,12 +144,10 @@ describe("migrateLegacyConnections", () => { · 12 unmodified lines |
| 117 | 144 | owned_by_connection_id: "mcp-oauth2-remote-mcp", |
| 118 | 145 | }, |
| 119 | 146 | ]); |
| 120 | | − |
| 121 | | − db.close(); |
| 122 | 147 | }); |
| 123 | 148 | |
| 124 | 149 | it("backfills legacy OpenAPI OAuth from oauth2 column after invocation_config has been dropped", async () => { |
| 125 | | − const db = new Database(join(workDir, "data.db")); |
| 150 | + const db = openDatabase(); |
| 126 | 151 | migrate(drizzle(db), { |
| 127 | 152 | migrationsFolder: join(import.meta.dirname, "../../drizzle"), |
| 128 | 153 | }); |
| @@ -196,10 +221,8 @@ describe("migrateLegacyConnections", () => { · 67 unmodified lines |
| 196 | 221 | const source = db |
| 197 | 222 | .prepare("SELECT oauth2 FROM openapi_source WHERE scope_id = ? AND id = ?") |
| 198 | 223 | .get("scope-1", "legacy-openapi") as { readonly oauth2: string }; |
| 199 | | − const oauth2 = JSON.parse(source.oauth2); |
| 224 | + const oauth2 = decodeMigratedOpenApiOAuth2(source.oauth2); |
| 200 | 225 | expect(oauth2.kind).toBe("oauth2"); |
| 201 | 226 | expect(oauth2.connectionId).toBe(connection?.id); |
| 202 | | − |
| 203 | | − db.close(); |
| 204 | 227 | }); |
| 205 | 228 | }); |