Offline licensing integration tests
This commit is contained in:
parent
7449fd97b7
commit
ea52013503
|
@ -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]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 })
|
||||||
|
})
|
||||||
|
})
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue