Backed out changeset 100f3ba430f9 (bug 871445)

This commit is contained in:
Ed Morley 2013-10-02 17:57:49 +01:00
parent cecd6b1998
commit e357dbae06
8 changed files with 34 additions and 603 deletions

View File

@ -8,26 +8,13 @@
var EXPORTED_SYMBOLS = ["DataStore"]; var EXPORTED_SYMBOLS = ["DataStore"];
function debug(s) {
// dump('DEBUG DataStore: ' + s + '\n');
}
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/DataStoreDB.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
Cu.import('resource://gre/modules/Services.jsm');
/* DataStore object */ /* DataStore object */
function DataStore(aAppId, aName, aOwner, aReadOnly, aGlobalScope) { function DataStore(aAppId, aName, aOwner, aReadOnly) {
this.appId = aAppId; this.appId = aAppId;
this.name = aName; this.name = aName;
this.owner = aOwner; this.owner = aOwner;
this.readOnly = aReadOnly; this.readOnly = aReadOnly;
this.db = new DataStoreDB();
this.db.init(aOwner, aName, aGlobalScope);
} }
DataStore.prototype = { DataStore.prototype = {
@ -36,113 +23,9 @@ DataStore.prototype = {
owner: null, owner: null,
readOnly: null, readOnly: null,
newDBPromise: function(aWindow, aTxnType, aFunction) {
let db = this.db;
return new aWindow.Promise(function(aResolve, aReject) {
debug("DBPromise started");
db.txn(
aTxnType,
function(aTxn, aStore) {
debug("DBPromise success");
aFunction(aResolve, aReject, aTxn, aStore);
},
function() {
debug("DBPromise error");
aReject(new aWindow.DOMError("InvalidStateError"));
}
);
});
},
getInternal: function(aWindow, aResolve, aReject, aStore, aId) {
debug("GetInternal " + aId);
let request = aStore.get(aId);
request.onsuccess = function(aEvent) {
debug("GetInternal success. Record: " + aEvent.target.result);
aResolve(ObjectWrapper.wrap(aEvent.target.result, aWindow));
};
request.onerror = function(aEvent) {
debug("GetInternal error");
aReject(new aWindow.DOMError(aEvent.target.error.name));
};
},
updateInternal: function(aWindow, aResolve, aReject, aStore, aId, aObj) {
debug("UpdateInternal " + aId);
let request = aStore.put(aObj, aId);
request.onsuccess = function(aEvent) {
debug("UpdateInternal success");
// No wrap here because the result is always a int.
aResolve(aEvent.target.result);
};
request.onerror = function(aEvent) {
debug("UpdateInternal error");
aReject(new aWindow.DOMError(aEvent.target.error.name));
};
},
addInternal: function(aWindow, aResolve, aReject, aStore, aObj) {
debug("AddInternal");
let request = aStore.put(aObj);
request.onsuccess = function(aEvent) {
debug("Request successful. Id: " + aEvent.target.result);
// No wrap here because the result is always a int.
aResolve(aEvent.target.result);
};
request.onerror = function(aEvent) {
debug("AddInternal error");
aReject(new aWindow.DOMError(aEvent.target.error.name));
};
},
removeInternal: function(aResolve, aReject, aStore, aId) {
debug("RemoveInternal");
let request = aStore.delete(aId);
request.onsuccess = function() {
debug("RemoveInternal success");
aResolve();
};
request.onerror = function(aEvent) {
debug("RemoveInternal error");
aReject(new aWindow.DOMError(aEvent.target.error.name));
};
},
clearInternal: function(aResolve, aReject, aStore) {
debug("ClearInternal");
let request = aStore.clear();
request.onsuccess = function() {
debug("ClearInternal success");
aResolve();
};
request.onerror = function(aEvent) {
debug("ClearInternal error");
aReject(new aWindow.DOMError(aEvent.target.error.name));
};
},
throwInvalidArg: function(aWindow) {
return aWindow.Promise.reject(
new aWindow.DOMError("SyntaxError", "Non-numeric or invalid id"));
},
throwReadOnly: function(aWindow) {
return aWindow.Promise.reject(
new aWindow.DOMError("ReadOnlyError", "DataStore in readonly mode"));
},
exposeObject: function(aWindow) { exposeObject: function(aWindow) {
let self = this; let self = this;
let object = { let chromeObject = {
// Public interface :
get name() { get name() {
return self.name; return self.name;
}, },
@ -155,83 +38,13 @@ DataStore.prototype = {
return self.readOnly; return self.readOnly;
}, },
get: function DS_get(aId) {
aId = parseInt(aId);
if (isNaN(aId) || aId <= 0) {
return self.throwInvalidArg(aWindow);
}
// Promise<Object>
return self.newDBPromise(aWindow, "readonly",
function(aResolve, aReject, aTxn, aStore) {
self.getInternal(aWindow, aResolve, aReject, aStore, aId);
}
);
},
update: function DS_update(aId, aObj) {
aId = parseInt(aId);
if (isNaN(aId) || aId <= 0) {
return self.throwInvalidArg(aWindow);
}
if (self.readOnly) {
return self.throwReadOnly(aWindow);
}
// Promise<void>
return self.newDBPromise(aWindow, "readwrite",
function(aResolve, aReject, aTxn, aStore) {
self.updateInternal(aWindow, aResolve, aReject, aStore, aId, aObj);
}
);
},
add: function DS_add(aObj) {
if (self.readOnly) {
return self.throwReadOnly(aWindow);
}
// Promise<int>
return self.newDBPromise(aWindow, "readwrite",
function(aResolve, aReject, aTxn, aStore) {
self.addInternal(aWindow, aResolve, aReject, aStore, aObj);
}
);
},
remove: function DS_remove(aId) {
aId = parseInt(aId);
if (isNaN(aId) || aId <= 0) {
return self.throwInvalidArg(aWindow);
}
if (self.readOnly) {
return self.throwReadOnly(aWindow);
}
// Promise<void>
return self.newDBPromise(aWindow, "readwrite",
function(aResolve, aReject, aTxn, aStore) {
self.removeInternal(aResolve, aReject, aStore, aId);
}
);
},
clear: function DS_clear() {
if (self.readOnly) {
return self.throwReadOnly(aWindow);
}
// Promise<void>
return self.newDBPromise(aWindow, "readwrite",
function(aResolve, aReject, aTxn, aStore) {
self.clearInternal(aResolve, aReject, aStore);
}
);
},
/* TODO: /* TODO:
Promise<Object> get(unsigned long id);
Promise<void> update(unsigned long id, any obj);
Promise<int> add(any obj)
Promise<boolean> remove(unsigned long id)
Promise<void> clear();
readonly attribute DOMString revisionId readonly attribute DOMString revisionId
attribute EventHandler onchange; attribute EventHandler onchange;
Promise<DataStoreChanges> getChanges(DOMString revisionId) Promise<DataStoreChanges> getChanges(DOMString revisionId)
@ -241,19 +54,10 @@ DataStore.prototype = {
__exposedProps__: { __exposedProps__: {
name: 'r', name: 'r',
owner: 'r', owner: 'r',
readOnly: 'r', readOnly: 'r'
get: 'r',
update: 'r',
add: 'r',
remove: 'r',
clear: 'r'
} }
}; };
return object; return chromeObject;
},
delete: function() {
this.db.delete();
} }
}; };

View File

@ -1,54 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
this.EXPORTED_SYMBOLS = ['DataStoreDB'];
function debug(s) {
// dump('DEBUG DataStoreDB: ' + s + '\n');
}
const DATASTOREDB_VERSION = 1;
const DATASTOREDB_OBJECTSTORE_NAME = 'DataStoreDB';
Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
this.DataStoreDB = function DataStoreDB() {}
DataStoreDB.prototype = {
__proto__: IndexedDBHelper.prototype,
upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
debug('updateSchema');
aDb.createObjectStore(DATASTOREDB_OBJECTSTORE_NAME, { autoIncrement: true });
},
init: function(aOrigin, aName) {
let dbName = aOrigin + '_' + aName;
this.initDBHelper(dbName, DATASTOREDB_VERSION,
[DATASTOREDB_OBJECTSTORE_NAME]);
},
txn: function(aType, aCallback, aErrorCb) {
debug('Transaction request');
this.newTxn(
aType,
DATASTOREDB_OBJECTSTORE_NAME,
aCallback,
function() {},
aErrorCb
);
},
delete: function() {
debug('delete');
this.close();
indexedDB.deleteDatabase(this.dbName);
debug('database deleted');
}
}

View File

@ -8,9 +8,12 @@
/* static functions */ /* static functions */
function debug(s) { let DEBUG = 0;
// dump('DEBUG DataStoreService: ' + s + '\n'); let debug;
} if (DEBUG)
debug = function (s) { dump('DEBUG DataStore: ' + s + '\n'); }
else
debug = function (s) {}
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
@ -39,9 +42,8 @@ DataStoreService.prototype = {
stores: {}, stores: {},
installDataStore: function(aAppId, aName, aOwner, aReadOnly) { installDataStore: function(aAppId, aName, aOwner, aReadOnly) {
debug('installDataStore - appId: ' + aAppId + ', aName: ' + debug('installDataStore - appId: ' + aAppId + ', aName: ' + aName +
aName + ', aOwner:' + aOwner + ', aReadOnly: ' + ', aOwner:' + aOwner + ', aReadOnly: ' + aReadOnly);
aReadOnly);
if (aName in this.stores && aAppId in this.stores[aName]) { if (aName in this.stores && aAppId in this.stores[aName]) {
debug('This should not happen'); debug('This should not happen');
@ -90,7 +92,6 @@ DataStoreService.prototype = {
for (let key in this.stores) { for (let key in this.stores) {
if (params.appId in this.stores[key]) { if (params.appId in this.stores[key]) {
this.stores[key][params.appId].delete();
delete this.stores[key][params.appId]; delete this.stores[key][params.appId];
} }

View File

@ -21,5 +21,4 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [ EXTRA_JS_MODULES += [
'DataStore.jsm', 'DataStore.jsm',
'DataStoreDB.jsm',
] ]

View File

@ -13,8 +13,6 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \ MOCHITEST_FILES = \
test_app_install.html \ test_app_install.html \
test_readonly.html \
test_basic.html \
file_app.sjs \ file_app.sjs \
file_app.template.webapp \ file_app.template.webapp \
$(NULL) $(NULL)

View File

@ -5,9 +5,6 @@
<title>Test for DataStore - install/uninstall apps</title> <title>Test for DataStore - install/uninstall apps</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7"> <script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
@ -16,11 +13,13 @@
var gHostedManifestURL = gBaseURL + 'file_app.sjs'; var gHostedManifestURL = gBaseURL + 'file_app.sjs';
var gGenerator = runTest(); var gGenerator = runTest();
SpecialPowers.pushPermissions( function go() {
[{ "type": "browser", "allow": 1, "context": document }, SpecialPowers.pushPermissions(
{ "type": "embed-apps", "allow": 1, "context": document }, [{ "type": "browser", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], { "type": "embed-apps", "allow": 1, "context": document },
function() { gGenerator.next() }); { "type": "webapps-manage", "allow": 1, "context": document }],
function() { gGenerator.next() });
}
function continueTest() { function continueTest() {
gGenerator.next(); gGenerator.next();
@ -93,5 +92,14 @@
} }
</script> </script>
</head>
<body onload="go()">
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<div id="container"></div>
</body> </body>
</html> </html>

View File

@ -1,229 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var gBaseURL = 'http://test/tests/dom/datastore/tests/';
var gHostedManifestURL = gBaseURL + 'file_app.sjs';
var gApp;
var gStore;
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
runTest();
}
}
function testGetDataStores() {
navigator.getDataStores('foo').then(function(stores) {
is(stores.length, 1, "getDataStores('foo') returns 1 element");
is(stores[0].name, 'foo', 'The dataStore.name is foo');
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
var store = stores[0];
ok("get" in store, "store.get exists");
ok("update" in store, "store.update exists");
ok("add" in store, "store.add exists");
ok("remove" in store, "store.remove exists");
ok("clear" in store, "store.clear exists");
gStore = stores[0];
runTest();
}, cbError);
}
function testStoreErrorGet(id) {
gStore.get(id).then(function(what) {
ok(false, "store.get(" + id + ") retrieves data");
}, function(error) {
ok(true, "store.get() failed properly because the id is non-valid");
ok(error instanceof DOMError, "error is a DOMError");
is(error.name, "SyntaxError", "Error is a syntax error");
}).then(runTest, cbError);
}
function testStoreErrorUpdate(id) {
gStore.update(id, "foo").then(function(what) {
ok(false, "store.update(" + id + ") retrieves data");
}, function(error) {
ok(true, "store.update() failed properly because the id is non-valid");
ok(error instanceof DOMError, "error is a DOMError");
is(error.name, "SyntaxError", "Error is a syntax error");
}).then(runTest, cbError);
}
function testStoreErrorRemove(id) {
gStore.remove(id).then(function(what) {
ok(false, "store.remove(" + id + ") retrieves data");
}, function(error) {
ok(true, "store.remove() failed properly because the id is non-valid");
ok(error instanceof DOMError, "error is a DOMError");
is(error.name, "SyntaxError", "Error is a syntax error");
}).then(runTest, cbError);
}
function testStoreGet(id, value) {
gStore.get(id).then(function(what) {
ok(true, "store.get() retrieves data");
is(what, value, "store.get(" + id + ") returns " + value);
}, function() {
ok(false, "store.get(" + id + ") retrieves data");
}).then(runTest, cbError);
}
function testStoreAdd(value) {
return gStore.add(value).then(function(what) {
ok(true, "store.add() is called");
ok(what > 0, "store.add() returns something");
return what;
}, cbError);
}
function testStoreUpdate(id, value) {
return gStore.update(id, value).then(function(what) {
ok(true, "store.update() is called");
is(id, what, "store.update(" + id + ") updates the correct id");
}, cbError);
}
function testStoreRemove(id) {
return gStore.remove(id).then(function() {
ok(true, "store.remove() is called");
}, cbError);
}
function testStoreClear() {
return gStore.clear().then(function() {
ok(true, "store.clear() is called");
}, cbError);
}
function uninstallApp() {
// Uninstall the app.
request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
runTest();
}
}
var tests = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
},
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, runTest);
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
},
// Installing the app
installApp,
// Test for GetDataStore
testGetDataStores,
// Broken ID
function() { testStoreErrorGet('hello world'); },
function() { testStoreErrorGet(true); },
function() { testStoreErrorGet(null); },
// Unknown ID
function() { testStoreGet(42, undefined); },
function() { testStoreGet(42, undefined); }, // twice
// Add + Get - number
function() { testStoreAdd(42).then(function(id) {
gId = id; runTest(); }, cbError); },
function() { testStoreGet(gId, 42); },
function() { testStoreGet(gId+"", 42); },
// Add + Get - boolean
function() { testStoreAdd(true).then(function(id) {
gId = id; runTest(); }, cbError); },
function() { testStoreGet(gId, true); },
// Add + Get - string
function() { testStoreAdd("hello world").then(function(id) {
gId = id; runTest(); }, cbError); },
function() { testStoreGet(gId, "hello world"); },
// Broken update
function() { testStoreErrorUpdate('hello world'); },
function() { testStoreErrorUpdate(true); },
function() { testStoreErrorUpdate(null); },
// Update + Get - string
function() { testStoreUpdate(gId, "hello world 2").then(function() {
runTest(); }, cbError); },
function() { testStoreGet(gId, "hello world 2"); },
// Broken remove
function() { testStoreErrorRemove('hello world'); },
function() { testStoreErrorRemove(true); },
function() { testStoreErrorRemove(null); },
// Remove
function() { testStoreRemove(gId).then(function(what) {
runTest(); }, cbError); },
function() { testStoreGet(gId).catch(function() {
runTest(); }); },
// Remove - wrong ID
function() { testStoreRemove(gId).then(function(what) {
runTest(); }, cbError); },
// Clear
function() { testStoreClear().then(function(what) {
runTest(); }, cbError); },
// Uninstall the app
uninstallApp
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
function finish() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>

View File

@ -1,96 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var gBaseURL = 'http://test/tests/dom/datastore/tests/';
var gHostedManifestURL = gBaseURL + 'file_app.sjs';
var gGenerator = runTest();
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }],
function() { gGenerator.next() });
function continueTest() {
try { gGenerator.next(); }
catch(e) {}
}
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function runTest() {
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var app = request.result;
navigator.getDataStores('bar').then(function(stores) {
is(stores.length, 1, "getDataStores('bar') returns 1 element");
is(stores[0].name, 'bar', 'The dataStore.name is bar');
is(stores[0].readOnly, true, 'The dataStore bar is readonly');
var store = stores[0];
ok("get" in store, "store.get exists");
ok("update" in store, "store.update exists");
ok("add" in store, "store.add exists");
ok("remove" in store, "store.remove exists");
ok("clear" in store, "store.clear exists");
var f = store.clear();
f = f.then(cbError, function() {
ok(true, "store.clear() fails because the db is readonly");
return store.remove(123);
});
f = f.then(cbError, function() {
ok(true, "store.remove() fails because the db is readonly");
return store.add(123, true);
});
f = f.then(cbError, function() {
ok(true, "store.add() fails because the db is readonly");
return store.update(123, {});
})
f = f.then(cbError, function() {
ok(true, "store.update() fails because the db is readonly");
})
f.then(function() {
// Uninstall the app.
request = navigator.mozApps.mgmt.uninstall(app);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
finish();
}
});
}, cbError);
}
function finish() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, runTest);
</script>
</body>
</html>