Index: chrome/test/data/extensions/platform_apps/web_view/isolation_indexeddb/main.js |
diff --git a/chrome/test/data/extensions/platform_apps/web_view/isolation_indexeddb/main.js b/chrome/test/data/extensions/platform_apps/web_view/isolation_indexeddb/main.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cde86be53be1e3b7e777bded33ed9b06fb536fdf |
--- /dev/null |
+++ b/chrome/test/data/extensions/platform_apps/web_view/isolation_indexeddb/main.js |
@@ -0,0 +1,254 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+var LOG = function(msg) { |
+ window.console.log(msg); |
+}; |
+ |
+// Wrapper class for a <webview> guest. |
+function Guest(id, webview) { |
+ this.id_ = id; |
+ this.webview_ = webview; |
+}; |
+ |
+// Runs a single verification |step| for this test. |
+// |
+// A step is asynchronous and involves sending postMessage to a <webview> and |
+// receiving a reply postMessage back from the <webview>. |
+Guest.prototype.sendStepRequestAndWait = function( |
+ step, successCallback, failureCallback) { |
+ this.expectedMessage_ = step.expect; |
+ this.successCallback_ = successCallback; |
+ this.failureCallback_ = failureCallback; |
+ this.expectingResponse_ = true; |
+ step.id = this.id_; |
+ this.webview_.contentWindow.postMessage(JSON.stringify(step), '*'); |
+}; |
+ |
+// Runs verification steps for this test listed in |stepList|. |
+Guest.prototype.runIDBSteps = function( |
+ stepList, successCallback, failureCallback) { |
+ if (!stepList.length) { |
+ LOG('error, runIDBSteps() require at least one step to run'); |
+ failureCallback(); |
+ return; |
+ } |
+ |
+ var currentStep = 0; |
+ // Proceeds to next step upon success. |
+ var stepSuccessCallback = function() { |
+ ++currentStep; |
+ if (currentStep == stepList.length) { |
+ // All steps succeeded. |
+ successCallback(); |
+ return; |
+ } |
+ this.sendStepRequestAndWait(stepList[currentStep], stepSuccessCallback, |
+ failureCallback); |
+ }.bind(this); |
+ this.sendStepRequestAndWait(stepList[currentStep], stepSuccessCallback, |
+ failureCallback); |
+}; |
+ |
+// Post message handler for this |Guest|. |
+Guest.prototype.onResponse = function(responseStr) { |
+ if (!this.expectingResponse_) { |
+ return; |
+ } |
+ if (this.expectedMessage_ !== responseStr) { |
+ LOG('Expected response from guest[' + this.id_ + ']: ' + |
+ this.expectedMessage_ + ' but received: ' + |
+ responseStr); |
+ this.failureCallback_(); |
+ } else { |
+ this.successCallback_(); |
+ } |
+}; |
+ |
+// Tester class to run test steps. |
+function Tester(port) { |
+ this.port_ = port; |
+ window.onmessage = this.onMessage_.bind(this); |
+ this.failed_ = false; |
+}; |
+ |
+Tester.prototype.getURL = function(filename) { |
+ return 'http://localhost:' + this.port_ + |
+ '/extensions/platform_apps/web_view/isolation_indexeddb/' + filename; |
+}; |
+ |
+Tester.prototype.loadGuest = function(guestInfo, callback) { |
+ var id = guestInfo.id; |
+ var partition = guestInfo.partition; |
+ var html = guestInfo.html; |
+ var js = guestInfo.js; |
+ |
+ var webview = document.createElement('webview'); |
+ if (partition) { |
+ webview.setAttribute('partition', partition); |
+ } |
+ webview.src = this.getURL(html); |
+ |
+ var loadFailed = false; |
+ webview.onloadstop = function(e) { |
+ LOG('webview.onloadstop: ' + id); |
+ if (loadFailed) { |
+ return; |
+ } |
+ |
+ var guest = new Guest(id, webview); |
+ webview.executeScript({file: js} , function(results) { |
+ if (!results || !results.length) { |
+ loadFailed = true; |
+ callback(null); |
+ } |
+ callback(id, new Guest(id, webview)); |
+ }.bind(this)); |
+ }.bind(this); |
+ |
+ webview.onloadabort = function(e) { |
+ loadFailed = true; |
+ callback(undefined); |
+ }; |
+ |
+ webview.onconsolemessage = function(e) { |
+ LOG('G: ' + e.message); |
+ }; |
+ document.body.appendChild(webview); |
+}; |
+ |
+Tester.prototype.loadGuests = function(guestInfoList, doneCallback) { |
+ var failed = false; |
+ var responses = []; |
+ var numResponses = 0; |
+ var completedCallack = function(id, guest) { |
+ if (failed) { // We've already failed. |
+ return; |
+ } |
+ if (!guest) { |
+ // guest didn't load. |
+ failed = true; |
+ doneCallback(undefined); |
+ return; |
+ } |
+ responses[id] = guest; |
+ ++numResponses; |
+ if (numResponses == guestInfoList.length) { |
+ // We are done. |
+ doneCallback(responses); |
+ } |
+ }; |
+ for (var i = 0; i < guestInfoList.length; ++i) { |
+ this.loadGuest(guestInfoList[i], completedCallack); |
+ } |
+}; |
+ |
+Tester.prototype.runTest = function() { |
+ var guestInfoList = [ |
+ {id: 1, html: 'storage1.html', js: 'storage.js', partition: 'partition1'}, |
+ {id: 2, html: 'storage2.html', js: 'storage.js', partition: 'partition1'}, |
+ {id: 3, html: 'storage3.html', js: 'storage.js'} |
+ ]; |
+ this.loadGuests(guestInfoList, function doneCallback(guests) { |
+ if (!guests) { |
+ LOG('One or all guests failed to load'); |
+ this.testFail(); |
+ return; |
+ } |
+ |
+ LOG('guests load complete'); |
+ this.guests_ = guests; |
+ // Loaded all the guests. |
+ this.runStep1(); |
+ }.bind(this)); |
+}; |
+ |
+// Initializes the storage for the first <webview>. |
+Tester.prototype.runStep1 = function() { |
+ var guest = this.guests_[1]; |
+ guest.runIDBSteps([ |
+ {name: 'init', expect: 'idb created'}, |
+ {name: 'add', params: [7, 'page1'], expect: 'addItemIDB complete'}, |
+ {name: 'read', params: [7], expect: 'readItemIDB: page1'}, |
+ ], this.runStep2.bind(this), this.testFail.bind(this)); |
+}; |
+ |
+// Initializes the storage for the second <webview>, which share a storage |
+// partition with the first <webview>. |
+Tester.prototype.runStep2 = function() { |
+ var guest = this.guests_[2]; |
+ guest.runIDBSteps([ |
+ {name: 'init', expect: 'idb open'}, |
+ {name: 'add', params: [7, 'page2'], expect: 'addItemIDB complete'}, |
+ {name: 'read', params: [7], expect: 'readItemIDB: page2'}, |
+ ], this.runStep3.bind(this), this.testFail.bind(this)); |
+}; |
+ |
+// Reads through the first <webview> to ensure we have the second value. |
+Tester.prototype.runStep3 = function() { |
+ var guest = this.guests_[1]; |
+ guest.runIDBSteps([ |
+ {name: 'read', params: [7], expect: 'readItemIDB: page2'}, |
+ ], this.runStep4.bind(this), this.testFail.bind(this)); |
+}; |
+ |
+// Confirms that the first two <webview>s do not affect the database |
+// of the main browser (embedder). |
+Tester.prototype.runStep4 = function() { |
+ var request = indexedDB.open('isolation'); |
+ request.onsuccess = function(e) { |
+ var version = e.target.result.version; |
+ // Expect version = 1. |
+ if (version == 1) { |
+ this.runStep5(); // Continue to next step. |
+ } else { |
+ this.testFail(); |
+ } |
+ }.bind(this); |
+ request.onerror = this.testFail.bind(this); |
+ request.onblocked = this.testFail.bind(this); |
+}; |
+ |
+// Confirms that a third <webview>'s storage does not get affect by the |
+// other two <webview>s. |
+Tester.prototype.runStep5 = function() { |
+ var guest = this.guests_[3]; |
+ guest.runIDBSteps([ |
+ {name: 'open', params: ['isolation'], expect: 'db not found'}, |
+ ], this.testPass(this), this.testFail.bind(this)); |
+}; |
+ |
+// Central postMessage handler. |
+Tester.prototype.onMessage_ = function(e) { |
+ var data = JSON.parse(e.data); |
+ var id = data[0]; |
+ if (typeof id !== 'number' || id < 0 || id >= this.guests_.length) { |
+ LOG('unexpeced guest id: ' + id); |
+ this.testFail(); |
+ return; |
+ } |
+ |
+ // Re-route message to the appropriate guest. |
+ this.guests_[id].onResponse(data[1]); |
+}; |
+ |
+Tester.prototype.testFail = function() { |
+ this.failed_ = true; |
+ chrome.test.fail(); |
+}; |
+ |
+Tester.prototype.testPass = function() { |
+ if (this.failed_) { // We've failed already. |
+ return; |
+ } |
+ chrome.test.succeed(); |
+}; |
+ |
+chrome.test.getConfig(function(config) { |
+ chrome.test.runTests([ |
+ function indexedDBIsolation() { |
+ var tester = new Tester(config.testServer.port); |
+ tester.runTest(); |
+ }]); |
+}); |