head_migration.js (8086B)
1 "use strict"; 2 3 var { MigrationUtils } = ChromeUtils.importESModule( 4 "resource:///modules/MigrationUtils.sys.mjs" 5 ); 6 var { LoginHelper } = ChromeUtils.importESModule( 7 "resource://gre/modules/LoginHelper.sys.mjs" 8 ); 9 var { NetUtil } = ChromeUtils.importESModule( 10 "resource://gre/modules/NetUtil.sys.mjs" 11 ); 12 var { PlacesUtils } = ChromeUtils.importESModule( 13 "resource://gre/modules/PlacesUtils.sys.mjs" 14 ); 15 var { Preferences } = ChromeUtils.importESModule( 16 "resource://gre/modules/Preferences.sys.mjs" 17 ); 18 var { XPCOMUtils } = ChromeUtils.importESModule( 19 "resource://gre/modules/XPCOMUtils.sys.mjs" 20 ); 21 var { TestUtils } = ChromeUtils.importESModule( 22 "resource://testing-common/TestUtils.sys.mjs" 23 ); 24 var { PlacesTestUtils } = ChromeUtils.importESModule( 25 "resource://testing-common/PlacesTestUtils.sys.mjs" 26 ); 27 const { AppConstants } = ChromeUtils.importESModule( 28 "resource://gre/modules/AppConstants.sys.mjs" 29 ); 30 31 ChromeUtils.defineESModuleGetters(this, { 32 FileUtils: "resource://gre/modules/FileUtils.sys.mjs", 33 Sqlite: "resource://gre/modules/Sqlite.sys.mjs", 34 }); 35 36 // Initialize profile. 37 var gProfD = do_get_profile(); 38 39 var { getAppInfo, newAppInfo, updateAppInfo } = ChromeUtils.importESModule( 40 "resource://testing-common/AppInfo.sys.mjs" 41 ); 42 updateAppInfo(); 43 44 /** 45 * Migrates the requested resource and waits for the migration to be complete. 46 * 47 * @param {MigratorBase} migrator 48 * The migrator being used to migrate the data. 49 * @param {number} resourceType 50 * This is a bitfield with bits from nsIBrowserProfileMigrator flipped to indicate what 51 * resources should be migrated. 52 * @param {object|string|null} [aProfile=null] 53 * The profile to be migrated. If set to null, the default profile will be 54 * migrated. 55 * @param {boolean} succeeds 56 * True if this migration is expected to succeed. 57 * @returns {Promise<Array<string[]>>} 58 * An array of the results from each nsIObserver topics being observed to 59 * verify if the migration succeeded or failed. Those results are 2-element 60 * arrays of [subject, data]. 61 */ 62 async function promiseMigration( 63 migrator, 64 resourceType, 65 aProfile = null, 66 succeeds = null 67 ) { 68 // Ensure resource migration is available. 69 let availableSources = await migrator.getMigrateData(aProfile); 70 Assert.greater( 71 availableSources & resourceType, 72 0, 73 "Resource supported by migrator" 74 ); 75 let promises = [TestUtils.topicObserved("Migration:Ended")]; 76 77 if (succeeds !== null) { 78 // Check that the specific resource type succeeded 79 promises.push( 80 TestUtils.topicObserved( 81 succeeds ? "Migration:ItemAfterMigrate" : "Migration:ItemError", 82 (_, data) => data == resourceType 83 ) 84 ); 85 } 86 87 // Start the migration. 88 migrator.migrate(resourceType, null, aProfile); 89 90 return Promise.all(promises); 91 } 92 93 /** 94 * Takes an array of page URIs and checks that the favicon was imported for each page URI 95 * 96 * @param {Array} pageURIs An array of page URIs 97 */ 98 async function assertFavicons(pageURIs) { 99 for (let uri of pageURIs) { 100 let favicon = await PlacesUtils.favicons.getFaviconForPage(uri); 101 Assert.ok(favicon, `Got favicon for ${favicon.uri.spec}`); 102 } 103 } 104 105 /** 106 * Check the image data for favicon of given page uri. 107 * 108 * @param {string} pageURI 109 * The page URI to which the favicon belongs. 110 * @param {Array} expectedImageData 111 * Expected image data of the favicon. 112 * @param {string} expectedMimeType 113 * Expected mime type of the favicon. 114 */ 115 async function assertFavicon(pageURI, expectedImageData, expectedMimeType) { 116 let result = await PlacesUtils.favicons.getFaviconForPage( 117 Services.io.newURI(pageURI) 118 ); 119 Assert.ok(!!result, `Got favicon for ${pageURI}`); 120 Assert.equal( 121 result.rawData.join(","), 122 expectedImageData.join(","), 123 "Image data is correct" 124 ); 125 Assert.equal(result.mimeType, expectedMimeType, "Mime type is correct"); 126 } 127 128 /** 129 * Replaces a directory service entry with a given nsIFile. 130 * 131 * @param {string} key 132 * The nsIDirectoryService directory key to register a fake path for. 133 * For example: "AppData", "ULibDir". 134 * @param {nsIFile} file 135 * The nsIFile to map the key to. Note that this nsIFile should represent 136 * a directory and not an individual file. 137 * @see nsDirectoryServiceDefs.h for the list of directories that can be 138 * overridden. 139 */ 140 function registerFakePath(key, file) { 141 let dirsvc = Services.dirsvc.QueryInterface(Ci.nsIProperties); 142 let originalFile; 143 try { 144 // If a file is already provided save it and undefine, otherwise set will 145 // throw for persistent entries (ones that are cached). 146 originalFile = dirsvc.get(key, Ci.nsIFile); 147 dirsvc.undefine(key); 148 } catch (e) { 149 // dirsvc.get will throw if nothing provides for the key and dirsvc.undefine 150 // will throw if it's not a persistent entry, in either case we don't want 151 // to set the original file in cleanup. 152 originalFile = undefined; 153 } 154 155 dirsvc.set(key, file); 156 registerCleanupFunction(() => { 157 dirsvc.undefine(key); 158 if (originalFile) { 159 dirsvc.set(key, originalFile); 160 } 161 }); 162 } 163 164 function getRootPath() { 165 let dirKey; 166 if (AppConstants.platform == "win") { 167 dirKey = "LocalAppData"; 168 } else if (AppConstants.platform == "macosx") { 169 dirKey = "ULibDir"; 170 } else { 171 dirKey = "Home"; 172 } 173 return Services.dirsvc.get(dirKey, Ci.nsIFile).path; 174 } 175 176 /** 177 * Returns a PRTime value for the current date minus daysAgo number 178 * of days. 179 * 180 * @param {number} daysAgo 181 * How many days in the past from now the returned date should be. 182 * @returns {number} 183 */ 184 function PRTimeDaysAgo(daysAgo) { 185 return PlacesUtils.toPRTime(Date.now() - daysAgo * 24 * 60 * 60 * 1000); 186 } 187 188 /** 189 * Returns a Date value for the current date minus daysAgo number 190 * of days. 191 * 192 * @param {number} daysAgo 193 * How many days in the past from now the returned date should be. 194 * @returns {Date} 195 */ 196 function dateDaysAgo(daysAgo) { 197 return new Date(Date.now() - daysAgo * 24 * 60 * 60 * 1000); 198 } 199 200 /** 201 * Constructs and returns a data structure consistent with the Chrome 202 * browsers bookmarks storage. This data structure can then be serialized 203 * to JSON and written to disk to simulate a Chrome browser's bookmarks 204 * database. 205 * 206 * @param {number} [totalBookmarks=100] 207 * How many bookmarks to create. 208 * @returns {object} 209 */ 210 function createChromeBookmarkStructure(totalBookmarks = 100) { 211 let bookmarksData = { 212 roots: { 213 bookmark_bar: { children: [] }, 214 other: { children: [] }, 215 synced: { children: [] }, 216 }, 217 }; 218 const MAX_BMS = totalBookmarks; 219 let barKids = bookmarksData.roots.bookmark_bar.children; 220 let menuKids = bookmarksData.roots.other.children; 221 let syncedKids = bookmarksData.roots.synced.children; 222 let currentMenuKids = menuKids; 223 let currentBarKids = barKids; 224 let currentSyncedKids = syncedKids; 225 for (let i = 0; i < MAX_BMS; i++) { 226 currentBarKids.push({ 227 url: "https://www.chrome-bookmark-bar-bookmark" + i + ".com", 228 name: "bookmark " + i, 229 type: "url", 230 }); 231 currentMenuKids.push({ 232 url: "https://www.chrome-menu-bookmark" + i + ".com", 233 name: "bookmark for menu " + i, 234 type: "url", 235 }); 236 currentSyncedKids.push({ 237 url: "https://www.chrome-synced-bookmark" + i + ".com", 238 name: "bookmark for synced " + i, 239 type: "url", 240 }); 241 if (i % 20 == 19) { 242 let nextFolder = { 243 name: "toolbar folder " + Math.ceil(i / 20), 244 type: "folder", 245 children: [], 246 }; 247 currentBarKids.push(nextFolder); 248 currentBarKids = nextFolder.children; 249 250 nextFolder = { 251 name: "menu folder " + Math.ceil(i / 20), 252 type: "folder", 253 children: [], 254 }; 255 currentMenuKids.push(nextFolder); 256 currentMenuKids = nextFolder.children; 257 258 nextFolder = { 259 name: "synced folder " + Math.ceil(i / 20), 260 type: "folder", 261 children: [], 262 }; 263 currentSyncedKids.push(nextFolder); 264 currentSyncedKids = nextFolder.children; 265 } 266 } 267 return bookmarksData; 268 }