Skip to content

Commit 1a3019b

Browse files
committed
more btrfs unit tests
1 parent d087c8e commit 1a3019b

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

src/packages/file-server/btrfs/subvolume.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,11 @@ export class Subvolume {
219219
const s = await this.snapshots();
220220
if (s.length == 0) {
221221
// more than just the SNAPSHOTS directory?
222-
return (await listdir(this.path)).length > 1;
222+
const v = await listdir(this.path);
223+
if (v.length == 0 || (v.length == 1 && v[0] == this.snapshotsDir)) {
224+
return false;
225+
}
226+
return true;
223227
}
224228
const pathGen = await getGeneration(this.path);
225229
const snapGen = await getGeneration(

src/packages/file-server/btrfs/test/setup.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { chmod, mkdtemp, mkdir, rm } from "node:fs/promises";
77
import { tmpdir } from "node:os";
88
import { join } from "path";
99
import { until } from "@cocalc/util/async-utils";
10+
export { sudo } from "../util";
11+
export { delay } from "awaiting";
1012

1113
export let fs: Filesystem;
1214
let tempDir;

src/packages/file-server/btrfs/test/subvolume.test.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { before, after, fs } from "./setup";
2-
import { writeFile } from "fs/promises";
1+
import { before, after, fs, sudo } from "./setup";
2+
import { readFile, writeFile, unlink } from "fs/promises";
33
import { join } from "path";
4-
import { delay } from "awaiting";
54
import { wait } from "@cocalc/backend/conat/test/util";
65
import { randomBytes } from "crypto";
76

@@ -24,7 +23,7 @@ describe("setting and getting quota of a subvolume", () => {
2423
await writeFile(join(vol.path, "buf"), buf);
2524
await wait({
2625
until: async () => {
27-
await delay(1000);
26+
await sudo({ command: "sync" });
2827
const { used } = await vol.usage();
2928
return used > 0;
3029
},
@@ -42,4 +41,54 @@ describe("setting and getting quota of a subvolume", () => {
4241
});
4342
});
4443

44+
describe("test snapshots", () => {
45+
let vol;
46+
it("creates a volume and write a file to it", async () => {
47+
vol = await fs.subvolume("snapper");
48+
expect(await vol.hasUnsavedChanges()).toBe(false);
49+
await writeFile(join(vol.path, "a.txt"), "hello");
50+
expect(await vol.hasUnsavedChanges()).toBe(true);
51+
});
52+
53+
it("snapshot the volume", async () => {
54+
expect(await vol.snapshots()).toEqual([]);
55+
await vol.createSnapshot("snap1");
56+
expect(await vol.snapshots()).toEqual(["snap1"]);
57+
expect(await vol.hasUnsavedChanges()).toBe(false);
58+
});
59+
60+
it("create a file see that we know there are unsaved changes", async () => {
61+
await writeFile(join(vol.path, "b.txt"), "world");
62+
await sudo({ command: "sync" });
63+
expect(await vol.hasUnsavedChanges()).toBe(true);
64+
});
65+
66+
it("delete our file, but then read it in a snapshot", async () => {
67+
await unlink(join(vol.path, "a.txt"));
68+
const b = await readFile(join(vol.snapshotsDir, "snap1", "a.txt"), "utf8");
69+
expect(b).toEqual("hello");
70+
});
71+
72+
it("verifies snapshot exists", async () => {
73+
expect(await vol.snapshotExists("snap1")).toBe(true);
74+
expect(await vol.snapshotExists("snap2")).toBe(false);
75+
});
76+
77+
it("lock our snapshot and confirm it prevents deletion", async () => {
78+
await vol.lockSnapshot("snap1");
79+
expect(async () => {
80+
await vol.deleteSnapshot("snap1");
81+
}).rejects.toThrow("locked");
82+
});
83+
84+
it("unlock our snapshot and delete it", async () => {
85+
await vol.unlockSnapshot("snap1");
86+
await vol.deleteSnapshot("snap1");
87+
expect(await vol.snapshotExists("snap1")).toBe(false);
88+
expect(await vol.snapshots()).toEqual([]);
89+
});
90+
91+
92+
});
93+
4594
afterAll(after);

0 commit comments

Comments
 (0)