280 lines · 8.6 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest";import { Effect } from "effect";import { collectTables } from "@executor-js/sdk";import { createSqliteTestFumaDb } from "@executor-js/sdk/testing";import type { SqliteDataMigrationClient } from "@executor-js/sdk/core"; import { runSqliteGoogleOpenApiOwnershipMigration } from "./openapi-ownership-migration"; const now = 1_780_000_000_000; const insertIntegration = (  client: SqliteDataMigrationClient,  row: {    readonly rowId: string;    readonly tenant: string;    readonly slug: string;    readonly pluginId: string;    readonly config: unknown;  },) =>  client.execute({    sql: `INSERT INTO integration      (row_id, tenant, slug, plugin_id, name, description, config, can_remove, can_refresh, created_at, updated_at)      VALUES (?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?)`,    args: [      row.rowId,      row.tenant,      row.slug,      row.pluginId,      row.slug,      row.slug,      JSON.stringify(row.config),      now,      now,    ],  }); const insertIntegrationRawConfig = (  client: SqliteDataMigrationClient,  row: {    readonly rowId: string;    readonly tenant: string;    readonly slug: string;    readonly pluginId: string;    readonly config: string;  },) =>  client.execute({    sql: `INSERT INTO integration      (row_id, tenant, slug, plugin_id, name, description, config, can_remove, can_refresh, created_at, updated_at)      VALUES (?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?)`,    args: [row.rowId, row.tenant, row.slug, row.pluginId, row.slug, row.slug, row.config, now, now],  }); const insertBlob = (  client: SqliteDataMigrationClient,  row: {    readonly namespace: string;    readonly key: string;    readonly value: string;  },) =>  client.execute({    sql: "INSERT INTO blob (namespace, key, value, row_id, id) VALUES (?, ?, ?, ?, ?)",    args: [      row.namespace,      row.key,      row.value,      `blob-${row.namespace}-${row.key}`,      JSON.stringify([row.namespace, row.key]),    ],  }); const insertOperationStorage = (  client: SqliteDataMigrationClient,  row: {    readonly tenant: string;    readonly pluginId: string;    readonly integration: string;    readonly toolName: string;  },) =>  client.execute({    sql: `INSERT INTO plugin_storage      (tenant, owner, subject, plugin_id, collection, key, data, created_at, updated_at, row_id)      VALUES (?, 'org', '', ?, 'operation', ?, ?, ?, ?, ?)`,    args: [      row.tenant,      row.pluginId,      `${row.integration}.${row.toolName}`,      JSON.stringify({        integration: row.integration,        toolName: row.toolName,        binding: { method: "get", pathTemplate: "/items" },      }),      now,      now,      `storage-${row.pluginId}-${row.integration}-${row.toolName}`,    ],  }); const insertTool = (  client: SqliteDataMigrationClient,  row: {    readonly tenant: string;    readonly pluginId: string;    readonly integration: string;  },) =>  client.execute({    sql: `INSERT INTO tool      (tenant, owner, subject, integration, connection, plugin_id, name, description, input_schema, output_schema, annotations, created_at, updated_at, row_id)      VALUES (?, 'org', '', ?, 'default', ?, 'items.list', 'List items', NULL, NULL, NULL, ?, ?, ?)`,    args: [row.tenant, row.integration, row.pluginId, now, now, `tool-${row.integration}`],  }); const insertDefinition = (  client: SqliteDataMigrationClient,  row: {    readonly tenant: string;    readonly pluginId: string;    readonly integration: string;  },) =>  client.execute({    sql: `INSERT INTO definition      (tenant, owner, subject, integration, connection, plugin_id, name, schema, created_at, row_id)      VALUES (?, 'org', '', ?, 'default', ?, 'Item', '{}', ?, ?)`,    args: [row.tenant, row.integration, row.pluginId, now, `definition-${row.integration}`],  }); describe("runSqliteGoogleOpenApiOwnershipMigration", () => {  it.effect("skips malformed legacy integration config rows", () =>    Effect.gen(function* () {      const db = yield* Effect.promise(() => createSqliteTestFumaDb({ tables: collectTables() }));       yield* Effect.promise(() =>        insertIntegrationRawConfig(db.client, {          rowId: "malformed-row",          tenant: "org_1",          slug: "broken",          pluginId: "openapi",          config: "",        }),      );       expect(yield* runSqliteGoogleOpenApiOwnershipMigration(db.client)).toBe(0);       const integrations = yield* Effect.promise(() =>        db.client.execute("SELECT slug, plugin_id, config FROM integration"),      );      expect(integrations.rows).toEqual([{ slug: "broken", plugin_id: "openapi", config: "" }]);       yield* Effect.promise(() => db.close());    }),  );   it.effect("moves OpenAPI-owned Google bundle rows to the Google plugin", () =>    Effect.gen(function* () {      const db = yield* Effect.promise(() => createSqliteTestFumaDb({ tables: collectTables() }));      const client = db.client;       yield* Effect.promise(() =>        insertIntegration(client, {          rowId: "google-row",          tenant: "org_1",          slug: "google",          pluginId: "openapi",          config: {            specHash: "googlehash",            googleDiscoveryUrls: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"],          },        }),      );      yield* Effect.promise(() =>        insertIntegration(client, {          rowId: "stripe-row",          tenant: "org_1",          slug: "stripe",          pluginId: "openapi",          config: {            specHash: "stripehash",            specUrl: "https://stripe.example/openapi.json",          },        }),      );      yield* Effect.promise(() =>        insertBlob(client, {          namespace: "o:org_1/openapi",          key: "spec/googlehash",          value: "google spec",        }),      );      yield* Effect.promise(() =>        insertBlob(client, {          namespace: "o:org_1/openapi",          key: "spec/stripehash",          value: "stripe spec",        }),      );       for (const integration of ["google", "stripe"] as const) {        yield* Effect.promise(() =>          insertOperationStorage(client, {            tenant: "org_1",            pluginId: "openapi",            integration,            toolName: "items.list",          }),        );        yield* Effect.promise(() =>          insertTool(client, {            tenant: "org_1",            pluginId: "openapi",            integration,          }),        );        yield* Effect.promise(() =>          insertDefinition(client, {            tenant: "org_1",            pluginId: "openapi",            integration,          }),        );      }       expect(yield* runSqliteGoogleOpenApiOwnershipMigration(client)).toBe(1);      expect(yield* runSqliteGoogleOpenApiOwnershipMigration(client)).toBe(0);       const integrations = yield* Effect.promise(() =>        client.execute("SELECT slug, plugin_id FROM integration ORDER BY slug"),      );      expect(integrations.rows).toEqual([        { slug: "google", plugin_id: "google" },        { slug: "stripe", plugin_id: "openapi" },      ]);       const googleBlob = yield* Effect.promise(() =>        client.execute({          sql: "SELECT value FROM blob WHERE id = ?",          args: [JSON.stringify(["o:org_1/google", "spec/googlehash"])],        }),      );      expect(googleBlob.rows).toEqual([{ value: "google spec" }]);       const openApiBlobs = yield* Effect.promise(() =>        client.execute("SELECT key FROM blob WHERE namespace = 'o:org_1/openapi' ORDER BY key"),      );      expect(openApiBlobs.rows).toEqual([{ key: "spec/googlehash" }, { key: "spec/stripehash" }]);       const storage = yield* Effect.promise(() =>        client.execute(          "SELECT plugin_id, key FROM plugin_storage WHERE collection = 'operation' ORDER BY plugin_id, key",        ),      );      expect(storage.rows).toEqual([        { plugin_id: "google", key: "google.items.list" },        { plugin_id: "openapi", key: "stripe.items.list" },      ]);       const tools = yield* Effect.promise(() =>        client.execute("SELECT integration, plugin_id FROM tool ORDER BY integration"),      );      expect(tools.rows).toEqual([        { integration: "google", plugin_id: "google" },        { integration: "stripe", plugin_id: "openapi" },      ]);       const definitions = yield* Effect.promise(() =>        client.execute("SELECT integration, plugin_id FROM definition ORDER BY integration"),      );      expect(definitions.rows).toEqual([        { integration: "google", plugin_id: "google" },        { integration: "stripe", plugin_id: "openapi" },      ]);       yield* Effect.promise(() => db.close());    }),  );});