Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: third_party/WebKit/LayoutTests/external/wpt/IndexedDB/request-event-ordering.html

Issue 2822453003: Wrap large IndexedDB values into Blobs before writing to LevelDB. (Closed)
Patch Set: Rebased. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!doctype html>
2 <meta charset="utf8">
3 <meta name="timeout" content="long">
4 <title>IndexedDB: request result events are delivered in order</title>
5 <link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
6 <link rel="author" href="pwnall@chromium.org" title="Victor Costan">
7 <script src="/resources/testharness.js"></script>
8 <script src="/resources/testharnessreport.js"></script>
9 <script src="support-promises.js"></script>
10 <script>
11 'use strict';
12
13 // Should be large enough to trigger large value handling in the IndexedDB
14 // engines that have special code paths for large values.
15 const wrapThreshold = 128 * 1024;
16
17 function populateStore(store) {
18 store.put({id: 1, key: 'k1', value: largeValue(wrapThreshold, 1) });
19 store.put({id: 2, key: 'k2', value: ['small-2'] });
20 store.put({id: 3, key: 'k3', value: largeValue(wrapThreshold, 3) });
21 store.put({id: 4, key: 'k4', value: ['small-4'] });
22 }
23
24 // Assigns cursor indexes for operations that require open cursors.
25 //
26 // Returns the number of open cursors required to perform all operations.
27 function assignCursors(operations) {
28 return cursorCount;
29 }
30
31 // Opens index cursors for operations that require open cursors.
32 //
33 // onsuccess is called if all cursors are opened successfully. Otherwise,
34 // onerror will be called at least once.
35 function openCursors(testCase, index, operations, onerror, onsuccess) {
36 let pendingCursors = 0;
37
38 for (let operation of operations) {
39 const opcode = operation[0];
40 const primaryKey = operation[1];
41 let request;
42 switch (opcode) {
43 case 'continue':
44 request = index.openCursor(
45 IDBKeyRange.lowerBound(`k${primaryKey - 1}`));
46 break;
47 case 'continue-empty':
48 // k4 is the last key in the data set, so calling continue() will get
49 // the cursor past the end of the store.
50 request = index.openCursor(IDBKeyRange.lowerBound('k4'));
51 break;
52 default:
53 continue;
54 }
55
56 operation[2] = request;
57 ++pendingCursors;
58
59 request.onsuccess = testCase.step_func(() => {
60 --pendingCursors;
61 if (!pendingCursors)
62 onsuccess();
63 });
64 request.onerror = testCase.step_func(onerror);
65 }
66
67 if (!pendingCursors)
68 onsuccess();
69 }
70
71 function doOperation(testCase, store, index, operation, requestId, results) {
72 const opcode = operation[0];
73 const primaryKey = operation[1];
74 const cursor = operation[2];
75
76 return new Promise((resolve, reject) => {
77 let request;
78 switch (opcode) {
79 case 'put': // Tests returning a primary key.
80 request = store.put(
81 { key: `k${primaryKey}`, value: [`small-${primaryKey}`] });
82 break;
83 case 'get': // Tests returning a value.
84 case 'get-empty': // Tests returning undefined.
85 request = store.get(primaryKey);
86 break;
87 case 'getall': // Tests returning an array of values.
88 request = store.getAll();
89 break;
90 case 'error': // Tests returning an error.
91 request = store.put(
92 { key: `k${primaryKey}`, value: [`small-${primaryKey}`] });
93 request.onerror = testCase.step_func(event => {
94 event.preventDefault();
95 results.push([requestId, request.error]);
96 resolve();
97 });
98 request.onsuccess = testCase.step_func(() => {
99 reject(new Error('put with duplicate primary key succeded'));
100 });
101 break;
102 case 'continue': // Tests returning a key, primary key, and value.
103 request = cursor;
104 cursor.result.continue();
105 request.onsuccess = testCase.step_func(() => {
106 const result = request.result;
107 results.push(
108 [requestId, result.key, result.primaryKey, result.value]);
109 resolve();
110 });
111 request.onerror = null;
112 break;
113 case 'open': // Tests returning a cursor, key, primary key, and value.
114 request = index.openCursor(IDBKeyRange.lowerBound(`k${primaryKey}`));
115 request.onsuccess = testCase.step_func(() => {
116 const result = request.result;
117 results.push(
118 [requestId, result.key, result.primaryKey, result.value]);
119 resolve();
120 });
121 break;
122 case 'continue-empty': // Tests returning a null result.
123 request = cursor;
124 cursor.result.continue();
125 request.onsuccess = testCase.step_func(() => {
126 results.push([requestId, request.result]);
127 resolve();
128 });
129 request.onerror = null;
130 break;
131 case 'open-empty': // Tests returning a null cursor.
132 request = index.openCursor(IDBKeyRange.lowerBound(`k${primaryKey}`));
133 request.onsuccess = testCase.step_func(() => {
134 const result = request.result;
135 results.push([requestId, request.result]);
136 resolve();
137 });
138 break;
139 case 'count': // Tests returning a numeric result.
140 request = index.count();
141 request.onsuccess = testCase.step_func(() => {
142 results.push([requestId, request.result]);
143 resolve();
144 });
145 break;
146 };
147
148 if (!request.onsuccess) {
149 request.onsuccess = testCase.step_func(() => {
150 results.push([requestId, request.result]);
151 resolve();
152 });
153 }
154 if (!request.onerror)
155 request.onerror = testCase.step_func(event => {
156 event.preventDefault();
157 reject(request.error);
158 });
159 });
160 }
161
162 function checkOperationResult(operation, result, requestId) {
163 const opcode = operation[0];
164 const primaryKey = operation[1];
165
166 const expectedValue = (primaryKey == 1 || primaryKey == 3) ?
167 largeValue(wrapThreshold, primaryKey) : [`small-${primaryKey}`];
168
169 const requestIndex = result[0];
170 assert_equals(
171 requestIndex, requestId, 'result event order should match request order');
172 switch (opcode) {
173 case 'put':
174 assert_equals(
175 result[1], primaryKey,
176 "put result should be the new object's primary key");
177 break;
178 case 'get':
179 assert_equals(
180 result[1].id, primaryKey,
181 'get result should match put value (primary key)');
182 assert_equals(
183 result[1].key, `k${primaryKey}`,
184 'get result should match put value (key)');
185 assert_equals(
186 result[1].value.join(','), expectedValue.join(','),
187 'get result should match put value (nested value)');
188 break;
189 case 'getall':
190 assert_equals(
191 result[1].length, primaryKey,
192 'getAll should return all the objects in the store');
193 for (let i = 0; i < primaryKey; ++i) {
194 const object = result[1][i];
195 assert_equals(
196 object.id, i + 1,
197 `getAll result ${i + 1} should match put value (primary key)`);
198 assert_equals(
199 object.key, `k${i + 1}`,
200 `get result ${i + 1} should match put value (key)`);
201
202 const expectedValue = (i == 0 || i == 2) ?
203 largeValue(wrapThreshold, i + 1) : [`small-${i + 1}`];
204 assert_equals(
205 object.value.join(','), object.value.join(','),
206 `get result ${i + 1} should match put value (nested value)`);
207 }
208 break;
209 case 'get-empty':
210 assert_equals(
211 result[1], undefined, 'get-empty result should be undefined');
212 break;
213 case 'error':
214 assert_equals(
215 result[1].name, 'ConstraintError',
216 'incorrect error from put with duplicate primary key');
217 break;
218 case 'continue':
219 case 'open':
220 assert_equals(
221 result[1], `k${primaryKey}`,
222 `${opcode} key should match the key in the put value`);
223 assert_equals(
224 result[2], primaryKey,
225 `${opcode} primary key should match the put value's primary key`);
226 assert_equals(
227 result[3].id, primaryKey,
228 `${opcode} value should match put value (primary key)`);
229 assert_equals(
230 result[3].key, `k${primaryKey}`,
231 `${opcode} value should match put value (key)`);
232 assert_equals(
233 result[3].value.join(','), expectedValue.join(','),
234 `${opcode} value should match put value (nested value)`);
235 break;
236 case 'continue-empty':
237 case 'open-empty':
238 assert_equals(result[1], null, `${opcode} result should be null`);
239 break;
240 }
241 }
242
243 function eventsTest(label, operations) {
244 promise_test(testCase => {
245 return createDatabase(testCase, (database, transaction) => {
246 const store = database.createObjectStore(
247 'test-store', { autoIncrement: true, keyPath: 'id' });
248 store.createIndex('test-index', 'key', { unique: true });
249 populateStore(store);
250 }).then(database => {
251 const transaction = database.transaction(['test-store'], 'readwrite');
252 const store = transaction.objectStore('test-store');
253 const index = store.index('test-index');
254 return new Promise((resolve, reject) => {
255 openCursors(testCase, index, operations, reject, () => {
256 const results = [];
257 const promises = [];
258 for (let i = 0; i < operations.length; ++i) {
259 const promise = doOperation(
260 testCase, store, index, operations[i], i, results);
261 promises.push(promise);
262 };
263 resolve(Promise.all(promises).then(() => results));
264 });
265 });
266 }).then(results => {
267 assert_equals(
268 results.length, operations.length,
269 'Promise.all should resolve after all sub-promises resolve');
270 for (let i = 0; i < operations.length; ++i)
271 checkOperationResult(operations[i], results[i], i);
272 });
273 }, label);
274 }
275
276 eventsTest('small values', [
277 ['get', 2],
278 ['count', 4],
279 ['continue-empty', null],
280 ['get-empty', 5],
281 ['put', 5],
282 ['open', 2],
283 ['continue', 2],
284 ['get', 4],
285 ['get-empty', 6],
286 ['count', 5],
287 ['put', 6],
288 ['error', 3],
289 ['continue', 4],
290 ['count', 6],
291 ['get-empty', 7],
292 ['open', 4],
293 ['open-empty', 7],
294 ]);
295
296 eventsTest('large values', [
297 ['open', 1],
298 ['get', 1],
299 ['getall', 4],
300 ['get', 3],
301 ['continue', 3],
302 ['open', 3],
303 ]);
304
305 eventsTest('large value followed by small values', [
306 ['get', 1],
307 ['getall', 4],
308 ['open', 2],
309 ['continue-empty', null],
310 ['get', 2],
311 ['get-empty', 5],
312 ['count', 4],
313 ['continue-empty', null],
314 ['open-empty', 5],
315 ['put', 5],
316 ['error', 1],
317 ['continue', 2],
318 ['get-empty', 6],
319 ]);
320
321 eventsTest('large values mixed with small values', [
322 ['get', 1],
323 ['get', 2],
324 ['get-empty', 5],
325 ['count', 4],
326 ['continue-empty', null],
327 ['open', 1],
328 ['continue', 2],
329 ['open-empty', 5],
330 ['getall', 4],
331 ['open', 2],
332 ['continue-empty', null],
333 ['put', 5],
334 ['get', 3],
335 ['count', 5],
336 ['get-empty', 6],
337 ['getall', 5],
338 ['continue', 3],
339 ['open-empty', 6],
340 ['put', 6],
341 ['error', 1],
342 ['continue', 2],
343 ['open', 4],
344 ['get-empty', 7],
345 ['continue', 3],
346 ['getall', 6],
347 ['error', 3],
348 ['count', 6],
349 ]);
350
351 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698