| | use std::time::Duration; |
| |
|
| | use regex::Regex; |
| | use serde_json::json; |
| |
|
| | use super::*; |
| | use crate::chat::{ |
| | ChatId, MuteDuration, add_contact_to_chat, create_broadcast, create_group, forward_msgs, |
| | remove_contact_from_chat, resend_msgs, send_msg, send_text_msg, set_muted, |
| | }; |
| | use crate::chatlist::Chatlist; |
| | use crate::config::Config; |
| | use crate::download::DownloadState; |
| | use crate::ephemeral; |
| | use crate::receive_imf::{receive_imf, receive_imf_from_inbox}; |
| | use crate::test_utils::{E2EE_INFO_MSGS, TestContext, TestContextManager}; |
| | use crate::tools::{self, SystemTime}; |
| | use crate::{message, sql}; |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_is_webxdc_file() -> Result<()> { |
| | let t = TestContext::new().await; |
| | assert!( |
| | !t.is_webxdc_file( |
| | "bad-ext-no-zip.txt", |
| | include_bytes!("../../test-data/message/issue_523.txt") |
| | ) |
| | .await? |
| | ); |
| | assert!( |
| | !t.is_webxdc_file( |
| | "bad-ext-good-zip.txt", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc") |
| | ) |
| | .await? |
| | ); |
| | assert!( |
| | !t.is_webxdc_file( |
| | "good-ext-no-zip.xdc", |
| | include_bytes!("../../test-data/message/issue_523.txt") |
| | ) |
| | .await? |
| | ); |
| | assert!( |
| | !t.is_webxdc_file( |
| | "good-ext-no-index-html.xdc", |
| | include_bytes!("../../test-data/webxdc/no-index-html.xdc") |
| | ) |
| | .await? |
| | ); |
| | assert!( |
| | t.is_webxdc_file( |
| | "good-ext-good-zip.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc") |
| | ) |
| | .await? |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | fn create_webxdc_instance(t: &TestContext, name: &str, bytes: &[u8]) -> Result<Message> { |
| | let mut instance = Message::new(Viewtype::File); |
| | instance.set_file_from_bytes(t, name, bytes, None)?; |
| | Ok(instance) |
| | } |
| |
|
| | async fn send_webxdc_instance(t: &TestContext, chat_id: ChatId) -> Result<Message> { |
| | let mut instance = create_webxdc_instance( |
| | t, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | let instance_msg_id = send_msg(t, chat_id, &mut instance).await?; |
| | assert_eq!(instance.viewtype, Viewtype::Webxdc); |
| | Message::load_from_db(t, instance_msg_id).await |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_webxdc_instance() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | assert_eq!(instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(instance.get_filename(), Some("minimal.xdc".to_string())); |
| | assert_eq!(instance.chat_id, chat_id); |
| |
|
| | |
| | let mut instance = Message::new(Viewtype::Webxdc); |
| | instance.set_file_from_bytes(&t, "index.html", b"<html>ola!</html>", None)?; |
| | assert!(send_msg(&t, chat_id, &mut instance).await.is_err()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_invalid_webxdc() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "invalid-no-zip-but-7z.xdc", |
| | include_bytes!("../../test-data/webxdc/invalid-no-zip-but-7z.xdc"), |
| | )?; |
| | let instance_id = send_msg(&t, chat_id, &mut instance).await?; |
| | assert_eq!(instance.viewtype, Viewtype::File); |
| | let test = Message::load_from_db(&t, instance_id).await?; |
| | assert_eq!(test.viewtype, Viewtype::File); |
| |
|
| | |
| | let mut instance = Message::new(Viewtype::Webxdc); |
| | instance.set_file_from_bytes( |
| | &t, |
| | "invalid2.xdc", |
| | include_bytes!("../../test-data/webxdc/invalid-no-zip-but-7z.xdc"), |
| | None, |
| | )?; |
| | assert!(send_msg(&t, chat_id, &mut instance).await.is_err()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_set_draft_invalid_webxdc() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "invalid-no-zip-but-7z.xdc", |
| | include_bytes!("../../test-data/webxdc/invalid-no-zip-but-7z.xdc"), |
| | )?; |
| |
|
| | |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | chat_id.get_draft(&t).await.unwrap(); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_special_webxdc_format() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "chess.xdc", |
| | include_bytes!("../../test-data/webxdc/chess.xdc"), |
| | )?; |
| | let instance_id = send_msg(&t, chat_id, &mut instance).await?; |
| | let instance = Message::load_from_db(&t, instance_id).await?; |
| | assert_eq!(instance.viewtype, Viewtype::Webxdc); |
| |
|
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "Chess Board"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_forward_webxdc_instance() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | t.send_webxdc_status_update( |
| | instance.id, |
| | r#"{"info": "foo", "summary":"bar", "document":"doc", "payload": 42}"#, |
| | ) |
| | .await?; |
| | assert!(!instance.is_forwarded()); |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":42,"info":"foo","document":"doc","summary":"bar","serial":1,"max_serial":1}]"# |
| | ); |
| | assert_eq!(chat_id.get_msg_cnt(&t).await?, 3); |
| | let info = Message::load_from_db(&t, instance.id) |
| | .await? |
| | .get_webxdc_info(&t) |
| | .await?; |
| | assert_eq!(info.summary, "bar".to_string()); |
| | assert_eq!(info.document, "doc".to_string()); |
| |
|
| | |
| | forward_msgs(&t, &[instance.get_id()], chat_id).await?; |
| | let instance2 = t.get_last_msg_in(chat_id).await; |
| | assert!(instance2.is_forwarded()); |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance2.id, StatusUpdateSerial(0)) |
| | .await?, |
| | "[]" |
| | ); |
| | assert_eq!(chat_id.get_msg_cnt(&t).await?, 4); |
| | let info = Message::load_from_db(&t, instance2.id) |
| | .await? |
| | .get_webxdc_info(&t) |
| | .await?; |
| | assert_eq!(info.summary, "".to_string()); |
| | assert_eq!(info.document, "".to_string()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_resend_webxdc_instance_and_info() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | |
| | alice.set_config_bool(Config::BccSelf, false).await?; |
| | let alice_grp = create_group(&alice, "grp").await?; |
| | let alice_instance = send_webxdc_instance(&alice, alice_grp).await?; |
| | assert_eq!(alice_grp.get_msg_cnt(&alice).await?, 2); |
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | r#"{"payload":7,"info": "i","summary":"s"}"#, |
| | ) |
| | .await?; |
| | assert_eq!(alice_grp.get_msg_cnt(&alice).await?, 3); |
| | assert!(alice.get_last_msg_in(alice_grp).await.is_info()); |
| |
|
| | |
| | add_contact_to_chat( |
| | &alice, |
| | alice_grp, |
| | alice.add_or_lookup_contact_id(&bob).await, |
| | ) |
| | .await?; |
| | assert_eq!(alice_grp.get_msg_cnt(&alice).await?, 4); |
| | resend_msgs(&alice, &[alice_instance.id]).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| |
|
| | |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | bob.recv_msg_trash(&sent2).await; |
| | assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); |
| | assert!(!bob_instance.is_info()); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":7,"info":"i","summary":"s","serial":1,"max_serial":1}]"# |
| | ); |
| | let bob_grp = bob_instance.chat_id; |
| | assert_eq!(bob.get_last_msg_in(bob_grp).await.id, bob_instance.id); |
| | assert_eq!(bob_grp.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_receive_webxdc_instance() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | receive_imf( |
| | &t, |
| | include_bytes!("../../test-data/message/webxdc_good_extension.eml"), |
| | false, |
| | ) |
| | .await?; |
| | let instance = t.get_last_msg().await; |
| | assert_eq!(instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(instance.get_filename().unwrap(), "minimal.xdc"); |
| |
|
| | receive_imf( |
| | &t, |
| | include_bytes!("../../test-data/message/webxdc_bad_extension.eml"), |
| | false, |
| | ) |
| | .await?; |
| | let instance = t.get_last_msg().await; |
| | assert_eq!(instance.viewtype, Viewtype::File); |
| | assert_eq!(instance.get_filename().unwrap(), "index.html"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_contact_request() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let _alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | bob.recv_msg(&alice.pop_sent_msg().await).await; |
| |
|
| | |
| | |
| | let bob_instance = bob.get_last_msg().await; |
| | let bob_chat = Chat::load_from_db(&bob, bob_instance.chat_id).await?; |
| | assert!(bob_chat.is_contact_request()); |
| | assert!( |
| | bob_instance |
| | .get_webxdc_blob(&bob, "index.html") |
| | .await |
| | .is_ok() |
| | ); |
| | assert!( |
| | bob.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#) |
| | .await |
| | .is_err() |
| | ); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | "[]" |
| | ); |
| |
|
| | |
| | bob_chat.id.accept(&bob).await?; |
| | assert!( |
| | bob.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#) |
| | .await |
| | .is_ok() |
| | ); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":42,"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_update_for_not_downloaded_instance() -> Result<()> { |
| | |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| | let chat = alice.create_chat(&bob).await; |
| | bob.set_config(Config::DownloadLimit, Some("40000")).await?; |
| | let mut alice_instance = create_webxdc_instance( |
| | &alice, |
| | "chess.xdc", |
| | include_bytes!("../../test-data/webxdc/chess.xdc"), |
| | )?; |
| | let sent1 = alice.send_msg(chat.id, &mut alice_instance).await; |
| | let alice_instance = sent1.load_from_db().await; |
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | r#"{"payload": 7, "summary":"sum", "document":"doc"}"#, |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| |
|
| | |
| | receive_imf_from_inbox( |
| | &bob, |
| | &alice_instance.rfc724_mid, |
| | sent1.payload().as_bytes(), |
| | false, |
| | Some(70790), |
| | ) |
| | .await?; |
| | let bob_instance = bob.get_last_msg().await; |
| | bob_instance.chat_id.accept(&bob).await?; |
| | bob.recv_msg_trash(&sent2).await; |
| | assert_eq!(bob_instance.download_state, DownloadState::Available); |
| |
|
| | |
| | let received_msg = receive_imf_from_inbox( |
| | &bob, |
| | &alice_instance.rfc724_mid, |
| | sent1.payload().as_bytes(), |
| | false, |
| | None, |
| | ) |
| | .await? |
| | .unwrap(); |
| | assert_eq!(*received_msg.msg_ids.first().unwrap(), bob_instance.id); |
| | let bob_instance = bob.get_last_msg().await; |
| | assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(bob_instance.download_state, DownloadState::Done); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":7,"document":"doc","summary":"sum","serial":1,"max_serial":1}]"# |
| | ); |
| | let info = bob_instance.get_webxdc_info(&bob).await?; |
| | assert_eq!(info.document, "doc"); |
| | assert_eq!(info.summary, "sum"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_delete_webxdc_instance() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let now = tools::time(); |
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updates":[{"payload":1}]}"#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 1 |
| | ); |
| |
|
| | message::delete_msgs(&t, &[instance.id]).await?; |
| | sql::housekeeping(&t).await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 0 |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_delete_chat_with_webxdc() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let now = tools::time(); |
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updates":[{"payload":1}, {"payload":2}]}"#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 2 |
| | ); |
| |
|
| | chat_id.delete(&t).await?; |
| | sql::housekeeping(&t).await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 0 |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_delete_webxdc_draft() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let instance = chat_id.get_draft(&t).await?.unwrap(); |
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 42}"#) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":42,"serial":1,"max_serial":1}]"#.to_string() |
| | ); |
| |
|
| | |
| | chat_id.set_draft(&t, None).await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | "[]".to_string() |
| | ); |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 0 |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_create_status_update_record() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| |
|
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | "[]" |
| | ); |
| |
|
| | let update_id1 = t |
| | .create_status_update_record( |
| | &instance, |
| | StatusUpdateItem { |
| | payload: json!({"foo": "bar"}), |
| | info: None, |
| | href: None, |
| | document: None, |
| | summary: None, |
| | uid: Some("iecie2Ze".to_string()), |
| | notify: None, |
| | }, |
| | 1640178619, |
| | true, |
| | ContactId::SELF, |
| | ) |
| | .await? |
| | .unwrap(); |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | |
| | |
| | let update_id1_duplicate = t |
| | .create_status_update_record( |
| | &instance, |
| | StatusUpdateItem { |
| | payload: json!({"nothing": "this should be ignored"}), |
| | info: None, |
| | href: None, |
| | document: None, |
| | summary: None, |
| | uid: Some("iecie2Ze".to_string()), |
| | notify: None, |
| | }, |
| | 1640178619, |
| | true, |
| | ContactId::SELF, |
| | ) |
| | .await?; |
| | assert_eq!(update_id1_duplicate, None); |
| |
|
| | assert!( |
| | t.send_webxdc_status_update(instance.id, "\n\n\n") |
| | .await |
| | .is_err() |
| | ); |
| |
|
| | assert!( |
| | t.send_webxdc_status_update(instance.id, "bad json") |
| | .await |
| | .is_err() |
| | ); |
| |
|
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | let update_id2 = t |
| | .create_status_update_record( |
| | &instance, |
| | StatusUpdateItem { |
| | payload: json!({"foo2": "bar2"}), |
| | info: None, |
| | href: None, |
| | document: None, |
| | summary: None, |
| | uid: None, |
| | notify: None, |
| | }, |
| | 1640178619, |
| | true, |
| | ContactId::SELF, |
| | ) |
| | .await? |
| | .unwrap(); |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, update_id1).await?, |
| | r#"[{"payload":{"foo2":"bar2"},"serial":3,"max_serial":3}]"# |
| | ); |
| | t.create_status_update_record( |
| | &instance, |
| | StatusUpdateItem { |
| | payload: Value::Bool(true), |
| | info: None, |
| | href: None, |
| | document: None, |
| | summary: None, |
| | uid: None, |
| | notify: None, |
| | }, |
| | 1640178619, |
| | true, |
| | ContactId::SELF, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":4}, |
| | {"payload":{"foo2":"bar2"},"serial":3,"max_serial":4}, |
| | {"payload":true,"serial":4,"max_serial":4}]"# |
| | ); |
| |
|
| | t.send_webxdc_status_update( |
| | instance.id, |
| | r#"{"payload" : 1, "sender": "that is not used"}"#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, update_id2).await?, |
| | r#"[{"payload":true,"serial":4,"max_serial":5}, |
| | {"payload":1,"serial":5,"max_serial":5}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_receive_status_update() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let now = tools::time(); |
| |
|
| | assert!( |
| | t.receive_status_update(ContactId::SELF, &instance, now, true, r#"foo: bar"#) |
| | .await |
| | .is_err() |
| | ); |
| | assert!( |
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updada":[{"payload":{"foo":"bar"}}]}"# |
| | ) |
| | .await |
| | .is_err() |
| | ); |
| | assert!( |
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updates":[{"foo":"bar"}]}"# |
| | ) |
| | .await |
| | .is_err() |
| | ); |
| | assert!( |
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updates":{"payload":{"foo":"bar"}}}"# |
| | ) |
| | .await |
| | .is_err() |
| | ); |
| |
|
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#"{"updates":[{"payload":{"foo":"bar"}, "someTrash": "definitely TrAsH"}]}"#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#" {"updates": [ {"payload" :42} , {"payload": 23} ] } "#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":3}, |
| | {"payload":42,"serial":2,"max_serial":3}, |
| | {"payload":23,"serial":3,"max_serial":3}]"# |
| | ); |
| |
|
| | t.receive_status_update( |
| | ContactId::SELF, |
| | &instance, |
| | now, |
| | true, |
| | r#" {"updates": [ {"payload" :"ok", "future_item": "test"} ], "from": "future" } "#, |
| | ) |
| | .await?; |
| | assert_eq!( |
| | t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":4}, |
| | {"payload":42,"serial":2,"max_serial":4}, |
| | {"payload":23,"serial":3,"max_serial":4}, |
| | {"payload":"ok","serial":4,"max_serial":4}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | async fn expect_status_update_event(t: &TestContext, instance_id: MsgId) -> Result<()> { |
| | let event = t |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::WebxdcStatusUpdate { .. })) |
| | .await; |
| | match event { |
| | EventType::WebxdcStatusUpdate { |
| | msg_id, |
| | status_update_serial: _, |
| | } => { |
| | assert_eq!(msg_id, instance_id); |
| | } |
| | _ => unreachable!(), |
| | } |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_webxdc_status_update() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | alice.set_config_bool(Config::BccSelf, true).await?; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_email_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent1 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_instance.viewtype, Viewtype::Webxdc); |
| | assert!(!sent1.payload().contains("report-type=status-update")); |
| |
|
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload" : {"foo":"bar"}}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | expect_status_update_event(&alice, alice_instance.id).await?; |
| | let sent2 = &alice.pop_sent_msg().await; |
| | let alice_update = sent2.load_from_db().await; |
| | assert!(alice_update.hidden); |
| | assert_eq!(alice_update.viewtype, Viewtype::Text); |
| | assert_eq!(alice_update.get_filename(), None); |
| | assert_eq!(alice_update.text, BODY_DESCR.to_string()); |
| | assert_eq!(alice_update.chat_id, alice_instance.chat_id); |
| | assert_eq!( |
| | alice_update.parent(&alice).await?.unwrap().id, |
| | alice_instance.id |
| | ); |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 1); |
| | assert!(sent2.payload().contains("report-type=status-update")); |
| | assert!(sent2.payload().contains(BODY_DESCR)); |
| | assert_eq!( |
| | alice |
| | .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload":{"snipp":"snapp"}}"#) |
| | .await?; |
| | assert_eq!( |
| | alice |
| | .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":2}, |
| | {"payload":{"snipp":"snapp"},"serial":2,"max_serial":2}]"# |
| | ); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent1).await; |
| | let bob_chat_id = bob_instance.chat_id; |
| | assert_eq!(bob_instance.rfc724_mid, alice_instance.rfc724_mid); |
| | assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1); |
| |
|
| | let bob_received_update = bob.recv_msg_opt(sent2).await; |
| | assert!(bob_received_update.is_none()); |
| | expect_status_update_event(&bob, bob_instance.id).await?; |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1); |
| |
|
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | |
| | let alice2 = TestContext::new_alice().await; |
| | alice2.recv_msg(sent1).await; |
| | alice2.recv_msg_trash(sent2).await; |
| | let alice2_instance = alice2.get_last_msg().await; |
| | let alice2_chat_id = alice2_instance.chat_id; |
| | assert_eq!(alice2_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(alice2_chat_id.get_msg_cnt(&alice2).await?, 1); |
| |
|
| | |
| | |
| | alice.recv_msg_opt(sent1).await; |
| | alice.recv_msg_opt(sent2).await; |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 1); |
| | assert_eq!( |
| | alice |
| | .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":2}, |
| | {"payload":{"snipp":"snapp"},"serial":2,"max_serial":2}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_big_webxdc_status_update() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | alice.set_config_bool(Config::BccSelf, true).await?; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent1 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_instance.viewtype, Viewtype::Webxdc); |
| | assert!(!sent1.payload().contains("report-type=status-update")); |
| |
|
| | let update1_str = r#"{"payload":{"foo":""#.to_string() |
| | + &String::from_utf8(vec![b'a'; STATUS_UPDATE_SIZE_MAX])? |
| | + r#""}"#; |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, &(update1_str.clone() + "}")) |
| | .await?; |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload" : {"foo":"bar2"}}"#) |
| | .await?; |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload" : {"foo":"bar3"}}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| |
|
| | |
| | let sent3 = &alice.pop_sent_msg().await; |
| | let alice_update = sent3.load_from_db().await; |
| | assert_eq!(alice_update.text, BODY_DESCR.to_string()); |
| | let sent2 = &alice.pop_sent_msg().await; |
| | let alice_update = sent2.load_from_db().await; |
| | assert_eq!(alice_update.text, BODY_DESCR.to_string()); |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 1); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent1).await; |
| | let bob_chat_id = bob_instance.chat_id; |
| | assert_eq!(bob_instance.rfc724_mid, alice_instance.rfc724_mid); |
| | assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1); |
| |
|
| | |
| | bob.recv_msg_trash(sent2).await; |
| | expect_status_update_event(&bob, bob_instance.id).await?; |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | "[".to_string() + &update1_str + r#","serial":1,"max_serial":1}]"# |
| | ); |
| | bob.recv_msg_trash(sent3).await; |
| | for _ in 0..2 { |
| | expect_status_update_event(&bob, bob_instance.id).await?; |
| | } |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(1)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar2"},"serial":2,"max_serial":3}, |
| | {"payload":{"foo":"bar3"},"serial":3,"max_serial":3}]"# |
| | ); |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_render_webxdc_status_update_object() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "a chat").await?; |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let (first, last) = (StatusUpdateSerial(1), StatusUpdateSerial::MAX); |
| | assert_eq!( |
| | t.render_webxdc_status_update_object(instance.id, first, last, None) |
| | .await?, |
| | (None, StatusUpdateSerial(u32::MAX)) |
| | ); |
| |
|
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 1}"#) |
| | .await?; |
| | let (object, first_new) = t |
| | .render_webxdc_status_update_object(instance.id, first, last, None) |
| | .await?; |
| | assert!(object.is_some()); |
| | assert_eq!(first_new, StatusUpdateSerial(u32::MAX)); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_render_webxdc_status_update_object_range() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "a chat").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 1}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 2}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 3}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance.id, r#"{"payload": 4}"#) |
| | .await?; |
| | let (json, first_new) = t |
| | .render_webxdc_status_update_object( |
| | instance.id, |
| | StatusUpdateSerial(2), |
| | StatusUpdateSerial(3), |
| | None, |
| | ) |
| | .await?; |
| | let json = json.unwrap(); |
| | assert_eq!(first_new, StatusUpdateSerial(4)); |
| | let json = Regex::new(r#""uid":"[^"]*""#) |
| | .unwrap() |
| | .replace_all(&json, "XXX"); |
| | assert_eq!( |
| | json, |
| | "{\"updates\":[{\"payload\":2,XXX},\n{\"payload\":3,XXX}]}" |
| | ); |
| |
|
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM smtp_status_updates", ()) |
| | .await?, |
| | 1 |
| | ); |
| | t.flush_status_updates().await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM smtp_status_updates", ()) |
| | .await?, |
| | 0 |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_pop_status_update() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "a chat").await?; |
| | let instance1 = send_webxdc_instance(&t, chat_id).await?; |
| | let instance2 = send_webxdc_instance(&t, chat_id).await?; |
| | let instance3 = send_webxdc_instance(&t, chat_id).await?; |
| | assert!(t.smtp_status_update_get().await?.is_none()); |
| |
|
| | t.send_webxdc_status_update(instance1.id, r#"{"payload": "1a"}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance2.id, r#"{"payload": "2a"}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance2.id, r#"{"payload": "2b"}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance3.id, r#"{"payload": "3a"}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance3.id, r#"{"payload": "3b"}"#) |
| | .await?; |
| | t.send_webxdc_status_update(instance3.id, r#"{"payload": "3c"}"#) |
| | .await?; |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM smtp_status_updates", ()) |
| | .await?, |
| | 3 |
| | ); |
| |
|
| | |
| | let mut instances_checked = 0; |
| | for i in 0..3 { |
| | let (instance, min_ser, max_ser) = t.smtp_status_update_get().await?.unwrap(); |
| | t.smtp_status_update_pop_serials( |
| | instance, |
| | min_ser, |
| | StatusUpdateSerial::new(max_ser.to_u32().checked_add(1).unwrap()), |
| | ) |
| | .await?; |
| | let min_ser: u32 = min_ser.try_into()?; |
| | if instance == instance1.id { |
| | assert_eq!(min_ser, max_ser.to_u32()); |
| |
|
| | instances_checked += 1; |
| | } else if instance == instance2.id { |
| | assert_eq!(min_ser, max_ser.to_u32() - 1); |
| |
|
| | instances_checked += 1; |
| | } else if instance == instance3.id { |
| | assert_eq!(min_ser, max_ser.to_u32() - 2); |
| | instances_checked += 1; |
| | } else { |
| | bail!("unexpected instance"); |
| | } |
| | assert_eq!( |
| | t.sql |
| | .count("SELECT COUNT(*) FROM smtp_status_updates", ()) |
| | .await?, |
| | 2 - i |
| | ); |
| | } |
| | assert_eq!(instances_checked, 3); |
| | assert!(t.smtp_status_update_get().await?.is_none()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_draft_and_send_webxdc_status_update() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| | let alice_chat_id = alice.create_email_chat(&bob).await.id; |
| |
|
| | |
| | |
| | let mut alice_instance = create_webxdc_instance( |
| | &alice, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | alice_chat_id |
| | .set_draft(&alice, Some(&mut alice_instance)) |
| | .await?; |
| | let mut alice_instance = alice_chat_id.get_draft(&alice).await?.unwrap(); |
| |
|
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload": {"foo":"bar"}}"#) |
| | .await?; |
| | expect_status_update_event(&alice, alice_instance.id).await?; |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"payload":42, "info":"i"}"#) |
| | .await?; |
| | expect_status_update_event(&alice, alice_instance.id).await?; |
| | assert_eq!( |
| | alice |
| | .sql |
| | .count("SELECT COUNT(*) FROM smtp_status_updates", ()) |
| | .await?, |
| | 0 |
| | ); |
| | assert!(!alice.get_last_msg().await.is_info()); |
| |
|
| | |
| | |
| | let alice_instance_id = send_msg(&alice, alice_chat_id, &mut alice_instance).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let alice_instance = Message::load_from_db(&alice, alice_instance_id).await?; |
| | assert_eq!(alice_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!( |
| | alice_instance.get_filename(), |
| | Some("minimal.xdc".to_string()) |
| | ); |
| | assert_eq!(alice_instance.chat_id, alice_chat_id); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); |
| | assert_eq!(bob_instance.get_filename().unwrap(), "minimal.xdc"); |
| | assert!(sent1.payload().contains("Content-Type: application/json")); |
| | assert!(sent1.payload().contains("status-update.json")); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":2}, |
| | {"payload":42,"info":"i","serial":2,"max_serial":2}]"# |
| | ); |
| | assert!(!bob.get_last_msg().await.is_info()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_webxdc_status_update_to_non_webxdc() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let msg_id = send_text_msg(&t, chat_id, "ho!".to_string()).await?; |
| | assert!( |
| | t.send_webxdc_status_update(msg_id, r#"{"foo":"bar"}"#) |
| | .await |
| | .is_err() |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_blob() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| |
|
| | let buf = instance.get_webxdc_blob(&t, "index.html").await?; |
| | assert_eq!(buf.len(), 188); |
| | assert!(String::from_utf8_lossy(&buf).contains("document.write")); |
| |
|
| | assert!( |
| | instance |
| | .get_webxdc_blob(&t, "not-existent.html") |
| | .await |
| | .is_err() |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_blob_default_icon() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| |
|
| | let buf = instance.get_webxdc_blob(&t, WEBXDC_DEFAULT_ICON).await?; |
| | assert!(buf.len() > 100); |
| | assert!(String::from_utf8_lossy(&buf).contains("PNG\r\n")); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_blob_with_absolute_paths() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| |
|
| | let buf = instance.get_webxdc_blob(&t, "/index.html").await?; |
| | assert!(String::from_utf8_lossy(&buf).contains("document.write")); |
| |
|
| | assert!(instance.get_webxdc_blob(&t, "/not-there").await.is_err()); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_blob_with_subdirs() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "some-files.xdc", |
| | include_bytes!("../../test-data/webxdc/some-files.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| |
|
| | let buf = instance.get_webxdc_blob(&t, "index.html").await?; |
| | assert_eq!(buf.len(), 65); |
| | assert!(String::from_utf8_lossy(&buf).contains("many files")); |
| |
|
| | let buf = instance.get_webxdc_blob(&t, "subdir/bla.txt").await?; |
| | assert_eq!(buf.len(), 4); |
| | assert!(String::from_utf8_lossy(&buf).starts_with("bla")); |
| |
|
| | let buf = instance |
| | .get_webxdc_blob(&t, "subdir/subsubdir/text.md") |
| | .await?; |
| | assert_eq!(buf.len(), 24); |
| | assert!(String::from_utf8_lossy(&buf).starts_with("this is a markdown file")); |
| |
|
| | let buf = instance |
| | .get_webxdc_blob(&t, "subdir/subsubdir/text2.md") |
| | .await?; |
| | assert_eq!(buf.len(), 22); |
| | assert!(String::from_utf8_lossy(&buf).starts_with("another markdown")); |
| |
|
| | let buf = instance |
| | .get_webxdc_blob(&t, "anotherdir/anothersubsubdir/foo.txt") |
| | .await?; |
| | assert_eq!(buf.len(), 4); |
| | assert!(String::from_utf8_lossy(&buf).starts_with("foo")); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_parse_webxdc_manifest() -> Result<()> { |
| | let result = parse_webxdc_manifest(r#"key = syntax error"#.as_bytes()); |
| | assert!(result.is_err()); |
| |
|
| | let manifest = parse_webxdc_manifest(r#"no_name = "no name, no icon""#.as_bytes())?; |
| | assert_eq!(manifest.name, None); |
| |
|
| | let manifest = parse_webxdc_manifest(r#"name = "name, no icon""#.as_bytes())?; |
| | assert_eq!(manifest.name, Some("name, no icon".to_string())); |
| |
|
| | let manifest = parse_webxdc_manifest( |
| | r#"name = "foo" |
| | icon = "bar""# |
| | .as_bytes(), |
| | )?; |
| | assert_eq!(manifest.name, Some("foo".to_string())); |
| |
|
| | let manifest = parse_webxdc_manifest( |
| | r#"name = "foz" |
| | icon = "baz" |
| | add_item = "that should be just ignored" |
| | |
| | [section] |
| | sth_for_the = "future""# |
| | .as_bytes(), |
| | )?; |
| | assert_eq!(manifest.name, Some("foz".to_string())); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_parse_webxdc_manifest_min_api() -> Result<()> { |
| | let manifest = parse_webxdc_manifest(r#"min_api = 3"#.as_bytes())?; |
| | assert_eq!(manifest.min_api, Some(3)); |
| |
|
| | let result = parse_webxdc_manifest(r#"min_api = "1""#.as_bytes()); |
| | assert!(result.is_err()); |
| |
|
| | let result = parse_webxdc_manifest(r#"min_api = 1.2"#.as_bytes()); |
| | assert!(result.is_err()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_parse_webxdc_manifest_source_code_url() -> Result<()> { |
| | let result = parse_webxdc_manifest(r#"source_code_url = 3"#.as_bytes()); |
| | assert!(result.is_err()); |
| |
|
| | let manifest = parse_webxdc_manifest(r#"source_code_url = "https://foo.bar""#.as_bytes())?; |
| | assert_eq!( |
| | manifest.source_code_url, |
| | Some("https://foo.bar".to_string()) |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_min_api_too_large() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "chat").await?; |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-min-api-1001.xdc", |
| | include_bytes!("../../test-data/webxdc/with-min-api-1001.xdc"), |
| | )?; |
| | send_msg(&t, chat_id, &mut instance).await?; |
| |
|
| | let instance = t.get_last_msg().await; |
| | let html = instance.get_webxdc_blob(&t, "index.html").await?; |
| | assert!(String::from_utf8_lossy(&html).contains("requires a newer Delta Chat version")); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_info() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "minimal.xdc"); |
| | assert_eq!(info.icon, WEBXDC_DEFAULT_ICON.to_string()); |
| | assert_eq!(info.send_update_interval, 1000); |
| | assert_eq!(info.send_update_max_size, RECOMMENDED_FILE_SIZE as usize); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-manifest-empty-name.xdc", |
| | include_bytes!("../../test-data/webxdc/with-manifest-empty-name.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "with-manifest-empty-name.xdc"); |
| | assert_eq!(info.icon, WEBXDC_DEFAULT_ICON.to_string()); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-manifest-no-name.xdc", |
| | include_bytes!("../../test-data/webxdc/with-manifest-no-name.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "with-manifest-no-name.xdc"); |
| | assert_eq!(info.icon, WEBXDC_DEFAULT_ICON.to_string()); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-minimal-manifest.xdc", |
| | include_bytes!("../../test-data/webxdc/with-minimal-manifest.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "nice app!"); |
| | assert_eq!(info.icon, WEBXDC_DEFAULT_ICON.to_string()); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-manifest-and-png-icon.xdc", |
| | include_bytes!("../../test-data/webxdc/with-manifest-and-png-icon.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "with some icon"); |
| | assert_eq!(info.icon, "icon.png"); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-png-icon.xdc", |
| | include_bytes!("../../test-data/webxdc/with-png-icon.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "with-png-icon.xdc"); |
| | assert_eq!(info.icon, "icon.png"); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-jpg-icon.xdc", |
| | include_bytes!("../../test-data/webxdc/with-jpg-icon.xdc"), |
| | )?; |
| | chat_id.set_draft(&t, Some(&mut instance)).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.name, "with-jpg-icon.xdc"); |
| | assert_eq!(info.icon, "icon.jpg"); |
| |
|
| | let msg_id = send_text_msg(&t, chat_id, "foo".to_string()).await?; |
| | let msg = Message::load_from_db(&t, msg_id).await?; |
| | let result = msg.get_webxdc_info(&t).await; |
| | assert!(result.is_err()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_webxdc_self_addr() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "foo").await?; |
| |
|
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let info1 = instance.get_webxdc_info(&t).await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| | let info2 = instance.get_webxdc_info(&t).await?; |
| |
|
| | let real_addr = t.get_primary_self_addr().await?; |
| | assert!(!info1.self_addr.contains(&real_addr)); |
| | assert_ne!(info1.self_addr, info2.self_addr); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_info_summary() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent_instance = &alice.pop_sent_msg().await; |
| | let info = alice_instance.get_webxdc_info(&alice).await?; |
| | assert_eq!(info.summary, "".to_string()); |
| |
|
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"summary":"sum: 1", "payload":1}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent_update1 = &alice.pop_sent_msg().await; |
| | let info = Message::load_from_db(&alice, alice_instance.id) |
| | .await? |
| | .get_webxdc_info(&alice) |
| | .await?; |
| | assert_eq!(info.summary, "sum: 1".to_string()); |
| |
|
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"summary":"sum: 2", "payload":2}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent_update2 = &alice.pop_sent_msg().await; |
| | let info = Message::load_from_db(&alice, alice_instance.id) |
| | .await? |
| | .get_webxdc_info(&alice) |
| | .await?; |
| | assert_eq!(info.summary, "sum: 2".to_string()); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent_instance).await; |
| | bob.recv_msg_trash(sent_update1).await; |
| | bob.recv_msg_trash(sent_update2).await; |
| | let info = Message::load_from_db(&bob, bob_instance.id) |
| | .await? |
| | .get_webxdc_info(&bob) |
| | .await?; |
| | assert_eq!(info.summary, "sum: 2".to_string()); |
| |
|
| | |
| | let alice2 = TestContext::new_alice().await; |
| | let alice2_instance = alice2.recv_msg(sent_instance).await; |
| | alice2.recv_msg_trash(sent_update1).await; |
| | alice2.recv_msg_trash(sent_update2).await; |
| | let info = Message::load_from_db(&alice2, alice2_instance.id) |
| | .await? |
| | .get_webxdc_info(&alice2) |
| | .await?; |
| | assert_eq!(info.summary, "sum: 2".to_string()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_document_name() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent_instance = &alice.pop_sent_msg().await; |
| | let info = alice_instance.get_webxdc_info(&alice).await?; |
| | assert_eq!(info.document, "".to_string()); |
| | assert_eq!(info.summary, "".to_string()); |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | r#"{"document":"my file", "payload":1337}"#, |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent_update1 = &alice.pop_sent_msg().await; |
| | let info = Message::load_from_db(&alice, alice_instance.id) |
| | .await? |
| | .get_webxdc_info(&alice) |
| | .await?; |
| | assert_eq!(info.document, "my file".to_string()); |
| | assert_eq!(info.summary, "".to_string()); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent_instance).await; |
| | bob.recv_msg_trash(sent_update1).await; |
| | let info = Message::load_from_db(&bob, bob_instance.id) |
| | .await? |
| | .get_webxdc_info(&bob) |
| | .await?; |
| | assert_eq!(info.document, "my file".to_string()); |
| | assert_eq!(info.summary, "".to_string()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_info_msg() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent1 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 1); |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | r#"{"info":"this appears in-chat", "payload":"sth. else"}"#, |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2); |
| | let info_msg = alice.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage); |
| | assert_eq!(info_msg.from_id, ContactId::SELF); |
| | assert_eq!(info_msg.get_text(), "this appears in-chat"); |
| | assert_eq!( |
| | info_msg.parent(&alice).await?.unwrap().id, |
| | alice_instance.id |
| | ); |
| | assert!(info_msg.quoted_message(&alice).await?.is_none()); |
| | assert_eq!( |
| | alice |
| | .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":"sth. else","info":"this appears in-chat","serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent1).await; |
| | let bob_chat_id = bob_instance.chat_id; |
| | bob.recv_msg_trash(sent2).await; |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2); |
| | let info_msg = bob.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage); |
| | assert!(!info_msg.from_id.is_special()); |
| | assert_eq!(info_msg.get_text(), "this appears in-chat"); |
| | assert_eq!(info_msg.parent(&bob).await?.unwrap().id, bob_instance.id); |
| | assert!(info_msg.quoted_message(&bob).await?.is_none()); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":"sth. else","info":"this appears in-chat","serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | |
| | let alice2 = TestContext::new_alice().await; |
| | let alice2_instance = alice2.recv_msg(sent1).await; |
| | let alice2_chat_id = alice2_instance.chat_id; |
| | alice2.recv_msg_trash(sent2).await; |
| | assert_eq!( |
| | alice2_chat_id.get_msg_cnt(&alice2).await?, |
| | E2EE_INFO_MSGS + 2 |
| | ); |
| | let info_msg = alice2.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage); |
| | assert_eq!(info_msg.from_id, ContactId::SELF); |
| | assert_eq!(info_msg.get_text(), "this appears in-chat"); |
| | assert_eq!( |
| | info_msg.parent(&alice2).await?.unwrap().id, |
| | alice2_instance.id |
| | ); |
| | assert!(info_msg.quoted_message(&alice2).await?.is_none()); |
| | assert_eq!( |
| | alice2 |
| | .get_webxdc_status_updates(alice2_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":"sth. else","info":"this appears in-chat","serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_info_msg_cleanup_series() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| | let sent1 = &alice.pop_sent_msg().await; |
| |
|
| | |
| | |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"info":"i1", "payload":1}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2); |
| | alice |
| | .send_webxdc_status_update(alice_instance.id, r#"{"info":"i2", "payload":2}"#) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent3 = &alice.pop_sent_msg().await; |
| | assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2); |
| | let info_msg = alice.get_last_msg().await; |
| | assert_eq!(info_msg.get_text(), "i2"); |
| |
|
| | |
| | let bob_instance = bob.recv_msg(sent1).await; |
| | let bob_chat_id = bob_instance.chat_id; |
| | bob.recv_msg_trash(sent2).await; |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2); |
| | bob.recv_msg_trash(sent3).await; |
| | assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2); |
| | let info_msg = bob.get_last_msg().await; |
| | assert_eq!(info_msg.get_text(), "i2"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_info_msg_no_cleanup_on_interrupted_series() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "c").await?; |
| | let instance = send_webxdc_instance(&t, chat_id).await?; |
| |
|
| | t.send_webxdc_status_update(instance.id, r#"{"info":"i1", "payload":1}"#) |
| | .await?; |
| | assert_eq!(chat_id.get_msg_cnt(&t).await?, E2EE_INFO_MSGS + 2); |
| | send_text_msg(&t, chat_id, "msg between info".to_string()).await?; |
| | assert_eq!(chat_id.get_msg_cnt(&t).await?, E2EE_INFO_MSGS + 3); |
| | t.send_webxdc_status_update(instance.id, r#"{"info":"i2", "payload":2}"#) |
| | .await?; |
| | assert_eq!(chat_id.get_msg_cnt(&t).await?, E2EE_INFO_MSGS + 4); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_no_internet_access() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let self_id = t.get_self_chat().await.id; |
| | let single_id = t.create_chat_with_contact("bob", "bob@e.com").await.id; |
| | let group_id = create_group(&t, "chat").await?; |
| | let broadcast_id = create_broadcast(&t, "Channel".to_string()).await?; |
| |
|
| | for chat_id in [self_id, single_id, group_id, broadcast_id] { |
| | for internet_xdc in [true, false] { |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "foo.xdc", |
| | if internet_xdc { |
| | include_bytes!("../../test-data/webxdc/request-internet-access.xdc") |
| | } else { |
| | include_bytes!("../../test-data/webxdc/minimal.xdc") |
| | }, |
| | )?; |
| | let instance_id = send_msg(&t, chat_id, &mut instance).await?; |
| | t.send_webxdc_status_update( |
| | instance_id, |
| | r#"{"summary":"real summary", "payload": 42}"#, |
| | ) |
| | .await?; |
| | let instance = Message::load_from_db(&t, instance_id).await?; |
| | let info = instance.get_webxdc_info(&t).await?; |
| | assert_eq!(info.internet_access, false); |
| | } |
| | } |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_chatlist_summary() -> Result<()> { |
| | let t = TestContext::new_alice().await; |
| | let chat_id = create_group(&t, "chat").await?; |
| | let mut instance = create_webxdc_instance( |
| | &t, |
| | "with-minimal-manifest.xdc", |
| | include_bytes!("../../test-data/webxdc/with-minimal-manifest.xdc"), |
| | )?; |
| | send_msg(&t, chat_id, &mut instance).await?; |
| |
|
| | let chatlist = Chatlist::try_load(&t, 0, None, None).await?; |
| | assert_eq!(chatlist.len(), 1); |
| | let summary = chatlist.get_summary(&t, 0, None).await?; |
| | assert_eq!(summary.text, "nice app!".to_string()); |
| | assert_eq!(summary.thumbnail_path.unwrap(), "webxdc-icon://last-msg-id"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_and_text() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| |
|
| | |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let mut alice_instance = create_webxdc_instance( |
| | &alice, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | alice_instance.set_text("user added text".to_string()); |
| | send_msg(&alice, alice_chat.id, &mut alice_instance).await?; |
| | let alice_instance = alice.get_last_msg().await; |
| | assert_eq!(alice_instance.get_text(), "user added text"); |
| |
|
| | |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | assert_eq!(bob_instance.get_text(), "user added text"); |
| |
|
| | |
| | let alice2 = TestContext::new_alice().await; |
| | let alice2_instance = alice2.recv_msg(&sent1).await; |
| | assert_eq!(alice2_instance.get_text(), "user added text"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | async fn helper_send_receive_status_update( |
| | bob: &TestContext, |
| | alice: &TestContext, |
| | bob_instance: &Message, |
| | alice_instance: &Message, |
| | ) -> Result<String> { |
| | bob.send_webxdc_status_update( |
| | bob_instance.id, |
| | r#"{"payload":7,"info": "i","summary":"s"}"#, |
| | ) |
| | .await?; |
| | bob.flush_status_updates().await?; |
| | let msg = bob.pop_sent_msg().await; |
| | alice.recv_msg_trash(&msg).await; |
| | alice |
| | .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) |
| | .await |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_reject_updates_from_non_groupmembers() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | let contact_bob = alice.add_or_lookup_contact_id(bob).await; |
| | let chat_id = create_group(alice, "Group").await?; |
| | add_contact_to_chat(alice, chat_id, contact_bob).await?; |
| | let instance = send_webxdc_instance(alice, chat_id).await?; |
| | bob.recv_msg(&alice.pop_sent_msg().await).await; |
| | let bob_instance = bob.get_last_msg().await; |
| | Chat::load_from_db(bob, bob_instance.chat_id) |
| | .await? |
| | .id |
| | .accept(bob) |
| | .await?; |
| |
|
| | let status = helper_send_receive_status_update(bob, alice, &bob_instance, &instance).await?; |
| | assert_eq!( |
| | status, |
| | r#"[{"payload":7,"info":"i","summary":"s","serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | remove_contact_from_chat(alice, chat_id, contact_bob).await?; |
| | alice.pop_sent_msg().await; |
| | let status = helper_send_receive_status_update(bob, alice, &bob_instance, &instance).await?; |
| |
|
| | assert_eq!( |
| | status, |
| | r#"[{"payload":7,"info":"i","summary":"s","serial":1,"max_serial":1}]"# |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_delete_event() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let chat_id = create_group(&alice, "foo").await?; |
| | let instance = send_webxdc_instance(&alice, chat_id).await?; |
| | message::delete_msgs(&alice, &[instance.id]).await?; |
| | alice |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::WebxdcInstanceDeleted { .. })) |
| | .await; |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn change_logging_webxdc() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let chat_id = ChatId::create_for_contact(&alice, ContactId::SELF).await?; |
| |
|
| | assert_eq!( |
| | alice |
| | .sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await?, |
| | 0 |
| | ); |
| |
|
| | let mut instance = create_webxdc_instance( |
| | &alice, |
| | "debug_logging.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | assert!(alice.debug_logging.read().unwrap().is_none()); |
| | send_msg(&alice, chat_id, &mut instance).await?; |
| | assert!(alice.debug_logging.read().unwrap().is_some()); |
| |
|
| | alice.emit_event(EventType::Info("hi".to_string())); |
| | alice |
| | .evtracker |
| | .get_matching(|ev| matches!(*ev, EventType::WebxdcStatusUpdate { .. })) |
| | .await; |
| | assert!( |
| | alice |
| | .sql |
| | .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) |
| | .await? |
| | > 0 |
| | ); |
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_webxdc_status_update_extensibility() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| | let bob = TestContext::new_bob().await; |
| | let alice_chat = alice.create_chat(&bob).await; |
| | let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; |
| |
|
| | let bob_instance = bob.recv_msg(&alice.pop_sent_msg().await).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | r#"{"payload":"p","info":"i","aNewUnknownProperty":"x","max_serial":123}"#, |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let received_update = bob.recv_msg_opt(&alice.pop_sent_msg().await).await; |
| | assert!(received_update.is_none()); |
| |
|
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":"p","info":"i","serial":1,"max_serial":1}]"# |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_status_update_vs_delete_device_after() -> Result<()> { |
| | let alice = &TestContext::new_alice().await; |
| | let bob = &TestContext::new_bob().await; |
| | bob.set_config(Config::DeleteDeviceAfter, Some("3600")) |
| | .await?; |
| | let alice_chat = alice.create_chat(bob).await; |
| | let alice_instance = send_webxdc_instance(alice, alice_chat.id).await?; |
| | let bob_instance = bob.recv_msg(&alice.pop_sent_msg().await).await; |
| | assert_eq!(bob.add_or_lookup_contact(alice).await.is_bot(), false); |
| |
|
| | SystemTime::shift(Duration::from_secs(1800)); |
| | let mut update = Message { |
| | chat_id: alice_chat.id, |
| | viewtype: Viewtype::Text, |
| | text: "I'm an update".to_string(), |
| | hidden: true, |
| | ..Default::default() |
| | }; |
| | update.param.set_cmd(SystemMessage::WebxdcStatusUpdate); |
| | update |
| | .param |
| | .set(Param::Arg, r#"{"updates":[{"payload":{"foo":"bar"}}]}"#); |
| | update.set_quote(alice, Some(&alice_instance)).await?; |
| | let sent_msg = alice.send_msg(alice_chat.id, &mut update).await; |
| | bob.recv_msg_trash(&sent_msg).await; |
| | assert_eq!(bob.add_or_lookup_contact(alice).await.is_bot(), false); |
| | assert_eq!( |
| | bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) |
| | .await?, |
| | r#"[{"payload":{"foo":"bar"},"serial":1,"max_serial":1}]"# |
| | ); |
| | assert_eq!(bob.add_or_lookup_contact(alice).await.is_bot(), false); |
| |
|
| | SystemTime::shift(Duration::from_secs(2700)); |
| | ephemeral::delete_expired_messages(bob, tools::time()).await?; |
| | let bob_instance = Message::load_from_db(bob, bob_instance.id).await?; |
| | assert_eq!(bob_instance.chat_id.is_trash(), false); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | async fn has_incoming_webxdc_event( |
| | t: &TestContext, |
| | expected_msg: Message, |
| | expected_text: &str, |
| | ) -> bool { |
| | t.evtracker |
| | .get_matching_opt(t, |evt| { |
| | if let EventType::IncomingWebxdcNotify { msg_id, text, .. } = evt { |
| | *msg_id == expected_msg.id && text == expected_text |
| | } else { |
| | false |
| | } |
| | }) |
| | .await |
| | .is_some() |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_one() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | let _fiona_instance = fiona.recv_msg(&sent1).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":7,\"info\": \"Alice moved\",\"notify\":{{\"{}\": \"Your move!\"}} }}", |
| | bob_instance.get_webxdc_self_addr(&bob).await? |
| | ), |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.text, "Alice moved"); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "").await); |
| |
|
| | bob.recv_msg_trash(&sent2).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.text, "Alice moved"); |
| | assert!(has_incoming_webxdc_event(&bob, info_msg, "Your move!").await); |
| |
|
| | fiona.recv_msg_trash(&sent2).await; |
| | let info_msg = fiona.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.text, "Alice moved"); |
| | assert!(!has_incoming_webxdc_event(&fiona, info_msg, "").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_multiple() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | let fiona_instance = fiona.recv_msg(&sent1).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":7,\"info\": \"moved\", \"summary\": \"move summary\", \"notify\":{{\"{}\":\"move, Bob\",\"{}\":\"move, Fiona\"}} }}", |
| | bob_instance.get_webxdc_self_addr(&bob).await?, |
| | fiona_instance.get_webxdc_self_addr(&fiona).await? |
| | ), |
| |
|
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "").await); |
| |
|
| | bob.recv_msg_trash(&sent2).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert!(has_incoming_webxdc_event(&bob, info_msg, "move, Bob").await); |
| |
|
| | fiona.recv_msg_trash(&sent2).await; |
| | let info_msg = fiona.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert!(has_incoming_webxdc_event(&fiona, info_msg, "move, Fiona").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_no_notify_self() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let alice2 = tcm.alice().await; |
| |
|
| | let grp_id = alice.create_group_with_members("grp", &[]).await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let alice2_instance = alice2.recv_msg(&sent1).await; |
| | assert_eq!( |
| | alice_instance.get_webxdc_self_addr(&alice).await?, |
| | alice2_instance.get_webxdc_self_addr(&alice2).await? |
| | ); |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":7,\"info\": \"moved\", \"notify\":{{\"{}\": \"bla\"}} }}", |
| | alice2_instance.get_webxdc_self_addr(&alice2).await? |
| | ), |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "").await); |
| |
|
| | alice2.recv_msg_trash(&sent2).await; |
| | let info_msg = alice2.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert!(!has_incoming_webxdc_event(&alice2, info_msg, "").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_all() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | bob.recv_msg(&sent1).await; |
| | fiona.recv_msg(&sent1).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | "{\"payload\":7,\"info\": \"go\", \"notify\":{\"*\":\"notify all\"} }", |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert_eq!(info_msg.text, "go"); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "").await); |
| |
|
| | bob.recv_msg_trash(&sent2).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert_eq!(info_msg.text, "go"); |
| | assert!(has_incoming_webxdc_event(&bob, info_msg, "notify all").await); |
| |
|
| | fiona.recv_msg_trash(&sent2).await; |
| | let info_msg = fiona.get_last_msg().await; |
| | assert_eq!(info_msg.text, "go"); |
| | assert!(has_incoming_webxdc_event(&fiona, info_msg, "notify all").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_muted() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | let fiona_instance = fiona.recv_msg(&sent1).await; |
| |
|
| | set_muted(&bob, bob_instance.chat_id, MuteDuration::Forever).await?; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | "{\"payload\":7,\"info\": \"all\", \"notify\":{\"*\":\"notify all\"} }", |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert_eq!(info_msg.text, "all"); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "notify all").await); |
| |
|
| | bob.recv_msg_trash(&sent2).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert_eq!(info_msg.text, "all"); |
| | assert!(!has_incoming_webxdc_event(&bob, info_msg, "notify all").await); |
| |
|
| | fiona.recv_msg_trash(&sent2).await; |
| | let info_msg = fiona.get_last_msg().await; |
| | assert_eq!(info_msg.text, "all"); |
| | assert!(has_incoming_webxdc_event(&fiona, info_msg, "notify all").await); |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":8,\"info\": \"reply\", \"notify\":{{\"{}\":\"reply, Bob\",\"{}\":\"reply, Fiona\"}} }}", |
| | bob_instance.get_webxdc_self_addr(&bob).await?, |
| | fiona_instance.get_webxdc_self_addr(&fiona).await? |
| | ), |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent3 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert_eq!(info_msg.text, "reply"); |
| | assert!(!has_incoming_webxdc_event(&alice, info_msg, "").await); |
| |
|
| | bob.recv_msg_trash(&sent3).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert_eq!(info_msg.text, "reply"); |
| | assert!(has_incoming_webxdc_event(&bob, info_msg, "reply, Bob").await); |
| |
|
| | fiona.recv_msg_trash(&sent3).await; |
| | let info_msg = fiona.get_last_msg().await; |
| | assert_eq!(info_msg.text, "reply"); |
| | assert!(has_incoming_webxdc_event(&fiona, info_msg, "reply, Fiona").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_bob_and_all() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | let fiona_instance = fiona.recv_msg(&sent1).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":7, \"notify\":{{\"{}\": \"notify bob\",\"*\": \"notify all\"}} }}", |
| | bob_instance.get_webxdc_self_addr(&bob).await? |
| | ), |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | bob.recv_msg_trash(&sent2).await; |
| | fiona.recv_msg_trash(&sent2).await; |
| | assert!(has_incoming_webxdc_event(&bob, bob_instance, "notify bob").await); |
| | assert!(has_incoming_webxdc_event(&fiona, fiona_instance, "notify all").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_notify_all_and_bob() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| | let fiona = tcm.fiona().await; |
| |
|
| | let grp_id = alice |
| | .create_group_with_members("grp", &[&bob, &fiona]) |
| | .await; |
| | let alice_instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| | let bob_instance = bob.recv_msg(&sent1).await; |
| | let fiona_instance = fiona.recv_msg(&sent1).await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | alice_instance.id, |
| | &format!( |
| | "{{\"payload\":7, \"notify\":{{\"*\": \"notify all\", \"{}\": \"notify bob\"}} }}", |
| | bob_instance.get_webxdc_self_addr(&bob).await? |
| | ), |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | bob.recv_msg_trash(&sent2).await; |
| | fiona.recv_msg_trash(&sent2).await; |
| | assert!(has_incoming_webxdc_event(&bob, bob_instance, "notify bob").await); |
| | assert!(has_incoming_webxdc_event(&fiona, fiona_instance, "notify all").await); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_webxdc_href() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | let grp_id = alice.create_group_with_members("grp", &[&bob]).await; |
| | let instance = send_webxdc_instance(&alice, grp_id).await?; |
| | let sent1 = alice.pop_sent_msg().await; |
| |
|
| | alice |
| | .send_webxdc_status_update( |
| | instance.id, |
| | r##"{"payload": "my deeplink data", "info": "my move!", "href": "#foobar"}"##, |
| | ) |
| | .await?; |
| | alice.flush_status_updates().await?; |
| | let sent2 = alice.pop_sent_msg().await; |
| | let info_msg = alice.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.get_webxdc_href(), Some("#foobar".to_string())); |
| |
|
| | bob.recv_msg(&sent1).await; |
| | bob.recv_msg_trash(&sent2).await; |
| | let info_msg = bob.get_last_msg().await; |
| | assert!(info_msg.is_info()); |
| | assert_eq!(info_msg.get_webxdc_href(), Some("#foobar".to_string())); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_self_addr_consistency() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let alice_chat = alice.create_group_with_members("No friends :(", &[]).await; |
| | let mut instance = create_webxdc_instance( |
| | alice, |
| | "minimal.xdc", |
| | include_bytes!("../../test-data/webxdc/minimal.xdc"), |
| | )?; |
| | alice_chat.set_draft(alice, Some(&mut instance)).await?; |
| | let mut instance = alice_chat.get_draft(alice).await?.unwrap(); |
| | let self_addr = instance.get_webxdc_self_addr(alice).await?; |
| | let sent = alice.send_msg(alice_chat, &mut instance).await; |
| | let db_msg = Message::load_from_db(alice, sent.sender_msg_id).await?; |
| | assert_eq!(db_msg.get_webxdc_self_addr(alice).await?, self_addr); |
| | Ok(()) |
| | } |
| |
|