add_setup(
{ skip_if: () => AppConstants.platform == "android" }, function test_setup() { // We need to initialize it once, otherwise operations will be stuck in the pre-init queue.
Services.fog.initializeFOG();
}
);
// Tests
add_task(async function test_save_reload() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
add_task(async function test_load_with_dataPostProcessor() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
await storeForSave.load();
Object.assign(storeForSave.data, TEST_DATA);
await storeForSave._save();
let random = Math.random();
let storeForLoad = new JSONFile({
path: storeForSave.path,
dataPostProcessor: data => { Assert.deepEqual(data, TEST_DATA);
data.test = random; return data;
},
});
await storeForLoad.load();
Assert.equal(storeForLoad.data.test, random);
});
add_task(async function test_load_with_dataPostProcessor_fails() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
dataPostProcessor: () => { thrownew Error("dataPostProcessor fails.");
},
});
add_task(async function test_load_sync_with_dataPostProcessor_fails() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
dataPostProcessor: () => { thrownew Error("dataPostProcessor fails.");
},
});
/** *Loadsdatafromastringinapredefinedformat.Thepurposeofthistestis *toverifythattheJSONformatusedinpreviousversionscanbeloaded.
*/
add_task(async function test_load_string_predefined() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = '{"number":123,"string":"test","object":{"prop1":1,"prop2":2}}';
/** *LoadsdatafromamalformedJSONstring.
*/
add_task(async function test_load_string_malformed() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = '{"number":123,"string":"test","object":{"prop1":1,';
// A backup file should have been created. Assert.ok(await IOUtils.exists(store.path + ".corrupt"));
await IOUtils.remove(store.path + ".corrupt");
// The store should be ready to accept new data. Assert.ok(store.dataReady); Assert.deepEqual(store.data, {});
});
/** *LoadsdatafromamalformedJSONstring,usingthesynchronousinitialization *path.
*/
add_task(async function test_load_string_malformed_sync() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = '{"number":123,"string":"test","object":{"prop1":1,';
add_task(async function test_beforeSave() {
let store;
let promiseBeforeSave = new Promise(resolve => {
store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
beforeSave: resolve,
saveDelayMs: 250,
});
});
store.saveSoon();
await promiseBeforeSave;
});
add_task(async function test_beforeSave_rejects() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
beforeSave() { return Promise.reject(new Error("oops"));
},
saveDelayMs: 250,
});
let promiseSave = new Promise((resolve, reject) => {
let save = storeForSave._save.bind(storeForSave);
storeForSave._save = () => {
save().then(resolve, reject);
};
storeForSave.saveSoon();
});
add_task(async function test_finalize() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let barrier = new AsyncShutdown.Barrier("test-auto-finalize");
let storeForSave = new JSONFile({
path,
saveDelayMs: 2000,
finalizeAt: barrier.client,
});
await storeForSave.load();
storeForSave.data = TEST_DATA;
storeForSave.saveSoon();
let promiseFinalize = storeForSave.finalize();
await Assert.rejects(storeForSave.finalize(), /has already been finalized$/);
await promiseFinalize; Assert.ok(!storeForSave.dataReady);
// Finalization removes the blocker, so waiting should not log an unhandled // error even though the object has been explicitly finalized.
await barrier.wait();
let storeForLoad = new JSONFile({ path });
await storeForLoad.load(); Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_finalize_on_shutdown() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let barrier = new AsyncShutdown.Barrier("test-finalize-shutdown");
let storeForSave = new JSONFile({
path,
saveDelayMs: 2000,
finalizeAt: barrier.client,
});
await storeForSave.load();
storeForSave.data = TEST_DATA; // Arm the saver, then simulate shutdown and ensure the file is // automatically finalized.
storeForSave.saveSoon();
await barrier.wait(); // It's possible for `finalize` to reject when called concurrently with // shutdown. We don't distinguish between explicit `finalize` calls and // finalization on shutdown because we expect most consumers to rely on the // latter. However, this behavior can be safely changed if needed.
await Assert.rejects(storeForSave.finalize(), /has already been finalized$/); Assert.ok(!storeForSave.dataReady);
let storeForLoad = new JSONFile({ path });
await storeForLoad.load(); Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_save_failure_handler() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let saveFailureHandler = sinon.stub();
let storeForSave = new JSONFile({
path,
saveDelayMs: 10,
saveFailureHandler,
});
await storeForSave.load();
// Let's now add some invalid data that we'll fail to save.
let circularThing = {};
circularThing.circle = circularThing;
if (AppConstants.platform != "android") {
add_task(async function test_load_error_telemetry() {
let file = getTempFile("idontexist.json");
let store = new JSONFile({
path: file.path,
sanitizedBasename: "logins",
});
await store.load();
let telemetryData = Glean.jsonfile.loadLogins.testGetValue();
console.log( "Telemetry data after trying to read file that doesn't exist:",
JSON.stringify(telemetryData)
);
telemetryData = telemetryData?.filter(n =>
n.extra?.value?.startsWith("error")
);
Assert.equal(telemetryData.length, 1, "Telemetry should record one error."); Assert.equal(
telemetryData[0]?.extra.value, "error_notfounderror", "Telemetry should record not found."
);
// Can't easily create a file we can't read on Windows. if (AppConstants.platform != "win") {
Services.fog.testResetFOG();
store = new JSONFile({
path: file.path,
sanitizedBasename: "logins",
});
file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o111);
await store.load();
telemetryData = Glean.jsonfile.loadLogins.testGetValue();
console.log( "Telemetry data after trying to read unreadable file:",
JSON.stringify(telemetryData)
);
telemetryData = telemetryData?.filter(n =>
n.extra?.value?.startsWith("error")
);
Assert.equal(
telemetryData.length, 1, "Telemetry should record one error."
); Assert.equal(
telemetryData[0]?.extra.value, "error_notallowederror", "Telemetry should record permission denied."
);
Assert.ok(
await IOUtils.exists(store.path + ".corrupt"), "A backup file should have been created (via move)."
);
await IOUtils.remove(store.path + ".corrupt");
Assert.ok(
!(await IOUtils.exists(store.path)), "Original file should have been moved."
);
}
});
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.