1
Cu.import("resource://services-sync/util.js");
5
let ch = Cc["@mozilla.org/security/hash;1"].
6
createInstance(Ci.nsICryptoHash);
8
let ds = Cc["@mozilla.org/file/directory_service;1"]
9
.getService(Ci.nsIProperties);
12
getFile: function(prop, persistent) {
13
persistent.value = true;
16
return [ds.get("CurProcD", Ci.nsIFile)];
18
return ds.get("CurProcD", Ci.nsIFile);
20
let histFile = ds.get("CurProcD", Ci.nsIFile);
21
histFile.append("history.dat");
24
throw Cr.NS_ERROR_FAILURE;
27
QueryInterface: function(iid) {
28
if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
29
iid.equals(Ci.nsISupports)) {
32
throw Cr.NS_ERROR_NO_INTERFACE;
35
ds.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
37
function loadInSandbox(aUri) {
38
var sandbox = Components.utils.Sandbox(this);
39
var request = Components.
40
classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
43
request.open("GET", aUri, false);
44
request.overrideMimeType("application/javascript");
46
Components.utils.evalInSandbox(request.responseText, sandbox, "1.8");
51
function FakeTimerService() {
52
this.callbackQueue = [];
57
makeTimerForCall: function FTS_makeTimerForCall(cb) {
58
// Just add the callback to our queue and we'll call it later, so
59
// as to simulate a real nsITimer.
60
self.callbackQueue.push(cb);
61
return "fake nsITimer";
63
processCallback: function FTS_processCallbacks() {
64
var cb = self.callbackQueue.pop();
73
Utils.makeTimerForCall = self.makeTimerForCall;
76
btoa = Cu.import("resource://services-sync/log4moz.js").btoa;
77
function getTestLogger(component) {
78
return Log4Moz.repository.getLogger("Testing");
81
function initTestLogging(level) {
83
this.errorsLogged = 0;
85
LogStats.prototype = {
86
format: function BF_format(message) {
87
if (message.level == Log4Moz.Level.Error)
88
this.errorsLogged += 1;
89
return message.loggerName + "\t" + message.levelDesc + "\t" +
90
message.message + "\n";
93
LogStats.prototype.__proto__ = new Log4Moz.Formatter();
95
var log = Log4Moz.repository.rootLogger;
96
var logStats = new LogStats();
97
var appender = new Log4Moz.DumpAppender(logStats);
99
if (typeof(level) == "undefined")
101
getTestLogger().level = Log4Moz.Level[level];
103
log.level = Log4Moz.Level.Trace;
104
appender.level = Log4Moz.Level.Trace;
105
// Overwrite any other appenders (e.g. from previous incarnations)
106
log.ownAppenders = [appender];
107
log.updateAppenders();
112
function FakePrefService(contents) {
113
Cu.import("resource://services-sync/util.js");
114
this.fakeContents = contents;
115
Utils.__prefs = this;
118
FakePrefService.prototype = {
119
_getPref: function fake__getPref(pref) {
120
getTestLogger().trace("Getting pref: " + pref);
121
return this.fakeContents[pref];
123
getCharPref: function fake_getCharPref(pref) {
124
return this._getPref(pref);
126
getBoolPref: function fake_getBoolPref(pref) {
127
return this._getPref(pref);
129
getIntPref: function fake_getIntPref(pref) {
130
return this._getPref(pref);
132
addObserver: function fake_addObserver() {}
135
function FakePasswordService(contents) {
136
Cu.import("resource://services-sync/util.js");
138
this.fakeContents = contents;
141
Utils.findPassword = function fake_findPassword(realm, username) {
142
getTestLogger().trace("Password requested for " +
143
realm + ":" + username);
144
if (realm in self.fakeContents && username in self.fakeContents[realm])
145
return self.fakeContents[realm][username];
151
function FakeFilesystemService(contents) {
152
this.fakeContents = contents;
155
Utils.jsonSave = function jsonSave(filePath, that, obj, callback) {
156
let json = typeof obj == "function" ? obj.call(that) : obj;
157
self.fakeContents["weave/" + filePath + ".json"] = JSON.stringify(json);
161
Utils.jsonLoad = function jsonLoad(filePath, that, callback) {
163
let json = self.fakeContents["weave/" + filePath + ".json"];
165
obj = JSON.parse(json);
167
callback.call(that, obj);
171
function FakeGUIDService() {
174
Utils.makeGUID = function fake_makeGUID() {
175
return "fake-guid-" + latestGUID++;
181
* Mock implementation of IWeaveCrypto. It does not encrypt or
182
* decrypt, just returns the input verbatimly.
184
function FakeCryptoService() {
187
delete Svc.Crypto; // get rid of the getter first
189
Utils.sha256HMAC = this.sha256HMAC;
191
Cu.import("resource://services-sync/record.js");
192
CryptoWrapper.prototype.ciphertextHMAC = this.ciphertextHMAC;
194
FakeCryptoService.prototype = {
196
sha256HMAC: function Utils_sha256HMAC(message, hasher) {
197
message = message.substr(0, 64);
198
while (message.length < 64) {
204
ciphertextHMAC: function CryptoWrapper_ciphertextHMAC(keyBundle) {
205
return Utils.sha256HMAC(this.ciphertext);
208
encrypt: function(aClearText, aSymmetricKey, aIV) {
212
decrypt: function(aCipherText, aSymmetricKey, aIV) {
216
generateRandomKey: function() {
217
return btoa("fake-symmetric-key-" + this.counter++);
220
generateRandomIV: function() {
221
// A base64-encoded IV is 24 characters long
222
return btoa("fake-fake-fake-random-iv");
225
expandData : function expandData(data, len) {
229
deriveKeyFromPassphrase : function (passphrase, salt, keyLength) {
230
return "some derived key string composed of bytes";
233
generateRandomBytes: function(aByteCount) {
234
return "not-so-random-now-are-we-HA-HA-HA! >:)".slice(aByteCount);
239
function SyncTestingInfrastructure(engineFactory) {
240
let __fakePasswords = {
241
'Mozilla Services Password': {foo: "bar"},
242
'Mozilla Services Encryption Passphrase': {foo: "a-abcde-abcde-abcde-abcde-abcde"}
246
"encryption" : "none",
247
"log.logger.service.crypto" : "Debug",
248
"log.logger.service.engine" : "Debug",
249
"log.logger.async" : "Debug",
250
"xmpp.enabled" : false
253
Cu.import("resource://services-sync/identity.js");
254
Cu.import("resource://services-sync/util.js");
257
new Identity('Mozilla Services Encryption Passphrase', 'foo'));
258
ID.set('WeaveCryptoID',
259
new Identity('Mozilla Services Encryption Passphrase', 'foo'));
261
this.fakePasswordService = new FakePasswordService(__fakePasswords);
262
this.fakePrefService = new FakePrefService(__fakePrefs);
263
this.fakeTimerService = new FakeTimerService();
264
this.logStats = initTestLogging();
265
this.fakeFilesystem = new FakeFilesystemService({});
266
this.fakeGUIDService = new FakeGUIDService();
267
this.fakeCryptoService = new FakeCryptoService();
269
this._logger = getTestLogger();
270
this._engineFactory = engineFactory;
271
this._clientStates = [];
273
this.saveClientState = function pushClientState(label) {
274
let state = Utils.deepCopy(this.fakeFilesystem.fakeContents);
275
let currContents = this.fakeFilesystem.fakeContents;
276
this.fakeFilesystem.fakeContents = [];
277
let engine = this._engineFactory();
278
let snapshot = Utils.deepCopy(engine._store.wrap());
279
this._clientStates[label] = {state: state, snapshot: snapshot};
280
this.fakeFilesystem.fakeContents = currContents;
283
this.restoreClientState = function restoreClientState(label) {
284
let state = this._clientStates[label].state;
285
let snapshot = this._clientStates[label].snapshot;
287
function _restoreState() {
290
this.fakeFilesystem.fakeContents = [];
291
let engine = this._engineFactory();
292
engine._store.wipe();
293
let originalSnapshot = Utils.deepCopy(engine._store.wrap());
295
engine._core.detectUpdates(self.cb, originalSnapshot, snapshot);
296
let commands = yield;
298
engine._store.applyCommands.async(engine._store, self.cb, commands);
301
this.fakeFilesystem.fakeContents = Utils.deepCopy(state);
306
function restoreState(cb) {
307
_restoreState.async(self, cb);
310
this.runAsyncFunc("restore client state of " + label,
314
this.__makeCallback = function __makeCallback() {
315
this.__callbackCalled = false;
317
return function callback() {
318
self.__callbackCalled = true;
322
this.doSync = function doSync(name) {
325
function freshEngineSync(cb) {
326
let engine = self._engineFactory();
330
this.runAsyncFunc(name, freshEngineSync);
333
this.runAsyncFunc = function runAsyncFunc(name, func) {
334
let logger = this._logger;
336
logger.info("-----------------------------------------");
337
logger.info("Step '" + name + "' starting.");
338
logger.info("-----------------------------------------");
339
func(this.__makeCallback());
340
while (this.fakeTimerService.processCallback()) {}
341
do_check_true(this.__callbackCalled);
342
for (name in Async.outstandingGenerators)
343
logger.warn("Outstanding generator exists: " + name);
344
do_check_eq(this.logStats.errorsLogged, 0);
345
do_check_eq(Async.outstandingGenerators.length, 0);
346
logger.info("Step '" + name + "' succeeded.");
349
this.resetClientState = function resetClientState() {
350
this.fakeFilesystem.fakeContents = {};
351
let engine = this._engineFactory();
352
engine._store.wipe();
358
* Ensure exceptions from inside callbacks leads to test failures.
360
function ensureThrows(func) {
363
func.apply(this, arguments);
370
function asyncChainTests() {
371
return Utils.asyncChain.apply(this, Array.map(arguments, ensureThrows));
376
* Print some debug message to the console. All arguments will be printed,
377
* separated by spaces.
379
* @param [arg0, arg1, arg2, ...]
380
* Any number of arguments to print out
381
* @usage _("Hello World") -> prints "Hello World"
382
* @usage _(1, 2, 3) -> prints "1 2 3"
384
let _ = function(some, debug, text, to) print(Array.slice(arguments).join(" "));
386
_("Setting the identity for passphrase");
387
Cu.import("resource://services-sync/identity.js");
391
* Test setup helpers.
394
// Turn WBO cleartext into "encrypted" payload as it goes over the wire
395
function encryptPayload(cleartext) {
396
if (typeof cleartext == "object") {
397
cleartext = JSON.stringify(cleartext);
400
return {ciphertext: cleartext, // ciphertext == cleartext with fake crypto
402
hmac: Utils.sha256HMAC(cleartext, Utils.makeHMACKey(""))};