add http js server for unit tests; add tests for resources, auth manager, base weave record types (WBOs, keys, crypto wrappers/crypto meta)
add http js server for unit tests; add tests for resources, auth manager, base weave record types (WBOs, keys, crypto wrappers/crypto meta)
--- a/services/sync/tests/unit/Makefile
+++ b/services/sync/tests/unit/Makefile
@@ -1,2 +1,1 @@
-all:
- ${MAKE} -f ../harness/Makefile
+include ../harness/Makefile
--- a/services/sync/tests/unit/head_first.js
+++ b/services/sync/tests/unit/head_first.js
@@ -27,16 +27,17 @@ let provider = {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
ds.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
do_bind_resource(do_get_file("modules"), "weave");
+do_bind_resource(do_get_file("tests"), "tests");
function loadInSandbox(aUri) {
var sandbox = Components.utils.Sandbox(this);
var request = Components.
classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance();
request.open("GET", aUri, false);
@@ -69,17 +70,17 @@ function FakeTimerService() {
return false;
}
};
Utils.makeTimerForCall = self.makeTimerForCall;
};
function getTestLogger(component) {
- return Log4Moz.Service.getLogger("Testing");
+ return Log4Moz.repository.getLogger("Testing");
}
function initTestLogging(level) {
Cu.import("resource://weave/log4moz.js");
function LogStats() {
this.errorsLogged = 0;
}
@@ -88,17 +89,17 @@ function initTestLogging(level) {
if (message.level == Log4Moz.Level.Error)
this.errorsLogged += 1;
return message.loggerName + "\t" + message.levelDesc + "\t" +
message.message + "\n";
}
};
LogStats.prototype.__proto__ = new Log4Moz.Formatter();
- var log = Log4Moz.Service.rootLogger;
+ var log = Log4Moz.repository.rootLogger;
var logStats = new LogStats();
var appender = new Log4Moz.DumpAppender(logStats);
if (typeof(level) == "undefined")
level = "Debug";
getTestLogger().level = Log4Moz.Level[level];
log.level = Log4Moz.Level.Trace;
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/head_http_server.js
@@ -0,0 +1,25 @@
+let Httpd = {};
+Cu.import("resource://tests/lib/httpd.js", Httpd);
+
+function httpd_setup (handlers) {
+ let server = new Httpd.nsHttpServer();
+ for (let path in handlers) {
+ server.registerPathHandler(path, handlers[path]);
+ }
+ server.start(8080);
+ return server;
+}
+
+function httpd_basic_auth_handler(body, metadata, response) {
+ // no btoa() in xpcshell. it's guest:guest
+ if (metadata.hasHeader("Authorization") &&
+ metadata.getHeader("Authorization") == "Basic Z3Vlc3Q6Z3Vlc3Q=") {
+ response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+ } else {
+ body = "This path exists and is protected - failed";
+ response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+ }
+ response.bodyOutputStream.write(body, body.length);
+}
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_auth_manager.js
@@ -0,0 +1,59 @@
+Cu.import("resource://weave/log4moz.js");
+Cu.import("resource://weave/util.js");
+Cu.import("resource://weave/async.js");
+Cu.import("resource://weave/auth.js");
+Cu.import("resource://weave/identity.js");
+Cu.import("resource://weave/resource.js");
+
+Function.prototype.async = Async.sugar;
+
+let logger;
+let Httpd = {};
+Cu.import("resource://tests/lib/httpd.js", Httpd);
+
+function server_handler(metadata, response) {
+ let body;
+
+ // no btoa() in xpcshell. it's guest:guest
+ if (metadata.hasHeader("Authorization") &&
+ metadata.getHeader("Authorization") == "Basic Z3Vlc3Q6Z3Vlc3Q=") {
+ body = "This path exists and is protected";
+ response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+
+ } else {
+ body = "This path exists and is protected - failed";
+ response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+ }
+
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function async_test() {
+ let self = yield;
+
+ logger = Log4Moz.repository.getLogger('Test');
+ Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
+
+ let server = new Httpd.nsHttpServer();
+ server.registerPathHandler("/foo", server_handler);
+ server.start(8080);
+
+ let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest"));
+ Auth.defaultAuthenticator = auth;
+
+ let res = new Resource("http://localhost:8080/foo"); // no authenticator
+ let content = yield res.get(self.cb);
+ do_check_eq(content, "This path exists and is protected");
+ do_check_eq(res.lastRequest.status, 200);
+
+ do_test_finished();
+ server.stop();
+ self.done();
+}
+
+function run_test() {
+ async_test.async(this);
+ do_test_pending();
+}
--- a/services/sync/tests/unit/test_fault_tolerance.js
+++ b/services/sync/tests/unit/test_fault_tolerance.js
@@ -1,13 +1,13 @@
function run_test() {
Components.utils.import("resource://weave/log4moz.js");
Components.utils.import("resource://weave/faultTolerance.js");
// Just make sure the getter works and the service is a singleton.
FaultTolerance.Service._testProperty = "hi";
do_check_eq(FaultTolerance.Service._testProperty, "hi");
- var log = Log4Moz.Service.rootLogger;
+ var log = Log4Moz.repository.rootLogger;
log.level = Log4Moz.Level.All;
log.info("Testing.");
- do_check_eq(Log4Moz.Service.rootLogger.appenders.length, 1);
+ do_check_eq(Log4Moz.repository.rootLogger.appenders.length, 1);
}
--- a/services/sync/tests/unit/test_log4moz.js
+++ b/services/sync/tests/unit/test_log4moz.js
@@ -7,17 +7,17 @@ function MockAppender(formatter) {
MockAppender.prototype = {
doAppend: function DApp_doAppend(message) {
this.messages.push(message);
}
};
MockAppender.prototype.__proto__ = new Log4Moz.Appender();
function run_test() {
- var log = Log4Moz.Service.rootLogger;
+ var log = Log4Moz.repository.rootLogger;
var appender = new MockAppender(new Log4Moz.BasicFormatter());
log.level = Log4Moz.Level.Debug;
appender.level = Log4Moz.Level.Info;
log.addAppender(appender);
log.info("info test");
log.debug("this should be logged but not appended.");
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_records_crypto.js
@@ -0,0 +1,105 @@
+try {
+ Cu.import("resource://weave/log4moz.js");
+ Cu.import("resource://weave/util.js");
+ Cu.import("resource://weave/async.js");
+ Cu.import("resource://weave/auth.js");
+ Cu.import("resource://weave/identity.js");
+ Cu.import("resource://weave/base_records/keys.js");
+ Cu.import("resource://weave/base_records/crypto.js");
+} catch (e) {
+ do_throw(e);
+}
+Function.prototype.async = Async.sugar;
+
+let jsonSvc, cryptoSvc, salt, iv, symKey, wrappedKey, pubKey, privKey;
+
+function pubkey_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ payload: {type: "pubkey",
+ private_key: "http://localhost:8080/privkey",
+ key_data: pubKey}};
+ return httpd_basic_auth_handler(jsonSvc.encode(obj), metadata, response);
+}
+
+function privkey_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ payload: {type: "privkey",
+ public_key: "http://localhost:8080/pubkey",
+ key_data: privKey}};
+ return httpd_basic_auth_handler(jsonSvc.encode(obj), metadata, response);
+}
+
+function crypted_resource_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ encryption: "http://localhost:8080/crypto-meta",
+ payload: cryptoSvc.encrypt("my payload here", symKey, iv)};
+ return httpd_basic_auth_handler(jsonSvc.encode(obj), metadata, response);
+}
+
+function crypto_meta_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ payload: {type: "crypto-meta",
+ salt: salt,
+ iv: iv,
+ keyring: {
+ "pubkey": wrappedKey
+ }}};
+ return httpd_basic_auth_handler(jsonSvc.encode(obj), metadata, response);
+}
+
+function async_test() {
+ let self = yield;
+ let server;
+
+ try {
+ let log = Log4Moz.repository.getLogger();
+ Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
+
+ jsonSvc = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+ cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
+ getService(Ci.IWeaveCrypto);
+
+ let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest"));
+ Auth.defaultAuthenticator = auth;
+ PubKeys.defaultKeyUrl = "http://localhost:8080/pubkey";
+
+ server = httpd_setup({"/pubkey": pubkey_handler,
+ "/privkey": privkey_handler,
+ "/crypted-resource": crypted_resource_handler,
+ "/crypto-meta": crypto_meta_handler});
+
+ salt = cryptoSvc.generateRandomBytes(16);
+ iv = cryptoSvc.generateRandomIV();
+
+ let pubOut = {}, privOut = {};
+ cryptoSvc.generateKeypair("my passphrase", salt, iv, pubOut, privOut);
+ pubKey = pubOut.value;
+ privKey = privOut.value;
+
+ symKey = cryptoSvc.generateRandomKey();
+ wrappedKey = cryptoSvc.wrapSymmetricKey(symKey, pubKey);
+
+ let wrap = new CryptoWrapper("http://localhost:8080/crypted-resource", auth);
+ yield wrap.get(self.cb);
+
+ let payload = yield wrap.decrypt(self.cb, "my passphrase");
+ do_check_eq(payload, "my payload here");
+ do_check_neq(payload, wrap.data.payload); // wrap.data.payload is the encrypted one
+
+ wrap.cleartext = "another payload";
+ yield wrap.encrypt(self.cb, "my passphrase");
+ payload = yield wrap.decrypt(self.cb, "my passphrase");
+ do_check_eq(payload, "another payload");
+
+ do_test_finished();
+ }
+ catch (e) { do_throw(e); }
+ finally { server.stop(); }
+
+ self.done();
+}
+
+function run_test() {
+ async_test.async(this);
+ do_test_pending();
+}
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_records_keys.js
@@ -0,0 +1,64 @@
+try {
+ Cu.import("resource://weave/log4moz.js");
+ Cu.import("resource://weave/util.js");
+ Cu.import("resource://weave/async.js");
+ Cu.import("resource://weave/auth.js");
+ Cu.import("resource://weave/identity.js");
+ Cu.import("resource://weave/base_records/keys.js");
+} catch (e) {
+ do_throw(e);
+}
+Function.prototype.async = Async.sugar;
+
+let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+
+function pubkey_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ payload: {type: "pubkey",
+ private_key: "http://localhost:8080/privkey",
+ key_data: "asdfasdfasf..."}};
+ return httpd_basic_auth_handler(json.encode(obj), metadata, response);
+}
+
+function privkey_handler(metadata, response) {
+ let obj = {modified: "2454725.98283",
+ payload: {type: "privkey",
+ public_key: "http://localhost:8080/pubkey",
+ key_data: "asdfasdfasf..."}};
+ let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+ return httpd_basic_auth_handler(json.encode(obj), metadata, response);
+}
+
+function async_test() {
+ let self = yield;
+ let server;
+
+ try {
+ let log = Log4Moz.repository.getLogger();
+ Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
+
+ let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest"));
+ Auth.defaultAuthenticator = auth;
+ server = httpd_setup({"/pubkey": pubkey_handler,
+ "/privkey": privkey_handler});
+
+ let pubkey = yield PubKeys.get(self.cb, "http://localhost:8080/pubkey");
+ do_check_eq(pubkey.data.payload.type, "pubkey");
+ do_check_eq(pubkey.lastRequest.status, 200);
+
+ let privkey = yield PrivKeys.get(self.cb, pubkey.privateKeyUri);
+ do_check_eq(privkey.data.payload.type, "privkey");
+ do_check_eq(privkey.lastRequest.status, 200);
+
+ do_test_finished();
+ }
+ catch (e) { do_throw(e); }
+ finally { server.stop(); }
+
+ self.done();
+}
+
+function run_test() {
+ async_test.async(this);
+ do_test_pending();
+}
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_records_wbo.js
@@ -0,0 +1,44 @@
+Cu.import("resource://weave/log4moz.js");
+Cu.import("resource://weave/async.js");
+Cu.import("resource://weave/auth.js");
+Cu.import("resource://weave/identity.js");
+Cu.import("resource://weave/base_records/wbo.js");
+
+Function.prototype.async = Async.sugar;
+
+let logger;
+let Httpd = {};
+Cu.import("resource://tests/lib/httpd.js", Httpd);
+
+function server_handler(metadata, response) {
+ let body = '{"guid": "asdf-1234-asdf-1234", "type": ["object"]}';
+ response.setStatusLine(metadata.httpVersion, 200, "OK");
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function async_test() {
+ let self = yield;
+
+ logger = Log4Moz.repository.getLogger('Test');
+ Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
+
+ let server = new Httpd.nsHttpServer();
+ server.registerPathHandler("/record", server_handler);
+ server.start(8080);
+
+ let res = new WBORecord("http://localhost:8080/record");
+ let rec = yield res.get(self.cb);
+ do_check_eq(rec.guid, "asdf-1234-asdf-1234");
+ do_check_eq(rec.type[0], "object");
+ do_check_eq(res.lastRequest.status, 200);
+
+ do_test_finished();
+ server.stop();
+
+ self.done();
+}
+
+function run_test() {
+ async_test.async(this);
+ do_test_pending();
+}
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_resource.js
@@ -0,0 +1,104 @@
+Cu.import("resource://weave/log4moz.js");
+Cu.import("resource://weave/util.js");
+Cu.import("resource://weave/async.js");
+Cu.import("resource://weave/resource.js");
+Cu.import("resource://weave/auth.js");
+Cu.import("resource://weave/identity.js");
+
+Function.prototype.async = Async.sugar;
+
+let logger;
+let Httpd = {};
+Cu.import("resource://tests/lib/httpd.js", Httpd);
+
+function server_open(metadata, response) {
+ let body = "This path exists";
+ response.setStatusLine(metadata.httpVersion, 200, "OK");
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function server_protected(metadata, response) {
+ let body;
+
+ // no btoa() in xpcshell. it's guest:guest
+ if (metadata.hasHeader("Authorization") &&
+ metadata.getHeader("Authorization") == "Basic Z3Vlc3Q6Z3Vlc3Q=") {
+ body = "This path exists and is protected";
+ response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+
+ } else {
+ body = "This path exists and is protected - failed";
+ response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
+ response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+ }
+
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function server_404(metadata, response) {
+ let body = "File not found";
+ response.setStatusLine(metadata.httpVersion, 404, "Not Found");
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function async_test() {
+ let self = yield;
+
+ logger = Log4Moz.repository.getLogger('Test');
+ Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
+
+ let server = new Httpd.nsHttpServer();
+ server.registerPathHandler("/open", server_open);
+ server.registerPathHandler("/protected", server_protected);
+ server.registerPathHandler("/404", server_404);
+ server.start(8080);
+
+ Utils.prefs.setIntPref("network.numRetries", 1); // speed up test
+
+ // 1. A regular non-password-protected resource
+
+ let res = new Resource("http://localhost:8080/open");
+ let content = yield res.get(self.cb);
+ do_check_eq(content, "This path exists");
+ do_check_eq(res.lastRequest.status, 200);
+
+ // 2. A password protected resource (test that it'll fail w/o pass)
+ let res2 = new Resource("http://localhost:8080/protected");
+ try {
+ content = yield res2.get(self.cb);
+ do_check_true(false); // unreachable, get() above must fail
+ } catch (e) {}
+
+ // 3. A password protected resource
+
+ let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest"));
+ let res3 = new Resource("http://localhost:8080/protected", auth);
+ content = yield res3.get(self.cb);
+ do_check_eq(content, "This path exists and is protected");
+ do_check_eq(res3.lastRequest.status, 200);
+
+ // 4. A non-existent resource (test that it'll fail)
+
+ let res4 = new Resource("http://localhost:8080/404");
+ try {
+ let content = yield res4.get(self.cb);
+ do_check_true(false); // unreachable, get() above must fail
+ } catch (e) {}
+ do_check_eq(res4.lastRequest.responseText, "File not found");
+ do_check_eq(res4.lastRequest.status, 404);
+
+ // FIXME: additional coverage needed:
+ // * PUT requests
+ // * DELETE requests
+ // * JsonFilter
+
+ do_test_finished();
+ server.stop();
+ self.done();
+}
+
+function run_test() {
+ async_test.async(this);
+ do_test_pending();
+}