Bug 997949 - Make sure NotificationDB never starves. r=mhenretty
authorAlexandre Lissy <lissyx@lissyx.dyndns.org>
Mon, 28 Apr 2014 02:55:00 -0400
changeset 181099 566be5533bc5440a3e3e7e7142b9dadba77fd9b9
parent 181098 8b6c2a901df64db1cbdc22eb9d43fe637178f26b
child 181100 3a9f212f6fd9dcb544395558af0c33598e044e88
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersmhenretty
bugs997949
milestone32.0a1
Bug 997949 - Make sure NotificationDB never starves. r=mhenretty
dom/src/notification/NotificationDB.jsm
dom/src/notification/moz.build
dom/src/notification/test/unit/test_notificationdb.js
dom/src/notification/test/unit/xpcshell.ini
--- a/dom/src/notification/NotificationDB.jsm
+++ b/dom/src/notification/NotificationDB.jsm
@@ -267,23 +267,25 @@ let NotificationDB = {
   },
 
   taskDelete: function(data, callback) {
     if (DEBUG) { debug("Task, deleting"); }
     var origin = data.origin;
     var id = data.id;
     if (!this.notifications[origin]) {
       if (DEBUG) { debug("No notifications found for origin: " + origin); }
+      callback();
       return;
     }
 
     // Make sure we can find the notification to delete.
     var oldNotification = this.notifications[origin][id];
     if (!oldNotification) {
       if (DEBUG) { debug("No notification found with id: " + id); }
+      callback();
       return;
     }
 
     if (oldNotification.tag) {
       delete this.byTag[origin][oldNotification.tag];
     }
     delete this.notifications[origin][id];
     this.save(callback);
--- a/dom/src/notification/moz.build
+++ b/dom/src/notification/moz.build
@@ -29,8 +29,9 @@ include('/ipc/chromium/chromium-config.m
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/dom/base',
     '/dom/ipc',
 ]
 
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/dom/src/notification/test/unit/test_notificationdb.js
@@ -0,0 +1,338 @@
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsIMessageSender");
+
+let systemNotification = {
+  origin: "app://system.gaiamobile.org/manifest.webapp",
+  id: "{2bc883bf-2809-4432-b0f4-f54e10372764}",
+  title: "SystemNotification:" + Date.now(),
+  dir: "auto",
+  lang: "",
+  body: "System notification body",
+  tag: "",
+  icon: "icon.png"
+};
+
+let calendarNotification = {
+  origin: "app://calendar.gaiamobile.org/manifest.webapp",
+  id: "{d8d11299-a58e-429b-9a9a-57c562982fbf}",
+  title: "CalendarNotification:" + Date.now(),
+  dir: "auto",
+  lang: "",
+  body: "Calendar notification body",
+  tag: "",
+  icon: "icon.png"
+};
+
+function run_test() {
+  do_get_profile();
+  Cu.import("resource://gre/modules/NotificationDB.jsm");
+  run_next_test();
+}
+
+// Helper function to add a listener, send message and treat the reply
+function addAndSend(msg, reply, callback, payload, runNext = true) {
+  let handler = {
+    receiveMessage: function(message) {
+      if (message.name === reply) {
+        cpmm.removeMessageListener(reply, handler);
+        callback(message);
+        if (runNext) {
+          run_next_test();
+        }
+      }
+    }
+  };
+  cpmm.addMessageListener(reply, handler);
+  cpmm.sendAsyncMessage(msg, payload);
+}
+
+// helper fonction, comparing two notifications
+function compareNotification(notif1, notif2) {
+  // retrieved notification should be the second one sent
+  for (let prop in notif1) {
+    // compare each property
+    do_check_eq(notif1[prop], notif2[prop]);
+  }
+}
+
+// Get one notification, none exists
+add_test(function test_get_none() {
+  let requestID = 0;
+  let msgReply = "Notification:GetAll:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+    do_check_eq(0, message.data.notifications.length);
+  };
+
+  addAndSend("Notification:GetAll", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    requestID: requestID
+  });
+});
+
+// Store one notification
+add_test(function test_send_one() {
+  let requestID = 1;
+  let msgReply = "Notification:Save:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+  };
+
+  addAndSend("Notification:Save", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    notification: systemNotification,
+    requestID: requestID
+  });
+});
+
+// Get one notification, one exists
+add_test(function test_get_one() {
+  let requestID = 2;
+  let msgReply = "Notification:GetAll:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+    do_check_eq(1, message.data.notifications.length);
+    // compare the content
+    compareNotification(systemNotification, message.data.notifications[0]);
+  };
+
+  addAndSend("Notification:GetAll", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    requestID: requestID
+  });
+});
+
+// Delete one notification
+add_test(function test_delete_one() {
+  let requestID = 3;
+  let msgReply = "Notification:Delete:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+  };
+
+  addAndSend("Notification:Delete", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    id: systemNotification.id,
+    requestID: requestID
+  });
+});
+
+// Get one notification, none exists
+add_test(function test_get_none_again() {
+  let requestID = 4;
+  let msgReply = "Notification:GetAll:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+    do_check_eq(0, message.data.notifications.length);
+  };
+
+  addAndSend("Notification:GetAll", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    requestID: requestID
+  });
+});
+
+// Delete one notification that do not exists anymore
+add_test(function test_delete_one_nonexistent() {
+  let requestID = 5;
+  let msgReply = "Notification:Delete:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+  };
+
+  addAndSend("Notification:Delete", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    id: systemNotification.id,
+    requestID: requestID
+  });
+});
+
+// Store two notifications with the same id
+add_test(function test_send_two_get_one() {
+  let requestID = 6;
+  let calls = 0;
+
+  let msgGetReply = "Notification:GetAll:Return:OK";
+  let msgGetHandler = function(message) {
+    do_check_eq(requestID + 2, message.data.requestID);
+    do_check_eq(1, message.data.notifications.length);
+    // compare the content
+    compareNotification(systemNotification, message.data.notifications[0]);
+  };
+
+  let msgSaveReply = "Notification:Save:Return:OK";
+  let msgSaveHandler = function(message) {
+    calls += 1;
+    if (calls === 2) {
+      addAndSend("Notification:GetAll", msgGetReply, msgGetHandler, {
+        origin: systemNotification.origin,
+        requestID: (requestID + 2)
+      });
+    }
+  };
+
+  addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
+    origin: systemNotification.origin,
+    notification: systemNotification,
+    requestID: requestID
+  }, false);
+
+  addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
+    origin: systemNotification.origin,
+    notification: systemNotification,
+    requestID: (requestID + 1)
+  }, false);
+});
+
+// Delete previous notification
+add_test(function test_delete_previous() {
+  let requestID = 8;
+  let msgReply = "Notification:Delete:Return:OK";
+  let msgHandler = function(message) {
+    do_check_eq(requestID, message.data.requestID);
+  };
+
+  addAndSend("Notification:Delete", msgReply, msgHandler, {
+    origin: systemNotification.origin,
+    id: systemNotification.id,
+    requestID: requestID
+  });
+});
+
+// Store two notifications from same origin with the same tag
+add_test(function test_send_two_get_one() {
+  let requestID = 10;
+  let tag = "voicemail";
+
+  let systemNotification1 = systemNotification;
+  systemNotification1.id = "{f271f9ee-3955-4c10-b1f2-af552fb270ee}";
+  systemNotification1.tag = tag;
+
+  let systemNotification2 = systemNotification;
+  systemNotification2.id = "{8ef9a628-f0f4-44b4-820d-c117573c33e3}";
+  systemNotification2.tag = tag;
+
+  let msgGetReply = "Notification:GetAll:Return:OK";
+  let msgGetNotifHandler = {
+    receiveMessage: function(message) {
+      if (message.name === msgGetReply) {
+        cpmm.removeMessageListener(msgGetReply, msgGetNotifHandler);
+        let notifications = message.data.notifications;
+        // same tag, so replaced
+        do_check_eq(1, notifications.length);
+        // compare the content
+        compareNotification(systemNotification2, notifications[0]);
+        run_next_test();
+      }
+    }
+  };
+
+  cpmm.addMessageListener(msgGetReply, msgGetNotifHandler);
+
+  let msgSaveReply = "Notification:Save:Return:OK";
+  let msgSaveCalls = 0;
+  let msgSaveHandler = function(message) {
+    msgSaveCalls++;
+    // Once both request have been sent, trigger getall
+    if (msgSaveCalls === 2) {
+      cpmm.sendAsyncMessage("Notification:GetAll", {
+        origin: systemNotification1.origin,
+        requestID: message.data.requestID + 2 // 12, 13
+      });
+    }
+  };
+
+  addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
+    origin: systemNotification1.origin,
+    notification: systemNotification1,
+    requestID: requestID // 10
+  }, false);
+
+  addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
+    origin: systemNotification2.origin,
+    notification: systemNotification2,
+    requestID: (requestID + 1) // 11
+  }, false);
+});
+
+// Store two notifications from two origins with the same tag
+add_test(function test_send_two_get_two() {
+  let requestID = 20;
+  let tag = "voicemail";
+
+  let systemNotification1 = systemNotification;
+  systemNotification1.tag = tag;
+
+  let calendarNotification2 = calendarNotification;
+  calendarNotification2.tag = tag;
+
+  let msgGetReply = "Notification:GetAll:Return:OK";
+  let msgGetCalls = 0;
+  let msgGetHandler = {
+    receiveMessage: function(message) {
+      if (message.name === msgGetReply) {
+        msgGetCalls++;
+        let notifications = message.data.notifications;
+
+        // one notification per origin
+        do_check_eq(1, notifications.length);
+
+        // first call should be system notification
+        if (msgGetCalls === 1) {
+          compareNotification(systemNotification1, notifications[0]);
+        }
+
+        // second and last call should be calendar notification
+        if (msgGetCalls === 2) {
+          cpmm.removeMessageListener(msgGetReply, msgGetHandler);
+          compareNotification(calendarNotification2, notifications[0]);
+          run_next_test();
+        }
+      }
+    }
+  };
+  cpmm.addMessageListener(msgGetReply, msgGetHandler);
+
+  let msgSaveReply = "Notification:Save:Return:OK";
+  let msgSaveCalls = 0;
+  let msgSaveHandler = {
+    receiveMessage: function(message) {
+      if (message.name === msgSaveReply) {
+        msgSaveCalls++;
+        if (msgSaveCalls === 2) {
+          cpmm.removeMessageListener(msgSaveReply, msgSaveHandler);
+
+          // Trigger getall for each origin
+          cpmm.sendAsyncMessage("Notification:GetAll", {
+            origin: systemNotification1.origin,
+            requestID: message.data.requestID + 1 // 22
+          });
+
+          cpmm.sendAsyncMessage("Notification:GetAll", {
+            origin: calendarNotification2.origin,
+            requestID: message.data.requestID + 2 // 23
+          });
+        }
+      }
+    }
+  };
+  cpmm.addMessageListener(msgSaveReply, msgSaveHandler);
+
+  cpmm.sendAsyncMessage("Notification:Save", {
+    origin: systemNotification1.origin,
+    notification: systemNotification1,
+    requestID: requestID // 20
+  });
+
+  cpmm.sendAsyncMessage("Notification:Save", {
+    origin: calendarNotification2.origin,
+    notification: calendarNotification2,
+    requestID: (requestID + 1) // 21
+  });
+});
new file mode 100644
--- /dev/null
+++ b/dom/src/notification/test/unit/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head =
+tail =
+
+[test_notificationdb.js]