1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/devtools/server/tests/browser/browser_storage_dynamic_windows.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,353 @@ 1.4 +const Cu = Components.utils; 1.5 +Cu.import("resource://gre/modules/Services.jsm"); 1.6 +let tempScope = {}; 1.7 +Cu.import("resource://gre/modules/devtools/dbg-client.jsm", tempScope); 1.8 +Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope); 1.9 +Cu.import("resource://gre/modules/Promise.jsm", tempScope); 1.10 +let {DebuggerServer, DebuggerClient, Promise} = tempScope; 1.11 +tempScope = null; 1.12 + 1.13 +const {StorageFront} = require("devtools/server/actors/storage"); 1.14 +let gFront, gWindow; 1.15 + 1.16 +const beforeReload = { 1.17 + cookies: { 1.18 + "test1.example.org": ["c1", "cs2", "c3", "uc1"], 1.19 + "sectest1.example.org": ["uc1", "cs2"] 1.20 + }, 1.21 + localStorage: { 1.22 + "http://test1.example.org": ["ls1", "ls2"], 1.23 + "http://sectest1.example.org": ["iframe-u-ls1"] 1.24 + }, 1.25 + sessionStorage: { 1.26 + "http://test1.example.org": ["ss1"], 1.27 + "http://sectest1.example.org": ["iframe-u-ss1", "iframe-u-ss2"] 1.28 + }, 1.29 + indexedDB: { 1.30 + "http://test1.example.org": [ 1.31 + JSON.stringify(["idb1", "obj1"]), 1.32 + JSON.stringify(["idb1", "obj2"]), 1.33 + JSON.stringify(["idb2", "obj3"]), 1.34 + ], 1.35 + "http://sectest1.example.org": [] 1.36 + } 1.37 +}; 1.38 + 1.39 +function finishTests(client) { 1.40 + // Cleanup so that indexed db created from this test do not interfere next ones 1.41 + 1.42 + /** 1.43 + * This method iterates over iframes in a window and clears the indexed db 1.44 + * created by this test. 1.45 + */ 1.46 + let clearIDB = (w, i, c) => { 1.47 + if (w[i] && w[i].clear) { 1.48 + w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c)); 1.49 + w[i].clearIterator.next(); 1.50 + } 1.51 + else if (w[i] && w[i + 1]) { 1.52 + clearIDB(w, i + 1, c); 1.53 + } 1.54 + else { 1.55 + c(); 1.56 + } 1.57 + }; 1.58 + 1.59 + let closeConnection = () => { 1.60 + // Forcing GC/CC to get rid of docshells and windows created by this test. 1.61 + forceCollections(); 1.62 + client.close(() => { 1.63 + forceCollections(); 1.64 + DebuggerServer.destroy(); 1.65 + forceCollections(); 1.66 + gFront = gWindow = DebuggerClient = DebuggerServer = null; 1.67 + finish(); 1.68 + }); 1.69 + } 1.70 + gWindow.clearIterator = gWindow.clear(() => { 1.71 + clearIDB(gWindow, 0, closeConnection); 1.72 + }); 1.73 + gWindow.clearIterator.next(); 1.74 +} 1.75 + 1.76 +function testStores(data, client) { 1.77 + testWindowsBeforeReload(data); 1.78 + testReload().then(() => 1.79 + testAddIframe()).then(() => 1.80 + testRemoveIframe()).then(() => 1.81 + finishTests(client)); 1.82 +} 1.83 + 1.84 +function testWindowsBeforeReload(data) { 1.85 + for (let storageType in beforeReload) { 1.86 + ok(data[storageType], storageType + " storage actor is present"); 1.87 + is(Object.keys(data[storageType].hosts).length, 1.88 + Object.keys(beforeReload[storageType]).length, 1.89 + "Number of hosts for " + storageType + "match"); 1.90 + for (let host in beforeReload[storageType]) { 1.91 + ok(data[storageType].hosts[host], "Host " + host + " is present"); 1.92 + } 1.93 + } 1.94 +} 1.95 + 1.96 +function markOutMatched(toBeEmptied, data, deleted) { 1.97 + if (!Object.keys(toBeEmptied).length) { 1.98 + info("Object empty") 1.99 + return; 1.100 + } 1.101 + ok(Object.keys(data).length, 1.102 + "Atleast some storage types should be present in deleted"); 1.103 + for (let storageType in toBeEmptied) { 1.104 + if (!data[storageType]) { 1.105 + continue; 1.106 + } 1.107 + info("Testing for " + storageType); 1.108 + for (let host in data[storageType]) { 1.109 + ok(toBeEmptied[storageType][host], "Host " + host + " found"); 1.110 + if (!deleted) { 1.111 + for (let item of data[storageType][host]) { 1.112 + let index = toBeEmptied[storageType][host].indexOf(item); 1.113 + ok(index > -1, "Item found - " + item); 1.114 + if (index > -1) { 1.115 + toBeEmptied[storageType][host].splice(index, 1); 1.116 + } 1.117 + } 1.118 + if (!toBeEmptied[storageType][host].length) { 1.119 + delete toBeEmptied[storageType][host]; 1.120 + } 1.121 + } 1.122 + else { 1.123 + delete toBeEmptied[storageType][host]; 1.124 + } 1.125 + } 1.126 + if (!Object.keys(toBeEmptied[storageType]).length) { 1.127 + delete toBeEmptied[storageType]; 1.128 + } 1.129 + } 1.130 +} 1.131 + 1.132 +function testReload() { 1.133 + info("Testing if reload works properly"); 1.134 + 1.135 + let shouldBeEmptyFirst = Cu.cloneInto(beforeReload, {}); 1.136 + let shouldBeEmptyLast = Cu.cloneInto(beforeReload, {}); 1.137 + let reloaded = Promise.defer(); 1.138 + 1.139 + let onStoresUpdate = data => { 1.140 + info("in stores update of testReload"); 1.141 + // This might be second time stores update is happening, in which case, 1.142 + // data.deleted will be null. 1.143 + // OR.. This might be the first time on a super slow machine where both 1.144 + // data.deleted and data.added is missing in the first update. 1.145 + if (data.deleted) { 1.146 + markOutMatched(shouldBeEmptyFirst, data.deleted, true); 1.147 + } 1.148 + 1.149 + if (!Object.keys(shouldBeEmptyFirst).length) { 1.150 + info("shouldBeEmptyFirst is empty now"); 1.151 + } 1.152 + 1.153 + // stores-update call might not have data.added for the first time on slow 1.154 + // machines, in which case, data.added will be null 1.155 + if (data.added) { 1.156 + markOutMatched(shouldBeEmptyLast, data.added); 1.157 + } 1.158 + 1.159 + if (!Object.keys(shouldBeEmptyLast).length) { 1.160 + info("Everything to be received is received."); 1.161 + endTestReloaded(); 1.162 + } 1.163 + }; 1.164 + 1.165 + let endTestReloaded = () => { 1.166 + gFront.off("stores-update", onStoresUpdate); 1.167 + reloaded.resolve(); 1.168 + }; 1.169 + 1.170 + gFront.on("stores-update", onStoresUpdate); 1.171 + 1.172 + content.location.reload(); 1.173 + return reloaded.promise; 1.174 +} 1.175 + 1.176 +function testAddIframe() { 1.177 + info("Testing if new iframe addition works properly"); 1.178 + let reloaded = Promise.defer(); 1.179 + 1.180 + let shouldBeEmpty = { 1.181 + localStorage: { 1.182 + "https://sectest1.example.org": ["iframe-s-ls1"] 1.183 + }, 1.184 + sessionStorage: { 1.185 + "https://sectest1.example.org": ["iframe-s-ss1"] 1.186 + }, 1.187 + cookies: { 1.188 + "sectest1.example.org": ["sc1"] 1.189 + }, 1.190 + indexedDB: { 1.191 + // empty because indexed db creation happens after the page load, so at 1.192 + // the time of window-ready, there was no indexed db present. 1.193 + "https://sectest1.example.org": [] 1.194 + } 1.195 + }; 1.196 + 1.197 + let onStoresUpdate = data => { 1.198 + info("checking if the hosts list is correct for this iframe addition"); 1.199 + 1.200 + markOutMatched(shouldBeEmpty, data.added); 1.201 + 1.202 + ok(!data.changed || !data.changed.cookies || 1.203 + !data.changed.cookies["https://sectest1.example.org"], 1.204 + "Nothing got changed for cookies"); 1.205 + ok(!data.changed || !data.changed.localStorage || 1.206 + !data.changed.localStorage["https://sectest1.example.org"], 1.207 + "Nothing got changed for local storage"); 1.208 + ok(!data.changed || !data.changed.sessionStorage || 1.209 + !data.changed.sessionStorage["https://sectest1.example.org"], 1.210 + "Nothing got changed for session storage"); 1.211 + ok(!data.changed || !data.changed.indexedDB || 1.212 + !data.changed.indexedDB["https://sectest1.example.org"], 1.213 + "Nothing got changed for indexed db"); 1.214 + 1.215 + ok(!data.deleted || !data.deleted.cookies || 1.216 + !data.deleted.cookies["https://sectest1.example.org"], 1.217 + "Nothing got deleted for cookies"); 1.218 + ok(!data.deleted || !data.deleted.localStorage || 1.219 + !data.deleted.localStorage["https://sectest1.example.org"], 1.220 + "Nothing got deleted for local storage"); 1.221 + ok(!data.deleted || !data.deleted.sessionStorage || 1.222 + !data.deleted.sessionStorage["https://sectest1.example.org"], 1.223 + "Nothing got deleted for session storage"); 1.224 + ok(!data.deleted || !data.deleted.indexedDB || 1.225 + !data.deleted.indexedDB["https://sectest1.example.org"], 1.226 + "Nothing got deleted for indexed db"); 1.227 + 1.228 + if (!Object.keys(shouldBeEmpty).length) { 1.229 + info("Everything to be received is received."); 1.230 + endTestReloaded(); 1.231 + } 1.232 + }; 1.233 + 1.234 + let endTestReloaded = () => { 1.235 + gFront.off("stores-update", onStoresUpdate); 1.236 + reloaded.resolve(); 1.237 + }; 1.238 + 1.239 + gFront.on("stores-update", onStoresUpdate); 1.240 + 1.241 + let iframe = content.document.createElement("iframe"); 1.242 + iframe.src = ALT_DOMAIN_SECURED + "storage-secured-iframe.html"; 1.243 + content.document.querySelector("body").appendChild(iframe); 1.244 + return reloaded.promise; 1.245 +} 1.246 + 1.247 +function testRemoveIframe() { 1.248 + info("Testing if iframe removal works properly"); 1.249 + let reloaded = Promise.defer(); 1.250 + 1.251 + let shouldBeEmpty = { 1.252 + localStorage: { 1.253 + "http://sectest1.example.org": [] 1.254 + }, 1.255 + sessionStorage: { 1.256 + "http://sectest1.example.org": [] 1.257 + } 1.258 + }; 1.259 + 1.260 + let onStoresUpdate = data => { 1.261 + info("checking if the hosts list is correct for this iframe deletion"); 1.262 + 1.263 + markOutMatched(shouldBeEmpty, data.deleted, true); 1.264 + 1.265 + ok(!data.deleted.cookies || !data.deleted.cookies["sectest1.example.org"], 1.266 + "Nothing got deleted for Cookies as the same hostname is still present"); 1.267 + 1.268 + ok(!data.changed || !data.changed.cookies || 1.269 + !data.changed.cookies["http://sectest1.example.org"], 1.270 + "Nothing got changed for cookies"); 1.271 + ok(!data.changed || !data.changed.localStorage || 1.272 + !data.changed.localStorage["http://sectest1.example.org"], 1.273 + "Nothing got changed for local storage"); 1.274 + ok(!data.changed || !data.changed.sessionStorage || 1.275 + !data.changed.sessionStorage["http://sectest1.example.org"], 1.276 + "Nothing got changed for session storage"); 1.277 + 1.278 + ok(!data.added || !data.added.cookies || 1.279 + !data.added.cookies["http://sectest1.example.org"], 1.280 + "Nothing got added for cookies"); 1.281 + ok(!data.added || !data.added.localStorage || 1.282 + !data.added.localStorage["http://sectest1.example.org"], 1.283 + "Nothing got added for local storage"); 1.284 + ok(!data.added || !data.added.sessionStorage || 1.285 + !data.added.sessionStorage["http://sectest1.example.org"], 1.286 + "Nothing got added for session storage"); 1.287 + 1.288 + if (!Object.keys(shouldBeEmpty).length) { 1.289 + info("Everything to be received is received."); 1.290 + endTestReloaded(); 1.291 + } 1.292 + }; 1.293 + 1.294 + let endTestReloaded = () => { 1.295 + gFront.off("stores-update", onStoresUpdate); 1.296 + reloaded.resolve(); 1.297 + }; 1.298 + 1.299 + gFront.on("stores-update", onStoresUpdate); 1.300 + 1.301 + for (let iframe of content.document.querySelectorAll("iframe")) { 1.302 + if (iframe.src.startsWith("http:")) { 1.303 + iframe.remove(); 1.304 + break; 1.305 + } 1.306 + } 1.307 + return reloaded.promise; 1.308 +} 1.309 + 1.310 +function test() { 1.311 + waitForExplicitFinish(); 1.312 + addTab(MAIN_DOMAIN + "storage-dynamic-windows.html", function(doc) { 1.313 + try { 1.314 + // Sometimes debugger server does not get destroyed correctly by previous 1.315 + // tests. 1.316 + DebuggerServer.destroy(); 1.317 + } catch (ex) { } 1.318 + DebuggerServer.init(function () { return true; }); 1.319 + DebuggerServer.addBrowserActors(); 1.320 + 1.321 + let createConnection = () => { 1.322 + let client = new DebuggerClient(DebuggerServer.connectPipe()); 1.323 + client.connect(function onConnect() { 1.324 + client.listTabs(function onListTabs(aResponse) { 1.325 + let form = aResponse.tabs[aResponse.selected]; 1.326 + gFront = StorageFront(client, form); 1.327 + 1.328 + gFront.listStores().then(data => testStores(data, client)); 1.329 + }); 1.330 + }); 1.331 + }; 1.332 + 1.333 + /** 1.334 + * This method iterates over iframes in a window and setups the indexed db 1.335 + * required for this test. 1.336 + */ 1.337 + let setupIDBInFrames = (w, i, c) => { 1.338 + if (w[i] && w[i].idbGenerator) { 1.339 + w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c)); 1.340 + w[i].setupIDB.next(); 1.341 + } 1.342 + else if (w[i] && w[i + 1]) { 1.343 + setupIDBInFrames(w, i + 1, c); 1.344 + } 1.345 + else { 1.346 + c(); 1.347 + } 1.348 + }; 1.349 + // Setup the indexed db in main window. 1.350 + gWindow = doc.defaultView.wrappedJSObject; 1.351 + gWindow.setupIDB = gWindow.idbGenerator(() => { 1.352 + setupIDBInFrames(gWindow, 0, createConnection); 1.353 + }); 1.354 + gWindow.setupIDB.next(); 1.355 + }); 1.356 +}