test_queue.js (12553B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 ChromeUtils.defineESModuleGetters(this, { 5 PageDataService: 6 "moz-src:///browser/components/pagedata/PageDataService.sys.mjs", 7 TestUtils: "resource://testing-common/TestUtils.sys.mjs", 8 }); 9 10 // Test that urls are retrieved in the expected order. 11 add_task(async function test_queueOrder() { 12 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 0); 13 // Pretend we are idle. 14 PageDataService.observe(null, "idle", null); 15 16 let pageDataResults = [ 17 { 18 date: Date.now(), 19 url: "http://www.mozilla.org/1", 20 siteName: "Mozilla", 21 data: {}, 22 }, 23 { 24 date: Date.now() - 3600, 25 url: "http://www.google.com/2", 26 siteName: "Google", 27 data: {}, 28 }, 29 { 30 date: Date.now() + 3600, 31 url: "http://www.example.com/3", 32 image: "http://www.example.com/banner.jpg", 33 data: {}, 34 }, 35 { 36 date: Date.now() / 2, 37 url: "http://www.wikipedia.org/4", 38 data: {}, 39 }, 40 { 41 date: Date.now() / 3, 42 url: "http://www.microsoft.com/5", 43 data: { 44 [PageDataSchema.DATA_TYPE.PRODUCT]: { 45 name: "Windows 11", 46 }, 47 }, 48 }, 49 ]; 50 51 let requests = []; 52 PageDataService.fetchPageData = url => { 53 requests.push(url); 54 55 for (let pageData of pageDataResults) { 56 if (pageData.url == url) { 57 return Promise.resolve(pageData); 58 } 59 } 60 61 return Promise.reject(new Error("Unknown url")); 62 }; 63 64 let { promise: completePromise, resolve } = Promise.withResolvers(); 65 66 let results = []; 67 let listener = (_, pageData) => { 68 results.push(pageData); 69 if (results.length == pageDataResults.length) { 70 resolve(); 71 } 72 }; 73 74 PageDataService.on("page-data", listener); 75 76 for (let pageData of pageDataResults) { 77 PageDataService.queueFetch(pageData.url); 78 } 79 80 await completePromise; 81 PageDataService.off("page-data", listener); 82 83 Assert.deepEqual( 84 requests, 85 pageDataResults.map(pd => pd.url) 86 ); 87 88 // Because our fetch implementation is essentially synchronous the results 89 // will be in a known order. This isn't guaranteed by the API though. 90 Assert.deepEqual(results, pageDataResults); 91 92 delete PageDataService.fetchPageData; 93 }); 94 95 // Tests that limiting the number of fetches works. 96 add_task(async function test_queueLimit() { 97 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3); 98 // Pretend we are idle. 99 PageDataService.observe(null, "idle", null); 100 101 let requests = []; 102 PageDataService.fetchPageData = url => { 103 let { promise, resolve, reject } = Promise.withResolvers(); 104 requests.push({ url, resolve, reject }); 105 106 return promise; 107 }; 108 109 let results = []; 110 let listener = (_, pageData) => { 111 results.push(pageData?.url); 112 }; 113 114 PageDataService.on("page-data", listener); 115 116 PageDataService.queueFetch("https://www.mozilla.org/1"); 117 PageDataService.queueFetch("https://www.mozilla.org/2"); 118 PageDataService.queueFetch("https://www.mozilla.org/3"); 119 PageDataService.queueFetch("https://www.mozilla.org/4"); 120 PageDataService.queueFetch("https://www.mozilla.org/5"); 121 PageDataService.queueFetch("https://www.mozilla.org/6"); 122 PageDataService.queueFetch("https://www.mozilla.org/7"); 123 PageDataService.queueFetch("https://www.mozilla.org/8"); 124 PageDataService.queueFetch("https://www.mozilla.org/9"); 125 PageDataService.queueFetch("https://www.mozilla.org/10"); 126 PageDataService.queueFetch("https://www.mozilla.org/11"); 127 128 await TestUtils.waitForTick(); 129 130 Assert.deepEqual( 131 requests.map(r => r.url), 132 [ 133 "https://www.mozilla.org/1", 134 "https://www.mozilla.org/2", 135 "https://www.mozilla.org/3", 136 ] 137 ); 138 139 // Completing or rejecting a request should start new ones. 140 141 requests[1].resolve({ 142 date: 2345, 143 url: "https://www.mozilla.org/2", 144 siteName: "Test 2", 145 data: {}, 146 }); 147 148 await TestUtils.waitForTick(); 149 150 Assert.deepEqual( 151 requests.map(r => r.url), 152 [ 153 "https://www.mozilla.org/1", 154 "https://www.mozilla.org/2", 155 "https://www.mozilla.org/3", 156 "https://www.mozilla.org/4", 157 ] 158 ); 159 160 requests[3].reject(new Error("Fail")); 161 162 await TestUtils.waitForTick(); 163 164 Assert.deepEqual( 165 requests.map(r => r.url), 166 [ 167 "https://www.mozilla.org/1", 168 "https://www.mozilla.org/2", 169 "https://www.mozilla.org/3", 170 "https://www.mozilla.org/4", 171 "https://www.mozilla.org/5", 172 ] 173 ); 174 175 // Increasing the limit should start more requests. 176 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 5); 177 178 await TestUtils.waitForTick(); 179 180 Assert.deepEqual( 181 requests.map(r => r.url), 182 [ 183 "https://www.mozilla.org/1", 184 "https://www.mozilla.org/2", 185 "https://www.mozilla.org/3", 186 "https://www.mozilla.org/4", 187 "https://www.mozilla.org/5", 188 "https://www.mozilla.org/6", 189 "https://www.mozilla.org/7", 190 ] 191 ); 192 193 // Dropping the limit shouldn't start anything new. 194 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3); 195 196 await TestUtils.waitForTick(); 197 198 Assert.deepEqual( 199 requests.map(r => r.url), 200 [ 201 "https://www.mozilla.org/1", 202 "https://www.mozilla.org/2", 203 "https://www.mozilla.org/3", 204 "https://www.mozilla.org/4", 205 "https://www.mozilla.org/5", 206 "https://www.mozilla.org/6", 207 "https://www.mozilla.org/7", 208 ] 209 ); 210 211 // But resolving should also not start new requests. 212 requests[5].resolve({ 213 date: 345334, 214 url: "https://www.mozilla.org/6", 215 siteName: "Test 6", 216 data: {}, 217 }); 218 219 requests[0].resolve({ 220 date: 343446434, 221 url: "https://www.mozilla.org/1", 222 siteName: "Test 1", 223 data: {}, 224 }); 225 226 await TestUtils.waitForTick(); 227 228 Assert.deepEqual( 229 requests.map(r => r.url), 230 [ 231 "https://www.mozilla.org/1", 232 "https://www.mozilla.org/2", 233 "https://www.mozilla.org/3", 234 "https://www.mozilla.org/4", 235 "https://www.mozilla.org/5", 236 "https://www.mozilla.org/6", 237 "https://www.mozilla.org/7", 238 ] 239 ); 240 241 // Until a previous request completes. 242 requests[4].resolve(null); 243 244 await TestUtils.waitForTick(); 245 246 Assert.deepEqual( 247 requests.map(r => r.url), 248 [ 249 "https://www.mozilla.org/1", 250 "https://www.mozilla.org/2", 251 "https://www.mozilla.org/3", 252 "https://www.mozilla.org/4", 253 "https://www.mozilla.org/5", 254 "https://www.mozilla.org/6", 255 "https://www.mozilla.org/7", 256 "https://www.mozilla.org/8", 257 ] 258 ); 259 260 // Inifinite queue should work. 261 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 0); 262 263 await TestUtils.waitForTick(); 264 265 Assert.deepEqual( 266 requests.map(r => r.url), 267 [ 268 "https://www.mozilla.org/1", 269 "https://www.mozilla.org/2", 270 "https://www.mozilla.org/3", 271 "https://www.mozilla.org/4", 272 "https://www.mozilla.org/5", 273 "https://www.mozilla.org/6", 274 "https://www.mozilla.org/7", 275 "https://www.mozilla.org/8", 276 "https://www.mozilla.org/9", 277 "https://www.mozilla.org/10", 278 "https://www.mozilla.org/11", 279 ] 280 ); 281 282 requests[10].resolve({ 283 date: 345334, 284 url: "https://www.mozilla.org/11", 285 data: {}, 286 }); 287 requests[2].resolve({ 288 date: 345334, 289 url: "https://www.mozilla.org/3", 290 data: {}, 291 }); 292 requests[7].resolve({ 293 date: 345334, 294 url: "https://www.mozilla.org/8", 295 data: {}, 296 }); 297 requests[6].resolve({ 298 date: 345334, 299 url: "https://www.mozilla.org/7", 300 data: {}, 301 }); 302 requests[8].resolve({ 303 date: 345334, 304 url: "https://www.mozilla.org/9", 305 data: {}, 306 }); 307 requests[9].resolve({ 308 date: 345334, 309 url: "https://www.mozilla.org/10", 310 data: {}, 311 }); 312 313 await TestUtils.waitForTick(); 314 315 Assert.deepEqual( 316 requests.map(r => r.url), 317 [ 318 "https://www.mozilla.org/1", 319 "https://www.mozilla.org/2", 320 "https://www.mozilla.org/3", 321 "https://www.mozilla.org/4", 322 "https://www.mozilla.org/5", 323 "https://www.mozilla.org/6", 324 "https://www.mozilla.org/7", 325 "https://www.mozilla.org/8", 326 "https://www.mozilla.org/9", 327 "https://www.mozilla.org/10", 328 "https://www.mozilla.org/11", 329 ] 330 ); 331 332 PageDataService.off("page-data", listener); 333 334 delete PageDataService.fetchPageData; 335 336 Assert.deepEqual(results, [ 337 "https://www.mozilla.org/2", 338 "https://www.mozilla.org/6", 339 "https://www.mozilla.org/1", 340 "https://www.mozilla.org/11", 341 "https://www.mozilla.org/3", 342 "https://www.mozilla.org/8", 343 "https://www.mozilla.org/7", 344 "https://www.mozilla.org/9", 345 "https://www.mozilla.org/10", 346 ]); 347 }); 348 349 // Tests that the user idle state stops and starts fetches. 350 add_task(async function test_idle() { 351 Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3); 352 // Pretend we are active. 353 PageDataService.observe(null, "active", null); 354 355 let requests = []; 356 PageDataService.fetchPageData = url => { 357 let { promise, resolve, reject } = Promise.withResolvers(); 358 requests.push({ url, resolve, reject }); 359 360 return promise; 361 }; 362 363 let results = []; 364 let listener = (_, pageData) => { 365 results.push(pageData?.url); 366 }; 367 368 PageDataService.on("page-data", listener); 369 370 PageDataService.queueFetch("https://www.mozilla.org/1"); 371 PageDataService.queueFetch("https://www.mozilla.org/2"); 372 PageDataService.queueFetch("https://www.mozilla.org/3"); 373 PageDataService.queueFetch("https://www.mozilla.org/4"); 374 PageDataService.queueFetch("https://www.mozilla.org/5"); 375 PageDataService.queueFetch("https://www.mozilla.org/6"); 376 PageDataService.queueFetch("https://www.mozilla.org/7"); 377 378 await TestUtils.waitForTick(); 379 380 // Nothing will start when active. 381 Assert.deepEqual( 382 requests.map(r => r.url), 383 [] 384 ); 385 386 // Pretend we are idle. 387 PageDataService.observe(null, "idle", null); 388 389 await TestUtils.waitForTick(); 390 391 Assert.deepEqual( 392 requests.map(r => r.url), 393 [ 394 "https://www.mozilla.org/1", 395 "https://www.mozilla.org/2", 396 "https://www.mozilla.org/3", 397 ] 398 ); 399 400 // Completing or rejecting a request should start new ones. 401 402 requests[1].resolve({ 403 date: 2345, 404 url: "https://www.mozilla.org/2", 405 data: {}, 406 }); 407 408 await TestUtils.waitForTick(); 409 410 Assert.deepEqual( 411 requests.map(r => r.url), 412 [ 413 "https://www.mozilla.org/1", 414 "https://www.mozilla.org/2", 415 "https://www.mozilla.org/3", 416 "https://www.mozilla.org/4", 417 ] 418 ); 419 420 // But not when active 421 PageDataService.observe(null, "active", null); 422 423 requests[3].resolve({ 424 date: 2345, 425 url: "https://www.mozilla.org/4", 426 data: {}, 427 }); 428 requests[0].resolve({ 429 date: 2345, 430 url: "https://www.mozilla.org/1", 431 data: {}, 432 }); 433 requests[2].resolve({ 434 date: 2345, 435 url: "https://www.mozilla.org/3", 436 data: {}, 437 }); 438 439 await TestUtils.waitForTick(); 440 441 Assert.deepEqual( 442 requests.map(r => r.url), 443 [ 444 "https://www.mozilla.org/1", 445 "https://www.mozilla.org/2", 446 "https://www.mozilla.org/3", 447 "https://www.mozilla.org/4", 448 ] 449 ); 450 451 // Going idle should start more workers 452 PageDataService.observe(null, "idle", null); 453 454 await TestUtils.waitForTick(); 455 456 Assert.deepEqual( 457 requests.map(r => r.url), 458 [ 459 "https://www.mozilla.org/1", 460 "https://www.mozilla.org/2", 461 "https://www.mozilla.org/3", 462 "https://www.mozilla.org/4", 463 "https://www.mozilla.org/5", 464 "https://www.mozilla.org/6", 465 "https://www.mozilla.org/7", 466 ] 467 ); 468 469 requests[4].resolve({ 470 date: 2345, 471 url: "https://www.mozilla.org/5", 472 data: {}, 473 }); 474 requests[5].resolve({ 475 date: 2345, 476 url: "https://www.mozilla.org/6", 477 data: {}, 478 }); 479 requests[6].resolve({ 480 date: 2345, 481 url: "https://www.mozilla.org/7", 482 data: {}, 483 }); 484 485 await TestUtils.waitForTick(); 486 487 Assert.deepEqual( 488 requests.map(r => r.url), 489 [ 490 "https://www.mozilla.org/1", 491 "https://www.mozilla.org/2", 492 "https://www.mozilla.org/3", 493 "https://www.mozilla.org/4", 494 "https://www.mozilla.org/5", 495 "https://www.mozilla.org/6", 496 "https://www.mozilla.org/7", 497 ] 498 ); 499 500 PageDataService.off("page-data", listener); 501 502 delete PageDataService.fetchPageData; 503 504 Assert.deepEqual(results, [ 505 "https://www.mozilla.org/2", 506 "https://www.mozilla.org/4", 507 "https://www.mozilla.org/1", 508 "https://www.mozilla.org/3", 509 "https://www.mozilla.org/5", 510 "https://www.mozilla.org/6", 511 "https://www.mozilla.org/7", 512 ]); 513 });