michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: MARIONETTE_TIMEOUT = 40000; michael@0: michael@0: SpecialPowers.addPermission("sms", true, document); michael@0: SpecialPowers.setBoolPref("dom.sms.enabled", true); michael@0: michael@0: let manager = window.navigator.mozMobileMessage; michael@0: ok(manager instanceof MozMobileMessageManager, michael@0: "manager is instance of " + manager.constructor); michael@0: michael@0: let pendingEmulatorCmdCount = 0; michael@0: function sendSmsToEmulator(from, text, callback) { michael@0: ++pendingEmulatorCmdCount; michael@0: michael@0: let cmd = "sms send " + from + " " + text; michael@0: runEmulatorCmd(cmd, function(result) { michael@0: --pendingEmulatorCmdCount; michael@0: michael@0: callback(result[0] == "OK"); michael@0: }); michael@0: } michael@0: michael@0: let tasks = { michael@0: // List of test fuctions. Each of them should call |tasks.next()| when michael@0: // completed or |tasks.finish()| to jump to the last one. michael@0: _tasks: [], michael@0: _nextTaskIndex: 0, michael@0: michael@0: push: function(func) { michael@0: this._tasks.push(func); michael@0: }, michael@0: michael@0: next: function() { michael@0: let index = this._nextTaskIndex++; michael@0: let task = this._tasks[index]; michael@0: try { michael@0: task.apply(null, Array.slice(arguments)); michael@0: } catch (ex) { michael@0: ok(false, "test task[" + index + "] throws: " + ex); michael@0: // Run last task as clean up if possible. michael@0: if (index != this._tasks.length - 1) { michael@0: this.finish(); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: finish: function() { michael@0: this._tasks[this._tasks.length - 1](); michael@0: }, michael@0: michael@0: run: function() { michael@0: this.next(); michael@0: } michael@0: }; michael@0: michael@0: function getAllMessages(callback, filter, reverse) { michael@0: if (!filter) { michael@0: filter = new MozSmsFilter; michael@0: } michael@0: let messages = []; michael@0: let request = manager.getMessages(filter, reverse || false); michael@0: request.onsuccess = function(event) { michael@0: if (!request.done) { michael@0: messages.push(request.result); michael@0: request.continue(); michael@0: return; michael@0: } michael@0: michael@0: window.setTimeout(callback.bind(null, messages), 0); michael@0: } michael@0: } michael@0: michael@0: function deleteAllMessages() { michael@0: getAllMessages(function deleteAll(messages) { michael@0: let message = messages.shift(); michael@0: if (!message) { michael@0: ok(true, "all messages deleted"); michael@0: tasks.next(); michael@0: return; michael@0: } michael@0: michael@0: let request = manager.delete(message.id); michael@0: request.onsuccess = deleteAll.bind(null, messages); michael@0: request.onerror = function(event) { michael@0: ok(false, "failed to delete all messages"); michael@0: tasks.finish(); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: function sendMessage(to, body) { michael@0: manager.onsent = function() { michael@0: manager.onsent = null; michael@0: tasks.next(); michael@0: }; michael@0: let request = manager.send(to, body); michael@0: request.onerror = tasks.finish.bind(tasks); michael@0: } michael@0: michael@0: function receiveMessage(from, body) { michael@0: manager.onreceived = function() { michael@0: manager.onreceived = null; michael@0: tasks.next(); michael@0: }; michael@0: sendSmsToEmulator(from, body, function(success) { michael@0: if (!success) { michael@0: tasks.finish(); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: function getAllThreads(callback) { michael@0: let threads = []; michael@0: michael@0: let cursor = manager.getThreads(); michael@0: ok(cursor instanceof DOMCursor, michael@0: "cursor is instanceof " + cursor.constructor); michael@0: michael@0: cursor.onsuccess = function(event) { michael@0: if (!cursor.done) { michael@0: threads.push(cursor.result); michael@0: cursor.continue(); michael@0: return; michael@0: } michael@0: michael@0: window.setTimeout(callback.bind(null, threads), 0); michael@0: }; michael@0: } michael@0: michael@0: function checkThread(bodies, lastBody, unreadCount, participants, michael@0: thread, callback) { michael@0: log("Validating MozMobileMessageThread attributes " + michael@0: JSON.stringify([bodies, lastBody, unreadCount, participants])); michael@0: michael@0: ok(thread, "current thread should be valid."); michael@0: michael@0: ok(thread.id, "thread id", "thread.id"); michael@0: log("Got thread " + thread.id); michael@0: michael@0: if (lastBody != null) { michael@0: is(thread.body, lastBody, "thread.body"); michael@0: } michael@0: michael@0: is(thread.unreadCount, unreadCount, "thread.unreadCount"); michael@0: michael@0: ok(Array.isArray(thread.participants), "thread.participants is array"); michael@0: is(thread.participants.length, participants.length, michael@0: "thread.participants.length"); michael@0: for (let i = 0; i < participants.length; i++) { michael@0: is(thread.participants[i], participants[i], michael@0: "thread.participants[" + i + "]"); michael@0: } michael@0: michael@0: // Check whether the thread does contain all the messages it supposed to have. michael@0: let filter = new MozSmsFilter; michael@0: filter.threadId = thread.id; michael@0: getAllMessages(function(messages) { michael@0: is(messages.length, bodies.length, "messages.length and bodies.length"); michael@0: michael@0: for (let message of messages) { michael@0: let index = bodies.indexOf(message.body); michael@0: ok(index >= 0, "message.body '" + message.body + michael@0: "' should be found in bodies array."); michael@0: bodies.splice(index, 1); michael@0: } michael@0: michael@0: is(bodies.length, 0, "bodies array length"); michael@0: michael@0: window.setTimeout(callback, 0); michael@0: }, filter, false); michael@0: } michael@0: michael@0: tasks.push(deleteAllMessages); michael@0: michael@0: tasks.push(getAllThreads.bind(null, function(threads) { michael@0: is(threads.length, 0, "Empty thread list at beginning."); michael@0: tasks.next(); michael@0: })); michael@0: michael@0: // Populate MobileMessageDB with messages. michael@0: let checkFuncs = []; michael@0: michael@0: // [Thread 1] michael@0: // One message only, body = "thread 1"; michael@0: // All sent message, unreadCount = 0; michael@0: // One participant only, participants = ["5555211001"]. michael@0: tasks.push(sendMessage.bind(null, "5555211001", "thread 1")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 1"], michael@0: "thread 1", 0, ["5555211001"])); michael@0: michael@0: // [Thread 2] michael@0: // Two messages, body = "thread 2-2"; michael@0: // All sent message, unreadCount = 0; michael@0: // One participant with two aliased addresses, participants = ["5555211002"]. michael@0: tasks.push(sendMessage.bind(null, "5555211002", "thread 2-1")); michael@0: tasks.push(sendMessage.bind(null, "+15555211002", "thread 2-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 2-1", "thread 2-2"], michael@0: "thread 2-2", 0, ["5555211002"])); michael@0: michael@0: // [Thread 3] michael@0: // Two messages, body = "thread 3-2"; michael@0: // All sent message, unreadCount = 0; michael@0: // One participant with two aliased addresses, participants = ["+15555211003"]. michael@0: tasks.push(sendMessage.bind(null, "+15555211003", "thread 3-1")); michael@0: tasks.push(sendMessage.bind(null, "5555211003", "thread 3-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 3-1", "thread 3-2"], michael@0: "thread 3-2", 0, ["+15555211003"])); michael@0: michael@0: // [Thread 4] michael@0: // One message only, body = "thread 4"; michael@0: // All received message, unreadCount = 1; michael@0: // One participant only, participants = ["5555211004"]. michael@0: tasks.push(receiveMessage.bind(null, "5555211004", "thread 4")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 4"], michael@0: "thread 4", 1, ["5555211004"])); michael@0: michael@0: // [Thread 5] michael@0: // michael@0: // Thread body should be set to text body of the last message in this michael@0: // thread. However due to BUG 840051, we're having SMSC time as message michael@0: // timestamp and SMSC time resolution is 1 second. So it's likely that the two michael@0: // messages have the same timestamp and we just can't tell which is the later michael@0: // one. michael@0: // michael@0: // All received message, unreadCount = 2; michael@0: // One participant with two aliased addresses, participants = ["5555211005"]. michael@0: tasks.push(receiveMessage.bind(null, "5555211005", "thread 5-1")); michael@0: tasks.push(receiveMessage.bind(null, "+15555211005", "thread 5-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 5-1", "thread 5-2"], michael@0: null, 2, ["5555211005"])); michael@0: michael@0: // [Thread 6] michael@0: // michael@0: // Thread body should be set to text body of the last message in this michael@0: // thread. However due to BUG 840051, we're having SMSC time as message michael@0: // timestamp and SMSC time resolution is 1 second. So it's likely that the two michael@0: // messages have the same timestamp and we just can't tell which is the later michael@0: // one. michael@0: // michael@0: // All received message, unreadCount = 2; michael@0: // One participant with two aliased addresses, participants = ["+15555211006"]. michael@0: tasks.push(receiveMessage.bind(null, "+15555211006", "thread 6-1")); michael@0: tasks.push(receiveMessage.bind(null, "5555211006", "thread 6-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 6-1", "thread 6-2"], michael@0: null, 2, ["+15555211006"])); michael@0: michael@0: // [Thread 7] michael@0: // michael@0: // Thread body should be set to text body of the last message in this michael@0: // thread. However due to BUG 840051, there might be time difference between michael@0: // SMSC and device time. So the result of comparing the timestamps of sent and michael@0: // received message may not follow the order of requests and may result in michael@0: // UNEXPECTED-FAIL in following tests. michael@0: // michael@0: // Two received message, unreadCount = 2; michael@0: // One participant with two aliased addresses, participants = ["5555211007"]. michael@0: tasks.push(sendMessage.bind(null, "5555211007", "thread 7-1")); michael@0: tasks.push(sendMessage.bind(null, "+15555211007", "thread 7-2")); michael@0: tasks.push(receiveMessage.bind(null, "5555211007", "thread 7-3")); michael@0: tasks.push(receiveMessage.bind(null, "+15555211007", "thread 7-4")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 7-1", "thread 7-2", michael@0: "thread 7-3", "thread 7-4"], michael@0: null, 2, ["5555211007"])); michael@0: michael@0: // [Thread 8] michael@0: // michael@0: // Thread body should be set to text body of the last message in this michael@0: // thread. However due to BUG 840051, there might be time difference between michael@0: // SMSC and device time. So the result of comparing the timestamps of sent and michael@0: // received message may not follow the order of requests and may result in michael@0: // UNEXPECTED-FAIL in following tests. michael@0: // michael@0: // Two received message, unreadCount = 2; michael@0: // One participant with two aliased addresses, participants = ["5555211008"]. michael@0: tasks.push(receiveMessage.bind(null, "5555211008", "thread 8-1")); michael@0: tasks.push(receiveMessage.bind(null, "+15555211008", "thread 8-2")); michael@0: tasks.push(sendMessage.bind(null, "5555211008", "thread 8-3")); michael@0: tasks.push(sendMessage.bind(null, "+15555211008", "thread 8-4")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 8-1", "thread 8-2", michael@0: "thread 8-3", "thread 8-4"], michael@0: null, 2, ["5555211008"])); michael@0: michael@0: // [Thread 9] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["+15555211009"]. michael@0: tasks.push(sendMessage.bind(null, "+15555211009", "thread 9-1")); michael@0: tasks.push(sendMessage.bind(null, "01115555211009", "thread 9-2")); michael@0: tasks.push(sendMessage.bind(null, "5555211009", "thread 9-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 9-1", "thread 9-2", michael@0: "thread 9-3"], michael@0: "thread 9-3", 0, ["+15555211009"])); michael@0: michael@0: // [Thread 10] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["+15555211010"]. michael@0: tasks.push(sendMessage.bind(null, "+15555211010", "thread 10-1")); michael@0: tasks.push(sendMessage.bind(null, "5555211010", "thread 10-2")); michael@0: tasks.push(sendMessage.bind(null, "01115555211010", "thread 10-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 10-1", "thread 10-2", michael@0: "thread 10-3"], michael@0: "thread 10-3", 0, ["+15555211010"])); michael@0: michael@0: // [Thread 11] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["01115555211011"]. michael@0: tasks.push(sendMessage.bind(null, "01115555211011", "thread 11-1")); michael@0: tasks.push(sendMessage.bind(null, "5555211011", "thread 11-2")); michael@0: tasks.push(sendMessage.bind(null, "+15555211011", "thread 11-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 11-1", "thread 11-2", michael@0: "thread 11-3"], michael@0: "thread 11-3", 0, ["01115555211011"])); michael@0: michael@0: // [Thread 12] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["01115555211012"]. michael@0: tasks.push(sendMessage.bind(null, "01115555211012", "thread 12-1")); michael@0: tasks.push(sendMessage.bind(null, "+15555211012", "thread 12-2")); michael@0: tasks.push(sendMessage.bind(null, "5555211012", "thread 12-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 12-1", "thread 12-2", michael@0: "thread 12-3"], michael@0: "thread 12-3", 0, ["01115555211012"])); michael@0: michael@0: // [Thread 13] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["5555211013"]. michael@0: tasks.push(sendMessage.bind(null, "5555211013", "thread 13-1")); michael@0: tasks.push(sendMessage.bind(null, "+15555211013", "thread 13-2")); michael@0: tasks.push(sendMessage.bind(null, "01115555211013", "thread 13-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 13-1", "thread 13-2", michael@0: "thread 13-3"], michael@0: "thread 13-3", 0, ["5555211013"])); michael@0: michael@0: // [Thread 14] michael@0: // Three sent message, unreadCount = 0; michael@0: // One participant with three aliased addresses, participants = ["5555211014"]. michael@0: tasks.push(sendMessage.bind(null, "5555211014", "thread 14-1")); michael@0: tasks.push(sendMessage.bind(null, "01115555211014", "thread 14-2")); michael@0: tasks.push(sendMessage.bind(null, "+15555211014", "thread 14-3")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 14-1", "thread 14-2", michael@0: "thread 14-3"], michael@0: "thread 14-3", 0, ["5555211014"])); michael@0: michael@0: //[Thread 15] michael@0: //Three sent message, unreadCount = 0; michael@0: //One participant but might be merged to 555211015, participants = ["5555211015"]. michael@0: tasks.push(sendMessage.bind(null, "5555211015", "thread 15-1")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 15-1"], michael@0: "thread 15-1", 0, ["5555211015"])); michael@0: michael@0: //[Thread 16] michael@0: //Three sent message, unreadCount = 0; michael@0: //One participant but might be merged to 5555211015, participants = ["555211015"]. michael@0: tasks.push(sendMessage.bind(null, "555211015", "thread 16-1")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 16-1"], michael@0: "thread 16-1", 0, ["555211015"])); michael@0: michael@0: //[Thread 17] michael@0: //Three sent message, unreadCount = 0; michael@0: //One participant with two aliased addresses, participants = ["555211017"]. michael@0: tasks.push(sendMessage.bind(null, "+5511555211017", "thread 17-1")); michael@0: tasks.push(sendMessage.bind(null, "555211017", "thread 17-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 17-1", "thread 17-2"], michael@0: "thread 17-2", 0, ["+5511555211017"])); michael@0: michael@0: //[Thread 18] michael@0: //Three sent message, unreadCount = 0; michael@0: //One participant with two aliased addresses, participants = ["555211018"]. michael@0: tasks.push(sendMessage.bind(null, "555211018", "thread 18-1")); michael@0: tasks.push(sendMessage.bind(null, "+5511555211018", "thread 18-2")); michael@0: checkFuncs.push(checkThread.bind(null, ["thread 18-1", "thread 18-2"], michael@0: "thread 18-2", 0, ["555211018"])); michael@0: michael@0: // Check threads. michael@0: tasks.push(getAllThreads.bind(null, function(threads) { michael@0: is(threads.length, checkFuncs.length, "number of threads got"); michael@0: michael@0: // Reverse threads as we iterate over them in reverse order michael@0: threads.reverse(); michael@0: michael@0: (function callback() { michael@0: if (!threads.length) { michael@0: tasks.next(); michael@0: return; michael@0: } michael@0: michael@0: checkFuncs.shift()(threads.shift(), callback); michael@0: })(); michael@0: })); michael@0: michael@0: tasks.push(deleteAllMessages); michael@0: michael@0: tasks.push(getAllThreads.bind(null, function(threads) { michael@0: is(threads.length, 0, "Empty thread list at the end."); michael@0: tasks.next(); michael@0: })); michael@0: michael@0: // WARNING: All tasks should be pushed before this!!! michael@0: tasks.push(function cleanUp() { michael@0: if (pendingEmulatorCmdCount) { michael@0: window.setTimeout(cleanUp, 100); michael@0: return; michael@0: } michael@0: michael@0: SpecialPowers.removePermission("sms", document); michael@0: SpecialPowers.clearUserPref("dom.sms.enabled"); michael@0: finish(); michael@0: }); michael@0: michael@0: tasks.run();