参考所有分组:完善OPFS参数备份桥接
结论:按 LinuxCNC rs274ngc_pre.cc save_parameters()/restore_parameters() 语义,补齐浏览器 OPFS 参数文件 .bak 持久化;未扩展 smoke 解析行为。 验证:./test-native.sh;./test-linuxcnc-source-link.sh;./test-web-wasm-node-smoke.sh;./test-web-wasm-browser-smoke.sh。
This commit is contained in:
@@ -703,10 +703,19 @@ export async function createWasmSimulator(moduleOptions = {}) {
|
|||||||
throw new Error("OPFS workspace is not available for parameter file persistence");
|
throw new Error("OPFS workspace is not available for parameter file persistence");
|
||||||
}
|
}
|
||||||
cleanupLinuxCncParameterFiles(module);
|
cleanupLinuxCncParameterFiles(module);
|
||||||
await opfs.loadParameterFile(parameterPath);
|
const previousParameterFile = await opfs.loadParameterFile(parameterPath);
|
||||||
try {
|
try {
|
||||||
const events = parseText(program, dialect, options, { keepLinuxCncParameterFiles: true });
|
const events = parseText(program, dialect, options, { keepLinuxCncParameterFiles: true });
|
||||||
await opfs.persistParameterFile(parameterPath);
|
await opfs.persistParameterFile(parameterPath);
|
||||||
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
||||||
|
// links the previous parameter file to filename + ".bak" before
|
||||||
|
// replacing filename. Browser filesystems may not expose that link
|
||||||
|
// through the WASM mirror, so preserve the loaded OPFS file here.
|
||||||
|
if (previousParameterFile === null) {
|
||||||
|
await opfs.removeFile(`${parameterPath}.bak`);
|
||||||
|
} else if (!(await opfs.exists(`${parameterPath}.bak`))) {
|
||||||
|
await opfs.writeFile(`${parameterPath}.bak`, previousParameterFile);
|
||||||
|
}
|
||||||
return events;
|
return events;
|
||||||
} finally {
|
} finally {
|
||||||
cleanupLinuxCncParameterFiles(module);
|
cleanupLinuxCncParameterFiles(module);
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ export async function runBrowserAppOpfsSections(context) {
|
|||||||
const savedParameterFile = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var"));
|
const savedParameterFile = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var"));
|
||||||
expectIncludes(savedParameterFile, "5161\t1.000000",
|
expectIncludes(savedParameterFile, "5161\t1.000000",
|
||||||
"app frame did not persist LinuxCNC parameter state into OPFS");
|
"app frame did not persist LinuxCNC parameter state into OPFS");
|
||||||
|
await appSimulator.fs.opfs.removeFile("parameters/rs274ngc.var.bak");
|
||||||
|
parseAppFrameProgram(appFrame, "G21 G90\nG0 X2\nG28.1\nM30\n");
|
||||||
|
await waitFor(
|
||||||
|
() => appFrame.contentDocument?.querySelector("#axisX")?.value === "2.000",
|
||||||
|
"app frame did not parse second program for parameter backup coverage",
|
||||||
|
);
|
||||||
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
||||||
|
// preserves the previous parameter file as filename + ".bak".
|
||||||
|
const updatedParameterFile = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var"));
|
||||||
|
expectIncludes(updatedParameterFile, "5161\t2.000000",
|
||||||
|
"app frame did not replace LinuxCNC parameter state after second parse");
|
||||||
|
const savedParameterBackup = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var.bak"));
|
||||||
|
expectIncludes(savedParameterBackup, "5161\t1.000000",
|
||||||
|
"app frame did not persist LinuxCNC parameter backup into OPFS");
|
||||||
} finally {
|
} finally {
|
||||||
await disposeAppFrame(appFrame);
|
await disposeAppFrame(appFrame);
|
||||||
}
|
}
|
||||||
@@ -38,7 +52,7 @@ export async function runBrowserAppOpfsSections(context) {
|
|||||||
await waitForAppControls(restoredAppFrame, "restored app frame did not load CNC controls");
|
await waitForAppControls(restoredAppFrame, "restored app frame did not load CNC controls");
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
const restoredInput = restoredAppFrame.contentDocument?.querySelector("#programInput");
|
const restoredInput = restoredAppFrame.contentDocument?.querySelector("#programInput");
|
||||||
return restoredInput?.value === "G21 G90\nG0 X1\nG28.1\nM30\n";
|
return restoredInput?.value === "G21 G90\nG0 X2\nG28.1\nM30\n";
|
||||||
}, "app frame did not restore current program from OPFS after reload");
|
}, "app frame did not restore current program from OPFS after reload");
|
||||||
await waitForAppAlarm(
|
await waitForAppAlarm(
|
||||||
restoredAppFrame,
|
restoredAppFrame,
|
||||||
@@ -48,7 +62,7 @@ export async function runBrowserAppOpfsSections(context) {
|
|||||||
await getAppFrameSimulator(restoredAppFrame, "restored app frame did not create OPFS simulator workspace");
|
await getAppFrameSimulator(restoredAppFrame, "restored app frame did not create OPFS simulator workspace");
|
||||||
parseAppFrameProgram(
|
parseAppFrameProgram(
|
||||||
restoredAppFrame,
|
restoredAppFrame,
|
||||||
"G21 G90\nF100\nO10 if [#5161 EQ 1]\nG1 X12\nO10 endif\nM30\n",
|
"G21 G90\nF100\nO10 if [#5161 EQ 2]\nG1 X12\nO10 endif\nM30\n",
|
||||||
);
|
);
|
||||||
await waitForAppAlarm(
|
await waitForAppAlarm(
|
||||||
restoredAppFrame,
|
restoredAppFrame,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
expectText,
|
expectText,
|
||||||
expectWasmFilesMissing,
|
expectWasmFilesMissing,
|
||||||
near,
|
near,
|
||||||
|
readOpfsText,
|
||||||
removeWasmPathIfExists,
|
removeWasmPathIfExists,
|
||||||
runSection,
|
runSection,
|
||||||
withSmokeSimulator,
|
withSmokeSimulator,
|
||||||
@@ -21,9 +22,7 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
"linuxcnc",
|
"linuxcnc",
|
||||||
{ backend: "linuxcnc-rs274" },
|
{ backend: "linuxcnc-rs274" },
|
||||||
);
|
);
|
||||||
const opfsParameterFile = new TextDecoder().decode(
|
const opfsParameterFile = await readOpfsText(simulator, "parameters/rs274ngc.var");
|
||||||
await simulator.fs.opfs.readFile("parameters/rs274ngc.var"),
|
|
||||||
);
|
|
||||||
expectIncludes(opfsParameterFile, "5161\t1.000000", "LinuxCNC parameter file was not persisted into OPFS");
|
expectIncludes(opfsParameterFile, "5161\t1.000000", "LinuxCNC parameter file was not persisted into OPFS");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,6 +41,20 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await runSection("opfs default parameter backup", async () => {
|
||||||
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
||||||
|
// preserves the previous default parameter file as filename + ".bak".
|
||||||
|
await simulator.parseWithParameterFile(
|
||||||
|
"G21 G90\nM30\n",
|
||||||
|
"parameters/rs274ngc.var",
|
||||||
|
"linuxcnc",
|
||||||
|
{ backend: "linuxcnc-rs274" },
|
||||||
|
);
|
||||||
|
const defaultParameterBackup = await readOpfsText(simulator, "parameters/rs274ngc.var.bak");
|
||||||
|
expectIncludes(defaultParameterBackup, "5161\t1.000000",
|
||||||
|
"LinuxCNC default OPFS parameter backup did not preserve the previous file");
|
||||||
|
});
|
||||||
|
|
||||||
await runSection("opfs parameter temporary cleanup", async () => {
|
await runSection("opfs parameter temporary cleanup", async () => {
|
||||||
await simulator.fs.opfs.writeFile("parameters/rs274ngc.var.new", "stale temporary parameter file\n");
|
await simulator.fs.opfs.writeFile("parameters/rs274ngc.var.new", "stale temporary parameter file\n");
|
||||||
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() writes
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() writes
|
||||||
@@ -73,24 +86,49 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
simulator.fs.module.FS.writeFile("rs274ngc.var", "5161\t2.000000\n");
|
simulator.fs.module.FS.writeFile("rs274ngc.var", "5161\t2.000000\n");
|
||||||
simulator.fs.module.FS.writeFile("rs274ngc.var.bak", "5161\t1.000000\n");
|
simulator.fs.module.FS.writeFile("rs274ngc.var.bak", "5161\t1.000000\n");
|
||||||
await simulator.fs.opfs.persistParameterFile("parameters/backup-bridge.var");
|
await simulator.fs.opfs.persistParameterFile("parameters/backup-bridge.var");
|
||||||
const opfsParameterBackup = new TextDecoder().decode(
|
const opfsParameterBackup = await readOpfsText(simulator, "parameters/backup-bridge.var.bak");
|
||||||
await simulator.fs.opfs.readFile("parameters/backup-bridge.var.bak"),
|
|
||||||
);
|
|
||||||
expectIncludes(opfsParameterBackup, "5161\t1.000000",
|
expectIncludes(opfsParameterBackup, "5161\t1.000000",
|
||||||
"LinuxCNC parameter backup file was not bridged into OPFS");
|
"LinuxCNC parameter backup file was not bridged into OPFS");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await runSection("opfs parameter backup after existing save", async () => {
|
||||||
|
await simulator.fs.opfs.writeFile("parameters/existing-save.var", "5161\t3.000000\n");
|
||||||
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
||||||
|
// unlinks filename + ".bak", links the current parameter file to
|
||||||
|
// filename + ".bak", then renames filename + ".new" over filename.
|
||||||
|
await simulator.parseWithParameterFile(
|
||||||
|
"G21 G90\nG0 X4\nG28.1\nM30\n",
|
||||||
|
"parameters/existing-save.var",
|
||||||
|
"linuxcnc",
|
||||||
|
{ backend: "linuxcnc-rs274" },
|
||||||
|
);
|
||||||
|
const existingSaveParameterFile = await readOpfsText(simulator, "parameters/existing-save.var");
|
||||||
|
expectIncludes(existingSaveParameterFile, "5161\t4.000000",
|
||||||
|
"LinuxCNC existing OPFS parameter file was not replaced after save");
|
||||||
|
const existingSaveParameterBackup = await readOpfsText(simulator, "parameters/existing-save.var.bak");
|
||||||
|
expectIncludes(existingSaveParameterBackup, "5161\t3.000000",
|
||||||
|
"LinuxCNC existing OPFS parameter backup did not preserve the previous file");
|
||||||
|
await expectMissingOpfsFile(
|
||||||
|
() => simulator.fs.opfs.readFile("parameters/existing-save.var.new"),
|
||||||
|
"LinuxCNC existing OPFS parameter temporary file remained after save",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
await runSection("opfs parameter stale backup cleanup", async () => {
|
await runSection("opfs parameter stale backup cleanup", async () => {
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/stale-backup-cleanup.var");
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/stale-backup-cleanup.var.new");
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/stale-backup-cleanup.var.bak");
|
||||||
|
await simulator.fs.opfs.writeFile("parameters/stale-backup-cleanup.var.bak", "stale backup without main file\n");
|
||||||
removeWasmPathIfExists(simulator, "rs274ngc.var.bak");
|
removeWasmPathIfExists(simulator, "rs274ngc.var.bak");
|
||||||
removeWasmPathIfExists(simulator, "/rs274ngc.var.bak");
|
removeWasmPathIfExists(simulator, "/rs274ngc.var.bak");
|
||||||
await simulator.parseWithParameterFile(
|
await simulator.parseWithParameterFile(
|
||||||
"G21 G90\nM30\n",
|
"G21 G90\nM30\n",
|
||||||
"parameters/rs274ngc.var",
|
"parameters/stale-backup-cleanup.var",
|
||||||
"linuxcnc",
|
"linuxcnc",
|
||||||
{ backend: "linuxcnc-rs274" },
|
{ backend: "linuxcnc-rs274" },
|
||||||
);
|
);
|
||||||
await expectMissingOpfsFile(
|
await expectMissingOpfsFile(
|
||||||
() => simulator.fs.opfs.readFile("parameters/rs274ngc.var.bak"),
|
() => simulator.fs.opfs.readFile("parameters/stale-backup-cleanup.var.bak"),
|
||||||
"stale LinuxCNC parameter backup file remained in OPFS",
|
"stale LinuxCNC parameter backup file remained in OPFS",
|
||||||
);
|
);
|
||||||
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
|
||||||
@@ -111,6 +149,9 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await runSection("opfs missing parameter file creation", async () => {
|
await runSection("opfs missing parameter file creation", async () => {
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/missing-main.var");
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/missing-main.var.new");
|
||||||
|
await simulator.fs.opfs.removeFile("parameters/missing-main.var.bak");
|
||||||
await simulator.fs.opfs.writeFile("parameters/missing-main.var.bak", "stale backup without main file\n");
|
await simulator.fs.opfs.writeFile("parameters/missing-main.var.bak", "stale backup without main file\n");
|
||||||
await simulator.fs.opfs.writeFile("parameters/missing-main.var.new", "stale temporary without main file\n");
|
await simulator.fs.opfs.writeFile("parameters/missing-main.var.new", "stale temporary without main file\n");
|
||||||
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() unlinks
|
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() unlinks
|
||||||
@@ -124,13 +165,15 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
"linuxcnc",
|
"linuxcnc",
|
||||||
{ backend: "linuxcnc-rs274" },
|
{ backend: "linuxcnc-rs274" },
|
||||||
);
|
);
|
||||||
const missingMainParameterFile = new TextDecoder().decode(
|
const missingMainParameterFile = await readOpfsText(simulator, "parameters/missing-main.var");
|
||||||
await simulator.fs.opfs.readFile("parameters/missing-main.var"),
|
|
||||||
);
|
|
||||||
expectIncludes(missingMainParameterFile, "5220\t1.000000",
|
expectIncludes(missingMainParameterFile, "5220\t1.000000",
|
||||||
"LinuxCNC missing parameter file was not created through OPFS");
|
"LinuxCNC missing parameter file was not created through OPFS");
|
||||||
expectIncludes(missingMainParameterFile, "5161\t0.000000",
|
expectIncludes(missingMainParameterFile, "5161\t0.000000",
|
||||||
"LinuxCNC missing parameter file did not include required G28 parameter");
|
"LinuxCNC missing parameter file did not include required G28 parameter");
|
||||||
|
await expectMissingOpfsFile(
|
||||||
|
() => simulator.fs.opfs.readFile("parameters/missing-main.var.bak"),
|
||||||
|
"stale LinuxCNC missing-parameter backup remained in OPFS after first creation",
|
||||||
|
);
|
||||||
const missingMainRestoreEvents = await simulator.parseWithParameterFile(
|
const missingMainRestoreEvents = await simulator.parseWithParameterFile(
|
||||||
"G21 G90\nF100\nO10 if [#5220 EQ 1]\nG1 X6\nO10 endif\n",
|
"G21 G90\nF100\nO10 if [#5220 EQ 1]\nG1 X6\nO10 endif\n",
|
||||||
"parameters/missing-main.var",
|
"parameters/missing-main.var",
|
||||||
@@ -139,10 +182,9 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
);
|
);
|
||||||
expectEvent(missingMainRestoreEvents, (event) => event.type === "linear-feed" && near(event.end.x, 6),
|
expectEvent(missingMainRestoreEvents, (event) => event.type === "linear-feed" && near(event.end.x, 6),
|
||||||
"LinuxCNC-created missing OPFS parameter file was not restored on the next parse");
|
"LinuxCNC-created missing OPFS parameter file was not restored on the next parse");
|
||||||
await expectMissingOpfsFile(
|
const missingMainParameterBackup = await readOpfsText(simulator, "parameters/missing-main.var.bak");
|
||||||
() => simulator.fs.opfs.readFile("parameters/missing-main.var.bak"),
|
expectIncludes(missingMainParameterBackup, "5220\t1.000000",
|
||||||
"stale LinuxCNC missing-parameter backup remained in OPFS",
|
"LinuxCNC-created OPFS parameter file was not backed up on the next successful save");
|
||||||
);
|
|
||||||
expectMissingWasmPath(
|
expectMissingWasmPath(
|
||||||
() => simulator.fs.module.FS.readFile("rs274ngc.var.bak"),
|
() => simulator.fs.module.FS.readFile("rs274ngc.var.bak"),
|
||||||
"stale LinuxCNC missing-parameter backup remained in WASM FS",
|
"stale LinuxCNC missing-parameter backup remained in WASM FS",
|
||||||
@@ -169,9 +211,7 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
"Parameter file out of order",
|
"Parameter file out of order",
|
||||||
"LinuxCNC accepted an out-of-order OPFS parameter file",
|
"LinuxCNC accepted an out-of-order OPFS parameter file",
|
||||||
);
|
);
|
||||||
const outOfOrderParameterFile = new TextDecoder().decode(
|
const outOfOrderParameterFile = await readOpfsText(simulator, "parameters/out-of-order.var");
|
||||||
await simulator.fs.opfs.readFile("parameters/out-of-order.var"),
|
|
||||||
);
|
|
||||||
expectText(outOfOrderParameterFile, "5162\t1.000000\n5161\t1.000000\n",
|
expectText(outOfOrderParameterFile, "5162\t1.000000\n5161\t1.000000\n",
|
||||||
"LinuxCNC persisted an out-of-order OPFS parameter file after restore failure");
|
"LinuxCNC persisted an out-of-order OPFS parameter file after restore failure");
|
||||||
expectMissingWasmPath(
|
expectMissingWasmPath(
|
||||||
@@ -189,9 +229,7 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
"Parameter number out of range",
|
"Parameter number out of range",
|
||||||
"LinuxCNC accepted an out-of-range OPFS parameter file",
|
"LinuxCNC accepted an out-of-range OPFS parameter file",
|
||||||
);
|
);
|
||||||
const outOfRangeParameterFile = new TextDecoder().decode(
|
const outOfRangeParameterFile = await readOpfsText(simulator, "parameters/out-of-range.var");
|
||||||
await simulator.fs.opfs.readFile("parameters/out-of-range.var"),
|
|
||||||
);
|
|
||||||
expectText(outOfRangeParameterFile, "0\t1.000000\n",
|
expectText(outOfRangeParameterFile, "0\t1.000000\n",
|
||||||
"LinuxCNC persisted an out-of-range OPFS parameter file after restore failure");
|
"LinuxCNC persisted an out-of-range OPFS parameter file after restore failure");
|
||||||
expectMissingWasmPath(
|
expectMissingWasmPath(
|
||||||
@@ -209,9 +247,7 @@ export async function runBrowserOpfsParameterSections(context, simulator) {
|
|||||||
"",
|
"",
|
||||||
"LinuxCNC accepted a failing parse that should not persist parameters",
|
"LinuxCNC accepted a failing parse that should not persist parameters",
|
||||||
);
|
);
|
||||||
const failedParseParameterFile = new TextDecoder().decode(
|
const failedParseParameterFile = await readOpfsText(simulator, "parameters/failed-parse.var");
|
||||||
await simulator.fs.opfs.readFile("parameters/failed-parse.var"),
|
|
||||||
);
|
|
||||||
if (failedParseParameterFile.includes("5161\t1.000000")) {
|
if (failedParseParameterFile.includes("5161\t1.000000")) {
|
||||||
throw new Error("LinuxCNC persisted failed parse parameter updates into OPFS");
|
throw new Error("LinuxCNC persisted failed parse parameter updates into OPFS");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user