@saltcorn/admin-models 1.6.3-beta.1 → 1.7.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.cjs +18 -0
- package/cjs/models/backup-retention.cjs +18 -0
- package/cjs/models/backup.cjs +18 -0
- package/cjs/models/config-check.cjs +18 -0
- package/cjs/models/file-globs.cjs +18 -0
- package/cjs/models/pack.cjs +18 -0
- package/cjs/models/snapshot.cjs +18 -0
- package/cjs/models/tenant.cjs +18 -0
- package/cjs/models/zip-extract.cjs +18 -0
- package/cjs/models/zip-format.cjs +18 -0
- package/cjs/models/zip-worker.cjs +18 -0
- package/cjs/models/zip-writer.cjs +18 -0
- package/cjs/models/zip.cjs +18 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -18
- package/dist/index.js.map +1 -1
- package/dist/models/backup-retention.d.ts +57 -0
- package/dist/models/backup-retention.d.ts.map +1 -0
- package/dist/models/backup-retention.js +108 -0
- package/dist/models/backup-retention.js.map +1 -0
- package/dist/models/backup.d.ts +7 -3
- package/dist/models/backup.d.ts.map +1 -1
- package/dist/models/backup.js +479 -409
- package/dist/models/backup.js.map +1 -1
- package/dist/models/config-check.d.ts +2 -1
- package/dist/models/config-check.d.ts.map +1 -1
- package/dist/models/config-check.js +16 -23
- package/dist/models/config-check.js.map +1 -1
- package/dist/models/file-globs.d.ts +34 -0
- package/dist/models/file-globs.d.ts.map +1 -0
- package/dist/models/file-globs.js +47 -0
- package/dist/models/file-globs.js.map +1 -0
- package/dist/models/pack.d.ts +3 -2
- package/dist/models/pack.d.ts.map +1 -1
- package/dist/models/pack.js +147 -151
- package/dist/models/pack.js.map +1 -1
- package/dist/models/snapshot.d.ts +1 -1
- package/dist/models/snapshot.d.ts.map +1 -1
- package/dist/models/snapshot.js +26 -29
- package/dist/models/snapshot.js.map +1 -1
- package/dist/models/tenant.d.ts +1 -1
- package/dist/models/tenant.d.ts.map +1 -1
- package/dist/models/tenant.js +45 -48
- package/dist/models/tenant.js.map +1 -1
- package/dist/models/zip-extract.d.ts +14 -0
- package/dist/models/zip-extract.d.ts.map +1 -0
- package/dist/models/zip-extract.js +110 -0
- package/dist/models/zip-extract.js.map +1 -0
- package/dist/models/zip-format.d.ts +57 -0
- package/dist/models/zip-format.d.ts.map +1 -0
- package/dist/models/zip-format.js +106 -0
- package/dist/models/zip-format.js.map +1 -0
- package/dist/models/zip-worker.d.ts +2 -0
- package/dist/models/zip-worker.d.ts.map +1 -0
- package/dist/models/zip-worker.js +177 -0
- package/dist/models/zip-worker.js.map +1 -0
- package/dist/models/zip-writer.d.ts +75 -0
- package/dist/models/zip-writer.d.ts.map +1 -0
- package/dist/models/zip-writer.js +321 -0
- package/dist/models/zip-writer.js.map +1 -0
- package/dist/models/zip.d.ts +101 -0
- package/dist/models/zip.d.ts.map +1 -0
- package/dist/models/zip.js +211 -0
- package/dist/models/zip.js.map +1 -0
- package/dist/tests/backup-retention.test.d.ts +2 -0
- package/dist/tests/backup-retention.test.d.ts.map +1 -0
- package/dist/tests/backup-retention.test.js +134 -0
- package/dist/tests/backup-retention.test.js.map +1 -0
- package/dist/tests/backup.test.d.ts +2 -0
- package/dist/tests/backup.test.d.ts.map +1 -0
- package/dist/tests/backup.test.js +385 -0
- package/dist/tests/backup.test.js.map +1 -0
- package/dist/tests/cfgcheck.test.d.ts +2 -0
- package/dist/tests/cfgcheck.test.d.ts.map +1 -0
- package/dist/tests/cfgcheck.test.js +32 -0
- package/dist/tests/cfgcheck.test.js.map +1 -0
- package/dist/tests/file-globs.test.d.ts +2 -0
- package/dist/tests/file-globs.test.d.ts.map +1 -0
- package/dist/tests/file-globs.test.js +66 -0
- package/dist/tests/file-globs.test.js.map +1 -0
- package/dist/tests/pack.test.d.ts +2 -0
- package/dist/tests/pack.test.d.ts.map +1 -0
- package/dist/tests/pack.test.js +780 -0
- package/dist/tests/pack.test.js.map +1 -0
- package/dist/tests/random.test.d.ts +2 -0
- package/dist/tests/random.test.d.ts.map +1 -0
- package/dist/tests/random.test.js +150 -0
- package/dist/tests/random.test.js.map +1 -0
- package/dist/tests/tenant.test.d.ts +2 -0
- package/dist/tests/tenant.test.d.ts.map +1 -0
- package/dist/tests/tenant.test.js +106 -0
- package/dist/tests/tenant.test.js.map +1 -0
- package/dist/tests/zip.test.d.ts +2 -0
- package/dist/tests/zip.test.d.ts.map +1 -0
- package/dist/tests/zip.test.js +319 -0
- package/dist/tests/zip.test.js.map +1 -0
- package/gen-cjs-shims.cjs +71 -0
- package/package.json +39 -29
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-retention.test.d.ts","sourceRoot":"","sources":["../../tests/backup-retention.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { selectBackupsToDelete, selectBackupsToDeleteGrouped, } from "../models/backup-retention.js";
|
|
2
|
+
import { describe, it, expect } from "@saltcorn/db-common/test_expect";
|
|
3
|
+
const mkEntry = (iso, key) => ({
|
|
4
|
+
key: key || `sc-backup-Site-${iso}.zip`,
|
|
5
|
+
date: new Date(`${iso}T03:00:00Z`),
|
|
6
|
+
});
|
|
7
|
+
/** N consecutive daily backups ending at `end` (inclusive), newest last */
|
|
8
|
+
const dailySeries = (end, n, prefix = "Site") => {
|
|
9
|
+
const endDate = new Date(`${end}T03:00:00Z`);
|
|
10
|
+
const out = [];
|
|
11
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
12
|
+
const d = new Date(endDate.getTime() - i * 86400000);
|
|
13
|
+
const iso = d.toISOString().slice(0, 10);
|
|
14
|
+
out.push({ key: `sc-backup-${prefix}-${iso}.zip`, date: d });
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
};
|
|
18
|
+
const policy = (p) => ({
|
|
19
|
+
keep_daily: 0,
|
|
20
|
+
keep_weekly: 0,
|
|
21
|
+
keep_monthly: 0,
|
|
22
|
+
keep_yearly: 0,
|
|
23
|
+
keep_min: 0,
|
|
24
|
+
...p,
|
|
25
|
+
});
|
|
26
|
+
describe("selectBackupsToDelete", () => {
|
|
27
|
+
it("returns nothing for an empty list", () => {
|
|
28
|
+
expect(selectBackupsToDelete([], policy({ keep_daily: 7 }))).toEqual([]);
|
|
29
|
+
});
|
|
30
|
+
it("keeps the last N daily backups", () => {
|
|
31
|
+
const entries = dailySeries("2026-07-26", 30);
|
|
32
|
+
const del = selectBackupsToDelete(entries, policy({ keep_daily: 7 }));
|
|
33
|
+
expect(del).toHaveLength(23);
|
|
34
|
+
const deletedKeys = new Set(del.map((e) => e.key));
|
|
35
|
+
// the 7 newest must survive
|
|
36
|
+
for (const e of entries.slice(-7))
|
|
37
|
+
expect(deletedKeys.has(e.key)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
it("keeps one backup per ISO week for keep_weekly", () => {
|
|
40
|
+
const entries = dailySeries("2026-07-26", 28); // 4+ ISO weeks
|
|
41
|
+
const del = selectBackupsToDelete(entries, policy({ keep_weekly: 4 }));
|
|
42
|
+
const kept = entries.filter((e) => !del.includes(e));
|
|
43
|
+
expect(kept).toHaveLength(4);
|
|
44
|
+
// one kept backup per week, all on distinct days
|
|
45
|
+
const days = new Set(kept.map((e) => e.date.toISOString().slice(0, 10)));
|
|
46
|
+
expect(days.size).toBe(4);
|
|
47
|
+
});
|
|
48
|
+
it("a single backup can satisfy multiple tiers", () => {
|
|
49
|
+
const entries = [mkEntry("2026-07-26")];
|
|
50
|
+
const del = selectBackupsToDelete(entries, policy({
|
|
51
|
+
keep_daily: 7,
|
|
52
|
+
keep_weekly: 4,
|
|
53
|
+
keep_monthly: 12,
|
|
54
|
+
keep_yearly: 3,
|
|
55
|
+
}));
|
|
56
|
+
expect(del).toEqual([]);
|
|
57
|
+
});
|
|
58
|
+
it("combined GFS policy over a year of daily backups", () => {
|
|
59
|
+
const entries = dailySeries("2026-07-26", 365);
|
|
60
|
+
const del = selectBackupsToDelete(entries, policy({
|
|
61
|
+
keep_daily: 7,
|
|
62
|
+
keep_weekly: 4,
|
|
63
|
+
keep_monthly: 12,
|
|
64
|
+
keep_yearly: 3,
|
|
65
|
+
}));
|
|
66
|
+
const kept = entries.length - del.length;
|
|
67
|
+
// 7 daily + 4 weekly + 12 monthly + yearly, minus overlaps
|
|
68
|
+
expect(kept).toBeGreaterThanOrEqual(12);
|
|
69
|
+
expect(kept).toBeLessThanOrEqual(26);
|
|
70
|
+
});
|
|
71
|
+
it("keep_min prevents deleting the last backups even when all are old", () => {
|
|
72
|
+
// 5 backups, all several years old, policy window long passed
|
|
73
|
+
const entries = dailySeries("2020-01-05", 5);
|
|
74
|
+
const del = selectBackupsToDelete(entries, policy({ keep_daily: 7, keep_min: 3 }));
|
|
75
|
+
// keep_daily keeps 5 (each its own day-bucket within capacity 7)
|
|
76
|
+
expect(del).toEqual([]);
|
|
77
|
+
// stricter: only 1 daily slot, keep_min=3 → exactly 2 deleted
|
|
78
|
+
const del2 = selectBackupsToDelete(entries, policy({ keep_daily: 1, keep_min: 3 }));
|
|
79
|
+
expect(del2).toHaveLength(2);
|
|
80
|
+
});
|
|
81
|
+
it("never deletes everything when keep_min > 0", () => {
|
|
82
|
+
const entries = dailySeries("2019-06-01", 10);
|
|
83
|
+
const del = selectBackupsToDelete(entries, policy({ keep_min: 1 }));
|
|
84
|
+
expect(del).toHaveLength(9);
|
|
85
|
+
// the newest is the one retained
|
|
86
|
+
expect(del.map((e) => e.key)).not.toContain(entries[9].key);
|
|
87
|
+
});
|
|
88
|
+
it("keeps the newest backup of each of the last N months", () => {
|
|
89
|
+
// one backup every 5 days for a year
|
|
90
|
+
const entries = [];
|
|
91
|
+
const end = new Date("2026-07-26T03:00:00Z").getTime();
|
|
92
|
+
for (let i = 72; i >= 0; i--) {
|
|
93
|
+
const d = new Date(end - i * 5 * 86400000);
|
|
94
|
+
entries.push({
|
|
95
|
+
key: `sc-backup-Site-${d.toISOString().slice(0, 10)}.zip`,
|
|
96
|
+
date: d,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const del = selectBackupsToDelete(entries, policy({ keep_monthly: 3 }));
|
|
100
|
+
const kept = entries.filter((e) => !del.includes(e));
|
|
101
|
+
expect(kept).toHaveLength(3);
|
|
102
|
+
const months = new Set(kept.map((e) => e.date.toISOString().slice(0, 7)));
|
|
103
|
+
expect(months.size).toBe(3);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("selectBackupsToDeleteGrouped", () => {
|
|
107
|
+
it("applies the policy per tenant", () => {
|
|
108
|
+
const root = dailySeries("2026-07-26", 10, "Root");
|
|
109
|
+
const t1 = dailySeries("2026-07-26", 10, "tenant1");
|
|
110
|
+
const del = selectBackupsToDeleteGrouped([...root, ...t1], policy({ keep_daily: 7 }));
|
|
111
|
+
// 3 deleted per tenant — tenants do not steal each other's slots
|
|
112
|
+
expect(del).toHaveLength(6);
|
|
113
|
+
expect(del.filter((e) => e.key.includes("Root"))).toHaveLength(3);
|
|
114
|
+
expect(del.filter((e) => e.key.includes("tenant1"))).toHaveLength(3);
|
|
115
|
+
});
|
|
116
|
+
it("groups by basename, ignoring the key path prefix", () => {
|
|
117
|
+
const withPrefix = dailySeries("2026-07-26", 10).map((e) => ({
|
|
118
|
+
...e,
|
|
119
|
+
key: `backups/prod/${e.key}`,
|
|
120
|
+
}));
|
|
121
|
+
const del = selectBackupsToDeleteGrouped(withPrefix, policy({ keep_daily: 7 }));
|
|
122
|
+
expect(del).toHaveLength(3);
|
|
123
|
+
});
|
|
124
|
+
it("groups non-matching filenames by their own basename", () => {
|
|
125
|
+
const odd = {
|
|
126
|
+
key: "manual-export.zip",
|
|
127
|
+
date: new Date("2020-01-01T00:00:00Z"),
|
|
128
|
+
};
|
|
129
|
+
const del = selectBackupsToDeleteGrouped([odd, ...dailySeries("2026-07-26", 3)], policy({ keep_daily: 1, keep_min: 1 }));
|
|
130
|
+
// the odd file forms its own group and is kept by its own keep_min
|
|
131
|
+
expect(del.map((e) => e.key)).not.toContain("manual-export.zip");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=backup-retention.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-retention.test.js","sourceRoot":"","sources":["../../tests/backup-retention.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.test.d.ts","sourceRoot":"","sources":["../../tests/backup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import db from "@saltcorn/data/db/index";
|
|
2
|
+
import { getState } from "@saltcorn/data/db/state";
|
|
3
|
+
import basePlugin from "@saltcorn/data/base-plugin";
|
|
4
|
+
getState().registerPlugin("base", basePlugin);
|
|
5
|
+
import backup from "../models/backup.js";
|
|
6
|
+
const { create_backup, restore, auto_backup_now } = backup;
|
|
7
|
+
import reset from "@saltcorn/data/db/reset_schema";
|
|
8
|
+
import fixtures from "@saltcorn/data/db/fixtures";
|
|
9
|
+
import { unlink, mkdtemp, writeFile, readdir, rm, stat } from "fs/promises";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { tmpdir } from "os";
|
|
12
|
+
import Table from "@saltcorn/data/models/table";
|
|
13
|
+
import View from "@saltcorn/data/models/view";
|
|
14
|
+
import User from "@saltcorn/data/models/user";
|
|
15
|
+
import * as config from "@saltcorn/data/models/config";
|
|
16
|
+
const { setConfig, getConfig } = config;
|
|
17
|
+
import Trigger from "@saltcorn/data/models/trigger";
|
|
18
|
+
import Library from "@saltcorn/data/models/library";
|
|
19
|
+
import MetaData from "@saltcorn/data/models/metadata";
|
|
20
|
+
import Role from "@saltcorn/data/models/role";
|
|
21
|
+
import WorkflowStep from "@saltcorn/data/models/workflow_step";
|
|
22
|
+
import { assertIsSet, assertsObjectIsUser, } from "@saltcorn/data/tests/assertions";
|
|
23
|
+
import { afterAll, describe, it, expect, beforeAll, jest, } from "@saltcorn/db-common/test_expect";
|
|
24
|
+
import Field from "@saltcorn/data/models/field";
|
|
25
|
+
import File from "@saltcorn/data/models/file";
|
|
26
|
+
import Zip from "adm-zip";
|
|
27
|
+
import * as mocks from "@saltcorn/data/tests/mocks";
|
|
28
|
+
const { mockReqRes, plugin_with_routes } = mocks;
|
|
29
|
+
afterAll(db.close);
|
|
30
|
+
beforeAll(async () => {
|
|
31
|
+
await reset();
|
|
32
|
+
await fixtures();
|
|
33
|
+
getState().registerPlugin("mock_plugin", plugin_with_routes());
|
|
34
|
+
});
|
|
35
|
+
jest.setTimeout(30000);
|
|
36
|
+
describe("Backup and restore", () => {
|
|
37
|
+
it("should create and restore backup", async () => {
|
|
38
|
+
await setConfig("site_name", "backups rule!");
|
|
39
|
+
await setConfig("menu_items", [
|
|
40
|
+
{
|
|
41
|
+
type: "Page",
|
|
42
|
+
label: "a_page",
|
|
43
|
+
min_role: 100,
|
|
44
|
+
pagename: "a_page",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
url: "https://www.bbc.co.uk/news",
|
|
48
|
+
icon: "undefined",
|
|
49
|
+
text: "BBC",
|
|
50
|
+
type: "Link",
|
|
51
|
+
label: "BBC",
|
|
52
|
+
style: "",
|
|
53
|
+
location: "Standard",
|
|
54
|
+
min_role: 100,
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
const sn1 = await getConfig("site_name");
|
|
58
|
+
expect(sn1).toBe("backups rule!");
|
|
59
|
+
await Role.create({ role: "paid", id: 60 });
|
|
60
|
+
await Table.create("myblanktable", { min_role_read: 60 });
|
|
61
|
+
const vtbl = await Table.create("myversionedtable", {
|
|
62
|
+
min_role_read: 80,
|
|
63
|
+
versioned: true,
|
|
64
|
+
});
|
|
65
|
+
await Field.create({
|
|
66
|
+
name: "name",
|
|
67
|
+
type: "String",
|
|
68
|
+
table: vtbl,
|
|
69
|
+
});
|
|
70
|
+
await vtbl.insertRow({ name: "Fred" });
|
|
71
|
+
await vtbl.updateRow({ name: "Sam" }, 1);
|
|
72
|
+
await vtbl.insertRow({ name: 'My \nSp\\ecial "Friend"' });
|
|
73
|
+
await Trigger.create({
|
|
74
|
+
name: "footrig",
|
|
75
|
+
table_id: 1,
|
|
76
|
+
when_trigger: "Insert",
|
|
77
|
+
action: "run_js_code",
|
|
78
|
+
configuration: { code: "console.log('new user')" },
|
|
79
|
+
});
|
|
80
|
+
await Trigger.create({
|
|
81
|
+
name: "hourtrig",
|
|
82
|
+
when_trigger: "Hourly",
|
|
83
|
+
action: "run_js_code",
|
|
84
|
+
configuration: { code: "console.log('cuckoo')" },
|
|
85
|
+
});
|
|
86
|
+
const trigger = await Trigger.create({
|
|
87
|
+
action: "Workflow",
|
|
88
|
+
when_trigger: "Never",
|
|
89
|
+
name: "mywf",
|
|
90
|
+
});
|
|
91
|
+
await WorkflowStep.create({
|
|
92
|
+
trigger_id: trigger.id,
|
|
93
|
+
name: "first_step",
|
|
94
|
+
next_step: "second_step",
|
|
95
|
+
action_name: "run_js_code",
|
|
96
|
+
initial_step: true,
|
|
97
|
+
configuration: { code: `return {x:1}` },
|
|
98
|
+
});
|
|
99
|
+
await WorkflowStep.create({
|
|
100
|
+
trigger_id: trigger.id,
|
|
101
|
+
name: "second_step",
|
|
102
|
+
next_step: "third_step",
|
|
103
|
+
action_name: "run_js_code",
|
|
104
|
+
initial_step: false,
|
|
105
|
+
configuration: { code: `return {y:x+1}` },
|
|
106
|
+
});
|
|
107
|
+
await Library.create({
|
|
108
|
+
name: "foo",
|
|
109
|
+
icon: "fa-bar",
|
|
110
|
+
layout: { baz: "bar" },
|
|
111
|
+
});
|
|
112
|
+
await MetaData.create({
|
|
113
|
+
type: "PromptSummary",
|
|
114
|
+
name: "View45",
|
|
115
|
+
user_id: 1,
|
|
116
|
+
written_at: new Date(),
|
|
117
|
+
body: { foo: { bar: 1 }, baz: 7 },
|
|
118
|
+
});
|
|
119
|
+
await Table.create("JoeTable", {
|
|
120
|
+
provider_name: "provtab",
|
|
121
|
+
provider_cfg: { middle_name: "Robinette" },
|
|
122
|
+
});
|
|
123
|
+
await User.table.update({
|
|
124
|
+
min_role_read: 40,
|
|
125
|
+
description: "Users are the best",
|
|
126
|
+
});
|
|
127
|
+
await getState().refresh_tables();
|
|
128
|
+
const fnm = await create_backup();
|
|
129
|
+
const t1 = Table.findOne({ name: "books" });
|
|
130
|
+
assertIsSet(t1);
|
|
131
|
+
const t1c = await t1.countRows();
|
|
132
|
+
const v1 = await View.find();
|
|
133
|
+
expect(!!t1).toBe(true);
|
|
134
|
+
await reset();
|
|
135
|
+
const admu = await User.create({
|
|
136
|
+
email: "admin@foo.com",
|
|
137
|
+
password: "AhGGr6rhu45",
|
|
138
|
+
role_id: 1,
|
|
139
|
+
});
|
|
140
|
+
assertsObjectIsUser(admu);
|
|
141
|
+
expect(typeof admu.password).toBe("string");
|
|
142
|
+
expect(User.table.min_role_read).toBe(1);
|
|
143
|
+
const t2 = Table.findOne({ name: "books" });
|
|
144
|
+
expect(t2).toBe(null);
|
|
145
|
+
const sn0 = await getConfig("site_name");
|
|
146
|
+
expect(sn0).toBe("Saltcorn");
|
|
147
|
+
const menus0 = await getConfig("menu_items", []);
|
|
148
|
+
expect(menus0.length).toBe(7); // newly liberated menu items
|
|
149
|
+
//restore
|
|
150
|
+
const restore_res = await restore(fnm, (p) => { });
|
|
151
|
+
await unlink(fnm);
|
|
152
|
+
expect(restore_res).toBe(undefined);
|
|
153
|
+
const t3 = Table.findOne({ name: "books" });
|
|
154
|
+
assertIsSet(t3);
|
|
155
|
+
expect(!!t3).toBe(true);
|
|
156
|
+
const t5 = Table.findOne({ name: "myblanktable" });
|
|
157
|
+
assertIsSet(t5);
|
|
158
|
+
const t6 = Table.findOne({ name: "myversionedtable" });
|
|
159
|
+
assertIsSet(t6);
|
|
160
|
+
const vhist = await t6.get_history();
|
|
161
|
+
expect(vhist.length).toBe(3);
|
|
162
|
+
const t6row = await t6.getRow({ id: 2 });
|
|
163
|
+
assertIsSet(t6row);
|
|
164
|
+
expect(t6row.name).toBe('My \nSp\\ecial "Friend"');
|
|
165
|
+
expect(!!t5).toBe(true);
|
|
166
|
+
expect(t5.min_role_read).toBe(60);
|
|
167
|
+
const t3c = await t3.countRows();
|
|
168
|
+
expect(t1c).toBe(t3c);
|
|
169
|
+
const v2 = await View.find();
|
|
170
|
+
expect(v1.length).toBe(v2.length);
|
|
171
|
+
const sn = await getConfig("site_name");
|
|
172
|
+
expect(sn).toBe("backups rule!");
|
|
173
|
+
const menus = await getConfig("menu_items");
|
|
174
|
+
expect(menus.length).toBe(2);
|
|
175
|
+
expect(menus[0].type).toBe("Page");
|
|
176
|
+
expect(menus[0].pagename).toBe("a_page");
|
|
177
|
+
expect(menus[1].type).toBe("Link");
|
|
178
|
+
expect(menus[1].url).toBe("https://www.bbc.co.uk/news");
|
|
179
|
+
await t3.insertRow({ author: "Marcus Rediker", pages: 224 });
|
|
180
|
+
const staff = await User.findOne({ email: "staff@foo.com" });
|
|
181
|
+
expect(!!staff).toBe(true);
|
|
182
|
+
assertsObjectIsUser(staff);
|
|
183
|
+
expect(typeof staff.password).toBe("string");
|
|
184
|
+
const trig = await Trigger.findOne({ name: "footrig" });
|
|
185
|
+
expect(!!trig).toBe(true);
|
|
186
|
+
const htrig = await Trigger.findOne({ name: "hourtrig" });
|
|
187
|
+
expect(!!htrig).toBe(true);
|
|
188
|
+
const mywf = await Trigger.findOne({ name: "mywf" });
|
|
189
|
+
expect(!!mywf).toBe(true);
|
|
190
|
+
const mySteps = await WorkflowStep.find({ trigger_id: mywf.id });
|
|
191
|
+
expect(mySteps.length).toBe(2);
|
|
192
|
+
const lib = await Library.findOne({ name: "foo" });
|
|
193
|
+
expect(!!lib).toBe(true);
|
|
194
|
+
const md = await MetaData.findOne({ type: "PromptSummary" });
|
|
195
|
+
expect(!!md).toBe(true);
|
|
196
|
+
expect(md.body.foo.bar).toBe(1);
|
|
197
|
+
const tp = Table.findOne({ name: "JoeTable" });
|
|
198
|
+
expect(tp?.provider_name).toBe("provtab");
|
|
199
|
+
expect(tp?.provider_cfg?.middle_name).toBe("Robinette");
|
|
200
|
+
expect(staff.checkPassword("ghrarhr54hg")).toBe(true);
|
|
201
|
+
expect(User.table.min_role_read).toBe(40);
|
|
202
|
+
expect(User.table.description).toBe("Users are the best");
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe("auto backup retention to local directory", () => {
|
|
206
|
+
it("deletes backups not retained by the tiered policy", async () => {
|
|
207
|
+
const dir = await mkdtemp(join(tmpdir(), "sc-backup-retention-"));
|
|
208
|
+
const prefix = getState().getConfig("backup_file_prefix");
|
|
209
|
+
await getState().setConfig("site_name", "RetTest");
|
|
210
|
+
await getState().setConfig("auto_backup_destination", "Local directory");
|
|
211
|
+
await getState().setConfig("auto_backup_directory", dir);
|
|
212
|
+
await getState().setConfig("auto_backup_retention_mode", "Tiered (GFS)");
|
|
213
|
+
await getState().setConfig("auto_backup_keep_daily", 1);
|
|
214
|
+
await getState().setConfig("auto_backup_keep_weekly", 0);
|
|
215
|
+
await getState().setConfig("auto_backup_keep_monthly", 0);
|
|
216
|
+
await getState().setConfig("auto_backup_keep_yearly", 0);
|
|
217
|
+
await getState().setConfig("auto_backup_keep_min", 1);
|
|
218
|
+
// older backups of the same site, plus files the policy must not touch
|
|
219
|
+
for (const day of ["2020-01-01-00-00", "2020-01-02-00-00"])
|
|
220
|
+
await writeFile(join(dir, `${prefix}RetTest-${day}.zip`), "old");
|
|
221
|
+
await writeFile(join(dir, "not-a-backup.zip"), "keep me");
|
|
222
|
+
await writeFile(join(dir, `${prefix}RetTest-2020-01-03.txt`), "keep me");
|
|
223
|
+
await auto_backup_now();
|
|
224
|
+
const remaining = await readdir(dir);
|
|
225
|
+
// one backup of this site is retained (keep_daily=1, all in one day bucket)
|
|
226
|
+
expect(remaining.filter((f) => f.startsWith(`${prefix}RetTest`) && f.endsWith(".zip"))).toHaveLength(1);
|
|
227
|
+
// files outside the backup prefix or not zips are never deleted
|
|
228
|
+
expect(remaining).toContain("not-a-backup.zip");
|
|
229
|
+
expect(remaining).toContain(`${prefix}RetTest-2020-01-03.txt`);
|
|
230
|
+
await rm(dir, { recursive: true, force: true });
|
|
231
|
+
});
|
|
232
|
+
it("does not delete anything when retention is not configured", async () => {
|
|
233
|
+
const dir = await mkdtemp(join(tmpdir(), "sc-backup-retention-"));
|
|
234
|
+
const prefix = getState().getConfig("backup_file_prefix");
|
|
235
|
+
await getState().setConfig("auto_backup_directory", dir);
|
|
236
|
+
await getState().setConfig("auto_backup_retention_mode", "Expiration");
|
|
237
|
+
await getState().setConfig("auto_backup_expire_days", null);
|
|
238
|
+
for (const day of ["2020-01-01-00-00", "2020-01-02-00-00"])
|
|
239
|
+
await writeFile(join(dir, `${prefix}RetTest-${day}.zip`), "old");
|
|
240
|
+
await auto_backup_now();
|
|
241
|
+
const remaining = await readdir(dir);
|
|
242
|
+
expect(remaining).toContain(`${prefix}RetTest-2020-01-01-00-00.zip`);
|
|
243
|
+
expect(remaining).toContain(`${prefix}RetTest-2020-01-02-00-00.zip`);
|
|
244
|
+
await rm(dir, { recursive: true, force: true });
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
describe("backup file exclusion", () => {
|
|
248
|
+
it("excludes files matching the configured globs", async () => {
|
|
249
|
+
await File.ensure_file_store();
|
|
250
|
+
const mv = async (fnm) => {
|
|
251
|
+
await writeFile(fnm, "cecinestpasunpng");
|
|
252
|
+
};
|
|
253
|
+
await File.from_req_files({ mimetype: "video/mp4", name: "bigvideo.mp4", mv, size: 16 }, 1, 100);
|
|
254
|
+
await File.from_req_files({ mimetype: "image/png", name: "keepme.png", mv, size: 16 }, 1, 100);
|
|
255
|
+
await File.new_folder("cache");
|
|
256
|
+
await File.from_req_files({ mimetype: "image/png", name: "thumb.png", mv, size: 16 }, 1, 100, "cache");
|
|
257
|
+
await getState().setConfig("backup_exclude_file_globs", "*.mp4, cache/**");
|
|
258
|
+
const fnm = await create_backup();
|
|
259
|
+
const zip = new Zip(fnm);
|
|
260
|
+
const entries = zip.getEntries().map((e) => e.entryName);
|
|
261
|
+
const filesCsv = zip.readAsText("files.csv");
|
|
262
|
+
await unlink(fnm);
|
|
263
|
+
await getState().setConfig("backup_exclude_file_globs", "");
|
|
264
|
+
expect(entries).toContain("files/keepme.png");
|
|
265
|
+
expect(entries.filter((e) => e.includes("bigvideo"))).toHaveLength(0);
|
|
266
|
+
expect(entries.filter((e) => e.includes("thumb.png"))).toHaveLength(0);
|
|
267
|
+
// excluded files are also left out of the file metadata
|
|
268
|
+
expect(filesCsv.includes("keepme.png")).toBe(true);
|
|
269
|
+
expect(filesCsv.includes("bigvideo.mp4")).toBe(false);
|
|
270
|
+
expect(filesCsv.includes("thumb.png")).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
it("includes all files when no globs are configured", async () => {
|
|
273
|
+
const fnm = await create_backup();
|
|
274
|
+
const entries = new Zip(fnm)
|
|
275
|
+
.getEntries()
|
|
276
|
+
.map((e) => e.entryName)
|
|
277
|
+
.join("\n");
|
|
278
|
+
await unlink(fnm);
|
|
279
|
+
expect(entries.includes("bigvideo.mp4")).toBe(true);
|
|
280
|
+
expect(entries.includes("keepme.png")).toBe(true);
|
|
281
|
+
expect(entries.includes("thumb.png")).toBe(true);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
describe("backup destinations", () => {
|
|
285
|
+
// backup file names are built from the site name, and the other test files
|
|
286
|
+
// run in parallel in this same working directory - so give this file's
|
|
287
|
+
// backups a name only it produces
|
|
288
|
+
const siteName = "DestTest";
|
|
289
|
+
/** zips of this site left lying around in the working directory */
|
|
290
|
+
const strayBackups = async () => {
|
|
291
|
+
const prefix = getState().getConfig("backup_file_prefix");
|
|
292
|
+
return (await readdir(process.cwd())).filter((f) => f.startsWith(`${prefix}${siteName}-`) && f.endsWith(".zip"));
|
|
293
|
+
};
|
|
294
|
+
it("writes a local directory backup into the directory itself", async () => {
|
|
295
|
+
// the OS temporary directory is usually a different filesystem (tmpfs on
|
|
296
|
+
// most Linux distributions), like the Docker volumes and external drives
|
|
297
|
+
// of issue #4332: the backup must be written where it belongs rather than
|
|
298
|
+
// written elsewhere and renamed, because renaming across filesystems
|
|
299
|
+
// fails with EXDEV
|
|
300
|
+
const dir = await mkdtemp(join(tmpdir(), "sc-backup-dest-"));
|
|
301
|
+
await getState().setConfig("site_name", siteName);
|
|
302
|
+
await getState().setConfig("auto_backup_destination", "Local directory");
|
|
303
|
+
await getState().setConfig("auto_backup_directory", dir);
|
|
304
|
+
await getState().setConfig("auto_backup_retention_mode", "Expiration");
|
|
305
|
+
await getState().setConfig("auto_backup_expire_days", null);
|
|
306
|
+
await auto_backup_now();
|
|
307
|
+
const written = (await readdir(dir)).filter((f) => f.endsWith(".zip"));
|
|
308
|
+
expect(written).toHaveLength(1);
|
|
309
|
+
// and it is a readable backup, not a truncated or empty file
|
|
310
|
+
const zip = new Zip(join(dir, written[0]));
|
|
311
|
+
expect(zip.getEntries().map((e) => e.entryName)).toContain("pack.json");
|
|
312
|
+
// nothing was staged in the working directory on the way there
|
|
313
|
+
expect(await strayBackups()).toHaveLength(0);
|
|
314
|
+
await rm(dir, { recursive: true, force: true });
|
|
315
|
+
});
|
|
316
|
+
it("creates no local file when backing up to Saltcorn files", async () => {
|
|
317
|
+
await File.ensure_file_store();
|
|
318
|
+
await getState().setConfig("site_name", siteName);
|
|
319
|
+
await getState().setConfig("auto_backup_destination", "Saltcorn files");
|
|
320
|
+
// in a folder of its own: on SQLite every test file shares one file
|
|
321
|
+
// store, and a file appearing and disappearing in its root upsets the
|
|
322
|
+
// test files listing it in parallel
|
|
323
|
+
await getState().setConfig("auto_backup_directory", "desttest-backups");
|
|
324
|
+
await auto_backup_now();
|
|
325
|
+
const backupFile = (await File.find({ folder: "desttest-backups", mime_sub: "zip" })).find((f) => f.filename.startsWith(getState().getConfig("backup_file_prefix")));
|
|
326
|
+
assertIsSet(backupFile);
|
|
327
|
+
// the size recorded in the file listing is the size on disk
|
|
328
|
+
const stats = await stat(backupFile.location);
|
|
329
|
+
expect(backupFile.size_kb).toBe(Math.round(stats.size / 1024));
|
|
330
|
+
expect(await strayBackups()).toHaveLength(0);
|
|
331
|
+
await backupFile.delete();
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
describe("encrypted backups", () => {
|
|
335
|
+
const password = "hunter2!";
|
|
336
|
+
afterAll(async () => {
|
|
337
|
+
await getState().setConfig("backup_password", "");
|
|
338
|
+
});
|
|
339
|
+
it("encrypts the backup with the configured password", async () => {
|
|
340
|
+
await getState().setConfig("backup_password", password);
|
|
341
|
+
const fnm = await create_backup();
|
|
342
|
+
try {
|
|
343
|
+
const zip = new Zip(fnm);
|
|
344
|
+
// the entry names are readable, the contents are not
|
|
345
|
+
expect(zip.getEntries().map((e) => e.entryName)).toContain("pack.json");
|
|
346
|
+
expect(() => zip.readFile("pack.json")).toThrow();
|
|
347
|
+
const pack = JSON.parse(zip.readFile("pack.json", password).toString());
|
|
348
|
+
expect(Array.isArray(pack.tables)).toBe(true);
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
await unlink(fnm);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
it("restores an encrypted backup", async () => {
|
|
355
|
+
await getState().setConfig("backup_password", password);
|
|
356
|
+
const fnm = await create_backup();
|
|
357
|
+
try {
|
|
358
|
+
await reset();
|
|
359
|
+
expect(Table.findOne({ name: "books" })).toBe(null);
|
|
360
|
+
const err = await restore(fnm, (p) => { }, true, password);
|
|
361
|
+
expect(err).toBe(undefined);
|
|
362
|
+
const books = Table.findOne({ name: "books" });
|
|
363
|
+
assertIsSet(books);
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
await unlink(fnm);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
it("reports that a password is required when it is missing", async () => {
|
|
370
|
+
await getState().setConfig("backup_password", password);
|
|
371
|
+
const fnm = await create_backup();
|
|
372
|
+
try {
|
|
373
|
+
let error;
|
|
374
|
+
await restore(fnm, (p) => { }, true).catch((e) => {
|
|
375
|
+
error = e;
|
|
376
|
+
});
|
|
377
|
+
expect(error).toBeTruthy();
|
|
378
|
+
expect(error.requiresPassword).toBe(true);
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
await unlink(fnm);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
//# sourceMappingURL=backup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.test.js","sourceRoot":"","sources":["../../tests/backup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cfgcheck.test.d.ts","sourceRoot":"","sources":["../../tests/cfgcheck.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import db from "@saltcorn/data/db/index";
|
|
2
|
+
import { getState } from "@saltcorn/data/db/state";
|
|
3
|
+
import { afterAll, describe, it, expect, beforeAll, jest, } from "@saltcorn/db-common/test_expect";
|
|
4
|
+
import { runConfigurationCheck } from "../models/config-check.js";
|
|
5
|
+
import * as mocks from "@saltcorn/data/tests/mocks";
|
|
6
|
+
import basePlugin from "@saltcorn/data/base-plugin";
|
|
7
|
+
import sbadmin2 from "@saltcorn/sbadmin2";
|
|
8
|
+
import reset from "@saltcorn/data/db/reset_schema";
|
|
9
|
+
import fixtures from "@saltcorn/data/db/fixtures";
|
|
10
|
+
const { mockReqRes } = mocks;
|
|
11
|
+
getState().registerPlugin("base", basePlugin);
|
|
12
|
+
getState().registerPlugin("sbadmin2", sbadmin2);
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
await reset();
|
|
15
|
+
await fixtures();
|
|
16
|
+
});
|
|
17
|
+
afterAll(async () => {
|
|
18
|
+
await db.close();
|
|
19
|
+
});
|
|
20
|
+
jest.setTimeout(30000);
|
|
21
|
+
// todo tests for broken view
|
|
22
|
+
// todo tests for broken trigger / action
|
|
23
|
+
// todo tests for broken page
|
|
24
|
+
describe("config check", () => {
|
|
25
|
+
it("runs", async () => {
|
|
26
|
+
const { errors, passes, pass } = await runConfigurationCheck(mockReqRes.req);
|
|
27
|
+
expect(errors).toStrictEqual([]);
|
|
28
|
+
expect(passes.length).toBeGreaterThan(10);
|
|
29
|
+
expect(pass).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=cfgcheck.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cfgcheck.test.js","sourceRoot":"","sources":["../../tests/cfgcheck.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,EAAE,EACF,MAAM,EACN,SAAS,EACT,IAAI,GACL,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,KAAK,MAAM,4BAA4B,CAAC;AACpD,OAAO,UAAU,MAAM,4BAA4B,CAAC;AACpD,OAAO,QAAQ,MAAM,oBAAoB,CAAC;AAC1C,OAAO,KAAK,MAAM,gCAAgC,CAAC;AACnD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAElD,MAAM,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;AAE7B,QAAQ,EAAG,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC/C,QAAQ,EAAG,CAAC,cAAc,CAAC,UAAU,EAAE,QAAe,CAAC,CAAC;AAExD,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,KAAK,EAAE,CAAC;IACd,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;IAClB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC;AACH,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACvB,6BAA6B;AAC7B,yCAAyC;AACzC,6BAA6B;AAC7B,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACpB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,qBAAqB,CAC1D,UAAU,CAAC,GAAG,CACf,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-globs.test.d.ts","sourceRoot":"","sources":["../../tests/file-globs.test.ts"],"names":[],"mappings":""}
|