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

Side by Side Diff: third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-requests-abort.html

Issue 2822453003: Wrap large IndexedDB values into Blobs before writing to LevelDB. (Closed)
Patch Set: Addressed last round of feedback. Created 3 years, 6 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: transactions with large request results are aborted correctly< /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 // Opens index cursors for operations that require open cursors.
25 //
26 // onsuccess is called if all cursors are opened successfully. Otherwise,
27 // onerror will be called at least once.
28 function openCursors(testCase, index, operations, onerror, onsuccess) {
29 let pendingCursors = 0;
30
31 for (let operation of operations) {
32 const opcode = operation[0];
33 const primaryKey = operation[1];
34 let request;
35 switch (opcode) {
36 case 'continue':
37 request = index.openCursor(
38 IDBKeyRange.lowerBound(`k${primaryKey - 1}`));
39 break;
40 case 'continue-empty':
41 // k4 is the last key in the data set, so calling continue() will get
42 // the cursor past the end of the store.
43 request = index.openCursor(IDBKeyRange.lowerBound('k4'));
44 break;
45 default:
46 continue;
47 }
48
49 operation[2] = request;
50 ++pendingCursors;
51
52 request.onsuccess = testCase.step_func(() => {
53 --pendingCursors;
54 if (!pendingCursors)
55 onsuccess();
56 });
57 request.onerror = testCase.step_func(onerror);
58 }
59
60 if (!pendingCursors)
61 onsuccess();
62 }
63
64 function doOperation(testCase, store, index, operation, requestId, results) {
65 const opcode = operation[0];
66 const primaryKey = operation[1];
67 const cursor = operation[2];
68
69 return new Promise((resolve, reject) => {
70 let request;
71 switch (opcode) {
72 case 'add': // Tests returning a primary key.
73 request = store.add(
74 { key: `k${primaryKey}`, value: [`small-${primaryKey}`] });
75 break;
76 case 'put': // Tests returning a primary key.
77 request = store.put(
78 { key: `k${primaryKey}`, value: [`small-${primaryKey}`] });
79 break;
80 case 'put-with-id': // Tests returning success or a primary key.
81 request = store.put(
82 { key: `k${primaryKey}`, value: [`small-${primaryKey}`],
83 id: primaryKey });
84 break;
85 case 'get': // Tests returning a value.
86 case 'get-empty': // Tests returning undefined.
87 request = store.get(primaryKey);
88 break;
89 case 'getall': // Tests returning an array of values.
90 request = store.getAll();
91 break;
92 case 'error': // Tests returning an error.
93 request = store.put(
94 { key: `k${primaryKey}`, value: [`small-${primaryKey}`] });
95 break;
96 case 'continue': // Tests returning a key, primary key, and value.
97 case 'continue-empty': // Tests returning null.
98 request = cursor;
99 cursor.result.continue();
100 break;
101 case 'open': // Tests returning a cursor, key, primary key, and value.
102 case 'open-empty': // Tests returning null.
103 request = index.openCursor(IDBKeyRange.lowerBound(`k${primaryKey}`));
104 break;
105 case 'count': // Tests returning a numeric result.
106 request = index.count();
107 break;
108 };
109
110 request.onsuccess = testCase.step_func(() => {
111 reject(new Error(
112 'requests should not succeed after the transaction is aborted'));
113 });
114 request.onerror = testCase.step_func(event => {
115 event.preventDefault();
116 results.push([requestId, request.error]);
117 resolve();
118 });
119 });
120 }
121
122 function abortTest(label, operations) {
123 promise_test(testCase => {
124 return createDatabase(testCase, (database, transaction) => {
125 const store = database.createObjectStore(
126 'test-store', { autoIncrement: true, keyPath: 'id' });
127 store.createIndex('test-index', 'key', { unique: true });
128 populateStore(store);
129 }).then(database => {
130 const transaction = database.transaction(['test-store'], 'readwrite');
131 const store = transaction.objectStore('test-store');
132 const index = store.index('test-index');
133 return new Promise((resolve, reject) => {
134 openCursors(testCase, index, operations, reject, () => {
135 const results = [];
136 const promises = [];
137 for (let i = 0; i < operations.length; ++i) {
138 const promise = doOperation(
139 testCase, store, index, operations[i], i, results);
140 promises.push(promise);
141 };
142 transaction.abort();
143 resolve(Promise.all(promises).then(() => results));
144 });
145 });
146 }).then(results => {
147 assert_equals(
148 results.length, operations.length,
149 'Promise.all should resolve after all sub-promises resolve');
150 for (let i = 0; i < operations.length; ++i) {
151 assert_equals(
152 results[i][0], i,
153 'error event order should match request order');
154 assert_equals(
155 results[i][1].name, 'AbortError',
156 'transaction aborting should result in AbortError on all requests');
157 }
158 });
159 }, label);
160 }
161
162 abortTest('small values', [
163 ['get', 2],
164 ['count', null],
165 ['continue-empty', null],
166 ['get-empty', 5],
167 ['add', 5],
168 ['open', 2],
169 ['continue', 2],
170 ['get', 4],
171 ['get-empty', 6],
172 ['count', null],
173 ['put-with-id', 5],
174 ['put', 6],
175 ['error', 3],
176 ['continue', 4],
177 ['count', null],
178 ['get-empty', 7],
179 ['open', 4],
180 ['open-empty', 7],
181 ['add', 7],
182 ]);
183
184 abortTest('large values', [
185 ['open', 1],
186 ['get', 1],
187 ['getall', 4],
188 ['get', 3],
189 ['continue', 3],
190 ['open', 3],
191 ]);
192
193 abortTest('large value followed by small values', [
194 ['get', 1],
195 ['getall', null],
196 ['open', 2],
197 ['continue-empty', null],
198 ['get', 2],
199 ['get-empty', 5],
200 ['count', null],
201 ['continue-empty', null],
202 ['open-empty', 5],
203 ['add', 5],
204 ['error', 1],
205 ['continue', 2],
206 ['get-empty', 6],
207 ['put-with-id', 5],
208 ['put', 6],
209 ]);
210
211 abortTest('large values mixed with small values', [
212 ['get', 1],
213 ['get', 2],
214 ['get-empty', 5],
215 ['count', null],
216 ['continue-empty', null],
217 ['open', 1],
218 ['continue', 2],
219 ['open-empty', 5],
220 ['getall', 4],
221 ['open', 2],
222 ['continue-empty', null],
223 ['add', 5],
224 ['get', 3],
225 ['count', null],
226 ['get-empty', 6],
227 ['put-with-id', 5],
228 ['getall', null],
229 ['continue', 3],
230 ['open-empty', 6],
231 ['put', 6],
232 ['error', 1],
233 ['continue', 2],
234 ['open', 4],
235 ['get-empty', 7],
236 ['count', null],
237 ['continue', 3],
238 ['add', 7],
239 ['getall', null],
240 ['error', 3],
241 ['count', null],
242 ]);
243
244 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698