From d06899cc29ed1ffc448a93bc25fc6a244868f5ff Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Sep 2026 16:12:43 +0000 Subject: [PATCH] Test the live-photo writer's fsyncs (closes #130) A test checks that the live-photo writer fsyncs the image's and the video's temp files before renaming either into place, and fsyncs the directory after both renames, as the writeAtomic test does for one file. Model: opus-5-5 --- TODO.md | 5 +++++ test/download/download.test.ts | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/TODO.md b/TODO.md index e7f30fc..e6c2c8a 100644 --- a/TODO.md +++ b/TODO.md @@ -21,6 +21,11 @@ declares one. # Completed Steps +- 2026-09-28: Tested the live-photo writer's fsyncs (issue 130). A test checks + that the image's and the video's temp files are fsynced before either is + renamed into place, and the directory after both renames, as the `writeAtomic` + test does for one file. + - 2026-09-23: Live photos are stored as their image and their video (issue 107). A live photo, which Ente stores as one ZIP, is unpacked as it downloads into `.` for the image and for the video, each with its extension from diff --git a/test/download/download.test.ts b/test/download/download.test.ts index b361ae8..e08a948 100644 --- a/test/download/download.test.ts +++ b/test/download/download.test.ts @@ -1909,6 +1909,24 @@ describe("downloadFile live photos", () => { ]); }); + it("fsyncs each part's temp file before the renames and the directory after", async () => { + const t = setup(livePhotoZip(), livePhoto); + + await t.run(); + + // The same durability contract as `writeAtomic`, for two files: both + // temp files are on disk before either is renamed into place, and the + // directory is fsynced once both renames are done. + const [imageTmp, videoTmp] = renameHook.calls.map((c) => c.from); + expect(durabilityHook.events).toEqual([ + `sync:w:${imageTmp}`, + `sync:w:${videoTmp}`, + `rename:${join(t.dir, "f.heic")}`, + `rename:${join(t.dir, "f.mov")}`, + `sync:r:${t.dir}`, + ]); + }); + it("stores neither part when the video cannot be renamed into place", async () => { const t = setup(livePhotoZip(), livePhoto); renameHook.failWith = new Error("simulated rename failure"); -- 2.54.0