browser_UserContextManager.js (9052B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { UserContextManagerClass } = ChromeUtils.importESModule( 7 "chrome://remote/content/shared/UserContextManager.sys.mjs" 8 ); 9 10 add_task(async function test_invalid() { 11 const userContextManager = new UserContextManagerClass(); 12 13 // Check invalid types for hasUserContextId/getInternalIdById which expects 14 // a string. 15 for (const value of [null, undefined, 1, [], {}]) { 16 is(userContextManager.hasUserContextId(value), false); 17 is(userContextManager.getInternalIdById(value), null); 18 } 19 20 // Check an invalid value for hasUserContextId/getInternalIdById which expects 21 // either "default" or a UUID from Services.uuid.generateUUID. 22 is(userContextManager.hasUserContextId("foo"), false); 23 is(userContextManager.getInternalIdById("foo"), null); 24 25 // Check invalid types for getIdByInternalId which expects a number. 26 for (const value of [null, undefined, "foo", [], {}]) { 27 is(userContextManager.getIdByInternalId(value), null); 28 } 29 30 userContextManager.destroy(); 31 }); 32 33 add_task(async function test_default_context() { 34 const userContextManager = new UserContextManagerClass(); 35 ok( 36 userContextManager.hasUserContextId("default"), 37 `Context id default is known by the manager` 38 ); 39 ok( 40 userContextManager.getUserContextIds().includes("default"), 41 `Context id default is listed by the manager` 42 ); 43 is( 44 userContextManager.getInternalIdById("default"), 45 0, 46 "Default user context has the expected internal id" 47 ); 48 49 userContextManager.destroy(); 50 }); 51 52 add_task(async function test_new_internal_contexts() { 53 info("Create a new user context with ContextualIdentityService"); 54 const beforeInternalId = 55 ContextualIdentityService.create("before").userContextId; 56 57 info("Create the UserContextManager"); 58 const userContextManager = new UserContextManagerClass(); 59 60 const beforeContextId = 61 userContextManager.getIdByInternalId(beforeInternalId); 62 assertContextAvailable(userContextManager, beforeContextId, beforeInternalId); 63 64 info("Create another user context with ContextualIdentityService"); 65 const afterInternalId = 66 ContextualIdentityService.create("after").userContextId; 67 const afterContextId = userContextManager.getIdByInternalId(afterInternalId); 68 assertContextAvailable(userContextManager, afterContextId, afterInternalId); 69 70 info("Delete both user contexts"); 71 ContextualIdentityService.remove(beforeInternalId); 72 ContextualIdentityService.remove(afterInternalId); 73 assertContextRemoved(userContextManager, afterContextId, afterInternalId); 74 assertContextRemoved(userContextManager, beforeContextId, beforeInternalId); 75 76 userContextManager.destroy(); 77 }); 78 79 add_task(async function test_create_remove_context() { 80 const userContextManager = new UserContextManagerClass(); 81 82 for (const closeContextTabs of [true, false]) { 83 info("Create two contexts via createContext"); 84 const userContextId1 = userContextManager.createContext(); 85 const internalId1 = userContextManager.getInternalIdById(userContextId1); 86 assertContextAvailable(userContextManager, userContextId1); 87 88 const userContextId2 = userContextManager.createContext(); 89 const internalId2 = userContextManager.getInternalIdById(userContextId2); 90 assertContextAvailable(userContextManager, userContextId2); 91 92 info("Create tabs in various user contexts"); 93 const url = "https://example.com/document-builder.sjs?html=tab"; 94 const tabDefault = await addTab(gBrowser, url); 95 const tabContext1 = await addTab(gBrowser, url, { 96 userContextId: internalId1, 97 }); 98 const tabContext2 = await addTab(gBrowser, url, { 99 userContextId: internalId2, 100 }); 101 102 info("Remove the user context 1 via removeUserContext"); 103 userContextManager.removeUserContext(userContextId1, { closeContextTabs }); 104 105 assertContextRemoved(userContextManager, userContextId1, internalId1); 106 if (closeContextTabs) { 107 ok(!gBrowser.tabs.includes(tabContext1), "Tab context 1 is closed"); 108 } else { 109 ok(gBrowser.tabs.includes(tabContext1), "Tab context 1 is not closed"); 110 } 111 ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed"); 112 ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed"); 113 114 info("Remove the user context 2 via removeUserContext"); 115 userContextManager.removeUserContext(userContextId2, { closeContextTabs }); 116 assertContextRemoved(userContextManager, userContextId2, internalId2); 117 if (closeContextTabs) { 118 ok(!gBrowser.tabs.includes(tabContext2), "Tab context 2 is closed"); 119 } else { 120 ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed"); 121 } 122 ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed"); 123 } 124 125 userContextManager.destroy(); 126 }); 127 128 add_task(async function test_create_context_prefix() { 129 const userContextManager = new UserContextManagerClass(); 130 131 info("Create a context with a custom prefix via createContext"); 132 const userContextId = userContextManager.createContext("test_prefix"); 133 const internalId = userContextManager.getInternalIdById(userContextId); 134 const identity = 135 ContextualIdentityService.getPublicIdentityFromId(internalId); 136 ok( 137 identity.name.startsWith("test_prefix"), 138 "The new identity used the provided prefix" 139 ); 140 141 userContextManager.removeUserContext(userContextId); 142 userContextManager.destroy(); 143 }); 144 145 add_task(async function test_events() { 146 const manager = new UserContextManagerClass(); 147 const userContextCreatedEvents = []; 148 const userContextDeletedEvents = []; 149 manager.on("user-context-created", (name, data) => 150 userContextCreatedEvents.push(data) 151 ); 152 manager.on("user-context-deleted", (name, data) => 153 userContextDeletedEvents.push(data) 154 ); 155 156 const contextId1 = manager.createContext(); 157 is(userContextCreatedEvents.length, 1); 158 is(userContextCreatedEvents[0].userContextId, contextId1); 159 is(userContextDeletedEvents.length, 0); 160 161 manager.removeUserContext(contextId1); 162 is(userContextCreatedEvents.length, 1); 163 is(userContextDeletedEvents.length, 1); 164 is(userContextDeletedEvents[0].userContextId, contextId1); 165 166 manager.destroy(); 167 }); 168 169 add_task(async function test_several_managers() { 170 const manager1 = new UserContextManagerClass(); 171 const manager2 = new UserContextManagerClass(); 172 173 info("Create a context via manager1"); 174 const contextId1 = manager1.createContext(); 175 const internalId = manager1.getInternalIdById(contextId1); 176 assertContextUnknown(manager2, contextId1); 177 178 info("Retrieve the corresponding user context id in manager2"); 179 const contextId2 = manager2.getIdByInternalId(internalId); 180 is( 181 typeof contextId2, 182 "string", 183 "manager2 has a valid id for the user context created by manager 1" 184 ); 185 186 Assert.notEqual( 187 contextId1, 188 contextId2, 189 "manager1 and manager2 have different ids for the same internal context id" 190 ); 191 192 info("Remove the user context via manager2"); 193 manager2.removeUserContext(contextId2); 194 195 info("Check that the user context is removed from both managers"); 196 assertContextRemoved(manager1, contextId1, internalId); 197 assertContextRemoved(manager2, contextId2, internalId); 198 199 manager1.destroy(); 200 manager2.destroy(); 201 }); 202 203 function assertContextAvailable(manager, contextId, expectedInternalId = null) { 204 ok( 205 manager.getUserContextIds().includes(contextId), 206 `Context id ${contextId} is listed by the manager` 207 ); 208 ok( 209 manager.hasUserContextId(contextId), 210 `Context id ${contextId} is known by the manager` 211 ); 212 213 const internalId = manager.getInternalIdById(contextId); 214 if (expectedInternalId != null) { 215 is(internalId, expectedInternalId, "Internal id has the expected value"); 216 } 217 218 is( 219 typeof internalId, 220 "number", 221 `Context id ${contextId} corresponds to a valid internal id (${internalId})` 222 ); 223 is( 224 manager.getIdByInternalId(internalId), 225 contextId, 226 `Context id ${contextId} is returned for internal id ${internalId}` 227 ); 228 ok( 229 ContextualIdentityService.getPublicUserContextIds().includes(internalId), 230 `User context for context id ${contextId} is found by ContextualIdentityService` 231 ); 232 } 233 234 function assertContextUnknown(manager, contextId) { 235 ok( 236 !manager.getUserContextIds().includes(contextId), 237 `Context id ${contextId} is not listed by the manager` 238 ); 239 ok( 240 !manager.hasUserContextId(contextId), 241 `Context id ${contextId} is not known by the manager` 242 ); 243 is( 244 manager.getInternalIdById(contextId), 245 null, 246 `Context id ${contextId} does not match any internal id` 247 ); 248 } 249 250 function assertContextRemoved(manager, contextId, internalId) { 251 assertContextUnknown(manager, contextId); 252 is( 253 manager.getIdByInternalId(internalId), 254 null, 255 `Internal id ${internalId} cannot be converted to user context id` 256 ); 257 ok( 258 !ContextualIdentityService.getPublicUserContextIds().includes(internalId), 259 `Internal id ${internalId} is not found in ContextualIdentityService` 260 ); 261 }