/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env node */
const { logTest } = require(
"./utils/profiling");
module.exports = logTest(
"indexedDB write test",
async
function (context, commands) {
context.log.info(
"Starting a indexedDB write");
const post_startup_delay = context.options.browsertime.post_startup_delay;
console.log(
"context options", context.options);
const test_url = context.options.browsertime.url;
const chunk_size = context.options.browsertime.chunk_size;
const iterations = context.options.browsertime.iterations;
const buffer_type = context.options.browsertime.buffer_type;
const atomic_value = context.options.browsertime.atomic;
if (atomic_value * atomic_value != atomic_value) {
throw Error(
"Value of atomic shall be 0 for falsehood, 1 for truth.");
}
const atomic = 0 != atomic_value;
const accepted_buffers = [
"Array",
"ArrayBuffer",
"Blob"];
if (!accepted_buffers.includes(buffer_type)) {
throw Error(
"Buffer type " + buffer_type +
" is unknown.");
}
context.log.info(
"IndexedDB write URL = " + test_url);
context.log.info(
"IndexedDB write chunk size = " + chunk_size);
context.log.info(
"IndexedDB write iterations = " + iterations);
context.log.info(
"IndexedDB writes " +
(atomic ?
"all in one big transaction" :
"in separate transactions")
);
context.log.info(
"IndexedDB write data format " + buffer_type);
context.log.info(
"Waiting for %d ms (post_startup_delay)",
post_startup_delay
);
await commands.navigate(test_url);
const seleniumDriver = context.selenium.driver;
await commands.wait.byTime(post_startup_delay);
await commands.measure.start();
const time_duration = await seleniumDriver.executeAsyncScript(`
const notifyDone = arguments[arguments.length - 1];
const iterations = ${iterations};
const sizeInBytes = ${chunk_size};
const bufferType =
"${buffer_type}";
const atomic = ${atomic};
const makeData = (() => {
if (bufferType ===
"ArrayBuffer") {
return () => {
const valueBuffer =
new ArrayBuffer(sizeInBytes);
const charCodeView =
new Uint16Array(valueBuffer);
const sizeInUint16 = sizeInBytes / 2;
for (let i=0; i < sizeInUint16; ++i) {
charCodeView[i] =
"qwerty".charCodeAt(i % 6);
}
return valueBuffer;
};
}
if (bufferType ===
"Array") {
return () => {
return Array.from({length: sizeInBytes}, (_, i) =>
"qwerty"[i % 6]);
};
}
if (bufferType !==
"Blob") {
throw Error(
"Unknown buffer type " + bufferType);
}
return () => {
return new Blob([Array.from({length: sizeInBytes}, (_, i) =>
"qwerty"[i % 6])]);
};
})();
function addData(txSource, txProvider, i) {
try {
const keyName =
"doc_" + i;
const valueData = makeData();
const record = { key: keyName, property: valueData };
const rq = txProvider(txSource).add(record);
return new Promise((res_ad, rej_ad) => {
rq.onsuccess = () => { res_ad(); };
rq.onerror = e => { rej_ad(e); };
});
}
catch (e) {
return new Promise((_, rej_ad) => rej_ad(e));
}
}
function waitForData(txSource) {
try {
if (!atomic) {
const txProvider = src => src.transaction(
"store",
"readwrite").objectStore(
"store");
return Promise.all(
Array.from({ length: iterations }, (_, i) => {
return addData(txSource, txProvider, i);
}));
}
const currentTx = txSource.transaction(
"store",
"readwrite").objectStore(
"store");
return Promise.all(
Array.from({ length: iterations }, (_, i) => {
return addData(currentTx, src => src, i);
}));
}
catch (e) {
return new Promise((_, rej_tx) => rej_tx(e));
}
}
function upgradePromise() {
try {
const open_db = indexedDB.open(
"rootsdb");
return new Promise((res_upgrade, rej_upgrade) => {
open_db.onupgradeneeded = e => {
e.target.result.createObjectStore(
"store", { keyPath:
"key" });
};
open_db.onsuccess = e => { res_upgrade(e.target.result); };
open_db.onerror = e => { rej_upgrade(e); };
});
}
catch (e) {
return new Promise((_, rej_upgrade) => rej_upgrade(e));
}
}
const startTime = performance.now();
upgradePromise().then(waitForData).then(() => {
notifyDone(performance.now() - startTime);
});
`);
await commands.measure.stop();
console.log(
"Time duration was ", time_duration);
await commands.measure.addObject({
custom_data: { time_duration },
});
context.log.info(
"IndexedDB write ended.");
return true;
}
);