/* Any copyright is dedicated to the Public Domain.
* http : //creativecommons.org/publicdomain/zero/1.0/
*/
"use strict" ;
const { TabUnloader } = ChromeUtils.importESModule(
"moz-src:///browser/components/tabbrowser/TabUnloader.sys.mjs"
);
let TestTabUnloaderMethods = {
isNonDiscardable(tab, weight) {
return /\bselected\b/.test(tab.keywords) ? weight : 0 ;
},
isParentProcess(tab, weight) {
return /\bparent\b/.test(tab.keywords) ? weight : 0 ;
},
isPinned(tab, weight) {
return /\bpinned\b/.test(tab.keywords) ? weight : 0 ;
},
isLoading(tab, weight) {
return /\bloading\b/.test(tab.keywords) ? weight : 0 ;
},
usingPictureInPicture(tab, weight) {
return /\bpictureinpicture\b/.test(tab.keywords) ? weight : 0 ;
},
playingMedia(tab, weight) {
return /\bmedia\b/.test(tab.keywords) ? weight : 0 ;
},
usingWebRTC(tab, weight) {
return /\bwebrtc\b/.test(tab.keywords) ? weight : 0 ;
},
isPrivate(tab, weight) {
return /\bprivate\b/.test(tab.keywords) ? weight : 0 ;
},
getMinTabCount() {
// Use a low number for testing.
return 3 ;
},
getNow() {
return 100 ;
},
*iterateProcesses(tab) {
for (let process of tab.process.split("," )) {
yield Number(process);
}
},
async calculateMemoryUsage(processMap, tabs) {
let memory = tabs[0 ].memory;
for (let pid of processMap.keys()) {
processMap.get(pid).memory = memory ? memory[pid - 1 ] : 1 ;
}
},
};
let unloadTests = [
// Each item in the array represents one test. The test is a subarray
// containing an element per tab. This is a string of keywords that
// identify which criteria apply. The first part of the string may contain
// a number that represents the last visit time, where higher numbers
// are later. The last element in the subarray is special and identifies
// the expected order of the tabs sorted by weight. The first tab in
// this list is the one that is expected to selected to be discarded.
{ tabs: ["1 selected" , "2" , "3" ], result: "1,2,0" },
{ tabs: ["1" , "2 selected" , "3" ], result: "0,2,1" },
{ tabs: ["1 selected" , "2" , "3" ], process: ["1" , "2" , "3" ], result: "1,2,0" },
{
tabs: ["1 selected" , "2 selected" , "3 selected" ],
process: ["1" , "2" , "3" ],
result: "0,1,2" ,
},
{
tabs: ["1 selected" , "2" , "3" ],
process: ["1,2,3" , "2" , "3" ],
result: "1,2,0" ,
},
{
tabs: ["9" , "8" , "6" , "5 selected" , "2" , "3" , "4" , "1" ],
result: "7,4,5,6,2,1,0,3" ,
},
{
tabs: ["9" , "8 pinned" , "6" , "5 selected" , "2" , "3 pinned" , "4" , "1" ],
result: "7,4,6,2,0,5,1,3" ,
},
{
tabs: [
"9" ,
"8 pinned" ,
"6" ,
"5 selected pinned" ,
"2" ,
"3 pinned" ,
"4" ,
"1" ,
],
result: "7,4,6,2,0,5,1,3" ,
},
{
tabs: [
"9" ,
"8 pinned" ,
"6" ,
"5 selected pinned" ,
"2" ,
"3 selected pinned" ,
"4" ,
"1" ,
],
result: "7,4,6,2,0,1,5,3" ,
},
{
tabs: ["1" , "2 selected" , "3" , "4 media" , "5" , "6" ],
result: "0,2,4,5,1,3" ,
},
{
tabs: ["1 media" , "2 selected media" , "3" , "4 media" , "5" , "6" ],
result: "2,4,5,0,3,1" ,
},
{
tabs: ["1 media" , "2 media pinned" , "3" , "4 media" , "5 pinned" , "6" ],
result: "2,5,4,0,3,1" ,
},
{
tabs: [
"1 media" ,
"2 media pinned" ,
"3" ,
"4 media" ,
"5 media pinned" ,
"6 selected" ,
],
result: "2,0,3,5,1,4" ,
},
{
tabs: [
"10 selected" ,
"20 private" ,
"30 webrtc" ,
"40 pictureinpicture" ,
"50 loading pinned" ,
"60" ,
],
result: "5,4,0,1,2,3" ,
},
{
// Since TestTabUnloaderMethods.getNow() returns 100 and the test
// passes minInactiveDuration = 0 to TabUnloader.getSortedTabs(),
// tab 200 and 300 are excluded from the result.
tabs: ["300" , "10" , "50" , "100" , "200" ],
result: "1,2,3" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "1" , "1" , "1" , "1" ],
result: "1,0,2,3,4,5" ,
},
{
tabs: ["1" , "2 selected" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "1" , "1" , "1" , "1" ],
result: "0,2,3,4,5,1" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "2" , "1" , "1" , "1" ],
result: "0,1,2,3,4,5" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "3" , "1" , "1" , "1" ],
result: "1,0,2,3,4,5" ,
},
{
tabs: ["1" , "2 media" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "3" , "1" , "1" , "1" ],
result: "2,0,3,4,5,1" ,
},
{
tabs: ["1" , "2 media" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "3" , "1" , "1,2,3" , "1" ],
result: "0,2,3,4,5,1" ,
},
{
tabs: ["1" , "2 media" , "3" , "4" , "5" , "6" ],
process: ["1" , "2" , "3" , "1" , "1,4,5" , "1" ],
result: "2,0,3,4,5,1" ,
},
{
tabs: ["1" , "2 media" , "3 media" , "4" , "5 media" , "6" ],
process: ["1" , "2" , "3" , "1" , "1,4,5" , "1" ],
result: "0,3,5,1,2,4" ,
},
{
tabs: ["1" , "2 media" , "3 media" , "4" , "5 media" , "6" ],
process: ["1" , "1" , "3" , "1" , "1,4,5" , "1" ],
result: "0,3,5,1,2,4" ,
},
{
tabs: ["1" , "2 media" , "3 media" , "4" , "5 media" , "6" ],
process: ["1" , "2" , "3" , "4" , "1,4,5" , "5" ],
result: "0,3,5,1,2,4" ,
},
{
tabs: ["1" , "2 media" , "3 media" , "4" , "5 media" , "6" ],
process: ["1" , "1" , "3" , "4" , "1,4,5" , "5" ],
result: "0,3,5,1,2,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1" , "1" , "1" , "2" , "1,3,4,5,6,7,8" , "1" ],
result: "0,1,2,3,4,5" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "2" , "1,3,4,5,6,7,8" , "1" , "1" , "1" ],
result: "4,0,3,1,2,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 selected" , "6" ],
process: ["1" , "1" , "1" , "2" , "1,3,4,5,6,7,8" , "1" ],
result: "0,1,2,3,5,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" ],
process: ["1" , "1" , "1" , "2" , "1,3,4,5,6,7,8" , "1" ],
result: "0,1,2,3,5,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "2" , "1,3,4,5,6,7,8" , "1" , "1" , "1" ],
result: "0,3,1,2,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1,3,4,5,6,7,8" , "1" , "1" , "1" , "1" , "1" , "1" ],
result: "1,0,2,3,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1,3,4,5,6,7,8" , "1" , "1" , "1" , "1" , "1" ],
result: "2,0,1,3,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1,1,1,1,1,1,1" , "1" , "1" , "1" , "1,1,1,1,1" , "1" ],
result: "0,1,2,3,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1,2,3,4,5" , "1" , "1" , "1" , "1,2,3,4,5" , "1" ],
result: "0,1,2,3,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1,6" , "1" , "1" , "1" , "1,2,3,4,5" , "1" ],
result: "0,2,1,3,5,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1" , "1" , "1,6" , "1,7" , "1,8" , "1,9" , "1,2,3,4,5" , "1" ],
result: "2,3,0,5,1,6,7,4" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5 media" , "6" , "7" , "8" ],
process: ["1,10,11" , "1" , "1,2" , "1,7" , "1,8" , "1,9" , "1,2,3,4,5" , "1" ],
result: "0,3,1,5,2,6,7,4" ,
},
{
tabs: [
"1 media" ,
"2 media" ,
"3 media" ,
"4 media" ,
"5 media" ,
"6" ,
"7" ,
"8" ,
],
process: ["1,10,11" , "1" , "1,2" , "1,7" , "1,8" , "1,9" , "1,2,3,4,5" , "1" ],
result: "6,5,7,0,1,2,3,4" ,
},
{
tabs: ["1" , "2" , "3" ],
process: ["1" , "2" , "3" ],
memory: ["100" , "200" , "300" ],
result: "0,1,2" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
process: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
memory: [
"100" ,
"200" ,
"300" ,
"400" ,
"500" ,
"600" ,
"700" ,
"800" ,
"900" ,
"1000" ,
],
result: "0,1,2,3,4,5,6,7,8,9" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
process: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
memory: [
"100" ,
"900" ,
"300" ,
"500" ,
"400" ,
"700" ,
"600" ,
"1000" ,
"200" ,
"200" ,
],
result: "1,0,2,3,5,4,6,7,8,9" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
process: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" ],
memory: [
"1000" ,
"900" ,
"300" ,
"500" ,
"400" ,
"1000" ,
"600" ,
"1000" ,
"200" ,
"200" ,
],
result: "0,1,2,3,5,4,6,7,8,9" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1" , "2,7" , "3" , "4" , "5" , "6" ],
memory: ["100" , "200" , "300" , "400" , "500" , "600" , "700" ],
result: "1,0,2,3,4,5" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1,6" , "2,7" , "3,8" , "4,1,2" , "5" , "6" , "7" , "8" ],
memory: ["100" , "200" , "300" , "400" , "500" , "600" , "700" , "800" ],
result: "2,3,0,1,4,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "2" , "1" , "1" , "1" , "1" ],
memory: ["700" , "1000" ],
result: "0,3,1,2,4,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "1" , "2,1" , "2,1" , "3" , "3" ],
memory: ["1000" , "2000" , "3000" ],
result: "0,1,2,4,3,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["2" , "2" , "2" , "2" , "2,1" , "2,1" , "3" , "3" ],
memory: ["1000" , "600" , "1000" ],
result: "0,1,2,4,3,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "2" , "2,1,1,1" , "2,1" , "3" , "3" ],
memory: ["1000" , "1800" , "1000" ],
result: "0,1,3,2,4,5,6,7" ,
},
{
tabs: ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" ],
process: ["1" , "1" , "1" , "2" , "2,1,1,1" , "2,1" , "3" , "3" ],
memory: ["4000" , "1800" , "1000" ],
result: "0,1,2,4,3,5,6,7" ,
},
{
// The tab "1" contains 4 frames, but its uniqueCount is 1 because
// all of those frames are backed by the process "1". As a result,
// TabUnloader puts the tab "1" first based on the last access time.
tabs: ["1" , "2" , "3" , "4" , "5" ],
process: ["1,1,1,1" , "2" , "3" , "3" , "3" ],
memory: ["100" , "100" , "100" ],
result: "0,1,2,3,4" ,
},
{
// The uniqueCount of the tab "1", "2", and "3" is 1, 2, and 3,
// respectively. As a result the first three tabs are sorted as 2,1,0.
tabs: ["1" , "2" , "3" , "4" , "5" , "6" ],
process: ["1,7,1,7,1,1,7,1" , "7,3,7,2" , "4,5,7,4,6,7" , "7" , "7" , "7" ],
memory: ["100" , "100" , "100" , "100" , "100" , "100" , "100" ],
result: "2,1,0,3,4,5" ,
},
];
let globalBrowser = {
discardBrowser() {
return true ;
},
};
add_task(async function doTests() {
for (let test of unloadTests) {
function * iterateTabs() {
let tabs = test.tabs;
for (let t = 0 ; t < tabs.length; t++) {
let tab = {
tab: {
originalIndex: t,
lastAccessed: Number(/^[0 -9 ]+/.exec(tabs[t])[0 ]),
keywords: tabs[t],
process: "process" in test ? test.process[t] : "1" ,
},
memory: test.memory,
gBrowser: globalBrowser,
};
yield tab;
}
}
TestTabUnloaderMethods.iterateTabs = iterateTabs;
let expectedOrder = "" ;
const sortedTabs = await TabUnloader.getSortedTabs(
0 ,
TestTabUnloaderMethods
);
for (let tab of sortedTabs) {
if (expectedOrder) {
expectedOrder += "," ;
}
expectedOrder += tab.tab.originalIndex;
}
Assert .equal(expectedOrder, test.result);
}
});
Messung V0.5 in Prozent C=94 H=88 G=90