Snapshot of upstream SQLite 3.41.0
[sqlcipher.git] / ext / wasm / tests / opfs / concurrency / test.js
blob14cd6f514fece4e3c91ed5f74b58208fbac6dfdc
1 (async function(self){
3 const logCss = (function(){
4 const mapToString = (v)=>{
5 switch(typeof v){
6 case 'number': case 'string': case 'boolean':
7 case 'undefined': case 'bigint':
8 return ''+v;
9 default: break;
11 if(null===v) return 'null';
12 if(v instanceof Error){
13 v = {
14 message: v.message,
15 stack: v.stack,
16 errorClass: v.name
19 return JSON.stringify(v,undefined,2);
21 const normalizeArgs = (args)=>args.map(mapToString);
22 const logTarget = document.querySelector('#test-output');
23 const logCss = function(cssClass,...args){
24 const ln = document.createElement('div');
25 if(cssClass){
26 for(const c of (Array.isArray(cssClass) ? cssClass : [cssClass])){
27 ln.classList.add(c);
30 ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
31 logTarget.append(ln);
33 const cbReverse = document.querySelector('#cb-log-reverse');
34 const cbReverseKey = 'tester1:cb-log-reverse';
35 const cbReverseIt = ()=>{
36 logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
37 localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
39 cbReverse.addEventListener('change', cbReverseIt, true);
40 if(localStorage.getItem(cbReverseKey)){
41 cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
43 cbReverseIt();
44 return logCss;
45 })();
46 const stdout = (...args)=>logCss('',...args);
47 const stderr = (...args)=>logCss('error',...args);
49 const wait = async (ms)=>{
50 return new Promise((resolve)=>setTimeout(resolve,ms));
53 const urlArgsJs = new URL(document.currentScript.src).searchParams;
54 const urlArgsHtml = new URL(self.location.href).searchParams;
55 const options = Object.create(null);
56 options.sqlite3Dir = urlArgsJs.get('sqlite3.dir');
57 options.workerCount = (
58 urlArgsHtml.has('workers') ? +urlArgsHtml.get('workers') : 3
59 ) || 4;
60 options.opfsVerbose = (
61 urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1
62 ) || 1;
63 options.interval = (
64 urlArgsHtml.has('interval') ? +urlArgsHtml.get('interval') : 1000
65 ) || 1000;
66 options.iterations = (
67 urlArgsHtml.has('iterations') ? +urlArgsHtml.get('iterations') : 10
68 ) || 10;
69 options.unlockAsap = (
70 urlArgsHtml.has('unlock-asap') ? +urlArgsHtml.get('unlock-asap') : 0
71 ) || 0;
72 options.noUnlink = !!urlArgsHtml.has('no-unlink');
73 const workers = [];
74 workers.post = (type,...args)=>{
75 for(const w of workers) w.postMessage({type, payload:args});
77 workers.counts = {loaded: 0, passed: 0, failed: 0};
78 const checkFinished = function(){
79 if(workers.counts.passed + workers.counts.failed !== workers.length){
80 return;
82 if(workers.counts.failed>0){
83 logCss('tests-fail',"Finished with",workers.counts.failed,"failure(s).");
84 }else{
85 logCss('tests-pass',"All",workers.length,"workers finished.");
88 workers.onmessage = function(msg){
89 msg = msg.data;
90 const prefix = 'Worker #'+msg.worker+':';
91 switch(msg.type){
92 case 'loaded':
93 stdout(prefix,"loaded");
94 if(++workers.counts.loaded === workers.length){
95 stdout("All",workers.length,"workers loaded. Telling them to run...");
96 workers.post('run');
98 break;
99 case 'stdout': stdout(prefix,...msg.payload); break;
100 case 'stderr': stderr(prefix,...msg.payload); break;
101 case 'error': stderr(prefix,"ERROR:",...msg.payload); break;
102 case 'finished':
103 ++workers.counts.passed;
104 logCss('tests-pass',prefix,...msg.payload);
105 checkFinished();
106 break;
107 case 'failed':
108 ++workers.counts.failed;
109 logCss('tests-fail',prefix,"FAILED:",...msg.payload);
110 checkFinished();
111 break;
112 default: logCss('error',"Unhandled message type:",msg); break;
116 stdout("Launching",options.workerCount,"workers. Options:",options);
117 workers.uri = (
118 'worker.js?'
119 + 'sqlite3.dir='+options.sqlite3Dir
120 + '&interval='+options.interval
121 + '&iterations='+options.iterations
122 + '&opfs-verbose='+options.opfsVerbose
123 + '&opfs-unlock-asap='+options.unlockAsap
125 for(let i = 0; i < options.workerCount; ++i){
126 stdout("Launching worker...");
127 workers.push(new Worker(
128 workers.uri+'&workerId='+(i+1)+(
129 (i || options.noUnlink) ? '' : '&unlink-db'
133 // Have to delay onmessage assignment until after the loop
134 // to avoid that early workers get an undue head start.
135 workers.forEach((w)=>w.onmessage = workers.onmessage);
136 })(self);