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.
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::utils::{server::TestServer, webdav::GenerateTestDavResource};
|
||||
|
||||
use ahash::AHashSet;
|
||||
use dav_proto::Depth;
|
||||
use groupware::DavResourceName;
|
||||
use hyper::StatusCode;
|
||||
|
||||
pub async fn test(test: &TestServer) {
|
||||
let client = test.account("[email protected]").webdav_client();
|
||||
|
||||
for resource_type in [
|
||||
DavResourceName::File,
|
||||
DavResourceName::Cal,
|
||||
DavResourceName::Card,
|
||||
] {
|
||||
println!(
|
||||
"Running REPORT sync-collection tests ({})...",
|
||||
resource_type.base_path()
|
||||
);
|
||||
let user_base_path = format!("{}/john%40example.com/", resource_type.base_path());
|
||||
|
||||
// Test 1: Initial sync
|
||||
let response = client
|
||||
.sync_collection(&user_base_path, "", Depth::Infinity, None, ["D:getetag"])
|
||||
.await;
|
||||
assert_eq!(
|
||||
response.hrefs().len(),
|
||||
if resource_type == DavResourceName::File {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
},
|
||||
"{:?}",
|
||||
response.hrefs()
|
||||
);
|
||||
let sync_token_1 = response.sync_token().to_string();
|
||||
|
||||
// Test 2: No changes since last sync
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token_1,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.hrefs(), Vec::<String>::new());
|
||||
|
||||
// Test 3: Create a collection and make sure it is synced
|
||||
let new_collection = format!("{}new-collection/", user_base_path);
|
||||
client
|
||||
.mkcol("MKCOL", &new_collection, [], [])
|
||||
.await
|
||||
.with_status(StatusCode::CREATED);
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token_1,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.hrefs(), vec![new_collection.clone()]);
|
||||
let sync_token_2 = response.sync_token().to_string();
|
||||
|
||||
// Test 4: Create a file and make sure it is synced
|
||||
let new_file = format!("{new_collection}new-file");
|
||||
let contents = resource_type.generate();
|
||||
client
|
||||
.request("PUT", &new_file, &contents)
|
||||
.await
|
||||
.with_status(StatusCode::CREATED);
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token_1,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(
|
||||
response.hrefs(),
|
||||
vec![new_collection.clone(), new_file.clone()]
|
||||
);
|
||||
let sync_token_3 = response.sync_token().to_string();
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token_2,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.hrefs(), vec![new_file.clone()]);
|
||||
|
||||
// Test 5: sync-token with Depth 1
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token_1,
|
||||
Depth::One,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.hrefs(), vec![new_collection.clone()]);
|
||||
|
||||
// Test 6: sync-token with Depth 0
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&new_collection,
|
||||
&sync_token_1,
|
||||
Depth::Zero,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.hrefs(), vec![new_collection.clone()]);
|
||||
|
||||
// Test 7: Outdated sync-token in If header should fail
|
||||
let new_file2 = format!("{new_collection}new-file2");
|
||||
let contents = resource_type.generate();
|
||||
let condition = format!("(<{sync_token_2}>)");
|
||||
client
|
||||
.request_with_headers(
|
||||
"PUT",
|
||||
&new_file2,
|
||||
[("if", condition.as_str())],
|
||||
contents.as_str(),
|
||||
)
|
||||
.await
|
||||
.with_status(StatusCode::PRECONDITION_FAILED)
|
||||
.with_empty_body();
|
||||
|
||||
// Test 8: Correct sync-token in If header should work
|
||||
let condition = format!("(<{sync_token_3}>)");
|
||||
client
|
||||
.request_with_headers(
|
||||
"PUT",
|
||||
&new_file2,
|
||||
[("if", condition.as_str())],
|
||||
contents.as_str(),
|
||||
)
|
||||
.await
|
||||
.with_status(StatusCode::CREATED)
|
||||
.with_empty_body();
|
||||
|
||||
// Test 9: Limit
|
||||
let mut sync_token = client
|
||||
.sync_collection(
|
||||
&new_collection,
|
||||
&sync_token_3,
|
||||
Depth::Zero,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await
|
||||
.sync_token()
|
||||
.to_string();
|
||||
let (folder_name, files) = client
|
||||
.create_hierarchy(user_base_path.trim_end_matches('/'), 1, 0, 10)
|
||||
.await;
|
||||
let mut expected_changes = files
|
||||
.iter()
|
||||
.map(|x| x.0.as_str())
|
||||
.chain([folder_name.as_str()])
|
||||
.collect::<AHashSet<_>>();
|
||||
for _ in 0..10 {
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token,
|
||||
Depth::Infinity,
|
||||
2.into(),
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
sync_token = response.sync_token().to_string();
|
||||
let hrefs = response.hrefs();
|
||||
if hrefs.is_empty() {
|
||||
break;
|
||||
}
|
||||
let mut has_user_base_path = false;
|
||||
let mut item_count = 0;
|
||||
for href in hrefs {
|
||||
if href == user_base_path {
|
||||
has_user_base_path = true;
|
||||
} else if expected_changes.remove(href) {
|
||||
item_count += 1;
|
||||
} else {
|
||||
panic!("Unexpected href: {href}");
|
||||
}
|
||||
}
|
||||
if has_user_base_path {
|
||||
assert_eq!(item_count, 2);
|
||||
response
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:status",
|
||||
"HTTP/1.1 507 Insufficient Storage",
|
||||
)
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:error.D:number-of-matches-within-limits",
|
||||
"",
|
||||
)
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:responsedescription",
|
||||
"The number of matches exceeds the limit of 2",
|
||||
);
|
||||
} else {
|
||||
assert!(item_count <= 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(expected_changes.is_empty(), "{:?}", expected_changes);
|
||||
|
||||
// Test 10: Expect changes after deletion
|
||||
client
|
||||
.request("DELETE", &new_file, "")
|
||||
.await
|
||||
.with_status(StatusCode::NO_CONTENT);
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
sync_token = response.sync_token().to_string();
|
||||
response
|
||||
.with_href_count(1)
|
||||
.with_value("D:multistatus.D:response.D:href", &new_file)
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:status",
|
||||
"HTTP/1.1 404 Not Found",
|
||||
);
|
||||
client
|
||||
.request("DELETE", &new_collection, "")
|
||||
.await
|
||||
.with_status(StatusCode::NO_CONTENT);
|
||||
let response = client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await;
|
||||
sync_token = response.sync_token().to_string();
|
||||
response
|
||||
.with_href_count(1)
|
||||
.with_value("D:multistatus.D:response.D:href", &new_collection)
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:status",
|
||||
"HTTP/1.1 404 Not Found",
|
||||
);
|
||||
client
|
||||
.request("DELETE", &folder_name, "")
|
||||
.await
|
||||
.with_status(StatusCode::NO_CONTENT);
|
||||
client
|
||||
.sync_collection(
|
||||
&user_base_path,
|
||||
&sync_token,
|
||||
Depth::Infinity,
|
||||
None,
|
||||
["D:getetag"],
|
||||
)
|
||||
.await
|
||||
.with_href_count(1)
|
||||
.with_value("D:multistatus.D:response.D:href", &folder_name)
|
||||
.with_value(
|
||||
"D:multistatus.D:response.D:status",
|
||||
"HTTP/1.1 404 Not Found",
|
||||
);
|
||||
}
|
||||
|
||||
client.delete_default_containers().await;
|
||||
test.assert_is_empty().await;
|
||||
}
|
||||
Reference in New Issue
Block a user