Commit 198fb2cf authored by Harley Li's avatar Harley Li Committed by Commit Bot

[DevTools] Expose all IndexedDB databases to DevTools

Before this patch, only the main frame's IndexedDBs are exposed in
DevTools>Application>IndexedDB panel.

Bug: 943770
Change-Id: Ia8e13e06065ca7ceedb83f8f6edf0dffabf63f2d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1539214Reviewed-by: default avatarJoel Einbinder <einbinder@chromium.org>
Commit-Queue: Haihong Li (Harley) <hhli@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649705}
parent e8f29ced
......@@ -26,7 +26,6 @@ ApplicationTestRunner.dumpCacheTreeNoRefresh = async function(pathFilter) {
TestRunner.addResult(' '.repeat(8) + entries.join(', '));
}
}
UI.panels.resources._sidebar.cacheStorageListTreeElement.expand();
if (!pathFilter)
......
......@@ -29,7 +29,6 @@
*/
/**
* @implements {SDK.TargetManager.Observer}
* @implements {SDK.SDKModelObserver<!Resources.DOMStorageModel>}
* @unrestricted
*/
Resources.ApplicationPanelSidebar = class extends UI.VBox {
......@@ -196,18 +195,22 @@ Resources.ApplicationPanelSidebar = class extends UI.VBox {
this._addCookieDocument(frame);
this._databaseModel.enable();
const indexedDBModel = this._target.model(Resources.IndexedDBModel);
if (indexedDBModel)
indexedDBModel.enable();
const cacheStorageModel = this._target.model(SDK.ServiceWorkerCacheModel);
if (cacheStorageModel)
cacheStorageModel.enable();
const resourceTreeModel = this._target.model(SDK.ResourceTreeModel);
if (resourceTreeModel)
this._populateApplicationCacheTree(resourceTreeModel);
SDK.targetManager.observeModels(Resources.DOMStorageModel, this);
SDK.targetManager.observeModels(Resources.DOMStorageModel, /** @type {!SDK.SDKModelObserver} */ ({
modelAdded: model => this._domStorageModelAdded(model),
modelRemoved: model => this._domStorageModelRemoved(model)
}));
this.indexedDBListTreeElement._initialize();
SDK.targetManager.observeModels(
Resources.IndexedDBModel, /** @type {!SDK.SDKModelObserver} */ ({
modelAdded: model => model.enable(),
modelRemoved: model => this.indexedDBListTreeElement.removeIndexedDBForModel(model)
}));
const serviceWorkerCacheModel = this._target.model(SDK.ServiceWorkerCacheModel);
this.cacheStorageListTreeElement._initialize(serviceWorkerCacheModel);
const backgroundServiceModel = this._target.model(Resources.BackgroundServiceModel);
......@@ -218,25 +221,22 @@ Resources.ApplicationPanelSidebar = class extends UI.VBox {
}
/**
* @override
* @param {!Resources.DOMStorageModel} domStorageModel
* @param {!Resources.DOMStorageModel} model
*/
modelAdded(domStorageModel) {
domStorageModel.enable();
domStorageModel.storages().forEach(this._addDOMStorage.bind(this));
domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
_domStorageModelAdded(model) {
model.enable();
model.storages().forEach(this._addDOMStorage.bind(this));
model.addEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
model.addEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
}
/**
* @override
* @param {!Resources.DOMStorageModel} domStorageModel
* @param {!Resources.DOMStorageModel} model
*/
modelRemoved(domStorageModel) {
domStorageModel.storages().forEach(this._removeDOMStorage.bind(this));
domStorageModel.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
domStorageModel.removeEventListener(
Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
_domStorageModelRemoved(model) {
model.storages().forEach(this._removeDOMStorage.bind(this));
model.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
model.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
}
_resetWithFrames() {
......@@ -287,8 +287,11 @@ Resources.ApplicationPanelSidebar = class extends UI.VBox {
this.cookieListTreeElement.removeChildren();
}
/**
* @param {!Common.Event} event
*/
_frameNavigated(event) {
const frame = event.data;
const frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data);
if (frame.isTopFrame())
this._reset();
......@@ -1137,6 +1140,15 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
}
}
/**
* @param {!Resources.IndexedDBModel} model
*/
removeIndexedDBForModel(model) {
const idbDatabaseTreeElements = this._idbDatabaseTreeElements.filter(element => element._model === model);
for (const idbDatabaseTreeElement of idbDatabaseTreeElements)
this._removeIDBDatabaseTreeElement(idbDatabaseTreeElement);
}
/**
* @override
*/
......@@ -1186,7 +1198,13 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
const idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, databaseId);
if (!idbDatabaseTreeElement)
return;
this._removeIDBDatabaseTreeElement(idbDatabaseTreeElement);
}
/**
* @param {!Resources.IDBDatabaseTreeElement} idbDatabaseTreeElement
*/
_removeIDBDatabaseTreeElement(idbDatabaseTreeElement) {
idbDatabaseTreeElement.clear();
this.removeChild(idbDatabaseTreeElement);
this._idbDatabaseTreeElements.remove(idbDatabaseTreeElement);
......@@ -1205,6 +1223,11 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
if (!idbDatabaseTreeElement)
return;
idbDatabaseTreeElement.update(database, entriesUpdated);
this._indexedDBLoadedForTest();
}
_indexedDBLoadedForTest() {
// For sniffing in tests.
}
/**
......@@ -1222,23 +1245,12 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
}
/**
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
* @param {!Resources.IndexedDBModel} model
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
* @return {?Resources.IDBDatabaseTreeElement}
*/
_idbDatabaseTreeElement(model, databaseId) {
let index = -1;
let i;
for (i = 0; i < this._idbDatabaseTreeElements.length; ++i) {
if (this._idbDatabaseTreeElements[i]._databaseId.equals(databaseId) &&
this._idbDatabaseTreeElements[i]._model === model) {
index = i;
break;
}
}
if (index !== -1)
return this._idbDatabaseTreeElements[i];
return null;
return this._idbDatabaseTreeElements.find(x => x._databaseId.equals(databaseId) && x._model === model) || null;
}
};
......
......@@ -499,7 +499,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
}
};
SDK.SDKModel.register(Resources.IndexedDBModel, SDK.Target.Capability.None, false);
SDK.SDKModel.register(Resources.IndexedDBModel, SDK.Target.Capability.DOM, false);
Resources.IndexedDBModel.KeyTypes = {
NumberType: 'number',
......
Tests Application Panel's handling of storages in iframes.
Initial tree...
Application
Manifest
Service Workers
Clear storage
Storage
Local Storage
http://127.0.0.1:8000
http://localhost:8000
Session Storage
http://127.0.0.1:8000
http://localhost:8000
IndexedDB
Database-iframe - http://localhost:8000
Database-iframe
Database-main-frame - http://127.0.0.1:8000
Web SQL
Cookies
http://127.0.0.1:8000
http://localhost:8000
Cache
Cache Storage
Application Cache
Frames
top
Remove iframe from page...
Application
Manifest
Service Workers
Clear storage
Storage
Local Storage
http://127.0.0.1:8000
Session Storage
http://127.0.0.1:8000
IndexedDB
Database-main-frame - http://127.0.0.1:8000
Web SQL
Cookies
http://127.0.0.1:8000
http://localhost:8000
Cache
Cache Storage
Application Cache
Frames
top
Add iframe to page again...
Application
Manifest
Service Workers
Clear storage
Storage
Local Storage
http://127.0.0.1:8000
http://localhost:8000
Session Storage
http://127.0.0.1:8000
http://localhost:8000
IndexedDB
Database-main-frame - http://127.0.0.1:8000
Database-iframe - http://localhost:8000
Database-iframe
Web SQL
Cookies
http://127.0.0.1:8000
http://localhost:8000
Cache
Cache Storage
Application Cache
Frames
top
// Copyright 2019 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.
(async function() {
TestRunner.addResult(`Tests Application Panel's handling of storages in iframes.\n`);
await TestRunner.loadModule('application_test_runner');
// Note: every test that uses a storage API must manually clean-up state from previous tests.
await ApplicationTestRunner.resetState();
await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('resources');
function createIndexedDBInMainFrame(callback) {
var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
var model = TestRunner.mainTarget.model(Resources.IndexedDBModel);
ApplicationTestRunner.createDatabase(mainFrameId, 'Database-main-frame', () => {
var event = model.addEventListener(Resources.IndexedDBModel.Events.DatabaseAdded, () => {
Common.EventTarget.removeEventListeners([event]);
callback();
});
model.refreshDatabaseNames();
});
}
function dumpTree(node, level) {
for (var child of node.children()) {
TestRunner.addResult(' '.repeat(level) + child.listItemElement.textContent);
dumpTree(child, level + 1);
}
}
// create IndexedDB in iframe
await TestRunner.addIframe('http://localhost:8000/devtools/application-panel/resources/indexeddb-in-iframe.html', {'id': 'indexeddb_page'});
await TestRunner.addSnifferPromise(UI.panels.resources._sidebar.indexedDBListTreeElement, '_indexedDBLoadedForTest');
// create IndexedDB in main frame
await new Promise(createIndexedDBInMainFrame);
await TestRunner.addSnifferPromise(UI.panels.resources._sidebar.indexedDBListTreeElement, '_indexedDBLoadedForTest');
const view = UI.panels.resources;
TestRunner.addResult('Initial tree...\n');
dumpTree(view._sidebar._sidebarTree.rootElement(), 0);
TestRunner.addResult('\nRemove iframe from page...\n');
await TestRunner.evaluateInPageAsync(`
(function(){
let iframe = document.getElementById('indexeddb_page');
iframe.parentNode.removeChild(iframe);
})();
`);
dumpTree(view._sidebar._sidebarTree.rootElement(), 0);
TestRunner.addResult('\nAdd iframe to page again...\n');
await TestRunner.addIframe('http://localhost:8000/devtools/application-panel/resources/indexeddb-in-iframe.html', {'id': 'indexeddb_page'});
await TestRunner.addSnifferPromise(UI.panels.resources._sidebar.indexedDBListTreeElement, '_indexedDBLoadedForTest');
dumpTree(view._sidebar._sidebarTree.rootElement(), 0);
TestRunner.completeTest();
})();
......@@ -43,11 +43,6 @@
TestRunner.addResult('Visible view is a cookie view: ' + (view.visibleView instanceof Resources.CookieItemsView));
}
function fireFrameNavigated() {
var rtm = TestRunner.resourceTreeModel;
rtm.dispatchEventToListeners(SDK.ResourceTreeModel.Events.FrameNavigated, rtm.mainFrame);
}
await new Promise(createIndexedDB);
await ApplicationTestRunner.createWebSQLDatabase('database-for-test');
UI.viewManager.showView('resources');
......
<script>
function makeDB() {
return new Promise((resolve) => {
indexedDB.open('Database-iframe').onupgradeneeded = event => {
const db = event.target.result;
const objectStore = db.createObjectStore('Database-iframe');
objectStore.transaction.oncomplete = _ => {
indexedDB.open('Database-iframe').onsuccess = event => event.target.result
.transaction('Database-iframe', 'readwrite')
.objectStore('Database-iframe')
.add(940123, 'key');
}
resolve();
}
});
}
window.addEventListener("load", async function(e) {
await makeDB();
}, false);
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment