/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { UserContextManagerClass } = ChromeUtils.importESModule( "chrome://remote/content/shared/UserContextManager.sys.mjs" ); add_task(async function test_invalid() { const userContextManager = new UserContextManagerClass(); // Check invalid types for hasUserContextId/getInternalIdById which expects // a string. for (const value of [null, undefined, 1, [], {}]) { is(userContextManager.hasUserContextId(value), false); is(userContextManager.getInternalIdById(value), null); } // Check an invalid value for hasUserContextId/getInternalIdById which expects // either "default" or a UUID from Services.uuid.generateUUID. is(userContextManager.hasUserContextId("foo"), false); is(userContextManager.getInternalIdById("foo"), null); // Check invalid types for getIdByInternalId which expects a number. for (const value of [null, undefined, "foo", [], {}]) { is(userContextManager.getIdByInternalId(value), null); } userContextManager.destroy(); }); add_task(async function test_default_context() { const userContextManager = new UserContextManagerClass(); ok( userContextManager.hasUserContextId("default"), `Context id default is known by the manager` ); ok( userContextManager.getUserContextIds().includes("default"), `Context id default is listed by the manager` ); is( userContextManager.getInternalIdById("default"), 0, "Default user context has the expected internal id" ); userContextManager.destroy(); }); add_task(async function test_new_internal_contexts() { info("Create a new user context with ContextualIdentityService"); const beforeInternalId = ContextualIdentityService.create("before").userContextId; info("Create the UserContextManager"); const userContextManager = new UserContextManagerClass(); const beforeContextId = userContextManager.getIdByInternalId(beforeInternalId); assertContextAvailable(userContextManager, beforeContextId, beforeInternalId); info("Create another user context with ContextualIdentityService"); const afterInternalId = ContextualIdentityService.create("after").userContextId; const afterContextId = userContextManager.getIdByInternalId(afterInternalId); assertContextAvailable(userContextManager, afterContextId, afterInternalId); info("Delete both user contexts"); ContextualIdentityService.remove(beforeInternalId); ContextualIdentityService.remove(afterInternalId); assertContextRemoved(userContextManager, afterContextId, afterInternalId); assertContextRemoved(userContextManager, beforeContextId, beforeInternalId); userContextManager.destroy(); }); add_task(async function test_create_remove_context() { const userContextManager = new UserContextManagerClass(); for (const closeContextTabs of [true, false]) { info("Create two contexts via createContext"); const userContextId1 = userContextManager.createContext(); const internalId1 = userContextManager.getInternalIdById(userContextId1); assertContextAvailable(userContextManager, userContextId1); const userContextId2 = userContextManager.createContext(); const internalId2 = userContextManager.getInternalIdById(userContextId2); assertContextAvailable(userContextManager, userContextId2); info("Create tabs in various user contexts"); const url = "https://example.com/document-builder.sjs?html=tab"; const tabDefault = await addTab(gBrowser, url); const tabContext1 = await addTab(gBrowser, url, { userContextId: internalId1, }); const tabContext2 = await addTab(gBrowser, url, { userContextId: internalId2, }); info("Remove the user context 1 via removeUserContext"); userContextManager.removeUserContext(userContextId1, { closeContextTabs }); assertContextRemoved(userContextManager, userContextId1, internalId1); if (closeContextTabs) { ok(!gBrowser.tabs.includes(tabContext1), "Tab context 1 is closed"); } else { ok(gBrowser.tabs.includes(tabContext1), "Tab context 1 is not closed"); } ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed"); ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed"); info("Remove the user context 2 via removeUserContext"); userContextManager.removeUserContext(userContextId2, { closeContextTabs }); assertContextRemoved(userContextManager, userContextId2, internalId2); if (closeContextTabs) { ok(!gBrowser.tabs.includes(tabContext2), "Tab context 2 is closed"); } else { ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed"); } ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed"); } userContextManager.destroy(); }); add_task(async function test_create_context_prefix() { const userContextManager = new UserContextManagerClass(); info("Create a context with a custom prefix via createContext"); const userContextId = userContextManager.createContext("test_prefix"); const internalId = userContextManager.getInternalIdById(userContextId); const identity = ContextualIdentityService.getPublicIdentityFromId(internalId); ok( identity.name.startsWith("test_prefix"), "The new identity used the provided prefix" ); userContextManager.removeUserContext(userContextId); userContextManager.destroy(); }); add_task(async function test_several_managers() { const manager1 = new UserContextManagerClass(); const manager2 = new UserContextManagerClass(); info("Create a context via manager1"); const contextId1 = manager1.createContext(); const internalId = manager1.getInternalIdById(contextId1); assertContextUnknown(manager2, contextId1); info("Retrieve the corresponding user context id in manager2"); const contextId2 = manager2.getIdByInternalId(internalId); is( typeof contextId2, "string", "manager2 has a valid id for the user context created by manager 1" ); Assert.notEqual( contextId1, contextId2, "manager1 and manager2 have different ids for the same internal context id" ); info("Remove the user context via manager2"); manager2.removeUserContext(contextId2); info("Check that the user context is removed from both managers"); assertContextRemoved(manager1, contextId1, internalId); assertContextRemoved(manager2, contextId2, internalId); manager1.destroy(); manager2.destroy(); }); function assertContextAvailable(manager, contextId, expectedInternalId = null) { ok( manager.getUserContextIds().includes(contextId), `Context id ${contextId} is listed by the manager` ); ok( manager.hasUserContextId(contextId), `Context id ${contextId} is known by the manager` ); const internalId = manager.getInternalIdById(contextId); if (expectedInternalId != null) { is(internalId, expectedInternalId, "Internal id has the expected value"); } is( typeof internalId, "number", `Context id ${contextId} corresponds to a valid internal id (${internalId})` ); is( manager.getIdByInternalId(internalId), contextId, `Context id ${contextId} is returned for internal id ${internalId}` ); ok( ContextualIdentityService.getPublicUserContextIds().includes(internalId), `User context for context id ${contextId} is found by ContextualIdentityService` ); } function assertContextUnknown(manager, contextId) { ok( !manager.getUserContextIds().includes(contextId), `Context id ${contextId} is not listed by the manager` ); ok( !manager.hasUserContextId(contextId), `Context id ${contextId} is not known by the manager` ); is( manager.getInternalIdById(contextId), null, `Context id ${contextId} does not match any internal id` ); } function assertContextRemoved(manager, contextId, internalId) { assertContextUnknown(manager, contextId); is( manager.getIdByInternalId(internalId), null, `Internal id ${internalId} cannot be converted to user context id` ); ok( !ContextualIdentityService.getPublicUserContextIds().includes(internalId), `Internal id ${internalId} is not found in ContextualIdentityService` ); }