| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 (function() |  | 
| 2 { |  | 
| 3   let testRunner = null; |  | 
| 4   let randomResult = 0.5; |  | 
| 5 |  | 
| 6   let originalInfo; |  | 
| 7   let info = require("info"); |  | 
| 8 |  | 
| 9   function showNotifications(url) |  | 
| 10   { |  | 
| 11     let shownNotifications = []; |  | 
| 12     function showListener(notification) |  | 
| 13     { |  | 
| 14       shownNotifications.push(notification); |  | 
| 15       Notification.markAsShown(notification.id); |  | 
| 16     } |  | 
| 17     Notification.addShowListener(showListener); |  | 
| 18     Notification.showNext(url); |  | 
| 19     Notification.removeShowListener(showListener); |  | 
| 20     return shownNotifications; |  | 
| 21   } |  | 
| 22 |  | 
| 23   module("Notification handling", |  | 
| 24   { |  | 
| 25     setup: function() |  | 
| 26     { |  | 
| 27       testRunner = this; |  | 
| 28 |  | 
| 29       preparePrefs.call(this); |  | 
| 30       setupVirtualTime.call(this, function(wrapTimer) |  | 
| 31       { |  | 
| 32         let NotificationModule = getModuleGlobal("notification"); |  | 
| 33         NotificationModule.downloader._timer = wrapTimer(NotificationModule.down
     loader._timer); |  | 
| 34       }, "notification", "downloader"); |  | 
| 35       setupVirtualXMLHttp.call(this, "notification", "downloader"); |  | 
| 36 |  | 
| 37       originalInfo = {}; |  | 
| 38       for (let key in info) |  | 
| 39         originalInfo[key] = info[key]; |  | 
| 40 |  | 
| 41       info.addonName = "adblockpluschrome"; |  | 
| 42       info.addonVersion = "1.4.1"; |  | 
| 43       info.application = "chrome"; |  | 
| 44       info.applicationVersion = "27.0"; |  | 
| 45       info.platform = "chromium"; |  | 
| 46       info.platformVersion = "12.0"; |  | 
| 47 |  | 
| 48       Prefs.notificationurl = "http://example.com/notification.json"; |  | 
| 49       Prefs.notificationdata = {}; |  | 
| 50       Prefs.notifications_ignoredcategories = []; |  | 
| 51 |  | 
| 52       // Replace Math.random() function |  | 
| 53       let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader")
     ); |  | 
| 54       this._origRandom = DownloaderGlobal.Math.random; |  | 
| 55       DownloaderGlobal.Math.random = () => randomResult; |  | 
| 56       randomResult = 0.5; |  | 
| 57 |  | 
| 58       let NotificationGlobal = getModuleGlobal("notification"); |  | 
| 59       this._origShowListeners = NotificationGlobal.showListeners; |  | 
| 60       NotificationGlobal.showListeners = []; |  | 
| 61     }, |  | 
| 62 |  | 
| 63     teardown: function() |  | 
| 64     { |  | 
| 65       restorePrefs.call(this); |  | 
| 66       restoreVirtualTime.call(this); |  | 
| 67       restoreVirtualXMLHttp.call(this); |  | 
| 68 |  | 
| 69       for (let key in originalInfo) |  | 
| 70         info[key] = originalInfo[key]; |  | 
| 71 |  | 
| 72       if (this._origRandom) |  | 
| 73       { |  | 
| 74         let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader
     ")); |  | 
| 75         DownloaderGlobal.Math.random = this._origRandom; |  | 
| 76         delete this._origRandom; |  | 
| 77       } |  | 
| 78 |  | 
| 79       if (this._origShowListeners) |  | 
| 80       { |  | 
| 81         let NotificationGlobal = getModuleGlobal("notification"); |  | 
| 82         NotificationGlobal.showListeners = this._origShowListeners; |  | 
| 83         delete this._origShowListeners; |  | 
| 84       } |  | 
| 85 |  | 
| 86       Notification.init(); |  | 
| 87     } |  | 
| 88   }); |  | 
| 89 |  | 
| 90   function registerHandler(notifications, checkCallback) |  | 
| 91   { |  | 
| 92     testRunner.registerHandler("/notification.json", function(metadata) |  | 
| 93     { |  | 
| 94       if (checkCallback) |  | 
| 95         checkCallback(metadata); |  | 
| 96 |  | 
| 97       let notification = { |  | 
| 98         version: 55, |  | 
| 99         notifications: notifications |  | 
| 100       }; |  | 
| 101 |  | 
| 102       return [Cr.NS_OK, 200, JSON.stringify(notification)]; |  | 
| 103     }); |  | 
| 104   } |  | 
| 105 |  | 
| 106   function fixConstructors(object) |  | 
| 107   { |  | 
| 108     // deepEqual() expects that the constructors used in expected objects and |  | 
| 109     // the ones in the actual results are the same. That means that we actually |  | 
| 110     // have to construct our objects in the context of the notification module. |  | 
| 111     let JSON = Cu.getGlobalForObject(Notification).JSON; |  | 
| 112     return JSON.parse(JSON.stringify(object)); |  | 
| 113   } |  | 
| 114 |  | 
| 115   test("No data", function() |  | 
| 116   { |  | 
| 117     deepEqual(showNotifications(), [], "No notifications should be returned if t
     here is no data"); |  | 
| 118   }); |  | 
| 119 |  | 
| 120   test("Single notification", function() |  | 
| 121   { |  | 
| 122     let information = fixConstructors({ |  | 
| 123       id: 1, |  | 
| 124       type: "information", |  | 
| 125       message: {"en-US": "Information"} |  | 
| 126     }); |  | 
| 127 |  | 
| 128     registerHandler([information]); |  | 
| 129     testRunner.runScheduledTasks(1); |  | 
| 130 |  | 
| 131     deepEqual(showNotifications(), [information], "The notification is shown"); |  | 
| 132     deepEqual(showNotifications(), [], "Informational notifications aren't shown
      more than once"); |  | 
| 133   }); |  | 
| 134 |  | 
| 135   test("Information and critical", function() |  | 
| 136   { |  | 
| 137     let information = fixConstructors({ |  | 
| 138       id: 1, |  | 
| 139       type: "information", |  | 
| 140       message: {"en-US": "Information"} |  | 
| 141     }); |  | 
| 142     let critical = fixConstructors({ |  | 
| 143       id: 2, |  | 
| 144       type: "critical", |  | 
| 145       message: {"en-US": "Critical"} |  | 
| 146     }); |  | 
| 147 |  | 
| 148     registerHandler([information, critical]); |  | 
| 149     testRunner.runScheduledTasks(1); |  | 
| 150 |  | 
| 151     deepEqual(showNotifications(), [critical], "The critical notification is giv
     en priority"); |  | 
| 152     deepEqual(showNotifications(), [critical], "Critical notifications can be sh
     own multiple times"); |  | 
| 153   }); |  | 
| 154 |  | 
| 155   test("No type", function() |  | 
| 156   { |  | 
| 157     let information = fixConstructors({ |  | 
| 158       id: 1, |  | 
| 159       message: {"en-US": "Information"} |  | 
| 160     }); |  | 
| 161 |  | 
| 162     registerHandler([information]); |  | 
| 163     testRunner.runScheduledTasks(1); |  | 
| 164 |  | 
| 165     deepEqual(showNotifications(), [information], "The notification is shown"); |  | 
| 166     deepEqual(showNotifications(), [], "Notification is treated as type informat
     ion"); |  | 
| 167   }); |  | 
| 168 |  | 
| 169   test("Target selection", function() |  | 
| 170   { |  | 
| 171     let targets = [ |  | 
| 172       ["extension", "adblockpluschrome", true], |  | 
| 173       ["extension", "adblockplus", false], |  | 
| 174       ["extension", "adblockpluschrome2", false], |  | 
| 175       ["extensionMinVersion", "1.4", true], |  | 
| 176       ["extensionMinVersion", "1.4.1", true], |  | 
| 177       ["extensionMinVersion", "1.5", false], |  | 
| 178       ["extensionMaxVersion", "1.5", true], |  | 
| 179       ["extensionMaxVersion", "1.4.1", true], |  | 
| 180       ["extensionMaxVersion", "1.4.*", true], |  | 
| 181       ["extensionMaxVersion", "1.4", false], |  | 
| 182       ["application", "chrome", true], |  | 
| 183       ["application", "firefox", false], |  | 
| 184       ["applicationMinVersion", "27.0", true], |  | 
| 185       ["applicationMinVersion", "27", true], |  | 
| 186       ["applicationMinVersion", "26", true], |  | 
| 187       ["applicationMinVersion", "28", false], |  | 
| 188       ["applicationMinVersion", "27.1", false], |  | 
| 189       ["applicationMaxVersion", "27.0", true], |  | 
| 190       ["applicationMaxVersion", "27", true], |  | 
| 191       ["applicationMaxVersion", "28", true], |  | 
| 192       ["applicationMaxVersion", "26", false], |  | 
| 193       ["platform", "chromium", true], |  | 
| 194       ["platform", "gecko", false], |  | 
| 195       ["platformMinVersion", "12.0", true], |  | 
| 196       ["platformMinVersion", "12", true], |  | 
| 197       ["platformMinVersion", "11", true], |  | 
| 198       ["platformMinVersion", "13", false], |  | 
| 199       ["platformMinVersion", "12.1", false], |  | 
| 200       ["platformMaxVersion", "12.0", true], |  | 
| 201       ["platformMaxVersion", "12", true], |  | 
| 202       ["platformMaxVersion", "13", true], |  | 
| 203       ["platformMaxVersion", "11", false], |  | 
| 204     ]; |  | 
| 205 |  | 
| 206     for (let [propName, value, result] of targets) |  | 
| 207     { |  | 
| 208       let targetInfo = {}; |  | 
| 209       targetInfo[propName] = value; |  | 
| 210 |  | 
| 211       let information = fixConstructors({ |  | 
| 212         id: 1, |  | 
| 213         type: "information", |  | 
| 214         message: {"en-US": "Information"}, |  | 
| 215         targets: [targetInfo] |  | 
| 216       }); |  | 
| 217 |  | 
| 218       Prefs.notificationdata = {}; |  | 
| 219       registerHandler([information]); |  | 
| 220       testRunner.runScheduledTasks(1); |  | 
| 221 |  | 
| 222       let expected = (result ? [information] : []); |  | 
| 223       deepEqual(showNotifications(), expected, "Selected notification for " + JS
     ON.stringify(information.targets)); |  | 
| 224       deepEqual(showNotifications(), [], "No notification on second call"); |  | 
| 225     } |  | 
| 226   }); |  | 
| 227 |  | 
| 228   test("Multiple targets", function() |  | 
| 229   { |  | 
| 230     let targets = [ |  | 
| 231       ["extension", "adblockpluschrome", true], |  | 
| 232       ["extension", "adblockplus", false], |  | 
| 233       ["extensionMinVersion", "1.4", true], |  | 
| 234       ["extensionMinVersion", "1.5", false], |  | 
| 235       ["application", "chrome", true], |  | 
| 236       ["application", "firefox", false], |  | 
| 237       ["applicationMinVersion", "27", true], |  | 
| 238       ["applicationMinVersion", "28", false], |  | 
| 239       ["platform", "chromium", true], |  | 
| 240       ["platform", "gecko", false], |  | 
| 241       ["platformMinVersion", "12", true], |  | 
| 242       ["platformMinVersion", "13", false], |  | 
| 243     ]; |  | 
| 244 |  | 
| 245     function pairs(array) |  | 
| 246     { |  | 
| 247       for (let element1 of array) |  | 
| 248         for (let element2 of array) |  | 
| 249           if (element1 != element2) |  | 
| 250             yield [element1, element2]; |  | 
| 251     } |  | 
| 252 |  | 
| 253     for (let [[propName1, value1, result1], [propName2, value2, result2]] in pai
     rs(targets)) |  | 
| 254     { |  | 
| 255       let targetInfo1 = {}; |  | 
| 256       targetInfo1[propName1] = value1; |  | 
| 257       let targetInfo2 = {}; |  | 
| 258       targetInfo2[propName2] = value2; |  | 
| 259 |  | 
| 260       let information = fixConstructors({ |  | 
| 261         id: 1, |  | 
| 262         type: "information", |  | 
| 263         message: {"en-US": "Information"}, |  | 
| 264         targets: [targetInfo1, targetInfo2] |  | 
| 265       }); |  | 
| 266 |  | 
| 267       Prefs.notificationdata = {}; |  | 
| 268       registerHandler([information]); |  | 
| 269       testRunner.runScheduledTasks(1); |  | 
| 270 |  | 
| 271       let expected = (result1 || result2 ? [information] : []) |  | 
| 272       deepEqual(showNotifications(), expected, "Selected notification for " + JS
     ON.stringify(information.targets)); |  | 
| 273     } |  | 
| 274   }); |  | 
| 275 |  | 
| 276   test("Parameters sent", function() |  | 
| 277   { |  | 
| 278     Prefs.notificationdata = { |  | 
| 279       data: { |  | 
| 280         version: "3" |  | 
| 281       }, |  | 
| 282     }; |  | 
| 283 |  | 
| 284     let parameters = null; |  | 
| 285     registerHandler([], function(metadata) |  | 
| 286     { |  | 
| 287       parameters = decodeURI(metadata.queryString); |  | 
| 288     }); |  | 
| 289     testRunner.runScheduledTasks(1); |  | 
| 290 |  | 
| 291     equal(parameters, |  | 
| 292           "addonName=adblockpluschrome&addonVersion=1.4.1&application=chrome&app
     licationVersion=27.0&platform=chromium&platformVersion=12.0&lastVersion=3&downlo
     adCount=0", |  | 
| 293           "The correct parameters are sent to the server"); |  | 
| 294   }); |  | 
| 295 |  | 
| 296   test("Expiration interval", function() |  | 
| 297   { |  | 
| 298     let initialDelay = 1 / 60; |  | 
| 299     let tests = [ |  | 
| 300       { |  | 
| 301         randomResult: 0.5, |  | 
| 302         requests: [initialDelay, initialDelay + 24, initialDelay + 48] |  | 
| 303       }, |  | 
| 304       { |  | 
| 305         randomResult: 0,        // Changes interval by factor 0.8 (19.2 hours) |  | 
| 306         requests: [initialDelay, initialDelay + 20, initialDelay + 40] |  | 
| 307       }, |  | 
| 308       { |  | 
| 309         randomResult: 1,        // Changes interval by factor 1.2 (28.8 hours) |  | 
| 310         requests: [initialDelay, initialDelay + 29, initialDelay + 58] |  | 
| 311       }, |  | 
| 312       { |  | 
| 313         randomResult: 0.25,     // Changes interval by factor 0.9 (21.6 hours) |  | 
| 314         requests: [initialDelay, initialDelay + 22, initialDelay + 44] |  | 
| 315       }, |  | 
| 316       { |  | 
| 317         randomResult: 0.5, |  | 
| 318         skipAfter: initialDelay + 5, |  | 
| 319         skip: 10,               // Short break should not increase soft expirati
     on |  | 
| 320         requests: [initialDelay, initialDelay + 24] |  | 
| 321       }, |  | 
| 322       { |  | 
| 323         randomResult: 0.5, |  | 
| 324         skipAfter: initialDelay + 5, |  | 
| 325         skip: 30,               // Long break should increase soft expiration, h
     itting hard expiration |  | 
| 326         requests: [initialDelay, initialDelay + 48] |  | 
| 327       } |  | 
| 328     ]; |  | 
| 329 |  | 
| 330     let requests = []; |  | 
| 331     registerHandler([], (metadata) => requests.push(testRunner.getTimeOffset()))
     ; |  | 
| 332     for (let test of tests) |  | 
| 333     { |  | 
| 334       Prefs.notificationdata = {}; |  | 
| 335       requests = []; |  | 
| 336       randomResult = test.randomResult; |  | 
| 337 |  | 
| 338       let maxHours = Math.round(Math.max.apply(null, test.requests)) + 1; |  | 
| 339       testRunner.runScheduledTasks(maxHours, test.skipAfter, test.skip); |  | 
| 340 |  | 
| 341       let skipAddendum = (typeof test.skip != "number" ? "" : " skipping " + tes
     t.skip + " hours after " + test.skipAfter + " hours"); |  | 
| 342       deepEqual(requests, test.requests, "Requests with Math.random() returning 
     " + randomResult + skipAddendum); |  | 
| 343     } |  | 
| 344   }); |  | 
| 345 |  | 
| 346   test("Uses severity instead of type", 3, function() |  | 
| 347   { |  | 
| 348     let severityNotification = { |  | 
| 349       id: 1, |  | 
| 350       severity: "information", |  | 
| 351       message: {"en-US": "Information"} |  | 
| 352     }; |  | 
| 353 |  | 
| 354     function listener(name) |  | 
| 355     { |  | 
| 356       if (name !== "notificationdata") |  | 
| 357         return; |  | 
| 358 |  | 
| 359       Prefs.removeListener(listener); |  | 
| 360       let notification = Prefs.notificationdata.data.notifications[0]; |  | 
| 361       ok(!("severity" in notification), "Severity property was removed"); |  | 
| 362       ok("type" in notification, "Type property was added"); |  | 
| 363       equal(notification.type, severityNotification.severity, "Type property has
      correct value"); |  | 
| 364     } |  | 
| 365     Prefs.addListener(listener); |  | 
| 366 |  | 
| 367     let responseText = JSON.stringify({ |  | 
| 368       notifications: [severityNotification] |  | 
| 369     }); |  | 
| 370     Notification._onDownloadSuccess({}, responseText, function() {}, function() 
     {}); |  | 
| 371   }); |  | 
| 372 |  | 
| 373   test("URL-specific notification", function() |  | 
| 374   { |  | 
| 375     let withURLFilterFoo = fixConstructors({ |  | 
| 376       id: 1, |  | 
| 377       urlFilters: ["foo.com$document"] |  | 
| 378     }); |  | 
| 379     let withoutURLFilter = fixConstructors({ |  | 
| 380       id: 2 |  | 
| 381     }); |  | 
| 382     let withURLFilterBar = fixConstructors({ |  | 
| 383       id: 3, |  | 
| 384       urlFilters: ["bar.com$document"] |  | 
| 385     }); |  | 
| 386     let subdomainURLFilter = fixConstructors({ |  | 
| 387       id: 4, |  | 
| 388       urlFilters: ["||example.com$document"] |  | 
| 389     }); |  | 
| 390 |  | 
| 391     registerHandler([ |  | 
| 392       withURLFilterFoo, |  | 
| 393       withoutURLFilter, |  | 
| 394       withURLFilterBar, |  | 
| 395       subdomainURLFilter |  | 
| 396     ]); |  | 
| 397     testRunner.runScheduledTasks(1); |  | 
| 398 |  | 
| 399     deepEqual(showNotifications(), [withoutURLFilter], "URL-specific notificatio
     ns are skipped"); |  | 
| 400     deepEqual(showNotifications("http://foo.com"), [withURLFilterFoo], "URL-spec
     ific notification is retrieved"); |  | 
| 401     deepEqual(showNotifications("http://foo.com"), [], "URL-specific notificatio
     n is not retrieved"); |  | 
| 402     deepEqual(showNotifications("http://www.example.com"), [subdomainURLFilter],
      "URL-specific notification matches subdomain"); |  | 
| 403   }); |  | 
| 404 |  | 
| 405   test("Global opt-out", function() |  | 
| 406   { |  | 
| 407     Notification.toggleIgnoreCategory("*", true); |  | 
| 408     ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enable g
     lobal opt-out"); |  | 
| 409     Notification.toggleIgnoreCategory("*", true); |  | 
| 410     ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enable g
     lobal opt-out (again)"); |  | 
| 411     Notification.toggleIgnoreCategory("*", false); |  | 
| 412     ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disable 
     global opt-out"); |  | 
| 413     Notification.toggleIgnoreCategory("*", false); |  | 
| 414     ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disable 
     global opt-out (again)"); |  | 
| 415     Notification.toggleIgnoreCategory("*"); |  | 
| 416     ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Toggle enable 
     global opt-out"); |  | 
| 417     Notification.toggleIgnoreCategory("*"); |  | 
| 418     ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Toggle disable
      global opt-out"); |  | 
| 419 |  | 
| 420     Prefs.notifications_showui = false; |  | 
| 421     Notification.toggleIgnoreCategory("*", false); |  | 
| 422     ok(!Prefs.notifications_showui, "Opt-out UI will not be shown if global opt-
     out hasn't been enabled yet"); |  | 
| 423     Notification.toggleIgnoreCategory("*", true); |  | 
| 424     ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling glob
     al opt-out"); |  | 
| 425     Notification.toggleIgnoreCategory("*", false); |  | 
| 426     ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling glob
     al opt-out even if it got disabled again"); |  | 
| 427 |  | 
| 428     let information = fixConstructors({ |  | 
| 429       id: 1, |  | 
| 430       type: "information" |  | 
| 431     }); |  | 
| 432     let critical = fixConstructors({ |  | 
| 433       id: 2, |  | 
| 434       type: "critical" |  | 
| 435     }); |  | 
| 436 |  | 
| 437     Notification.toggleIgnoreCategory("*", true); |  | 
| 438     registerHandler([information]); |  | 
| 439     testRunner.runScheduledTasks(1); |  | 
| 440 |  | 
| 441     deepEqual(showNotifications(), [], "Information notifications are ignored af
     ter enabling global opt-out"); |  | 
| 442     Notification.toggleIgnoreCategory("*", false); |  | 
| 443     deepEqual(showNotifications(), [information], "Information notifications are
      shown after disabling global opt-out"); |  | 
| 444 |  | 
| 445     Notification.toggleIgnoreCategory("*", true); |  | 
| 446     Prefs.notificationdata = {}; |  | 
| 447     registerHandler([critical]); |  | 
| 448     testRunner.runScheduledTasks(1); |  | 
| 449 |  | 
| 450     deepEqual(showNotifications(), [critical], "Critical notifications are not i
     gnored"); |  | 
| 451   }); |  | 
| 452 |  | 
| 453   module("Notification localization"); |  | 
| 454 |  | 
| 455   test("Message without localization", function() |  | 
| 456   { |  | 
| 457     let notification = {message: "non-localized"}; |  | 
| 458     let texts = Notification.getLocalizedTexts(notification, "en-US"); |  | 
| 459     equal(texts.message, "non-localized"); |  | 
| 460   }); |  | 
| 461 |  | 
| 462   test("Language only", function() |  | 
| 463   { |  | 
| 464     let notification = {message: {fr: "fr"}}; |  | 
| 465     let texts = Notification.getLocalizedTexts(notification, "fr"); |  | 
| 466     equal(texts.message, "fr"); |  | 
| 467     texts = Notification.getLocalizedTexts(notification, "fr-CA"); |  | 
| 468     equal(texts.message, "fr"); |  | 
| 469   }); |  | 
| 470 |  | 
| 471   test("Language and country", function() |  | 
| 472   { |  | 
| 473     let notification = {message: {fr: "fr", "fr-CA": "fr-CA"}}; |  | 
| 474     let texts = Notification.getLocalizedTexts(notification, "fr-CA"); |  | 
| 475     equal(texts.message, "fr-CA"); |  | 
| 476     texts = Notification.getLocalizedTexts(notification, "fr"); |  | 
| 477     equal(texts.message, "fr"); |  | 
| 478   }); |  | 
| 479 |  | 
| 480   test("Missing translation", function() |  | 
| 481   { |  | 
| 482     let notification = {message: {"en-US": "en-US"}}; |  | 
| 483     let texts = Notification.getLocalizedTexts(notification, "fr"); |  | 
| 484     equal(texts.message, "en-US"); |  | 
| 485   }); |  | 
| 486 })(); |  | 
| OLD | NEW | 
|---|