Box large futures

This commit is contained in:
Maurus Decimus
2026-04-19 08:11:56 +02:00
parent c0d0ac9ea3
commit af23099e35
72 changed files with 1267 additions and 1469 deletions

View File

@@ -1,28 +0,0 @@
FROM golang:1.18-alpine as builder
ENV CGO_ENABLED=0
WORKDIR /pebble-src
RUN apk update && apk add --no-cache git
RUN git clone https://github.com/letsencrypt/pebble/ /pebble-src
RUN go build -o /go/bin/pebble ./cmd/pebble
## main
FROM alpine:3.15.4
COPY --from=builder /go/bin/pebble /usr/bin/pebble
COPY --from=builder /pebble-src/test/ /test/
CMD [ "/usr/bin/pebble" ]
EXPOSE 14000
EXPOSE 15000
# Build:
# docker build -f Docker.pebble -t pebble
# Run:
# docker run -d -p 14000:14000 -p 15000:15000 pebble
# docker run -d --name pebble -p 14000:14000 -p 15000:15000 pebble pebble -config /test/config/pebble-config.json -strict

View File

@@ -1,58 +0,0 @@
acme.pebble.contact = "postmaster@example.org"
acme.pebble.directory = "https://localhost:14000/dir"
#acme.pebble.domains = "mail.example.org"
acme.pebble.renew-before = "30d"
acme.pebble.challenge = "tls-alpn-01"
#acme.pebble.challenge = "http-01"
#acme.pebble.challenge = "dns-01"
acme.pebble.domains = "*.example.org"
acme.pebble.provider = "cloudflare"
acme.pebble.secret = "<KEY>"
authentication.fallback-admin.secret = "secret"
authentication.fallback-admin.user = "admin"
config.local-keys.0 = "*"
directory.internal.store = "rocksdb"
directory.internal.type = "internal"
lookup.default.hostname = "mail.example.org"
lookup.default.domain = "example.org"
oauth.key = "0Wn7rO4UdmBoE8mp3cDcD9Qlpz3na74z7fGRoSuq8fVsGPelLl3KrHomBN8h2biA"
queue.quota.size.enable = true
queue.quota.size.messages = 100000
queue.quota.size.size = 10737418240
report.analysis.addresses = "postmaster@*"
server.http.permissive-cors = true
server.listener.http.bind = "[::]:5002"
server.listener.http.protocol = "http"
server.listener.https.bind = "[::]:5001"
server.listener.https.protocol = "http"
server.listener.https.tls.implicit = true
server.listener.imap.bind = "[::]:143"
server.listener.imap.protocol = "imap"
server.listener.imaptls.bind = "[::]:993"
server.listener.imaptls.protocol = "imap"
server.listener.imaptls.tls.implicit = true
server.listener.sieve.bind = "[::]:4190"
server.listener.sieve.protocol = "managesieve"
server.listener.smtp.bind = "[::]:25"
server.listener.smtp.protocol = "smtp"
server.listener.submission.bind = "[::]:587"
server.listener.submission.protocol = "smtp"
server.listener.submissions.bind = "[::]:465"
server.listener.submissions.protocol = "smtp"
server.listener.submissions.tls.implicit = true
storage.blob = "rocksdb"
storage.data = "rocksdb"
storage.directory = "internal"
storage.fts = "rocksdb"
storage.lookup = "rocksdb"
store.rocksdb.compression = "lz4"
store.rocksdb.path = "/tmp/stalwart-temp-data"
store.rocksdb.type = "rocksdb"
tracer.stdout.ansi = true
tracer.stdout.enable = true
tracer.stdout.level = "trace"
tracer.stdout.type = "stdout"
version.spam-filter = 1.0

View File

@@ -1,33 +0,0 @@
# docker-compose -f docker-compose-pebble.yaml up
# curl --request POST --data '{"ip":"192.168.5.2"}' http://localhost:8055/set-default-ipv4
# HTTPS port should be 5001
# HTTP port should be 5002
# Directory https://localhost:14000/dir
version: '3'
services:
pebble:
image: letsencrypt/pebble:latest
command: pebble -config /test/config/pebble-config.json -strict -dnsserver 10.30.50.3:8053 #-dnsserver 8.8.8.8:53
ports:
- 14000:14000 # HTTPS ACME API
- 15000:15000 # HTTPS Management API
networks:
acmenet:
ipv4_address: 10.30.50.2
challtestsrv:
image: letsencrypt/pebble-challtestsrv:latest
command: pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 10.30.50.3
ports:
- 8055:8055 # HTTP Management API
networks:
acmenet:
ipv4_address: 10.30.50.3
networks:
acmenet:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.30.50.0/24

View File

@@ -1,9 +0,0 @@
#!/bin/sh
rm -Rf /tmp/stalwart-temp-data
mkdir -p /tmp/stalwart-temp-data
cp ./tests/resources/acme/config.toml /tmp/stalwart-temp-data/config.toml
curl --request POST --data '{"ip":"192.168.5.2"}' http://localhost:8055/set-default-ipv4
cargo run -p stalwart --no-default-features --features "sqlite foundationdb postgres mysql rocks elastic s3 redis" -- --config=/tmp/stalwart-temp-data/config.toml

View File

@@ -1,53 +0,0 @@
#!/bin/bash
BASE_DIR="/Users/me/Downloads/stalwart-cluster"
FEATURES="rocks"
NUM_NODES=5
# Kill previous processes
sudo pkill stalwart
# Delete previous tests
rm -rf $BASE_DIR
# Build the stalwart binary
cargo build -p stalwart --no-default-features --features "$FEATURES"
for NUM in $(seq 1 $NUM_NODES); do
sudo ifconfig en0 alias 10.0.$NUM.1 netmask 255.255.255.0
mkdir -p $BASE_DIR/data$NUM
cat <<EOF | sed "s|_N_|$NUM|g" | sed "s|_D_|$BASE_DIR|g" > $BASE_DIR/config$NUM.toml
cluster.bind-addr = "10.0._N_.1"
cluster.key = "the cluster key"
cluster.seed-nodes = ["10.0.1.1", "10.0.2.1", "10.0.3.1"]
authentication.fallback-admin.secret = "secret"
authentication.fallback-admin.user = "admin"
directory.internal.store = "rocksdb"
directory.internal.type = "internal"
lookup.default.hostname = "mail_N_.example.org"
server.http.permissive-cors = true
server.listener.https.bind = "10.0._N_.1:1443"
server.listener.https.protocol = "http"
server.listener.https.tls.implicit = true
server.listener.imap.bind = "10.0._N_.1:1143"
server.listener.imap.protocol = "imap"
server.listener.smtp.bind = "10.0._N_.1:1125"
server.listener.smtp.protocol = "smtp"
storage.blob = "rocksdb"
storage.data = "rocksdb"
storage.directory = "internal"
storage.fts = "rocksdb"
storage.lookup = "rocksdb"
store.rocksdb.compression = "lz4"
store.rocksdb.path = "_D_/data_N_"
store.rocksdb.type = "rocksdb"
tracer.stdout.ansi = true
tracer.stdout.enable = true
tracer.stdout.level = "debug"
tracer.stdout.type = "stdout"
config.resource.spam-filter = "file:///dev/null"
config.resource.webadmin = "file:///dev/null"
EOF
sudo ./target/debug/stalwart --config $BASE_DIR/config$NUM.toml &
done

View File

@@ -1,15 +0,0 @@
#!/bin/bash
BASE_DIR="/Users/me/Downloads/stalwart-test"
FEATURES="sqlite foundationdb postgres mysql rocks elastic s3 redis"
# Delete previous tests
rm -rf $BASE_DIR
# Create admin user
cargo run -p stalwart --no-default-features --features "$FEATURES" -- --init=$BASE_DIR
printf "[server.http]\npermissive-cors = true\n" >> $BASE_DIR/etc/config.toml
printf "[tracer.stdout]\ntype = 'stdout'\nlevel = 'trace'\nansi = true\nenable = true\n" >> $BASE_DIR/etc/config.toml
sed -i '' 's/secret =/secret = "secret"\n#secret =/g' $BASE_DIR/etc/config.toml
#cargo run -p stalwart --no-default-features --features "$FEATURES" -- --config=$BASE_DIR/etc/config.toml

View File

@@ -30,189 +30,178 @@ use types::id::Id;
pub const NUM_NODES: usize = 3;
#[test]
fn cluster_tests() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn cluster_tests() {
println!("Running cluster broadcast tests...");
let mut servers = Vec::with_capacity(NUM_NODES);
let coordinator_id = std::env::var("COORDINATOR").expect(concat!(
"Missing coordinator type. Try running `STORE=<store_type> ",
"COORDINATOR=<coordinator_type> cargo test`"
));
let coordinator = match coordinator_id.as_str() {
"Nats" => Coordinator::Nats(NatsCoordinator {
addresses: Map::new(vec!["127.0.0.1:4222".to_string()]),
use_tls: false,
..Default::default()
}),
"Redis" => Coordinator::Redis(RedisStore {
url: "redis://127.0.0.1".to_string(),
..Default::default()
}),
_ => panic!("Unsupported coordinator type: {}", coordinator_id),
};
// Create initial server
let test = TestServerBuilder::new("cluster_test_0")
.await
.with_object(coordinator)
.await
.with_listener(NetworkListenerProtocol::Http, "http_0", 11000, true)
.await
.with_imap_listener(12000)
.await
.with_listener(NetworkListenerProtocol::Lmtp, "lmtp_0", 11200, false)
.await
.build()
.unwrap()
.block_on(async {
println!("Running cluster broadcast tests...");
let mut servers = Vec::with_capacity(NUM_NODES);
.await;
let admin = test.account("admin");
admin.mta_no_auth().await;
let account = admin
.create_user_account(
"jdoe@example.com",
"this is john's secret",
"John's account",
&[],
vec![],
)
.await;
admin.reload_settings().await;
let coordinator_id = std::env::var("COORDINATOR").expect(concat!(
"Missing coordinator type. Try running `STORE=<store_type> ",
"COORDINATOR=<coordinator_type> cargo test`"
));
let coordinator = match coordinator_id.as_str() {
"Nats" => Coordinator::Nats(NatsCoordinator {
addresses: Map::new(vec!["127.0.0.1:4222".to_string()]),
use_tls: false,
..Default::default()
// Create listeners
let mut listeners = vec![
test.server
.registry()
.query::<Vec<Id>>(RegistryQuery::new(ObjectType::NetworkListener))
.await
.unwrap(),
];
for node_id in 1..NUM_NODES {
let http_listener_id = admin
.registry_create_object(NetworkListener {
name: format!("http_{}", node_id),
bind: Map::new(vec![
SocketAddr::from_str(&format!("127.0.0.1:1100{node_id}")).unwrap(),
]),
protocol: NetworkListenerProtocol::Http,
tls_implicit: true,
use_tls: true,
..Default::default()
})
.await;
let imap_listener_id = admin
.registry_create_object(NetworkListener {
name: format!("imap_{}", node_id),
bind: Map::new(vec![
SocketAddr::from_str(&format!("127.0.0.1:1200{node_id}")).unwrap(),
]),
protocol: NetworkListenerProtocol::Imap,
tls_implicit: false,
use_tls: true,
..Default::default()
})
.await;
listeners.push(vec![http_listener_id, imap_listener_id]);
}
// Create node roles
for (role_id, listener_ids) in listeners.into_iter().enumerate() {
admin
.registry_create_object(ClusterRole {
name: format!("role_{role_id}"),
listeners: ClusterListenerGroup::EnableSome(ClusterListenerGroupProperties {
listener_ids: Map::new(listener_ids),
}),
"Redis" => Coordinator::Redis(RedisStore {
url: "redis://127.0.0.1".to_string(),
..Default::default()
}),
_ => panic!("Unsupported coordinator type: {}", coordinator_id),
};
tasks: ClusterTaskGroup::EnableAll,
description: None,
})
.await;
}
servers.push(test);
// Create initial server
let test = TestServerBuilder::new("cluster_test_0")
.await
.with_object(coordinator)
.await
.with_listener(NetworkListenerProtocol::Http, "http_0", 11000, true)
.await
.with_imap_listener(12000)
.await
.with_listener(NetworkListenerProtocol::Lmtp, "lmtp_0", 11200, false)
.await
.build()
.await;
let admin = test.account("admin");
admin.mta_no_auth().await;
let account = admin
.create_user_account(
"jdoe@example.com",
"this is john's secret",
"John's account",
&[],
vec![],
)
.await;
admin.reload_settings().await;
// Build additional servers
for node_id in 1..NUM_NODES {
let test = TestServerBuilder::new_with_role(
&format!("cluster_test_{node_id}"),
format!("mail-{node_id}.example.com"),
Some(format!("role_{node_id}")),
false,
)
.await
.build_with_opts(false)
.await;
// Create listeners
let mut listeners = vec![
test.server
.registry()
.query::<Vec<Id>>(RegistryQuery::new(ObjectType::NetworkListener))
.await
.unwrap(),
];
for node_id in 1..NUM_NODES {
let http_listener_id = admin
.registry_create_object(NetworkListener {
name: format!("http_{}", node_id),
bind: Map::new(vec![
SocketAddr::from_str(&format!("127.0.0.1:1100{node_id}")).unwrap(),
]),
protocol: NetworkListenerProtocol::Http,
tls_implicit: true,
use_tls: true,
..Default::default()
})
.await;
let imap_listener_id = admin
.registry_create_object(NetworkListener {
name: format!("imap_{}", node_id),
bind: Map::new(vec![
SocketAddr::from_str(&format!("127.0.0.1:1200{node_id}")).unwrap(),
]),
protocol: NetworkListenerProtocol::Imap,
tls_implicit: false,
use_tls: true,
..Default::default()
})
.await;
listeners.push(vec![http_listener_id, imap_listener_id]);
}
// Verify that the server was assigned the correct node id
assert_eq!(test.server.registry().node_id(), node_id as u16);
servers.push(test);
}
// Create node roles
for (role_id, listener_ids) in listeners.into_iter().enumerate() {
admin
.registry_create_object(ClusterRole {
name: format!("role_{role_id}"),
listeners: ClusterListenerGroup::EnableSome(
ClusterListenerGroupProperties {
listener_ids: Map::new(listener_ids),
},
),
tasks: ClusterTaskGroup::EnableAll,
description: None,
})
.await;
}
servers.push(test);
// Verify cross-cluster cache invalidations
let admin = servers[0].account("admin");
let server1 = &servers[1].server;
let server2 = &servers[2].server;
let account_id = account.id().document_id();
assert_eq!(
server1
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John's account")
);
assert_eq!(
server2
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John's account")
);
admin
.registry_update_object(
ObjectType::Account,
account.id(),
json!({
Property::Description: "John Doe"
}),
)
.await;
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
assert_eq!(
server1
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John Doe")
);
assert_eq!(
server2
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John Doe")
);
// Build additional servers
for node_id in 1..NUM_NODES {
let test = TestServerBuilder::new_with_role(
&format!("cluster_test_{node_id}"),
format!("mail-{node_id}.example.com"),
Some(format!("role_{node_id}")),
false,
)
.await
.build_with_opts(false)
.await;
// Verify that the server was assigned the correct node id
assert_eq!(test.server.registry().node_id(), node_id as u16);
servers.push(test);
}
// Verify cross-cluster cache invalidations
let admin = servers[0].account("admin");
let server1 = &servers[1].server;
let server2 = &servers[2].server;
let account_id = account.id().document_id();
assert_eq!(
server1
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John's account")
);
assert_eq!(
server2
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John's account")
);
admin
.registry_update_object(
ObjectType::Account,
account.id(),
json!({
Property::Description: "John Doe"
}),
)
.await;
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
assert_eq!(
server1
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John Doe")
);
assert_eq!(
server2
.account(account_id)
.await
.unwrap()
.description
.as_deref(),
Some("John Doe")
);
// Run IMAP idle tests across nodes
let mut node1_client =
imap_client("jdoe@example.com", "this is john's secret", 1).await;
let mut node2_client =
imap_client("jdoe@example.com", "this is john's secret", 2).await;
idle::test(&mut node1_client, &mut node2_client, true).await;
});
// Run IMAP idle tests across nodes
let mut node1_client = imap_client("jdoe@example.com", "this is john's secret", 1).await;
let mut node2_client = imap_client("jdoe@example.com", "this is john's secret", 2).await;
idle::test(&mut node1_client, &mut node2_client, true).await;
}
async fn imap_client(login: &str, secret: &str, node_id: u32) -> ImapConnection {

View File

@@ -41,251 +41,244 @@ use serde_json::json;
use std::{path::PathBuf, time::Instant};
use utils::map::vec_map::VecMap;
#[test]
fn imap_tests() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn imap_tests() {
let mut test = TestServerBuilder::new("imap_tests")
.await
.with_default_listeners()
.await
.build()
.unwrap()
.block_on(async {
let mut test = TestServerBuilder::new("imap_tests")
.await
.with_default_listeners()
.await
.build()
.await;
.await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create test users
for (name, secret, description, aliases) in [
(
"jdoe@example.com",
"12345 + extra safety",
"John Doe",
&["john.doe@example.com"][..],
),
(
"jane.smith@example.com",
"abcde + extra safety",
"Jane Smith",
&["jane@example.com"][..],
),
(
"foobar@example.com",
"098765 + extra safety",
"Bill Foobar",
&["bill.foobar@example.com"][..],
),
(
"popper@example.com",
"a_pop3_safe_secret_with_extra_safety",
"Karl Popper",
&["karl.popper@example.com"][..],
),
(
"sgd@example.com",
"secret2 + extra safety",
"Sigmund Gudmund Dudmundsson",
&[][..],
),
(
"spamtrap@example.com",
"secret3 + extra safety",
"Spam Trap",
&[][..],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![Permission::UnlimitedRequests, Permission::UnlimitedUploads],
// Create test users
for (name, secret, description, aliases) in [
(
"jdoe@example.com",
"12345 + extra safety",
"John Doe",
&["john.doe@example.com"][..],
),
(
"jane.smith@example.com",
"abcde + extra safety",
"Jane Smith",
&["jane@example.com"][..],
),
(
"foobar@example.com",
"098765 + extra safety",
"Bill Foobar",
&["bill.foobar@example.com"][..],
),
(
"popper@example.com",
"a_pop3_safe_secret_with_extra_safety",
"Karl Popper",
&["karl.popper@example.com"][..],
),
(
"sgd@example.com",
"secret2 + extra safety",
"Sigmund Gudmund Dudmundsson",
&[][..],
),
(
"spamtrap@example.com",
"secret3 + extra safety",
"Spam Trap",
&[][..],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![Permission::UnlimitedRequests, Permission::UnlimitedUploads],
)
.await;
test.insert_account(account);
}
// Create test group
test.insert_account(
admin
.create_group_account("support@example.com", "Support Group", &[])
.await,
);
// Add Jane to the Support group
let support_id = test.account("support@example.com").id();
admin
.registry_update_object(
ObjectType::Account,
test.account("jane.smith@example.com").id(),
json!({
"memberGroupIds": { support_id: true },
}),
)
.await;
// Add test settings
admin
.registry_create_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(SpamClassifier {
min_ham_samples: 10,
min_spam_samples: 10,
..Default::default()
})
.await;
admin
.registry_create_object(Email {
default_folders: VecMap::from_iter(
[
(SpecialUse::Inbox, "Inbox"),
(SpecialUse::Sent, "Sent Items"),
(SpecialUse::Trash, "Deleted Items"),
(SpecialUse::Junk, "Junk Mail"),
(SpecialUse::Drafts, "Drafts"),
]
.into_iter()
.map(|(use_, name)| {
(
use_,
EmailFolder {
name: name.into(),
subscribe: false,
..Default::default()
},
)
.await;
test.insert_account(account);
}
}),
),
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageData {
add_delivered_to_header: false,
enable_spam_filter: Expression {
else_: "recipients[0] != 'popper@example.com'".into(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(10.0),
tag: "PROB_SPAM_LOW".into(),
}))
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(10.0),
tag: "PROB_SPAM_HIGH".into(),
}))
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(100.0),
tag: "SPAM_TRAP".into(),
}))
.await;
admin
.registry_create_object(MemoryLookupKey {
is_glob_pattern: true,
key: "spamtrap@*".into(),
namespace: "spam-traps".into(),
})
.await;
admin.reload_settings().await;
admin.reload_lookup_stores().await;
// Create test group
test.insert_account(
admin
.create_group_account("support@example.com", "Support Group", &[])
.await,
);
test.insert_account(admin);
// Add Jane to the Support group
let support_id = test.account("support@example.com").id();
admin
.registry_update_object(
ObjectType::Account,
test.account("jane.smith@example.com").id(),
json!({
"memberGroupIds": { support_id: true },
}),
)
.await;
let start_time = Instant::now();
// Add test settings
admin
.registry_create_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(SpamClassifier {
min_ham_samples: 10,
min_spam_samples: 10,
..Default::default()
})
.await;
admin
.registry_create_object(Email {
default_folders: VecMap::from_iter(
[
(SpecialUse::Inbox, "Inbox"),
(SpecialUse::Sent, "Sent Items"),
(SpecialUse::Trash, "Deleted Items"),
(SpecialUse::Junk, "Junk Mail"),
(SpecialUse::Drafts, "Drafts"),
]
.into_iter()
.map(|(use_, name)| {
(
use_,
EmailFolder {
name: name.into(),
subscribe: false,
..Default::default()
},
)
}),
),
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageData {
add_delivered_to_header: false,
enable_spam_filter: Expression {
else_: "recipients[0] != 'popper@example.com'".into(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(10.0),
tag: "PROB_SPAM_LOW".into(),
}))
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(10.0),
tag: "PROB_SPAM_HIGH".into(),
}))
.await;
admin
.registry_create_object(SpamTag::Score(SpamTagScore {
score: Float::new(100.0),
tag: "SPAM_TRAP".into(),
}))
.await;
admin
.registry_create_object(MemoryLookupKey {
is_glob_pattern: true,
key: "spamtrap@*".into(),
namespace: "spam-traps".into(),
})
.await;
admin.reload_settings().await;
admin.reload_lookup_stores().await;
// Body structure tests
body_structure::test();
test.insert_account(admin);
// Connect to IMAP server
let mut imap_check = ImapConnection::connect(b"_y ").await;
let mut imap = ImapConnection::connect(b"_x ").await;
for imap in [&mut imap, &mut imap_check] {
imap.assert_read(Type::Untagged, ResponseType::Ok).await;
}
let start_time = Instant::now();
// Unauthenticated tests
basic::test(&mut imap, &mut imap_check).await;
// Body structure tests
body_structure::test();
// Login
let account = test.account("jdoe@example.com");
for imap in [&mut imap, &mut imap_check] {
imap.authenticate(account.name(), account.secret()).await;
}
// Connect to IMAP server
let mut imap_check = ImapConnection::connect(b"_y ").await;
let mut imap = ImapConnection::connect(b"_x ").await;
for imap in [&mut imap, &mut imap_check] {
imap.assert_read(Type::Untagged, ResponseType::Ok).await;
}
// Delete folders
for mailbox in ["Drafts", "Junk Mail", "Sent Items"] {
imap.send(&format!("DELETE \"{}\"", mailbox)).await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
}
// Unauthenticated tests
basic::test(&mut imap, &mut imap_check).await;
mailbox::test(&mut imap, &mut imap_check, &test).await;
append::test(&mut imap, &mut imap_check, &test).await;
search::test(&mut imap, &mut imap_check, &test).await;
fetch::test(&mut imap, &mut imap_check).await;
store::test(&mut imap, &mut imap_check, &test).await;
copy_move::test(&mut imap, &mut imap_check).await;
thread::test(&mut imap, &mut imap_check, &test).await;
idle::test(&mut imap, &mut imap_check, false).await;
condstore::test(&mut imap, &mut imap_check).await;
acl::test(&mut imap, &mut imap_check, &test).await;
// Login
let account = test.account("jdoe@example.com");
for imap in [&mut imap, &mut imap_check] {
imap.authenticate(account.name(), account.secret()).await;
}
// Logout
for imap in [&mut imap, &mut imap_check] {
imap.send("UNAUTHENTICATE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Delete folders
for mailbox in ["Drafts", "Junk Mail", "Sent Items"] {
imap.send(&format!("DELETE \"{}\"", mailbox)).await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
}
imap.send("LOGOUT").await;
imap.assert_read(Type::Untagged, ResponseType::Bye).await;
}
mailbox::test(&mut imap, &mut imap_check, &test).await;
append::test(&mut imap, &mut imap_check, &test).await;
search::test(&mut imap, &mut imap_check, &test).await;
fetch::test(&mut imap, &mut imap_check).await;
store::test(&mut imap, &mut imap_check, &test).await;
copy_move::test(&mut imap, &mut imap_check).await;
thread::test(&mut imap, &mut imap_check, &test).await;
idle::test(&mut imap, &mut imap_check, false).await;
condstore::test(&mut imap, &mut imap_check).await;
acl::test(&mut imap, &mut imap_check, &test).await;
// Antispam training
antispam::test(&test).await;
// Logout
for imap in [&mut imap, &mut imap_check] {
imap.send("UNAUTHENTICATE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Run ManageSieve tests
managesieve::test(&test).await;
imap.send("LOGOUT").await;
imap.assert_read(Type::Untagged, ResponseType::Bye).await;
}
// Run POP3 tests
pop::test(&test).await;
// Antispam training
antispam::test(&test).await;
// Print elapsed time
let elapsed = start_time.elapsed();
println!(
"Elapsed: {}.{:03}s",
elapsed.as_secs(),
elapsed.subsec_millis()
);
// Run ManageSieve tests
managesieve::test(&test).await;
// Run POP3 tests
pop::test(&test).await;
// Print elapsed time
let elapsed = start_time.elapsed();
println!(
"Elapsed: {}.{:03}s",
elapsed.as_secs(),
elapsed.subsec_millis()
);
// Remove test data
if test.is_reset() {
test.temp_dir.delete();
}
});
// Remove test data
if test.is_reset() {
test.temp_dir.delete();
}
}
pub fn expand_uid_list(list: &str) -> AHashSet<u32> {

View File

@@ -23,201 +23,194 @@ pub mod files;
pub mod mail;
pub mod principal;
#[test]
fn jmap_tests() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn jmap_tests() {
let mut test = TestServerBuilder::new("jmap_tests")
.await
.with_default_listeners()
.await
.build()
.unwrap()
.block_on(async {
let mut test = TestServerBuilder::new("jmap_tests")
.await
.with_default_listeners()
.await
.build()
.await;
.await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create test users
for (name, secret, description, aliases) in [
(
"jdoe@example.com",
"12345 + extra safety",
"John Doe",
&["john.doe@example.com"][..],
),
(
"jane.smith@example.com",
"abcde + extra safety",
"Jane Smith",
&["jane@example.com"],
),
(
"bill@example.com",
"098765 + extra safety",
"Bill Foobar",
&["bill.foobar@example.com"],
),
(
"robert@example.com",
"aabbcc + extra safety",
"Robert Foobar",
&[][..],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![Permission::UnlimitedRequests, Permission::UnlimitedUploads],
)
.await;
test.insert_account(account);
}
// Create test users
for (name, secret, description, aliases) in [
(
"jdoe@example.com",
"12345 + extra safety",
"John Doe",
&["john.doe@example.com"][..],
),
(
"jane.smith@example.com",
"abcde + extra safety",
"Jane Smith",
&["jane@example.com"],
),
(
"bill@example.com",
"098765 + extra safety",
"Bill Foobar",
&["bill.foobar@example.com"],
),
(
"robert@example.com",
"aabbcc + extra safety",
"Robert Foobar",
&[][..],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![Permission::UnlimitedRequests, Permission::UnlimitedUploads],
)
.await;
test.insert_account(account);
}
// Create test group
test.insert_account(
admin
.create_group_account("sales@example.com", "Sales Group", &[])
.await,
);
// Create test group
test.insert_account(
admin
.create_group_account("sales@example.com", "Sales Group", &[])
.await,
);
// Add test settings
admin
.registry_create_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await;
admin
.registry_create_object(Jmap {
set_max_objects: 100_000,
get_max_results: 100_000,
event_source_throttle: 500u64.into(),
push_throttle: 500u64.into(),
websocket_throttle: 500u64.into(),
push_attempt_wait: 500u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
// Add test settings
admin
.registry_create_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await;
admin
.registry_create_object(Jmap {
set_max_objects: 100_000,
get_max_results: 100_000,
event_source_throttle: 500u64.into(),
push_throttle: 500u64.into(),
websocket_throttle: 500u64.into(),
push_attempt_wait: 500u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(CalendarAlarm {
min_trigger_interval: 1000u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(Sharing {
allow_directory_queries: true,
..Default::default()
})
.await;
admin
.registry_create_object(MtaOutboundStrategy {
route: Expression {
match_: List::from_iter([
ExpressionMatch {
if_: "rcpt_domain == 'example.com'".into(),
then: "'local'".into(),
},
..Default::default()
})
.await;
admin
.registry_create_object(CalendarAlarm {
min_trigger_interval: 1000u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(Sharing {
allow_directory_queries: true,
..Default::default()
})
.await;
admin
.registry_create_object(MtaOutboundStrategy {
route: Expression {
match_: List::from_iter([
ExpressionMatch {
if_: "rcpt_domain == 'example.com'".into(),
then: "'local'".into(),
},
ExpressionMatch {
if_: concat!(
"contains(['remote.org', 'foobar.com', ",
"'test.com', 'other_domain.com'], rcpt_domain)"
)
.into(),
then: "'mock-smtp'".into(),
},
]),
else_: "'mx'".to_string(),
ExpressionMatch {
if_: concat!(
"contains(['remote.org', 'foobar.com', ",
"'test.com', 'other_domain.com'], rcpt_domain)"
)
.into(),
then: "'mock-smtp'".into(),
},
..Default::default()
})
.await;
admin
.registry_create_object(MtaRoute::Relay(MtaRouteRelay {
address: "127.0.0.1".into(),
port: 9999,
allow_invalid_certs: true,
implicit_tls: false,
name: "mock-smtp".into(),
protocol: MtaProtocol::Smtp,
..Default::default()
}))
.await;
admin
.registry_create_object(MtaExtensions {
future_release: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "!is_empty(authenticated_as)".into(),
then: "99999999d".into(),
}]),
else_: "false".to_string(),
},
..Default::default()
})
.await;
admin.reload_settings().await;
]),
else_: "'mx'".to_string(),
},
..Default::default()
})
.await;
admin
.registry_create_object(MtaRoute::Relay(MtaRouteRelay {
address: "127.0.0.1".into(),
port: 9999,
allow_invalid_certs: true,
implicit_tls: false,
name: "mock-smtp".into(),
protocol: MtaProtocol::Smtp,
..Default::default()
}))
.await;
admin
.registry_create_object(MtaExtensions {
future_release: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "!is_empty(authenticated_as)".into(),
then: "99999999d".into(),
}]),
else_: "false".to_string(),
},
..Default::default()
})
.await;
admin.reload_settings().await;
test.insert_account(admin);
test.insert_account(admin);
/*mail::get::test(&test).await;
mail::set::test(&test).await;
mail::parse::test(&test).await;
mail::query::test(&test).await;
mail::search_snippet::test(&test).await;
mail::changes::test(&test).await;
mail::query_changes::test(&test).await;
mail::copy::test(&test).await;
mail::thread_get::test(&test).await;*/
mail::thread_merge::test(&test).await;
mail::mailbox::test(&test).await;
mail::acl::test(&test).await;
mail::sieve_script::test(&test).await;
mail::vacation_response::test(&test).await;
mail::submission::test(&test).await;
mail::get::test(&test).await;
mail::set::test(&test).await;
mail::parse::test(&test).await;
mail::query::test(&test).await;
mail::search_snippet::test(&test).await;
mail::changes::test(&test).await;
mail::query_changes::test(&test).await;
mail::copy::test(&test).await;
mail::thread_get::test(&test).await;
mail::thread_merge::test(&test).await;
mail::mailbox::test(&test).await;
mail::acl::test(&test).await;
mail::sieve_script::test(&test).await;
mail::vacation_response::test(&test).await;
mail::submission::test(&test).await;
core::event_source::test(&test).await;
core::websocket::test(&test).await;
core::push_subscription::test(&test).await;
core::blob::test(&test).await;
core::event_source::test(&test).await;
core::websocket::test(&test).await;
core::push_subscription::test(&test).await;
core::blob::test(&test).await;
contacts::addressbook::test(&test).await;
contacts::contact::test(&test).await;
contacts::acl::test(&test).await;
contacts::addressbook::test(&test).await;
contacts::contact::test(&test).await;
contacts::acl::test(&test).await;
files::node::test(&test).await;
files::acl::test(&test).await;
files::node::test(&test).await;
files::acl::test(&test).await;
calendar::calendars::test(&test).await;
calendar::event::test(&test).await;
calendar::notification::test(&test).await;
calendar::alarm::test(&test).await;
calendar::calendars::test(&test).await;
calendar::event::test(&test).await;
calendar::notification::test(&test).await;
calendar::alarm::test(&test).await;
calendar::identity::test(&test).await;
calendar::acl::test(&test).await;
calendar::identity::test(&test).await;
calendar::acl::test(&test).await;
principal::get::test(&test).await;
principal::availability::test(&test).await;
principal::get::test(&test).await;
principal::availability::test(&test).await;
if test.is_reset() {
test.temp_dir.delete();
}
});
if test.is_reset() {
test.temp_dir.delete();
}
}
pub fn find_values(string: &str, name: &str) -> Vec<String> {

View File

@@ -27,49 +27,43 @@ if allof( envelope :localpart :contains "to" ".",
}
"#;
#[test]
fn address_rewrite() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn address_rewrite() {
let mut test = TestServerBuilder::new("smtp_rewrite_test")
.await
.with_http_listener(19007)
.await
.disable_services()
.build()
.unwrap()
.block_on(async {
let mut test = TestServerBuilder::new("smtp_rewrite_test")
.await
.with_http_listener(19007)
.await
.disable_services()
.build()
.await;
.await;
// Add test settings
let admin = test.account("admin");
admin.mta_no_auth().await;
admin
.registry_create_object(MtaStageMail {
rewrite: Expression {
match_: List::from_iter([ExpressionMatch {
if_: concat!(
"ends_with(sender_domain, '.foobar.net') & ",
"matches('^([^.]+)@([^.]+)\\.(.+)$', sender)"
)
.into(),
then: "$1 + '+' + $2 + '@' + $3".into(),
}]),
else_: "false".into(),
},
script: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "sender_domain = 'foobar.org'".into(),
then: "'mail'".into(),
}]),
else_: "false".into(),
},
..Default::default()
})
.await;
admin
// Add test settings
let admin = test.account("admin");
admin.mta_no_auth().await;
admin
.registry_create_object(MtaStageMail {
rewrite: Expression {
match_: List::from_iter([ExpressionMatch {
if_: concat!(
"ends_with(sender_domain, '.foobar.net') & ",
"matches('^([^.]+)@([^.]+)\\.(.+)$', sender)"
)
.into(),
then: "$1 + '+' + $2 + '@' + $3".into(),
}]),
else_: "false".into(),
},
script: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "sender_domain = 'foobar.org'".into(),
then: "'mail'".into(),
}]),
else_: "false".into(),
},
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageRcpt {
rewrite: Expression {
match_: List::from_iter([ExpressionMatch {
@@ -93,81 +87,80 @@ fn address_rewrite() {
..Default::default()
})
.await;
admin
.registry_create_object(SieveSystemInterpreter {
default_from_address: Expression {
else_: "'sieve@foobar.org'".into(),
..Default::default()
},
admin
.registry_create_object(SieveSystemInterpreter {
default_from_address: Expression {
else_: "'sieve@foobar.org'".into(),
..Default::default()
},
default_from_name: Expression {
else_: "'Sieve Daemon'".into(),
..Default::default()
},
default_return_path: Expression {
else_: "''".into(),
..Default::default()
},
message_id_hostname: Some("'mx.foobar.org'".into()),
duplicate_expiry: (86_400u64 * 100 * 7).into(),
max_cpu_cycles: 10000,
max_nested_includes: 5,
max_out_messages: 5,
max_received_headers: 50,
max_redirects: 3,
..Default::default()
})
.await;
for (name, contents) in [("mail", MAIL_SCRIPT), ("rcpt", MAIL_RCPT)] {
admin
.registry_create_object(SieveSystemScript {
name: name.to_string(),
contents: contents.to_string(),
is_active: true,
..Default::default()
})
.await;
}
admin.reload_settings().await;
test.reload_core();
default_from_name: Expression {
else_: "'Sieve Daemon'".into(),
..Default::default()
},
default_return_path: Expression {
else_: "''".into(),
..Default::default()
},
message_id_hostname: Some("'mx.foobar.org'".into()),
duplicate_expiry: (86_400u64 * 100 * 7).into(),
max_cpu_cycles: 10000,
max_nested_includes: 5,
max_out_messages: 5,
max_received_headers: 50,
max_redirects: 3,
..Default::default()
})
.await;
for (name, contents) in [("mail", MAIL_SCRIPT), ("rcpt", MAIL_RCPT)] {
admin
.registry_create_object(SieveSystemScript {
name: name.to_string(),
contents: contents.to_string(),
is_active: true,
..Default::default()
})
.await;
}
admin.reload_settings().await;
test.reload_core();
// Init session
let mut session = test.new_mta_session();
session.data.remote_ip_str = "10.0.0.1".into();
session.eval_session_params().await;
session.ehlo("mx.doe.org").await;
// Init session
let mut session = test.new_mta_session();
session.data.remote_ip_str = "10.0.0.1".into();
session.eval_session_params().await;
session.ehlo("mx.doe.org").await;
// Sender rewrite using regex
session.mail_from("bill@doe.foobar.net", "250").await;
assert_eq!(
session.data.mail_from.as_ref().unwrap().address,
"bill+doe@foobar.net"
);
session.reset();
// Sender rewrite using regex
session.mail_from("bill@doe.foobar.net", "250").await;
assert_eq!(
session.data.mail_from.as_ref().unwrap().address,
"bill+doe@foobar.net"
);
session.reset();
// Sender rewrite using sieve
session.mail_from("this_is_admin@foobar.org", "250").await;
assert_eq!(
session.data.mail_from.as_ref().unwrap().address_lcase,
"mailer-daemon@foobar.org"
);
// Sender rewrite using sieve
session.mail_from("this_is_admin@foobar.org", "250").await;
assert_eq!(
session.data.mail_from.as_ref().unwrap().address_lcase,
"mailer-daemon@foobar.org"
);
// Recipient rewrite using regex
session.rcpt_to("mary.smith@foobar.net", "250").await;
assert_eq!(
session.data.rcpt_to.last().unwrap().address,
"mary+smith@foobar.net"
);
// Recipient rewrite using regex
session.rcpt_to("mary.smith@foobar.net", "250").await;
assert_eq!(
session.data.rcpt_to.last().unwrap().address,
"mary+smith@foobar.net"
);
// Remove duplicates
session.rcpt_to("mary.smith@foobar.net", "250").await;
assert_eq!(session.data.rcpt_to.len(), 1);
// Remove duplicates
session.rcpt_to("mary.smith@foobar.net", "250").await;
assert_eq!(session.data.rcpt_to.len(), 1);
// Recipient rewrite using sieve
session.rcpt_to("m.a.r.y.s.m.i.t.h@foobar.org", "250").await;
assert_eq!(
session.data.rcpt_to.last().unwrap().address,
"marysmith@foobar.org"
);
});
// Recipient rewrite using sieve
session.rcpt_to("m.a.r.y.s.m.i.t.h@foobar.org", "250").await;
assert_eq!(
session.data.rcpt_to.last().unwrap().address,
"marysmith@foobar.org"
);
}

View File

@@ -21,65 +21,58 @@ pub mod tenant;
use crate::utils::server::TestServerBuilder;
use registry::schema::structs::{Expression, Imap, MtaStageAuth};
#[test]
fn system_tests() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn system_tests() {
let mut test = TestServerBuilder::new("system_tests")
.await
.with_default_listeners()
.await
.with_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await
.with_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await
.build()
.unwrap()
.block_on(async {
let mut test = TestServerBuilder::new("system_tests")
.await
.with_default_listeners()
.await
.with_object(Imap {
allow_plain_text_auth: true,
..Default::default()
})
.await
.with_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await
.build()
.await;
.await;
// Create admin account
let admin = test
.create_user_account(
"admin",
"admin@example.org",
"these_pretzels_are_making_me_thirsty",
&[],
"Admin",
)
.await;
test.account("admin")
.assign_roles_to_account(admin.id(), &["user", "system"])
.await;
test.insert_account(admin);
// Create admin account
let admin = test
.create_user_account(
"admin",
"admin@example.org",
"these_pretzels_are_making_me_thirsty",
&[],
"Admin",
)
.await;
test.account("admin")
.assign_roles_to_account(admin.id(), &["user", "system"])
.await;
test.insert_account(admin);
directory::test(&test).await;
authentication::test(&test).await;
oidc::test(&mut test).await;
authorization::test(&mut test).await;
tenant::test(&mut test).await;
security::test(&mut test).await;
quota::test(&mut test).await;
purge::test(&mut test).await;
delivery::test(&mut test).await;
crypto::test(&mut test).await;
antispam::test(&mut test).await;
archiving::test(&mut test).await;
task::test(&mut test).await;
directory::test(&test).await;
authentication::test(&test).await;
oidc::test(&mut test).await;
authorization::test(&mut test).await;
tenant::test(&mut test).await;
security::test(&mut test).await;
quota::test(&mut test).await;
purge::test(&mut test).await;
delivery::test(&mut test).await;
crypto::test(&mut test).await;
antispam::test(&mut test).await;
archiving::test(&mut test).await;
task::test(&mut test).await;
if test.is_reset() {
test.temp_dir.delete();
}
});
if test.is_reset() {
test.temp_dir.delete();
}
}

View File

@@ -40,180 +40,173 @@ pub mod prop;
pub mod put_get;
pub mod sync;
#[test]
fn webdav_tests() {
tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(8 * 1024 * 1024) // 8MB stack
.enable_all()
#[tokio::test(flavor = "multi_thread")]
pub async fn webdav_tests() {
// Prepare settings
let assisted_discovery = std::env::var("ASSISTED_DISCOVERY").unwrap_or_default() == "1";
let mut test = TestServerBuilder::new("webdav_tests")
.await
.with_default_listeners()
.await
.build()
.unwrap()
.block_on(async {
// Prepare settings
let assisted_discovery = std::env::var("ASSISTED_DISCOVERY").unwrap_or_default() == "1";
.await;
let mut test = TestServerBuilder::new("webdav_tests")
.await
.with_default_listeners()
.await
.build()
.await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create admin account
let admin = test.create_admin_account("admin@example.com").await;
// Create test users
for (name, secret, description, aliases) in [
(
"john@example.com",
"secret2 + some more text",
"John Doe",
&["jdoe@example.com"],
),
(
"jane@example.com",
"secret3 + some more text",
"Jane Doe-Smith",
&["jane.smith@example.com"],
),
(
"bill@example.com",
"secret4 + some more text",
"Bill Foobar",
&["bill@example.com"],
),
(
"mike@example.com",
"secret5 + some more text",
"Mike Noquota",
&["mike@example.com"],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![
Permission::UnlimitedRequests,
Permission::UnlimitedUploads,
Permission::DavPrincipalList,
Permission::DavPrincipalSearch,
],
)
.await;
if name == "mike@example.com" {
admin
.registry_update_object(
ObjectType::Account,
account.id(),
json!({
Property::Quotas: { StorageQuota::MaxDiskQuota.as_str(): 1024}
}),
)
.await;
}
test.insert_account(account);
}
// Create test group
test.insert_account(
admin
.create_group_account("support@example.com", "Support Group", &[])
.await,
);
// Add Jane to the Support group
let support_id = test.account("support@example.com").id();
// Create test users
for (name, secret, description, aliases) in [
(
"john@example.com",
"secret2 + some more text",
"John Doe",
&["jdoe@example.com"],
),
(
"jane@example.com",
"secret3 + some more text",
"Jane Doe-Smith",
&["jane.smith@example.com"],
),
(
"bill@example.com",
"secret4 + some more text",
"Bill Foobar",
&["bill@example.com"],
),
(
"mike@example.com",
"secret5 + some more text",
"Mike Noquota",
&["mike@example.com"],
),
] {
let account = admin
.create_user_account(
name,
secret,
description,
aliases,
vec![
Permission::UnlimitedRequests,
Permission::UnlimitedUploads,
Permission::DavPrincipalList,
Permission::DavPrincipalSearch,
],
)
.await;
if name == "mike@example.com" {
admin
.registry_update_object(
ObjectType::Account,
test.account("jane@example.com").id(),
account.id(),
json!({
"memberGroupIds": { support_id: true },
Property::Quotas: { StorageQuota::MaxDiskQuota.as_str(): 1024}
}),
)
.await;
}
// Add test settings
admin
.registry_update_setting(
SystemSettings {
default_hostname: "webdav.example.org".to_string(),
..Default::default()
},
&[Property::DefaultHostname],
)
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(CalendarAlarm {
min_trigger_interval: 1000u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(Sharing {
allow_directory_queries: true,
..Default::default()
})
.await;
admin
.registry_create_object(CalendarScheduling {
auto_add_invitations: true,
..Default::default()
})
.await;
admin
.registry_create_object(WebDav {
enable_assisted_discovery: assisted_discovery,
..Default::default()
})
.await;
admin.reload_settings().await;
test.insert_account(account);
}
test.insert_account(admin);
// Create test group
test.insert_account(
admin
.create_group_account("support@example.com", "Support Group", &[])
.await,
);
let start_time = Instant::now();
//test_build_itip_templates(&test).await;
basic::test(&test).await;
put_get::test(&test).await;
mkcol::test(&test).await;
copy_move::test(&test, assisted_discovery).await;
prop::test(&test, assisted_discovery).await;
multiget::test(&test).await;
sync::test(&test).await;
lock::test(&test).await;
principals::test(&test, assisted_discovery).await;
acl::test(&test).await;
card_query::test(&test).await;
cal_query::test(&test).await;
cal_alarm::test(&test).await;
cal_itip::test();
cal_scheduling::test(&test).await;
// Add Jane to the Support group
let support_id = test.account("support@example.com").id();
admin
.registry_update_object(
ObjectType::Account,
test.account("jane@example.com").id(),
json!({
"memberGroupIds": { support_id: true },
}),
)
.await;
// Print elapsed time
let elapsed = start_time.elapsed();
println!(
"Elapsed: {}.{:03}s",
elapsed.as_secs(),
elapsed.subsec_millis()
);
// Add test settings
admin
.registry_update_setting(
SystemSettings {
default_hostname: "webdav.example.org".to_string(),
..Default::default()
},
&[Property::DefaultHostname],
)
.await;
admin
.registry_create_object(MtaStageAuth {
require: Expression {
else_: "false".to_string(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(CalendarAlarm {
min_trigger_interval: 1000u64.into(),
..Default::default()
})
.await;
admin
.registry_create_object(Sharing {
allow_directory_queries: true,
..Default::default()
})
.await;
admin
.registry_create_object(CalendarScheduling {
auto_add_invitations: true,
..Default::default()
})
.await;
admin
.registry_create_object(WebDav {
enable_assisted_discovery: assisted_discovery,
..Default::default()
})
.await;
admin.reload_settings().await;
// Remove test data
if test.is_reset() {
test.temp_dir.delete();
}
});
test.insert_account(admin);
let start_time = Instant::now();
//test_build_itip_templates(&test).await;
basic::test(&test).await;
put_get::test(&test).await;
mkcol::test(&test).await;
copy_move::test(&test, assisted_discovery).await;
prop::test(&test, assisted_discovery).await;
multiget::test(&test).await;
sync::test(&test).await;
lock::test(&test).await;
principals::test(&test, assisted_discovery).await;
acl::test(&test).await;
card_query::test(&test).await;
cal_query::test(&test).await;
cal_alarm::test(&test).await;
cal_itip::test();
cal_scheduling::test(&test).await;
// Print elapsed time
let elapsed = start_time.elapsed();
println!(
"Elapsed: {}.{:03}s",
elapsed.as_secs(),
elapsed.subsec_millis()
);
// Remove test data
if test.is_reset() {
test.temp_dir.delete();
}
}
pub trait DavResourcesTest {