test_BackupResource.js (8414B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { bytesToFuzzyKilobytes } = ChromeUtils.importESModule( 7 "resource:///modules/backup/BackupResource.sys.mjs" 8 ); 9 10 const { BookmarksBackupResource } = ChromeUtils.importESModule( 11 "resource:///modules/backup/BookmarksBackupResource.sys.mjs" 12 ); 13 14 const { PlacesBackupResource } = ChromeUtils.importESModule( 15 "resource:///modules/backup/PlacesBackupResource.sys.mjs" 16 ); 17 18 const EXPECTED_KILOBYTES_FOR_XULSTORE = 1; 19 20 /** 21 * Tests that BackupService.getFileSize will get the size of a file in kilobytes. 22 */ 23 add_task(async function test_getFileSize() { 24 let file = do_get_file("data/test_xulstore.json"); 25 26 let testFilePath = PathUtils.join(PathUtils.profileDir, "test_xulstore.json"); 27 28 await IOUtils.copy(file.path, PathUtils.profileDir); 29 30 let size = await BackupResource.getFileSize(testFilePath); 31 32 Assert.equal( 33 size, 34 EXPECTED_KILOBYTES_FOR_XULSTORE, 35 "Size of the test_xulstore.json is rounded up to the nearest kilobyte." 36 ); 37 38 await IOUtils.remove(testFilePath); 39 }); 40 41 /** 42 * Tests that BackupService.getDirectorySize will get the total size of all the 43 * files in a directory and it's children in kilobytes. 44 */ 45 add_task(async function test_getDirectorySize() { 46 let file = do_get_file("data/test_xulstore.json"); 47 48 // Create a test directory with the test json file in it. 49 let testDir = PathUtils.join(PathUtils.profileDir, "testDir"); 50 await IOUtils.makeDirectory(testDir); 51 await IOUtils.copy(file.path, testDir); 52 53 // Create another test directory inside of that one. 54 let nestedTestDir = PathUtils.join(testDir, "testDir"); 55 await IOUtils.makeDirectory(nestedTestDir); 56 await IOUtils.copy(file.path, nestedTestDir); 57 58 let size = await BackupResource.getDirectorySize(testDir); 59 60 Assert.equal( 61 size, 62 EXPECTED_KILOBYTES_FOR_XULSTORE * 2, 63 `Total size of the directory is rounded up to the nearest kilobyte 64 and is equal to twice the size of the test_xulstore.json file` 65 ); 66 67 await IOUtils.remove(testDir, { recursive: true }); 68 }); 69 70 /** 71 * Tests that bytesToFuzzyKilobytes will convert bytes to kilobytes 72 * and round to the nearest tenth kilobyte. 73 */ 74 add_task(async function test_bytesToFuzzyKilobytes() { 75 let largeSize = bytesToFuzzyKilobytes(1234000); 76 77 Assert.equal( 78 largeSize, 79 1230, 80 "1234 bytes is rounded to the nearest mulitple of ten kilobytes, 1230" 81 ); 82 83 let smallSize = bytesToFuzzyKilobytes(3); 84 85 Assert.equal(smallSize, 1, "Sizes under 10 kilobytes return 1 kilobyte"); 86 }); 87 88 /** 89 * Tests that BackupResource.copySqliteDatabases will call `backup` on a new 90 * read-only connection on each database file. 91 */ 92 add_task(async function test_copySqliteDatabases() { 93 let sandbox = sinon.createSandbox(); 94 const SQLITE_PAGES_PER_STEP_PREF = "browser.backup.sqlite.pages_per_step"; 95 const SQLITE_STEP_DELAY_MS_PREF = "browser.backup.sqlite.step_delay_ms"; 96 const DEFAULT_SQLITE_PAGES_PER_STEP = Services.prefs.getIntPref( 97 SQLITE_PAGES_PER_STEP_PREF 98 ); 99 const DEFAULT_SQLITE_STEP_DELAY_MS = Services.prefs.getIntPref( 100 SQLITE_STEP_DELAY_MS_PREF 101 ); 102 103 let sourcePath = await IOUtils.createUniqueDirectory( 104 PathUtils.tempDir, 105 "BackupResource-source-test" 106 ); 107 let destPath = await IOUtils.createUniqueDirectory( 108 PathUtils.tempDir, 109 "BackupResource-dest-test" 110 ); 111 let pretendDatabases = ["places.sqlite", "favicons.sqlite"]; 112 await createTestFiles( 113 sourcePath, 114 pretendDatabases.map(f => ({ path: f })) 115 ); 116 117 let fakeConnection = { 118 backup: sandbox.stub().resolves(true), 119 close: sandbox.stub().resolves(true), 120 }; 121 sandbox.stub(Sqlite, "openConnection").returns(fakeConnection); 122 123 await BackupResource.copySqliteDatabases( 124 sourcePath, 125 destPath, 126 pretendDatabases 127 ); 128 129 Assert.ok( 130 Sqlite.openConnection.calledTwice, 131 "Sqlite.openConnection called twice" 132 ); 133 Assert.ok( 134 Sqlite.openConnection.firstCall.calledWith({ 135 path: PathUtils.join(sourcePath, "places.sqlite"), 136 readOnly: true, 137 }), 138 "openConnection called with places.sqlite as read-only" 139 ); 140 Assert.ok( 141 Sqlite.openConnection.secondCall.calledWith({ 142 path: PathUtils.join(sourcePath, "favicons.sqlite"), 143 readOnly: true, 144 }), 145 "openConnection called with favicons.sqlite as read-only" 146 ); 147 148 Assert.ok( 149 fakeConnection.backup.calledTwice, 150 "backup on an Sqlite connection called twice" 151 ); 152 Assert.ok( 153 fakeConnection.backup.firstCall.calledWith( 154 PathUtils.join(destPath, "places.sqlite"), 155 DEFAULT_SQLITE_PAGES_PER_STEP, 156 DEFAULT_SQLITE_STEP_DELAY_MS 157 ), 158 "backup called with places.sqlite to the destination path with the right " + 159 "pages per step and step delay" 160 ); 161 Assert.ok( 162 fakeConnection.backup.secondCall.calledWith( 163 PathUtils.join(destPath, "favicons.sqlite"), 164 DEFAULT_SQLITE_PAGES_PER_STEP, 165 DEFAULT_SQLITE_STEP_DELAY_MS 166 ), 167 "backup called with favicons.sqlite to the destination path with the " + 168 "right pages per step and step delay" 169 ); 170 171 Assert.ok( 172 fakeConnection.close.calledTwice, 173 "close on an Sqlite connection called twice" 174 ); 175 176 // Now check that we can override the default pages per step and step delay. 177 fakeConnection.backup.resetHistory(); 178 const NEW_SQLITE_PAGES_PER_STEP = 10; 179 const NEW_SQLITE_STEP_DELAY_MS = 500; 180 Services.prefs.setIntPref( 181 SQLITE_PAGES_PER_STEP_PREF, 182 NEW_SQLITE_PAGES_PER_STEP 183 ); 184 Services.prefs.setIntPref( 185 SQLITE_STEP_DELAY_MS_PREF, 186 NEW_SQLITE_STEP_DELAY_MS 187 ); 188 await BackupResource.copySqliteDatabases( 189 sourcePath, 190 destPath, 191 pretendDatabases 192 ); 193 Assert.ok( 194 fakeConnection.backup.calledTwice, 195 "backup on an Sqlite connection called twice" 196 ); 197 Assert.ok( 198 fakeConnection.backup.firstCall.calledWith( 199 PathUtils.join(destPath, "places.sqlite"), 200 NEW_SQLITE_PAGES_PER_STEP, 201 NEW_SQLITE_STEP_DELAY_MS 202 ), 203 "backup called with places.sqlite to the destination path with the right " + 204 "pages per step and step delay" 205 ); 206 Assert.ok( 207 fakeConnection.backup.secondCall.calledWith( 208 PathUtils.join(destPath, "favicons.sqlite"), 209 NEW_SQLITE_PAGES_PER_STEP, 210 NEW_SQLITE_STEP_DELAY_MS 211 ), 212 "backup called with favicons.sqlite to the destination path with the " + 213 "right pages per step and step delay" 214 ); 215 216 await maybeRemovePath(sourcePath); 217 await maybeRemovePath(destPath); 218 sandbox.restore(); 219 }); 220 221 /** 222 * Tests that BackupResource.copyFiles will copy files from one directory to 223 * another. 224 */ 225 add_task(async function test_copyFiles() { 226 let sourcePath = await IOUtils.createUniqueDirectory( 227 PathUtils.tempDir, 228 "BackupResource-source-test" 229 ); 230 let destPath = await IOUtils.createUniqueDirectory( 231 PathUtils.tempDir, 232 "BackupResource-dest-test" 233 ); 234 235 const testFiles = [ 236 { path: "file1.txt" }, 237 { path: ["some", "nested", "file", "file2.txt"] }, 238 { path: "file3.txt" }, 239 ]; 240 241 await createTestFiles(sourcePath, testFiles); 242 243 await BackupResource.copyFiles(sourcePath, destPath, [ 244 "file1.txt", 245 "some", 246 "file3.txt", 247 "does-not-exist.txt", 248 ]); 249 250 await assertFilesExist(destPath, testFiles); 251 Assert.ok( 252 !(await IOUtils.exists(PathUtils.join(destPath, "does-not-exist.txt"))), 253 "does-not-exist.txt wasn't somehow written to." 254 ); 255 256 await maybeRemovePath(sourcePath); 257 await maybeRemovePath(destPath); 258 }); 259 260 add_task(async function test_bookmarks_places_backup_relation() { 261 // If places can be backed up, we don't need to backup bookmarks separately 262 Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true); 263 Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false); 264 265 Assert.ok(PlacesBackupResource.canBackupResource, "Places can be backed up"); 266 267 Assert.ok( 268 !BookmarksBackupResource.canBackupResource, 269 "Bookmarks won't be backed up separately" 270 ); 271 272 // If places can't be backed up, we need to backup bookmarks separately 273 Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true); 274 275 Assert.ok( 276 !PlacesBackupResource.canBackupResource, 277 "Places can not be backed up" 278 ); 279 280 Assert.ok( 281 BookmarksBackupResource.canBackupResource, 282 "Bookmarks will be backed up separately" 283 ); 284 285 Services.prefs.clearUserPref(HISTORY_ENABLED_PREF); 286 Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF); 287 });