Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 153 additions & 4 deletions linux-features/directory-only-working-tree-watch/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,61 @@ test("Watchbound package-set commit rolls back an injected partial failure", asy
);
});

test("the default package commit copies nested and hidden entries into its reservation", (t) => {
const workspace = tempDirectory(t, "watchbound-package-reserved-entries-");
const sourceDir = path.join(workspace, "source");
const targetDir = path.join(workspace, "target");
const nativeBytes = Buffer.from([0, 255, 127, 10]);
writeFile(path.join(sourceDir, ".metadata"), "metadata\n");
writeFile(path.join(sourceDir, "lib", "nested", "owned"), "owned\n", 0o755);
writeFile(path.join(sourceDir, "native.node"), nativeBytes);
fs.mkdirSync(path.join(sourceDir, "empty"));
let reservation;

commitPackageDirectoryNoReplace(sourceDir, targetDir, (identity) => {
reservation = identity;
assert.deepEqual(fs.readdirSync(targetDir), []);
});

const after = fs.lstatSync(targetDir, { bigint: true });
assert.equal(after.dev, reservation.dev);
assert.equal(after.ino, reservation.ino);
assert.deepEqual(fs.readdirSync(targetDir).sort(), [
".metadata", "empty", "lib", "native.node",
]);
assert.equal(fs.readFileSync(path.join(targetDir, ".metadata"), "utf8"), "metadata\n");
assert.equal(
fs.readFileSync(path.join(targetDir, "lib", "nested", "owned"), "utf8"),
"owned\n",
);
assert.equal(fs.statSync(path.join(targetDir, "lib", "nested", "owned")).mode & 0o777, 0o755);
assert.deepEqual(fs.readFileSync(path.join(targetDir, "native.node")), nativeBytes);
assert.deepEqual(fs.readdirSync(path.join(targetDir, "empty")), []);
});

test("the default package commit atomically refuses an empty destination", (t) => {
const workspace = tempDirectory(t, "watchbound-package-empty-no-replace-");
const sourceDir = path.join(workspace, "source");
const targetDir = path.join(workspace, "target");
writeFile(path.join(sourceDir, "owned"), "owned\n");
fs.mkdirSync(targetDir);
const targetIdentity = fs.lstatSync(targetDir, { bigint: true });
let reserved = false;

assert.throws(
() => commitPackageDirectoryNoReplace(sourceDir, targetDir, () => {
reserved = true;
}),
(error) => error?.code === "EEXIST",
);

const after = fs.lstatSync(targetDir, { bigint: true });
assert.equal(reserved, false);
assert.equal(after.dev, targetIdentity.dev);
assert.equal(after.ino, targetIdentity.ino);
assert.deepEqual(fs.readdirSync(targetDir), []);
});

test("the default package commit atomically refuses an existing destination", (t) => {
const workspace = tempDirectory(t, "watchbound-package-no-replace-");
const sourceDir = path.join(workspace, "source");
Expand All @@ -1977,6 +2032,48 @@ test("the default package commit atomically refuses an existing destination", (t
assert.equal(fs.existsSync(path.join(targetDir, "owned")), false);
});

test("the default package copy refuses existing reservation entries", async (t) => {
for (const kind of ["file", "directory", "symlink"]) {
await t.test(kind, (t) => {
const workspace = tempDirectory(t, "watchbound-package-entry-no-replace-");
const sourceDir = path.join(workspace, "source");
const targetDir = path.join(workspace, "target");
const conflictPath = path.join(targetDir, "lib");
const foreignDir = path.join(workspace, "foreign");
writeFile(path.join(sourceDir, "lib", "owned"), "owned\n");
writeFile(path.join(foreignDir, "foreign-owner"), "preserve\n");
let conflictIdentity;
let markerPath;

assert.throws(
() => commitPackageDirectoryNoReplace(sourceDir, targetDir, () => {
if (kind === "file") {
markerPath = conflictPath;
writeFile(markerPath, "preserve\n");
} else if (kind === "directory") {
markerPath = path.join(conflictPath, "foreign-owner");
writeFile(markerPath, "preserve\n");
} else {
markerPath = path.join(foreignDir, "foreign-owner");
fs.symlinkSync(foreignDir, conflictPath, "dir");
}
conflictIdentity = fs.lstatSync(conflictPath, { bigint: true });
}),
(error) => error?.code === "EEXIST",
);

const after = fs.lstatSync(conflictPath, { bigint: true });
assert.equal(after.dev, conflictIdentity.dev);
assert.equal(after.ino, conflictIdentity.ino);
assert.equal(fs.readFileSync(markerPath, "utf8"), "preserve\n");
if (kind !== "file") {
assert.equal(fs.existsSync(path.join(conflictPath, "owned")), false);
}
assert.deepEqual(fs.readdirSync(foreignDir), ["foreign-owner"]);
});
}
});

test("the default package commit rejects a swapped reservation before copying", (t) => {
const workspace = tempDirectory(t, "watchbound-package-reservation-swap-");
const sourceDir = path.join(workspace, "source");
Expand Down Expand Up @@ -2013,11 +2110,16 @@ test("the default package commit verifies reservation identity after copying", (
const movedTarget = path.join(workspace, "moved-target");
const markerPath = path.join(targetDir, "foreign-owner");
writeFile(path.join(sourceDir, "owned"), "owned\n");
writeFile(path.join(sourceDir, "nested", "owned"), "nested\n");
const originalCpSync = fs.cpSync;
let swapped = false;
fs.cpSync = (...args) => {
originalCpSync(...args);
fs.renameSync(targetDir, movedTarget);
writeFile(markerPath, "preserve\n");
if (!swapped) {
swapped = true;
fs.renameSync(targetDir, movedTarget);
writeFile(markerPath, "preserve\n");
}
};

try {
Expand All @@ -2036,6 +2138,8 @@ test("the default package commit verifies reservation identity after copying", (
assert.equal(fs.readFileSync(markerPath, "utf8"), "preserve\n");
assert.equal(fs.existsSync(path.join(targetDir, "owned")), false);
assert.equal(fs.readFileSync(path.join(movedTarget, "owned"), "utf8"), "owned\n");
assert.equal(fs.existsSync(path.join(targetDir, "nested")), false);
assert.equal(fs.readFileSync(path.join(movedTarget, "nested", "owned"), "utf8"), "nested\n");
});

test("the default package copy remains bound to a moved reservation", (t) => {
Expand All @@ -2045,10 +2149,15 @@ test("the default package copy remains bound to a moved reservation", (t) => {
const movedTarget = path.join(workspace, "moved-target");
const markerPath = path.join(targetDir, "foreign-owner");
writeFile(path.join(sourceDir, "owned"), "owned\n");
writeFile(path.join(sourceDir, "nested", "owned"), "nested\n");
const originalCpSync = fs.cpSync;
let swapped = false;
fs.cpSync = (...args) => {
fs.renameSync(targetDir, movedTarget);
writeFile(markerPath, "preserve\n");
if (!swapped) {
swapped = true;
fs.renameSync(targetDir, movedTarget);
writeFile(markerPath, "preserve\n");
}
originalCpSync(...args);
};

Expand All @@ -2068,6 +2177,46 @@ test("the default package copy remains bound to a moved reservation", (t) => {
assert.equal(fs.readFileSync(markerPath, "utf8"), "preserve\n");
assert.equal(fs.existsSync(path.join(targetDir, "owned")), false);
assert.equal(fs.readFileSync(path.join(movedTarget, "owned"), "utf8"), "owned\n");
assert.equal(fs.existsSync(path.join(targetDir, "nested")), false);
assert.equal(fs.readFileSync(path.join(movedTarget, "nested", "owned"), "utf8"), "nested\n");
});

test("the default package-set commit rolls back a partially copied reservation", async (t) => {
const fixture = packageFixtureManifest(t);
const extractedDir = tempDirectory(t, "watchbound-package-copy-rollback-");
writeExtractedAppRuntime(extractedDir);
const firstTarget = packageTarget(extractedDir, fixture.manifest.packages.targets.x64.name);
const originalCpSync = fs.cpSync;
let injected = false;
fs.cpSync = (source, target, options) => {
originalCpSync(source, target, options);
if (
target.startsWith("/proc/self/fd/") &&
path.basename(path.dirname(source)) === "watchbound-node"
) {
injected = true;
assert.equal(fs.existsSync(firstTarget), true);
assert.equal(fs.lstatSync(target).isFile(), true);
throw Object.assign(new Error("injected reserved-entry copy failure"), {
code: "EIO",
});
}
};

try {
await assert.rejects(
stageWatchboundPackages(packageStageOptions(extractedDir, fixture, {
arch: "x64",
materializePackage: fixtureMaterializer(fixture),
})),
/injected reserved-entry copy failure/u,
);
} finally {
fs.cpSync = originalCpSync;
}

assert.equal(injected, true);
assert.deepEqual(fs.readdirSync(extractedDir), ["package.json"]);
});

test("package reservation identity ambiguity is failed-integrity", async (t) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -966,12 +966,25 @@ function copyPackageIntoReservation(sourceDir, targetDir, identity) {
// Linux procfs resolves this path through the already-open directory
// descriptor. A concurrent rename of the public target pathname therefore
// cannot redirect package bytes into a replacement directory.
fs.cpSync(sourceDir, `/proc/self/fd/${identity.descriptor}/.`, {
recursive: true,
dereference: false,
errorOnExist: true,
force: false,
});
const reservationRoot = `/proc/self/fd/${identity.descriptor}`;
// The root already exists because mkdir reserved it. Node 26.10+ correctly
// rejects that root with errorOnExist, so copy its missing children instead.
for (const entry of fs.readdirSync(sourceDir)) {
const destination = path.join(reservationRoot, entry);
// Older Node versions may merge an existing directory even with
// errorOnExist. Refuse existing entries before invoking the copy API.
if (fs.lstatSync(destination, { throwIfNoEntry: false }) != null) {
throw Object.assign(new Error(
`Watchbound package reservation entry already exists: ${destination}`,
), { code: "EEXIST" });
}
fs.cpSync(path.join(sourceDir, entry), destination, {
recursive: true,
dereference: false,
errorOnExist: true,
force: false,
});
}
assertHeldDirectoryIdentity(
identity,
`Watchbound package reservation descriptor identity changed during copy: ${targetDir}`,
Expand Down
Loading