From b9886d1593d28e660b88827482a43059e19a28b9 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Mon, 16 Mar 2026 19:23:46 +0100 Subject: [PATCH] Add a test, small refactorings --- src/configure.rs | 2 +- src/transport.rs | 4 +- src/transport/transport_tests.rs | 220 +++++++++++++++++++++++++++---- 3 files changed, 194 insertions(+), 32 deletions(-) diff --git a/src/configure.rs b/src/configure.rs index c65c50515..6a195af22 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -661,7 +661,7 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result Result<()> { + let is_published = true; save_transport( context, entered_param, @@ -650,7 +650,7 @@ pub(crate) async fn save_transport( DO UPDATE SET entered_param=excluded.entered_param, configured_param=excluded.configured_param, add_timestamp=excluded.add_timestamp, - is_published=excluded.is_published, + is_published=excluded.is_published WHERE entered_param != excluded.entered_param OR configured_param != excluded.configured_param OR add_timestamp < excluded.add_timestamp diff --git a/src/transport/transport_tests.rs b/src/transport/transport_tests.rs index fdcb3ee49..db08229b9 100644 --- a/src/transport/transport_tests.rs +++ b/src/transport/transport_tests.rs @@ -2,6 +2,7 @@ use super::*; use crate::log::LogExt as _; use crate::provider::get_provider_by_id; use crate::test_utils::TestContext; +use crate::test_utils::TestContextManager; use crate::tools::time; #[test] @@ -47,7 +48,7 @@ async fn test_save_load_login_param() -> Result<()> { param .clone() - .save_to_transports_table(&t, &EnteredLoginParam::default(), time(), true) + .save_to_transports_table(&t, &EnteredLoginParam::default(), time()) .await?; let expected_param = r#"{"addr":"alice@example.org","imap":[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}],"imap_user":"","imap_password":"foo","smtp":[{"connection":{"host":"smtp.example.com","port":456,"security":"Tls"},"user":"alice@example.org"}],"smtp_user":"","smtp_password":"bar","provider_id":null,"certificate_checks":"Strict","oauth2":false}"#; assert_eq!( @@ -239,34 +240,9 @@ async fn test_empty_server_list() -> Result<()> { let addr = format!("alice@{domain}"); - ConfiguredLoginParam { - addr: addr.clone(), - imap: vec![ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "example.org".to_string(), - port: 100, - security: ConnectionSecurity::Tls, - }, - user: addr.clone(), - }], - imap_user: addr.clone(), - imap_password: "foobarbaz".to_string(), - smtp: vec![ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "example.org".to_string(), - port: 100, - security: ConnectionSecurity::Tls, - }, - user: addr.clone(), - }], - smtp_user: addr.clone(), - smtp_password: "foobarbaz".to_string(), - provider: Some(provider), - certificate_checks: ConfiguredCertificateChecks::Automatic, - oauth2: false, - } - .save_to_transports_table(&t, &EnteredLoginParam::default(), time(), true) - .await?; + dummy_configured_login_param(&addr, Some(provider)) + .save_to_transports_table(&t, &EnteredLoginParam::default(), time()) + .await?; let (_transport_id, loaded) = ConfiguredLoginParam::load(&t).await?.unwrap(); assert_eq!(loaded.provider, Some(*provider)); @@ -276,3 +252,189 @@ async fn test_empty_server_list() -> Result<()> { Ok(()) } + +fn dummy_configured_login_param( + addr: &str, + provider: Option<&'static Provider>, +) -> ConfiguredLoginParam { + ConfiguredLoginParam { + addr: addr.to_string(), + imap: vec![ConfiguredServerLoginParam { + connection: ConnectionCandidate { + host: "example.org".to_string(), + port: 100, + security: ConnectionSecurity::Tls, + }, + user: addr.to_string(), + }], + imap_user: addr.to_string(), + imap_password: "foobarbaz".to_string(), + smtp: vec![ConfiguredServerLoginParam { + connection: ConnectionCandidate { + host: "example.org".to_string(), + port: 100, + security: ConnectionSecurity::Tls, + }, + user: addr.to_string(), + }], + smtp_user: addr.to_string(), + smtp_password: "foobarbaz".to_string(), + provider, + certificate_checks: ConfiguredCertificateChecks::Automatic, + oauth2: false, + } +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_is_published_flag() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let alice2 = &tcm.alice().await; + for a in [alice, alice2] { + a.set_config_bool(Config::SyncMsgs, true).await?; + a.set_config_bool(Config::BccSelf, true).await?; + } + let bob = &tcm.bob().await; + + assert_eq!( + alice.get_all_self_addrs().await?, + vec!["alice@example.org".to_string()] + ); + assert_eq!( + alice.get_published_self_addrs().await?, + vec!["alice@example.org".to_string()] + ); + assert_eq!( + alice.get_secondary_self_addrs().await?, + Vec::::new() + ); + assert_eq!( + alice.get_published_secondary_self_addrs().await?, + Vec::::new() + ); + assert_eq!( + alice.is_transport_unpublished("alice@example.org").await?, + false + ); + send_recv_check_recipients(alice, bob, "alice@example.org").await; + + dummy_configured_login_param("alice@otherprovider.com", None) + .save_to_transports_table(alice, &EnteredLoginParam::default(), time()) + .await?; + send_sync_transports(alice).await?; + sync_and_check_recipients(alice, alice2, "alice@otherprovider.com alice@example.org").await; + + for a in [alice, alice2] { + assert_eq!( + a.get_all_self_addrs().await?, + vec![ + "alice@otherprovider.com".to_string(), + "alice@example.org".to_string(), + ] + ); + assert_eq!( + a.get_published_self_addrs().await?, + vec![ + "alice@otherprovider.com".to_string(), + "alice@example.org".to_string(), + ] + ); + assert_eq!( + a.get_secondary_self_addrs().await?, + vec!["alice@otherprovider.com".to_string()] + ); + assert_eq!( + a.get_published_secondary_self_addrs().await?, + vec!["alice@otherprovider.com".to_string()] + ); + assert_eq!( + alice.is_transport_unpublished("alice@example.org").await?, + false + ); + assert_eq!( + alice + .is_transport_unpublished("alice@otherprovider.com") + .await?, + false + ); + send_recv_check_recipients(a, bob, "alice@example.org alice@otherprovider.com").await; + } + + // TODO this should fail: + // alice + // .set_transport_unpublished("alice@example.org", true) + // .await + // .unwrap_err(); + + alice + .set_transport_unpublished("alice@otherprovider.com", true) + .await?; + sync_and_check_recipients(alice, alice2, "alice@example.org").await; + + for a in [alice, alice2] { + assert_eq!( + a.get_all_self_addrs().await?, + vec![ + "alice@example.org".to_string(), + "alice@otherprovider.com".to_string() + ] + ); + assert_eq!( + a.get_published_self_addrs().await?, + vec!["alice@example.org".to_string()] + ); + assert_eq!( + a.get_secondary_self_addrs().await?, + vec!["alice@otherprovider.com".to_string()] + ); + assert_eq!( + a.get_published_secondary_self_addrs().await?, + Vec::::new() + ); + assert_eq!( + alice.is_transport_unpublished("alice@example.org").await?, + false + ); + assert_eq!( + alice + .is_transport_unpublished("alice@otherprovider.com") + .await?, + true + ); + send_recv_check_recipients(a, bob, "alice@example.org").await; + } + + // TODO test that changing primary transport makes it published again + + Ok(()) +} + +async fn send_recv_check_recipients(alice: &TestContext, bob: &TestContext, published_addrs: &str) { + let alice_bob_chat_id = alice.create_chat_id(bob).await; + + let sent = alice.send_text(alice_bob_chat_id, "hi").await; + assert_eq!( + sent.recipients, + format!("bob@example.net {published_addrs}"), + "{} is sending to the wrong set of recipients", + alice.name() + ); + let bob_alice_chat_id = bob.recv_msg(&sent).await.chat_id; + bob_alice_chat_id.accept(bob).await.unwrap(); + let answer = bob.send_text(bob_alice_chat_id, "hi back").await; + assert_eq!( + answer.recipients, + format!("{published_addrs} bob@example.net") + ); +} + +pub(crate) async fn sync_and_check_recipients( + from: &TestContext, + to: &TestContext, + recipients: &str, +) { + from.send_sync_msg().await.unwrap(); + let sync_msg = from.pop_sent_msg().await; + assert_eq!(sync_msg.recipients, recipients); + to.recv_msg_trash(&sync_msg).await; +}