From 32695018bf5bbec7b01790890a81b5bbef85096d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 11 May 2023 17:48:37 +0200 Subject: [PATCH 1/7] Validate and test microsoft sql --- .../src/integrations/microsoftSqlServer.ts | 17 ++++++- .../integrations/validators/postgres.spec.ts | 47 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index eb87c1ccf1..3f14360d57 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -22,7 +22,7 @@ import { MSSQLTablesResponse, MSSQLColumn } from "./base/types" const sqlServer = require("mssql") const DEFAULT_SCHEMA = "dbo" -interface MSSQLConfig { +export interface MSSQLConfig { user: string password: string server: string @@ -138,6 +138,10 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { } } + // async end(){ + // this.client!. + // } + async internalQuery( query: SqlQuery, operation: string | undefined = undefined @@ -306,7 +310,18 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { } } +async function validateConnection(config: MSSQLConfig) { + const integration = new SqlServerIntegration(config) + try { + await integration.connect() + return true + } catch (e: any) { + return { error: e.message as string } + } +} + export default { schema: SCHEMA, integration: SqlServerIntegration, + validateConnection, } diff --git a/qa-core/src/integrations/validators/postgres.spec.ts b/qa-core/src/integrations/validators/postgres.spec.ts index 5aa3250e2a..dcc0b4cb73 100644 --- a/qa-core/src/integrations/validators/postgres.spec.ts +++ b/qa-core/src/integrations/validators/postgres.spec.ts @@ -2,6 +2,7 @@ import { GenericContainer } from "testcontainers" import postgres from "../../../../packages/server/src/integrations/postgres" jest.unmock("pg") +jest.unmock("mssql") describe("datasource validators", () => { describe("postgres", () => { @@ -50,4 +51,50 @@ describe("datasource validators", () => { }) }) }) + + describe("mssql", () => { + const validator = integrations.getValidator[SourceName.SQL_SERVER]! + + let host: string, port: number + + beforeAll(async () => { + const container = await new GenericContainer( + "mcr.microsoft.com/mssql/server" + ) + .withExposedPorts(1433) + .withEnv("ACCEPT_EULA", "Y") + .withEnv("MSSQL_SA_PASSWORD", "Str0Ng_p@ssW0rd!") + .withEnv("MSSQL_PID", "Developer") + .start() + + host = container.getContainerIpAddress() + port = container.getMappedPort(1433) + }) + + it("test valid connection string", async () => { + const result = await validator({ + user: "sa", + password: "Str0Ng_p@ssW0rd!", + server: host, + port: port, + database: "master", + schema: "dbo", + }) + expect(result).toBe(true) + }) + + it("test invalid password", async () => { + const result = await validator({ + user: "sa", + password: "wrong_pwd", + server: host, + port: port, + database: "master", + schema: "dbo", + }) + expect(result).toEqual({ + error: "ConnectionError: Login failed for user 'sa'.", + }) + }) + }) }) From fd18529135e636cd77aaf22b1b0f18b3ddb497b6 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 11 May 2023 20:32:44 +0200 Subject: [PATCH 2/7] Wait for readiness --- .../integrations/validators/postgres.spec.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/qa-core/src/integrations/validators/postgres.spec.ts b/qa-core/src/integrations/validators/postgres.spec.ts index dcc0b4cb73..e36686fe64 100644 --- a/qa-core/src/integrations/validators/postgres.spec.ts +++ b/qa-core/src/integrations/validators/postgres.spec.ts @@ -1,5 +1,8 @@ import { GenericContainer } from "testcontainers" +import { Duration, TemporalUnit } from "node-duration" + import postgres from "../../../../packages/server/src/integrations/postgres" +import { SourceName } from "@budibase/types" jest.unmock("pg") jest.unmock("mssql") @@ -57,14 +60,24 @@ describe("datasource validators", () => { let host: string, port: number + const password = "Str0Ng_p@ssW0rd!" + beforeAll(async () => { const container = await new GenericContainer( "mcr.microsoft.com/mssql/server" ) .withExposedPorts(1433) .withEnv("ACCEPT_EULA", "Y") - .withEnv("MSSQL_SA_PASSWORD", "Str0Ng_p@ssW0rd!") + .withEnv("MSSQL_SA_PASSWORD", password) .withEnv("MSSQL_PID", "Developer") + .withWaitStrategy(Wait.forHealthCheck()) + .withHealthCheck({ + test: `/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "${password}" -Q "SELECT 1" -b -o /dev/null`, + interval: new Duration(1000, TemporalUnit.MILLISECONDS), + timeout: new Duration(3, TemporalUnit.SECONDS), + retries: 20, + startPeriod: new Duration(100, TemporalUnit.MILLISECONDS), + }) .start() host = container.getContainerIpAddress() @@ -74,7 +87,7 @@ describe("datasource validators", () => { it("test valid connection string", async () => { const result = await validator({ user: "sa", - password: "Str0Ng_p@ssW0rd!", + password, server: host, port: port, database: "master", From 0418e90a37735d718002db28064a9db1761899e5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 12 May 2023 12:49:08 +0200 Subject: [PATCH 3/7] Implement the check as part of the integration --- .../src/integrations/microsoftSqlServer.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 3f14360d57..4391dbd07e 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -121,6 +121,15 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { } } + async testConnection() { + try { + await this.connect() + return true + } catch (e: any) { + return { error: e.message as string } + } + } + getBindingIdentifier(): string { return `@p${this.index++}` } @@ -310,18 +319,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { } } -async function validateConnection(config: MSSQLConfig) { - const integration = new SqlServerIntegration(config) - try { - await integration.connect() - return true - } catch (e: any) { - return { error: e.message as string } - } -} - export default { schema: SCHEMA, integration: SqlServerIntegration, - validateConnection, } From 2641a8c13552d6a032ec16edfb79b8b29b4e0ac8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 12 May 2023 12:50:47 +0200 Subject: [PATCH 4/7] Clean code --- packages/server/src/integrations/microsoftSqlServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 4391dbd07e..2650d777cc 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -22,7 +22,7 @@ import { MSSQLTablesResponse, MSSQLColumn } from "./base/types" const sqlServer = require("mssql") const DEFAULT_SCHEMA = "dbo" -export interface MSSQLConfig { +interface MSSQLConfig { user: string password: string server: string From d98bc11a20cb76d50953450d56874520f9812f53 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 12 May 2023 12:51:19 +0200 Subject: [PATCH 5/7] Clean --- packages/server/src/integrations/microsoftSqlServer.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 2650d777cc..4c77bc2632 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -147,10 +147,6 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { } } - // async end(){ - // this.client!. - // } - async internalQuery( query: SqlQuery, operation: string | undefined = undefined From 0557c8efcc2b06f19cc0e49bbb54de53428381b0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 15 May 2023 16:24:26 +0200 Subject: [PATCH 6/7] Split tests --- .../src/integrations/validators/mssql.spec.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 qa-core/src/integrations/validators/mssql.spec.ts diff --git a/qa-core/src/integrations/validators/mssql.spec.ts b/qa-core/src/integrations/validators/mssql.spec.ts new file mode 100644 index 0000000000..89af8e87c0 --- /dev/null +++ b/qa-core/src/integrations/validators/mssql.spec.ts @@ -0,0 +1,64 @@ +import { GenericContainer, Wait } from "testcontainers" +import { Duration, TemporalUnit } from "node-duration" + +import mssql from "../../../../packages/server/src/integrations/microsoftSqlServer" + +jest.unmock("mssql") + +describe("datasource validators", () => { + describe("mssql", () => { + let host: string, port: number + + const password = "Str0Ng_p@ssW0rd!" + + beforeAll(async () => { + const container = await new GenericContainer( + "mcr.microsoft.com/mssql/server" + ) + .withExposedPorts(1433) + .withEnv("ACCEPT_EULA", "Y") + .withEnv("MSSQL_SA_PASSWORD", password) + .withEnv("MSSQL_PID", "Developer") + .withWaitStrategy(Wait.forHealthCheck()) + .withHealthCheck({ + test: `/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "${password}" -Q "SELECT 1" -b -o /dev/null`, + interval: new Duration(1000, TemporalUnit.MILLISECONDS), + timeout: new Duration(3, TemporalUnit.SECONDS), + retries: 20, + startPeriod: new Duration(100, TemporalUnit.MILLISECONDS), + }) + .start() + + host = container.getContainerIpAddress() + port = container.getMappedPort(1433) + }) + + it("test valid connection string", async () => { + const integration = new mssql.integration({ + user: "sa", + password, + server: host, + port: port, + database: "master", + schema: "dbo", + }) + const result = await integration.testConnection() + expect(result).toBe(true) + }) + + it("test invalid password", async () => { + const integration = new mssql.integration({ + user: "sa", + password: "wrong_pwd", + server: host, + port: port, + database: "master", + schema: "dbo", + }) + const result = await integration.testConnection() + expect(result).toEqual({ + error: "ConnectionError: Login failed for user 'sa'.", + }) + }) + }) +}) From b739e8da9cede51829150740641235b214df6063 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 15 May 2023 16:25:12 +0200 Subject: [PATCH 7/7] Undo --- .../integrations/validators/postgres.spec.ts | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/qa-core/src/integrations/validators/postgres.spec.ts b/qa-core/src/integrations/validators/postgres.spec.ts index e36686fe64..5aa3250e2a 100644 --- a/qa-core/src/integrations/validators/postgres.spec.ts +++ b/qa-core/src/integrations/validators/postgres.spec.ts @@ -1,11 +1,7 @@ import { GenericContainer } from "testcontainers" -import { Duration, TemporalUnit } from "node-duration" - import postgres from "../../../../packages/server/src/integrations/postgres" -import { SourceName } from "@budibase/types" jest.unmock("pg") -jest.unmock("mssql") describe("datasource validators", () => { describe("postgres", () => { @@ -54,60 +50,4 @@ describe("datasource validators", () => { }) }) }) - - describe("mssql", () => { - const validator = integrations.getValidator[SourceName.SQL_SERVER]! - - let host: string, port: number - - const password = "Str0Ng_p@ssW0rd!" - - beforeAll(async () => { - const container = await new GenericContainer( - "mcr.microsoft.com/mssql/server" - ) - .withExposedPorts(1433) - .withEnv("ACCEPT_EULA", "Y") - .withEnv("MSSQL_SA_PASSWORD", password) - .withEnv("MSSQL_PID", "Developer") - .withWaitStrategy(Wait.forHealthCheck()) - .withHealthCheck({ - test: `/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "${password}" -Q "SELECT 1" -b -o /dev/null`, - interval: new Duration(1000, TemporalUnit.MILLISECONDS), - timeout: new Duration(3, TemporalUnit.SECONDS), - retries: 20, - startPeriod: new Duration(100, TemporalUnit.MILLISECONDS), - }) - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(1433) - }) - - it("test valid connection string", async () => { - const result = await validator({ - user: "sa", - password, - server: host, - port: port, - database: "master", - schema: "dbo", - }) - expect(result).toBe(true) - }) - - it("test invalid password", async () => { - const result = await validator({ - user: "sa", - password: "wrong_pwd", - server: host, - port: port, - database: "master", - schema: "dbo", - }) - expect(result).toEqual({ - error: "ConnectionError: Login failed for user 'sa'.", - }) - }) - }) })