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

Unified Diff: third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html

Issue 2822453003: Wrap large IndexedDB values into Blobs before writing to LevelDB. (Closed)
Patch Set: WIP: Getting IDBRequestTest.EventsAfterStopping to pass. 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
new file mode 100644
index 0000000000000000000000000000000000000000..e882f6aa5a8918da6d2dd26869b2ca468b625311
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
@@ -0,0 +1,270 @@
+<!doctype html>
+<meta charset="utf8">
+<title>IndexedDB: large nested objects are cloned correctly</title>
jsbell 2017/05/15 23:37:37 aside: I wonder if we should create a subdir for w
pwnall 2017/05/19 18:27:33 That sounds like a very reasonable proposal. So, w
+<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script>
jsbell 2017/05/15 23:37:37 Since this test involves multiple sequential trans
pwnall 2017/05/19 18:27:33 Done. Both tests can probably use that tag. Thank
+'use strict';
+
+// Should be large enough to trigger value wrapping in the IndexedDB engines
jsbell 2017/05/15 23:37:37 Maybe explain "wrapping" or say "that have special
pwnall 2017/05/19 18:27:33 Done.
+// that implement wrapping.
+const wrapThreshold = 128 * 1024;
+
+// Returns an Uint8Array with pseudorandom data.
+function largeValue(size, seed) {
+ const buffer = new Uint8Array(size);
+
+ // 32-bit xorshift - the seed can't be zero
+ let state = 1000 + seed;
+
+ for (let i = 0; i < size; ++i) {
+ state ^= state << 13;
+ state ^= state >> 17;
+ state ^= state << 5;
+ buffer[i] = state & 0xff;
+ }
+
+ return buffer;
+}
+
+// Returns an IndexedDB value created from a descriptor.
+//
+// See the bottom of the file for descriptor samples.
+function createValue(descriptor) {
+ if (typeof(descriptor) != 'object')
+ return descriptor;
+
+ if (Array.isArray(descriptor))
+ return descriptor.map((element) => createValue(element));
+
+ if (!descriptor.hasOwnProperty('type')) {
+ const value = {};
+ for (let property of Object.getOwnPropertyNames(descriptor))
+ value[property] = createValue(descriptor[property]);
+ return value;
+ }
+
+ switch (descriptor.type) {
+ case 'blob':
+ return new Blob(
+ [largeValue(descriptor.size, descriptor.seed)],
+ { type: descriptor.type });
+ case 'buffer':
+ return largeValue(descriptor.size, descriptor.seed);
+ }
+}
+
+
+// Checks an IndexedDB value against a descriptor.
+//
+// Returns a Promise that resolves if the value passes the check.
+//
+// See the bottom of the file for descriptor samples.
+function checkValue(testCase, value, descriptor) {
+ if (typeof(descriptor) != 'object') {
+ assert_equals(descriptor, value, 'incorrect value');
+ return Promise.resolve();
+ }
+
+ if (Array.isArray(descriptor)) {
+ assert_true(Array.isArray(value), 'incorrect value type');
+ assert_equals(descriptor.length, value.length, 'incorrect array size');
+
+ const subChecks = [];
+ for (let i = 0; i < descriptor.length; ++i)
+ subChecks.push(checkValue(testCase, value[i], descriptor[i]));
+ return Promise.all(subChecks);
+ }
+
+ if (!descriptor.hasOwnProperty('type')) {
+ assert_array_equals(
+ Object.getOwnPropertyNames(value).sort(),
+ Object.getOwnPropertyNames(descriptor).sort(),
+ 'incorrect object properties');
+ const subChecks = [];
+ for (let property of Object.getOwnPropertyNames(descriptor)) {
jsbell 2017/05/15 23:37:37 If you're feeling fancy, you could do this as: re
pwnall 2017/05/19 18:27:33 Done.
+ subChecks.push(
+ checkValue(testCase, value[property], descriptor[property]));
+ }
+ return Promise.all(subChecks);
+ }
+
+ switch (descriptor.type) {
+ case 'blob':
+ assert_class_string(value, 'Blob', 'incorrect value type');
jsbell 2017/05/15 23:37:37 nit: Word the message in terms of the *expected* o
pwnall 2017/05/19 18:27:33 Done.
+ assert_equals(descriptor.type, value.type, 'incorrect Blob type');
+ assert_equals(descriptor.size, value.size, 'incorrect Blob size');
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onloadend = testCase.step_func(() => {
+ if (reader.error) {
+ reject(reader.error);
+ return;
+ }
+ const view = new Uint8Array(reader.result);
+ assert_equals(
+ view.join(','),
+ largeValue(descriptor.size, descriptor.seed).join(','),
+ 'incorrect Blob content from IndexedDB');
+ resolve();
+ });
+ reader.readAsArrayBuffer(value);
+ });
+
+ case 'buffer':
+ assert_class_string(value, 'Uint8Array', 'incorrect value type');
+ assert_equals(
+ value.join(','),
+ largeValue(descriptor.size, descriptor.seed).join(','),
+ 'incorrect typed array content');
+ return Promise.resolve();
+ }
+}
+
+// Test that performs a series of put()s and verifies that gets() match.
+//
+// Each element of the valueDescriptors array is fed into createValue(), and the
+// resulting value is written to IndexedDB via a put() request. After the writes
+// complete, the values are read in the same order in which they were written.
+//
+// The test verifies that the get() values match the arguments to put() and that
jsbell 2017/05/15 23:37:37 This tests get() but not getAll()
pwnall 2017/05/19 18:27:33 Done. Thanks, I don't know how I managed to miss t
+// the order in which the get() result events are fired matches the order of the
+// get() requests.
+function cloningTest(label, valueDescriptors) {
+ promise_test(testCase => {
+ return createDatabase(testCase, (database, transaction) => {
+ const store = database.createObjectStore('test-store', { keyPath: null });
jsbell 2017/05/15 23:37:37 Why specify keyPath: null which is the default?
pwnall 2017/05/19 18:27:33 Done.
+ for (let i = 0; i < valueDescriptors.length; ++i) {
+ store.put(createValue(valueDescriptors[i]), i);
+ }
+ }).then(database => {
+ const transaction = database.transaction(['test-store'], 'readonly');
+ const store = transaction.objectStore('test-store');
+ const subChecks = [];
+ let resultIndex = 0;
+ for (let i = 0; i < valueDescriptors.length; ++i) {
+ subChecks.push(new Promise((resolve, reject) => {
+ const requestIndex = i;
+ const request = store.get(requestIndex);
+ request.onerror =
+ testCase.step_func(() => { reject(request.error); });
+ request.onsuccess = testCase.step_func(() => {
+ assert_equals(
+ resultIndex, requestIndex,
+ 'IDBRequest success events should be fired in request order');
+ ++resultIndex;
+ resolve(checkValue(
+ testCase, request.result, valueDescriptors[requestIndex]));
+ });
+ }));
+ }
+ return Promise.all(subChecks);
+ });
+ }, label);
+}
+
+cloningTest('small typed array', [
+ { type: 'buffer', size: 64, seed: 1 },
+]);
+
+cloningTest('large typed array', [
+ { type: 'buffer', size: wrapThreshold, seed: 1 },
+])
+
+cloningTest('blob', [
+ { type: 'blob', size: wrapThreshold, seed: 1 },
+]);
+
+cloningTest('blob with small typed array', [
+ {
+ blob: { type: 'blob', size: wrapThreshold, seed: 1 },
+ buffer: { type: 'buffer', size: 64, seed: 2 },
+ },
+]);
+
+cloningTest('blob with large typed array', [
+ {
+ blob: { type: 'blob', size: wrapThreshold, seed: 1 },
+ buffer: { type: 'buffer', size: wrapThreshold, seed: 2 },
+ },
+]);
+
+cloningTest('blob array', [
+ [
+ { type: 'blob', size: wrapThreshold, seed: 1 },
+ { type: 'blob', size: wrapThreshold, seed: 2 },
+ { type: 'blob', size: wrapThreshold, seed: 3 },
+ ],
+]);
+
+cloningTest('array of blobs and small typed arrays', [
+ [
+ { type: 'blob', size: wrapThreshold, seed: 1 },
+ { type: 'buffer', size: 64, seed: 2 },
+ { type: 'blob', size: wrapThreshold, seed: 3 },
+ { type: 'buffer', size: 64, seed: 4 },
+ { type: 'blob', size: wrapThreshold, seed: 5 },
+ ],
+]);
+
+cloningTest('array of blobs and large typed arrays', [
+ [
+ { type: 'blob', size: wrapThreshold, seed: 1 },
+ { type: 'buffer', size: wrapThreshold, seed: 2 },
+ { type: 'blob', size: wrapThreshold, seed: 3 },
+ { type: 'buffer', size: wrapThreshold, seed: 4 },
+ { type: 'blob', size: wrapThreshold, seed: 5 },
+ ],
+]);
+
+cloningTest('object with blobs and large typed arrays', [
+ {
+ blob: { type: 'blob', size: wrapThreshold, seed: 1 },
+ more: [
+ { type: 'buffer', size: wrapThreshold, seed: 2 },
+ { type: 'blob', size: wrapThreshold, seed: 3 },
+ { type: 'buffer', size: wrapThreshold, seed: 4 },
+ ],
+ blob2: { type: 'blob', size: wrapThreshold, seed: 5 },
+ },
+]);
+
+cloningTest('multiple requests of objects with blobs and large typed arrays', [
+ {
+ blob: { type: 'blob', size: wrapThreshold, seed: 1 },
+ more: [
+ { type: 'buffer', size: wrapThreshold, seed: 2 },
+ { type: 'blob', size: wrapThreshold, seed: 3 },
+ { type: 'buffer', size: wrapThreshold, seed: 4 },
+ ],
+ blob2: { type: 'blob', size: wrapThreshold, seed: 5 },
+ },
+ [
+ { type: 'blob', size: wrapThreshold, seed: 6 },
+ { type: 'buffer', size: wrapThreshold, seed: 7 },
+ { type: 'blob', size: wrapThreshold, seed: 8 },
+ { type: 'buffer', size: wrapThreshold, seed: 9 },
+ { type: 'blob', size: wrapThreshold, seed: 10 },
+ ],
+ {
+ data: [
+ { type: 'blob', size: wrapThreshold, seed: 11 },
+ { type: 'buffer', size: wrapThreshold, seed: 12 },
+ { type: 'blob', size: wrapThreshold, seed: 13 },
+ { type: 'buffer', size: wrapThreshold, seed: 14 },
+ { type: 'blob', size: wrapThreshold, seed: 15 },
+ ],
+ },
+ [
+ { type: 'blob', size: wrapThreshold, seed: 16 },
+ { type: 'buffer', size: wrapThreshold, seed: 17 },
+ { type: 'blob', size: wrapThreshold, seed: 18 },
+ { type: 'buffer', size: wrapThreshold, seed: 19 },
+ { type: 'blob', size: wrapThreshold, seed: 20 },
+ ],
+]);
+
+</script>

Powered by Google App Engine
This is Rietveld 408576698