summaryrefslogtreecommitdiffstats
path: root/testing/raptor/browsertime/indexeddb_write.js
blob: 30c5c84f8e47bd3cac5f8d236f08a515390ec6ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* 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 */

module.exports = 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;
};