From e2e1e9d7d2a9080e3af858820a7cfc85b0603017 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 3 Mar 2025 09:55:34 +0000 Subject: [PATCH] De-mock the environment variable tests. --- .../routes/tests/environmentVariables.spec.ts | 237 +++++++----------- .../src/tests/utilities/api/environment.ts | 52 ++++ .../server/src/tests/utilities/api/index.ts | 3 + .../server/src/tests/utilities/structures.ts | 5 +- 4 files changed, 155 insertions(+), 142 deletions(-) create mode 100644 packages/server/src/tests/utilities/api/environment.ts diff --git a/packages/server/src/api/routes/tests/environmentVariables.spec.ts b/packages/server/src/api/routes/tests/environmentVariables.spec.ts index beb6012c9c..e6df353797 100644 --- a/packages/server/src/api/routes/tests/environmentVariables.spec.ts +++ b/packages/server/src/api/routes/tests/environmentVariables.spec.ts @@ -1,153 +1,108 @@ const pg = require("pg") -jest.mock("pg", () => { - return { - Client: jest.fn().mockImplementation(() => ({ - connect: jest.fn(), - query: jest.fn().mockImplementation(() => ({ rows: [] })), - end: jest.fn().mockImplementation((fn: any) => fn()), - })), - queryMock: jest.fn().mockImplementation(() => {}), - on: jest.fn(), - } -}) -import * as setup from "./utilities" +import { structures } from "./utilities" import { mocks } from "@budibase/backend-core/tests" -import { env, events } from "@budibase/backend-core" -import { QueryPreview } from "@budibase/types" +import { setEnv } from "@budibase/backend-core" +import { Datasource } from "@budibase/types" +import TestConfiguration from "../../../tests/utilities/TestConfiguration" +import { + DatabaseName, + datasourceDescribe, +} from "../../../integrations/tests/utils" -const structures = setup.structures +const describes = datasourceDescribe({ only: [DatabaseName.POSTGRES] }) -env._set("ENCRYPTION_KEY", "budibase") -mocks.licenses.useEnvironmentVariables() +if (describes.length > 0) { + describe.each(describes)("/api/env/variables", ({ dsProvider }) => { + const config = new TestConfiguration() -describe("/api/env/variables", () => { - let request = setup.getRequest() - let config = setup.getConfig() + let rawDatasource: Datasource + let restoreEnv: () => void - afterAll(setup.afterAll) + beforeAll(async () => { + await config.init() + restoreEnv = setEnv({ ENCRYPTION_KEY: "budibase" }) + mocks.licenses.useEnvironmentVariables() - beforeAll(async () => { - await config.init() - }) + const ds = await dsProvider() + rawDatasource = ds.rawDatasource! + }) - it("should be able check the status of env var API", async () => { - const res = await request - .get(`/api/env/variables/status`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + afterAll(() => { + restoreEnv() + }) - expect(res.body.encryptionKeyAvailable).toEqual(true) - }) - - it("should be able to create an environment variable", async () => { - await request - .post(`/api/env/variables`) - .send(structures.basicEnvironmentVariable("test", "test")) - .set(config.defaultHeaders()) - .expect(200) - }) - - it("should be able to fetch the 'test' variable name", async () => { - const res = await request - .get(`/api/env/variables`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.variables.length).toEqual(1) - expect(res.body.variables[0]).toEqual("test") - }) - - it("should be able to update the environment variable 'test'", async () => { - const varName = "test" - await request - .patch(`/api/env/variables/${varName}`) - .send(structures.basicEnvironmentVariable("test", "test1")) - .set(config.defaultHeaders()) - .expect(200) - }) - - it("should be able to delete the environment variable 'test'", async () => { - const varName = "test" - await request - .delete(`/api/env/variables/${varName}`) - .set(config.defaultHeaders()) - .expect(200) - }) - - it("should create a datasource (using the environment variable) and query", async () => { - const datasourceBase = structures.basicDatasource() - await request - .post(`/api/env/variables`) - .send(structures.basicEnvironmentVariable("test", "test")) - .set(config.defaultHeaders()) - - datasourceBase.datasource.config = { - password: "{{ env.test }}", - } - const response = await request - .post(`/api/datasources`) - .send(datasourceBase) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(response.body.datasource._id).toBeDefined() - - const response2 = await request - .post(`/api/queries`) - .send(structures.basicQuery(response.body.datasource._id)) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(response2.body._id).toBeDefined() - }) - - it("should run a query preview and check the mocked results", async () => { - const datasourceBase = structures.basicDatasource() - await request - .post(`/api/env/variables`) - .send(structures.basicEnvironmentVariable("test", "test")) - .set(config.defaultHeaders()) - - datasourceBase.datasource.config = { - password: "{{ env.test }}", - } - const response = await request - .post(`/api/datasources`) - .send(datasourceBase) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(response.body.datasource._id).toBeDefined() - - const queryPreview: QueryPreview = { - datasourceId: response.body.datasource._id, - parameters: [], - fields: {}, - queryVerb: "read", - name: response.body.datasource.name, - transformer: null, - schema: {}, - readable: true, - } - const res = await request - .post(`/api/queries/preview`) - .send(queryPreview) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.rows.length).toEqual(0) - expect(events.query.previewed).toHaveBeenCalledTimes(1) - // API doesn't include config in response - delete response.body.datasource.config - expect(events.query.previewed).toHaveBeenCalledWith( - response.body.datasource, - { - ...queryPreview, - nullDefaultSupport: true, + beforeEach(async () => { + const { variables } = await config.api.environment.fetch() + for (const variable of variables) { + await config.api.environment.destroy(variable) } - ) - expect(pg.Client).toHaveBeenCalledWith({ password: "test", ssl: undefined }) + + await config.api.environment.create({ + name: "test", + production: rawDatasource.config!.password, + development: rawDatasource.config!.password, + }) + }) + + it("should be able check the status of env var API", async () => { + const { encryptionKeyAvailable } = await config.api.environment.status() + expect(encryptionKeyAvailable).toEqual(true) + }) + + it("should be able to fetch the 'test' variable name", async () => { + const { variables } = await config.api.environment.fetch() + expect(variables.length).toEqual(1) + expect(variables[0]).toEqual("test") + }) + + it("should be able to update the environment variable 'test'", async () => { + await config.api.environment.update("test", { + production: "test1", + development: "test1", + }) + }) + + it("should be able to delete the environment variable 'test'", async () => { + await config.api.environment.destroy("test") + }) + + it("should create a datasource (using the environment variable) and query", async () => { + const datasource = await config.api.datasource.create({ + ...structures.basicDatasource().datasource, + config: { + ...rawDatasource.config, + password: "{{ env.test }}", + }, + }) + + const query = await config.api.query.save({ + ...structures.basicQuery(datasource._id!), + fields: { sql: "SELECT 1" }, + }) + expect(query._id).toBeDefined() + }) + + it("should run a query preview and check the mocked results", async () => { + const datasource = await config.api.datasource.create({ + ...structures.basicDatasource().datasource, + config: { + ...rawDatasource.config, + password: "{{ env.test }}", + }, + }) + + const query = await config.api.query.save({ + ...structures.basicQuery(datasource._id!), + fields: { sql: "SELECT 1 as id" }, + }) + + const { rows } = await config.api.query.preview({ + ...query, + queryId: query._id!, + }) + + expect(rows).toEqual([{ id: 1 }]) + }) }) -}) +} diff --git a/packages/server/src/tests/utilities/api/environment.ts b/packages/server/src/tests/utilities/api/environment.ts new file mode 100644 index 0000000000..2c4e7a751e --- /dev/null +++ b/packages/server/src/tests/utilities/api/environment.ts @@ -0,0 +1,52 @@ +import { Expectations, TestAPI } from "./base" +import { + CreateEnvironmentVariableRequest, + CreateEnvironmentVariableResponse, + GetEnvironmentVariablesResponse, + Row, + StatusEnvironmentVariableResponse, + UpdateEnvironmentVariableRequest, +} from "@budibase/types" + +export class EnvironmentAPI extends TestAPI { + create = async ( + body: CreateEnvironmentVariableRequest, + expectations?: Expectations + ) => { + return await this._post( + `/api/env/variables`, + { body, expectations } + ) + } + + status = async (expectations?: Expectations) => { + return await this._get( + `/api/env/variables/status`, + { expectations } + ) + } + + fetch = async (expectations?: Expectations) => { + return await this._get( + `/api/env/variables`, + { expectations } + ) + } + + update = async ( + varName: string, + body: UpdateEnvironmentVariableRequest, + expectations?: Expectations + ) => { + return await this._patch(`/api/env/variables/${varName}`, { + body, + expectations, + }) + } + + destroy = async (varName: string, expectations?: Expectations) => { + return await this._delete(`/api/env/variables/${varName}`, { + expectations, + }) + } +} diff --git a/packages/server/src/tests/utilities/api/index.ts b/packages/server/src/tests/utilities/api/index.ts index 2fdf726b6c..42afd10647 100644 --- a/packages/server/src/tests/utilities/api/index.ts +++ b/packages/server/src/tests/utilities/api/index.ts @@ -17,6 +17,7 @@ import { RowActionAPI } from "./rowAction" import { AutomationAPI } from "./automation" import { PluginAPI } from "./plugin" import { WebhookAPI } from "./webhook" +import { EnvironmentAPI } from "./environment" export default class API { application: ApplicationAPI @@ -24,6 +25,7 @@ export default class API { automation: AutomationAPI backup: BackupAPI datasource: DatasourceAPI + environment: EnvironmentAPI legacyView: LegacyViewAPI permission: PermissionAPI plugin: PluginAPI @@ -44,6 +46,7 @@ export default class API { this.automation = new AutomationAPI(config) this.backup = new BackupAPI(config) this.datasource = new DatasourceAPI(config) + this.environment = new EnvironmentAPI(config) this.legacyView = new LegacyViewAPI(config) this.permission = new PermissionAPI(config) this.plugin = new PluginAPI(config) diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 38d60e1c11..bcad085e08 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -37,6 +37,9 @@ import { DeepPartial, FilterCondition, AutomationTriggerResult, + EnvironmentVariablesDoc, + EnvironmentVariableValue, + CreateEnvironmentVariableRequest, } from "@budibase/types" import { LoopInput } from "../../definitions/automations" import { merge } from "lodash" @@ -574,7 +577,7 @@ export function basicEnvironmentVariable( name: string, prod: string, dev?: string -) { +): CreateEnvironmentVariableRequest { return { name, production: prod,