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,680 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::utils::{jmap::JmapUtils, server::TestServer};
|
||||
use common::{
|
||||
auth::{ACCOUNT_IS_USER, EmailAddress, EmailCache},
|
||||
network::RcptResolution,
|
||||
};
|
||||
use jmap_proto::error::set::SetErrorType;
|
||||
use registry::{
|
||||
schema::{
|
||||
enums::{AccountType, StorageQuota},
|
||||
prelude::{ObjectType, Property},
|
||||
structs::{
|
||||
Account, CertificateManagement, Credential, DkimManagement, DnsManagement, Domain,
|
||||
EmailAlias, Expression, ExpressionMatch, GroupAccount, MailingList, PasswordCredential,
|
||||
SubAddressing, SubAddressingCustom, UserAccount,
|
||||
},
|
||||
},
|
||||
types::{EnumImpl, list::List, map::Map},
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use utils::map::vec_map::VecMap;
|
||||
|
||||
pub async fn test(test: &TestServer) {
|
||||
println!("Running Directory tests...");
|
||||
let account = test.account("[email protected]");
|
||||
|
||||
// Create a domain and make sure it's in the cache
|
||||
let domain_id = account
|
||||
.registry_create_object(Domain {
|
||||
name: "example.com".to_string(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
aliases: Map::new(vec!["beispiel.de".to_string()]),
|
||||
is_enabled: true,
|
||||
catch_all_address: Some("[email protected]".to_string()),
|
||||
sub_addressing: SubAddressing::Enabled,
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
let domain_cache = test
|
||||
.server
|
||||
.domain_by_id(domain_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
&domain_cache.names,
|
||||
&Box::from_iter(["example.com".into(), "beispiel.de".into()])
|
||||
);
|
||||
assert_eq!(domain_cache.id, domain_id.document_id());
|
||||
assert_eq!(
|
||||
domain_cache.catch_all.as_deref(),
|
||||
Some("[email protected]")
|
||||
);
|
||||
|
||||
// Multiple domains with the same name should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Domain {
|
||||
name: "example.com".to_string(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
|
||||
// An alias matching another domain's name should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Domain {
|
||||
name: "example.net".to_string(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
aliases: Map::new(vec!["example.com".to_string()]),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
|
||||
// An alias matching another domain's alias should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Domain {
|
||||
name: "example.net".to_string(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
aliases: Map::new(vec!["beispiel.de".to_string()]),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
|
||||
// A domain name matching another domain's alias should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Domain {
|
||||
name: "beispiel.de".to_string(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
|
||||
// Invalid local part should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Account::User(UserAccount {
|
||||
name: "!invalid".to_string(),
|
||||
domain_id,
|
||||
credentials: List::from_iter([Credential::Password(PasswordCredential {
|
||||
secret: "hello world".to_string(),
|
||||
..Default::default()
|
||||
})]),
|
||||
aliases: List::from_iter([EmailAlias {
|
||||
name: "inva..lid".to_string(),
|
||||
domain_id,
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
}]),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.assert_type(SetErrorType::InvalidPatch)
|
||||
.assert_description_contains("Invalid email local part");
|
||||
|
||||
// Valid account creation with local part sanitization
|
||||
let account_id = account
|
||||
.registry_create_object(Account::User(UserAccount {
|
||||
name: " john doe".to_string(),
|
||||
domain_id,
|
||||
description: "John 'Johnny-D' Doe".to_string().into(),
|
||||
credentials: List::from_iter([Credential::Password(PasswordCredential {
|
||||
secret: "hello world".to_string(),
|
||||
..Default::default()
|
||||
})]),
|
||||
aliases: List::from_iter([EmailAlias {
|
||||
name: "jdoe".to_string(),
|
||||
domain_id,
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
}]),
|
||||
quotas: VecMap::from_iter([
|
||||
(StorageQuota::MaxDiskQuota, 1024u64),
|
||||
(StorageQuota::MaxEmails, 100u64),
|
||||
]),
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
let account_cache = test.server.account(account_id.document_id()).await.unwrap();
|
||||
assert_eq!(account_cache.name.as_ref(), "[email protected]");
|
||||
assert_eq!(
|
||||
account_cache.description.as_deref(),
|
||||
Some("John 'Johnny-D' Doe")
|
||||
);
|
||||
assert_eq!(account_cache.id, account_id.document_id());
|
||||
assert_eq!(account_cache.quota_disk, 1024);
|
||||
assert_eq!(
|
||||
account_cache
|
||||
.quota_objects
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(StorageQuota::MaxEmails),
|
||||
100
|
||||
);
|
||||
assert_eq!(
|
||||
account_cache.addresses,
|
||||
vec![
|
||||
EmailAddress {
|
||||
local_part: "johndoe".into(),
|
||||
domain_id: domain_id.document_id(),
|
||||
},
|
||||
EmailAddress {
|
||||
local_part: "jdoe".into(),
|
||||
domain_id: domain_id.document_id(),
|
||||
}
|
||||
]
|
||||
.into_boxed_slice()
|
||||
);
|
||||
assert!(account_cache.flags & ACCOUNT_IS_USER != 0);
|
||||
|
||||
// Duplicate account names should not be allowed
|
||||
account
|
||||
.registry_create_object_expect_err(Account::User(UserAccount {
|
||||
name: "johndoe".to_string(),
|
||||
domain_id,
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
account
|
||||
.registry_create_object_expect_err(Account::User(UserAccount {
|
||||
name: "jdoe".to_string(),
|
||||
domain_id,
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
account
|
||||
.registry_create_object_expect_err(Account::Group(GroupAccount {
|
||||
name: "jdoe".to_string(),
|
||||
domain_id,
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
account
|
||||
.registry_create_object_expect_err(MailingList {
|
||||
name: "jdoe".to_string(),
|
||||
domain_id,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.assert_type(SetErrorType::PrimaryKeyViolation);
|
||||
|
||||
// Create a group and add it to the account
|
||||
let group_id = account
|
||||
.registry_create_object(Account::Group(GroupAccount {
|
||||
name: "sales".to_string(),
|
||||
domain_id,
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
let account_cache = test.server.account(group_id.document_id()).await.unwrap();
|
||||
assert_eq!(account_cache.name.as_ref(), "[email protected]");
|
||||
assert!(account_cache.flags & ACCOUNT_IS_USER == 0);
|
||||
account
|
||||
.registry_update_object(
|
||||
ObjectType::Account,
|
||||
account_id,
|
||||
json!({
|
||||
Property::MemberGroupIds: {
|
||||
group_id: true
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let account_cache = test.server.account(account_id.document_id()).await.unwrap();
|
||||
assert_eq!(
|
||||
account_cache.id_member_of.as_ref(),
|
||||
&[group_id.document_id()]
|
||||
);
|
||||
|
||||
// Linking invalid groups should not be allowed
|
||||
account
|
||||
.registry_update_object_expect_err(
|
||||
ObjectType::Account,
|
||||
account_id,
|
||||
json!({
|
||||
Property::MemberGroupIds: {
|
||||
account_id: true
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.assert_type(SetErrorType::InvalidForeignKey);
|
||||
|
||||
// Remove the group membership and make sure it's gone
|
||||
account
|
||||
.registry_update_object(
|
||||
ObjectType::Account,
|
||||
account_id,
|
||||
json!({
|
||||
Property::MemberGroupIds: {
|
||||
group_id: false
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let account_cache = test.server.account(account_id.document_id()).await.unwrap();
|
||||
assert!(account_cache.id_member_of.as_ref().is_empty());
|
||||
|
||||
// Create a masked email
|
||||
let john = crate::utils::account::Account::new(
|
||||
"[email protected]",
|
||||
"hello world",
|
||||
&[],
|
||||
"John",
|
||||
account_id,
|
||||
);
|
||||
let response = john
|
||||
.registry_create_many(
|
||||
ObjectType::MaskedEmail,
|
||||
[json!({
|
||||
Property::EmailPrefix: "test",
|
||||
})],
|
||||
)
|
||||
.await;
|
||||
let masked = response.created(0);
|
||||
let masked_id = masked.object_id();
|
||||
let masked_email = masked.text_field("email").to_string();
|
||||
assert_eq!(
|
||||
test.server
|
||||
.account_id_from_email("[email protected]", true)
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(account_id.document_id())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.account_id_from_email(&masked_email, true)
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(account_id.document_id())
|
||||
);
|
||||
|
||||
// Create a mailing list
|
||||
let list_id = account
|
||||
.registry_create_object(MailingList {
|
||||
name: "newsletter".to_string(),
|
||||
domain_id,
|
||||
recipients: Map::new(vec!["[email protected]".to_string()]),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
let list_cache = test
|
||||
.server
|
||||
.try_list(list_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
&list_cache.recipients,
|
||||
&Arc::from(Box::from_iter(["[email protected]".into()]))
|
||||
);
|
||||
|
||||
// Update mailing list
|
||||
account
|
||||
.registry_update_object(
|
||||
ObjectType::MailingList,
|
||||
list_id,
|
||||
json!({
|
||||
"recipients/[email protected]": true
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let list_cache = test
|
||||
.server
|
||||
.try_list(list_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
&list_cache.recipients,
|
||||
&Arc::from(Box::from_iter([
|
||||
"[email protected]".into(),
|
||||
"[email protected]".into()
|
||||
]))
|
||||
);
|
||||
|
||||
// Verify that alias domains resolve without the primary name warming the cache
|
||||
for address in [
|
||||
"[email protected]",
|
||||
"[email protected]",
|
||||
"[email protected]",
|
||||
] {
|
||||
test.server.invalidate_all_local_caches();
|
||||
assert!(
|
||||
test.server.domain("beispiel.de").await.unwrap().is_some(),
|
||||
"Alias domain failed to resolve on a cold cache"
|
||||
);
|
||||
|
||||
test.server.invalidate_all_local_caches();
|
||||
assert!(
|
||||
test.server
|
||||
.rcpt_id_from_email(address)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some(),
|
||||
"Cold cache resolution failed for {address}"
|
||||
);
|
||||
}
|
||||
|
||||
// Verify RCPT expansion
|
||||
for (address, expected) in [
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(account_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(account_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(account_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(account_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(group_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::Account(group_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::MailingList(list_id.document_id()),
|
||||
),
|
||||
(
|
||||
"[email protected]",
|
||||
EmailCache::MailingList(list_id.document_id()),
|
||||
),
|
||||
] {
|
||||
assert_eq!(
|
||||
test.server.rcpt_id_from_email(address).await.unwrap(),
|
||||
Some(expected),
|
||||
"Unexpected result for address: {address}"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_id_from_email("[email protected]")
|
||||
.await
|
||||
.unwrap(),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_id_from_email("[email protected]")
|
||||
.await
|
||||
.unwrap(),
|
||||
None
|
||||
);
|
||||
|
||||
// MTA rcpt resolve
|
||||
let domain_2_id = account
|
||||
.registry_create_object(Domain {
|
||||
name: "another-example.com".to_string(),
|
||||
is_enabled: true,
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
sub_addressing: SubAddressing::Custom(SubAddressingCustom {
|
||||
custom_rule: Expression {
|
||||
else_: "false".to_string(),
|
||||
match_: List::from_iter([ExpressionMatch {
|
||||
if_: "matches('^([^.]+)\\.([^.]+)', rcpt)".to_string(),
|
||||
then: "$1".to_string(),
|
||||
}]),
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
let account_2_id = account
|
||||
.registry_create_object(Account::User(UserAccount {
|
||||
name: "subaddresser".to_string(),
|
||||
domain_id: domain_2_id,
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
assert_eq!(
|
||||
test.server.rcpt_resolve("unknown", true, 0).await.unwrap(),
|
||||
RcptResolution::UnknownDomain
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::UnknownDomain
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Accept
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Accept
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Accept
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Expand(Arc::from(Box::from_iter([
|
||||
"[email protected]".into(),
|
||||
"[email protected]".into()
|
||||
])))
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", false, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::UnknownRecipient
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", false, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::UnknownRecipient
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve(masked_email.as_str(), true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
|
||||
// Catch-all addresses have to be resolved rather than accepted verbatim
|
||||
let domain_3_id = account
|
||||
.registry_create_object(Domain {
|
||||
name: "list-catch-all.com".to_string(),
|
||||
is_enabled: true,
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
catch_all_address: Some("[email protected]".to_string()),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
let domain_4_id = account
|
||||
.registry_create_object(Domain {
|
||||
name: "subaddress-catch-all.com".to_string(),
|
||||
is_enabled: true,
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
catch_all_address: Some("[email protected]".to_string()),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Expand(Arc::from(Box::from_iter([
|
||||
"[email protected]".into(),
|
||||
"[email protected]".into()
|
||||
])))
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", true, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::Rewrite("[email protected]".into())
|
||||
);
|
||||
assert_eq!(
|
||||
test.server
|
||||
.rcpt_resolve("[email protected]", false, 0)
|
||||
.await
|
||||
.unwrap(),
|
||||
RcptResolution::UnknownRecipient
|
||||
);
|
||||
|
||||
// Query tests
|
||||
assert_eq!(
|
||||
account
|
||||
.registry_query_ids(
|
||||
ObjectType::Domain,
|
||||
[(Property::Name, "example.com")],
|
||||
[Property::Name]
|
||||
)
|
||||
.await,
|
||||
vec![domain_id]
|
||||
);
|
||||
assert_eq!(
|
||||
account
|
||||
.registry_query_ids(
|
||||
ObjectType::Account,
|
||||
[
|
||||
(Property::Name, "johndoe"),
|
||||
(Property::Type, AccountType::User.as_str()),
|
||||
(Property::Text, "johnny")
|
||||
],
|
||||
[Property::Name]
|
||||
)
|
||||
.await,
|
||||
vec![account_id]
|
||||
);
|
||||
|
||||
// Delete everything
|
||||
john.registry_destroy(ObjectType::MaskedEmail, [masked_id])
|
||||
.await
|
||||
.assert_destroyed(&[masked_id]);
|
||||
account
|
||||
.registry_destroy(ObjectType::MailingList, [list_id])
|
||||
.await
|
||||
.assert_destroyed(&[list_id]);
|
||||
account
|
||||
.registry_destroy(ObjectType::Account, [group_id, account_id, account_2_id])
|
||||
.await
|
||||
.assert_destroyed(&[group_id, account_id, account_2_id]);
|
||||
account
|
||||
.registry_destroy(
|
||||
ObjectType::Domain,
|
||||
[domain_id, domain_2_id, domain_3_id, domain_4_id],
|
||||
)
|
||||
.await
|
||||
.assert_destroyed(&[domain_id, domain_2_id, domain_3_id, domain_4_id]);
|
||||
assert!(
|
||||
test.server
|
||||
.try_list(list_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
test.server
|
||||
.try_account(account_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
test.server
|
||||
.try_account(group_id.document_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
assert!(test.server.domain("example.com").await.unwrap().is_none());
|
||||
assert!(
|
||||
test.server
|
||||
.domain("another-example.com")
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
|
||||
test.cleanup().await;
|
||||
}
|
||||
Reference in New Issue
Block a user