crashReport-test.html (7167B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>CrashReportStorage API</title> 4 <link rel="author" title="Dominic Farolino" href="mailto:dom@chromium.org"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <body> 8 <script> 9 'use strict'; 10 11 // These tests verify the throwing and promise rejection behavior of the 12 // crashReport API. Each test is run in an iframe to ensure a fresh state. 13 14 promise_test(async t => { 15 const iframe = document.createElement('iframe'); 16 const loadPromise = new Promise(resolve => iframe.onload = resolve); 17 document.body.appendChild(iframe); 18 await loadPromise; 19 20 const child_window = iframe.contentWindow; 21 // Detach the document. 22 iframe.remove(); 23 assert_equals(child_window.crashReport, null, "getter returns null"); 24 }, 'crashReport getter returns null in detached Documents'); 25 26 promise_test(async t => { 27 const iframe = document.createElement('iframe'); 28 const loadPromise = new Promise(resolve => iframe.onload = resolve); 29 document.body.appendChild(iframe); 30 await loadPromise; 31 32 // Cache the iframe's `crashReport` and other important things for the 33 // following assertions. 34 const child_window = iframe.contentWindow; 35 const cachedCrashReport = child_window.crashReport; 36 const cachedDOMExceptionConstructor = child_window.DOMException; 37 38 iframe.remove(); 39 const createRejection = cachedCrashReport.initialize(256); 40 try { 41 await createRejection; 42 assert_unreached('createRejection must reject'); 43 } catch (e) { 44 // Note that we should be using `promise_rejects_dom` here, but this does 45 // not reliably work with detached Windows/event loops, so we have to run 46 // some manual assertions here. 47 assert_true(e instanceof cachedDOMExceptionConstructor, 48 "promise rejects with DOMException"); 49 assert_equals(e.code, cachedDOMExceptionConstructor.INVALID_STATE_ERR, 50 "promise rejects with InvalidStateError specifically"); 51 } 52 }, 'crashReport initialize() throws InvalidStateError in detached Documents'); 53 54 promise_test(async t => { 55 const iframe = document.createElement('iframe'); 56 const loadPromise = new Promise(resolve => iframe.onload = resolve); 57 document.body.appendChild(iframe); 58 await loadPromise; 59 60 const child_window = iframe.contentWindow; 61 const cachedCrashReport = child_window.crashReport; 62 await cachedCrashReport.initialize(256); 63 assert_throws_dom('InvalidStateError', child_window.DOMException, () => { 64 // Detach the document. 65 iframe.remove(); 66 cachedCrashReport.set('key', 'value'); 67 }); 68 }, 'crashReport.set() throws InvalidStateError in detached Documents'); 69 70 promise_test(async t => { 71 const iframe = document.createElement('iframe'); 72 const loadPromise = new Promise(resolve => iframe.onload = resolve); 73 document.body.appendChild(iframe); 74 await loadPromise; 75 76 const child_window = iframe.contentWindow; 77 const cachedCrashReport = child_window.crashReport; 78 await cachedCrashReport.initialize(256); 79 cachedCrashReport.set('key', 'value'); 80 81 assert_throws_dom('InvalidStateError', child_window.DOMException, () => { 82 // Detach the document. 83 iframe.remove(); 84 cachedCrashReport.remove('key', 'value'); 85 }); 86 }, 'crashReport.remove() throws InvalidStateError in detached Documents'); 87 88 promise_test(async t => { 89 const iframe = document.createElement('iframe'); 90 const loadPromise = new Promise(resolve => iframe.onload = resolve); 91 document.body.appendChild(iframe); 92 t.add_cleanup(() => iframe.remove()); 93 await loadPromise; 94 95 const child_window = iframe.contentWindow; 96 // The maximum allowed size is 5MB. 97 const large_size = 5 * 1024 * 1024 + 1; 98 await promise_rejects_dom(t, 'NotAllowedError', child_window.DOMException, 99 child_window.crashReport.initialize(large_size)); 100 }, 'crashReport.initialize() with size > 5MB rejects with NotAllowedError'); 101 102 promise_test(async t => { 103 const iframe = document.createElement('iframe'); 104 const loadPromise = new Promise(resolve => iframe.onload = resolve); 105 document.body.appendChild(iframe); 106 t.add_cleanup(() => iframe.remove()); 107 await loadPromise; 108 109 const child_window = iframe.contentWindow; 110 child_window.crashReport.initialize(1024); 111 await promise_rejects_dom(t, 'InvalidStateError', child_window.DOMException, 112 child_window.crashReport.initialize(1024)); 113 }, 'Calling crashReport.initialize() a second time throws InvalidStateError'); 114 115 promise_test(async t => { 116 const iframe = document.createElement('iframe'); 117 const loadPromise = new Promise(resolve => iframe.onload = resolve); 118 document.body.appendChild(iframe); 119 t.add_cleanup(() => iframe.remove()); 120 await loadPromise; 121 122 const child_window = iframe.contentWindow; 123 child_window.crashReport.initialize(1024); 124 assert_throws_dom('InvalidStateError', child_window.DOMException, () => { 125 child_window.crashReport.set('key', 'value'); 126 }); 127 }, 'crashReport.set() throws before initialize() resolves'); 128 129 promise_test(async t => { 130 const iframe = document.createElement('iframe'); 131 const loadPromise = new Promise(resolve => iframe.onload = resolve); 132 document.body.appendChild(iframe); 133 t.add_cleanup(() => iframe.remove()); 134 await loadPromise; 135 136 const child_window = iframe.contentWindow; 137 await child_window.crashReport.initialize(1024); 138 child_window.crashReport.set('key', 'value'); 139 child_window.crashReport.remove('key'); 140 }, 'crashReport.set() and .remove() succeed after initialize() resolves'); 141 142 promise_test(async t => { 143 const iframe = document.createElement('iframe'); 144 const loadPromise = new Promise(resolve => iframe.onload = resolve); 145 document.body.appendChild(iframe); 146 t.add_cleanup(() => iframe.remove()); 147 await loadPromise; 148 149 const child_window = iframe.contentWindow; 150 151 // 8 bytes is too small for the key/value pair "a"/"a" to be written; the 152 // memory required is 9 bytes, to support the JSONified format: 153 // 154 // {"a":"a"} 155 // 156 // Similarly, 17 bytes is required for "a"/"a" *and* "b"/"b" to be written, to 157 // support the format: 158 // 159 // {"a":"a","b":"b"} 160 await child_window.crashReport.initialize(8); 161 assert_throws_dom('NotAllowedError', child_window.DOMException, () => { 162 child_window.crashReport.set('a', 'a'); 163 }); 164 165 // This just fits in our 8-byte buffer though! 166 child_window.crashReport.set('b', ''); 167 }, 'crashReport.set() throws when there is not enough memory'); 168 169 promise_test(async t => { 170 const iframe = document.createElement('iframe'); 171 const loadPromise = new Promise(resolve => iframe.onload = resolve); 172 document.body.appendChild(iframe); 173 t.add_cleanup(() => iframe.remove()); 174 await loadPromise; 175 176 const child_window = iframe.contentWindow; 177 178 await child_window.crashReport.initialize(9); 179 child_window.crashReport.set('a', 'a'); 180 assert_throws_dom('NotAllowedError', child_window.DOMException, () => { 181 child_window.crashReport.set('b', 'b'); 182 }); 183 child_window.crashReport.remove('a'); 184 // Now `set()` will work again. 185 child_window.crashReport.set('b', 'b'); 186 }, 'crashReport.remove() properly frees memory, and allows you to invoke ' + 187 'set() again, assigning bytes to memory that was previously full'); 188 </script> 189 </body>