Revision control

Copy as Markdown

Other Tools

/* 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/. */
var { CalDAVServer } = ChromeUtils.importESModule(
);
var { DNS } = ChromeUtils.importESModule("resource:///modules/DNS.sys.mjs");
async function openWizard(...args) {
await CalendarTestUtils.openCalendarTab(window);
const wizardPromise = BrowserTestUtils.promiseAlertDialog(
undefined,
{
callback: wizardWindow => handleWizard(wizardWindow, ...args),
}
);
EventUtils.synthesizeMouseAtCenter(
document.querySelector("#newCalendarSidebarButton"),
{},
window
);
return wizardPromise;
}
async function handleWizard(wizardWindow, { username, url, password, expectedCalendars }) {
const wizardDocument = wizardWindow.document;
const acceptButton = wizardDocument.querySelector("dialog").getButton("accept");
const cancelButton = wizardDocument.querySelector("dialog").getButton("cancel");
// Select calendar type.
EventUtils.synthesizeMouseAtCenter(
wizardDocument.querySelector(`radio[value="network"]`),
{},
wizardWindow
);
EventUtils.synthesizeMouseAtCenter(acceptButton, {}, wizardWindow);
// Network calendar settings.
Assert.ok(acceptButton.disabled);
Assert.equal(wizardDocument.activeElement.id, "network-username-input");
if (username) {
EventUtils.sendString(username, wizardWindow);
}
if (username?.includes("@")) {
Assert.equal(
wizardDocument.getElementById("network-location-input").placeholder,
username.replace(/^.*@/, "")
);
}
EventUtils.synthesizeKey("VK_TAB", {}, wizardWindow);
Assert.equal(wizardDocument.activeElement.id, "network-location-input");
if (url) {
EventUtils.sendString(url, wizardWindow);
}
Assert.ok(!acceptButton.disabled);
const promptPromise = handlePasswordPrompt(password);
EventUtils.synthesizeKey("VK_RETURN", {}, wizardWindow);
await promptPromise;
// Select calendars.
const list = wizardDocument.getElementById("network-calendar-list");
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(list),
"waiting for calendar list to appear",
200,
100
);
Assert.equal(list.childElementCount, expectedCalendars.length);
for (let i = 0; i < expectedCalendars.length; i++) {
const item = list.children[i];
Assert.equal(item.calendar.uri.spec, expectedCalendars[i].uri);
Assert.equal(
item.querySelector(".calendar-color").style.backgroundColor,
expectedCalendars[i].color
);
Assert.equal(item.querySelector(".calendar-name").value, expectedCalendars[i].name);
if (expectedCalendars[i].hasOwnProperty("readOnly")) {
Assert.equal(
item.calendar.readOnly,
expectedCalendars[i].readOnly,
`calendar read-only property is ${expectedCalendars[i].readOnly}`
);
}
}
EventUtils.synthesizeMouseAtCenter(cancelButton, {}, wizardWindow);
}
async function handlePasswordPrompt(password) {
return BrowserTestUtils.promiseAlertDialog(null, undefined, {
async callback(prompt) {
await new Promise(resolve => prompt.setTimeout(resolve));
prompt.document.getElementById("password1Textbox").value = password;
const checkbox = prompt.document.getElementById("checkbox");
Assert.greater(checkbox.getBoundingClientRect().width, 0);
Assert.ok(checkbox.checked);
prompt.document.querySelector("dialog").getButton("accept").click();
},
});
}
/**
* Test that we correctly use DNS discovery. This uses the mochitest server
* (files in the data directory) instead of CalDAVServer because the latter
* can't speak HTTPS, and we only do DNS discovery for HTTPS.
*/
add_task(async function testDNS() {
var _srv = DNS.srv;
var _txt = DNS.txt;
DNS.srv = function (name) {
Assert.equal(name, "_caldavs._tcp.dnstest.invalid");
return [{ prio: 0, weight: 0, host: "example.org", port: 443 }];
};
DNS.txt = function (name) {
Assert.equal(name, "_caldavs._tcp.dnstest.invalid");
return [{ strings: ["path=/browser/comm/calendar/test/browser/data/dns.sjs"] }];
};
await openWizard({
username: "carol@dnstest.invalid",
password: "carol",
expectedCalendars: [
{
name: "You found me!",
color: "rgb(0, 128, 0)",
},
{
name: "Röda dagar",
color: "rgb(255, 0, 0)",
},
],
});
DNS.srv = _srv;
DNS.txt = _txt;
});
/**
* Test that the magic URL /.well-known/caldav works.
*/
add_task(async function testWellKnown() {
CalDAVServer.open("alice", "alice");
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
},
],
});
CalDAVServer.close();
});
/**
* Test that the magic URL /.well-known/caldav works, even if the server returns
* a 404 status for the resourcetype property (as done by iCloud.com).
* Verify successfull discovery, if current-user-principal and calendar-home-set
* are returned by the principal request.
*/
add_task(async function testWellKnown_noResourceType_earlyCalendarHomeSet() {
CalDAVServer.open("alice", "alice");
// Return a 404 status for the resourcetype property. Return a 200 status for
// current-user-principal and calendar-home-set. Implementation should then use
// the available calendar-home-set.
CalDAVServer.server.registerPathHandler("/principals/", (_request, response) => {
response.setStatusLine("1.1", 207, "Multi-Status");
response.setHeader("Content-Type", "text/xml");
response.write(
`<multistatus xmlns="DAV:">
<response>
<href>/principals/</href>
<propstat>
<prop>
<current-user-principal xmlns="DAV:">
<href>/principals/me/</href>
</current-user-principal>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
<href>/calendars/me/</href>
</calendar-home-set>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
<propstat>
<prop>
<resourcetype xmlns="DAV:"/>
</prop>
<status>HTTP/1.1 404 Not Found</status>
</propstat>
</response>
</multistatus>`.replace(/>\s+</g, "><")
);
});
// This should not be executed. Any empty response will cause the test to fail.
CalDAVServer.server.registerPathHandler("/principals/me/", () => {
Assert.report(
true,
undefined,
undefined,
"The current-user-principal (/principal/me/) returned by the /principal/ request should have been ignored, if a calendar-home-set was returned as well."
);
});
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
},
],
});
CalDAVServer.close();
});
/**
* Test that the magic URL /.well-known/caldav works, even if the server returns
* a 404 status for the resourcetype property (as done by iCloud.com).
* Verify successfull discovery, if only the current-user-principal is returned
* by the principal request.
*/
add_task(async function testWellKnown_noResourceType() {
CalDAVServer.open("alice", "alice");
// Return a 404 status for the resourcetype property. Return a 200 status for
// current-user-principal.
CalDAVServer.server.registerPathHandler("/principals/", (request, response) => {
response.setStatusLine("1.1", 207, "Multi-Status");
response.setHeader("Content-Type", "text/xml");
response.write(
`<multistatus xmlns="DAV:">
<response>
<href>/principals/</href>
<propstat>
<prop>
<current-user-principal xmlns="DAV:">
<href>/principals/me/</href>
</current-user-principal>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
<propstat>
<prop>
<resourcetype xmlns="DAV:"/>
</prop>
<status>HTTP/1.1 404 Not Found</status>
</propstat>
</response>
</multistatus>`.replace(/>\s+</g, "><")
);
});
// Return a 404 status for the resourcetype property. Return a 200 status for
// calendar-home-set.
CalDAVServer.server.registerPathHandler("/principals/me/", (request, response) => {
response.setStatusLine("1.1", 207, "Multi-Status");
response.setHeader("Content-Type", "text/xml");
response.write(
`<multistatus xmlns="DAV:">
<response>
<href>/principals/me/</href>
<propstat>
<prop>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
<href>/calendars/me/</href>
</calendar-home-set>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
<propstat>
<prop>
<resourcetype xmlns="DAV:"/>
</prop>
<status>HTTP/1.1 404 Not Found</status>
</propstat>
</response>
</multistatus>`.replace(/>\s+</g, "><")
);
});
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
},
],
});
CalDAVServer.close();
});
/**
* Tests calendars with only the "read" "current-user-privilege-set" are
* flagged read-only.
*/
add_task(async function testCalendarWithOnlyReadPriv() {
CalDAVServer.open("alice", "alice");
CalDAVServer.privileges = "<d:privilege><d:read/></d:privilege>";
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
readOnly: true,
},
],
});
CalDAVServer.close();
});
/**
* Tests calendars that return none of the expected values for "current-user-privilege-set"
* are flagged read-only.
*/
add_task(async function testCalendarWithoutPrivs() {
CalDAVServer.open("alice", "alice");
CalDAVServer.privileges = "";
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
readOnly: true,
},
],
});
CalDAVServer.close();
});
/**
* Tests calendars that return status 404 for "current-user-privilege-set" are
* not flagged read-only.
*/
add_task(async function testCalendarWithNoPrivSupport() {
CalDAVServer.open("alice", "alice");
CalDAVServer.privileges = null;
await openWizard({
username: "alice",
url: CalDAVServer.origin,
password: "alice",
expectedCalendars: [
{
uri: CalDAVServer.url,
name: "CalDAV Test",
color: "rgb(255, 128, 0)",
readOnly: false,
},
],
});
CalDAVServer.close();
});