Files
inbuxa-server/tests/src/webdav/mkcol.rs
T
jcoffey-dev 7dae9b29fd Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
2026-09-18 10:21:56 -07:00

294 lines
9.4 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use hyper::StatusCode;
use crate::webdav::{TEST_FILE_1, TEST_ICAL_1, TEST_VCARD_1, TEST_VTIMEZONE_1};
use crate::utils::server::TestServer;
pub async fn test(test: &TestServer) {
println!("Running MKCOL tests...");
let client = test.account("[email protected]").webdav_client();
// Creating collections in root elements is not allowed
for path in [
"/dav/file/test",
"/dav/card/test",
"/dav/cal/test",
"/dav/test",
] {
client
.request("MKCOL", path, "")
.await
.with_status(StatusCode::NOT_FOUND);
}
// Create collections using MKCOL (empty body)
for path in [
"/dav/file/john%40example.com/my-files",
"/dav/card/john%40example.com/my-cards",
"/dav/cal/john%40example.com/my-events",
] {
client
.request("MKCOL", path, "")
.await
.with_status(StatusCode::CREATED);
}
// Create resources under the newly created collections
for (path, content) in [
(
"/dav/file/john%40example.com/my-files/file1.txt",
TEST_FILE_1,
),
(
"/dav/card/john%40example.com/my-cards/card1.vcf",
TEST_VCARD_1,
),
(
"/dav/cal/john%40example.com/my-events/event1.ics",
TEST_ICAL_1,
),
] {
client
.request("PUT", path, content)
.await
.with_status(StatusCode::CREATED);
}
// Creating a collection on a mapped resource should fail
for path in [
"/dav/file/john%40example.com/my-files",
"/dav/card/john%40example.com/my-cards",
"/dav/cal/john%40example.com/my-events",
"/dav/file/john%40example.com/my-files/file1.txt",
"/dav/card/john%40example.com/my-cards/card1.vcf",
"/dav/cal/john%40example.com/my-events/event1.ics",
] {
client
.request("MKCOL", path, "")
.await
.with_status(StatusCode::METHOD_NOT_ALLOWED);
}
// Creating a sub-collections is allowed in FileDAV but in CalDAV and CardDAV
for (path, expected_status) in [
(
"/dav/file/john%40example.com/my-files/my-sub-files",
StatusCode::CREATED,
),
(
"/dav/card/john%40example.com/my-cards/my-sub-cards",
StatusCode::METHOD_NOT_ALLOWED,
),
(
"/dav/cal/john%40example.com/my-events/my-sub-events",
StatusCode::METHOD_NOT_ALLOWED,
),
] {
client
.request("MKCOL", path, "")
.await
.with_status(expected_status);
}
// Extended MKCOL with an unsupported resource types should fail
for (path, resource_type) in [
(
"/dav/file/john%40example.com/my-named-files",
"B:addressbook",
),
("/dav/card/john%40example.com/my-named-cards", "A:calendar"),
(
"/dav/cal/john%40example.com/my-named-events",
"B:addressbook",
),
] {
client
.mkcol("MKCOL", path, ["D:collection", resource_type], [])
.await
.with_status(StatusCode::FORBIDDEN)
.with_value(
"D:mkcol-response.D:propstat.D:error.D:valid-resourcetype",
"",
)
.with_value("D:mkcol-response.D:propstat.D:prop.D:resourcetype", "");
}
// Create using extended MKCOL
for (path, expected_properties, resource_types) in [
(
"/dav/file/john%40example.com/my-named-files/",
[("D:displayname", "Named Files")].as_slice(),
["D:collection"].as_slice(),
),
(
"/dav/card/john%40example.com/my-named-cards/",
[
("D:displayname", "Named Cards"),
("B:addressbook-description", "Some amazing contacts"),
]
.as_slice(),
["D:collection", "B:addressbook"].as_slice(),
),
(
"/dav/cal/john%40example.com/my-named-events/",
[
("D:displayname", "Named Events"),
("A:calendar-description", "Some amazing events"),
(
"A:calendar-timezone",
&TEST_VTIMEZONE_1.replace("\n", "\r\n"),
),
]
.as_slice(),
["D:collection", "A:calendar"].as_slice(),
),
] {
let response = client
.mkcol(
"MKCOL",
path,
resource_types.iter().copied(),
expected_properties.iter().copied(),
)
.await
.with_status(StatusCode::CREATED)
.into_propfind_response("D:mkcol-response".into());
let properties = response.properties("");
for (property, _) in expected_properties {
properties
.get(property)
.with_status(StatusCode::OK)
.with_values([""]);
}
// Check the properties of the created collection
let response = client
.propfind(path, expected_properties.iter().map(|x| x.0))
.await;
let properties = response.properties(path);
for (property, value) in expected_properties {
properties
.get(property)
.with_status(StatusCode::OK)
.with_values([*value]);
}
}
// Test MKCALENDAR
client
.mkcol(
"MKCALENDAR",
"/dav/cal/john%40example.com/my-named-events2",
[],
[
("D:displayname", "Named Events 2"),
("A:calendar-description", ""),
],
)
.await
.with_status(StatusCode::CREATED)
.with_value("A:mkcalendar-response.D:propstat.D:prop.D:displayname", "")
.with_values(
"A:mkcalendar-response.D:propstat.D:status",
["HTTP/1.1 200 OK"],
);
client
.mkcol(
"MKCALENDAR",
"/dav/cal/john%40example.com/my-named-events3",
[],
[
("D:displayname", "Named Events 3"),
(
"A:supported-calendar-component-set",
"<A:comp name=\"VEVENT\"/><A:comp name=\"VTODO\"/>",
),
],
)
.await
.with_status(StatusCode::CREATED)
.with_value("A:mkcalendar-response.D:propstat.D:prop.D:displayname", "")
.with_values(
"A:mkcalendar-response.D:propstat.D:status",
["HTTP/1.1 200 OK"],
);
// Check the properties of the created calendars
client
.propfind(
"/dav/cal/john%40example.com/my-named-events2/",
["A:supported-calendar-component-set"],
)
.await
.properties("/dav/cal/john%40example.com/my-named-events2/")
.get("A:supported-calendar-component-set")
.with_status(StatusCode::OK)
.with_values([
"A:comp.[name]:VJOURNAL",
"A:comp.[name]:VTIMEZONE",
"A:comp.[name]:VAVAILABILITY",
"A:comp.[name]:VALARM",
"A:comp.[name]:VRESOURCE",
"A:comp.[name]:AVAILABLE",
"A:comp.[name]:VTODO",
"A:comp.[name]:VFREEBUSY",
"A:comp.[name]:VEVENT",
"A:comp.[name]:STANDARD",
"A:comp.[name]:DAYLIGHT",
"A:comp.[name]:VLOCATION",
"A:comp.[name]:PARTICIPANT",
]);
client
.propfind(
"/dav/cal/john%40example.com/my-named-events3/",
["A:supported-calendar-component-set"],
)
.await
.properties("/dav/cal/john%40example.com/my-named-events3/")
.get("A:supported-calendar-component-set")
.with_status(StatusCode::OK)
.with_values(["A:comp.[name]:VEVENT", "A:comp.[name]:VTODO"]);
// Resource names arriving through the URI are echoed back verbatim
for name in ["My%20Folder", "file(1)+a:b", "%C3%9Cnterlagen", "Q&A"] {
let path = format!("/dav/file/john%40example.com/{name}");
let href = format!("{path}/");
client
.request("MKCOL", &path, "")
.await
.with_status(StatusCode::CREATED);
client
.propfind(&path, ["D:getetag"])
.await
.with_hrefs([href.as_str()]);
}
// Delete everything
for path in [
"/dav/file/john%40example.com/My%20Folder",
"/dav/file/john%40example.com/file(1)+a:b",
"/dav/file/john%40example.com/%C3%9Cnterlagen",
"/dav/file/john%40example.com/Q&A",
"/dav/file/john%40example.com/my-files",
"/dav/card/john%40example.com/my-cards",
"/dav/cal/john%40example.com/my-events",
"/dav/file/john%40example.com/my-named-files",
"/dav/card/john%40example.com/my-named-cards",
"/dav/cal/john%40example.com/my-named-events",
"/dav/cal/john%40example.com/my-named-events2",
"/dav/cal/john%40example.com/my-named-events3",
] {
client
.request("DELETE", path, "")
.await
.with_status(StatusCode::NO_CONTENT);
}
client.delete_default_containers().await;
test.assert_is_empty().await;
}