test_remote_settings_offline.js (4984B)
1 // A collection with a dump that's packaged on all builds where this test runs, 2 // including on Android at mobile/android/installer/package-manifest.in 3 const TEST_BUCKET = "main"; 4 const TEST_COLLECTION = "password-recipes"; 5 6 let client; 7 let DUMP_RECORDS; 8 let DUMP_LAST_MODIFIED; 9 10 add_setup(async () => { 11 // "services.settings.server" pref is not set. 12 // Test defaults to an unreachable server, 13 // and will only load from the dump if any. 14 15 client = new RemoteSettingsClient(TEST_COLLECTION, { 16 bucketName: TEST_BUCKET, 17 }); 18 19 const dump = await SharedUtils.loadJSONDump(TEST_BUCKET, TEST_COLLECTION); 20 DUMP_RECORDS = dump.data; 21 DUMP_LAST_MODIFIED = dump.timestamp; 22 23 // Dumps are fetched via the following, which sorts the records, newest first. 24 // https://searchfox.org/mozilla-central/rev/5b3444ad300e244b5af4214212e22bd9e4b7088a/taskcluster/docker/periodic-updates/scripts/periodic_file_updates.sh#304 25 equal( 26 DUMP_LAST_MODIFIED, 27 DUMP_RECORDS[0].last_modified, 28 "records in dump ought to be sorted by last_modified" 29 ); 30 }); 31 32 async function importData(records) { 33 await RemoteSettingsWorker._execute("_test_only_import", [ 34 TEST_BUCKET, 35 TEST_COLLECTION, 36 records, 37 records[0]?.last_modified || 0, 38 ]); 39 } 40 41 async function clear_state() { 42 await client.db.clear(); 43 } 44 45 add_task(async function test_load_from_dump_when_offline() { 46 // Baseline: verify that the collection is empty at first, 47 // but non-empty after loading from the dump. 48 const beforeTimestamp = await client.db.getLastModified(); 49 equal(beforeTimestamp, null, "collection empty when offline"); 50 51 // should import from dump since collection was not initialized. 52 const after = await client.get(); 53 equal(after.length, DUMP_RECORDS.length, "collection loaded from dump"); 54 equal(await client.getLastModified(), DUMP_LAST_MODIFIED, "dump's timestamp"); 55 }); 56 add_task(clear_state); 57 58 add_task(async function test_optional_skip_dump_after_empty_import() { 59 // clear_state should have wiped the database. 60 const beforeTimestamp = await client.db.getLastModified(); 61 equal(beforeTimestamp, null, "collection empty after clearing"); 62 63 // Verify that the dump is not imported again by client.get() 64 // when the database is initialized with an empty dump 65 // with `loadDumpIfNewer` disabled. 66 await importData([]); // <-- Empty set of records. 67 68 const after = await client.get({ loadDumpIfNewer: false }); 69 equal(after.length, 0, "collection still empty due to import"); 70 equal(await client.getLastModified(), 0, "Empty dump has no timestamp"); 71 }); 72 add_task(clear_state); 73 74 add_task(async function test_optional_skip_dump_after_non_empty_import() { 75 await importData([{ last_modified: 1234, id: "dummy" }]); 76 77 const after = await client.get({ loadDumpIfNewer: false }); 78 equal(after.length, 1, "Imported dummy data"); 79 equal(await client.getLastModified(), 1234, "Expected timestamp of import"); 80 81 await importData([]); 82 const after2 = await client.get({ loadDumpIfNewer: false }); 83 equal(after2.length, 0, "Previous data wiped on duplicate import"); 84 equal(await client.getLastModified(), 0, "Timestamp of empty collection"); 85 }); 86 add_task(clear_state); 87 88 add_task(async function test_load_dump_after_empty_import() { 89 await importData([]); // <-- Empty set of records, i.e. last_modified = 0. 90 91 const after = await client.get(); 92 equal(after.length, DUMP_RECORDS.length, "Imported dump"); 93 equal(await client.getLastModified(), DUMP_LAST_MODIFIED, "dump's timestamp"); 94 }); 95 add_task(clear_state); 96 97 add_task(async function test_load_dump_after_non_empty_import() { 98 // Dump is updated regularly, verify that the dump matches our expectations 99 // before running the test. 100 Assert.greater( 101 DUMP_LAST_MODIFIED, 102 1234, 103 "Assuming dump to be newer than dummy 1234" 104 ); 105 106 await importData([{ last_modified: 1234, id: "dummy" }]); 107 108 const after = await client.get(); 109 equal(after.length, DUMP_RECORDS.length, "Imported dump"); 110 equal(await client.getLastModified(), DUMP_LAST_MODIFIED, "dump's timestamp"); 111 }); 112 add_task(clear_state); 113 114 add_task(async function test_load_dump_after_import_from_broken_distro() { 115 // Dump is updated regularly, verify that the dump matches our expectations 116 // before running the test. 117 Assert.greater( 118 DUMP_LAST_MODIFIED, 119 1234, 120 "Assuming dump to be newer than dummy 1234" 121 ); 122 123 // No last_modified time. 124 await importData([{ id: "dummy" }]); 125 126 const after = await client.get(); 127 equal(after.length, DUMP_RECORDS.length, "Imported dump"); 128 equal(await client.getLastModified(), DUMP_LAST_MODIFIED, "dump's timestamp"); 129 }); 130 add_task(clear_state); 131 132 add_task(async function test_skip_dump_if_same_last_modified() { 133 await importData([{ last_modified: DUMP_LAST_MODIFIED, id: "dummy" }]); 134 135 const after = await client.get(); 136 equal(after.length, 1, "Not importing dump when time matches"); 137 equal(await client.getLastModified(), DUMP_LAST_MODIFIED, "Same timestamp"); 138 }); 139 add_task(clear_state);