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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
<!DOCTYPE html>
<meta charset=utf-8>
<title>CrashReportStorage API</title>
<link rel="author" title="Dominic Farolino" href="mailto:dom@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
'use strict';
// These tests verify the throwing and promise rejection behavior of the
// crashReport API. Each test is run in an iframe to ensure a fresh state.
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
await loadPromise;
const child_window = iframe.contentWindow;
// Detach the document.
iframe.remove();
assert_equals(child_window.crashReport, null, "getter returns null");
}, 'crashReport getter returns null in detached Documents');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
await loadPromise;
// Cache the iframe's `crashReport` and other important things for the
// following assertions.
const child_window = iframe.contentWindow;
const cachedCrashReport = child_window.crashReport;
const cachedDOMExceptionConstructor = child_window.DOMException;
iframe.remove();
const createRejection = cachedCrashReport.initialize(256);
try {
await createRejection;
assert_unreached('createRejection must reject');
} catch (e) {
// Note that we should be using `promise_rejects_dom` here, but this does
// not reliably work with detached Windows/event loops, so we have to run
// some manual assertions here.
assert_true(e instanceof cachedDOMExceptionConstructor,
"promise rejects with DOMException");
assert_equals(e.code, cachedDOMExceptionConstructor.INVALID_STATE_ERR,
"promise rejects with InvalidStateError specifically");
}
}, 'crashReport initialize() throws InvalidStateError in detached Documents');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
await loadPromise;
const child_window = iframe.contentWindow;
const cachedCrashReport = child_window.crashReport;
await cachedCrashReport.initialize(256);
assert_throws_dom('InvalidStateError', child_window.DOMException, () => {
// Detach the document.
iframe.remove();
cachedCrashReport.set('key', 'value');
});
}, 'crashReport.set() throws InvalidStateError in detached Documents');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
await loadPromise;
const child_window = iframe.contentWindow;
const cachedCrashReport = child_window.crashReport;
await cachedCrashReport.initialize(256);
cachedCrashReport.set('key', 'value');
assert_throws_dom('InvalidStateError', child_window.DOMException, () => {
// Detach the document.
iframe.remove();
cachedCrashReport.remove('key', 'value');
});
}, 'crashReport.remove() throws InvalidStateError in detached Documents');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
// The maximum allowed size is 5MB.
const large_size = 5 * 1024 * 1024 + 1;
await promise_rejects_dom(t, 'NotAllowedError', child_window.DOMException,
child_window.crashReport.initialize(large_size));
}, 'crashReport.initialize() with size > 5MB rejects with NotAllowedError');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
child_window.crashReport.initialize(1024);
await promise_rejects_dom(t, 'InvalidStateError', child_window.DOMException,
child_window.crashReport.initialize(1024));
}, 'Calling crashReport.initialize() a second time throws InvalidStateError');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
child_window.crashReport.initialize(1024);
assert_throws_dom('InvalidStateError', child_window.DOMException, () => {
child_window.crashReport.set('key', 'value');
});
}, 'crashReport.set() throws before initialize() resolves');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
await child_window.crashReport.initialize(1024);
child_window.crashReport.set('key', 'value');
child_window.crashReport.remove('key');
}, 'crashReport.set() and .remove() succeed after initialize() resolves');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
// 8 bytes is too small for the key/value pair "a"/"a" to be written; the
// memory required is 9 bytes, to support the JSONified format:
//
// {"a":"a"}
//
// Similarly, 17 bytes is required for "a"/"a" *and* "b"/"b" to be written, to
// support the format:
//
// {"a":"a","b":"b"}
await child_window.crashReport.initialize(8);
assert_throws_dom('NotAllowedError', child_window.DOMException, () => {
child_window.crashReport.set('a', 'a');
});
// This just fits in our 8-byte buffer though!
child_window.crashReport.set('b', '');
}, 'crashReport.set() throws when there is not enough memory');
promise_test(async t => {
const iframe = document.createElement('iframe');
const loadPromise = new Promise(resolve => iframe.onload = resolve);
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadPromise;
const child_window = iframe.contentWindow;
await child_window.crashReport.initialize(9);
child_window.crashReport.set('a', 'a');
assert_throws_dom('NotAllowedError', child_window.DOMException, () => {
child_window.crashReport.set('b', 'b');
});
child_window.crashReport.remove('a');
// Now `set()` will work again.
child_window.crashReport.set('b', 'b');
}, 'crashReport.remove() properly frees memory, and allows you to invoke ' +
'set() again, assigning bytes to memory that was previously full');
</script>
</body>
|