Offline licensing integration tests

This commit is contained in:
Rory Powell 2023-07-15 00:12:18 +01:00
parent 7449fd97b7
commit ea52013503
6 changed files with 154 additions and 4 deletions

View File

@ -1,5 +1,5 @@
import AccountInternalAPIClient from "../AccountInternalAPIClient" import AccountInternalAPIClient from "../AccountInternalAPIClient"
import { Account, UpdateLicenseRequest } from "@budibase/types" import { Account, CreateOfflineLicenseRequest, GetOfflineLicenseResponse, UpdateLicenseRequest } from "@budibase/types"
import { Response } from "node-fetch" import { Response } from "node-fetch"
export default class LicenseAPI { export default class LicenseAPI {
@ -28,4 +28,44 @@ export default class LicenseAPI {
} }
return [response, json] return [response, json]
} }
// TODO: Better approach for setting tenant id header
async createOfflineLicense(
accountId: string,
tenantId: string,
body: CreateOfflineLicenseRequest,
opts: { status?: number } = {}
): Promise<Response> {
const [response, json] = await this.client.post(
`/api/internal/accounts/${accountId}/license/offline`,
{
body,
internal: true,
headers: {
"x-budibase-tenant-id": tenantId
}
}
)
expect(response.status).toBe(opts.status ? opts.status : 201)
return response
}
async getOfflineLicense(
accountId: string,
tenantId: string,
opts: { status?: number } = {}
): Promise<[Response, GetOfflineLicenseResponse]> {
const [response, json] = await this.client.get(
`/api/internal/accounts/${accountId}/license/offline`,
{
internal: true,
headers: {
"x-budibase-tenant-id": tenantId
}
}
)
expect(response.status).toBe(opts.status ? opts.status : 200)
return [response, json]
}
} }

View File

@ -1,7 +1,7 @@
import { generator } from "../../shared" import { generator } from "../../shared"
import { Hosting, CreateAccountRequest } from "@budibase/types" import { Hosting, CreateAccountRequest } from "@budibase/types"
export const generateAccount = (): CreateAccountRequest => { export const generateAccount = (partial: Partial<CreateAccountRequest>): CreateAccountRequest => {
const uuid = generator.guid() const uuid = generator.guid()
const email = `${uuid}@budibase.com` const email = `${uuid}@budibase.com`
@ -16,5 +16,6 @@ export const generateAccount = (): CreateAccountRequest => {
size: "10+", size: "10+",
tenantId: tenant, tenantId: tenant,
tenantName: tenant, tenantName: tenant,
...partial,
} }
} }

View File

@ -0,0 +1,72 @@
import TestConfiguration from "../../config/TestConfiguration"
import * as fixures from "../../fixtures"
import { Hosting, Feature } from "@budibase/types"
describe("offline", () => {
const config = new TestConfiguration()
beforeAll(async () => {
await config.beforeAll()
})
afterAll(async () => {
await config.afterAll()
})
// TODO: Currently requires a self host install + account portal
// How do we flag this as a self host specific test?
it("creates, activates and deletes offline license", async () => {
// installation: Delete any token
await config.internalApi.license.deleteOfflineLicenseToken()
// installation: Assert token not found
let [getTokenRes] = await config.internalApi.license.getOfflineLicenseToken({ status: 404 })
// installation: Retrieve Identifier
const [getIdentifierRes, identifier] = await config.internalApi.license.getOfflineIdentifier()
// account-portal: Create self-host account
const createAccountRequest = fixures.accounts.generateAccount({ hosting: Hosting.SELF })
const [createAccountRes, account] = await config.accountsApi.accounts.create(createAccountRequest)
const accountId = account.accountId!
const tenantId = account.tenantId!
// account-portal: Enable feature on license
await config.accountsApi.licenses.updateLicense(accountId, {
overrides: {
features: [Feature.OFFLINE]
}
})
// account-portal: Create offline token
const expireAt = new Date()
expireAt.setDate(new Date().getDate() + 1)
await config.accountsApi.licenses.createOfflineLicense(
accountId,
tenantId,
{
expireAt: expireAt.toISOString(),
installationIdentifierBase64: identifier.identifierBase64
})
// account-portal: Retrieve offline token
const [getLicenseRes, offlineLicense] = await config.accountsApi.licenses.getOfflineLicense(accountId, tenantId)
// installation: Activate offline token
await config.internalApi.license.activateOfflineLicenseToken({
offlineLicenseToken: offlineLicense.offlineLicenseToken
})
// installation: Assert token found
await config.internalApi.license.getOfflineLicenseToken()
// TODO: Assert on license for current user
// installation: Remove the token
await config.internalApi.license.deleteOfflineLicenseToken()
// installation: Assert token not found
await config.internalApi.license.getOfflineLicenseToken({ status: 404 })
})
})

View File

@ -11,6 +11,7 @@ import DatasourcesAPI from "./apis/DatasourcesAPI"
import IntegrationsAPI from "./apis/IntegrationsAPI" import IntegrationsAPI from "./apis/IntegrationsAPI"
import QueriesAPI from "./apis/QueriesAPI" import QueriesAPI from "./apis/QueriesAPI"
import PermissionsAPI from "./apis/PermissionsAPI" import PermissionsAPI from "./apis/PermissionsAPI"
import LicenseAPI from "./apis/LicenseAPI"
import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient" import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient"
import { State } from "../../types" import { State } from "../../types"
@ -30,6 +31,7 @@ export default class BudibaseInternalAPI {
integrations: IntegrationsAPI integrations: IntegrationsAPI
queries: QueriesAPI queries: QueriesAPI
permissions: PermissionsAPI permissions: PermissionsAPI
license: LicenseAPI
constructor(state: State) { constructor(state: State) {
this.client = new BudibaseInternalAPIClient(state) this.client = new BudibaseInternalAPIClient(state)
@ -47,5 +49,6 @@ export default class BudibaseInternalAPI {
this.integrations = new IntegrationsAPI(this.client) this.integrations = new IntegrationsAPI(this.client)
this.queries = new QueriesAPI(this.client) this.queries = new QueriesAPI(this.client)
this.permissions = new PermissionsAPI(this.client) this.permissions = new PermissionsAPI(this.client)
this.license = new LicenseAPI(this.client)
} }
} }

View File

@ -8,9 +8,9 @@ export default class BaseAPI {
this.client = client this.client = client
} }
async get(url: string): Promise<[Response, any]> { async get(url: string, status?: number): Promise<[Response, any]> {
const [response, json] = await this.client.get(url) const [response, json] = await this.client.get(url)
expect(response).toHaveStatusCode(200) expect(response).toHaveStatusCode(status ? status : 200)
return [response, json] return [response, json]
} }

View File

@ -0,0 +1,34 @@
import { Response } from "node-fetch"
import {
ActivateOfflineLicenseTokenRequest,
GetOfflineIdentifierResponse,
GetOfflineLicenseTokenResponse,
} from "@budibase/types"
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
import BaseAPI from "./BaseAPI"
export default class LicenseAPI extends BaseAPI {
constructor(client: BudibaseInternalAPIClient) {
super(client)
}
async getOfflineLicenseToken(opts: { status?: number } = {}): Promise<[Response, GetOfflineLicenseTokenResponse]> {
const [response, body] = await this.get(`/global/license/offline`, opts.status)
return [response, body]
}
async deleteOfflineLicenseToken(): Promise<[Response]> {
const [response] = await this.del(`/global/license/offline`, 204)
return [response]
}
async activateOfflineLicenseToken(body: ActivateOfflineLicenseTokenRequest): Promise<[Response]> {
const [response] = await this.post(`/global/license/offline`, body)
return [response]
}
async getOfflineIdentifier(): Promise<[Response, GetOfflineIdentifierResponse]> {
const [response, body] = await this.get(`/global/license/offline/identifier`)
return [response, body]
}
}