Updating app backup exports to not include automation logs as these bloat the backups.
This commit is contained in:
parent
9229ab6896
commit
41d99f6a58
|
@ -3,6 +3,7 @@ const mockS3 = {
|
||||||
deleteObject: jest.fn().mockReturnThis(),
|
deleteObject: jest.fn().mockReturnThis(),
|
||||||
deleteObjects: jest.fn().mockReturnThis(),
|
deleteObjects: jest.fn().mockReturnThis(),
|
||||||
createBucket: jest.fn().mockReturnThis(),
|
createBucket: jest.fn().mockReturnThis(),
|
||||||
|
getObject: jest.fn().mockReturnThis(),
|
||||||
listObject: jest.fn().mockReturnThis(),
|
listObject: jest.fn().mockReturnThis(),
|
||||||
getSignedUrl: jest.fn((operation: string, params: any) => {
|
getSignedUrl: jest.fn((operation: string, params: any) => {
|
||||||
return `http://s3.example.com/${params.Bucket}/${params.Key}`
|
return `http://s3.example.com/${params.Bucket}/${params.Key}`
|
||||||
|
|
|
@ -1,2 +1,7 @@
|
||||||
export const MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
|
export const MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
|
||||||
|
|
||||||
|
export const MOCK_DATE_PLUS = (ms: number) => {
|
||||||
|
return new Date(Date.now() + ms)
|
||||||
|
}
|
||||||
|
|
||||||
export const MOCK_DATE_TIMESTAMP = 1577836800000
|
export const MOCK_DATE_TIMESTAMP = 1577836800000
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3820c0c93a3e448e10a60a9feb5396844b537ca8
|
Subproject commit 132b080643f0b1ef1488bb8362d1c41ea0bd263f
|
|
@ -70,6 +70,13 @@ module AwsMock {
|
||||||
Contents: {},
|
Contents: {},
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
this.getObject = jest.fn(
|
||||||
|
response({
|
||||||
|
Body: "",
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
aws.DynamoDB = { DocumentClient }
|
aws.DynamoDB = { DocumentClient }
|
||||||
|
|
|
@ -5,6 +5,8 @@ import sdk from "../../../sdk"
|
||||||
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||||
import { mocks } from "@budibase/backend-core/tests"
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
mocks.licenses.useBackups()
|
||||||
|
|
||||||
describe("/backups", () => {
|
describe("/backups", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
let config = setup.getConfig()
|
let config = setup.getConfig()
|
||||||
|
@ -15,13 +17,13 @@ describe("/backups", () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("exportAppDump", () => {
|
describe("/api/backups/export", () => {
|
||||||
it("should be able to export app", async () => {
|
it("should be able to export app", async () => {
|
||||||
const res = await request
|
const { body, headers } = await config.api.backup.exportBasicBackup(
|
||||||
.post(`/api/backups/export?appId=${config.getAppId()}`)
|
config.getAppId()!
|
||||||
.set(config.defaultHeaders())
|
)
|
||||||
.expect(200)
|
expect(body instanceof Buffer).toBe(true)
|
||||||
expect(res.headers["content-type"]).toEqual("application/gzip")
|
expect(headers["content-type"]).toEqual("application/gzip")
|
||||||
expect(events.app.exported).toBeCalledTimes(1)
|
expect(events.app.exported).toBeCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -36,11 +38,11 @@ describe("/backups", () => {
|
||||||
it("should infer the app name from the app", async () => {
|
it("should infer the app name from the app", async () => {
|
||||||
tk.freeze(mocks.date.MOCK_DATE)
|
tk.freeze(mocks.date.MOCK_DATE)
|
||||||
|
|
||||||
const res = await request
|
const { headers } = await config.api.backup.exportBasicBackup(
|
||||||
.post(`/api/backups/export?appId=${config.getAppId()}`)
|
config.getAppId()!
|
||||||
.set(config.defaultHeaders())
|
)
|
||||||
|
|
||||||
expect(res.headers["content-disposition"]).toEqual(
|
expect(headers["content-disposition"]).toEqual(
|
||||||
`attachment; filename="${
|
`attachment; filename="${
|
||||||
config.getApp()!.name
|
config.getApp()!.name
|
||||||
}-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"`
|
}-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"`
|
||||||
|
@ -48,6 +50,21 @@ describe("/backups", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("/api/backups/import", () => {
|
||||||
|
it("should be able to import an app", async () => {
|
||||||
|
const appId = config.getAppId()!
|
||||||
|
const automation = await config.createAutomation()
|
||||||
|
await config.createAutomationLog(automation, appId)
|
||||||
|
await config.createScreen()
|
||||||
|
const exportRes = await config.api.backup.createBackup(appId)
|
||||||
|
expect(exportRes.backupId).toBeDefined()
|
||||||
|
const importRes = await config.api.backup.importBackup(
|
||||||
|
appId,
|
||||||
|
exportRes.backupId
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("calculateBackupStats", () => {
|
describe("calculateBackupStats", () => {
|
||||||
it("should be able to calculate the backup statistics", async () => {
|
it("should be able to calculate the backup statistics", async () => {
|
||||||
await config.createAutomation()
|
await config.createAutomation()
|
||||||
|
|
|
@ -84,7 +84,11 @@ export async function exportDB(
|
||||||
}
|
}
|
||||||
|
|
||||||
function defineFilter(excludeRows?: boolean, excludeLogs?: boolean) {
|
function defineFilter(excludeRows?: boolean, excludeLogs?: boolean) {
|
||||||
const ids = [USER_METDATA_PREFIX, LINK_USER_METADATA_PREFIX]
|
const ids = [
|
||||||
|
USER_METDATA_PREFIX,
|
||||||
|
LINK_USER_METADATA_PREFIX,
|
||||||
|
AUTOMATION_LOG_PREFIX,
|
||||||
|
]
|
||||||
if (excludeRows) {
|
if (excludeRows) {
|
||||||
ids.push(TABLE_ROW_PREFIX)
|
ids.push(TABLE_ROW_PREFIX)
|
||||||
}
|
}
|
||||||
|
|
|
@ -774,8 +774,9 @@ class TestConfiguration {
|
||||||
|
|
||||||
// AUTOMATION LOG
|
// AUTOMATION LOG
|
||||||
|
|
||||||
async createAutomationLog(automation: Automation) {
|
async createAutomationLog(automation: Automation, appId?: string) {
|
||||||
return await context.doInAppContext(this.getProdAppId(), async () => {
|
appId = appId || this.getProdAppId()
|
||||||
|
return await context.doInAppContext(appId!, async () => {
|
||||||
return await pro.sdk.automations.logs.storeLog(
|
return await pro.sdk.automations.logs.storeLog(
|
||||||
automation,
|
automation,
|
||||||
basicAutomationResults(automation._id!)
|
basicAutomationResults(automation._id!)
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import {
|
||||||
|
CreateAppBackupResponse,
|
||||||
|
ImportAppBackupResponse,
|
||||||
|
} from "@budibase/types"
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI } from "./base"
|
||||||
|
import tk from "timekeeper"
|
||||||
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
export class BackupAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
exportBasicBackup = async (appId: string) => {
|
||||||
|
const result = await this.request
|
||||||
|
.post(`/api/backups/export?appId=${appId}`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /application\/gzip/)
|
||||||
|
.expect(200)
|
||||||
|
return {
|
||||||
|
body: result.body as Buffer,
|
||||||
|
headers: result.headers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createBackup = async (appId: string) => {
|
||||||
|
tk.freeze(mocks.date.MOCK_DATE_PLUS(1))
|
||||||
|
const result = await this.request
|
||||||
|
.post(`/api/apps/${appId}/backups`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
return result.body as CreateAppBackupResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
importBackup = async (
|
||||||
|
appId: string,
|
||||||
|
backupId: string
|
||||||
|
): Promise<ImportAppBackupResponse> => {
|
||||||
|
tk.freeze(mocks.date.MOCK_DATE_PLUS(1))
|
||||||
|
const result = await this.request
|
||||||
|
.post(`/api/apps/${appId}/backups/${backupId}/import`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
return result.body as ImportAppBackupResponse
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import { DatasourceAPI } from "./datasource"
|
||||||
import { LegacyViewAPI } from "./legacyView"
|
import { LegacyViewAPI } from "./legacyView"
|
||||||
import { ScreenAPI } from "./screen"
|
import { ScreenAPI } from "./screen"
|
||||||
import { ApplicationAPI } from "./application"
|
import { ApplicationAPI } from "./application"
|
||||||
|
import { BackupAPI } from "./backup"
|
||||||
|
|
||||||
export default class API {
|
export default class API {
|
||||||
table: TableAPI
|
table: TableAPI
|
||||||
|
@ -17,6 +18,7 @@ export default class API {
|
||||||
datasource: DatasourceAPI
|
datasource: DatasourceAPI
|
||||||
screen: ScreenAPI
|
screen: ScreenAPI
|
||||||
application: ApplicationAPI
|
application: ApplicationAPI
|
||||||
|
backup: BackupAPI
|
||||||
|
|
||||||
constructor(config: TestConfiguration) {
|
constructor(config: TestConfiguration) {
|
||||||
this.table = new TableAPI(config)
|
this.table = new TableAPI(config)
|
||||||
|
@ -27,5 +29,6 @@ export default class API {
|
||||||
this.datasource = new DatasourceAPI(config)
|
this.datasource = new DatasourceAPI(config)
|
||||||
this.screen = new ScreenAPI(config)
|
this.screen = new ScreenAPI(config)
|
||||||
this.application = new ApplicationAPI(config)
|
this.application = new ApplicationAPI(config)
|
||||||
|
this.backup = new BackupAPI(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,3 +20,8 @@ export interface CreateAppBackupResponse {
|
||||||
export interface UpdateAppBackupRequest {
|
export interface UpdateAppBackupRequest {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ImportAppBackupResponse {
|
||||||
|
restoreId: string
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue