Bug 1851536 - Test the quota status bar panel and the folder properties dialog quota tab. r=mkmelin
This includes an incomplete implementation of RFC 2087 for the IMAP fakeserver, and resurrecting a long-dead function in nsImapIncomingServer which should make future tests involving IMAP a bit easier to write. Differential Revision: https://phabricator.services.mozilla.com/D194174 --HG-- extra : rebase_source : e70724b757af11fbb90b3881975eb7a3467cee5c extra : amend_source : 3cc8117ce9a674c6edd08bbb35f249ddc3ac465e
This commit is contained in:
Родитель
244dff4ca8
Коммит
b3bcc45f50
|
@ -674,7 +674,7 @@ function openActivityMgr() {
|
||||||
function openFolderQuota() {
|
function openFolderQuota() {
|
||||||
document
|
document
|
||||||
.getElementById("tabmail")
|
.getElementById("tabmail")
|
||||||
.currentAbout3Pane?.folderPane.editFolder("QuotaTab");
|
.currentAbout3Pane?.folderPane.editFolder(undefined, "QuotaTab");
|
||||||
}
|
}
|
||||||
|
|
||||||
function openIMAccountMgr() {
|
function openIMAccountMgr() {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
const {
|
const {
|
||||||
IMAP_GMAIL_extension,
|
IMAP_GMAIL_extension,
|
||||||
|
IMAP_RFC2087_extension,
|
||||||
IMAP_RFC2197_extension,
|
IMAP_RFC2197_extension,
|
||||||
IMAP_RFC2342_extension,
|
IMAP_RFC2342_extension,
|
||||||
IMAP_RFC3348_extension,
|
IMAP_RFC3348_extension,
|
||||||
|
@ -108,3 +109,32 @@ export class GmailServer extends IMAPServer {
|
||||||
this.testScope.registerCleanupFunction(() => this.close());
|
this.testScope.registerCleanupFunction(() => this.close());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple IMAP server, with RFC2087 extension, for testing purposes.
|
||||||
|
*/
|
||||||
|
export class QuotaServer extends IMAPServer {
|
||||||
|
open() {
|
||||||
|
this.daemon = new ImapDaemon();
|
||||||
|
this.server = new nsMailServer(daemon => {
|
||||||
|
const handler = new IMAP_RFC3501_handler(daemon, {
|
||||||
|
username: this.username,
|
||||||
|
});
|
||||||
|
mixinExtension(handler, IMAP_RFC2087_extension);
|
||||||
|
return handler;
|
||||||
|
}, this.daemon);
|
||||||
|
this.server.start();
|
||||||
|
|
||||||
|
this.testScope.registerCleanupFunction(() => this.close());
|
||||||
|
}
|
||||||
|
|
||||||
|
setQuota(folder, name, usage, limit) {
|
||||||
|
const mailbox = this.daemon.getMailbox(folder.name);
|
||||||
|
mailbox.quota = mailbox.quota ?? {};
|
||||||
|
if (limit) {
|
||||||
|
mailbox.quota[name] = { usage, limit };
|
||||||
|
} else {
|
||||||
|
delete mailbox.quota[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ skip-if = headless
|
||||||
[browser_paneFocus.js]
|
[browser_paneFocus.js]
|
||||||
[browser_paneSplitter.js]
|
[browser_paneSplitter.js]
|
||||||
[browser_preferDisplayName.js]
|
[browser_preferDisplayName.js]
|
||||||
|
[browser_quota.js]
|
||||||
[browser_searchBar.js]
|
[browser_searchBar.js]
|
||||||
[browser_searchMessages.js]
|
[browser_searchMessages.js]
|
||||||
[browser_spacesToolbar.js]
|
[browser_spacesToolbar.js]
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
const { QuotaServer } = ChromeUtils.importESModule(
|
||||||
|
"resource://testing-common/IMAPServer.sys.mjs"
|
||||||
|
);
|
||||||
|
|
||||||
|
let imapServer;
|
||||||
|
|
||||||
|
const tabmail = document.getElementById("tabmail");
|
||||||
|
const about3Pane = tabmail.currentAbout3Pane;
|
||||||
|
let imapRootFolder, imapFolder;
|
||||||
|
|
||||||
|
add_setup(async function () {
|
||||||
|
// This test uses a single IMAP connection so that we can be sure it is idle
|
||||||
|
// before using it.
|
||||||
|
Services.prefs.setIntPref("mail.server.default.max_cached_connections", 1);
|
||||||
|
imapServer = new QuotaServer(this);
|
||||||
|
|
||||||
|
const imapAccount = MailServices.accounts.createAccount();
|
||||||
|
imapAccount.addIdentity(MailServices.accounts.createIdentity());
|
||||||
|
imapAccount.incomingServer = MailServices.accounts.createIncomingServer(
|
||||||
|
`${imapAccount.key}user`,
|
||||||
|
"localhost",
|
||||||
|
"imap"
|
||||||
|
);
|
||||||
|
imapAccount.incomingServer.port = imapServer.port;
|
||||||
|
imapAccount.incomingServer.username = "user";
|
||||||
|
imapAccount.incomingServer.password = "password";
|
||||||
|
imapAccount.incomingServer.deleteModel = Ci.nsMsgImapDeleteModels.IMAPDelete;
|
||||||
|
imapRootFolder = imapAccount.incomingServer.rootFolder;
|
||||||
|
imapFolder = imapRootFolder
|
||||||
|
.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox)
|
||||||
|
.QueryInterface(Ci.nsIMsgImapMailFolder);
|
||||||
|
|
||||||
|
registerCleanupFunction(() => {
|
||||||
|
MailServices.accounts.removeAccount(imapAccount, false);
|
||||||
|
Services.prefs.clearUserPref("mail.server.default.max_cached_connections");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function () {
|
||||||
|
const quotaPanel = document.getElementById("quotaPanel");
|
||||||
|
|
||||||
|
// Load the folder with no quota.
|
||||||
|
|
||||||
|
about3Pane.displayFolder(imapFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
// Reload the folder with usage below mail.quota.mainwindow_threshold.show.
|
||||||
|
|
||||||
|
about3Pane.displayFolder(imapRootFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
await updateQuota(20, 123);
|
||||||
|
about3Pane.displayFolder(imapFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
// Reload the folder with usage above mail.quota.mainwindow_threshold.show
|
||||||
|
// but below mail.quota.mainwindow_threshold.warning.
|
||||||
|
|
||||||
|
about3Pane.displayFolder(imapRootFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
await updateQuota(98, 123);
|
||||||
|
about3Pane.displayFolder(imapFolder);
|
||||||
|
checkStatus(79, "98.0 KB", "123 KB");
|
||||||
|
|
||||||
|
// Reload the folder with usage above mail.quota.mainwindow_threshold.warning
|
||||||
|
// but below mail.quota.mainwindow_threshold.critical.
|
||||||
|
|
||||||
|
about3Pane.displayFolder(imapRootFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
await updateQuota(105, 123);
|
||||||
|
about3Pane.displayFolder(imapFolder);
|
||||||
|
checkStatus(85, "105 KB", "123 KB", "alert-warning");
|
||||||
|
|
||||||
|
about3Pane.displayFolder(imapRootFolder);
|
||||||
|
Assert.ok(BrowserTestUtils.is_hidden(quotaPanel), "panel should be hidden");
|
||||||
|
|
||||||
|
// Reload the folder with usage above mail.quota.mainwindow_threshold.critical.
|
||||||
|
|
||||||
|
await updateQuota(120, 123);
|
||||||
|
about3Pane.displayFolder(imapFolder);
|
||||||
|
checkStatus(97, "120 KB", "123 KB", "alert-critical");
|
||||||
|
|
||||||
|
// Click on the status bar panel to open the folder properties dialog.
|
||||||
|
|
||||||
|
const folderPropsPromise = BrowserTestUtils.promiseAlertDialog(
|
||||||
|
undefined,
|
||||||
|
"chrome://messenger/content/folderProps.xhtml",
|
||||||
|
{
|
||||||
|
async callback(win) {
|
||||||
|
await SimpleTest.promiseFocus(win);
|
||||||
|
|
||||||
|
const doc = win.document;
|
||||||
|
const tabBox = doc.getElementById("folderPropTabBox");
|
||||||
|
const quotaStatus = doc.getElementById("folderQuotaStatus");
|
||||||
|
const quotaDetails = doc.getElementById("quotaDetails");
|
||||||
|
const cancelButton = doc.querySelector("dialog").getButton("cancel");
|
||||||
|
|
||||||
|
Assert.equal(
|
||||||
|
tabBox.selectedPanel.id,
|
||||||
|
"quotaPanel",
|
||||||
|
"quota panel should be selected"
|
||||||
|
);
|
||||||
|
await TestUtils.waitForCondition(
|
||||||
|
() => BrowserTestUtils.is_hidden(quotaStatus),
|
||||||
|
"waiting for quota UI to update"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
BrowserTestUtils.is_visible(quotaDetails),
|
||||||
|
"quota details should be visible"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
quotaDetails.childElementCount,
|
||||||
|
1,
|
||||||
|
"one quota should be displayed"
|
||||||
|
);
|
||||||
|
|
||||||
|
const li = quotaDetails.firstElementChild;
|
||||||
|
Assert.equal(li.querySelector("span").textContent, "STORAGE");
|
||||||
|
Assert.equal(li.querySelector("progress").value, 120);
|
||||||
|
Assert.equal(li.querySelector("progress").max, 123);
|
||||||
|
Assert.deepEqual(
|
||||||
|
document.l10n.getAttributes(li.querySelector("span:nth-child(3)")),
|
||||||
|
{ id: "quota-percent-used", args: { percent: 97 } }
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
li.querySelector("span:nth-child(4)").textContent,
|
||||||
|
"120 KB / 123 KB"
|
||||||
|
);
|
||||||
|
|
||||||
|
cancelButton.click();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(quotaPanel, {}, window);
|
||||||
|
await folderPropsPromise;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function updateQuota(usage, limit) {
|
||||||
|
// Drain the event queue so that the folder just displayed starts to use the
|
||||||
|
// IMAP connection.
|
||||||
|
await TestUtils.waitForTick();
|
||||||
|
await TestUtils.waitForCondition(() => {
|
||||||
|
try {
|
||||||
|
return imapFolder.server.numIdleConnections;
|
||||||
|
} catch (ex) {
|
||||||
|
console.error(ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}, "waiting for IMAP connection to become idle");
|
||||||
|
imapServer.setQuota(imapFolder, "STORAGE", usage, limit);
|
||||||
|
// Force the folder to be updated from the server.
|
||||||
|
await new Promise(resolve =>
|
||||||
|
imapFolder.updateFolderWithListener(window.msgWindow, {
|
||||||
|
OnStartRunningUrl() {},
|
||||||
|
OnStopRunningUrl() {
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
await TestUtils.waitForCondition(
|
||||||
|
() => imapFolder.getQuota().length == 1,
|
||||||
|
"waiting for the folder to have a quota"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkStatus(percent, usage, limit, className) {
|
||||||
|
const quotaPanel = document.getElementById("quotaPanel");
|
||||||
|
const quotaMeter = document.getElementById("quotaMeter");
|
||||||
|
const quotaLabel = document.getElementById("quotaLabel");
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
BrowserTestUtils.is_visible(quotaPanel),
|
||||||
|
"status bar panel should be visible"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
quotaMeter.value,
|
||||||
|
percent,
|
||||||
|
"meter should have the correct value"
|
||||||
|
);
|
||||||
|
Assert.equal(quotaMeter.max, 100, "meter should have the correct maximum");
|
||||||
|
Assert.deepEqual(
|
||||||
|
document.l10n.getAttributes(quotaLabel),
|
||||||
|
{
|
||||||
|
id: "quota-panel-percent-used",
|
||||||
|
args: { percent, usage, limit },
|
||||||
|
},
|
||||||
|
"label should have the correct text"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
quotaPanel.classList.contains("alert-warning"),
|
||||||
|
className == "alert-warning",
|
||||||
|
"panel should have the correct classes"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
quotaPanel.classList.contains("alert-critical"),
|
||||||
|
className == "alert-critical",
|
||||||
|
"panel should have the correct classes"
|
||||||
|
);
|
||||||
|
}
|
|
@ -73,6 +73,9 @@ interface nsIImapIncomingServer : nsISupports {
|
||||||
/// Max age of messages we will autosync to, or keep in offline store.
|
/// Max age of messages we will autosync to, or keep in offline store.
|
||||||
attribute long autoSyncMaxAgeDays;
|
attribute long autoSyncMaxAgeDays;
|
||||||
|
|
||||||
|
/** Count of non-busy connections in cache. */
|
||||||
|
readonly attribute long numIdleConnections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See IMAP RFC 6855
|
* See IMAP RFC 6855
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -62,7 +62,6 @@ class nsImapIncomingServer : public nsMsgIncomingServer,
|
||||||
NS_IMETHOD GetSearchScope(nsMsgSearchScopeValue* searchScope) override;
|
NS_IMETHOD GetSearchScope(nsMsgSearchScopeValue* searchScope) override;
|
||||||
NS_IMETHOD GetServerRequiresPasswordForBiff(
|
NS_IMETHOD GetServerRequiresPasswordForBiff(
|
||||||
bool* aServerRequiresPasswordForBiff) override;
|
bool* aServerRequiresPasswordForBiff) override;
|
||||||
NS_IMETHOD GetNumIdleConnections(int32_t* aNumIdleConnections);
|
|
||||||
NS_IMETHOD ForgetSessionPassword(bool modifyLogin) override;
|
NS_IMETHOD ForgetSessionPassword(bool modifyLogin) override;
|
||||||
NS_IMETHOD GetMsgFolderFromURI(nsIMsgFolder* aFolderResource,
|
NS_IMETHOD GetMsgFolderFromURI(nsIMsgFolder* aFolderResource,
|
||||||
const nsACString& aURI,
|
const nsACString& aURI,
|
||||||
|
|
|
@ -13,6 +13,7 @@ var EXPORTED_SYMBOLS = [
|
||||||
"IMAP_GMAIL_extension",
|
"IMAP_GMAIL_extension",
|
||||||
"IMAP_MOVE_extension",
|
"IMAP_MOVE_extension",
|
||||||
"IMAP_CUSTOM_extension",
|
"IMAP_CUSTOM_extension",
|
||||||
|
"IMAP_RFC2087_extension",
|
||||||
"IMAP_RFC2197_extension",
|
"IMAP_RFC2197_extension",
|
||||||
"IMAP_RFC2342_extension",
|
"IMAP_RFC2342_extension",
|
||||||
"IMAP_RFC3348_extension",
|
"IMAP_RFC3348_extension",
|
||||||
|
@ -2185,6 +2186,23 @@ var IMAP_CUSTOM_extension = {
|
||||||
kCapabilities: ["X-CUSTOM1"],
|
kCapabilities: ["X-CUSTOM1"],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RFC 2087: Quota (incomplete implementation)
|
||||||
|
var IMAP_RFC2087_extension = {
|
||||||
|
GETQUOTAROOT(args) {
|
||||||
|
const mailbox = this._daemon.getMailbox(args[0]);
|
||||||
|
const quota = mailbox.quota ?? {};
|
||||||
|
const response = [`* QUOTAROOT INBOX ""`];
|
||||||
|
for (const [name, { usage, limit }] of Object.entries(quota)) {
|
||||||
|
response.push(`* QUOTA "" (${name} ${usage} ${limit})`);
|
||||||
|
}
|
||||||
|
response.push("OK Getquota completed");
|
||||||
|
return response.join("\0");
|
||||||
|
},
|
||||||
|
kCapabilities: ["QUOTA"],
|
||||||
|
_argFormat: { GETQUOTAROOT: ["mailbox"] },
|
||||||
|
_enabledCommands: { 1: ["GETQUOTAROOT"], 2: ["GETQUOTAROOT"] },
|
||||||
|
};
|
||||||
|
|
||||||
// RFC 2197: ID
|
// RFC 2197: ID
|
||||||
var IMAP_RFC2197_extension = {
|
var IMAP_RFC2197_extension = {
|
||||||
ID(args) {
|
ID(args) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче