Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
2 /**
3 * DummyCompleter() lets tests easily specify the results of a partial
4 * hash completion request.
5 */
6 function DummyCompleter() {
7 this.fragments = {};
8 this.queries = [];
9 this.tableName = "test-phish-simple";
10 }
12 DummyCompleter.prototype =
13 {
14 QueryInterface: function(iid)
15 {
16 if (!iid.equals(Ci.nsISupports) &&
17 !iid.equals(Ci.nsIUrlClassifierHashCompleter)) {
18 throw Cr.NS_ERROR_NO_INTERFACE;
19 }
20 return this;
21 },
23 complete: function(partialHash, cb)
24 {
25 this.queries.push(partialHash);
26 var fragments = this.fragments;
27 var self = this;
28 var doCallback = function() {
29 if (self.alwaysFail) {
30 cb.completionFinished(1);
31 return;
32 }
33 var results;
34 if (fragments[partialHash]) {
35 for (var i = 0; i < fragments[partialHash].length; i++) {
36 var chunkId = fragments[partialHash][i][0];
37 var hash = fragments[partialHash][i][1];
38 cb.completion(hash, self.tableName, chunkId);
39 }
40 }
41 cb.completionFinished(0);
42 }
43 var timer = new Timer(0, doCallback);
44 },
46 getHash: function(fragment)
47 {
48 var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
49 createInstance(Ci.nsIScriptableUnicodeConverter);
50 converter.charset = "UTF-8";
51 var data = converter.convertToByteArray(fragment);
52 var ch = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
53 ch.init(ch.SHA256);
54 ch.update(data, data.length);
55 var hash = ch.finish(false);
56 return hash.slice(0, 32);
57 },
59 addFragment: function(chunkId, fragment)
60 {
61 this.addHash(chunkId, this.getHash(fragment));
62 },
64 // This method allows the caller to generate complete hashes that match the
65 // prefix of a real fragment, but have different complete hashes.
66 addConflict: function(chunkId, fragment)
67 {
68 var realHash = this.getHash(fragment);
69 var invalidHash = this.getHash("blah blah blah blah blah");
70 this.addHash(chunkId, realHash.slice(0, 4) + invalidHash.slice(4, 32));
71 },
73 addHash: function(chunkId, hash)
74 {
75 var partial = hash.slice(0, 4);
76 if (this.fragments[partial]) {
77 this.fragments[partial].push([chunkId, hash]);
78 } else {
79 this.fragments[partial] = [[chunkId, hash]];
80 }
81 },
83 compareQueries: function(fragments)
84 {
85 var expectedQueries = [];
86 for (var i = 0; i < fragments.length; i++) {
87 expectedQueries.push(this.getHash(fragments[i]).slice(0, 4));
88 }
89 do_check_eq(this.queries.length, expectedQueries.length);
90 expectedQueries.sort();
91 this.queries.sort();
92 for (var i = 0; i < this.queries.length; i++) {
93 do_check_eq(this.queries[i], expectedQueries[i]);
94 }
95 }
96 };
98 function setupCompleter(table, hits, conflicts)
99 {
100 var completer = new DummyCompleter();
101 completer.tableName = table;
102 for (var i = 0; i < hits.length; i++) {
103 var chunkId = hits[i][0];
104 var fragments = hits[i][1];
105 for (var j = 0; j < fragments.length; j++) {
106 completer.addFragment(chunkId, fragments[j]);
107 }
108 }
109 for (var i = 0; i < conflicts.length; i++) {
110 var chunkId = conflicts[i][0];
111 var fragments = conflicts[i][1];
112 for (var j = 0; j < fragments.length; j++) {
113 completer.addConflict(chunkId, fragments[j]);
114 }
115 }
117 dbservice.setHashCompleter(table, completer);
119 return completer;
120 }
122 function installCompleter(table, fragments, conflictFragments)
123 {
124 return setupCompleter(table, fragments, conflictFragments);
125 }
127 function installFailingCompleter(table) {
128 var completer = setupCompleter(table, [], []);
129 completer.alwaysFail = true;
130 return completer;
131 }
133 // Helper assertion for checking dummy completer queries
134 gAssertions.completerQueried = function(data, cb)
135 {
136 var completer = data[0];
137 completer.compareQueries(data[1]);
138 cb();
139 }
141 function doTest(updates, assertions)
142 {
143 doUpdateTest(updates, assertions, runNextTest, updateError);
144 }
146 // Test an add of two partial urls to a fresh database
147 function testPartialAdds() {
148 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
149 var update = buildPhishingUpdate(
150 [
151 { "chunkNum" : 1,
152 "urls" : addUrls
153 }],
154 4);
157 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
159 var assertions = {
160 "tableData" : "test-phish-simple;a:1",
161 "urlsExist" : addUrls,
162 "completerQueried" : [completer, addUrls]
163 };
166 doTest([update], assertions);
167 }
169 function testPartialAddsWithConflicts() {
170 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
171 var update = buildPhishingUpdate(
172 [
173 { "chunkNum" : 1,
174 "urls" : addUrls
175 }],
176 4);
178 // Each result will have both a real match and a conflict
179 var completer = installCompleter('test-phish-simple',
180 [[1, addUrls]],
181 [[1, addUrls]]);
183 var assertions = {
184 "tableData" : "test-phish-simple;a:1",
185 "urlsExist" : addUrls,
186 "completerQueried" : [completer, addUrls]
187 };
189 doTest([update], assertions);
190 }
192 // Test whether the fragmenting code does not cause duplicated completions
193 function testFragments() {
194 var addUrls = [ "foo.com/a/b/c", "foo.net/", "foo.com/c/" ];
195 var update = buildPhishingUpdate(
196 [
197 { "chunkNum" : 1,
198 "urls" : addUrls
199 }],
200 4);
203 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
205 var assertions = {
206 "tableData" : "test-phish-simple;a:1",
207 "urlsExist" : addUrls,
208 "completerQueried" : [completer, addUrls]
209 };
212 doTest([update], assertions);
213 }
215 // Test http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
216 // section 6.2 example 1
217 function testSpecFragments() {
218 var probeUrls = [ "a.b.c/1/2.html?param=1" ];
220 var addUrls = [ "a.b.c/1/2.html",
221 "a.b.c/",
222 "a.b.c/1/",
223 "b.c/1/2.html?param=1",
224 "b.c/1/2.html",
225 "b.c/",
226 "b.c/1/",
227 "a.b.c/1/2.html?param=1" ];
229 var update = buildPhishingUpdate(
230 [
231 { "chunkNum" : 1,
232 "urls" : addUrls
233 }],
234 4);
237 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
239 var assertions = {
240 "tableData" : "test-phish-simple;a:1",
241 "urlsExist" : probeUrls,
242 "completerQueried" : [completer, addUrls]
243 };
245 doTest([update], assertions);
247 }
249 // Test http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
250 // section 6.2 example 2
251 function testMoreSpecFragments() {
252 var probeUrls = [ "a.b.c.d.e.f.g/1.html" ];
254 var addUrls = [ "a.b.c.d.e.f.g/1.html",
255 "a.b.c.d.e.f.g/",
256 "c.d.e.f.g/1.html",
257 "c.d.e.f.g/",
258 "d.e.f.g/1.html",
259 "d.e.f.g/",
260 "e.f.g/1.html",
261 "e.f.g/",
262 "f.g/1.html",
263 "f.g/" ];
265 var update = buildPhishingUpdate(
266 [
267 { "chunkNum" : 1,
268 "urls" : addUrls
269 }],
270 4);
272 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
274 var assertions = {
275 "tableData" : "test-phish-simple;a:1",
276 "urlsExist" : probeUrls,
277 "completerQueried" : [completer, addUrls]
278 };
280 doTest([update], assertions);
282 }
284 function testFalsePositives() {
285 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
286 var update = buildPhishingUpdate(
287 [
288 { "chunkNum" : 1,
289 "urls" : addUrls
290 }],
291 4);
293 // Each result will have no matching complete hashes and a non-matching
294 // conflict
295 var completer = installCompleter('test-phish-simple', [], [[1, addUrls]]);
297 var assertions = {
298 "tableData" : "test-phish-simple;a:1",
299 "urlsDontExist" : addUrls,
300 "completerQueried" : [completer, addUrls]
301 };
303 doTest([update], assertions);
304 }
306 function testEmptyCompleter() {
307 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
308 var update = buildPhishingUpdate(
309 [
310 { "chunkNum" : 1,
311 "urls" : addUrls
312 }],
313 4);
315 // Completer will never return full hashes
316 var completer = installCompleter('test-phish-simple', [], []);
318 var assertions = {
319 "tableData" : "test-phish-simple;a:1",
320 "urlsDontExist" : addUrls,
321 "completerQueried" : [completer, addUrls]
322 };
324 doTest([update], assertions);
325 }
327 function testCompleterFailure() {
328 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
329 var update = buildPhishingUpdate(
330 [
331 { "chunkNum" : 1,
332 "urls" : addUrls
333 }],
334 4);
336 // Completer will never return full hashes
337 var completer = installFailingCompleter('test-phish-simple');
339 var assertions = {
340 "tableData" : "test-phish-simple;a:1",
341 "urlsDontExist" : addUrls,
342 "completerQueried" : [completer, addUrls]
343 };
345 doTest([update], assertions);
346 }
348 function testMixedSizesSameDomain() {
349 var add1Urls = [ "foo.com/a" ];
350 var add2Urls = [ "foo.com/b" ];
352 var update1 = buildPhishingUpdate(
353 [
354 { "chunkNum" : 1,
355 "urls" : add1Urls }],
356 4);
357 var update2 = buildPhishingUpdate(
358 [
359 { "chunkNum" : 2,
360 "urls" : add2Urls }],
361 32);
363 // We should only need to complete the partial hashes
364 var completer = installCompleter('test-phish-simple', [[1, add1Urls]], []);
366 var assertions = {
367 "tableData" : "test-phish-simple;a:1-2",
368 // both urls should match...
369 "urlsExist" : add1Urls.concat(add2Urls),
370 // ... but the completer should only be queried for the partial entry
371 "completerQueried" : [completer, add1Urls]
372 };
374 doTest([update1, update2], assertions);
375 }
377 function testMixedSizesDifferentDomains() {
378 var add1Urls = [ "foo.com/a" ];
379 var add2Urls = [ "bar.com/b" ];
381 var update1 = buildPhishingUpdate(
382 [
383 { "chunkNum" : 1,
384 "urls" : add1Urls }],
385 4);
386 var update2 = buildPhishingUpdate(
387 [
388 { "chunkNum" : 2,
389 "urls" : add2Urls }],
390 32);
392 // We should only need to complete the partial hashes
393 var completer = installCompleter('test-phish-simple', [[1, add1Urls]], []);
395 var assertions = {
396 "tableData" : "test-phish-simple;a:1-2",
397 // both urls should match...
398 "urlsExist" : add1Urls.concat(add2Urls),
399 // ... but the completer should only be queried for the partial entry
400 "completerQueried" : [completer, add1Urls]
401 };
403 doTest([update1, update2], assertions);
404 }
406 function testInvalidHashSize()
407 {
408 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
409 var update = buildPhishingUpdate(
410 [
411 { "chunkNum" : 1,
412 "urls" : addUrls
413 }],
414 12); // only 4 and 32 are legal hash sizes
416 var addUrls2 = [ "zaz.com/a", "xyz.com/b" ];
417 var update2 = buildPhishingUpdate(
418 [
419 { "chunkNum" : 2,
420 "urls" : addUrls2
421 }],
422 4);
424 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
426 var assertions = {
427 "tableData" : "test-phish-simple;a:2",
428 "urlsDontExist" : addUrls
429 };
431 // A successful update will trigger an error
432 doUpdateTest([update2, update], assertions, updateError, runNextTest);
433 }
435 function testWrongTable()
436 {
437 var addUrls = [ "foo.com/a" ];
438 var update = buildPhishingUpdate(
439 [
440 { "chunkNum" : 1,
441 "urls" : addUrls
442 }],
443 4);
444 var completer = installCompleter('test-malware-simple', // wrong table
445 [[1, addUrls]], []);
447 // The above installCompleter installs the completer for test-malware-simple,
448 // we want it to be used for test-phish-simple too.
449 dbservice.setHashCompleter("test-phish-simple", completer);
452 var assertions = {
453 "tableData" : "test-phish-simple;a:1",
454 // The urls were added as phishing urls, but the completer is claiming
455 // that they are malware urls, and we trust the completer in this case.
456 // The result will be discarded, so we can only check for non-existence.
457 "urlsDontExist" : addUrls,
458 // Make sure the completer was actually queried.
459 "completerQueried" : [completer, addUrls]
460 };
462 doUpdateTest([update], assertions,
463 function() {
464 // Give the dbservice a chance to (not) cache the result.
465 var timer = new Timer(3000, function() {
466 // The miss earlier will have caused a miss to be cached.
467 // Resetting the completer does not count as an update,
468 // so we will not be probed again.
469 var newCompleter = installCompleter('test-malware-simple', [[1, addUrls]], []); dbservice.setHashCompleter("test-phish-simple",
470 newCompleter);
472 var assertions = {
473 "urlsDontExist" : addUrls
474 };
475 checkAssertions(assertions, runNextTest);
476 });
477 }, updateError);
478 }
480 function setupCachedResults(addUrls, part2)
481 {
482 var update = buildPhishingUpdate(
483 [
484 { "chunkNum" : 1,
485 "urls" : addUrls
486 }],
487 4);
489 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
491 var assertions = {
492 "tableData" : "test-phish-simple;a:1",
493 // Request the add url. This should cause the completion to be cached.
494 "urlsExist" : addUrls,
495 // Make sure the completer was actually queried.
496 "completerQueried" : [completer, addUrls]
497 };
499 doUpdateTest([update], assertions,
500 function() {
501 // Give the dbservice a chance to cache the result.
502 var timer = new Timer(3000, part2);
503 }, updateError);
504 }
506 function testCachedResults()
507 {
508 setupCachedResults(["foo.com/a"], function(add) {
509 // This is called after setupCachedResults(). Verify that
510 // checking the url again does not cause a completer request.
512 // install a new completer, this one should never be queried.
513 var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
515 var assertions = {
516 "urlsExist" : ["foo.com/a"],
517 "completerQueried" : [newCompleter, []]
518 };
519 checkAssertions(assertions, runNextTest);
520 });
521 }
523 function testCachedResultsWithSub() {
524 setupCachedResults(["foo.com/a"], function() {
525 // install a new completer, this one should never be queried.
526 var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
528 var removeUpdate = buildPhishingUpdate(
529 [ { "chunkNum" : 2,
530 "chunkType" : "s",
531 "urls": ["1:foo.com/a"] }],
532 4);
534 var assertions = {
535 "urlsDontExist" : ["foo.com/a"],
536 "completerQueried" : [newCompleter, []]
537 }
539 doTest([removeUpdate], assertions);
540 });
541 }
543 function testCachedResultsWithExpire() {
544 setupCachedResults(["foo.com/a"], function() {
545 // install a new completer, this one should never be queried.
546 var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
548 var expireUpdate =
549 "n:1000\n" +
550 "i:test-phish-simple\n" +
551 "ad:1\n";
553 var assertions = {
554 "urlsDontExist" : ["foo.com/a"],
555 "completerQueried" : [newCompleter, []]
556 }
557 doTest([expireUpdate], assertions);
558 });
559 }
561 function testCachedResultsUpdate()
562 {
563 var existUrls = ["foo.com/a"];
564 setupCachedResults(existUrls, function() {
565 // This is called after setupCachedResults(). Verify that
566 // checking the url again does not cause a completer request.
568 // install a new completer, this one should never be queried.
569 var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
571 var assertions = {
572 "urlsExist" : existUrls,
573 "completerQueried" : [newCompleter, []]
574 };
576 var addUrls = ["foobar.org/a"];
578 var update2 = buildPhishingUpdate(
579 [
580 { "chunkNum" : 2,
581 "urls" : addUrls
582 }],
583 4);
585 checkAssertions(assertions, function () {
586 // Apply the update. The cached completes should be gone.
587 doStreamUpdate(update2, function() {
588 // Now the completer gets queried again.
589 var newCompleter2 = installCompleter('test-phish-simple', [[1, existUrls]], []);
590 var assertions2 = {
591 "tableData" : "test-phish-simple;a:1-2",
592 "urlsExist" : existUrls,
593 "completerQueried" : [newCompleter2, existUrls]
594 };
595 checkAssertions(assertions2, runNextTest);
596 }, updateError);
597 });
598 });
599 }
601 function testCachedResultsFailure()
602 {
603 var existUrls = ["foo.com/a"];
604 setupCachedResults(existUrls, function() {
605 // This is called after setupCachedResults(). Verify that
606 // checking the url again does not cause a completer request.
608 // install a new completer, this one should never be queried.
609 var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
611 var assertions = {
612 "urlsExist" : existUrls,
613 "completerQueried" : [newCompleter, []]
614 };
616 var addUrls = ["foobar.org/a"];
618 var update2 = buildPhishingUpdate(
619 [
620 { "chunkNum" : 2,
621 "urls" : addUrls
622 }],
623 4);
625 checkAssertions(assertions, function() {
626 // Apply the update. The cached completes should be gone.
627 doErrorUpdate("test-phish-simple,test-malware-simple", function() {
628 // Now the completer gets queried again.
629 var newCompleter2 = installCompleter('test-phish-simple', [[1, existUrls]], []);
630 var assertions2 = {
631 "tableData" : "test-phish-simple;a:1",
632 "urlsExist" : existUrls,
633 "completerQueried" : [newCompleter2, existUrls]
634 };
635 checkAssertions(assertions2, runNextTest);
636 }, updateError);
637 });
638 });
639 }
641 function testErrorList()
642 {
643 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
644 var update = buildPhishingUpdate(
645 [
646 { "chunkNum" : 1,
647 "urls" : addUrls
648 }],
649 4);
650 // The update failure should will kill the completes, so the above
651 // must be a prefix to get any hit at all past the update failure.
653 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
655 var assertions = {
656 "tableData" : "test-phish-simple;a:1",
657 "urlsExist" : addUrls,
658 // These are complete urls, and will only be completed if the
659 // list is stale.
660 "completerQueried" : [completer, addUrls]
661 };
663 // Apply the update.
664 doStreamUpdate(update, function() {
665 // Now the test-phish-simple and test-malware-simple tables are marked
666 // as fresh. Fake an update failure to mark them stale.
667 doErrorUpdate("test-phish-simple,test-malware-simple", function() {
668 // Now the lists should be marked stale. Check assertions.
669 checkAssertions(assertions, runNextTest);
670 }, updateError);
671 }, updateError);
672 }
675 function testStaleList()
676 {
677 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
678 var update = buildPhishingUpdate(
679 [
680 { "chunkNum" : 1,
681 "urls" : addUrls
682 }],
683 32);
685 var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
687 var assertions = {
688 "tableData" : "test-phish-simple;a:1",
689 "urlsExist" : addUrls,
690 // These are complete urls, and will only be completed if the
691 // list is stale.
692 "completerQueried" : [completer, addUrls]
693 };
695 // Consider a match stale after one second.
696 prefBranch.setIntPref("urlclassifier.max-complete-age", 1);
698 // Apply the update.
699 doStreamUpdate(update, function() {
700 // Now the test-phish-simple and test-malware-simple tables are marked
701 // as fresh. Wait three seconds to make sure the list is marked stale.
702 new Timer(3000, function() {
703 // Now the lists should be marked stale. Check assertions.
704 checkAssertions(assertions, function() {
705 prefBranch.setIntPref("urlclassifier.max-complete-age", 2700);
706 runNextTest();
707 });
708 }, updateError);
709 }, updateError);
710 }
712 // Same as testStaleList, but verifies that an empty response still
713 // unconfirms the entry.
714 function testStaleListEmpty()
715 {
716 var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
717 var update = buildPhishingUpdate(
718 [
719 { "chunkNum" : 1,
720 "urls" : addUrls
721 }],
722 32);
724 var completer = installCompleter('test-phish-simple', [], []);
726 var assertions = {
727 "tableData" : "test-phish-simple;a:1",
728 // None of these should match, because they won't be completed
729 "urlsDontExist" : addUrls,
730 // These are complete urls, and will only be completed if the
731 // list is stale.
732 "completerQueried" : [completer, addUrls]
733 };
735 // Consider a match stale after one second.
736 prefBranch.setIntPref("urlclassifier.max-complete-age", 1);
738 // Apply the update.
739 doStreamUpdate(update, function() {
740 // Now the test-phish-simple and test-malware-simple tables are marked
741 // as fresh. Wait three seconds to make sure the list is marked stale.
742 new Timer(3000, function() {
743 // Now the lists should be marked stale. Check assertions.
744 checkAssertions(assertions, function() {
745 prefBranch.setIntPref("urlclassifier.max-complete-age", 2700);
746 runNextTest();
747 });
748 }, updateError);
749 }, updateError);
750 }
753 // Verify that different lists (test-phish-simple,
754 // test-malware-simple) maintain their freshness separately.
755 function testErrorListIndependent()
756 {
757 var phishUrls = [ "phish.com/a" ];
758 var malwareUrls = [ "attack.com/a" ];
759 var update = buildPhishingUpdate(
760 [
761 { "chunkNum" : 1,
762 "urls" : phishUrls
763 }],
764 4);
765 // These have to persist past the update failure, so they must be prefixes,
766 // not completes.
768 update += buildMalwareUpdate(
769 [
770 { "chunkNum" : 2,
771 "urls" : malwareUrls
772 }],
773 32);
775 var completer = installCompleter('test-phish-simple', [[1, phishUrls]], []);
777 var assertions = {
778 "tableData" : "test-malware-simple;a:2\ntest-phish-simple;a:1",
779 "urlsExist" : phishUrls,
780 "malwareUrlsExist" : malwareUrls,
781 // Only this phishing urls should be completed, because only the phishing
782 // urls will be stale.
783 "completerQueried" : [completer, phishUrls]
784 };
786 // Apply the update.
787 doStreamUpdate(update, function() {
788 // Now the test-phish-simple and test-malware-simple tables are
789 // marked as fresh. Fake an update failure to mark *just*
790 // phishing data as stale.
791 doErrorUpdate("test-phish-simple", function() {
792 // Now the lists should be marked stale. Check assertions.
793 checkAssertions(assertions, runNextTest);
794 }, updateError);
795 }, updateError);
796 }
798 function run_test()
799 {
800 runTests([
801 testPartialAdds,
802 testPartialAddsWithConflicts,
803 testFragments,
804 testSpecFragments,
805 testMoreSpecFragments,
806 testFalsePositives,
807 testEmptyCompleter,
808 testCompleterFailure,
809 testMixedSizesSameDomain,
810 testMixedSizesDifferentDomains,
811 testInvalidHashSize,
812 testWrongTable,
813 testCachedResults,
814 testCachedResultsWithSub,
815 testCachedResultsWithExpire,
816 testCachedResultsUpdate,
817 testCachedResultsFailure,
818 testStaleList,
819 testStaleListEmpty,
820 testErrorList,
821 testErrorListIndependent
822 ]);
823 }
825 do_test_pending();