From 2777757e2b8d06cd52d4f1fd312774644f56c1e5 Mon Sep 17 00:00:00 2001 From: lentil32 Date: Thu, 25 Jun 2026 17:43:48 +0900 Subject: [PATCH] fix(server): test R2 SQL connections with catalog metadata --- .../data-source-query/execute-query.test.ts | 48 ++++++++++++++++++- .../providers/cloudflare-r2-sql/driver.ts | 2 +- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/server/src/services/data-source-query/execute-query.test.ts b/packages/server/src/services/data-source-query/execute-query.test.ts index db0671ee..b2cce9be 100644 --- a/packages/server/src/services/data-source-query/execute-query.test.ts +++ b/packages/server/src/services/data-source-query/execute-query.test.ts @@ -6,19 +6,21 @@ import type { } from "snowflake-sdk"; import { afterEach, describe, expect, it, vi } from "vitest"; +import { createQueryDeadline } from "./core/timeout"; import { executeBigQueryQuery, executeCloudflareD1Query, executeCloudflareR2SqlQuery, executeDatabaseQuery, + executeLaminarQuery, executeMotherDuckQuery, + executePostgresQuery, executeSnowflakeQuery, executeValidatedDatabaseQuery, - executeLaminarQuery, - executePostgresQuery, } from "./execute-query"; import type { DatabaseQueryResult } from "./execute-query"; import type { PostgresClientConfig } from "./postgres-transport"; +import { cloudflareR2SqlQueryDriver } from "./providers/cloudflare-r2-sql/driver"; const originalFetch = globalThis.fetch; const postgresCredentials = { @@ -296,6 +298,48 @@ describe("data source query execution", () => { }); }); + it("tests Cloudflare R2 SQL connections with a catalog metadata command", async () => { + const fetchSpy = vi.fn(async (_url: string | URL, _init?: RequestInit) => ({ + json: async () => ({ + errors: [], + messages: [], + result: { + metrics: { + bytes_scanned: 0, + files_scanned: 0, + r2_requests_count: 1, + }, + rows: [{ namespace: "default" }], + schema: [{ name: "namespace", type: "Utf8" }], + }, + success: true, + }), + ok: true, + status: 200, + text: async () => "", + })); + globalThis.fetch = fetchSpy as unknown as typeof fetch; + + const result = await cloudflareR2SqlQueryDriver.testConnection({ + context: {}, + credentials: { + accountId: "acct_123", + apiToken: "cf-r2-sql-token", + bucketName: "analytics-events", + type: "cloudflare_r2_sql", + }, + deadline: createQueryDeadline(1000), + }); + + expect(result.isOk()).toBe(true); + expect(fetchSpy).toHaveBeenCalledTimes(1); + const [, init] = fetchSpy.mock.calls[0] ?? []; + expect(JSON.parse(init?.body as string)).toEqual({ + query: "SHOW DATABASES", + warehouse: "acct_123_analytics-events", + }); + }); + it("sanitizes Cloudflare R2 SQL error text", async () => { const fetchSpy = vi.fn(async (_url: string | URL, _init?: RequestInit) => ({ json: async () => ({}), diff --git a/packages/server/src/services/data-source-query/providers/cloudflare-r2-sql/driver.ts b/packages/server/src/services/data-source-query/providers/cloudflare-r2-sql/driver.ts index d358be59..831bcf34 100644 --- a/packages/server/src/services/data-source-query/providers/cloudflare-r2-sql/driver.ts +++ b/packages/server/src/services/data-source-query/providers/cloudflare-r2-sql/driver.ts @@ -29,7 +29,7 @@ const DEFAULT_CLOUDFLARE_R2_SQL_API_BASE_URL = const TRANSIENT_CLOUDFLARE_R2_SQL_STATUS_CODES = new Set([ 429, 500, 502, 503, 504, ]); -const CONNECTION_TEST_QUERY = "SELECT 1 AS onequery_connection_test"; +const CONNECTION_TEST_QUERY = "SHOW DATABASES"; export async function executeCloudflareR2SqlQuery( creds: CloudflareR2SqlCredentials,