Files
Stalwart/tests/src/imap/condstore.rs
2023-07-15 21:14:34 +02:00

296 lines
9.6 KiB
Rust

/*
* Copyright (c) 2020-2022, Stalwart Labs Ltd.
*
* This file is part of Stalwart Mail Server.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* in the LICENSE file at the top-level directory of this distribution.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can be released from the requirements of the AGPLv3 license by
* purchasing a commercial license. Please contact licensing@stalw.art
* for more details.
*/
use imap_proto::ResponseType;
use crate::imap::{
append::{assert_append_message, build_messages},
AssertResult,
};
use super::{ImapConnection, Type};
pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
// Test CONDSTORE parameter
imap.send("SELECT INBOX (CONDSTORE)").await;
let hms = imap
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq();
// Unselect
imap.send("UNSELECT").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Create test folders
imap.send("CREATE Pecorino").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Enable CONDSTORE and QRESYNC
imap.send("ENABLE CONDSTORE QRESYNC").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Make sure modseq did not change after creating a mailbox
imap.send("SELECT Pecorino").await;
assert_eq!(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
hms
);
imap_check.send("LIST \"\" \"*\"").await;
imap_check.assert_read(Type::Tagged, ResponseType::Ok).await;
imap_check.send("SELECT Pecorino (CONDSTORE)").await;
imap_check.assert_read(Type::Tagged, ResponseType::Ok).await;
// SEQ 0: Init
let mut messages = build_messages();
let mut modseqs = vec![hms];
// SEQ 1: Append a message and make sure the modseq increased
assert_append_message(imap, "Pecorino", &messages.pop().unwrap(), ResponseType::Ok).await;
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
assert_ne!(modseqs[modseqs.len() - 1], modseqs[modseqs.len() - 2]);
// SEQ 2: Move out the message and make sure the modseq increased
imap.send("UID MOVE 1 \"Deleted Items\"").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* VANISHED 1");
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
assert_ne!(modseqs[modseqs.len() - 1], modseqs[modseqs.len() - 2]);
// SEQ 3: Insert message
assert_append_message(imap, "Pecorino", &messages.pop().unwrap(), ResponseType::Ok).await;
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
// SEQ 4: Insert message
assert_append_message(imap, "Pecorino", &messages.pop().unwrap(), ResponseType::Ok).await;
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
// SEQ 5: Insert message
assert_append_message(imap, "Pecorino", &messages.pop().unwrap(), ResponseType::Ok).await;
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
// SEQ 6: Change a message flag
imap.send("UID STORE 4 +FLAGS.SILENT (\\Answered)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_modseq(),
);
// SEQ 7: Insert message
assert_append_message(imap, "Pecorino", &messages.pop().unwrap(), ResponseType::Ok).await;
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
// SEQ 8: Delete a message
imap.send("UID STORE 2 +FLAGS.SILENT (\\Deleted)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("EXPUNGE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("VANISHED 2")
.assert_contains("* 3 EXISTS");
imap.send("STATUS Pecorino (HIGHESTMODSEQ)").await;
modseqs.push(
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_highest_modseq(),
);
// Fetch changes since SEQ 0
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[0]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("FETCH (", 3)
.assert_count("VANISHED", 0);
// Fetch changes since SEQ 1, UID MOVE should count as a deletion
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[1]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 1")
.assert_count("FETCH (", 3);
// Fetch changes since SEQ 3
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[3]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 3);
// Fetch changes since SEQ 4
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[4]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 2);
// Fetch changes since SEQ 6
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[6]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 1);
// Fetch changes since SEQ 7
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[7]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 0);
// Fetch changes since SEQ 8
imap.send(&format!(
"UID FETCH 1:* (FLAGS) (CHANGEDSINCE {} VANISHED)",
modseqs[8]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 0)
.assert_count("FETCH (", 0);
// Search since MODSEQ
imap.send(&format!("SEARCH RETURN (ALL) MODSEQ {}", modseqs[3]))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("ALL 1:3 MODSEQ");
imap_check.send("NOOP").await;
imap_check
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("3 EXISTS");
imap_check
.send(&format!("SEARCH MODSEQ {}", modseqs[4]))
.await;
imap_check
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("SEARCH 2 3 (MODSEQ");
// Store unchanged since
imap.send(&format!(
"UID STORE 2:5 (UNCHANGEDSINCE {}) +FLAGS.SILENT (\\Junk)",
modseqs[5]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* 1 FETCH")
.assert_contains("UID 3)")
.assert_count("FETCH (", 1)
.assert_contains("[MODIFIED 2,4:5]");
imap.send(&format!(
"UID STORE 4,5 (UNCHANGEDSINCE {}) -FLAGS.SILENT (\\Answered)",
modseqs[6]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* 2 FETCH")
.assert_contains("UID 4)")
.assert_count("FETCH (", 1)
.assert_contains("[MODIFIED 5]");
// QResync
imap.send("STATUS Pecorino (UIDVALIDITY)").await;
let uid_validity = imap
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.into_uid_validity();
imap.send(&format!(
"SELECT Pecorino (QRESYNC ({} {} 1:5)) ",
uid_validity, modseqs[6]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("FETCH (", 3)
.assert_contains("VANISHED (EARLIER) 1:2"); // .assert_contains("VANISHED (EARLIER) 2");
}