1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/
6 const { TabUnloader } = ChromeUtils.importESModule(
7 "resource:///modules/TabUnloader.sys.mjs"
10 let TestTabUnloaderMethods = {
11 isNonDiscardable(tab, weight) {
12 return /\bselected\b/.test(tab.keywords) ? weight : 0;
15 isParentProcess(tab, weight) {
16 return /\bparent\b/.test(tab.keywords) ? weight : 0;
19 isPinned(tab, weight) {
20 return /\bpinned\b/.test(tab.keywords) ? weight : 0;
23 isLoading(tab, weight) {
24 return /\bloading\b/.test(tab.keywords) ? weight : 0;
27 usingPictureInPicture(tab, weight) {
28 return /\bpictureinpicture\b/.test(tab.keywords) ? weight : 0;
31 playingMedia(tab, weight) {
32 return /\bmedia\b/.test(tab.keywords) ? weight : 0;
35 usingWebRTC(tab, weight) {
36 return /\bwebrtc\b/.test(tab.keywords) ? weight : 0;
39 isPrivate(tab, weight) {
40 return /\bprivate\b/.test(tab.keywords) ? weight : 0;
44 // Use a low number for testing.
52 *iterateProcesses(tab) {
53 for (let process of tab.process.split(",")) {
54 yield Number(process);
58 async calculateMemoryUsage(processMap, tabs) {
59 let memory = tabs[0].memory;
60 for (let pid of processMap.keys()) {
61 processMap.get(pid).memory = memory ? memory[pid - 1] : 1;
67 // Each item in the array represents one test. The test is a subarray
68 // containing an element per tab. This is a string of keywords that
69 // identify which criteria apply. The first part of the string may contain
70 // a number that represents the last visit time, where higher numbers
71 // are later. The last element in the subarray is special and identifies
72 // the expected order of the tabs sorted by weight. The first tab in
73 // this list is the one that is expected to selected to be discarded.
74 { tabs: ["1 selected", "2", "3"], result: "1,2,0" },
75 { tabs: ["1", "2 selected", "3"], result: "0,2,1" },
76 { tabs: ["1 selected", "2", "3"], process: ["1", "2", "3"], result: "1,2,0" },
78 tabs: ["1 selected", "2 selected", "3 selected"],
79 process: ["1", "2", "3"],
83 tabs: ["1 selected", "2", "3"],
84 process: ["1,2,3", "2", "3"],
88 tabs: ["9", "8", "6", "5 selected", "2", "3", "4", "1"],
89 result: "7,4,5,6,2,1,0,3",
92 tabs: ["9", "8 pinned", "6", "5 selected", "2", "3 pinned", "4", "1"],
93 result: "7,4,6,2,0,5,1,3",
106 result: "7,4,6,2,0,5,1,3",
119 result: "7,4,6,2,0,1,5,3",
122 tabs: ["1", "2 selected", "3", "4 media", "5", "6"],
123 result: "0,2,4,5,1,3",
126 tabs: ["1 media", "2 selected media", "3", "4 media", "5", "6"],
127 result: "2,4,5,0,3,1",
130 tabs: ["1 media", "2 media pinned", "3", "4 media", "5 pinned", "6"],
131 result: "2,5,4,0,3,1",
142 result: "2,0,3,5,1,4",
149 "40 pictureinpicture",
153 result: "5,4,0,1,2,3",
156 // Since TestTabUnloaderMethods.getNow() returns 100 and the test
157 // passes minInactiveDuration = 0 to TabUnloader.getSortedTabs(),
158 // tab 200 and 300 are excluded from the result.
159 tabs: ["300", "10", "50", "100", "200"],
163 tabs: ["1", "2", "3", "4", "5", "6"],
164 process: ["1", "2", "1", "1", "1", "1"],
165 result: "1,0,2,3,4,5",
168 tabs: ["1", "2 selected", "3", "4", "5", "6"],
169 process: ["1", "2", "1", "1", "1", "1"],
170 result: "0,2,3,4,5,1",
173 tabs: ["1", "2", "3", "4", "5", "6"],
174 process: ["1", "2", "2", "1", "1", "1"],
175 result: "0,1,2,3,4,5",
178 tabs: ["1", "2", "3", "4", "5", "6"],
179 process: ["1", "2", "3", "1", "1", "1"],
180 result: "1,0,2,3,4,5",
183 tabs: ["1", "2 media", "3", "4", "5", "6"],
184 process: ["1", "2", "3", "1", "1", "1"],
185 result: "2,0,3,4,5,1",
188 tabs: ["1", "2 media", "3", "4", "5", "6"],
189 process: ["1", "2", "3", "1", "1,2,3", "1"],
190 result: "0,2,3,4,5,1",
193 tabs: ["1", "2 media", "3", "4", "5", "6"],
194 process: ["1", "2", "3", "1", "1,4,5", "1"],
195 result: "2,0,3,4,5,1",
198 tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
199 process: ["1", "2", "3", "1", "1,4,5", "1"],
200 result: "0,3,5,1,2,4",
203 tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
204 process: ["1", "1", "3", "1", "1,4,5", "1"],
205 result: "0,3,5,1,2,4",
208 tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
209 process: ["1", "2", "3", "4", "1,4,5", "5"],
210 result: "0,3,5,1,2,4",
213 tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
214 process: ["1", "1", "3", "4", "1,4,5", "5"],
215 result: "0,3,5,1,2,4",
218 tabs: ["1", "2", "3", "4", "5", "6"],
219 process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
220 result: "0,1,2,3,4,5",
223 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
224 process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1", "1", "1"],
225 result: "4,0,3,1,2,5,6,7",
228 tabs: ["1", "2", "3", "4", "5 selected", "6"],
229 process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
230 result: "0,1,2,3,5,4",
233 tabs: ["1", "2", "3", "4", "5 media", "6"],
234 process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
235 result: "0,1,2,3,5,4",
238 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
239 process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1", "1", "1"],
240 result: "0,3,1,2,5,6,7,4",
243 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
244 process: ["1", "1,3,4,5,6,7,8", "1", "1", "1", "1", "1", "1"],
245 result: "1,0,2,3,5,6,7,4",
248 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
249 process: ["1", "1", "1,3,4,5,6,7,8", "1", "1", "1", "1", "1"],
250 result: "2,0,1,3,5,6,7,4",
253 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
254 process: ["1", "1", "1,1,1,1,1,1,1", "1", "1", "1", "1,1,1,1,1", "1"],
255 result: "0,1,2,3,5,6,7,4",
258 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
259 process: ["1", "1", "1,2,3,4,5", "1", "1", "1", "1,2,3,4,5", "1"],
260 result: "0,1,2,3,5,6,7,4",
263 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
264 process: ["1", "1", "1,6", "1", "1", "1", "1,2,3,4,5", "1"],
265 result: "0,2,1,3,5,6,7,4",
268 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
269 process: ["1", "1", "1,6", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
270 result: "2,3,0,5,1,6,7,4",
273 tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
274 process: ["1,10,11", "1", "1,2", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
275 result: "0,3,1,5,2,6,7,4",
288 process: ["1,10,11", "1", "1,2", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
289 result: "6,5,7,0,1,2,3,4",
292 tabs: ["1", "2", "3"],
293 process: ["1", "2", "3"],
294 memory: ["100", "200", "300"],
298 tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
299 process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
312 result: "0,1,2,3,4,5,6,7,8,9",
315 tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
316 process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
329 result: "1,0,2,3,5,4,6,7,8,9",
332 tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
333 process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
346 result: "0,1,2,3,5,4,6,7,8,9",
349 tabs: ["1", "2", "3", "4", "5", "6"],
350 process: ["1", "2,7", "3", "4", "5", "6"],
351 memory: ["100", "200", "300", "400", "500", "600", "700"],
352 result: "1,0,2,3,4,5",
355 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
356 process: ["1,6", "2,7", "3,8", "4,1,2", "5", "6", "7", "8"],
357 memory: ["100", "200", "300", "400", "500", "600", "700", "800"],
358 result: "2,3,0,1,4,5,6,7",
361 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
362 process: ["1", "1", "1", "2", "1", "1", "1", "1"],
363 memory: ["700", "1000"],
364 result: "0,3,1,2,4,5,6,7",
367 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
368 process: ["1", "1", "1", "1", "2,1", "2,1", "3", "3"],
369 memory: ["1000", "2000", "3000"],
370 result: "0,1,2,4,3,5,6,7",
373 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
374 process: ["2", "2", "2", "2", "2,1", "2,1", "3", "3"],
375 memory: ["1000", "600", "1000"],
376 result: "0,1,2,4,3,5,6,7",
379 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
380 process: ["1", "1", "1", "2", "2,1,1,1", "2,1", "3", "3"],
381 memory: ["1000", "1800", "1000"],
382 result: "0,1,3,2,4,5,6,7",
385 tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
386 process: ["1", "1", "1", "2", "2,1,1,1", "2,1", "3", "3"],
387 memory: ["4000", "1800", "1000"],
388 result: "0,1,2,4,3,5,6,7",
391 // The tab "1" contains 4 frames, but its uniqueCount is 1 because
392 // all of those frames are backed by the process "1". As a result,
393 // TabUnloader puts the tab "1" first based on the last access time.
394 tabs: ["1", "2", "3", "4", "5"],
395 process: ["1,1,1,1", "2", "3", "3", "3"],
396 memory: ["100", "100", "100"],
400 // The uniqueCount of the tab "1", "2", and "3" is 1, 2, and 3,
401 // respectively. As a result the first three tabs are sorted as 2,1,0.
402 tabs: ["1", "2", "3", "4", "5", "6"],
403 process: ["1,7,1,7,1,1,7,1", "7,3,7,2", "4,5,7,4,6,7", "7", "7", "7"],
404 memory: ["100", "100", "100", "100", "100", "100", "100"],
405 result: "2,1,0,3,4,5",
409 let globalBrowser = {
415 add_task(async function doTests() {
416 for (let test of unloadTests) {
417 function* iterateTabs() {
418 let tabs = test.tabs;
419 for (let t = 0; t < tabs.length; t++) {
423 lastAccessed: Number(/^[0-9]+/.exec(tabs[t])[0]),
425 process: "process" in test ? test.process[t] : "1",
428 gBrowser: globalBrowser,
433 TestTabUnloaderMethods.iterateTabs = iterateTabs;
435 let expectedOrder = "";
436 const sortedTabs = await TabUnloader.getSortedTabs(
438 TestTabUnloaderMethods
440 for (let tab of sortedTabs) {
442 expectedOrder += ",";
444 expectedOrder += tab.tab.originalIndex;
447 Assert.equal(expectedOrder, test.result);