diff options
Diffstat (limited to 'browser/components/migration/tests/unit/test_fx_telemetry.js')
-rw-r--r-- | browser/components/migration/tests/unit/test_fx_telemetry.js | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/browser/components/migration/tests/unit/test_fx_telemetry.js b/browser/components/migration/tests/unit/test_fx_telemetry.js new file mode 100644 index 0000000000..5be6b740fc --- /dev/null +++ b/browser/components/migration/tests/unit/test_fx_telemetry.js @@ -0,0 +1,269 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +const { FirefoxProfileMigrator } = ChromeUtils.importESModule( + "resource:///modules/FirefoxProfileMigrator.sys.mjs" +); + +function readFile(file) { + let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + stream.init(file, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF); + + let sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( + Ci.nsIScriptableInputStream + ); + sis.init(stream); + let contents = sis.read(file.fileSize); + sis.close(); + return contents; +} + +function checkDirectoryContains(dir, files) { + print("checking " + dir.path + " - should contain " + Object.keys(files)); + let seen = new Set(); + for (let file of dir.directoryEntries) { + print("found file: " + file.path); + Assert.ok(file.leafName in files, file.leafName + " exists, but shouldn't"); + + let expectedContents = files[file.leafName]; + if (typeof expectedContents != "string") { + // it's a subdir - recurse! + Assert.ok(file.isDirectory(), "should be a subdir"); + let newDir = dir.clone(); + newDir.append(file.leafName); + checkDirectoryContains(newDir, expectedContents); + } else { + Assert.ok(!file.isDirectory(), "should be a regular file"); + let contents = readFile(file); + Assert.equal(contents, expectedContents); + } + seen.add(file.leafName); + } + let missing = []; + for (let x in files) { + if (!seen.has(x)) { + missing.push(x); + } + } + Assert.deepEqual(missing, [], "no missing files in " + dir.path); +} + +function getTestDirs() { + // we make a directory structure in a temp dir which mirrors what we are + // testing. + let tempDir = do_get_tempdir(); + let srcDir = tempDir.clone(); + srcDir.append("test_source_dir"); + srcDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + + let targetDir = tempDir.clone(); + targetDir.append("test_target_dir"); + targetDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + + // no need to cleanup these dirs - the xpcshell harness will do it for us. + return [srcDir, targetDir]; +} + +function writeToFile(dir, leafName, contents) { + let file = dir.clone(); + file.append(leafName); + + let outputStream = FileUtils.openFileOutputStream(file); + outputStream.write(contents, contents.length); + outputStream.close(); +} + +function createSubDir(dir, subDirName) { + let subDir = dir.clone(); + subDir.append(subDirName); + subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + return subDir; +} + +async function promiseMigrator(name, srcDir, targetDir) { + // As the FirefoxProfileMigrator is a startup-only migrator, we import its + // module and instantiate it directly rather than going through MigrationUtils, + // to bypass that availability check. + let migrator = new FirefoxProfileMigrator(); + let migrators = migrator._getResourcesInternal(srcDir, targetDir); + for (let m of migrators) { + if (m.name == name) { + return new Promise(resolve => m.migrate(resolve)); + } + } + throw new Error("failed to find the " + name + " migrator"); +} + +function promiseTelemetryMigrator(srcDir, targetDir) { + return promiseMigrator("telemetry", srcDir, targetDir); +} + +add_task(async function test_empty() { + let [srcDir, targetDir] = getTestDirs(); + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true with empty directories"); + // check both are empty + checkDirectoryContains(srcDir, {}); + checkDirectoryContains(targetDir, {}); +}); + +add_task(async function test_migrate_files() { + let [srcDir, targetDir] = getTestDirs(); + + // Set up datareporting files, some to copy, some not. + let stateContent = JSON.stringify({ + clientId: "68d5474e-19dc-45c1-8e9a-81fca592707c", + }); + let sessionStateContent = "foobar 5432"; + let subDir = createSubDir(srcDir, "datareporting"); + writeToFile(subDir, "state.json", stateContent); + writeToFile(subDir, "session-state.json", sessionStateContent); + writeToFile(subDir, "other.file", "do not copy"); + + let archived = createSubDir(subDir, "archived"); + writeToFile(archived, "other.file", "do not copy"); + + // Set up FHR files, they should not be copied. + writeToFile(srcDir, "healthreport.sqlite", "do not copy"); + writeToFile(srcDir, "healthreport.sqlite-wal", "do not copy"); + subDir = createSubDir(srcDir, "healthreport"); + writeToFile(subDir, "state.json", "do not copy"); + writeToFile(subDir, "other.file", "do not copy"); + + // Perform migration. + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok( + ok, + "callback should have been true with important telemetry files copied" + ); + + checkDirectoryContains(targetDir, { + datareporting: { + "state.json": stateContent, + "session-state.json": sessionStateContent, + }, + }); +}); + +add_task(async function test_datareporting_not_dir() { + let [srcDir, targetDir] = getTestDirs(); + + writeToFile(srcDir, "datareporting", "I'm a file but should be a directory"); + + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok( + ok, + "callback should have been true even though the directory was a file" + ); + + checkDirectoryContains(targetDir, {}); +}); + +add_task(async function test_datareporting_empty() { + let [srcDir, targetDir] = getTestDirs(); + + // Migrate with an empty 'datareporting' subdir. + createSubDir(srcDir, "datareporting"); + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + + // We should end up with no migrated files. + checkDirectoryContains(targetDir, { + datareporting: {}, + }); +}); + +add_task(async function test_healthreport_empty() { + let [srcDir, targetDir] = getTestDirs(); + + // Migrate with no 'datareporting' and an empty 'healthreport' subdir. + createSubDir(srcDir, "healthreport"); + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + + // We should end up with no migrated files. + checkDirectoryContains(targetDir, {}); +}); + +add_task(async function test_datareporting_many() { + let [srcDir, targetDir] = getTestDirs(); + + // Create some datareporting files. + let subDir = createSubDir(srcDir, "datareporting"); + let shouldBeCopied = "should be copied"; + writeToFile(subDir, "state.json", shouldBeCopied); + writeToFile(subDir, "session-state.json", shouldBeCopied); + writeToFile(subDir, "something.else", "should not"); + createSubDir(subDir, "emptyDir"); + + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + + checkDirectoryContains(targetDir, { + datareporting: { + "state.json": shouldBeCopied, + "session-state.json": shouldBeCopied, + }, + }); +}); + +add_task(async function test_no_session_state() { + let [srcDir, targetDir] = getTestDirs(); + + // Check that migration still works properly if we only have state.json. + let subDir = createSubDir(srcDir, "datareporting"); + let stateContent = "abcd984"; + writeToFile(subDir, "state.json", stateContent); + + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + + checkDirectoryContains(targetDir, { + datareporting: { + "state.json": stateContent, + }, + }); +}); + +add_task(async function test_no_state() { + let [srcDir, targetDir] = getTestDirs(); + + // Check that migration still works properly if we only have session-state.json. + let subDir = createSubDir(srcDir, "datareporting"); + let sessionStateContent = "abcd512"; + writeToFile(subDir, "session-state.json", sessionStateContent); + + let ok = await promiseTelemetryMigrator(srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + + checkDirectoryContains(targetDir, { + datareporting: { + "session-state.json": sessionStateContent, + }, + }); +}); + +add_task(async function test_times_migration() { + let [srcDir, targetDir] = getTestDirs(); + + // create a times.json in the source directory. + let contents = JSON.stringify({ created: 1234 }); + writeToFile(srcDir, "times.json", contents); + + let earliest = Date.now(); + let ok = await promiseMigrator("times", srcDir, targetDir); + Assert.ok(ok, "callback should have been true"); + let latest = Date.now(); + + let timesFile = targetDir.clone(); + timesFile.append("times.json"); + + let raw = readFile(timesFile); + let times = JSON.parse(raw); + Assert.ok(times.reset >= earliest && times.reset <= latest); + // and it should have left the creation time alone. + Assert.equal(times.created, 1234); +}); |