diff --git a/packages/types/src/documents/app/datasource.ts b/packages/types/src/documents/app/datasource.ts index 8dfdfe6d0f..9b498fb4b3 100644 --- a/packages/types/src/documents/app/datasource.ts +++ b/packages/types/src/documents/app/datasource.ts @@ -56,3 +56,11 @@ export interface RestConfig { } ] } + +export interface CreateDatasourceResponse { + datasource: Datasource +} + +export interface UpdatedDatasourceResponse { + datasource: Datasource +} diff --git a/packages/types/src/documents/app/query.ts b/packages/types/src/documents/app/query.ts index 72b6c288a5..d0bbf05b5c 100644 --- a/packages/types/src/documents/app/query.ts +++ b/packages/types/src/documents/app/query.ts @@ -42,3 +42,7 @@ export interface PaginationValues { page: string | number | null limit: number | null } + +export interface PreviewQueryRequest extends Omit { + parameters: {} +} diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts index 9377461a24..262f5505df 100644 --- a/qa-core/src/environment.ts +++ b/qa-core/src/environment.ts @@ -13,6 +13,20 @@ const env = { ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL, BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL, BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD, + POSTGRES_HOST: process.env.POSTGRES_HOST, + POSTGRES_PORT: process.env.POSTGRES_PORT, + POSTGRES_DB: process.env.POSTGRES_DB, + POSTGRES_USER: process.env.POSTGRES_USER, + POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD, + MONGODB_CONNECTION_STRING: process.env.MONGODB_CONNECTION_STRING, + MONGODB_DB: process.env.MONGODB_DB, + REST_API_BASE_URL: process.env.REST_API_BASE_URL, + REST_API_KEY: process.env.REST_API_KEY, + MARIADB_HOST: process.env.MARIADB_HOST, + MARIADB_PORT: process.env.MARIADB_PORT, + MARIADB_DB: process.env.MARIADB_DB, + MARIADB_USER: process.env.MARIADB_USER, + MARIADB_PASSWORD: process.env.MARIADB_PASSWORD, } export = env diff --git a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts b/qa-core/src/internal-api/api/BudibaseInternalAPI.ts index 4796799396..316775b1b9 100644 --- a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts +++ b/qa-core/src/internal-api/api/BudibaseInternalAPI.ts @@ -8,6 +8,9 @@ import SelfAPI from "./apis/SelfAPI" import TableAPI from "./apis/TableAPI" import UserAPI from "./apis/UserAPI" import DatasourcesAPI from "./apis/DatasourcesAPI" +import IntegrationsAPI from "./apis/IntegrationsAPI" +import QueriesAPI from "./apis/QueriesAPI" +import PermissionsAPI from "./apis/PermissionsAPI" import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient" import { State } from "../../types" @@ -24,6 +27,9 @@ export default class BudibaseInternalAPI { tables: TableAPI users: UserAPI datasources: DatasourcesAPI + integrations: IntegrationsAPI + queries: QueriesAPI + permissions: PermissionsAPI constructor(state: State) { this.client = new BudibaseInternalAPIClient(state) @@ -38,5 +44,8 @@ export default class BudibaseInternalAPI { this.tables = new TableAPI(this.client) this.users = new UserAPI(this.client) this.datasources = new DatasourcesAPI(this.client) + this.integrations = new IntegrationsAPI(this.client) + this.queries = new QueriesAPI(this.client) + this.permissions = new PermissionsAPI(this.client) } } diff --git a/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts b/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts index f61692b02f..7b9d7af789 100644 --- a/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts +++ b/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts @@ -1,6 +1,9 @@ import { Response } from "node-fetch" -import { Datasource } from "@budibase/types" -import { AddedDatasource } from "../../../types" +import { + Datasource, + CreateDatasourceResponse, + UpdatedDatasourceResponse, +} from "@budibase/types" import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" export default class DatasourcesAPI { @@ -34,7 +37,7 @@ export default class DatasourcesAPI { return [response, json] } - async add(body: any): Promise<[Response, AddedDatasource]> { + async add(body: any): Promise<[Response, CreateDatasourceResponse]> { const [response, json] = await this.client.post(`/datasources`, { body }) expect(response).toHaveStatusCode(200) expect(json.datasource._id).toBeDefined() @@ -43,7 +46,7 @@ export default class DatasourcesAPI { return [response, json] } - async update(body: any): Promise<[Response, AddedDatasource]> { + async update(body: any): Promise<[Response, UpdatedDatasourceResponse]> { const [response, json] = await this.client.put(`/datasources/${body._id}`, { body, }) diff --git a/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts b/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts new file mode 100644 index 0000000000..b42b999825 --- /dev/null +++ b/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts @@ -0,0 +1,18 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" + +export default class IntegrationsAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async getAll(): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/integrations`) + expect(response).toHaveStatusCode(200) + const integrationsCount = Object.keys(json).length + expect(integrationsCount).toBe(16) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/api/apis/PermissionsAPI.ts b/qa-core/src/internal-api/api/apis/PermissionsAPI.ts new file mode 100644 index 0000000000..e78ef7560d --- /dev/null +++ b/qa-core/src/internal-api/api/apis/PermissionsAPI.ts @@ -0,0 +1,16 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" + +export default class PermissionsAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async getAll(id: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/permissions/${id}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/api/apis/QueriesAPI.ts b/qa-core/src/internal-api/api/apis/QueriesAPI.ts new file mode 100644 index 0000000000..5c8ac9883e --- /dev/null +++ b/qa-core/src/internal-api/api/apis/QueriesAPI.ts @@ -0,0 +1,33 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" +import { PreviewQueryRequest, Query } from "@budibase/types" + +export default class DatasourcesAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async preview(body: PreviewQueryRequest): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries/preview`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async save(body: Query): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async get(queryId: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/queries/${queryId}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/fixtures/index.ts b/qa-core/src/internal-api/fixtures/index.ts index 880ff8d3d9..38291052b8 100644 --- a/qa-core/src/internal-api/fixtures/index.ts +++ b/qa-core/src/internal-api/fixtures/index.ts @@ -5,3 +5,4 @@ export * as screens from "./screens" export * as tables from "./tables" export * as users from "./users" export * as datasources from "./datasources" +export * as queries from "./queries" diff --git a/qa-core/src/internal-api/fixtures/queries.ts b/qa-core/src/internal-api/fixtures/queries.ts new file mode 100644 index 0000000000..7ba81fc744 --- /dev/null +++ b/qa-core/src/internal-api/fixtures/queries.ts @@ -0,0 +1,75 @@ +import { PreviewQueryRequest } from "@budibase/types" + +const query = (datasourceId: string, fields: any): any => { + return { + datasourceId: datasourceId, + fields: fields, + name: "Query 1", + parameters: {}, + queryVerb: "read", + schema: {}, + transformer: "return data", + } +} + +export const mariaDB = (datasourceId: string): PreviewQueryRequest => { + const fields = { + sql: "SELECT * FROM employees LIMIT 10;", + } + return query(datasourceId, fields) +} + +export const mongoDB = (datasourceId: string): PreviewQueryRequest => { + const fields = { + extra: { + collection: "movies", + actionType: "find", + }, + json: "", + } + return query(datasourceId, fields) +} + +export const postgres = (datasourceId: string): PreviewQueryRequest => { + const fields = { + sql: "SELECT * FROM customers;", + } + return query(datasourceId, fields) +} + +export const expectedSchemaFields = { + mariaDB: { + birth_date: "string", + emp_no: "number", + first_name: "string", + gender: "string", + hire_date: "string", + last_name: "string", + }, + mongoDB: { + directors: "array", + genres: "array", + image: "string", + plot: "string", + rank: "number", + rating: "number", + release_date: "string", + running_time_secs: "number", + title: "string", + year: "number", + _id: "json", + }, + postgres: { + address: "string", + city: "string", + company_name: "string", + contact_name: "string", + contact_title: "string", + country: "string", + customer_id: "string", + fax: "string", + phone: "string", + postal_code: "string", + region: "string", + }, +} diff --git a/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts b/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts index 4ff9a7cd0a..44c2c03c8b 100644 --- a/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts +++ b/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts @@ -1,5 +1,6 @@ import TestConfiguration from "../../config/TestConfiguration" import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" describe("Internal API - Data Sources: MariaDB", () => { const config = new TestConfiguration() @@ -16,6 +17,9 @@ describe("Internal API - Data Sources: MariaDB", () => { // Create app await config.createApp() + // Get all integrations + await config.api.integrations.getAll() + // Add data source const [dataSourceResponse, dataSourceJson] = await config.api.datasources.add(fixtures.datasources.mariaDB()) @@ -28,44 +32,38 @@ describe("Internal API - Data Sources: MariaDB", () => { const [updatedDataSourceResponse, updatedDataSourceJson] = await config.api.datasources.update(newDataSourceInfo) - const dataSourceQuery = { - datasourceId: updatedDataSourceJson.datasource._id, - fields: { - sql: "SELECT * FROM employees;", - }, - name: "Query 1", - parameters: {}, - queryVerb: "read", - schema: {}, - transformer: "return data", - } // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!) + ) - const [queryResponse, queryJson] = - await config.api.datasources.previewQuery(dataSourceQuery) + expect(queryJson.rows.length).toEqual(10) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.mariaDB + ) // Save query - const datasourcetoSave = { - ...dataSourceQuery, + const datasourcetoSave: Query = { + ...fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!), parameters: [], } - const [saveQueryResponse, saveQueryJson] = - await config.api.datasources.saveQuery(datasourcetoSave) + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) // Get Query - const [getQueryResponse, getQueryJson] = - await config.api.datasources.getQuery(saveQueryJson._id) + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id + ) // Get Query permissions const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.datasources.getQueryPermissions( - saveQueryJson._id - ) + await config.api.permissions.getAll(saveQueryJson._id!) // Delete data source const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id, - updatedDataSourceJson.datasource._rev + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! ) }) }) diff --git a/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts b/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts index 6c57467930..ed5178b57c 100644 --- a/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts +++ b/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts @@ -1,5 +1,6 @@ import TestConfiguration from "../../config/TestConfiguration" import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" describe("Internal API - Data Sources: MongoDB", () => { const config = new TestConfiguration() @@ -16,6 +17,9 @@ describe("Internal API - Data Sources: MongoDB", () => { // Create app await config.createApp() + // Get all integrations + await config.api.integrations.getAll() + // Add data source const [dataSourceResponse, dataSourceJson] = await config.api.datasources.add(fixtures.datasources.mongoDB()) @@ -28,48 +32,38 @@ describe("Internal API - Data Sources: MongoDB", () => { const [updatedDataSourceResponse, updatedDataSourceJson] = await config.api.datasources.update(newDataSourceInfo) - const dataSourceQuery = { - datasourceId: updatedDataSourceJson.datasource._id, - fields: { - extra: { - collection: "movies", - actionType: "find", - }, - json: "", - }, - name: "Test Query", - parameters: {}, - queryVerb: "read", - schema: {}, - transformer: "return data", - } // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!) + ) - const [queryResponse, queryJson] = - await config.api.datasources.previewQuery(dataSourceQuery) + expect(queryJson.rows.length).toBeGreaterThan(10) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.mongoDB + ) // Save query - const datasourcetoSave = { - ...dataSourceQuery, + const datasourcetoSave: Query = { + ...fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!), parameters: [], } - const [saveQueryResponse, saveQueryJson] = - await config.api.datasources.saveQuery(datasourcetoSave) + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) // Get Query - const [getQueryResponse, getQueryJson] = - await config.api.datasources.getQuery(saveQueryJson._id) + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id + ) // Get Query permissions const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.datasources.getQueryPermissions( - saveQueryJson._id - ) + await config.api.permissions.getAll(saveQueryJson._id!) // Delete data source const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id, - updatedDataSourceJson.datasource._rev + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! ) }) }) diff --git a/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts b/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts index 83d1fc782d..bc8d86b862 100644 --- a/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts +++ b/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts @@ -1,5 +1,6 @@ import TestConfiguration from "../../config/TestConfiguration" import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" describe("Internal API - Data Sources: PostgresSQL", () => { const config = new TestConfiguration() @@ -16,6 +17,9 @@ describe("Internal API - Data Sources: PostgresSQL", () => { // Create app await config.createApp() + // Get all integrations + await config.api.integrations.getAll() + // Add data source const [dataSourceResponse, dataSourceJson] = await config.api.datasources.add(fixtures.datasources.postgresSQL()) @@ -28,44 +32,38 @@ describe("Internal API - Data Sources: PostgresSQL", () => { const [updatedDataSourceResponse, updatedDataSourceJson] = await config.api.datasources.update(newDataSourceInfo) - const dataSourceQuery = { - datasourceId: updatedDataSourceJson.datasource._id, - fields: { - sql: "SELECT * FROM categories;", - }, - name: "Query 1", - parameters: {}, - queryVerb: "read", - schema: {}, - transformer: "return data", - } // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.postgres(updatedDataSourceJson.datasource._id!) + ) - const [queryResponse, queryJson] = - await config.api.datasources.previewQuery(dataSourceQuery) + expect(queryJson.rows.length).toEqual(91) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.postgres + ) // Save query - const datasourcetoSave = { - ...dataSourceQuery, + const datasourcetoSave: Query = { + ...fixtures.queries.postgres(updatedDataSourceJson.datasource._id!), parameters: [], } - const [saveQueryResponse, saveQueryJson] = - await config.api.datasources.saveQuery(datasourcetoSave) + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) // Get Query - const [getQueryResponse, getQueryJson] = - await config.api.datasources.getQuery(saveQueryJson._id) + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id! + ) // Get Query permissions const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.datasources.getQueryPermissions( - saveQueryJson._id - ) + await config.api.permissions.getAll(saveQueryJson._id!) // Delete data source const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id, - updatedDataSourceJson.datasource._rev + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! ) }) }) diff --git a/qa-core/src/types/addedDatasource.ts b/qa-core/src/types/addedDatasource.ts deleted file mode 100644 index 65f51fd1bd..0000000000 --- a/qa-core/src/types/addedDatasource.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Datasource } from "@budibase/types" - -export interface AddedDatasource { - datasource: Datasource -}