test_FormHistoryBackupResource.js (7475B)
1 /* Any copyright is dedicated to the Public Domain. 2 https://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { FormHistoryBackupResource } = ChromeUtils.importESModule( 7 "resource:///modules/backup/FormHistoryBackupResource.sys.mjs" 8 ); 9 10 /** 11 * Tests that we can measure the Form History db in a profile directory. 12 */ 13 add_task(async function test_measure() { 14 const EXPECTED_FORM_HISTORY_DB_SIZE = 500; 15 16 Services.fog.testResetFOG(); 17 18 // Create resource files in temporary directory 19 let tempDir = PathUtils.tempDir; 20 let tempFormHistoryDBPath = PathUtils.join(tempDir, "formhistory.sqlite"); 21 await createKilobyteSizedFile( 22 tempFormHistoryDBPath, 23 EXPECTED_FORM_HISTORY_DB_SIZE 24 ); 25 26 let formHistoryBackupResource = new FormHistoryBackupResource(); 27 await formHistoryBackupResource.measure(tempDir); 28 29 let formHistoryMeasurement = 30 Glean.browserBackup.formHistorySize.testGetValue(); 31 let scalars = TelemetryTestUtils.getProcessScalars("parent", false, false); 32 33 // Compare glean vs telemetry measurements 34 TelemetryTestUtils.assertScalar( 35 scalars, 36 "browser.backup.form_history_size", 37 formHistoryMeasurement, 38 "Glean and telemetry measurements for formhistory.sqlite should be equal" 39 ); 40 41 // Compare glean measurements vs actual file sizes 42 Assert.equal( 43 formHistoryMeasurement, 44 EXPECTED_FORM_HISTORY_DB_SIZE, 45 "Should have collected the correct glean measurement for formhistory.sqlite" 46 ); 47 48 await IOUtils.remove(tempFormHistoryDBPath); 49 }); 50 51 /** 52 * Test that the backup method correctly copies items from the profile directory 53 * into the staging directory. 54 */ 55 add_task(async function test_backup() { 56 let sandbox = sinon.createSandbox(); 57 58 let formHistoryBackupResource = new FormHistoryBackupResource(); 59 let sourcePath = await IOUtils.createUniqueDirectory( 60 PathUtils.tempDir, 61 "FormHistoryBackupResource-source-test" 62 ); 63 let stagingPath = await IOUtils.createUniqueDirectory( 64 PathUtils.tempDir, 65 "FormHistoryBackupResource-staging-test" 66 ); 67 68 // Make sure this file exists in the source directory, otherwise 69 // BackupResource will skip attempting to back it up. 70 await createTestFiles(sourcePath, [{ path: "formhistory.sqlite" }]); 71 72 // We have no need to test that Sqlite.sys.mjs's backup method is working - 73 // this is something that is tested in Sqlite's own tests. We can just make 74 // sure that it's being called using sinon. Unfortunately, we cannot do the 75 // same thing with IOUtils.copy, as its methods are not stubbable. 76 let fakeConnection = { 77 backup: sandbox.stub().resolves(true), 78 close: sandbox.stub().resolves(true), 79 }; 80 sandbox.stub(Sqlite, "openConnection").returns(fakeConnection); 81 82 let manifestEntry = await formHistoryBackupResource.backup( 83 stagingPath, 84 sourcePath 85 ); 86 Assert.equal( 87 manifestEntry, 88 null, 89 "FormHistoryBackupResource.backup should return null as its ManifestEntry" 90 ); 91 92 // Next, we'll make sure that the Sqlite connection had `backup` called on it 93 // with the right arguments. 94 Assert.ok( 95 fakeConnection.backup.calledOnce, 96 "Called backup the expected number of times for all connections" 97 ); 98 Assert.ok( 99 fakeConnection.backup.calledWith( 100 PathUtils.join(stagingPath, "formhistory.sqlite") 101 ), 102 "Called backup on the formhistory.sqlite Sqlite connection" 103 ); 104 105 await maybeRemovePath(stagingPath); 106 await maybeRemovePath(sourcePath); 107 108 sandbox.restore(); 109 }); 110 111 /** 112 * Tests that the backup method does not copy the form history database if the 113 * browser is configured to not save history - either while running, or to 114 * clear it at shutdown. 115 */ 116 add_task(async function test_backup_no_saved_history() { 117 let formHistoryBackupResource = new FormHistoryBackupResource(); 118 let sourcePath = await IOUtils.createUniqueDirectory( 119 PathUtils.tempDir, 120 "FormHistoryBackupResource-source-test" 121 ); 122 let stagingPath = await IOUtils.createUniqueDirectory( 123 PathUtils.tempDir, 124 "FormHistoryBackupResource-staging-test" 125 ); 126 127 let sandbox = sinon.createSandbox(); 128 let fakeConnection = { 129 backup: sandbox.stub().resolves(true), 130 close: sandbox.stub().resolves(true), 131 }; 132 sandbox.stub(Sqlite, "openConnection").returns(fakeConnection); 133 134 Services.prefs.setBoolPref(FORM_HISTORY_CLEARED_ON_SHUTDOWN_PREF, true); 135 Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true); 136 137 Assert.ok( 138 !FormHistoryBackupResource.canBackupResource, 139 "Cannot backup form history since it is being cleared on shutdown" 140 ); 141 142 Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false); 143 Services.prefs.setBoolPref(FORM_HISTORY_CLEARED_ON_SHUTDOWN_PREF, false); 144 145 // We'll try with browsing history in general being disabled. 146 Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false); 147 148 Assert.ok( 149 !FormHistoryBackupResource.canBackupResource, 150 "Cannot backup form history since it is being cleared on shutdown" 151 ); 152 153 Assert.ok( 154 fakeConnection.backup.notCalled, 155 "No sqlite connections should have been made with remember history disabled" 156 ); 157 158 Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true); 159 160 Assert.ok( 161 FormHistoryBackupResource.canBackupResource, 162 "We should be allowed to backup this resource now" 163 ); 164 165 fakeConnection.backup.resetHistory(); 166 let manifestEntry = await formHistoryBackupResource.backup( 167 stagingPath, 168 sourcePath 169 ); 170 Assert.deepEqual( 171 manifestEntry, 172 null, 173 "Should have gotten back a null ManifestEntry" 174 ); 175 176 Assert.ok( 177 fakeConnection.backup.notCalled, 178 "No sqlite connections should have been made with sanitize shutdown enabled" 179 ); 180 181 await maybeRemovePath(stagingPath); 182 await maybeRemovePath(sourcePath); 183 184 sandbox.restore(); 185 Services.prefs.clearUserPref(HISTORY_ENABLED_PREF); 186 Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF); 187 }); 188 189 /** 190 * Tests that the backup method correctly skips backing up form history when 191 * permanent private browsing mode is enabled. 192 */ 193 add_task(async function test_backup_private_browsing() { 194 let sandbox = sinon.createSandbox(); 195 sandbox.stub(PrivateBrowsingUtils, "permanentPrivateBrowsing").value(true); 196 197 Assert.ok( 198 !FormHistoryBackupResource.canBackupResource, 199 "Cannot backup form history since Private Browsing is enabled" 200 ); 201 202 sandbox.restore(); 203 }); 204 205 /** 206 * Test that the recover method correctly copies items from the recovery 207 * directory into the destination profile directory. 208 */ 209 add_task(async function test_recover() { 210 let formHistoryBackupResource = new FormHistoryBackupResource(); 211 let recoveryPath = await IOUtils.createUniqueDirectory( 212 PathUtils.tempDir, 213 "FormHistoryBackupResource-recovery-test" 214 ); 215 let destProfilePath = await IOUtils.createUniqueDirectory( 216 PathUtils.tempDir, 217 "FormHistoryBackupResource-test-profile" 218 ); 219 220 const simpleCopyFiles = [{ path: "formhistory.sqlite" }]; 221 await createTestFiles(recoveryPath, simpleCopyFiles); 222 223 // The backup method is expected to have returned a null ManifestEntry 224 let postRecoveryEntry = await formHistoryBackupResource.recover( 225 null /* manifestEntry */, 226 recoveryPath, 227 destProfilePath 228 ); 229 Assert.equal( 230 postRecoveryEntry, 231 null, 232 "FormHistoryBackupResource.recover should return null as its post " + 233 "recovery entry" 234 ); 235 236 await assertFilesExist(destProfilePath, simpleCopyFiles); 237 238 await maybeRemovePath(recoveryPath); 239 await maybeRemovePath(destProfilePath); 240 });