function reset_vacuum_date(name = "testVacuum") {
let date = parseInt(Date.now() / 1000 - 31 * 86400); // Set last VACUUM to a date in the past.
Services.prefs.setIntPref(`storage.vacuum.last.${name}.sqlite`, date); return date;
}
function get_vacuum_date(name = "testVacuum") { return Services.prefs.getIntPref(`storage.vacuum.last.${name}.sqlite`, 0);
}
add_setup(async function () { // turn on Cu.isInAutomation
Services.prefs.setBoolPref( "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", true
);
});
add_task(async function test_common_vacuum() {
let last_vacuum_date = reset_vacuum_date();
info("Test that a VACUUM correctly happens and all notifications are fired.");
let promiseTestVacuumBegin = TestUtils.topicObserved("test-begin-vacuum");
let promiseTestVacuumEnd = TestUtils.topicObserved("test-end-vacuum-success");
let promiseVacuumBegin = TestUtils.topicObserved("vacuum-begin");
let promiseVacuumEnd = TestUtils.topicObserved("vacuum-end");
let participant = new VacuumParticipant(
Services.storage.openDatabase(new_db_file())
);
await participant.promiseRegistered();
synthesize_idle_daily(); // Wait for notifications.
await Promise.all([
promiseTestVacuumBegin,
promiseTestVacuumEnd,
promiseVacuumBegin,
promiseVacuumEnd,
]); Assert.greater(get_vacuum_date(), last_vacuum_date);
await participant.dispose();
});
add_task(async function test_skipped_if_recent_vacuum() {
info("Test that a VACUUM is skipped if it was run recently.");
Services.prefs.setIntPref( "storage.vacuum.last.testVacuum.sqlite",
parseInt(Date.now() / 1000)
); // Wait for VACUUM skipped notification.
let promiseSkipped = TestUtils.topicObserved("vacuum-skip");
let participant = new VacuumParticipant(
Services.storage.openDatabase(new_db_file())
);
await participant.promiseRegistered();
synthesize_idle_daily();
// Check that VACUUM has been skipped.
await promiseSkipped;
await participant.dispose();
});
add_task(async function test_page_size_change() {
info("Test that a VACUUM changes page_size");
reset_vacuum_date();
// obfsvfs (the default VFS when SQLite encryption is enabled) forces a fixed // page size and ignores PRAGMA/VACUUM page-size changes, so a VACUUM cannot // change the page size of an encrypted in-profile database.
let encrypted = Services.prefs.getBoolPref( "security.storage.encryption.sqlite.enabled", false
);
let conn = Services.storage.openDatabase(new_db_file());
info("Check initial page size.");
let stmt = conn.createStatement("PRAGMA page_size"); Assert.ok(stmt.executeStep()); Assert.equal(stmt.row.page_size, conn.defaultPageSize);
let initialPageSize = stmt.row.page_size;
stmt.finalize();
await populateFreeList(conn);
let participant = new VacuumParticipant(conn, { expectedPageSize: 1024 });
await participant.promiseRegistered();
let promiseVacuumEnd = TestUtils.topicObserved("test-end-vacuum-success");
synthesize_idle_daily();
await promiseVacuumEnd;
info("Check the page size after VACUUM.");
stmt = conn.createStatement("PRAGMA page_size"); Assert.ok(stmt.executeStep()); // Plaintext: the VACUUM applies the requested 1024-byte page size. // Encrypted: obfsvfs keeps its fixed page size unchanged. Assert.equal(stmt.row.page_size, encrypted ? initialPageSize : 1024);
stmt.finalize();
await participant.dispose();
});
add_task(async function test_skipped_optout_vacuum() {
info("Test that a VACUUM is skipped if the participant wants to opt-out.");
reset_vacuum_date();
let participant = new VacuumParticipant(
Services.storage.openDatabase(new_db_file()),
{ grant: false }
);
await participant.promiseRegistered(); // Wait for VACUUM skipped notification.
let promiseSkipped = TestUtils.topicObserved("vacuum-skip");
synthesize_idle_daily();
// Check that VACUUM has been skipped.
await promiseSkipped;
await participant.dispose();
});
add_task(async function test_memory_database_crash() {
info("Test that we don't crash trying to vacuum a memory database");
reset_vacuum_date();
let participant = new VacuumParticipant(
Services.storage.openSpecialDatabase("memory")
);
await participant.promiseRegistered(); // Wait for VACUUM skipped notification.
let promiseSkipped = TestUtils.topicObserved("vacuum-skip");
synthesize_idle_daily();
// Check that VACUUM has been skipped.
await promiseSkipped;
await participant.dispose();
});
add_task(async function test_async_connection() {
info("Test we can vacuum an async connection");
reset_vacuum_date();
let conn = await openAsyncDatabase(new_db_file());
await populateFreeList(conn);
let participant = new VacuumParticipant(conn);
await participant.promiseRegistered();
let promiseVacuumEnd = TestUtils.topicObserved("test-end-vacuum-success");
synthesize_idle_daily();
await promiseVacuumEnd;
await participant.dispose();
});
add_task(async function test_change_to_incremental_vacuum() {
info("Test we can change to incremental vacuum");
reset_vacuum_date();
// obfsvfs creates encrypted databases with full auto_vacuum (1); a plaintext // database starts with auto_vacuum disabled (0). Either way the incremental // VACUUM below switches it to incremental (2).
let encrypted = Services.prefs.getBoolPref( "security.storage.encryption.sqlite.enabled", false
);
let participant = new VacuumParticipant(conn, { useIncrementalVacuum: true });
await participant.promiseRegistered();
let promiseVacuumEnd = TestUtils.topicObserved("test-end-vacuum-success");
synthesize_idle_daily();
await promiseVacuumEnd;
info("Check that auto_vacuum was updated.");
stmt = conn.createStatement("PRAGMA auto_vacuum"); Assert.ok(stmt.executeStep()); // Plaintext switches to incremental (2). On an encrypted database obfsvfs // keeps full auto_vacuum (1): its fixed page layout requires full // auto_vacuum, so the incremental switch is not honored. Assert.equal(stmt.row.auto_vacuum, encrypted ? 1 : 2);
stmt.finalize();
await participant.dispose();
});
add_task(async function test_change_from_incremental_vacuum() {
info("Test we can change from incremental vacuum");
reset_vacuum_date();
let participant = new VacuumParticipant(conn);
await participant.promiseRegistered();
let promiseVacuumEnd = TestUtils.topicObserved("test-end-vacuum-success");
synthesize_idle_daily();
await promiseVacuumEnd;
await participant.dispose();
});
add_task(async function test_vacuum_fail() {
info("Test a failed vacuum");
reset_vacuum_date();
let conn = Services.storage.openDatabase(new_db_file()); // Cannot vacuum in a transaction.
conn.beginTransaction();
await populateFreeList(conn);
let participant = new VacuumParticipant(conn);
await participant.promiseRegistered();
let promiseVacuumEnd = TestUtils.topicObserved("test-end-vacuum-failure");
synthesize_idle_daily();
await promiseVacuumEnd;
add_task(async function test_async_vacuum() { // Since previous tests already go through most cases, this only checks // the basics of directly calling asyncVacuum().
info("Test synchronous connection");
let conn = Services.storage.openDatabase(new_db_file());
await populateFreeList(conn);
let rv = await new Promise(resolve => {
conn.asyncVacuum(status => {
resolve(status);
});
}); Assert.ok(Components.isSuccessCode(rv));
await asyncClose(conn);
// Chunked growth is disabled on Android, so this test is pointless there.
add_task(
{ skip_if: () => AppConstants.platform == "android" },
async function test_vacuum_growth() { // Tests vacuum doesn't nullify chunked growth.
let conn = Services.storage.openDatabase(new_db_file("incremental"));
conn.executeSimpleSQL("PRAGMA auto_vacuum = INCREMENTAL");
conn.setGrowthIncrement(2 * conn.defaultPageSize, "");
await populateFreeList(conn);
let stmt = conn.createStatement("PRAGMA freelist_count");
let count = 0; Assert.ok(stmt.executeStep());
count = stmt.row.freelist_count;
stmt.reset(); Assert.greater(count, 2, "There's more than 2 page in freelist");
let rv = await new Promise(resolve => {
conn.asyncVacuum(status => {
resolve(status);
}, true);
}); Assert.ok(Components.isSuccessCode(rv));
Assert.ok(stmt.executeStep()); Assert.equal(
stmt.row.freelist_count, 2, "chunked growth space was preserved"
);
stmt.reset();
// A full vacuuum should not be executed if there's less free pages than // chunked growth.
rv = await new Promise(resolve => {
conn.asyncVacuum(status => {
resolve(status);
});
}); Assert.ok(Components.isSuccessCode(rv));
Assert.ok(stmt.executeStep()); Assert.equal(
stmt.row.freelist_count, 2, "chunked growth space was preserved"
);
stmt.finalize();
await asyncClose(conn);
}
);
async function populateFreeList(conn, schema = "main") {
await executeSimpleSQLAsync(conn, `CREATE TABLE ${schema}.test (id TEXT)`);
await executeSimpleSQLAsync(
conn,
`INSERT INTO ${schema}.test
VALUES ${Array.from({ length: 3000 }, () => Math.random()).map(
v => "('" + v + "')"
)}`
);
await executeSimpleSQLAsync(conn, `DROP TABLE ${schema}.test`);
}
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.