diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 5ff3c29ed..2d602da62 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -713,12 +713,11 @@ def test_get_http_response(acfactory): def test_configured_imap_certificate_checks(acfactory): alice = acfactory.new_configured_account() - configured_certificate_checks = alice.get_config("configured_imap_certificate_checks") # Certificate checks should be configured (not None) - assert configured_certificate_checks + assert "cert_automatic" in alice.get_info().used_account_settings - # 0 is the value old Delta Chat core versions used + # "cert_old_automatic" is the value old Delta Chat core versions used # to mean user entered "imap_certificate_checks=0" (Automatic) # and configuration failed to use strict TLS checks # so it switched strict TLS checks off. @@ -729,7 +728,7 @@ def test_configured_imap_certificate_checks(acfactory): # # Core 1.142.4, 1.142.5 and 1.142.6 saved this value due to bug. # This test is a regression test to prevent this happening again. - assert configured_certificate_checks != "0" + assert "cert_old_automatic" not in alice.get_info().used_account_settings def test_no_old_msg_is_fresh(acfactory): diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index fe523aaa6..aecd333ff 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -482,12 +482,8 @@ class ACFactory: addr = f"{acname}@offline.org" ac.update_config( { - "addr": addr, - "displayname": acname, - "mail_pw": "123", "configured_addr": addr, - "configured_mail_pw": "123", - "configured": "1", + "displayname": acname, }, ) self._preconfigure_key(ac) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 48f88d0ca..72deacc15 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -1502,15 +1502,6 @@ def test_connectivity(acfactory, lp): assert len(msgs) == 2 assert msgs[1].text == "Hi 2" - lp.sec("Test that the connectivity is NOT_CONNECTED if the password is wrong") - - ac1.set_config("configured_mail_pw", "abc") - ac1.stop_io() - ac1._evtracker.wait_for_connectivity(dc.const.DC_CONNECTIVITY_NOT_CONNECTED) - ac1.start_io() - ac1._evtracker.wait_for_connectivity(dc.const.DC_CONNECTIVITY_CONNECTING) - ac1._evtracker.wait_for_connectivity(dc.const.DC_CONNECTIVITY_NOT_CONNECTED) - def test_fetch_deleted_msg(acfactory, lp): """This is a regression test: Messages with \\Deleted flag were downloaded again and again, diff --git a/src/config.rs b/src/config.rs index d24d5bfcd..1fa11d49e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,7 +4,7 @@ use std::env; use std::path::Path; use std::str::FromStr; -use anyhow::{ensure, Context as _, Result}; +use anyhow::{bail, ensure, Context as _, Result}; use base64::Engine as _; use deltachat_contact_tools::{addr_cmp, sanitize_single_line}; use serde::{Deserialize, Serialize}; @@ -13,10 +13,12 @@ use strum_macros::{AsRefStr, Display, EnumIter, EnumString}; use tokio::fs; use crate::blob::BlobObject; +use crate::configure::EnteredLoginParam; use crate::constants; use crate::context::Context; use crate::events::EventType; use crate::log::LogExt; +use crate::login_param::ConfiguredLoginParam; use crate::mimefactory::RECOMMENDED_FILE_SIZE; use crate::provider::{get_provider_by_id, Provider}; use crate::sync::{self, Sync::*, SyncData}; @@ -525,21 +527,22 @@ impl Context { // Default values let val = match key { Config::BccSelf => match Box::pin(self.is_chatmail()).await? { - false => Some("1"), - true => Some("0"), + false => Some("1".to_string()), + true => Some("0".to_string()), }, - Config::ConfiguredInboxFolder => Some("INBOX"), + Config::ConfiguredInboxFolder => Some("INBOX".to_string()), Config::DeleteServerAfter => { match !Box::pin(self.get_config_bool(Config::BccSelf)).await? && Box::pin(self.is_chatmail()).await? { - true => Some("1"), - false => Some("0"), + true => Some("1".to_string()), + false => Some("0".to_string()), } } - _ => key.get_str("default"), + Config::Addr => self.get_config_opt(Config::ConfiguredAddr).await?, + _ => key.get_str("default").map(|s| s.to_string()), }; - Ok(val.map(|s| s.to_string())) + Ok(val) } /// Returns Some(T) if a value for the given key is set and was successfully parsed. @@ -805,6 +808,19 @@ impl Context { .set_raw_config(constants::DC_FOLDERS_CONFIGURED_KEY, None) .await?; } + Config::ConfiguredAddr => { + if self.is_configured().await? { + bail!("Cannot change ConfiguredAddr"); + } + if let Some(addr) = value { + info!(self, "Creating a pseudo configured account which will not be able to send or receive messages. Only meant for tests!"); + ConfiguredLoginParam::from_json(&format!( + r#"{{"addr":"{addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic","oauth2":false}}"# + ))? + .save_to_transports_table(self, &EnteredLoginParam::default()) + .await?; + } + } _ => { self.sql.set_raw_config(key.as_ref(), value).await?; } @@ -891,6 +907,7 @@ impl Context { /// primary address (if exists) as a secondary address. /// /// This should only be used by test code and during configure. + #[cfg(test)] // AEAP is disabled, but there are still tests for it pub(crate) async fn set_primary_self_addr(&self, primary_new: &str) -> Result<()> { self.quota.write().await.take(); @@ -904,7 +921,8 @@ impl Context { ) .await?; - self.set_config_internal(Config::ConfiguredAddr, Some(primary_new)) + self.sql + .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(primary_new)) .await?; self.emit_event(EventType::ConnectivityChanged); Ok(()) diff --git a/src/configure.rs b/src/configure.rs index 3ad54aa8e..195fdff03 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -35,7 +35,7 @@ use crate::login_param::{ }; use crate::message::Message; use crate::oauth2::get_oauth2_addr; -use crate::provider::{Protocol, Socket, UsernamePattern}; +use crate::provider::{Protocol, Provider, Socket, UsernamePattern}; use crate::qr::set_account_from_qr; use crate::smtp::Smtp; use crate::sync::Sync::*; @@ -63,7 +63,7 @@ macro_rules! progress { impl Context { /// Checks if the context is already configured. pub async fn is_configured(&self) -> Result { - self.sql.get_raw_config_bool("configured").await + self.sql.exists("SELECT COUNT(*) FROM transports", ()).await } /// Configures this account with the currently provided parameters. @@ -181,9 +181,21 @@ impl Context { /// Use [Self::add_transport()] to add or change a transport /// and [Self::delete_transport()] to delete a transport. pub async fn list_transports(&self) -> Result> { - let param = EnteredLoginParam::load(self).await?; + let transports = self + .sql + .query_map( + "SELECT entered_param FROM transports", + (), + |row| row.get::<_, String>(0), + |rows| { + rows.flatten() + .map(|s| Ok(serde_json::from_str(&s)?)) + .collect::>>() + }, + ) + .await?; - Ok(vec![param]) + Ok(transports) } /// Removes the transport with the specified email address @@ -197,20 +209,20 @@ impl Context { info!(self, "Configure ..."); let old_addr = self.get_config(Config::ConfiguredAddr).await?; - let configured_param = configure(self, param).await?; + let provider = configure(self, param).await?; self.set_config_internal(Config::NotifyAboutWrongPw, Some("1")) .await?; - on_configure_completed(self, configured_param, old_addr).await?; + on_configure_completed(self, provider, old_addr).await?; Ok(()) } } async fn on_configure_completed( context: &Context, - param: ConfiguredLoginParam, + provider: Option<&'static Provider>, old_addr: Option, ) -> Result<()> { - if let Some(provider) = param.provider { + if let Some(provider) = provider { if let Some(config_defaults) = provider.config_defaults { for def in config_defaults { if !context.config_exists(def.key).await? { @@ -446,7 +458,7 @@ async fn get_configured_param( Ok(configured_login_param) } -async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result { +async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result> { progress!(ctx, 1); let ctx2 = ctx.clone(); @@ -556,7 +568,11 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result Result, + pub imap_user: String, + pub imap_password: String, + pub smtp: Vec, + pub smtp_user: String, + pub smtp_password: String, + pub provider_id: Option, + pub certificate_checks: ConfiguredCertificateChecks, + pub oauth2: bool, +} + impl fmt::Display for ConfiguredLoginParam { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let addr = &self.addr; @@ -487,6 +517,26 @@ impl ConfiguredLoginParam { /// /// Returns `None` if account is not configured. pub(crate) async fn load(context: &Context) -> Result> { + let Some(self_addr) = context.get_config(Config::ConfiguredAddr).await? else { + return Ok(None); + }; + + let json: Option = context + .sql + .query_get_value( + "SELECT configured_param FROM transports WHERE addr=?", + (&self_addr,), + ) + .await?; + if let Some(json) = json { + Ok(Some(Self::from_json(&json)?)) + } else { + bail!("Self address {self_addr} doesn't have a corresponding transport"); + } + } + + /// Loads legacy configured param. Only used for tests and the migration. + pub(crate) async fn load_legacy(context: &Context) -> Result> { if !context.get_config_bool(Config::Configured).await? { return Ok(None); } @@ -753,84 +803,82 @@ impl ConfiguredLoginParam { })) } - /// Save this loginparam to the database. - pub(crate) async fn save_as_configured_params(&self, context: &Context) -> Result<()> { - context.set_primary_self_addr(&self.addr).await?; - + pub(crate) async fn save_to_transports_table( + self, + context: &Context, + entered_param: &EnteredLoginParam, + ) -> Result<()> { + let addr = addr_normalize(&self.addr); + let configured_addr = context.get_config(Config::ConfiguredAddr).await?; + if let Some(configured_addr) = configured_addr { + ensure!( + addr_cmp(&configured_addr, &addr,), + "Adding a second transport is not supported right now." + ); + } context - .set_config( - Config::ConfiguredImapServers, - Some(&serde_json::to_string(&self.imap)?), - ) - .await?; - context - .set_config( - Config::ConfiguredSmtpServers, - Some(&serde_json::to_string(&self.smtp)?), - ) - .await?; - - context - .set_config(Config::ConfiguredMailUser, Some(&self.imap_user)) - .await?; - context - .set_config(Config::ConfiguredMailPw, Some(&self.imap_password)) - .await?; - - context - .set_config(Config::ConfiguredSendUser, Some(&self.smtp_user)) - .await?; - context - .set_config(Config::ConfiguredSendPw, Some(&self.smtp_password)) - .await?; - - context - .set_config_u32( - Config::ConfiguredImapCertificateChecks, - self.certificate_checks as u32, - ) - .await?; - context - .set_config_u32( - Config::ConfiguredSmtpCertificateChecks, - self.certificate_checks as u32, - ) - .await?; - - // Remove legacy settings. - context - .set_config(Config::ConfiguredMailServer, None) - .await?; - context.set_config(Config::ConfiguredMailPort, None).await?; - context - .set_config(Config::ConfiguredMailSecurity, None) - .await?; - context - .set_config(Config::ConfiguredSendServer, None) - .await?; - context.set_config(Config::ConfiguredSendPort, None).await?; - context - .set_config(Config::ConfiguredSendSecurity, None) - .await?; - - let server_flags = match self.oauth2 { - true => DC_LP_AUTH_OAUTH2, - false => DC_LP_AUTH_NORMAL, - }; - context - .set_config_u32(Config::ConfiguredServerFlags, server_flags as u32) - .await?; - - context - .set_config( - Config::ConfiguredProvider, + .sql + .set_raw_config( + Config::ConfiguredProvider.as_ref(), self.provider.map(|provider| provider.id), ) .await?; - + context + .sql + .execute( + "INSERT INTO transports (addr, entered_param, configured_param) + VALUES (?, ?, ?) + ON CONFLICT (addr) + DO UPDATE SET entered_param=excluded.entered_param, configured_param=excluded.configured_param", + ( + self.addr.clone(), + serde_json::to_string(entered_param)?, + self.into_json()?, + ), + ) + .await?; + context + .sql + .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(&addr)) + .await?; Ok(()) } + pub(crate) fn from_json(json: &str) -> Result { + let json: ConfiguredLoginParamJson = serde_json::from_str(json)?; + + let provider = json.provider_id.and_then(|id| get_provider_by_id(&id)); + + Ok(ConfiguredLoginParam { + addr: json.addr, + imap: json.imap, + imap_user: json.imap_user, + imap_password: json.imap_password, + smtp: json.smtp, + smtp_user: json.smtp_user, + smtp_password: json.smtp_password, + provider, + certificate_checks: json.certificate_checks, + oauth2: json.oauth2, + }) + } + + pub(crate) fn into_json(self) -> Result { + let json = ConfiguredLoginParamJson { + addr: self.addr, + imap: self.imap, + imap_user: self.imap_user, + imap_password: self.imap_password, + smtp: self.smtp, + smtp_user: self.smtp_user, + smtp_password: self.smtp_password, + provider_id: self.provider.map(|p| p.id.to_string()), + certificate_checks: self.certificate_checks, + oauth2: self.oauth2, + }; + Ok(serde_json::to_string(&json)?) + } + pub(crate) fn strict_tls(&self, connected_through_proxy: bool) -> bool { let provider_strict_tls = self.provider.map(|provider| provider.opt.strict_tls); match self.certificate_checks { @@ -848,8 +896,10 @@ impl ConfiguredLoginParam { #[cfg(test)] mod tests { use super::*; + use crate::log::LogExt as _; use crate::provider::get_provider_by_id; use crate::test_utils::TestContext; + use pretty_assertions::assert_eq; #[test] fn test_certificate_checks_display() { @@ -961,18 +1011,33 @@ mod tests { oauth2: false, }; - param.save_as_configured_params(&t).await?; + param + .clone() + .save_to_transports_table(&t, &EnteredLoginParam::default()) + .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!( - t.get_config(Config::ConfiguredImapServers).await?.unwrap(), - r#"[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}]"# + t.sql + .query_get_value::("SELECT configured_param FROM transports", ()) + .await? + .unwrap(), + expected_param ); - t.set_config(Config::Configured, Some("1")).await?; + assert_eq!(t.is_configured().await?, true); let loaded = ConfiguredLoginParam::load(&t).await?.unwrap(); assert_eq!(param, loaded); - // Test that we don't panic on unknown ConfiguredImapCertificateChecks values. + // Legacy ConfiguredImapCertificateChecks config is ignored t.set_config(Config::ConfiguredImapCertificateChecks, Some("999")) .await?; + assert!(ConfiguredLoginParam::load(&t).await.is_ok()); + + // Test that we don't panic on unknown ConfiguredImapCertificateChecks values. + let wrong_param = expected_param.replace("Strict", "Stricct"); + assert_ne!(expected_param, wrong_param); + t.sql + .execute("UPDATE transports SET configured_param=?", (wrong_param,)) + .await?; assert!(ConfiguredLoginParam::load(&t).await.is_err()); Ok(()) @@ -989,7 +1054,8 @@ mod tests { t.set_config(Config::Configured, Some("1")).await?; t.set_config(Config::ConfiguredProvider, Some("posteo")) .await?; - t.set_config(Config::ConfiguredAddr, Some("alice@posteo.at")) + t.sql + .set_raw_config(Config::ConfiguredAddr.as_ref(), Some("alice@posteo.at")) .await?; t.set_config(Config::ConfiguredMailServer, Some("posteo.de")) .await?; @@ -1063,12 +1129,68 @@ mod tests { oauth2: false, }; + let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap(); + assert_eq!(loaded, param); + + migrate_configured_login_param(&t).await; let loaded = ConfiguredLoginParam::load(&t).await?.unwrap(); assert_eq!(loaded, param); Ok(()) } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_empty_server_list_legacy() -> Result<()> { + // Find a provider that does not have server list set. + // + // There is at least one such provider in the provider database. + let (domain, provider) = crate::provider::data::PROVIDER_DATA + .iter() + .find(|(_domain, provider)| provider.server.is_empty()) + .unwrap(); + + let t = TestContext::new().await; + + let addr = format!("alice@{domain}"); + + t.set_config(Config::Configured, Some("1")).await?; + t.set_config(Config::ConfiguredProvider, Some(provider.id)) + .await?; + t.sql + .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(&addr)) + .await?; + t.set_config(Config::ConfiguredMailPw, Some("foobarbaz")) + .await?; + t.set_config(Config::ConfiguredImapCertificateChecks, Some("1")) + .await?; // Strict + t.set_config(Config::ConfiguredSendPw, Some("foobarbaz")) + .await?; + t.set_config(Config::ConfiguredSmtpCertificateChecks, Some("1")) + .await?; // Strict + t.set_config(Config::ConfiguredServerFlags, Some("0")) + .await?; + + let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap(); + assert_eq!(loaded.provider, Some(*provider)); + assert_eq!(loaded.imap.is_empty(), false); + assert_eq!(loaded.smtp.is_empty(), false); + + migrate_configured_login_param(&t).await; + + let loaded = ConfiguredLoginParam::load(&t).await?.unwrap(); + assert_eq!(loaded.provider, Some(*provider)); + assert_eq!(loaded.imap.is_empty(), false); + assert_eq!(loaded.smtp.is_empty(), false); + + Ok(()) + } + + async fn migrate_configured_login_param(t: &TestContext) { + t.sql.execute("DROP TABLE transports;", ()).await.unwrap(); + t.sql.set_raw_config_int("dbversion", 130).await.unwrap(); + t.sql.run_migrations(t).await.log_err(t).ok(); + } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_empty_server_list() -> Result<()> { // Find a provider that does not have server list set. @@ -1083,25 +1205,41 @@ mod tests { let addr = format!("alice@{domain}"); - t.set_config(Config::Configured, Some("1")).await?; - t.set_config(Config::ConfiguredProvider, Some(provider.id)) - .await?; - t.set_config(Config::ConfiguredAddr, Some(&addr)).await?; - t.set_config(Config::ConfiguredMailPw, Some("foobarbaz")) - .await?; - t.set_config(Config::ConfiguredImapCertificateChecks, Some("1")) - .await?; // Strict - t.set_config(Config::ConfiguredSendPw, Some("foobarbaz")) - .await?; - t.set_config(Config::ConfiguredSmtpCertificateChecks, Some("1")) - .await?; // Strict - t.set_config(Config::ConfiguredServerFlags, Some("0")) - .await?; + 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()) + .await?; let loaded = ConfiguredLoginParam::load(&t).await?.unwrap(); assert_eq!(loaded.provider, Some(*provider)); assert_eq!(loaded.imap.is_empty(), false); assert_eq!(loaded.smtp.is_empty(), false); + assert_eq!(t.get_configured_provider().await?, Some(*provider)); + Ok(()) } } diff --git a/src/provider.rs b/src/provider.rs index e812ec54a..9195b9e45 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -5,6 +5,7 @@ pub(crate) mod data; use anyhow::Result; use deltachat_contact_tools::EmailAddress; use hickory_resolver::{config, Resolver, TokioResolver}; +use serde::{Deserialize, Serialize}; use crate::config::Config; use crate::context::Context; @@ -37,7 +38,19 @@ pub enum Protocol { } /// Socket security. -#[derive(Debug, Default, Display, PartialEq, Eq, Copy, Clone, FromPrimitive, ToPrimitive)] +#[derive( + Debug, + Default, + Display, + PartialEq, + Eq, + Copy, + Clone, + FromPrimitive, + ToPrimitive, + Serialize, + Deserialize, +)] #[repr(u8)] pub enum Socket { /// Unspecified socket security, select automatically. diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index 5b7dc8f68..85e15e703 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -3113,7 +3113,6 @@ Message with references."#; async fn test_rfc1847_encapsulation() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; - alice.configure_addr("alice@example.org").await; // Alice sends an Autocrypt message to Bob so Bob gets Alice's key. let chat_alice = alice.create_chat(&bob).await; diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 428a5d345..be093db42 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -5,9 +5,11 @@ use deltachat_contact_tools::EmailAddress; use rusqlite::OptionalExtension; use crate::config::Config; +use crate::configure::EnteredLoginParam; use crate::constants::ShowEmails; use crate::context::Context; use crate::imap; +use crate::login_param::ConfiguredLoginParam; use crate::message::MsgId; use crate::provider::get_provider_by_domain; use crate::sql::Sql; @@ -1186,6 +1188,42 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint); .await?; } + inc_and_check(&mut migration_version, 131)?; + if dbversion < migration_version { + let entered_param = EnteredLoginParam::load(context).await?; + let configured_param = ConfiguredLoginParam::load_legacy(context).await?; + + sql.execute_migration_transaction( + |transaction| { + transaction.execute( + "CREATE TABLE transports ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + addr TEXT NOT NULL, + entered_param TEXT NOT NULL, + configured_param TEXT NOT NULL, + UNIQUE(addr) + )", + (), + )?; + if let Some(configured_param) = configured_param { + transaction.execute( + "INSERT INTO transports (addr, entered_param, configured_param) + VALUES (?, ?, ?)", + ( + configured_param.addr.clone(), + serde_json::to_string(&entered_param)?, + configured_param.into_json()?, + ), + )?; + } + + Ok(()) + }, + migration_version, + ) + .await?; + } + let new_version = sql .get_raw_config_int(VERSION_CFG) .await? @@ -1230,6 +1268,21 @@ impl Sql { } async fn execute_migration(&self, query: &str, version: i32) -> Result<()> { + self.execute_migration_transaction( + |transaction| { + transaction.execute_batch(query)?; + Ok(()) + }, + version, + ) + .await + } + + async fn execute_migration_transaction( + &self, + migration: impl Send + FnOnce(&mut rusqlite::Transaction) -> Result<()>, + version: i32, + ) -> Result<()> { self.transaction(move |transaction| { let curr_version: String = transaction.query_row( "SELECT IFNULL(value, ?) FROM config WHERE keyname=?;", @@ -1239,7 +1292,7 @@ impl Sql { let curr_version: i32 = curr_version.parse()?; ensure!(curr_version < version, "Db version must be increased"); Self::set_db_version_trans(transaction, version)?; - transaction.execute_batch(query)?; + migration(transaction)?; Ok(()) }) diff --git a/src/test_utils.rs b/src/test_utils.rs index 2c6eb24f5..8ee9a1c74 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -477,15 +477,11 @@ impl TestContext { /// The context will be configured but the key will not be pre-generated so if a key is /// used the fingerprint will be different every time. pub async fn configure_addr(&self, addr: &str) { - self.ctx.set_config(Config::Addr, Some(addr)).await.unwrap(); self.ctx .set_config(Config::ConfiguredAddr, Some(addr)) .await .unwrap(); - self.ctx - .set_config(Config::Configured, Some("1")) - .await - .unwrap(); + if let Some(name) = addr.split('@').next() { self.set_name(name); }