Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2012-07-09 20:53:11 -04:00
commit 8b9c9fea4d
37 changed files with 3131 additions and 224 deletions

View File

@ -16,7 +16,6 @@ let gSyncUI = {
"weave:ui:sync:error",
"weave:ui:sync:finish",
"weave:ui:clear-error",
"weave:engine:clients:display-uri",
],
_unloaded: false,
@ -397,21 +396,6 @@ let gSyncUI = {
this.updateUI();
},
/**
* Observer called when display URI command is received.
*/
onDisplayURI: function onDisplayURI(data) {
if (!gBrowser) {
return;
}
try {
gBrowser.addTab(data.wrappedJSObject.object.uri);
} catch (ex) {
Cu.reportError("Error displaying tab received by Sync: " + ex);
}
},
observe: function SUI_observe(subject, topic, data) {
if (this._unloaded) {
Cu.reportError("SyncUI observer called after unload: " + topic);
@ -461,9 +445,6 @@ let gSyncUI = {
case "weave:ui:clear-error":
this.clearError();
break;
case "weave:engine:clients:display-uri":
this.onDisplayURI(subject);
break;
}
},

View File

@ -182,6 +182,9 @@ BrowserGlue.prototype = {
case "weave:service:ready":
this._setSyncAutoconnectDelay();
break;
case "weave:engine:clients:display-uri":
this._onDisplaySyncURI(subject);
break;
#endif
case "session-save":
this._setPrefToSaveSession(true);
@ -265,6 +268,7 @@ BrowserGlue.prototype = {
#endif
#ifdef MOZ_SERVICES_SYNC
os.addObserver(this, "weave:service:ready", false);
os.addObserver(this, "weave:engine:clients:display-uri", false);
#endif
os.addObserver(this, "session-save", false);
os.addObserver(this, "places-init-complete", false);
@ -292,6 +296,7 @@ BrowserGlue.prototype = {
#endif
#ifdef MOZ_SERVICES_SYNC
os.removeObserver(this, "weave:service:ready", false);
os.removeObserver(this, "weave:engine:clients:display-uri", false);
#endif
os.removeObserver(this, "session-save");
if (this._isIdleObserver)
@ -1507,6 +1512,29 @@ BrowserGlue.prototype = {
#endif
},
#ifdef MOZ_SERVICES_SYNC
/**
* Called as an observer when Sync's "display URI" notification is fired.
*
* We open the received URI in a background tab.
*
* Eventually, this will likely be replaced by a more robust tab syncing
* feature. This functionality is considered somewhat evil by UX because it
* opens a new tab automatically without any prompting. However, it is a
* lesser evil than sending a tab to a specific device (from e.g. Fennec)
* and having nothing happen on the receiving end.
*/
_onDisplaySyncURI: function _onDisplaySyncURI(data) {
try {
let tabbrowser = this.getMostRecentBrowserWindow().gBrowser;
// The payload is wrapped weirdly because of how Sync does notifications.
tabbrowser.addTab(data.wrappedJSObject.object.uri);
} catch (ex) {
Cu.reportError("Error displaying tab received by Sync: " + ex);
}
},
#endif
// for XPCOM
classID: Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),

View File

@ -133,24 +133,15 @@ nsDOMMutationRecord::GetOldValue(nsAString& aPrevValue)
// Observer
NS_IMPL_CYCLE_COLLECTION_CLASS(nsMutationReceiver)
NS_IMPL_ADDREF(nsMutationReceiver)
NS_IMPL_RELEASE(nsMutationReceiver)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMutationReceiver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMutationReceiver)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMutationReceiver)
NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY(nsMutationReceiver)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsMutationReceiver)
tmp->Disconnect(false);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsMutationReceiver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
void
nsMutationReceiver::Disconnect(bool aRemoveFromObserver)
{

View File

@ -265,8 +265,7 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_IID)
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsMutationReceiver)
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE

View File

@ -69,9 +69,6 @@ nsDOMParser::ParseFromString(const PRUnichar *str,
rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
nsDependentString sourceBuffer(str);
rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document, false);
NS_ENSURE_SUCCESS(rv, rv);
// Keep the XULXBL state, base URL and principal setting in sync with the
// XML case
@ -85,6 +82,10 @@ nsDOMParser::ParseFromString(const PRUnichar *str,
// And the right principal
document->SetPrincipal(mPrincipal);
nsDependentString sourceBuffer(str);
rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document, false);
NS_ENSURE_SUCCESS(rv, rv);
domDocument.forget(aResult);
return rv;
}

View File

@ -143,6 +143,10 @@ let DOMApplicationRegistry = {
},
receiveMessage: function(aMessage) {
// nsIPrefBranch throws if pref does not exist, faster to simply write
// the pref instead of first checking if it is false.
Services.prefs.setBoolPref("dom.mozApps.used", true);
let msg = aMessage.json;
switch (aMessage.name) {

View File

@ -1603,7 +1603,7 @@ nsEditor::RemoveContainer(nsINode* aNode)
{
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
nsINode* parent = aNode->GetNodeParent();
nsCOMPtr<nsINode> parent = aNode->GetNodeParent();
NS_ENSURE_STATE(parent);
PRInt32 offset = parent->IndexOf(aNode);
@ -1616,7 +1616,7 @@ nsEditor::RemoveContainer(nsINode* aNode)
nsAutoRemoveContainerSelNotify selNotify(mRangeUpdater, aNode, parent, offset, nodeOrigLen);
while (aNode->HasChildren()) {
nsIContent* child = aNode->GetLastChild();
nsCOMPtr<nsIContent> child = aNode->GetLastChild();
nsresult rv = DeleteNode(child->AsDOMNode());
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -6,10 +6,10 @@
$(warning httpserver XPI_NAME=$(XPI_NAME))
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = netwerk/test/httpserver
include $(DEPTH)/config/autoconf.mk
@ -36,4 +36,6 @@ XPIDLSRCS = \
XPCSHELL_TESTS = test
TESTING_JS_MODULES = httpd.js
include $(topsrcdir)/config/rules.mk

View File

@ -10,6 +10,34 @@
* httpd.js.
*/
const EXPORTED_SYMBOLS = [
"HTTP_400",
"HTTP_401",
"HTTP_402",
"HTTP_403",
"HTTP_404",
"HTTP_405",
"HTTP_406",
"HTTP_407",
"HTTP_408",
"HTTP_409",
"HTTP_410",
"HTTP_411",
"HTTP_412",
"HTTP_413",
"HTTP_414",
"HTTP_415",
"HTTP_417",
"HTTP_500",
"HTTP_501",
"HTTP_502",
"HTTP_503",
"HTTP_504",
"HTTP_505",
"HttpError",
"HttpServer",
];
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const Cc = Components.classes;
@ -762,7 +790,7 @@ nsHttpServer.prototype =
// Bug 508125: Add a GC here else we'll use gigabytes of memory running
// mochitests. We can't rely on xpcshell doing an automated GC, as that
// would interfere with testing GC stuff...
gc();
Components.utils.forceGC();
},
/**
@ -776,6 +804,7 @@ nsHttpServer.prototype =
}
};
var HttpServer = nsHttpServer;
//
// RFC 2396 section 3.2.2:

View File

@ -0,0 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Ensure httpd.js can be imported as a module and that a server starts.
*/
function run_test() {
Components.utils.import("resource://testing-common/httpd.js");
let server = new HttpServer();
server.start(8080);
do_test_pending();
server.stop(do_test_finished);
}

View File

@ -14,6 +14,7 @@ tail =
[test_headers.js]
[test_host.js]
[test_linedata.js]
[test_load_module.js]
[test_name_scheme.js]
[test_processasync.js]
[test_qi.js]

View File

@ -8,9 +8,9 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://services-common/preferences.js");
function AitcService() {
this.aitc = null;
@ -20,7 +20,6 @@ AitcService.prototype = {
classID: Components.ID("{a3d387ca-fd26-44ca-93be-adb5fda5a78d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference]),
observe: function observe(subject, topic, data) {
@ -34,7 +33,6 @@ AitcService.prototype = {
Services.obs.removeObserver(this, "sessionstore-windows-restored");
// Don't start AITC if classic sync is on.
Cu.import("resource://services-common/preferences.js");
if (Preferences.get("services.sync.engine.apps", false)) {
return;
}
@ -43,43 +41,32 @@ AitcService.prototype = {
return;
}
// Start AITC service if apps.enabled is true. If false, we look
// in the browser history to determine if they're an "apps user". If
// an entry wasn't found, we'll watch for navigation to either the
// marketplace or dashboard and switch ourselves on then.
if (Preferences.get("apps.enabled", false)) {
this.start();
return;
}
// Set commonly used URLs.
this.DASHBOARD_URL = CommonUtils.makeURI(
Preferences.get("services.aitc.dashboard.url")
);
this.MARKETPLACE_URL = CommonUtils.makeURI(
Preferences.get("services.aitc.marketplace.url")
);
if (this.hasUsedApps()) {
Preferences.set("apps.enabled", true);
// Start AITC service only if apps.enabled is true. If false, setup
// an observer in case the value changes as a result of an access to
// the DOM API.
if (Preferences.get("dom.mozApps.used", false)) {
this.start();
return;
}
// Wait and see if the user wants anything apps related.
PlacesUtils.history.addObserver(this, true);
Preferences.observe("dom.mozApps.used", function checkIfEnabled() {
if (Preferences.get("dom.mozApps.used", false)) {
Preferences.ignore("dom.mozApps.used", checkIfEnabled, this);
this.start();
}
}, this);
break;
}
},
start: function start() {
Cu.import("resource://services-aitc/main.js");
if (this.aitc) {
return;
}
// Log to stdout if enabled.
Cu.import("resource://services-aitc/main.js");
Cu.import("resource://services-common/log4moz.js");
let root = Log4Moz.repository.getLogger("Service.AITC");
root.level = Log4Moz.Level[Preferences.get("services.aitc.log.level")];
@ -87,44 +74,31 @@ AitcService.prototype = {
root.addAppender(new Log4Moz.DumpAppender());
}
this.aitc = new Aitc();
Services.obs.notifyObservers(null, "service:aitc:started", null);
},
hasUsedApps: function hasUsedApps() {
// There is no easy way to determine whether a user is "using apps".
// The best we can do right now is to see if they have visited either
// the Mozilla dashboard or Marketplace. See bug 760898.
let gh = PlacesUtils.ghistory2;
if (gh.isVisited(this.DASHBOARD_URL)) {
return true;
}
if (gh.isVisited(this.MARKETPLACE_URL)) {
return true;
}
return false;
},
// nsINavHistoryObserver. We are only interested in onVisit().
onBeforeDeleteURI: function() {},
onBeginUpdateBatch: function() {},
onClearHistory: function() {},
onDeleteURI: function() {},
onDeleteVisits: function() {},
onEndUpdateBatch: function() {},
onPageChanged: function() {},
onPageExpired: function() {},
onTitleChanged: function() {},
onVisit: function onVisit(uri) {
if (!uri.equals(this.MARKETPLACE_URL) && !uri.equals(this.DASHBOARD_URL)) {
return;
}
PlacesUtils.history.removeObserver(this);
Preferences.set("apps.enabled", true);
this.start();
return;
},
};
const components = [AitcService];
function AboutApps() {
}
AboutApps.prototype = {
classID: Components.ID("{1de7cbe8-60f1-493e-b56b-9d099b3c018e}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIAboutModule]),
getURIFlags: function(aURI) {
return Ci.nsIAboutModule.ALLOW_SCRIPT;
},
newChannel: function(aURI) {
let channel = Services.io.newChannel(
Preferences.get("services.aitc.dashboard.url"), null, null
);
channel.originalURI = aURI;
return channel;
}
};
const components = [AitcService, AboutApps];
const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View File

@ -2,5 +2,9 @@
component {a3d387ca-fd26-44ca-93be-adb5fda5a78d} Aitc.js
contract @mozilla.org/services/aitc;1 {a3d387ca-fd26-44ca-93be-adb5fda5a78d}
category app-startup AitcService service,@mozilla.org/services/aitc;1
component {1de7cbe8-60f1-493e-b56b-9d099b3c018e} Aitc.js
contract @mozilla.org/network/protocol/about;1?what=apps {1de7cbe8-60f1-493e-b56b-9d099b3c018e}
# Register resource aliases
resource services-aitc resource:///modules/services-aitc/

View File

@ -16,6 +16,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-common/log4moz.js");
Cu.import("resource://services-common/preferences.js");
Cu.import("resource://services-common/rest.js");
Cu.import("resource://services-common/utils.js");
/**
* Provides a file-backed queue. Currently used by manager.js as persistent
@ -43,23 +44,17 @@ function AitcQueue(filename, cb) {
this._queue = [];
this._writeLock = false;
this._file = FileUtils.getFile("ProfD", ["webapps", filename], true);
this._filePath = "webapps/" + filename;
this._log.info("AitcQueue instance loading");
let self = this;
if (this._file.exists()) {
this._getFile(function gotFile(data) {
if (data && Array.isArray(data)) {
self._queue = data;
}
self._log.info("AitcQueue instance created");
cb(true);
});
} else {
self._log.info("AitcQueue instance created");
CommonUtils.jsonLoad(this._filePath, this, function jsonLoaded(data) {
if (data && Array.isArray(data)) {
this._queue = data;
}
this._log.info("AitcQueue instance created");
cb(true);
}
});
}
AitcQueue.prototype = {
/**
@ -144,36 +139,6 @@ AitcQueue.prototype = {
return this._queue.length;
},
/**
* Get contents of cache file and parse it into an array. Will throw an
* exception if there is an error while reading the file.
*/
_getFile: function _getFile(cb) {
let channel = NetUtil.newChannel(this._file);
channel.contentType = "application/json";
let self = this;
NetUtil.asyncFetch(channel, function _asyncFetched(stream, res) {
if (!Components.isSuccessCode(res)) {
self._log.error("Could not read from json file " + this._file.path);
cb(null);
return;
}
let data = [];
try {
data = JSON.parse(
NetUtil.readInputStreamToString(stream, stream.available())
);
stream.close();
cb(data);
} catch (e) {
self._log.error("Could not parse JSON " + e);
cb(null);
}
});
},
/**
* Put an array into the cache file. Will throw an exception if there is
* an error while trying to write to the file.
@ -184,32 +149,18 @@ AitcQueue.prototype = {
}
this._writeLock = true;
try {
let ostream = FileUtils.openSafeFileOutputStream(this._file);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(JSON.stringify(value));
// Asynchronously copy the data to the file.
let self = this;
this._log.info("Writing queue to disk");
NetUtil.asyncCopy(istream, ostream, function _asyncCopied(result) {
self._writeLock = false;
if (Components.isSuccessCode(result)) {
self._log.info("asyncCopy succeeded");
cb(null);
} else {
let msg = new Error("asyncCopy failed with " + result);
self._log.info(msg);
cb(msg);
}
});
} catch (e) {
this._log.info("Writing queue to disk");
CommonUtils.jsonSave(this._filePath, this, value, function jsonSaved(err) {
if (err) {
let msg = new Error("_putFile failed with " + err);
this._writeLock = false;
cb(msg);
return;
}
this._log.info("_putFile succeeded");
this._writeLock = false;
cb(msg);
}
cb(null);
});
},
};

View File

@ -1,5 +1,6 @@
// Root logger
pref("services.aitc.log.dump", false);
pref("dom.mozApps.used", false); // Set to true by DOMApplicationRegistry
pref("services.aitc.log.dump", false); // Root logger
pref("services.aitc.log.level", "All");
pref("services.aitc.browserid.url", "https://browserid.org/sign_in");

View File

@ -7,6 +7,7 @@ Cu.import("resource://services-common/async.js");
let queue = null;
function run_test() {
initTestLogging();
queue = new AitcQueue("test", run_next_test);
}
@ -97,7 +98,6 @@ add_test(function test_queue_multiaddremove() {
});
});
/* TODO Bug 760905 - Temporarily disabled for orange.
add_test(function test_queue_writelock() {
// Queue should not enqueue or dequeue if lock is enabled.
queue._writeLock = true;
@ -114,4 +114,3 @@ add_test(function test_queue_writelock() {
});
});
});
*/

View File

@ -17,6 +17,7 @@ modules := \
observers.js \
preferences.js \
rest.js \
storageservice.js \
stringbundle.js \
tokenserverclient.js \
utils.js \
@ -31,9 +32,8 @@ libs::
TEST_DIRS += tests
# TODO enable once build infra supports testing modules.
#TESTING_JS_MODULES := aitcserver.js storageserver.js
#TESTING_JS_MODULE_DIR := services-common
TESTING_JS_MODULES := aitcserver.js storageserver.js
TESTING_JS_MODULE_DIR := services-common
# What follows is a helper to launch a standalone storage server instance.
# Most of the code lives in a Python script in the tests directory. If we

View File

@ -4,8 +4,6 @@
"use strict";
// TODO enable once build infra supports test modules.
/*
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const EXPORTED_SYMBOLS = [
@ -14,7 +12,6 @@ const EXPORTED_SYMBOLS = [
];
Cu.import("resource://testing-common/httpd.js");
*/
Cu.import("resource://services-crypto/utils.js");
Cu.import("resource://services-common/log4moz.js");
Cu.import("resource://services-common/utils.js");
@ -133,7 +130,7 @@ AITCServer10User.prototype = {
function AITCServer10Server() {
this._log = Log4Moz.repository.getLogger("Services.Common.AITCServer");
this.server = new nsHttpServer();
this.server = new HttpServer();
this.port = null;
this.users = {};
this.autoCreateUsers = false;

View File

@ -8,4 +8,5 @@
pref("services.common.log.logger.rest.request", "Debug");
pref("services.common.log.logger.rest.response", "Debug");
pref("services.common.storageservice.sendVersionInfo", true);
pref("services.common.tokenserverclient.logger.level", "Info");

View File

@ -8,8 +8,6 @@
* The server should not be used for any production purposes.
*/
// TODO enable once build infra supports testing modules.
/*
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const EXPORTED_SYMBOLS = [
@ -17,11 +15,10 @@ const EXPORTED_SYMBOLS = [
"StorageServerCallback",
"StorageServerCollection",
"StorageServer",
"storageServerForUsers",
];
Cu.import("resource://testing-common/httpd.js");
*/
Cu.import("resource://services-common/async.js");
Cu.import("resource://services-common/log4moz.js");
Cu.import("resource://services-common/utils.js");
@ -240,7 +237,6 @@ ServerBSO.prototype = {
}
this.modified = request.timestamp;
response.newModified = request.timestamp;
response.setHeader("X-Last-Modified", "" + this.modified, false);
response.setStatusLine(request.httpVersion, code, status);
@ -265,7 +261,7 @@ ServerBSO.prototype = {
* An optional timestamp value to initialize the modified time of the
* collection. This should be in the format returned by new_timestamp().
*/
function StorageServerCollection(bsos, acceptNew, timestamp) {
function StorageServerCollection(bsos, acceptNew, timestamp=new_timestamp()) {
this._bsos = bsos || {};
this.acceptNew = acceptNew || false;
@ -275,8 +271,8 @@ function StorageServerCollection(bsos, acceptNew, timestamp) {
* has a modified time.
*/
CommonUtils.ensureMillisecondsTimestamp(timestamp);
this._timestamp = timestamp;
this.timestamp = timestamp || new_timestamp();
this._log = Log4Moz.repository.getLogger(STORAGE_HTTP_LOGGER);
}
StorageServerCollection.prototype = {
@ -404,13 +400,13 @@ StorageServerCollection.prototype = {
}
if (options.newer) {
if (bso.modified < options.newer) {
if (bso.modified <= options.newer) {
return false;
}
}
if (options.older) {
if (bso.modified > options.older) {
if (bso.modified >= options.older) {
return false;
}
}
@ -720,7 +716,6 @@ StorageServerCollection.prototype = {
});
body = normalized.join("\n") + "\n";
_(body);
} else {
response.setHeader("Content-Type", "application/json", false);
body = JSON.stringify({items: data});
@ -776,6 +771,10 @@ StorageServerCollection.prototype = {
throw HTTP_415;
}
if (this._ensureUnmodifiedSince(request, response)) {
return;
}
let res = this.post(input, request.timestamp);
let body = JSON.stringify(res);
response.setHeader("Content-Type", "application/json", false);
@ -791,6 +790,10 @@ StorageServerCollection.prototype = {
let options = this.parseOptions(request);
if (this._ensureUnmodifiedSince(request, response)) {
return;
}
let deleted = this.delete(options);
response.deleted = deleted;
this.timestamp = request.timestamp;
@ -817,7 +820,28 @@ StorageServerCollection.prototype = {
request.setHeader("Allow", "GET,POST,DELETE");
response.setStatusLine(request.httpVersion, 405, "Method Not Allowed");
};
}
},
_ensureUnmodifiedSince: function _ensureUnmodifiedSince(request, response) {
if (!request.hasHeader("x-if-unmodified-since")) {
return false;
}
let requestModified = parseInt(request.getHeader("x-if-unmodified-since"),
10);
let serverModified = this.timestamp;
this._log.debug("Request modified time: " + requestModified +
"; Server modified time: " + serverModified);
if (serverModified <= requestModified) {
return false;
}
this._log.info("Conditional request rejected because client time older " +
"than collection timestamp.");
response.setStatusLine(request.httpVersion, 412, "Precondition Failed");
return true;
},
};
@ -853,7 +877,7 @@ let StorageServerCallback = {
*/
function StorageServer(callback) {
this.callback = callback || {__proto__: StorageServerCallback};
this.server = new nsHttpServer();
this.server = new HttpServer();
this.started = false;
this.users = {};
this._log = Log4Moz.repository.getLogger(STORAGE_HTTP_LOGGER);
@ -1220,6 +1244,7 @@ StorageServer.prototype = {
* HTTP response utility.
*/
respond: function respond(req, resp, code, status, body, headers, timestamp) {
this._log.info("Response: " + code + " " + status);
resp.setStatusLine(req.httpVersion, code, status);
for each (let [header, value] in Iterator(headers || this.defaultHeaders)) {
resp.setHeader(header, value, false);
@ -1504,7 +1529,7 @@ StorageServer.prototype = {
bso.putHandler(req, resp);
coll.timestamp = resp.newModified;
coll.timestamp = req.timestamp;
return resp;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = Components;
// Where to bind test HTTP servers to.
const TEST_SERVER_URL = "http://localhost:8080/";
// This has the side-effect of populating Cc, Ci, Cu, Cr. It's best not to
// ask questions and just accept it.
do_load_httpd_js();
const Cm = Components.manager;
let gSyncProfile = do_get_profile();
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -54,4 +51,4 @@ function addResourceAlias() {
handler.setSubstitution("services-" + module, uri);
}
}
addResourceAlias();
addResourceAlias();

View File

@ -2,6 +2,7 @@
* 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/. */
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://services-common/log4moz.js");
Cu.import("resource://services-common/utils.js");
@ -93,7 +94,7 @@ function get_server_port() {
function httpd_setup (handlers, port) {
let port = port || 8080;
let server = new nsHttpServer();
let server = new HttpServer();
for (let path in handlers) {
server.registerPathHandler(path, handlers[path]);
}

View File

@ -6,8 +6,7 @@
Cu.import("resource://services-common/rest.js");
Cu.import("resource://services-common/utils.js");
// TODO enable once build infra supports testing modules.
//Cu.import("resource://testing-common/services-common/aitcserver.js");
Cu.import("resource://testing-common/services-common/aitcserver.js");
function run_test() {
initTestLogging("Trace");

View File

@ -6,6 +6,7 @@ const modules = [
"log4moz.js",
"preferences.js",
"rest.js",
"storageservice.js",
"stringbundle.js",
"tokenserverclient.js",
"utils.js",
@ -22,11 +23,8 @@ function run_test() {
Components.utils.import(resource, {});
}
// TODO enable once build infra supports testing modules.
/*
for each (let m in test_modules) {
let resource = "resource://testing-common/services-common/" + m;
Components.utils.import(resource, {});
}
*/
}

View File

@ -616,7 +616,7 @@ add_test(function test_abort() {
* channel activity until the request is automatically canceled.
*/
add_test(function test_timeout() {
let server = new nsHttpServer();
let server = new HttpServer();
let server_connection;
server._handler.handleResponse = function(connection) {
// This is a handler that doesn't do anything, just keeps the connection
@ -633,7 +633,9 @@ add_test(function test_timeout() {
do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT);
do_check_eq(this.status, this.ABORTED);
_("Closing connection.");
server_connection.close();
_("Shutting down server.");
server.stop(run_next_test);
});
});

View File

@ -4,8 +4,7 @@
Cu.import("resource://services-common/async.js");
Cu.import("resource://services-common/rest.js");
Cu.import("resource://services-common/utils.js");
// TODO enable once build infra supports testing modules.
//Cu.import("resource://testing-common/services-common/storageserver.js");
Cu.import("resource://testing-common/services-common/storageserver.js");
const PORT = 8080;
const DEFAULT_USER = "123";

View File

@ -0,0 +1,124 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-common/storageservice.js");
function run_test() {
initTestLogging("Trace");
run_next_test();
}
add_test(function test_bso_constructor() {
_("Ensure created BSO instances are initialized properly.");
let bso = new BasicStorageObject();
do_check_eq(bso.id, null);
do_check_eq(bso.collection, null);
do_check_attribute_count(bso.data, 0);
do_check_eq(bso.payload, null);
do_check_eq(bso.modified, null);
do_check_eq(bso.sortindex, 0);
do_check_eq(bso.ttl, null);
let bso = new BasicStorageObject("foobar");
do_check_eq(bso.id, "foobar");
do_check_eq(bso.collection, null);
do_check_attribute_count(bso.data, 0);
let bso = new BasicStorageObject("foo", "coll");
do_check_eq(bso.id, "foo");
do_check_eq(bso.collection, "coll");
do_check_attribute_count(bso.data, 0);
run_next_test();
});
add_test(function test_bso_attributes() {
_("Ensure attribute getters and setters work.");
let bso = new BasicStorageObject("foobar");
bso.payload = "pay";
do_check_eq(bso.payload, "pay");
bso.modified = 35423;
do_check_eq(bso.modified, 35423);
bso.sortindex = 10;
do_check_eq(bso.sortindex, 10);
bso.ttl = 60;
do_check_eq(bso.ttl, 60);
run_next_test();
});
add_test(function test_bso_deserialize() {
_("Ensure that deserialize() works.");
_("A simple working test.");
let json = '{"id": "foobar", "payload": "pay", "modified": 1223145532}';
let bso = new BasicStorageObject();
bso.deserialize(json);
do_check_neq(bso, null);
do_check_eq(bso.id, "foobar");
do_check_eq(bso.payload, "pay");
do_check_eq(bso.modified, 1223145532);
_("Invalid JSON.");
let json = '{id: "foobar}';
let bso = new BasicStorageObject();
try {
bso.deserialize(json);
do_check_true(false);
} catch (ex) {
do_check_eq(ex.name, "SyntaxError");
}
_("Invalid key in JSON.");
let json = '{"id": "foo", "payload": "pay", "BADKEY": "irrelevant"}';
let bso = new BasicStorageObject();
try {
bso.deserialize(json);
do_check_true(false);
} catch (ex) {
do_check_eq(ex.name, "Error");
do_check_eq(ex.message.indexOf("Invalid key"), 0);
}
_("Loading native JS objects works.");
let bso = new BasicStorageObject();
bso.deserialize({id: "foo", payload: "pay"});
do_check_neq(bso, null);
do_check_eq(bso.id, "foo");
do_check_eq(bso.payload, "pay");
_("Passing invalid type is caught.");
let bso = new BasicStorageObject();
try {
bso.deserialize(["foo", "bar"]);
do_check_true(false);
} catch (ex) {
do_check_eq(ex.name, "Error");
}
run_next_test();
});
add_test(function test_bso_toJSON() {
_("Ensure JSON serialization works.");
let bso = new BasicStorageObject();
do_check_attribute_count(bso.toJSON(), 0);
bso.id = "foo";
bso.payload = "pay";
let json = bso.toJSON();
let original = json;
do_check_attribute_count(original, 2);
do_check_eq(original.id, "foo");
do_check_eq(original.payload, "pay");
run_next_test();
});

View File

@ -0,0 +1,939 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-common/storageservice.js");
Cu.import("resource://testing-common/services-common/storageserver.js");
const BASE_URI = "http://localhost:8080/2.0";
function run_test() {
initTestLogging("Trace");
run_next_test();
}
function getEmptyServer(user="765", password="password") {
let users = {};
users[user] = password;
return storageServerForUsers(users, {
meta: {},
clients: {},
crypto: {},
});
}
function getClient(user="765", password="password") {
let client = new StorageServiceClient(BASE_URI + "/" + user);
client.addListener({
onDispatch: function onDispatch(request) {
let up = user + ":" + password;
request.request.setHeader("authorization", "Basic " + btoa(up));
}
});
return client;
}
function getServerAndClient(user="765", password="password") {
let server = getEmptyServer(user, password);
let client = getClient(user, password);
return [server, client, user, password];
}
add_test(function test_auth_failure_listener() {
_("Ensure the onAuthFailure listener is invoked.");
let server = getEmptyServer();
let client = getClient("324", "INVALID");
client.addListener({
onAuthFailure: function onAuthFailure(client, request) {
_("onAuthFailure");
server.stop(run_next_test);
}
});
let request = client.getCollectionInfo();
request.dispatch();
});
add_test(function test_duplicate_listeners() {
_("Ensure that duplicate listeners aren't installed multiple times.");
let server = getEmptyServer();
let client = getClient("1234567", "BAD_PASSWORD");
let invokeCount = 0;
let listener = {
onAuthFailure: function onAuthFailure() {
invokeCount++;
}
};
client.addListener(listener);
// No error expected.
client.addListener(listener);
let request = client.getCollectionInfo();
request.dispatch(function onComplete() {
do_check_eq(invokeCount, 1);
server.stop(run_next_test);
});
});
add_test(function test_handler_object() {
_("Ensure that installed handlers get their callbacks invoked.");
let [server, client] = getServerAndClient();
let onCompleteCount = 0;
let onDispatchCount = 0;
let handler = {
onComplete: function onComplete() {
onCompleteCount++;
do_check_eq(onDispatchCount, 1);
do_check_eq(onCompleteCount, 1);
server.stop(run_next_test);
},
onDispatch: function onDispatch() {
onDispatchCount++;
},
};
let request = client.getCollectionInfo();
request.handler = handler;
request.dispatch();
});
add_test(function test_info_collections() {
_("Ensure requests to /info/collections work as expected.");
let [server, client] = getServerAndClient();
let request = client.getCollectionInfo();
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq("object", typeof req.resultObj);
do_check_attribute_count(req.resultObj, 3);
do_check_true("meta" in req.resultObj);
server.stop(run_next_test);
});
});
add_test(function test_info_collections_conditional_not_modified() {
_("Ensure conditional getCollectionInfo requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionInfo();
request.locallyModifiedVersion = now + 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_info_collections_conditional_modified() {
_("Ensure conditional getCollectionInfo requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionInfo();
request.locallyModifiedVersion = now - 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_false(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_quota() {
_("Ensure quota requests work.");
let [server, client] = getServerAndClient();
let request = client.getQuota();
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(req.resultObj.quota, 1048576);
server.stop(run_next_test);
});
});
add_test(function test_get_quota_conditional_not_modified() {
_("Ensure conditional getQuota requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getQuota();
request.locallyModifiedVersion = now + 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_quota_conditional_modified() {
_("Ensure conditional getQuota requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getQuota();
request.locallyModifiedVersion = now - 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_false(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_collection_usage() {
_("Ensure info/collection_usage requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
user.createCollection("testcoll", {
abc123: new ServerBSO("abc123", "payload", Date.now())
});
let request = client.getCollectionUsage();
request.dispatch(function onComplete(error, req) {
do_check_null(error);
let usage = req.resultObj;
do_check_true("testcoll" in usage);
do_check_eq(usage.testcoll, "payload".length);
server.stop(run_next_test);
});
});
add_test(function test_get_usage_conditional_not_modified() {
_("Ensure conditional getCollectionUsage requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionUsage();
request.locallyModifiedVersion = now + 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_usage_conditional_modified() {
_("Ensure conditional getCollectionUsage requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionUsage();
request.locallyModifiedVersion = now - 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_false(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_collection_counts() {
_("Ensure info/collection_counts requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", Date.now()),
bar: new ServerBSO("bar", "payload1", Date.now())
});
let request = client.getCollectionCounts();
request.dispatch(function onComplete(error, req) {
do_check_null(error);
let counts = req.resultObj;
do_check_true("testcoll" in counts);
do_check_eq(counts.testcoll, 2);
server.stop(run_next_test);
});
});
add_test(function test_get_counts_conditional_not_modified() {
_("Ensure conditional getCollectionCounts requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionCounts();
request.locallyModifiedVersion = now + 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_counts_conditional_modified() {
_("Ensure conditional getCollectionCounts requests work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getCollectionCounts();
request.locallyModifiedVersion = now - 10;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_false(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_collection_simple() {
_("Ensure basic collection retrieval works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", Date.now()),
bar: new ServerBSO("bar", "payload1", Date.now())
});
let request = client.getCollection("testcoll");
let bsos = [];
request.handler = {
onBSORecord: function onBSORecord(request, bso) {
bsos.push(bso);
},
onComplete: function onComplete(error, request) {
do_check_null(error);
do_check_eq(bsos.length, 2);
do_check_eq(bsos[0], "foo");
do_check_eq(bsos[1], "bar");
server.stop(run_next_test);
}
};
request.dispatch();
});
add_test(function test_get_collection_conditional_not_modified() {
_("Ensure conditional requests with no new data to getCollection work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.getCollection("testcoll");
request.locallyModifiedVersion = now + 1;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_get_collection_conditional_modified() {
_("Ensure conditional requests with new data to getCollection work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.getCollection("testcoll");
request.locallyModifiedVersion = now - 1;
let bsoCount = 0;
request.handler = {
onBSORecord: function onBSORecord() {
bsoCount++;
},
onComplete: function onComplete(error, req) {
do_check_null(error);
do_check_false(req.notModified);
do_check_eq(bsoCount, 1);
server.stop(run_next_test);
}
};
request.dispatch();
});
// This is effectively a sanity test for query string generation.
add_test(function test_get_collection_newer() {
_("Ensure query string for newer and full work together.");
let [server, client, username] = getServerAndClient();
let date0 = Date.now();
let date1 = date0 + 500;
let user = server.user(username);
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", date0),
bar: new ServerBSO("bar", "payload1", date1)
});
let request = client.getCollection("testcoll");
request.full = true;
request.newer = date0;
let bsos = [];
request.handler = {
onBSORecord: function onBSORecord(request, bso) {
bsos.push(bso);
},
onComplete: function onComplete(error, req) {
do_check_null(error);
do_check_eq(bsos.length, 1);
let bso = bsos[0];
do_check_eq(bso.id, "bar");
do_check_eq(bso.payload, "payload1");
server.stop(run_next_test);
}
};
request.dispatch();
});
add_test(function test_get_bso() {
_("Ensure that simple BSO fetches work.");
let [server, client, username] = getServerAndClient();
server.createCollection(username, "testcoll", {
abc123: new ServerBSO("abc123", "payload", Date.now())
});
let request = client.getBSO("testcoll", "abc123");
request.dispatch(function(error, req) {
do_check_null(error);
do_check_true(req.resultObj instanceof BasicStorageObject);
let bso = req.resultObj;
do_check_eq(bso.id, "abc123");
do_check_eq(bso.payload, "payload");
server.stop(run_next_test);
});
});
add_test(function test_bso_conditional() {
_("Ensure conditional requests for an individual BSO work.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload", now)
});
let request = client.getBSO("testcoll", "foo");
request.locallyModifiedVersion = now;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_true(req.notModified);
server.stop(run_next_test);
});
});
add_test(function test_set_bso() {
_("Ensure simple BSO PUT works.");
let [server, client] = getServerAndClient();
let id = "mnas08h3f3r2351";
let bso = new BasicStorageObject(id, "testcoll");
bso.payload = "my test payload";
let request = client.setBSO(bso);
request.dispatch(function(error, req) {
do_check_eq(error, null);
do_check_eq(req.resultObj, null);
server.stop(run_next_test);
});
});
add_test(function test_set_bso_conditional() {
_("Ensure conditional setting a BSO is properly rejected.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now + 1000)
});
// Should get an mtime newer than server's.
let bso = new BasicStorageObject("foo", "testcoll");
bso.payload = "payload1";
let request = client.setBSO(bso);
request.locallyModifiedVersion = now;
request.dispatch(function onComplete(error, req) {
do_check_true(error instanceof StorageServiceRequestError);
do_check_true(error.serverModified);
server.stop(run_next_test);
});
});
add_test(function test_set_bso_argument_errors() {
_("Ensure BSO set detects invalid arguments.");
let bso = new BasicStorageObject();
let client = getClient();
let threw = false;
try {
client.setBSO(bso);
} catch (ex) {
threw = true;
do_check_eq(ex.name, "Error");
do_check_neq(ex.message.indexOf("does not have collection defined"), -1);
} finally {
do_check_true(threw);
threw = false;
}
bso = new BasicStorageObject("id");
try {
client.setBSO(bso);
} catch (ex) {
threw = true;
do_check_eq(ex.name, "Error");
do_check_neq(ex.message.indexOf("does not have collection defined"), -1);
} finally {
do_check_true(threw);
threw = false;
}
bso = new BasicStorageObject(null, "coll");
try {
client.setBSO(bso);
} catch (ex) {
threw = true;
do_check_eq(ex.name, "Error");
do_check_neq(ex.message.indexOf("does not have ID defined"), -1);
} finally {
do_check_true(threw);
threw = false;
}
run_next_test();
});
add_test(function test_set_bsos_simple() {
_("Ensure setBSOs with basic options works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let bso0 = new BasicStorageObject("foo");
bso0.payload = "payload0";
let bso1 = new BasicStorageObject("bar");
bso1.payload = "payload1";
let request = client.setBSOs("testcollection");
request.addBSO(bso0);
request.addBSO(bso1);
request.dispatch(function onComplete(error, req) {
do_check_null(error);
let successful = req.successfulIDs;
do_check_eq(successful.size(), 2);
do_check_true(successful.has(bso0.id));
do_check_true(successful.has(bso1.id));
server.stop(run_next_test);
});
});
add_test(function test_set_bsos_invalid_bso() {
_("Ensure that adding an invalid BSO throws.");
let client = getClient();
let request = client.setBSOs("testcoll");
let threw = false;
// Empty argument is invalid.
try {
request.addBSO(null);
} catch (ex) {
threw = true;
} finally {
do_check_true(threw);
threw = false;
}
try {
let bso = new BasicStorageObject();
request.addBSO(bso);
} catch (ex) {
threw = true;
} finally {
do_check_true(threw);
threw = false;
}
run_next_test();
});
add_test(function test_delete_bso_simple() {
_("Ensure deletion of individual BSOs works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", Date.now()),
bar: new ServerBSO("bar", "payload1", Date.now())
});
let request = client.deleteBSO("testcoll", "foo");
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(req.statusCode, 204);
do_check_eq(coll.count(), 1);
server.stop(run_next_test);
});
});
add_test(function test_delete_bso_conditional_failed() {
_("Ensure deletion of an individual BSO with older modification fails.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.deleteBSO("testcoll", "foo");
request.locallyModifiedVersion = now - 10;
request.dispatch(function onComplete(error, req) {
do_check_true(error instanceof StorageServiceRequestError);
do_check_true(error.serverModified);
server.stop(run_next_test);
});
});
add_test(function test_delete_bso_conditional_success() {
_("Ensure deletion of an individual BSO with newer modification works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.deleteBSO("testcoll", "foo");
request.locallyModifiedVersion = now;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(req.statusCode, 204);
server.stop(run_next_test);
});
});
add_test(function test_delete_bsos_simple() {
_("Ensure deletion of multiple BSOs works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", Date.now()),
bar: new ServerBSO("bar", "payload1", Date.now()),
baz: new ServerBSO("baz", "payload2", Date.now())
});
let request = client.deleteBSOs("testcoll", ["foo", "baz"]);
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(req.statusCode, 204);
do_check_eq(coll.count(), 1);
server.stop(run_next_test);
});
});
add_test(function test_delete_bsos_conditional_failed() {
_("Ensure deletion of BSOs with server modifications fails.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.deleteBSOs("testcoll", ["foo"]);
request.locallyModifiedVersion = coll.timestamp - 1;
request.dispatch(function onComplete(error, req) {
do_check_true(error instanceof StorageServiceRequestError);
do_check_true(error.serverModified);
server.stop(run_next_test);
});
});
add_test(function test_delete_bsos_conditional_success() {
_("Ensure conditional deletion of BSOs without server modifications works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now),
bar: new ServerBSO("bar", "payload1", now - 10)
});
let request = client.deleteBSOs("testcoll", ["bar"]);
request.locallyModifiedVersion = coll.timestamp;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(req.statusCode, 204);
server.stop(run_next_test);
});
});
add_test(function test_delete_collection() {
_("Ensure deleteCollection() works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", Date.now())
});
let request = client.deleteCollection("testcoll");
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(user.collection("testcoll", undefined));
server.stop(run_next_test);
});
});
add_test(function test_delete_collection_conditional_failed() {
_("Ensure conditional deletes with server modifications fail.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.deleteCollection("testcoll");
request.locallyModifiedVersion = coll.timestamp - 1;
request.dispatch(function onComplete(error, req) {
do_check_true(error instanceof StorageServiceRequestError);
do_check_true(error.serverModified);
server.stop(run_next_test);
});
});
add_test(function test_delete_collection_conditional_success() {
_("Ensure conditional delete of collection works when it's supposed to.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
let now = Date.now();
let coll = user.createCollection("testcoll", {
foo: new ServerBSO("foo", "payload0", now)
});
let request = client.deleteCollection("testcoll");
request.locallyModifiedVersion = coll.timestamp;
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(user.collection("testcoll"), undefined);
server.stop(run_next_test);
});
});
add_test(function test_delete_collections() {
_("Ensure deleteCollections() works.");
let [server, client, username] = getServerAndClient();
let user = server.user(username);
user.createCollection("testColl", {
foo: new ServerBSO("foo", "payload0", Date.now())
});
let request = client.deleteCollections();
request.dispatch(function onComplete(error, req) {
do_check_null(error);
do_check_eq(user.collection("testcoll"), undefined);
server.stop(run_next_test);
});
});
add_test(function test_network_error_captured() {
_("Ensure network errors are captured.");
// Network errors should result in .networkError being set on request.
let client = new StorageServiceClient("http://rnewman-is-splendid.badtld/");
let request = client.getCollectionInfo();
request.dispatch(function(error, req) {
do_check_neq(error, null);
do_check_neq(error.network, null);
run_next_test();
});
});
add_test(function test_network_error_listener() {
_("Ensure the onNetworkError listener is invoked on network errors.");
let listenerCalled = false;
let client = new StorageServiceClient("http://philikon-is-too.badtld/");
client.addListener({
onNetworkError: function(client, request) {
listenerCalled = true;
}
});
let request = client.getCollectionInfo();
request.dispatch(function() {
do_check_true(listenerCalled);
run_next_test();
});
});

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head_global.js head_helpers.js head_http.js aitcserver.js storageserver.js
head = head_global.js head_helpers.js head_http.js
tail =
# Test load modules first so syntax failures are caught early.
@ -22,6 +22,11 @@ tail =
[test_preferences.js]
[test_restrequest.js]
[test_tokenauthenticatedrequest.js]
# Storage service APIs
[test_storageservice_bso.js]
[test_storageservice_client.js]
[test_tokenserverclient.js]
[test_storage_server.js]

View File

@ -527,7 +527,7 @@ let SyncServerCallback = {
*/
function SyncServer(callback) {
this.callback = callback || {__proto__: SyncServerCallback};
this.server = new nsHttpServer();
this.server = new HttpServer();
this.started = false;
this.users = {};
this._log = Log4Moz.repository.getLogger(SYNC_HTTP_LOGGER);
@ -539,7 +539,7 @@ function SyncServer(callback) {
}
SyncServer.prototype = {
port: 8080,
server: null, // nsHttpServer.
server: null, // HttpServer.
users: null, // Map of username => {collections, password}.
/**
@ -775,8 +775,8 @@ SyncServer.prototype = {
},
/**
* This is invoked by the nsHttpServer. `this` is bound to the SyncServer;
* `handler` is the nsHttpServer's handler.
* This is invoked by the HttpServer. `this` is bound to the SyncServer;
* `handler` is the HttpServer's handler.
*
* TODO: need to use the correct Sync API response codes and errors here.
* TODO: Basic Auth.

View File

@ -170,7 +170,7 @@ add_test(function test_disabled_install_semantics() {
server.createContents(USER, contents);
server.start();
let amoServer = new nsHttpServer();
let amoServer = new HttpServer();
amoServer.registerFile("/search/guid:addon1%40tests.mozilla.org",
do_get_file("addon1-search.xml"));

View File

@ -42,7 +42,7 @@ function createRecordForThisApp(id, addonId, enabled, deleted) {
function createAndStartHTTPServer(port) {
try {
let server = new nsHttpServer();
let server = new HttpServer();
let bootstrap1XPI = ExtensionsTestPath("/addons/test_bootstrap1_1.xpi");

View File

@ -1,6 +1,6 @@
{
"talos.zip": {
"url": "http://build.mozilla.org/talos/zips/talos.aec9ddd2a04c.zip",
"url": "http://build.mozilla.org/talos/zips/talos.18ae2ce2749b.zip",
"path": ""
}
}

View File

@ -303,7 +303,16 @@ package-tests: stage-android
endif
make-stage-dir:
rm -rf $(PKG_STAGE) && $(NSINSTALL) -D $(PKG_STAGE) && $(NSINSTALL) -D $(PKG_STAGE)/bin && $(NSINSTALL) -D $(PKG_STAGE)/bin/components && $(NSINSTALL) -D $(PKG_STAGE)/certs && $(NSINSTALL) -D $(PKG_STAGE)/jetpack && $(NSINSTALL) -D $(PKG_STAGE)/firebug && $(NSINSTALL) -D $(PKG_STAGE)/peptest && $(NSINSTALL) -D $(PKG_STAGE)/mozbase && $(NSINSTALL) -D $(PKG_STAGE)/modules
rm -rf $(PKG_STAGE)
$(NSINSTALL) -D $(PKG_STAGE)
$(NSINSTALL) -D $(PKG_STAGE)/bin
$(NSINSTALL) -D $(PKG_STAGE)/bin/components
$(NSINSTALL) -D $(PKG_STAGE)/certs
$(NSINSTALL) -D $(PKG_STAGE)/jetpack
$(NSINSTALL) -D $(PKG_STAGE)/firebug
$(NSINSTALL) -D $(PKG_STAGE)/peptest
$(NSINSTALL) -D $(PKG_STAGE)/mozbase
$(NSINSTALL) -D $(PKG_STAGE)/modules
robotium-id-map:
ifeq ($(MOZ_BUILD_APP),mobile/android)
@ -347,9 +356,9 @@ stage-tps: make-stage-dir
@(cd $(topsrcdir)/services/sync/tps && tar $(TAR_CREATE_FLAGS) - *) | (cd $(PKG_STAGE)/tps && tar -xf -)
(cd $(topsrcdir)/services/sync/tests/tps && tar $(TAR_CREATE_FLAGS_QUIET) - *) | (cd $(PKG_STAGE)/tps/tests && tar -xf -)
# This will get replaced by actual logic in a subsequent patch.
stage-modules: make-stage-dir
$(TOUCH) $(PKG_STAGE)/modules/.dummy
$(NSINSTALL) -D $(PKG_STAGE)/modules
cp -RL $(DEPTH)/_tests/modules $(PKG_STAGE)
stage-mozbase: make-stage-dir
$(MAKE) -C $(DEPTH)/testing/mozbase stage-package

View File

@ -281,7 +281,18 @@ function _register_protocol_handlers() {
createInstance(Components.interfaces.nsILocalFile);
modulesFile.initWithPath(_TESTING_MODULES_DIR);
if (!modulesFile.exists()) {
throw new Error("Specified modules directory does not exist: " +
_TESTING_MODULES_DIR);
}
if (!modulesFile.isDirectory()) {
throw new Error("Specified modules directory is not a directory: " +
_TESTING_MODULES_DIR);
}
let modulesURI = ios.newFileURI(modulesFile);
protocolHandler.setSubstitution("testing-common", modulesURI);
}
}
@ -814,7 +825,8 @@ function do_load_child_test_harness()
+ "const _XPCSHELL_PROCESS='child';";
if (this._TESTING_MODULES_DIR) {
command += "const _TESTING_MODULES_DIR='" + _TESTING_MODULES_DIR + "'; ";
normalized = this._TESTING_MODULES_DIR.replace('\\', '\\\\', 'g');
command += "const _TESTING_MODULES_DIR='" + normalized + "'; ";
}
command += "load(_HEAD_JS_PATH);";

View File

@ -202,9 +202,11 @@ class XPCShellTests(object):
]
if self.testingModulesDir:
# Escape backslashes in string literal.
sanitized = self.testingModulesDir.replace('\\', '\\\\')
self.xpcsCmd.extend([
'-e',
'const _TESTING_MODULES_DIR = "%s";' % self.testingModulesDir
'const _TESTING_MODULES_DIR = "%s";' % sanitized
])
self.xpcsCmd.extend(['-f', os.path.join(self.testharnessdir, 'head.js')])
@ -587,10 +589,30 @@ class XPCShellTests(object):
raise Exception("testsRootDir path does not exists: %s" %
testsRootDir)
# Try to guess modules directory.
# This somewhat grotesque hack allows the buildbot machines to find the
# modules directory without having to configure the buildbot hosts. This
# code path should never be executed in local runs because the build system
# should always set this argument.
if not testingModulesDir:
ourDir = os.path.dirname(__file__)
possible = os.path.join(ourDir, os.path.pardir, 'modules')
if os.path.isdir(possible):
testingModulesDir = possible
if testingModulesDir:
# The resource loader expects native paths. Depending on how we were
# invoked, a UNIX style path may sneak in on Windows. We try to
# normalize that.
testingModulesDir = os.path.normpath(testingModulesDir)
if not os.path.isabs(testingModulesDir):
testingModulesDir = os.path.abspath(testingModulesDir)
if not testingModulesDir.endswith(os.path.sep):
testingModulesDir += os.path.sep
self.xpcshell = xpcshell
self.xrePath = xrePath
self.appPath = appPath
@ -664,6 +686,7 @@ class XPCShellTests(object):
# dir and the test with path characters replaced with '.' (using Java
# class notation).
if testsRootDir is not None:
testsRootDir = os.path.normpath(testsRootDir)
if test["here"].find(testsRootDir) != 0:
raise Exception("testsRootDir is not a parent path of %s" %
test["here"])