| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 (function() | 1 /* |
| 2 { | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 let testRunner = null; | 3 * Copyright (C) 2006-2016 Eyeo GmbH |
| 4 let requestHandlers = null; | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | |
| 6 * it under the terms of the GNU General Public License version 3 as | |
| 7 * published by the Free Software Foundation. | |
| 8 * | |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 * GNU General Public License for more details. | |
| 13 * | |
| 14 * You should have received a copy of the GNU General Public License | |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
| 16 */ | |
| 17 | |
| 18 "use strict"; | |
| 19 | |
| 20 let {createSandbox} = require("./_common"); | |
| 21 | |
| 22 const MILLIS_IN_SECOND = 1000; | |
| 23 const MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; | |
| 24 const MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; | |
| 25 const MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; | |
| 26 | |
| 27 const Cr = { | |
| 28 NS_OK: 0, | |
| 29 NS_BINDING_ABORTED: 0x804B0002, | |
| 30 NS_ERROR_FAILURE: 0x80004005 | |
| 31 } | |
| 32 | |
| 33 let Filter = null; | |
| 34 let FilterStorage = null; | |
| 35 let Prefs = null; | |
| 36 let Subscription = null; | |
| 37 let Synchronizer = null; | |
| 38 | |
| 39 exports.setUp = function(callback) | |
| 40 { | |
| 41 let currentTime = 100000 * MILLIS_IN_HOUR; | |
| 42 let startTime = currentTime; | |
| 43 | |
| 44 let fakeTimer = { | |
| 45 callback: null, | |
| 46 delay: -1, | |
| 47 nextExecution: 0, | |
| 48 | |
| 49 initWithCallback: function(callback, delay, type) | |
| 50 { | |
| 51 if (this.callback) | |
| 52 throw new Error("Only one timer instance supported"); | |
| 53 if (type != 1) | |
| 54 throw new Error("Only TYPE_REPEATING_SLACK timers supported"); | |
| 55 | |
| 56 this.callback = callback; | |
| 57 this.delay = delay; | |
| 58 this.nextExecution = currentTime + delay; | |
| 59 }, | |
| 60 | |
| 61 trigger: function() | |
| 62 { | |
| 63 if (currentTime < this.nextExecution) | |
| 64 currentTime = this.nextExecution; | |
| 65 try | |
| 66 { | |
| 67 this.callback(); | |
| 68 } | |
| 69 finally | |
| 70 { | |
| 71 this.nextExecution = currentTime + this.delay; | |
| 72 } | |
| 73 }, | |
| 74 | |
| 75 cancel: function() | |
| 76 { | |
| 77 this.nextExecution = -1; | |
| 78 } | |
| 79 }; | |
| 80 | |
| 81 let requests = []; | |
| 82 function XMLHttpRequest() | |
|
kzar
2016/10/05 11:36:51
Seems kind of wasteful to define XMLHttpRequest an
Wladimir Palant
2016/10/05 12:12:51
Not really - we want a clean environment for every
kzar
2016/10/05 12:18:16
Fair enough.
| |
| 83 { | |
| 84 this._host = "http://example.com"; | |
| 85 this._loadHandlers = []; | |
| 86 this._errorHandlers = []; | |
| 87 }; | |
| 88 XMLHttpRequest.prototype = | |
| 89 { | |
| 90 _path: null, | |
| 91 _data: null, | |
| 92 _queryString: null, | |
| 93 _loadHandlers: null, | |
| 94 _errorHandlers: null, | |
| 95 status: 0, | |
| 96 readyState: 0, | |
| 97 responseText: null, | |
| 98 | |
| 99 addEventListener: function(eventName, handler, capture) | |
| 100 { | |
| 101 let list; | |
| 102 if (eventName == "load") | |
| 103 list = this._loadHandlers; | |
| 104 else if (eventName == "error") | |
| 105 list = this._errorHandlers; | |
| 106 else | |
| 107 throw new Error("Event type " + eventName + " not supported"); | |
| 108 | |
| 109 if (list.indexOf(handler) < 0) | |
| 110 list.push(handler); | |
| 111 }, | |
| 112 | |
| 113 removeEventListener: function(eventName, handler, capture) | |
| 114 { | |
| 115 let list; | |
| 116 if (eventName == "load") | |
| 117 list = this._loadHandlers; | |
| 118 else if (eventName == "error") | |
| 119 list = this._errorHandlers; | |
| 120 else | |
| 121 throw new Error("Event type " + eventName + " not supported"); | |
| 122 | |
| 123 let index = list.indexOf(handler); | |
| 124 if (index >= 0) | |
| 125 list.splice(index, 1); | |
| 126 }, | |
| 127 | |
| 128 open: function(method, url, async, user, password) | |
| 129 { | |
| 130 if (method != "GET") | |
| 131 throw new Error("Only GET requests are supported"); | |
| 132 if (typeof async != "undefined" && !async) | |
| 133 throw new Error("Sync requests are not supported"); | |
| 134 if (typeof user != "undefined" || typeof password != "undefined") | |
| 135 throw new Error("User authentification is not supported"); | |
| 136 | |
| 137 let match = /^data:[^,]+,/.exec(url); | |
| 138 if (match) | |
| 139 { | |
| 140 this._data = decodeURIComponent(url.substr(match[0].length)); | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 if (url.substr(0, this._host.length + 1) != this._host + "/") | |
| 145 throw new Error("Unexpected URL: " + url + " (URL starting with " + this ._host + "expected)"); | |
| 146 | |
| 147 this._path = url.substr(this._host.length); | |
| 148 | |
| 149 let queryIndex = this._path.indexOf("?"); | |
| 150 this._queryString = ""; | |
| 151 if (queryIndex >= 0) | |
| 152 { | |
| 153 this._queryString = this._path.substr(queryIndex + 1); | |
| 154 this._path = this._path.substr(0, queryIndex); | |
| 155 } | |
| 156 }, | |
| 157 | |
| 158 send: function(data) | |
| 159 { | |
| 160 if (!this._data && !this._path) | |
| 161 throw new Error("No request path set"); | |
| 162 if (typeof data != "undefined" && data) | |
| 163 throw new Error("Sending data to server is not supported"); | |
| 164 | |
| 165 requests.push(Promise.resolve().then(() => | |
| 166 { | |
| 167 let result = [Cr.NS_OK, 404, ""]; | |
| 168 if (this._data) | |
| 169 result = [Cr.NS_OK, 0, this._data]; | |
| 170 else if (this._path in XMLHttpRequest.requestHandlers) | |
| 171 { | |
| 172 result = XMLHttpRequest.requestHandlers[this._path]({ | |
| 173 method: "GET", | |
| 174 path: this._path, | |
| 175 queryString: this._queryString | |
| 176 }); | |
| 177 } | |
| 178 | |
| 179 [this.channel.status, this.channel.responseStatus, this.responseText] = result; | |
| 180 this.status = this.channel.responseStatus; | |
| 181 | |
| 182 let eventName = (this.channel.status == Cr.NS_OK ? "load" : "error"); | |
| 183 let event = {type: eventName}; | |
| 184 for (let handler of this["_" + eventName + "Handlers"]) | |
| 185 handler.call(this, event); | |
| 186 })); | |
| 187 }, | |
| 188 | |
| 189 overrideMimeType: function(mime) | |
| 190 { | |
| 191 }, | |
| 192 | |
| 193 channel: | |
| 194 { | |
| 195 status: -1, | |
| 196 responseStatus: 0, | |
| 197 loadFlags: 0, | |
| 198 INHIBIT_CACHING: 0, | |
| 199 VALIDATE_ALWAYS: 0, | |
| 200 QueryInterface: () => this | |
| 201 } | |
| 202 }; | |
| 203 | |
| 204 XMLHttpRequest.requestHandlers = {}; | |
| 205 this.registerHandler = (path, handler) => | |
| 206 { | |
| 207 XMLHttpRequest.requestHandlers[path] = handler; | |
| 208 }; | |
| 209 | |
| 210 function waitForRequests() | |
| 211 { | |
| 212 if (requests.length) | |
| 213 { | |
| 214 let result = Promise.all(requests); | |
| 215 requests = []; | |
| 216 return result.catch(e => | |
| 217 { | |
| 218 console.error(e); | |
| 219 }).then(() => waitForRequests()); | |
| 220 } | |
| 221 else | |
| 222 return Promise.resolve(); | |
| 223 } | |
| 224 | |
| 225 function runScheduledTasks(maxMillis) | |
| 226 { | |
| 227 let endTime = currentTime + maxMillis; | |
| 228 if (fakeTimer.nextExecution < 0 || fakeTimer.nextExecution > endTime) | |
| 229 { | |
| 230 currentTime = endTime; | |
| 231 return Promise.resolve(); | |
| 232 } | |
| 233 else | |
| 234 { | |
| 235 fakeTimer.trigger(); | |
| 236 return waitForRequests().then(() => runScheduledTasks(endTime - currentTim e)); | |
| 237 } | |
| 238 | |
| 239 currentTime = endTime; | |
| 240 } | |
| 241 | |
| 242 this.runScheduledTasks = (maxHours, initial, skip) => | |
| 243 { | |
| 244 if (typeof maxHours != "number") | |
| 245 throw new Error("Numerical parameter expected"); | |
| 246 if (typeof initial != "number") | |
| 247 initial = 0; | |
| 248 if (typeof skip != "number") | |
| 249 skip = 0; | |
| 250 | |
| 251 startTime = currentTime; | |
| 252 return Promise.resolve().then(() => | |
| 253 { | |
| 254 if (initial >= 0) | |
| 255 { | |
| 256 maxHours -= initial; | |
| 257 return runScheduledTasks(initial * MILLIS_IN_HOUR); | |
| 258 } | |
| 259 }).then(() => | |
| 260 { | |
| 261 if (skip >= 0) | |
| 262 { | |
| 263 maxHours -= skip; | |
| 264 currentTime += skip * MILLIS_IN_HOUR; | |
| 265 } | |
| 266 return runScheduledTasks(maxHours * MILLIS_IN_HOUR); | |
| 267 }); | |
| 268 }; | |
| 269 | |
| 270 this.getTimeOffset = () => (currentTime - startTime) / MILLIS_IN_HOUR; | |
| 271 Object.defineProperty(this, "currentTime", { | |
| 272 get: () => currentTime | |
| 273 }); | |
| 274 | |
| 5 let randomResult = 0.5; | 275 let randomResult = 0.5; |
| 6 | 276 Object.defineProperty(this, "randomResult", { |
| 7 module("Synchronizer", { | 277 get: () => randomResult, |
| 8 setup: function() | 278 set: value => randomResult = value |
| 9 { | 279 }); |
| 10 testRunner = this; | 280 |
| 11 | 281 let sandboxedRequire = createSandbox({ |
| 12 prepareFilterComponents.call(this); | 282 globals: { |
| 13 preparePrefs.call(this); | 283 Cc: { |
| 14 | 284 "@mozilla.org/timer;1": { |
| 15 Synchronizer.init(); | 285 createInstance: () => fakeTimer |
| 16 | 286 } |
| 17 setupVirtualTime.call(this, function(wrapTimer) | 287 }, |
| 18 { | 288 Ci: { |
| 19 let SynchronizerModule = getModuleGlobal("synchronizer"); | 289 nsITimer: |
| 20 SynchronizerModule.downloader._timer = wrapTimer(SynchronizerModule.down loader._timer); | 290 { |
| 21 }, "synchronizer", "downloader"); | 291 TYPE_ONE_SHOT: 0, |
| 22 setupVirtualXMLHttp.call(this, "synchronizer", "downloader"); | 292 TYPE_REPEATING_SLACK: 1, |
| 23 | 293 TYPE_REPEATING_PRECISE: 2 |
| 24 // Replace Math.random() function | 294 }, |
| 25 let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader") ); | 295 nsIHttpChannel: () => null, |
| 26 this._origRandom = DownloaderGlobal.Math.random; | 296 }, |
| 27 DownloaderGlobal.Math.random = () => randomResult; | 297 Cr: Cr, |
| 28 randomResult = 0.5; | 298 XMLHttpRequest: XMLHttpRequest, |
| 29 }, | 299 Date: { |
| 30 | 300 now: () => currentTime |
| 31 teardown: function() | 301 }, |
| 32 { | 302 Math: { |
| 33 restoreFilterComponents.call(this); | 303 random: () => randomResult, |
| 34 restorePrefs.call(this); | 304 min: Math.min, |
| 35 restoreVirtualTime.call(this); | 305 max: Math.max, |
| 36 restoreVirtualXMLHttp.call(this); | 306 round: Math.round |
| 37 | 307 }, |
| 38 if (this._origRandom) | 308 URL: function(urlString) |
| 39 { | 309 { |
| 40 let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader ")); | 310 return require("url").parse(urlString); |
| 41 DownloaderGlobal.Math.random = this._origRandom; | |
| 42 delete this._origRandom; | |
| 43 } | 311 } |
| 44 | |
| 45 Synchronizer.init(); | |
| 46 } | 312 } |
| 47 }); | 313 }); |
| 48 | 314 |
| 49 function resetSubscription(subscription) | 315 ( |
| 50 { | 316 {Filter} = sandboxedRequire("../lib/filterClasses"), |
| 51 FilterStorage.updateSubscriptionFilters(subscription, []); | 317 {FilterStorage} = sandboxedRequire("../lib/filterStorage"), |
| 52 subscription.lastCheck = subscription.lastDownload = | 318 {Prefs} = sandboxedRequire("./stub-modules/prefs"), |
| 53 subscription.version = subscription.lastSuccess = | 319 {Subscription} = sandboxedRequire("../lib/subscriptionClasses"), |
| 54 subscription.expires = subscription.softExpiration = 0; | 320 {Synchronizer} = sandboxedRequire("../lib/synchronizer") |
| 55 subscription.title = ""; | 321 ); |
| 56 subscription.homepage = null; | 322 |
| 57 subscription.errors = 0; | 323 callback(); |
| 58 subscription.downloadStatus = null; | 324 }; |
| 59 subscription.requiredVersion = null; | 325 |
| 60 } | 326 function unexpectedError(error) |
| 61 | 327 { |
| 62 let initialDelay = 1 / 60; | 328 console.error(error); |
| 63 | 329 this.ok(false, "Unexpected error: " + error); |
| 64 test("Downloads of one subscription", function() | 330 } |
| 65 { | 331 |
| 66 let subscription = Subscription.fromURL("http://example.com/subscription"); | 332 function resetSubscription(subscription) |
| 67 FilterStorage.addSubscription(subscription); | 333 { |
| 68 | 334 FilterStorage.updateSubscriptionFilters(subscription, []); |
| 69 let requests = []; | 335 subscription.lastCheck = subscription.lastDownload = |
| 70 testRunner.registerHandler("/subscription", function(metadata) | 336 subscription.version = subscription.lastSuccess = |
| 71 { | 337 subscription.expires = subscription.softExpiration = 0; |
| 72 requests.push([testRunner.getTimeOffset(), metadata.method, metadata.path] ); | 338 subscription.title = ""; |
| 73 return [Cr.NS_OK, 200, "[Adblock]\n! ExPiREs: 1day\nfoo\nbar"]; | 339 subscription.homepage = null; |
| 74 }); | 340 subscription.errors = 0; |
| 75 | 341 subscription.downloadStatus = null; |
| 76 testRunner.runScheduledTasks(50); | 342 subscription.requiredVersion = null; |
| 77 deepEqual(requests, [ | 343 } |
| 344 | |
| 345 let initialDelay = 1 / 60; | |
| 346 | |
| 347 exports.testOneSubscriptionDownloads = function(test) | |
| 348 { | |
| 349 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 350 FilterStorage.addSubscription(subscription); | |
| 351 | |
| 352 let requests = []; | |
| 353 this.registerHandler("/subscription", metadata => | |
|
kzar
2016/10/05 11:36:51
I guess we could avoid declaring all the module va
Wladimir Palant
2016/10/05 12:12:51
Not during the initial migration - the fewer chang
| |
| 354 { | |
| 355 requests.push([this.getTimeOffset(), metadata.method, metadata.path]); | |
| 356 return [Cr.NS_OK, 200, "[Adblock]\n! ExPiREs: 1day\nfoo\nbar"]; | |
| 357 }); | |
| 358 | |
| 359 this.runScheduledTasks(50).then(() => | |
| 360 { | |
| 361 test.deepEqual(requests, [ | |
| 78 [0 + initialDelay, "GET", "/subscription"], | 362 [0 + initialDelay, "GET", "/subscription"], |
| 79 [24 + initialDelay, "GET", "/subscription"], | 363 [24 + initialDelay, "GET", "/subscription"], |
| 80 [48 + initialDelay, "GET", "/subscription"], | 364 [48 + initialDelay, "GET", "/subscription"], |
| 81 ], "Requests after 50 hours"); | 365 ], "Requests after 50 hours"); |
| 82 }); | 366 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 83 | 367 }; |
| 84 test("Downloads of two subscriptions", function() | 368 |
| 85 { | 369 exports.testTwoSubscriptionsDownloads = function(test) |
| 86 let subscription1 = Subscription.fromURL("http://example.com/subscription1") ; | 370 { |
| 87 FilterStorage.addSubscription(subscription1); | 371 let subscription1 = Subscription.fromURL("http://example.com/subscription1"); |
| 88 | 372 FilterStorage.addSubscription(subscription1); |
| 89 let subscription2 = Subscription.fromURL("http://example.com/subscription2") ; | 373 |
| 90 subscription2.expires = | 374 let subscription2 = Subscription.fromURL("http://example.com/subscription2"); |
| 91 subscription2.softExpiration = | 375 subscription2.expires = |
| 92 (testRunner.currentTime + 2 * MILLIS_IN_HOUR) / MILLIS_IN_SECOND; | 376 subscription2.softExpiration = |
| 93 FilterStorage.addSubscription(subscription2); | 377 (this.currentTime + 2 * MILLIS_IN_HOUR) / MILLIS_IN_SECOND; |
| 94 | 378 FilterStorage.addSubscription(subscription2); |
| 95 let requests = []; | 379 |
| 96 function handler(metadata) | 380 let requests = []; |
| 97 { | 381 let handler = metadata => |
| 98 requests.push([testRunner.getTimeOffset(), metadata.method, metadata.path] ); | 382 { |
| 99 return [Cr.NS_OK, 200, "[Adblock]\n! ExPiREs: 1day\nfoo\nbar"]; | 383 requests.push([this.getTimeOffset(), metadata.method, metadata.path]); |
| 100 } | 384 return [Cr.NS_OK, 200, "[Adblock]\n! ExPiREs: 1day\nfoo\nbar"]; |
| 101 | 385 }; |
| 102 testRunner.registerHandler("/subscription1", handler); | 386 |
| 103 testRunner.registerHandler("/subscription2", handler); | 387 this.registerHandler("/subscription1", handler); |
| 104 | 388 this.registerHandler("/subscription2", handler); |
| 105 testRunner.runScheduledTasks(55); | 389 |
| 106 deepEqual(requests, [ | 390 this.runScheduledTasks(55).then(() => |
| 391 { | |
| 392 test.deepEqual(requests, [ | |
| 107 [0 + initialDelay, "GET", "/subscription1"], | 393 [0 + initialDelay, "GET", "/subscription1"], |
| 108 [2 + initialDelay, "GET", "/subscription2"], | 394 [2 + initialDelay, "GET", "/subscription2"], |
| 109 [24 + initialDelay, "GET", "/subscription1"], | 395 [24 + initialDelay, "GET", "/subscription1"], |
| 110 [26 + initialDelay, "GET", "/subscription2"], | 396 [26 + initialDelay, "GET", "/subscription2"], |
| 111 [48 + initialDelay, "GET", "/subscription1"], | 397 [48 + initialDelay, "GET", "/subscription1"], |
| 112 [50 + initialDelay, "GET", "/subscription2"], | 398 [50 + initialDelay, "GET", "/subscription2"], |
| 113 ], "Requests after 55 hours"); | 399 ], "Requests after 55 hours"); |
| 114 }); | 400 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 115 | 401 }; |
| 116 test("Download result, various subscription headers", function() | 402 |
| 117 { | 403 exports.testSubscriptionHeaders = {}; |
| 118 let test; | 404 |
| 405 for (let currentTest of [ | |
| 406 {header: "[Adblock]", downloadStatus: "synchronize_ok", requiredVersion: null} , | |
| 407 {header: "[Adblock Plus]", downloadStatus: "synchronize_ok", requiredVersion: null}, | |
| 408 {header: "(something)[Adblock]", downloadStatus: "synchronize_ok", requiredVer sion: null}, | |
| 409 {header: "[Adblock Plus 0.0.1]", downloadStatus: "synchronize_ok", requiredVer sion: "0.0.1"}, | |
| 410 {header: "[Adblock Plus 99.9]", downloadStatus: "synchronize_ok", requiredVers ion: "99.9"}, | |
| 411 {header: "[Foo]", downloadStatus: "synchronize_invalid_data", requiredVersion: null} | |
| 412 ]) | |
| 413 { | |
| 414 exports.testSubscriptionHeaders[currentTest.header] = function(test) | |
| 415 { | |
| 119 let subscription = Subscription.fromURL("http://example.com/subscription"); | 416 let subscription = Subscription.fromURL("http://example.com/subscription"); |
| 120 FilterStorage.addSubscription(subscription); | 417 FilterStorage.addSubscription(subscription); |
| 121 | 418 |
| 122 testRunner.registerHandler("/subscription", function(metadata) | 419 this.registerHandler("/subscription", metadata => |
| 123 { | 420 { |
| 124 return [Cr.NS_OK, 200, test.header + "\n!Expires: 8 hours\nfoo\n!bar\n\n@@ bas\n#bam"]; | 421 return [Cr.NS_OK, 200, currentTest.header + "\n!Expires: 8 hours\nfoo\n!ba r\n\n@@bas\n#bam"]; |
| 125 }); | 422 }); |
| 126 | 423 |
| 127 let tests = [ | 424 this.runScheduledTasks(2).then(() => |
| 128 {header: "[Adblock]", downloadStatus: "synchronize_ok", requiredVersion: n ull}, | 425 { |
| 129 {header: "[Adblock Plus]", downloadStatus: "synchronize_ok", requiredVersi on: null}, | 426 test.equal(subscription.downloadStatus, currentTest.downloadStatus, "Downl oad status"); |
| 130 {header: "(something)[Adblock]", downloadStatus: "synchronize_ok", require dVersion: null}, | 427 test.equal(subscription.requiredVersion, currentTest.requiredVersion, "Req uired version"); |
| 131 {header: "[Adblock Plus 0.0.1]", downloadStatus: "synchronize_ok", require dVersion: "0.0.1"}, | 428 |
| 132 {header: "[Adblock Plus 99.9]", downloadStatus: "synchronize_ok", required Version: "99.9"}, | 429 if (currentTest.downloadStatus == "synchronize_ok") |
| 133 {header: "[Foo]", downloadStatus: "synchronize_invalid_data", requiredVers ion: null} | 430 { |
| 134 ]; | 431 test.deepEqual(subscription.filters, [ |
| 135 for (test of tests) | |
| 136 { | |
| 137 resetSubscription(subscription) | |
| 138 testRunner.runScheduledTasks(2); | |
| 139 | |
| 140 equal(subscription.downloadStatus, test.downloadStatus, "Download status f or " + test.header) | |
| 141 equal(subscription.requiredVersion, test.requiredVersion, "Required versio n for " + test.header) | |
| 142 | |
| 143 if (test.downloadStatus == "synchronize_ok") | |
| 144 { | |
| 145 deepEqual(subscription.filters, [ | |
| 146 Filter.fromText("foo"), | 432 Filter.fromText("foo"), |
| 147 Filter.fromText("!bar"), | 433 Filter.fromText("!bar"), |
| 148 Filter.fromText("@@bas"), | 434 Filter.fromText("@@bas"), |
| 149 Filter.fromText("#bam"), | 435 Filter.fromText("#bam"), |
| 150 ], "Resulting subscription filters for " + test.header); | 436 ], "Resulting subscription filters"); |
| 151 } | 437 } |
| 152 else | 438 else |
| 153 { | 439 { |
| 154 deepEqual(subscription.filters, [ | 440 test.deepEqual(subscription.filters, [ |
| 155 ], "Resulting subscription filters for " + test.header); | 441 ], "Resulting subscription filters"); |
| 156 } | 442 } |
| 157 } | 443 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 158 }) | 444 }; |
| 159 | 445 } |
| 160 test("Automatic updates disabled", function() | 446 |
| 161 { | 447 exports.testsDisabledUpdates = function(test) |
| 162 Prefs.subscriptions_autoupdate = false; | 448 { |
| 163 | 449 Prefs.subscriptions_autoupdate = false; |
| 450 | |
| 451 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 452 FilterStorage.addSubscription(subscription); | |
| 453 | |
| 454 let requests = 0; | |
| 455 this.registerHandler("/subscription", metadata => | |
| 456 { | |
| 457 requests++; | |
| 458 throw new Error("Unexpected request"); | |
| 459 }); | |
| 460 | |
| 461 this.runScheduledTasks(50).then(() => | |
| 462 { | |
| 463 test.equal(requests, 0, "Request count"); | |
| 464 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 465 }; | |
| 466 | |
| 467 exports.testExpirationTime = {}; | |
| 468 | |
| 469 for (let currentTest of [ | |
| 470 { | |
| 471 expiration: "default", | |
| 472 randomResult: 0.5, | |
| 473 requests: [0 + initialDelay, 5 * 24 + initialDelay] | |
| 474 }, | |
| 475 { | |
| 476 expiration: "1 hours", // Minimal expiration interval | |
| 477 randomResult: 0.5, | |
| 478 requests: [0 + initialDelay, 1 + initialDelay, 2 + initialDelay, 3 + initial Delay] | |
| 479 }, | |
| 480 { | |
| 481 expiration: "26 hours", | |
| 482 randomResult: 0.5, | |
| 483 requests: [0 + initialDelay, 26 + initialDelay] | |
| 484 }, | |
| 485 { | |
| 486 expiration: "2 days", | |
| 487 randomResult: 0.5, | |
| 488 requests: [0 + initialDelay, 48 + initialDelay] | |
| 489 }, | |
| 490 { | |
| 491 expiration: "20 days", // Too large, will be corrected | |
| 492 randomResult: 0.5, | |
| 493 requests: [0 + initialDelay, 14 * 24 + initialDelay] | |
| 494 }, | |
| 495 { | |
| 496 expiration: "35 hours", | |
| 497 randomResult: 0, // Changes interval by factor 0.8 | |
| 498 requests: [0 + initialDelay, 28 + initialDelay] | |
| 499 }, | |
| 500 { | |
| 501 expiration: "35 hours", | |
| 502 randomResult: 1, // Changes interval by factor 1.2 | |
| 503 requests: [0 + initialDelay, 42 + initialDelay] | |
| 504 }, | |
| 505 { | |
| 506 expiration: "35 hours", | |
| 507 randomResult: 0.25, // Changes interval by factor 0.9 | |
| 508 requests: [0 + initialDelay, 32 + initialDelay] | |
| 509 }, | |
| 510 { | |
| 511 expiration: "40 hours", | |
| 512 randomResult: 0.5, | |
| 513 skipAfter: 5 + initialDelay, | |
| 514 skip: 10, // Short break should not increase soft expiration | |
| 515 requests: [0 + initialDelay, 40 + initialDelay] | |
| 516 }, | |
| 517 { | |
| 518 expiration: "40 hours", | |
| 519 randomResult: 0.5, | |
| 520 skipAfter: 5 + initialDelay, | |
| 521 skip: 30, // Long break should increase soft expiration | |
| 522 requests: [0 + initialDelay, 70 + initialDelay] | |
| 523 }, | |
| 524 { | |
| 525 expiration: "40 hours", | |
| 526 randomResult: 0.5, | |
| 527 skipAfter: 5 + initialDelay, | |
| 528 skip: 80, // Hitting hard expiration, immediate download | |
| 529 requests: [0 + initialDelay, 85 + initialDelay] | |
| 530 } | |
| 531 ]) | |
| 532 { | |
| 533 let testId = `"${currentTest.expiration}"`; | |
| 534 if (currentTest.randomResult != 0.5) | |
| 535 testId += " with Math.random() returning " + currentTest.randomResult; | |
| 536 if (currentTest.skip) | |
| 537 testId += " skipping " + currentTest.skip + " hours after " + currentTest.sk ipAfter + " hours"; | |
| 538 exports.testExpirationTime[testId] = function(test) | |
| 539 { | |
| 164 let subscription = Subscription.fromURL("http://example.com/subscription"); | 540 let subscription = Subscription.fromURL("http://example.com/subscription"); |
| 165 FilterStorage.addSubscription(subscription); | 541 FilterStorage.addSubscription(subscription); |
| 166 | 542 |
| 167 let requests = 0; | 543 let requests = []; |
| 168 testRunner.registerHandler("/subscription", function(metadata) | 544 this.registerHandler("/subscription", metadata => |
| 169 { | 545 { |
| 170 requests++; | 546 requests.push(this.getTimeOffset()); |
| 171 throw new Error("Unexpected request"); | 547 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Expires: " + currentTest.expirati on + "\nbar"]; |
| 172 }); | 548 }); |
| 173 | 549 |
| 174 testRunner.runScheduledTasks(50); | 550 this.randomResult = currentTest.randomResult; |
| 175 equal(requests, 0, "Request count"); | 551 |
| 176 }); | 552 let maxHours = Math.round(Math.max.apply(null, currentTest.requests)) + 1; |
| 177 | 553 this.runScheduledTasks(maxHours, currentTest.skipAfter, currentTest.skip).th en(() => |
| 178 test("Expiration time", function() | 554 { |
| 555 test.deepEqual(requests, currentTest.requests, "Requests"); | |
| 556 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 557 }; | |
| 558 } | |
| 559 | |
| 560 exports.testChecksumVerification = {}; | |
| 561 | |
| 562 for (let [testName, subscriptionBody, expectedResult] of [ | |
| 563 ["Correct checksum", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHsq/A\nfoo\nbar\ n", true], | |
| 564 ["Wrong checksum", "[Adblock]\n! Checksum: wrongggny6Fn24b7JHsq/A\nfoo\nbar\n" , false], | |
| 565 ["Empty lines ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHsq/A\n\nfoo\ n\nbar\n\n", true], | |
| 566 ["CR LF line breaks treated like LR", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7 JHsq/A\nfoo\r\nbar\r\n", true], | |
| 567 ["CR line breaks treated like LR", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHs q/A\nfoo\rbar\r", true], | |
| 568 ["Trailing line break not ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JH sq/A\nfoo\nbar", false], | |
| 569 ["Line breaks between lines not ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn 24b7JHsq/A\nfoobar", false], | |
| 570 ["Lines with spaces not ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHsq /A\n \nfoo\n\nbar\n", false], | |
| 571 ["Extra content in checksum line is part of the checksum", "[Adblock]\n! Check sum: e/JCmqXny6Fn24b7JHsq/A foobar\nfoo\nbar\n", false], | |
| 572 ["= symbols after checksum are ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn2 4b7JHsq/A===\nfoo\nbar\n", true], | |
| 573 ["Header line is part of the checksum", "[Adblock Plus]\n! Checksum: e/JCmqXny 6Fn24b7JHsq/A\nfoo\nbar\n", false], | |
| 574 ["Special comments are part of the checksum", "[Adblock]\n! Checksum: e/JCmqXn y6Fn24b7JHsq/A\n! Expires: 1\nfoo\nbar\n", false], | |
| 575 ]) | |
| 576 { | |
| 577 exports.testChecksumVerification[testName] = function(test) | |
| 179 { | 578 { |
| 180 let subscription = Subscription.fromURL("http://example.com/subscription"); | 579 let subscription = Subscription.fromURL("http://example.com/subscription"); |
| 181 FilterStorage.addSubscription(subscription); | 580 FilterStorage.addSubscription(subscription); |
| 182 | 581 |
| 183 let test; | 582 this.registerHandler("/subscription", metadata => |
| 184 let requests = []; | 583 { |
| 185 testRunner.registerHandler("/subscription", function(metadata) | 584 return [Cr.NS_OK, 200, subscriptionBody]; |
| 186 { | 585 }); |
| 187 requests.push(testRunner.getTimeOffset()); | 586 |
| 188 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Expires: " + test.expiration + "\ nbar"]; | 587 this.runScheduledTasks(2).then(() => |
| 189 }); | 588 { |
| 190 | 589 test.equal(subscription.downloadStatus, expectedResult ? "synchronize_ok" : "synchronize_checksum_mismatch"); |
| 191 let tests = [ | 590 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 192 { | 591 }; |
| 193 expiration: "default", | 592 } |
| 194 randomResult: 0.5, | 593 |
| 195 requests: [0 + initialDelay, 5 * 24 + initialDelay] | 594 exports.testSpecialComments = {}; |
| 196 }, | 595 |
| 197 { | 596 for (let [comment, check] of [ |
| 198 expiration: "1 hours", // Minimal expiration interval | 597 ["! Homepage: http://example.com/", (test, subscription) => |
| 199 randomResult: 0.5, | 598 { |
| 200 requests: [0 + initialDelay, 1 + initialDelay, 2 + initialDelay, 3 + ini tialDelay] | 599 test.equal(subscription.homepage, "http://example.com/", "Valid homepage com ment"); |
| 201 }, | 600 }], |
| 202 { | 601 ["! Homepage: ssh://example.com/", (test, subscription) => |
| 203 expiration: "26 hours", | 602 { |
| 204 randomResult: 0.5, | 603 test.equal(subscription.homepage, null, "Invalid homepage comment"); |
| 205 requests: [0 + initialDelay, 26 + initialDelay] | 604 }], |
| 206 }, | 605 ["! Title: foo", (test, subscription) => |
| 207 { | 606 { |
| 208 expiration: "2 days", | 607 test.equal(subscription.title, "foo", "Title comment"); |
| 209 randomResult: 0.5, | 608 test.equal(subscription.fixedTitle, true, "Fixed title"); |
| 210 requests: [0 + initialDelay, 48 + initialDelay] | 609 }], |
| 211 }, | 610 ["! Version: 1234", (test, subscription) => |
| 212 { | 611 { |
| 213 expiration: "20 days", // Too large, will be corrected | 612 test.equal(subscription.version, 1234, "Version comment"); |
| 214 randomResult: 0.5, | 613 }] |
| 215 requests: [0 + initialDelay, 14 * 24 + initialDelay] | 614 ]) |
| 216 }, | 615 { |
| 217 { | 616 exports.testSpecialComments[comment] = function(test) |
| 218 expiration: "35 hours", | |
| 219 randomResult: 0, // Changes interval by factor 0.8 | |
| 220 requests: [0 + initialDelay, 28 + initialDelay] | |
| 221 }, | |
| 222 { | |
| 223 expiration: "35 hours", | |
| 224 randomResult: 1, // Changes interval by factor 1.2 | |
| 225 requests: [0 + initialDelay, 42 + initialDelay] | |
| 226 }, | |
| 227 { | |
| 228 expiration: "35 hours", | |
| 229 randomResult: 0.25, // Changes interval by factor 0.9 | |
| 230 requests: [0 + initialDelay, 32 + initialDelay] | |
| 231 }, | |
| 232 { | |
| 233 expiration: "40 hours", | |
| 234 randomResult: 0.5, | |
| 235 skipAfter: 5 + initialDelay, | |
| 236 skip: 10, // Short break should not increase soft expirati on | |
| 237 requests: [0 + initialDelay, 40 + initialDelay] | |
| 238 }, | |
| 239 { | |
| 240 expiration: "40 hours", | |
| 241 randomResult: 0.5, | |
| 242 skipAfter: 5 + initialDelay, | |
| 243 skip: 30, // Long break should increase soft expiration | |
| 244 requests: [0 + initialDelay, 70 + initialDelay] | |
| 245 }, | |
| 246 { | |
| 247 expiration: "40 hours", | |
| 248 randomResult: 0.5, | |
| 249 skipAfter: 5 + initialDelay, | |
| 250 skip: 80, // Hitting hard expiration, immediate download | |
| 251 requests: [0 + initialDelay, 85 + initialDelay] | |
| 252 } | |
| 253 ] | |
| 254 | |
| 255 for (test of tests) | |
| 256 { | |
| 257 requests = []; | |
| 258 randomResult = test.randomResult; | |
| 259 resetSubscription(subscription); | |
| 260 | |
| 261 let maxHours = Math.round(Math.max.apply(null, test.requests)) + 1; | |
| 262 testRunner.runScheduledTasks(maxHours, test.skipAfter, test.skip); | |
| 263 | |
| 264 let randomAddendum = (randomResult == 0.5 ? "" : " with Math.random() retu rning " + randomResult); | |
| 265 let skipAddendum = (typeof test.skip != "number" ? "" : " skipping " + tes t.skip + " hours after " + test.skipAfter + " hours"); | |
| 266 deepEqual(requests, test.requests, "Requests for \"" + test.expiration + " \"" + randomAddendum + skipAddendum); | |
| 267 } | |
| 268 }); | |
| 269 | |
| 270 test("Checksum verification", function() | |
| 271 { | 617 { |
| 272 let subscription = Subscription.fromURL("http://example.com/subscription"); | 618 let subscription = Subscription.fromURL("http://example.com/subscription"); |
| 273 FilterStorage.addSubscription(subscription); | 619 FilterStorage.addSubscription(subscription); |
| 274 | 620 |
| 275 let testName, subscriptionBody, expectedResult; | 621 this.registerHandler("/subscription", metadata => |
| 276 let tests = [ | 622 { |
| 277 ["Correct checksum", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHsq/A\nfoo\n bar\n", true], | 623 return [Cr.NS_OK, 200, "[Adblock]\n" + comment + "\nfoo\nbar"]; |
| 278 ["Wrong checksum", "[Adblock]\n! Checksum: wrongggny6Fn24b7JHsq/A\nfoo\nba r\n", false], | 624 }); |
| 279 ["Empty lines ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7JHsq/A\n\n foo\n\nbar\n\n", true], | 625 |
| 280 ["CR LF line breaks treated like LR", "[Adblock]\n! Checksum: e/JCmqXny6Fn 24b7JHsq/A\nfoo\r\nbar\r\n", true], | 626 this.runScheduledTasks(2).then(() => |
| 281 ["CR line breaks treated like LR", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b 7JHsq/A\nfoo\rbar\r", true], | 627 { |
| 282 ["Trailing line break not ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24 b7JHsq/A\nfoo\nbar", false], | 628 check(test, subscription); |
| 283 ["Line breaks between lines not ignored", "[Adblock]\n! Checksum: e/JCmqXn y6Fn24b7JHsq/A\nfoobar", false], | 629 test.deepEqual(subscription.filters, [Filter.fromText("foo"), Filter.fromT ext("bar")], "Special comment not added to filters"); |
| 284 ["Lines with spaces not ignored", "[Adblock]\n! Checksum: e/JCmqXny6Fn24b7 JHsq/A\n \nfoo\n\nbar\n", false], | 630 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 285 ["Extra content in checksum line is part of the checksum", "[Adblock]\n! C hecksum: e/JCmqXny6Fn24b7JHsq/A foobar\nfoo\nbar\n", false], | 631 }; |
| 286 ["= symbols after checksum are ignored", "[Adblock]\n! Checksum: e/JCmqXny 6Fn24b7JHsq/A===\nfoo\nbar\n", true], | 632 } |
| 287 ["Header line is part of the checksum", "[Adblock Plus]\n! Checksum: e/JCm qXny6Fn24b7JHsq/A\nfoo\nbar\n", false], | 633 |
| 288 ["Special comments are part of the checksum", "[Adblock]\n! Checksum: e/JC mqXny6Fn24b7JHsq/A\n! Expires: 1\nfoo\nbar\n", false], | 634 exports.testRedirects = function(test) |
| 289 ]; | 635 { |
| 290 | 636 let subscription = Subscription.fromURL("http://example.com/subscription"); |
| 291 testRunner.registerHandler("/subscription", function(metadata) | 637 FilterStorage.addSubscription(subscription); |
| 292 { | 638 |
| 293 return [Cr.NS_OK, 200, subscriptionBody]; | 639 this.registerHandler("/subscription", metadata => |
| 294 }); | 640 { |
| 295 | 641 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Redirect: http://example.com/redire cted\nbar"]; |
| 296 for ([testName, subscriptionBody, expectedResult] of tests) | |
| 297 { | |
| 298 resetSubscription(subscription); | |
| 299 testRunner.runScheduledTasks(2); | |
| 300 equal(subscription.downloadStatus, expectedResult ? "synchronize_ok" : "sy nchronize_checksum_mismatch", testName); | |
| 301 } | |
| 302 }); | 642 }); |
| 303 | 643 |
| 304 test("Special comments", function() | 644 let requests; |
| 305 { | 645 |
| 306 let subscription = Subscription.fromURL("http://example.com/subscription"); | 646 this.runScheduledTasks(30).then(() => |
| 307 FilterStorage.addSubscription(subscription); | 647 { |
| 308 | 648 test.equal(FilterStorage.subscriptions[0], subscription, "Invalid redirect i gnored"); |
| 309 let comment, check; | 649 test.equal(subscription.downloadStatus, "synchronize_connection_error", "Con nection error recorded"); |
| 310 let tests = [ | 650 test.equal(subscription.errors, 2, "Number of download errors"); |
| 311 ["! Homepage: http://example.com/", () => equal(subscription.homepage, "ht tp://example.com/", "Valid homepage comment")], | 651 |
| 312 ["! Homepage: ssh://example.com/", () => equal(subscription.homepage, null , "Invalid homepage comment")], | 652 requests = []; |
| 313 ["! Title: foo", function() | 653 |
| 314 { | 654 this.registerHandler("/redirected", metadata => |
| 315 equal(subscription.title, "foo", "Title comment"); | 655 { |
| 316 equal(subscription.fixedTitle, true, "Fixed title"); | 656 requests.push(this.getTimeOffset()); |
| 317 }], | |
| 318 ["! Version: 1234", () => equal(subscription.version, 1234, "Version comme nt")] | |
| 319 ]; | |
| 320 | |
| 321 testRunner.registerHandler("/subscription", function(metadata) | |
| 322 { | |
| 323 return [Cr.NS_OK, 200, "[Adblock]\n" + comment + "\nfoo\nbar"]; | |
| 324 }); | |
| 325 | |
| 326 for ([comment, check] of tests) | |
| 327 { | |
| 328 resetSubscription(subscription); | |
| 329 testRunner.runScheduledTasks(2); | |
| 330 check(); | |
| 331 deepEqual(subscription.filters, [Filter.fromText("foo"), Filter.fromText(" bar")], "Special comment not added to filters"); | |
| 332 } | |
| 333 }); | |
| 334 | |
| 335 test("Redirects", function() | |
| 336 { | |
| 337 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 338 FilterStorage.addSubscription(subscription); | |
| 339 | |
| 340 testRunner.registerHandler("/subscription", function(metadata) | |
| 341 { | |
| 342 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Redirect: http://example.com/redi rected\nbar"]; | |
| 343 }); | |
| 344 | |
| 345 testRunner.runScheduledTasks(30); | |
| 346 equal(FilterStorage.subscriptions[0], subscription, "Invalid redirect ignore d"); | |
| 347 equal(subscription.downloadStatus, "synchronize_connection_error", "Connecti on error recorded"); | |
| 348 equal(subscription.errors, 2, "Number of download errors"); | |
| 349 | |
| 350 let requests = []; | |
| 351 testRunner.registerHandler("/redirected", function(metadata) | |
| 352 { | |
| 353 requests.push(testRunner.getTimeOffset()); | |
| 354 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n! Expires: 8 hours\nbar"]; | 657 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n! Expires: 8 hours\nbar"]; |
| 355 }); | 658 }); |
| 356 | 659 |
| 357 resetSubscription(subscription); | 660 resetSubscription(subscription); |
| 358 testRunner.runScheduledTasks(15); | 661 return this.runScheduledTasks(15); |
| 359 equal(FilterStorage.subscriptions[0].url, "http://example.com/redirected", " Redirect followed"); | 662 }).then(() => |
| 360 deepEqual(requests, [0 + initialDelay, 8 + initialDelay], "Resulting request s"); | 663 { |
| 361 | 664 test.equal(FilterStorage.subscriptions[0].url, "http://example.com/redirecte d", "Redirect followed"); |
| 362 testRunner.registerHandler("/redirected", function(metadata) | 665 test.deepEqual(requests, [0 + initialDelay, 8 + initialDelay], "Resulting re quests"); |
| 666 | |
| 667 this.registerHandler("/redirected", metadata => | |
| 363 { | 668 { |
| 364 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Redirect: http://example.com/subs cription\nbar"]; | 669 return [Cr.NS_OK, 200, "[Adblock]\nfoo\n!Redirect: http://example.com/subs cription\nbar"]; |
| 365 }) | 670 }) |
| 366 | 671 |
| 367 subscription = Subscription.fromURL("http://example.com/subscription"); | 672 subscription = Subscription.fromURL("http://example.com/subscription"); |
| 368 resetSubscription(subscription); | 673 resetSubscription(subscription); |
| 369 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); | 674 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); |
| 370 FilterStorage.addSubscription(subscription); | 675 FilterStorage.addSubscription(subscription); |
| 371 | 676 |
| 372 testRunner.runScheduledTasks(2); | 677 return this.runScheduledTasks(2); |
| 373 equal(FilterStorage.subscriptions[0], subscription, "Redirect not followed o n redirect loop"); | 678 }).then(() => |
| 374 equal(subscription.downloadStatus, "synchronize_connection_error", "Download status after redirect loop"); | 679 { |
| 680 test.equal(FilterStorage.subscriptions[0], subscription, "Redirect not follo wed on redirect loop"); | |
| 681 test.equal(subscription.downloadStatus, "synchronize_connection_error", "Dow nload status after redirect loop"); | |
| 682 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 683 }; | |
| 684 | |
| 685 exports.testFallback = function(test) | |
| 686 { | |
| 687 Prefs.subscriptions_fallbackerrors = 3; | |
| 688 Prefs.subscriptions_fallbackurl = "http://example.com/fallback?%SUBSCRIPTION%& %CHANNELSTATUS%&%RESPONSESTATUS%"; | |
| 689 | |
| 690 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 691 FilterStorage.addSubscription(subscription); | |
| 692 | |
| 693 // No valid response from fallback | |
| 694 | |
| 695 let requests = []; | |
| 696 let fallbackParams; | |
| 697 let redirectedRequests; | |
| 698 this.registerHandler("/subscription", metadata => | |
| 699 { | |
| 700 requests.push(this.getTimeOffset()); | |
| 701 return [Cr.NS_OK, 404, ""]; | |
| 375 }); | 702 }); |
| 376 | 703 |
| 377 test("Fallback", function() | 704 this.runScheduledTasks(100).then(() => |
| 378 { | 705 { |
| 379 Prefs.subscriptions_fallbackerrors = 3; | 706 test.deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialD elay, 72 + initialDelay, 96 + initialDelay], "Continue trying if the fallback do esn't respond"); |
| 380 Prefs.subscriptions_fallbackurl = "http://example.com/fallback?%SUBSCRIPTION %&%CHANNELSTATUS%&%RESPONSESTATUS%"; | |
| 381 | |
| 382 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 383 FilterStorage.addSubscription(subscription); | |
| 384 | |
| 385 // No valid response from fallback | |
| 386 | |
| 387 let requests = []; | |
| 388 testRunner.registerHandler("/subscription", function(metadata) | |
| 389 { | |
| 390 requests.push(testRunner.getTimeOffset()); | |
| 391 return [Cr.NS_OK, 404, ""]; | |
| 392 }); | |
| 393 | |
| 394 testRunner.runScheduledTasks(100); | |
| 395 deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialDelay, 72 + initialDelay, 96 + initialDelay], "Continue trying if the fallback doesn't respond"); | |
| 396 | 707 |
| 397 // Fallback giving "Gone" response | 708 // Fallback giving "Gone" response |
| 398 | 709 |
| 399 resetSubscription(subscription); | 710 resetSubscription(subscription); |
| 400 requests = []; | 711 requests = []; |
| 401 fallbackParams = null; | 712 fallbackParams = null; |
| 402 testRunner.registerHandler("/fallback", function(metadata) | 713 this.registerHandler("/fallback", metadata => |
| 403 { | 714 { |
| 404 fallbackParams = decodeURIComponent(metadata.queryString); | 715 fallbackParams = decodeURIComponent(metadata.queryString); |
| 405 return [Cr.NS_OK, 200, "410 Gone"]; | 716 return [Cr.NS_OK, 200, "410 Gone"]; |
| 406 }); | 717 }); |
| 407 | 718 |
| 408 testRunner.runScheduledTasks(100); | 719 return this.runScheduledTasks(100); |
| 409 deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialDelay] , "Stop trying if the fallback responds with Gone"); | 720 }).then(() => |
| 410 equal(fallbackParams, "http://example.com/subscription&0&404", "Fallback arg uments"); | 721 { |
| 722 test.deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialD elay], "Stop trying if the fallback responds with Gone"); | |
| 723 test.equal(fallbackParams, "http://example.com/subscription&0&404", "Fallbac k arguments"); | |
| 411 | 724 |
| 412 // Fallback redirecting to a missing file | 725 // Fallback redirecting to a missing file |
| 413 | 726 |
| 414 subscription = Subscription.fromURL("http://example.com/subscription"); | 727 subscription = Subscription.fromURL("http://example.com/subscription"); |
| 415 resetSubscription(subscription); | 728 resetSubscription(subscription); |
| 416 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); | 729 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); |
| 417 FilterStorage.addSubscription(subscription); | 730 FilterStorage.addSubscription(subscription); |
| 418 requests = []; | 731 requests = []; |
| 419 | 732 |
| 420 testRunner.registerHandler("/fallback", function(metadata) | 733 this.registerHandler("/fallback", metadata => |
| 421 { | 734 { |
| 422 return [Cr.NS_OK, 200, "301 http://example.com/redirected"]; | 735 return [Cr.NS_OK, 200, "301 http://example.com/redirected"]; |
| 423 }); | 736 }); |
| 424 testRunner.runScheduledTasks(100); | 737 return this.runScheduledTasks(100); |
| 425 equal(FilterStorage.subscriptions[0].url, "http://example.com/subscription", "Ignore invalid redirect from fallback"); | 738 }).then(() => |
| 426 deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialDelay, 72 + initialDelay, 96 + initialDelay], "Requests not affected by invalid redire ct"); | 739 { |
| 740 test.equal(FilterStorage.subscriptions[0].url, "http://example.com/subscript ion", "Ignore invalid redirect from fallback"); | |
| 741 test.deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialD elay, 72 + initialDelay, 96 + initialDelay], "Requests not affected by invalid r edirect"); | |
| 427 | 742 |
| 428 // Fallback redirecting to an existing file | 743 // Fallback redirecting to an existing file |
| 429 | 744 |
| 430 resetSubscription(subscription); | 745 resetSubscription(subscription); |
| 431 requests = []; | 746 requests = []; |
| 432 let redirectedRequests = []; | 747 redirectedRequests = []; |
| 433 testRunner.registerHandler("/redirected", function(metadata) | 748 this.registerHandler("/redirected", metadata => |
| 434 { | 749 { |
| 435 redirectedRequests.push(testRunner.getTimeOffset()); | 750 redirectedRequests.push(this.getTimeOffset()); |
| 436 return [Cr.NS_OK, 200, "[Adblock]\n!Expires: 1day\nfoo\nbar"]; | 751 return [Cr.NS_OK, 200, "[Adblock]\n!Expires: 1day\nfoo\nbar"]; |
| 437 }); | 752 }); |
| 438 | 753 |
| 439 testRunner.runScheduledTasks(100); | 754 return this.runScheduledTasks(100); |
| 440 equal(FilterStorage.subscriptions[0].url, "http://example.com/redirected", " Valid redirect from fallback is followed"); | 755 }).then(() => |
| 441 deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialDelay] , "Stop polling original URL after a valid redirect from fallback"); | 756 { |
| 442 deepEqual(redirectedRequests, [48 + initialDelay, 72 + initialDelay, 96 + in itialDelay], "Request new URL after a valid redirect from fallback"); | 757 test.equal(FilterStorage.subscriptions[0].url, "http://example.com/redirecte d", "Valid redirect from fallback is followed"); |
| 758 test.deepEqual(requests, [0 + initialDelay, 24 + initialDelay, 48 + initialD elay], "Stop polling original URL after a valid redirect from fallback"); | |
| 759 test.deepEqual(redirectedRequests, [48 + initialDelay, 72 + initialDelay, 96 + initialDelay], "Request new URL after a valid redirect from fallback"); | |
| 443 | 760 |
| 444 // Checksum mismatch | 761 // Checksum mismatch |
| 445 | 762 |
| 446 testRunner.registerHandler("/subscription", function(metadata) | 763 this.registerHandler("/subscription", metadata => |
| 447 { | 764 { |
| 448 return [Cr.NS_OK, 200, "[Adblock]\n! Checksum: wrong\nfoo\nbar"]; | 765 return [Cr.NS_OK, 200, "[Adblock]\n! Checksum: wrong\nfoo\nbar"]; |
| 449 }); | 766 }); |
| 450 | 767 |
| 451 subscription = Subscription.fromURL("http://example.com/subscription"); | 768 subscription = Subscription.fromURL("http://example.com/subscription"); |
| 452 resetSubscription(subscription); | 769 resetSubscription(subscription); |
| 453 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); | 770 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); |
| 454 FilterStorage.addSubscription(subscription); | 771 FilterStorage.addSubscription(subscription); |
| 455 | 772 |
| 456 testRunner.runScheduledTasks(100); | 773 return this.runScheduledTasks(100); |
| 457 equal(FilterStorage.subscriptions[0].url, "http://example.com/redirected", " Wrong checksum produces fallback request"); | 774 }).then(() => |
| 775 { | |
| 776 test.equal(FilterStorage.subscriptions[0].url, "http://example.com/redirecte d", "Wrong checksum produces fallback request"); | |
| 458 | 777 |
| 459 // Redirect loop | 778 // Redirect loop |
| 460 | 779 |
| 461 testRunner.registerHandler("/subscription", function(metadata) | 780 this.registerHandler("/subscription", metadata => |
| 462 { | 781 { |
| 463 return [Cr.NS_OK, 200, "[Adblock]\n! Redirect: http://example.com/subscrip tion2"]; | 782 return [Cr.NS_OK, 200, "[Adblock]\n! Redirect: http://example.com/subscrip tion2"]; |
| 464 }); | 783 }); |
| 465 testRunner.registerHandler("/subscription2", function(metadata, response) | 784 this.registerHandler("/subscription2", metadata => |
| 466 { | 785 { |
| 467 return [Cr.NS_OK, 200, "[Adblock]\n! Redirect: http://example.com/subscrip tion"]; | 786 return [Cr.NS_OK, 200, "[Adblock]\n! Redirect: http://example.com/subscrip tion"]; |
| 468 }); | 787 }); |
| 469 | 788 |
| 470 subscription = Subscription.fromURL("http://example.com/subscription"); | 789 subscription = Subscription.fromURL("http://example.com/subscription"); |
| 471 resetSubscription(subscription); | 790 resetSubscription(subscription); |
| 472 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); | 791 FilterStorage.removeSubscription(FilterStorage.subscriptions[0]); |
| 473 FilterStorage.addSubscription(subscription); | 792 FilterStorage.addSubscription(subscription); |
| 474 | 793 |
| 475 testRunner.runScheduledTasks(100); | 794 return this.runScheduledTasks(100); |
| 476 equal(FilterStorage.subscriptions[0].url, "http://example.com/redirected", " Fallback can still redirect even after a redirect loop"); | 795 }).then(() => |
| 796 { | |
| 797 test.equal(FilterStorage.subscriptions[0].url, "http://example.com/redirecte d", "Fallback can still redirect even after a redirect loop"); | |
| 798 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 799 }; | |
| 800 | |
| 801 exports.testStateFields = function(test) | |
| 802 { | |
| 803 let subscription = Subscription.fromURL("http://example.com/subscription"); | |
| 804 FilterStorage.addSubscription(subscription); | |
| 805 | |
| 806 this.registerHandler("/subscription", metadata => | |
| 807 { | |
| 808 return [Cr.NS_OK, 200, "[Adblock]\n! Expires: 2 hours\nfoo\nbar"]; | |
| 477 }); | 809 }); |
| 478 | 810 |
| 479 test("State fields", function() | 811 let startTime = this.currentTime; |
| 480 { | 812 this.runScheduledTasks(2).then(() => |
| 481 let subscription = Subscription.fromURL("http://example.com/subscription"); | 813 { |
| 482 FilterStorage.addSubscription(subscription); | 814 test.equal(subscription.downloadStatus, "synchronize_ok", "downloadStatus af ter successful download"); |
| 483 | 815 test.equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + initia lDelay * MILLIS_IN_HOUR, "lastDownload after successful download"); |
| 484 testRunner.registerHandler("/subscription", function(metadata) | 816 test.equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initial Delay * MILLIS_IN_HOUR, "lastSuccess after successful download"); |
| 485 { | 817 test.equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (1 + init ialDelay) * MILLIS_IN_HOUR, "lastCheck after successful download"); |
| 486 return [Cr.NS_OK, 200, "[Adblock]\n! Expires: 2 hours\nfoo\nbar"]; | 818 test.equal(subscription.errors, 0, "errors after successful download"); |
| 487 }); | 819 |
| 488 | 820 this.registerHandler("/subscription", metadata => |
| 489 let startTime = testRunner.currentTime; | |
| 490 testRunner.runScheduledTasks(2); | |
| 491 | |
| 492 equal(subscription.downloadStatus, "synchronize_ok", "downloadStatus after s uccessful download"); | |
| 493 equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + initialDela y * MILLIS_IN_HOUR, "lastDownload after successful download"); | |
| 494 equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initialDelay * MILLIS_IN_HOUR, "lastSuccess after successful download"); | |
| 495 equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (1 + initialDe lay) * MILLIS_IN_HOUR, "lastCheck after successful download"); | |
| 496 equal(subscription.errors, 0, "errors after successful download"); | |
| 497 | |
| 498 testRunner.registerHandler("/subscription", function(metadata) | |
| 499 { | 821 { |
| 500 return [Cr.NS_ERROR_FAILURE, 0, ""]; | 822 return [Cr.NS_ERROR_FAILURE, 0, ""]; |
| 501 }); | 823 }); |
| 502 | 824 |
| 503 testRunner.runScheduledTasks(2); | 825 return this.runScheduledTasks(2); |
| 504 | 826 }).then(() => |
| 505 equal(subscription.downloadStatus, "synchronize_connection_error", "download Status after connection error"); | 827 { |
| 506 equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + (2 + initia lDelay) * MILLIS_IN_HOUR, "lastDownload after connection error"); | 828 test.equal(subscription.downloadStatus, "synchronize_connection_error", "dow nloadStatus after connection error"); |
| 507 equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initialDelay * MILLIS_IN_HOUR, "lastSuccess after connection error"); | 829 test.equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + (2 + i nitialDelay) * MILLIS_IN_HOUR, "lastDownload after connection error"); |
| 508 equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (3 + initialDel ay) * MILLIS_IN_HOUR, "lastCheck after connection error"); | 830 test.equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initialD elay * MILLIS_IN_HOUR, "lastSuccess after connection error"); |
| 509 equal(subscription.errors, 1, "errors after connection error"); | 831 test.equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (3 + initi alDelay) * MILLIS_IN_HOUR, "lastCheck after connection error"); |
| 510 | 832 test.equal(subscription.errors, 1, "errors after connection error"); |
| 511 testRunner.registerHandler("/subscription", function(metadata) | 833 |
| 834 this.registerHandler("/subscription", metadata => | |
| 512 { | 835 { |
| 513 return [Cr.NS_OK, 404, ""]; | 836 return [Cr.NS_OK, 404, ""]; |
| 514 }); | 837 }); |
| 515 | 838 |
| 516 testRunner.runScheduledTasks(24); | 839 return this.runScheduledTasks(24); |
| 517 | 840 }).then(() => |
| 518 equal(subscription.downloadStatus, "synchronize_connection_error", "download Status after download error"); | 841 { |
| 519 equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + (26 + initia lDelay) * MILLIS_IN_HOUR, "lastDownload after download error"); | 842 test.equal(subscription.downloadStatus, "synchronize_connection_error", "dow nloadStatus after download error"); |
| 520 equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initialDelay * MILLIS_IN_HOUR, "lastSuccess after download error"); | 843 test.equal(subscription.lastDownload * MILLIS_IN_SECOND, startTime + (26 + i nitialDelay) * MILLIS_IN_HOUR, "lastDownload after download error"); |
| 521 equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (27 + initialDe lay) * MILLIS_IN_HOUR, "lastCheck after download error"); | 844 test.equal(subscription.lastSuccess * MILLIS_IN_SECOND, startTime + initialD elay * MILLIS_IN_HOUR, "lastSuccess after download error"); |
| 522 equal(subscription.errors, 2, "errors after download error"); | 845 test.equal(subscription.lastCheck * MILLIS_IN_SECOND, startTime + (27 + init ialDelay) * MILLIS_IN_HOUR, "lastCheck after download error"); |
| 523 }); | 846 test.equal(subscription.errors, 2, "errors after download error"); |
| 524 })(); | 847 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 848 }; | |
| OLD | NEW |