Email/set create tests passing
This commit is contained in:
@@ -6,10 +6,11 @@ resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
store = { path = "../crates/store", features = ["test_mode"] }
|
||||
jmap = { path = "../crates/jmap" }
|
||||
jmap = { path = "../crates/jmap", features = ["test_mode"] }
|
||||
jmap_proto = { path = "../crates/jmap-proto" }
|
||||
utils = { path = "../crates/utils" }
|
||||
jmap-client = { git = "https://github.com/stalwartlabs/jmap-client", features = ["websockets", "debug", "async"] }
|
||||
#jmap-client = { git = "https://github.com/stalwartlabs/jmap-client", features = ["websockets", "debug", "async"] }
|
||||
jmap-client = { path = "/home/vagrant/code/jmap-client", features = ["websockets", "debug", "async"] }
|
||||
mail-parser = { git = "https://github.com/stalwartlabs/mail-parser", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
|
||||
tokio = { version = "1.23", features = ["full"] }
|
||||
csv = "1.1"
|
||||
|
||||
341
tests/src/jmap/email_set.rs
Normal file
341
tests/src/jmap/email_set.rs
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, Stalwart Labs Ltd.
|
||||
*
|
||||
* This file is part of the Stalwart JMAP 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 std::{fs, path::PathBuf, sync::Arc};
|
||||
|
||||
use jmap::JMAP;
|
||||
use jmap_client::{
|
||||
client::Client,
|
||||
core::set::{SetError, SetErrorType},
|
||||
email::{self, Email},
|
||||
mailbox::Role,
|
||||
Error, Set,
|
||||
};
|
||||
use jmap_proto::types::id::Id;
|
||||
|
||||
use super::{find_values, replace_blob_ids, replace_boundaries, replace_values};
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
println!("Running Email Set tests...");
|
||||
|
||||
let mailbox_id = "a";
|
||||
let coco = "fix";
|
||||
/*client
|
||||
.set_default_account_id(Id::new(1).to_string())
|
||||
.mailbox_create("JMAP Set", None::<String>, Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();*/
|
||||
|
||||
create(client, &mailbox_id).await;
|
||||
//update(client, &mailbox_id).await;
|
||||
|
||||
let coco = "fd";
|
||||
//client.mailbox_destroy(&mailbox_id, true).await.unwrap();
|
||||
|
||||
//server.store.assert_is_empty();
|
||||
}
|
||||
|
||||
async fn create(client: &mut Client, mailbox_id: &str) {
|
||||
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
test_dir.push("resources");
|
||||
test_dir.push("jmap_mail_set");
|
||||
|
||||
for file_name in fs::read_dir(&test_dir).unwrap() {
|
||||
let mut file_name = file_name.as_ref().unwrap().path();
|
||||
if file_name.extension().map_or(true, |e| e != "json") {
|
||||
continue;
|
||||
}
|
||||
println!("Creating email from {:?}", file_name);
|
||||
|
||||
// Upload blobs
|
||||
let mut json_request = String::from_utf8(fs::read(&file_name).unwrap()).unwrap();
|
||||
let blob_values = find_values(&json_request, "\"blobId\"");
|
||||
if !blob_values.is_empty() {
|
||||
let mut blob_ids = Vec::with_capacity(blob_values.len());
|
||||
for blob_value in &blob_values {
|
||||
let blob_value = blob_value.replace("\\r", "\r").replace("\\n", "\n");
|
||||
blob_ids.push(
|
||||
client
|
||||
.upload(None, blob_value.into_bytes(), None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_blob_id(),
|
||||
);
|
||||
}
|
||||
json_request = replace_values(json_request, &blob_values, &blob_ids);
|
||||
}
|
||||
|
||||
// Create message and obtain its blobId
|
||||
let mut request = client.build();
|
||||
let mut create_item =
|
||||
serde_json::from_slice::<Email<Set>>(json_request.as_bytes()).unwrap();
|
||||
create_item.mailbox_ids([mailbox_id]);
|
||||
let create_id = request.set_email().create_item(create_item);
|
||||
let created_email = request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.created(&create_id)
|
||||
.unwrap();
|
||||
|
||||
// Download raw message
|
||||
let raw_message = client
|
||||
.download(created_email.blob_id().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Fetch message
|
||||
let mut request = client.build();
|
||||
request
|
||||
.get_email()
|
||||
.ids([created_email.id().unwrap()])
|
||||
.properties([
|
||||
email::Property::Id,
|
||||
email::Property::BlobId,
|
||||
email::Property::ThreadId,
|
||||
email::Property::MailboxIds,
|
||||
email::Property::Keywords,
|
||||
email::Property::ReceivedAt,
|
||||
email::Property::MessageId,
|
||||
email::Property::InReplyTo,
|
||||
email::Property::References,
|
||||
email::Property::Sender,
|
||||
email::Property::From,
|
||||
email::Property::To,
|
||||
email::Property::Cc,
|
||||
email::Property::Bcc,
|
||||
email::Property::ReplyTo,
|
||||
email::Property::Subject,
|
||||
email::Property::SentAt,
|
||||
email::Property::HasAttachment,
|
||||
email::Property::Preview,
|
||||
email::Property::BodyValues,
|
||||
email::Property::TextBody,
|
||||
email::Property::HtmlBody,
|
||||
email::Property::Attachments,
|
||||
email::Property::BodyStructure,
|
||||
])
|
||||
.arguments()
|
||||
.body_properties([
|
||||
email::BodyProperty::PartId,
|
||||
email::BodyProperty::BlobId,
|
||||
email::BodyProperty::Size,
|
||||
email::BodyProperty::Name,
|
||||
email::BodyProperty::Type,
|
||||
email::BodyProperty::Charset,
|
||||
email::BodyProperty::Headers,
|
||||
email::BodyProperty::Disposition,
|
||||
email::BodyProperty::Cid,
|
||||
email::BodyProperty::Language,
|
||||
email::BodyProperty::Location,
|
||||
])
|
||||
.fetch_all_body_values(true)
|
||||
.max_body_value_bytes(100);
|
||||
let email = request
|
||||
.send_get_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_test();
|
||||
|
||||
// Compare raw message
|
||||
file_name.set_extension("eml");
|
||||
let result = replace_boundaries(String::from_utf8(raw_message).unwrap());
|
||||
|
||||
if fs::read(&file_name).unwrap() != result.as_bytes() {
|
||||
file_name.set_extension("eml_failed");
|
||||
fs::write(&file_name, result.as_bytes()).unwrap();
|
||||
panic!("Test failed, output saved to {}", file_name.display());
|
||||
}
|
||||
|
||||
// Compare response
|
||||
file_name.set_extension("jmap");
|
||||
let result = replace_blob_ids(replace_boundaries(
|
||||
serde_json::to_string_pretty(&email).unwrap(),
|
||||
));
|
||||
if fs::read(&file_name).unwrap() != result.as_bytes() {
|
||||
file_name.set_extension("jmap_failed");
|
||||
fs::write(&file_name, result.as_bytes()).unwrap();
|
||||
panic!("Test failed, output saved to {}", file_name.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(client: &mut Client, root_mailbox_id: &str) {
|
||||
// Obtain all messageIds previously created
|
||||
let mailbox = client
|
||||
.email_query(
|
||||
email::query::Filter::in_mailbox(root_mailbox_id).into(),
|
||||
None::<Vec<_>>,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Create two test mailboxes
|
||||
let test_mailbox1_id = client
|
||||
.set_default_account_id(Id::new(1).to_string())
|
||||
.mailbox_create("Test 1", None::<String>, Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
let test_mailbox2_id = client
|
||||
.set_default_account_id(Id::new(1).to_string())
|
||||
.mailbox_create("Test 2", None::<String>, Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
|
||||
// Set keywords and mailboxes
|
||||
let mut request = client.build();
|
||||
request
|
||||
.set_email()
|
||||
.update(mailbox.id(0))
|
||||
.mailbox_ids([&test_mailbox1_id, &test_mailbox2_id])
|
||||
.keywords(["test1", "test2"]);
|
||||
request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.updated(mailbox.id(0))
|
||||
.unwrap();
|
||||
assert_email_properties(
|
||||
client,
|
||||
mailbox.id(0),
|
||||
&[&test_mailbox1_id, &test_mailbox2_id],
|
||||
&["test1", "test2"],
|
||||
)
|
||||
.await;
|
||||
|
||||
// Patch keywords and mailboxes
|
||||
let mut request = client.build();
|
||||
request
|
||||
.set_email()
|
||||
.update(mailbox.id(0))
|
||||
.mailbox_id(&test_mailbox1_id, false)
|
||||
.keyword("test1", true)
|
||||
.keyword("test2", false)
|
||||
.keyword("test3", true);
|
||||
request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.updated(mailbox.id(0))
|
||||
.unwrap();
|
||||
assert_email_properties(
|
||||
client,
|
||||
mailbox.id(0),
|
||||
&[&test_mailbox2_id],
|
||||
&["test1", "test3"],
|
||||
)
|
||||
.await;
|
||||
|
||||
// Orphan messages should not be permitted
|
||||
let mut request = client.build();
|
||||
request
|
||||
.set_email()
|
||||
.update(mailbox.id(0))
|
||||
.mailbox_id(&test_mailbox2_id, false);
|
||||
assert!(matches!(
|
||||
request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.updated(mailbox.id(0)),
|
||||
Err(Error::Set(SetError {
|
||||
type_: SetErrorType::InvalidProperties,
|
||||
..
|
||||
}))
|
||||
));
|
||||
|
||||
// Updating and destroying the same item should not be allowed
|
||||
let mut request = client.build();
|
||||
let set_email_request = request.set_email();
|
||||
set_email_request
|
||||
.update(mailbox.id(0))
|
||||
.mailbox_id(&test_mailbox2_id, false);
|
||||
set_email_request.destroy([mailbox.id(0)]);
|
||||
assert!(matches!(
|
||||
request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.updated(mailbox.id(0)),
|
||||
Err(Error::Set(SetError {
|
||||
type_: SetErrorType::WillDestroy,
|
||||
..
|
||||
}))
|
||||
));
|
||||
|
||||
// Delete some messages
|
||||
let mut request = client.build();
|
||||
request.set_email().destroy([mailbox.id(1), mailbox.id(2)]);
|
||||
assert_eq!(
|
||||
request
|
||||
.send_set_email()
|
||||
.await
|
||||
.unwrap()
|
||||
.destroyed_ids()
|
||||
.unwrap()
|
||||
.count(),
|
||||
2
|
||||
);
|
||||
let mut request = client.build();
|
||||
request.get_email().ids([mailbox.id(1), mailbox.id(2)]);
|
||||
assert_eq!(request.send_get_email().await.unwrap().not_found().len(), 2);
|
||||
|
||||
// Destroy test mailboxes
|
||||
client
|
||||
.mailbox_destroy(&test_mailbox1_id, true)
|
||||
.await
|
||||
.unwrap();
|
||||
client
|
||||
.mailbox_destroy(&test_mailbox2_id, true)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn assert_email_properties(
|
||||
client: &mut Client,
|
||||
message_id: &str,
|
||||
mailbox_ids: &[&str],
|
||||
keywords: &[&str],
|
||||
) {
|
||||
let result = client
|
||||
.email_get(
|
||||
message_id,
|
||||
[email::Property::MailboxIds, email::Property::Keywords].into(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mut mailbox_ids_ = result.mailbox_ids().to_vec();
|
||||
let mut keywords_ = result.keywords().to_vec();
|
||||
mailbox_ids_.sort_unstable();
|
||||
keywords_.sort_unstable();
|
||||
|
||||
assert_eq!(mailbox_ids_, mailbox_ids);
|
||||
assert_eq!(keywords_, keywords);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{collections::BTreeSet, sync::Arc};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use jmap::{api::SessionManager, JMAP};
|
||||
use jmap_client::client::{Client, Credentials};
|
||||
@@ -9,6 +9,7 @@ use crate::{add_test_certs, store::TempDir};
|
||||
|
||||
pub mod email_get;
|
||||
pub mod email_query;
|
||||
pub mod email_set;
|
||||
pub mod thread_get;
|
||||
pub mod thread_merge;
|
||||
|
||||
@@ -50,9 +51,10 @@ pub async fn jmap_tests() {
|
||||
let delete = true;
|
||||
let mut params = init_jmap_tests(delete).await;
|
||||
//email_get::test(params.server.clone(), &mut params.client).await;
|
||||
email_set::test(params.server.clone(), &mut params.client).await;
|
||||
//email_query::test(params.server.clone(), &mut params.client, delete).await;
|
||||
//thread_get::test(params.server.clone(), &mut params.client).await;
|
||||
thread_merge::test(params.server.clone(), &mut params.client).await;
|
||||
//thread_merge::test(params.server.clone(), &mut params.client).await;
|
||||
if delete {
|
||||
params.temp_dir.delete();
|
||||
}
|
||||
@@ -84,7 +86,7 @@ async fn init_jmap_tests(delete_if_exists: bool) -> JMAPTest {
|
||||
// Create client
|
||||
let mut client = Client::new()
|
||||
.credentials(Credentials::bearer("DO_NOT_ATTEMPT_THIS_AT_HOME"))
|
||||
.timeout(360000)
|
||||
.timeout(Duration::from_secs(60))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
.await
|
||||
@@ -143,7 +145,6 @@ pub fn replace_boundaries(string: String) -> String {
|
||||
pub fn replace_blob_ids(string: String) -> String {
|
||||
let values = find_values(&string, "blobId\":");
|
||||
if !values.is_empty() {
|
||||
//let values = BTreeSet::from_iter(values).into_iter().collect::<Vec<_>>();
|
||||
replace_values(
|
||||
string,
|
||||
&values,
|
||||
|
||||
@@ -20,7 +20,7 @@ async fn test_1(db: Arc<Store>) {
|
||||
for id in 0..100 {
|
||||
handles.push({
|
||||
let db = db.clone();
|
||||
tokio::spawn(async move { db.assign_change_id(0, 0).await })
|
||||
tokio::spawn(async move { db.assign_change_id(0).await })
|
||||
});
|
||||
expected_ids.insert(id);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ pub async fn test(db: Arc<Store>, do_insert: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
builder.custom(fts_builder).unwrap();
|
||||
builder.custom(fts_builder);
|
||||
documents.lock().unwrap().push(builder.build());
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user