summaryrefslogtreecommitdiffstats
path: root/toolkit/components/contextualidentity/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/contextualidentity/tests/unit')
-rw-r--r--toolkit/components/contextualidentity/tests/unit/test_basic.html71
-rw-r--r--toolkit/components/contextualidentity/tests/unit/test_basic.js233
-rw-r--r--toolkit/components/contextualidentity/tests/unit/test_corruptedFile.js169
-rw-r--r--toolkit/components/contextualidentity/tests/unit/test_migratedFile.js136
-rw-r--r--toolkit/components/contextualidentity/tests/unit/xpcshell.toml11
5 files changed, 620 insertions, 0 deletions
diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.html b/toolkit/components/contextualidentity/tests/unit/test_basic.html
new file mode 100644
index 0000000000..fbdbc772a9
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_basic.html
@@ -0,0 +1,71 @@
+"use strict";
+
+do_get_profile();
+
+const { ContextualIdentityService } = ChromeUtils.importESModule(
+ "resource://gre/modules/ContextualIdentityService.sys.mjs"
+);
+
+const TEST_STORE_FILE_NAME = "test-containers.json";
+
+let cis;
+
+// Basic tests
+add_task(function() {
+ ok(!!ContextualIdentityService, "ContextualIdentityService exists");
+
+ cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME);
+ ok(!!cis, "We have our instance of ContextualIdentityService");
+
+ equal(cis.getPublicIdentities().length, 4, "By default, 4 containers.");
+ equal(cis.getPublicIdentityFromId(0), null, "No identity with id 0");
+
+ ok(!!cis.getPublicIdentityFromId(1), "Identity 1 exists");
+ ok(!!cis.getPublicIdentityFromId(2), "Identity 2 exists");
+ ok(!!cis.getPublicIdentityFromId(3), "Identity 3 exists");
+ ok(!!cis.getPublicIdentityFromId(4), "Identity 4 exists");
+});
+
+// Create a new identity
+add_task(function() {
+ equal(cis.getPublicIdentities().length, 4, "By default, 4 containers.");
+
+ let identity = cis.create("New Container", "Icon", "Color");
+ ok(!!identity, "New container created");
+ equal(identity.name, "New Container", "Name matches");
+ equal(identity.icon, "Icon", "Icon matches");
+ equal(identity.color, "Color", "Color matches");
+
+ equal(cis.getPublicIdentities().length, 5, "Expected 5 containers.");
+
+ ok(!!cis.getPublicIdentityFromId(identity.userContextId), "Identity exists");
+ equal(cis.getPublicIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK");
+ equal(cis.getPublicIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK");
+ equal(cis.getPublicIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK");
+ equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK");
+});
+
+// Remove an identity
+add_task(function() {
+ equal(cis.getPublicIdentities().length, 5, "Expected 5 containers.");
+
+ equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist.");
+ equal(cis.remove(1), true, "cis.remove() returns true if identity exists.");
+
+ equal(cis.getPublicIdentities().length, 4, "Expected 4 containers.");
+});
+
+// Update an identity
+add_task(function() {
+ ok(!!cis.getPublicIdentityFromId(2), "Identity 2 exists");
+
+ equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns true if everything is OK");
+
+ equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK");
+
+ ok(!!cis.getPublicIdentityFromId(2), "Identity exists");
+ equal(cis.getPublicIdentityFromId(2).name, "Container", "Identity name is OK");
+ equal(cis.getPublicIdentityFromId(2).icon, "Icon", "Identity icon is OK");
+ equal(cis.getPublicIdentityFromId(2).color, "Color", "Identity color is OK");
+ equal(cis.getUserContextLabel(2), "Container", "Identity label is OK");
+});
diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.js b/toolkit/components/contextualidentity/tests/unit/test_basic.js
new file mode 100644
index 0000000000..0ee1869371
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_basic.js
@@ -0,0 +1,233 @@
+"use strict";
+
+const profileDir = do_get_profile();
+
+const { ContextualIdentityService } = ChromeUtils.importESModule(
+ "resource://gre/modules/ContextualIdentityService.sys.mjs"
+);
+
+const TEST_STORE_FILE_PATH = PathUtils.join(
+ profileDir.path,
+ "test-containers.json"
+);
+
+let cis;
+
+// Basic tests
+add_task(function () {
+ ok(!!ContextualIdentityService, "ContextualIdentityService exists");
+
+ cis =
+ ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_PATH);
+ ok(!!cis, "We have our instance of ContextualIdentityService");
+
+ equal(cis.getPublicIdentities().length, 4, "By default, 4 containers.");
+ equal(cis.getPublicIdentityFromId(0), null, "No identity with id 0");
+
+ ok(!!cis.getPublicIdentityFromId(1), "Identity 1 exists");
+ ok(!!cis.getPublicIdentityFromId(2), "Identity 2 exists");
+ ok(!!cis.getPublicIdentityFromId(3), "Identity 3 exists");
+ ok(!!cis.getPublicIdentityFromId(4), "Identity 4 exists");
+
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ cis.getPublicIdentities().map(ident => ident.userContextId),
+ "getPublicUserContextIds has matching user context IDs"
+ );
+});
+
+// Make sure we are not allowed to only use whitespaces as a container name
+add_task(function () {
+ Assert.throws(
+ () =>
+ cis.create(
+ "\u0009\u000B\u000C\u0020\u00A0\uFEFF\u000A\u000D\u2028\u2029",
+ "icon",
+ "color"
+ ),
+ /Contextual identity names cannot contain only whitespace./,
+ "Contextual identity names cannot contain only whitespace."
+ );
+});
+
+add_task(function () {
+ ok(!!cis.getPublicIdentityFromId(2), "Identity 2 exists");
+ Assert.throws(
+ () =>
+ cis.update(
+ 2,
+ "\u0009\u000B\u000C\u0020\u00A0\uFEFF\u000A\u000D\u2028\u2029",
+ "icon",
+ "color"
+ ),
+ /Contextual identity names cannot contain only whitespace./,
+ "Contextual identity names cannot contain only whitespace."
+ );
+});
+
+// Create a new identity
+add_task(function () {
+ equal(cis.getPublicIdentities().length, 4, "By default, 4 containers.");
+
+ let identity = cis.create("New Container", "Icon", "Color");
+ ok(!!identity, "New container created");
+ equal(identity.name, "New Container", "Name matches");
+ equal(identity.icon, "Icon", "Icon matches");
+ equal(identity.color, "Color", "Color matches");
+
+ equal(cis.getPublicIdentities().length, 5, "Expected 5 containers.");
+
+ ok(!!cis.getPublicIdentityFromId(identity.userContextId), "Identity exists");
+ equal(
+ cis.getPublicIdentityFromId(identity.userContextId).name,
+ "New Container",
+ "Identity name is OK"
+ );
+ equal(
+ cis.getPublicIdentityFromId(identity.userContextId).icon,
+ "Icon",
+ "Identity icon is OK"
+ );
+ equal(
+ cis.getPublicIdentityFromId(identity.userContextId).color,
+ "Color",
+ "Identity color is OK"
+ );
+ equal(
+ cis.getUserContextLabel(identity.userContextId),
+ "New Container",
+ "Identity label is OK"
+ );
+
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ cis.getPublicIdentities().map(ident => ident.userContextId),
+ "getPublicUserContextIds has matching user context IDs"
+ );
+
+ // Remove an identity
+ equal(
+ cis.remove(-1),
+ false,
+ "cis.remove() returns false if identity doesn't exist."
+ );
+ equal(cis.remove(1), true, "cis.remove() returns true if identity exists.");
+
+ equal(cis.getPublicIdentities().length, 4, "Expected 4 containers.");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ cis.getPublicIdentities().map(ident => ident.userContextId),
+ "getPublicUserContextIds has matching user context IDs"
+ );
+});
+
+// Reorder identities
+add_task(function () {
+ equal(cis.getPublicIdentities().length, 4, "By default, 4 containers.");
+ // Get whatever the initial order is
+ const [id0, id1, id2, id3] = cis.getPublicUserContextIds();
+
+ ok(cis.move([id3], 0), "Moving one valid id");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id0, id1, id2],
+ "Moving one valid ID works"
+ );
+
+ ok(cis.move([id1, id2], 1), "Moving several valid ids");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id2, id0],
+ "Moving several valid IDs works"
+ );
+
+ ok(!cis.move([100], 0), "Moving non-existing ids");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id2, id0],
+ "Moving only non-existing IDs leaves list unchanged"
+ );
+
+ ok(cis.move([100, id1], 1), "Moving non-existing and existing ids");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id2, id0],
+ "Moving existing and non-existing IDs ignores non-existing ones"
+ );
+
+ ok(cis.move([id1, 100], 1), "Moving existing and non-existing ids");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id2, id0],
+ "Moving existing and non-existing IDs ignores non-existing ones"
+ );
+
+ ok(cis.move([id2], -1), "Moving to -1");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id0, id2],
+ "Moving to -1 works"
+ );
+
+ ok(!cis.move([id3], -10), "Moving to other negative positions");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id3, id1, id0, id2],
+ "Moving to other negative positions leaves list unchanged"
+ );
+
+ ok(cis.move([id3], 3), "Moving to last public position");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id1, id0, id2, id3],
+ "Moving to last position correctly skips private context ids"
+ );
+
+ ok(cis.move([id1, id2], 1), "Moving past current position");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id0, id1, id2, id3],
+ "Target position is index in resulting list"
+ );
+
+ ok(cis.move([id2, id2], 2), "Moving duplicate ids");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id0, id1, id2, id3],
+ "Resulting list does not contain duplicate ids"
+ );
+
+ ok(!cis.move([], 2), "Moving empty list");
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ [id0, id1, id2, id3],
+ "Resulting list does not contain duplicate ids"
+ );
+});
+
+// Update an identity
+add_task(function () {
+ ok(!!cis.getPublicIdentityFromId(2), "Identity 2 exists");
+
+ equal(
+ cis.update(-1, "Container", "Icon", "Color"),
+ false,
+ "Update returns false if the identity doesn't exist"
+ );
+
+ equal(
+ cis.update(2, "Container", "Icon", "Color"),
+ true,
+ "Update returns true if everything is OK"
+ );
+
+ ok(!!cis.getPublicIdentityFromId(2), "Identity exists");
+ equal(
+ cis.getPublicIdentityFromId(2).name,
+ "Container",
+ "Identity name is OK"
+ );
+ equal(cis.getPublicIdentityFromId(2).icon, "Icon", "Identity icon is OK");
+ equal(cis.getPublicIdentityFromId(2).color, "Color", "Identity color is OK");
+ equal(cis.getUserContextLabel(2), "Container", "Identity label is OK");
+});
diff --git a/toolkit/components/contextualidentity/tests/unit/test_corruptedFile.js b/toolkit/components/contextualidentity/tests/unit/test_corruptedFile.js
new file mode 100644
index 0000000000..9dfa13ae2e
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_corruptedFile.js
@@ -0,0 +1,169 @@
+"use strict";
+
+const profileDir = do_get_profile();
+
+const { ContextualIdentityService } = ChromeUtils.importESModule(
+ "resource://gre/modules/ContextualIdentityService.sys.mjs"
+);
+
+const TEST_STORE_FILE_PATH = PathUtils.join(
+ profileDir.path,
+ "test-containers.json"
+);
+
+const BASE_URL = "http://example.org/";
+
+const COOKIE = {
+ host: BASE_URL,
+ path: "/",
+ name: "test",
+ value: "yes",
+ isSecure: false,
+ isHttpOnly: false,
+ isSession: true,
+ expiry: 2145934800,
+};
+
+function createCookie(userContextId) {
+ Services.cookies.add(
+ COOKIE.host,
+ COOKIE.path,
+ COOKIE.name,
+ COOKIE.value,
+ COOKIE.isSecure,
+ COOKIE.isHttpOnly,
+ COOKIE.isSession,
+ COOKIE.expiry,
+ { userContextId },
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTP
+ );
+}
+
+function hasCookie(userContextId) {
+ let found = false;
+ for (let cookie of Services.cookies.getCookiesFromHost(BASE_URL, {
+ userContextId,
+ })) {
+ if (cookie.originAttributes.userContextId == userContextId) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+// Correpted file should delete all.
+add_task(async function corruptedFile() {
+ const thumbnailPrivateId = ContextualIdentityService._defaultIdentities
+ .filter(identity => identity.name === "userContextIdInternal.thumbnail")
+ .pop().userContextId;
+
+ const webextStoragePrivateId = ContextualIdentityService._defaultIdentities
+ .filter(
+ identity => identity.name === "userContextIdInternal.webextStorageLocal"
+ )
+ .pop().userContextId;
+
+ // Create a cookie in the default Firefox identity (userContextId 0).
+ createCookie(0);
+
+ // Create a cookie in the userContextId 1.
+ createCookie(1);
+
+ // Create a cookie in the thumbnail private userContextId.
+ createCookie(thumbnailPrivateId);
+
+ // Create a cookie in the extension storage private userContextId.
+ createCookie(webextStoragePrivateId);
+
+ ok(hasCookie(0), "We have the new cookie the default firefox identity!");
+ ok(hasCookie(1), "We have the new cookie in a public identity!");
+ ok(
+ hasCookie(thumbnailPrivateId),
+ "We have the new cookie in the thumbnail private identity!"
+ );
+ ok(
+ hasCookie(webextStoragePrivateId),
+ "We have the new cookie in the extension storage private identity!"
+ );
+
+ // Let's create a corrupted file.
+ await IOUtils.writeUTF8(TEST_STORE_FILE_PATH, "{ vers", {
+ tmpPath: TEST_STORE_FILE_PATH + ".tmp",
+ });
+
+ let cis =
+ ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_PATH);
+ ok(!!cis, "We have our instance of ContextualIdentityService");
+
+ equal(
+ cis.getPublicIdentities().length,
+ 4,
+ "We should have the default public identities"
+ );
+
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ cis.getPublicIdentities().map(identity => identity.userContextId),
+ "getPublicUserContextIds has matching user context IDs"
+ );
+
+ // Verify that when the containers.json file is being rebuilt, the computed lastUserContextId
+ // is the expected one.
+ equal(
+ cis._lastUserContextId,
+ thumbnailPrivateId,
+ "Expect cis._lastUserContextId to be equal to the thumbnails userContextId"
+ );
+
+ const privThumbnailIdentity = cis.getPrivateIdentity(
+ "userContextIdInternal.thumbnail"
+ );
+ equal(
+ privThumbnailIdentity && privThumbnailIdentity.userContextId,
+ thumbnailPrivateId,
+ "We should have the default thumbnail private identity"
+ );
+
+ const privWebextStorageIdentity = cis.getPrivateIdentity(
+ "userContextIdInternal.webextStorageLocal"
+ );
+ equal(
+ privWebextStorageIdentity && privWebextStorageIdentity.userContextId,
+ webextStoragePrivateId,
+ "We should have the default extensions storage.local private identity"
+ );
+
+ // Cookie is gone!
+ ok(
+ !hasCookie(1),
+ "We should not have the new cookie in the userContextId 1!"
+ );
+
+ // The data stored in the Firefox default userContextId (0), should have not be cleared.
+ ok(
+ hasCookie(0),
+ "We should not have the new cookie in the default Firefox identity!"
+ );
+
+ // The data stored in the non-public userContextId (e.g. thumbnails private identity)
+ // should have not be cleared.
+ ok(
+ hasCookie(thumbnailPrivateId),
+ "We should have the new cookie in the thumbnail private userContextId!"
+ );
+ ok(
+ hasCookie(webextStoragePrivateId),
+ "We should have the new cookie in the extension storage private userContextId!"
+ );
+
+ // Verify the version of the newly created containers.json file.
+ cis.save();
+ const stateFileText = await IOUtils.readUTF8(TEST_STORE_FILE_PATH);
+ equal(
+ JSON.parse(stateFileText).version,
+ cis.LAST_CONTAINERS_JSON_VERSION,
+ "Expect the new containers.json file to have the expected version"
+ );
+});
diff --git a/toolkit/components/contextualidentity/tests/unit/test_migratedFile.js b/toolkit/components/contextualidentity/tests/unit/test_migratedFile.js
new file mode 100644
index 0000000000..2c7a37f19b
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_migratedFile.js
@@ -0,0 +1,136 @@
+"use strict";
+
+const profileDir = do_get_profile();
+
+const { ContextualIdentityService } = ChromeUtils.importESModule(
+ "resource://gre/modules/ContextualIdentityService.sys.mjs"
+);
+
+const TEST_STORE_FILE_PATH = PathUtils.join(
+ profileDir.path,
+ "test-containers.json"
+);
+
+// Test the containers JSON file migrations.
+add_task(async function migratedFile() {
+ // Let's create a file that has to be migrated.
+ const oldFileData = {
+ version: 2,
+ lastUserContextId: 6,
+ identities: [
+ {
+ userContextId: 1,
+ public: true,
+ icon: "fingerprint",
+ color: "blue",
+ l10nID: "userContextPersonal.label",
+ accessKey: "userContextPersonal.accesskey",
+ },
+ {
+ userContextId: 2,
+ public: true,
+ icon: "briefcase",
+ color: "orange",
+ l10nID: "userContextWork.label",
+ accessKey: "userContextWork.accesskey",
+ },
+ {
+ userContextId: 3,
+ public: true,
+ icon: "dollar",
+ color: "green",
+ l10nID: "userContextBanking.label",
+ accessKey: "userContextBanking.accesskey",
+ },
+ {
+ userContextId: 4,
+ public: true,
+ icon: "cart",
+ color: "pink",
+ l10nID: "userContextShopping.label",
+ accessKey: "userContextShopping.accesskey",
+ },
+ {
+ userContextId: 5,
+ public: false,
+ icon: "",
+ color: "",
+ name: "userContextIdInternal.thumbnail",
+ accessKey: "",
+ },
+ {
+ userContextId: 6,
+ public: true,
+ icon: "cart",
+ color: "ping",
+ name: "Custom user-created identity",
+ },
+ ],
+ };
+
+ await IOUtils.writeJSON(TEST_STORE_FILE_PATH, oldFileData, {
+ tmpPath: TEST_STORE_FILE_PATH + ".tmp",
+ });
+
+ let cis =
+ ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_PATH);
+ ok(!!cis, "We have our instance of ContextualIdentityService");
+
+ // Check that the custom user-created identity exists.
+
+ const expectedPublicLength = oldFileData.identities.filter(
+ identity => identity.public
+ ).length;
+ const publicIdentities = cis.getPublicIdentities();
+ const oldLastIdentity =
+ oldFileData.identities[oldFileData.identities.length - 1];
+ const customUserCreatedIdentity = publicIdentities
+ .filter(identity => identity.name === oldLastIdentity.name)
+ .pop();
+
+ equal(
+ publicIdentities.length,
+ expectedPublicLength,
+ "We should have the expected number of public identities"
+ );
+ ok(!!customUserCreatedIdentity, "Got the custom user-created identity");
+
+ Assert.deepEqual(
+ cis.getPublicUserContextIds(),
+ cis.getPublicIdentities().map(identity => identity.userContextId),
+ "getPublicUserContextIds has matching user context IDs"
+ );
+
+ // Check that the reserved userContextIdInternal.webextStorageLocal identity exists.
+
+ const webextStorageLocalPrivateId =
+ ContextualIdentityService._defaultIdentities
+ .filter(
+ identity => identity.name === "userContextIdInternal.webextStorageLocal"
+ )
+ .pop().userContextId;
+
+ const privWebExtStorageLocal = cis.getPrivateIdentity(
+ "userContextIdInternal.webextStorageLocal"
+ );
+ equal(
+ privWebExtStorageLocal && privWebExtStorageLocal.userContextId,
+ webextStorageLocalPrivateId,
+ "We should have the default userContextIdInternal.webextStorageLocal private identity"
+ );
+
+ // Check that all StringBundle references are replaced by Fluent references.
+
+ equal(
+ cis
+ .getPublicIdentities()
+ .filter(identity => identity.l10nID || identity.accessKey).length,
+ 0,
+ "No StringBundle l10nID or accessKey should be set"
+ );
+ equal(
+ cis.getPublicIdentities().filter(identity => identity.l10nId).length,
+ oldFileData.identities.filter(identity => identity.l10nID).length,
+ "All StringBundle references should be replaced by Fluent references"
+ );
+});
diff --git a/toolkit/components/contextualidentity/tests/unit/xpcshell.toml b/toolkit/components/contextualidentity/tests/unit/xpcshell.toml
new file mode 100644
index 0000000000..733734eba2
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/xpcshell.toml
@@ -0,0 +1,11 @@
+[DEFAULT]
+firefox-appdir = "browser"
+
+["test_basic.js"]
+skip-if = ["appname == 'thunderbird'"]
+
+["test_corruptedFile.js"]
+skip-if = ["appname == 'thunderbird'"]
+
+["test_migratedFile.js"]
+skip-if = ["appname == 'thunderbird'"]