summaryrefslogtreecommitdiffstats
path: root/remote/shared/test/browser/browser_UserContextManager.js
blob: cfae75dbe21094ef3f17c993ab06ac62dfc6a455 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* 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`
  );
}