Compare commits

...
Author SHA1 Message Date
link2xt 38e01ef43f api: do not allow to set configured_* configs via public API 2023-10-09 18:53:38 +00:00
link2xt 26959d5b75 test(python): fix flaky test_set_get_group_image
Wait for one "Member added" message to be delivered
before sending another text message.
Otherwise they may be reordered by the mail server.
2023-10-09 12:48:33 +00:00
link2xt ff5005fa93 fix(python): fix scripts/make-python-testenv.sh
Without `-c python` tox does not find tox.ini and creates empty environment.

Renamed env/ into venv/ as it is more common.
2023-10-09 12:43:22 +00:00
iequidoo 8f316e12d5 fix: Assign encrypted partially downloaded group messages to 1:1 chat (#4757)
Before they were trashed. Note that for unencrypted ones DC works as expected creating the requested
group immediately because Chat-Group-Id is duplicated in the Message-Id header and Subject is
fetched.
2023-10-09 05:45:18 -03:00
iequidoo 5f00fc4e27 fix: Don't update timestamp, timestamp_rcvd, state when replacing partially downloaded message (#4700)
Also add a test on downloading a message later. Although it doesn't reproduce #4700 for some reason,
it fails w/o the fix because before a message state was changing to `InSeen` after a full download
which doesn't look correct. The result of a full message download should be such as if it was fully
downloaded initially.
2023-10-09 05:45:18 -03:00
link2xt f279730b0f feat: validate boolean values passed to set_config
They may only be set to "0" and "1".
Validation prevents accidentally setting the value to "true", "True" etc.
2023-10-08 23:15:49 +00:00
missytake 5a5f8b03d1 fix(python): don't automatically set the displayname to 'bot' when setting log level 2023-10-08 17:38:57 +00:00
missytake 5e73e9cd72 chore: added more typical virtualenv paths to gitignore 2023-10-08 17:38:57 +00:00
link2xt 129de9182f chore(deltachat-rpc-client): remove AsyncIO classifier 2023-10-08 01:38:52 +00:00
17 changed files with 256 additions and 72 deletions
+3
View File
@@ -18,6 +18,9 @@ python/.eggs
__pycache__
python/src/deltachat/capi*.so
python/.venv/
python/venv/
venv/
env/
python/liveconfig*
-1
View File
@@ -7,7 +7,6 @@ name = "deltachat-rpc-client"
description = "Python client for Delta Chat core JSON-RPC interface"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Framework :: AsyncIO",
"Intended Audience :: Developers",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Operating System :: POSIX :: Linux",
+6 -4
View File
@@ -617,18 +617,18 @@ class Account:
# meta API for start/stop and event based processing
#
def run_account(self, addr=None, password=None, account_plugins=None, show_ffi=False):
from .events import FFIEventLogger
def run_account(self, addr=None, password=None, account_plugins=None, show_ffi=False, displayname=None):
"""get the account running, configure it if necessary. add plugins if provided.
:param addr: the email address of the account
:param password: the password of the account
:param account_plugins: a list of plugins to add
:param show_ffi: show low level ffi events
:param displayname: the display name of the account
"""
from .events import FFIEventLogger
if show_ffi:
self.set_config("displayname", "bot")
log = FFIEventLogger(self)
self.add_account_plugin(log)
@@ -644,6 +644,8 @@ class Account:
configtracker = self.configure()
configtracker.wait_finish()
if displayname:
self.set_config("displayname", displayname)
# start IO threads and configure if necessary
self.start_io()
+4 -2
View File
@@ -1926,13 +1926,15 @@ def test_set_get_group_image(acfactory, data, lp):
lp.sec("ac1: add ac2 to promoted group chat")
chat.add_contact(ac2) # sends one message
lp.sec("ac2: wait for receiving member added message from ac1")
msg1 = ac2._evtracker.wait_next_incoming_message()
assert msg1.is_system_message() # Member added
lp.sec("ac1: send a first message to ac2")
chat.send_text("hi") # sends another message
assert chat.is_promoted()
lp.sec("ac2: wait for receiving message from ac1")
msg1 = ac2._evtracker.wait_next_incoming_message()
assert msg1.is_system_message() # Member added
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == "hi"
assert msg1.chat.id == msg2.chat.id
+1 -1
View File
@@ -18,7 +18,7 @@ and an own build machine.
- `remote_tests_rust.sh` rsyncs to the build machine and runs
`run-rust-test.sh` remotely on the build machine.
- `make-python-testenv.sh` creates or updates local python test development environment.
- `make-python-testenv.sh` creates local python test development environment.
Reusing the same environment is faster than running `run-python-test.sh` which always
recreates environment from scratch and runs additional lints.
+4 -8
View File
@@ -4,8 +4,8 @@
# It rebuilds the core and bindings as needed.
#
# After running the script, you can either
# run `pytest` directly with `env/bin/pytest python/`
# or activate the environment with `. env/bin/activacte`
# run `pytest` directly with `venv/bin/pytest python/`
# or activate the environment with `. venv/bin/activate`
# and run `pytest` from there.
set -euo pipefail
@@ -13,9 +13,5 @@ export DCC_RS_TARGET=debug
export DCC_RS_DEV="$PWD"
cargo build -p deltachat_ffi --features jsonrpc
if test -d env; then
env/bin/pip install -e python --force-reinstall
else
tox -e py --devenv env
env/bin/pip install --upgrade pip
fi
tox -c python -e py --devenv venv
env/bin/pip install --upgrade pip
+54 -3
View File
@@ -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 strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
@@ -465,9 +465,35 @@ impl Context {
.set_raw_config(key.as_ref(), value.as_deref())
.await?;
}
_ => {
Config::Socks5Enabled
| Config::BccSelf
| Config::E2eeEnabled
| Config::MdnsEnabled
| Config::SentboxWatch
| Config::MvboxMove
| Config::OnlyFetchMvbox
| Config::FetchExistingMsgs
| Config::DeleteToTrash
| Config::SaveMimeHeaders
| Config::Configured
| Config::Bot
| Config::NotifyAboutWrongPw
| Config::SendSyncMsgs
| Config::SignUnencrypted => {
ensure!(
matches!(value, None | Some("0") | Some("1")),
"Boolean value must be either 0 or 1"
);
self.sql.set_raw_config(key.as_ref(), value).await?;
}
_ => {
let key = key.as_ref();
if key.starts_with("configured_") {
bail!("not allowed to set {key} parameter directly");
} else {
self.sql.set_raw_config(key, value).await?;
}
}
}
Ok(())
}
@@ -535,7 +561,8 @@ impl Context {
)
.await?;
self.set_config(Config::ConfiguredAddr, Some(primary_new))
self.sql
.set_raw_config(Config::ConfiguredAddr.as_ref(), Some(primary_new))
.await?;
if let Some(old_addr) = old_addr {
@@ -614,6 +641,18 @@ mod tests {
);
}
/// Tests that "bot" config can only be set to "0" or "1".
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_config_bot() {
let t = TestContext::new().await;
assert!(t.set_config(Config::Bot, None).await.is_ok());
assert!(t.set_config(Config::Bot, Some("0")).await.is_ok());
assert!(t.set_config(Config::Bot, Some("1")).await.is_ok());
assert!(t.set_config(Config::Bot, Some("2")).await.is_err());
assert!(t.set_config(Config::Bot, Some("Foobar")).await.is_err());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_media_quality_config_option() {
let t = TestContext::new().await;
@@ -665,6 +704,18 @@ mod tests {
Ok(())
}
/// Test that it is not allowed to set configured parameters directly via public interface.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_configured() -> Result<()> {
let t = TestContext::new().await;
assert!(t
.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await
.is_err());
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_self_addrs() -> Result<()> {
let alice = TestContext::new_alice().await;
+5 -1
View File
@@ -472,7 +472,11 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
// the trailing underscore is correct
param.save_as_configured_params(ctx).await?;
ctx.set_config(Config::ConfiguredTimestamp, Some(&time().to_string()))
ctx.sql
.set_raw_config(
Config::ConfiguredTimestamp.as_ref(),
Some(&time().to_string()),
)
.await?;
progress!(ctx, 920);
+1 -1
View File
@@ -23,7 +23,7 @@ use crate::{job_try, stock_str, EventType};
/// eg. to assign them to the correct chat.
/// As these messages are typically small,
/// they're caught by `MIN_DOWNLOAD_LIMIT`.
const MIN_DOWNLOAD_LIMIT: u32 = 32768;
pub(crate) const MIN_DOWNLOAD_LIMIT: u32 = 32768;
/// If a message is downloaded only partially
/// and `delete_server_after` is set to small timeouts (eg. "at once"),
+14 -12
View File
@@ -1754,16 +1754,21 @@ impl Imap {
.context("failed to configure mvbox")?;
context
.set_config(Config::ConfiguredInboxFolder, Some("INBOX"))
.sql
.set_raw_config(Config::ConfiguredInboxFolder.as_ref(), Some("INBOX"))
.await?;
if let Some(mvbox_folder) = mvbox_folder {
info!(context, "Setting MVBOX FOLDER TO {}", &mvbox_folder);
context
.set_config(Config::ConfiguredMvboxFolder, Some(mvbox_folder))
.sql
.set_raw_config(Config::ConfiguredMvboxFolder.as_ref(), Some(mvbox_folder))
.await?;
}
for (config, name) in folder_configs {
context.set_config(config, Some(&name)).await?;
context
.sql
.set_raw_config(config.as_ref(), Some(&name))
.await?;
}
context
.sql
@@ -2652,15 +2657,12 @@ mod tests {
println!("Testing: For folder {folder}, mvbox_move {mvbox_move}, chat_msg {chat_msg}, accepted {accepted_chat}, outgoing {outgoing}, setupmessage {setupmessage}");
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::ConfiguredMvboxFolder, Some("DeltaChat"))
.await?;
t.ctx
.set_config(Config::ConfiguredSentboxFolder, Some("Sent"))
.await?;
t.ctx
.set_config(Config::MvboxMove, Some(if mvbox_move { "1" } else { "0" }))
.await?;
t.set_raw_config(Config::ConfiguredMvboxFolder, Some("DeltaChat"))
.await;
t.set_raw_config(Config::ConfiguredSentboxFolder, Some("Sent"))
.await;
t.set_raw_config(Config::MvboxMove, Some(if mvbox_move { "1" } else { "0" }))
.await;
if accepted_chat {
let contact_id = Contact::create(&t.ctx, "", "bob@example.net").await?;
+2 -1
View File
@@ -89,7 +89,8 @@ impl Imap {
Config::ConfiguredTrashFolder,
] {
context
.set_config(conf, folder_configs.get(&conf).map(|s| s.as_str()))
.sql
.set_raw_config(conf.as_ref(), folder_configs.get(&conf).map(|s| s.as_str()))
.await?;
}
+6 -9
View File
@@ -531,9 +531,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_self_generate_public() {
let t = TestContext::new().await;
t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await
.unwrap();
t.set_raw_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await;
let key = SignedPublicKey::load_self(&t).await;
assert!(key.is_ok());
}
@@ -541,9 +540,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_self_generate_secret() {
let t = TestContext::new().await;
t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await
.unwrap();
t.set_raw_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await;
let key = SignedSecretKey::load_self(&t).await;
assert!(key.is_ok());
}
@@ -553,9 +551,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
use std::thread;
let t = TestContext::new().await;
t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await
.unwrap();
t.set_raw_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await;
let thr0 = {
let ctx = t.clone();
thread::spawn(move || {
+10 -16
View File
@@ -1948,19 +1948,16 @@ mod tests {
use crate::config::Config;
let d = test::TestContext::new().await;
let ctx = &d.ctx;
ctx.set_config(Config::ConfiguredAddr, Some("self@example.com"))
.await
.unwrap();
d.set_raw_config(Config::ConfiguredAddr, Some("self@example.com"))
.await;
let chat = d.create_chat_with_contact("", "dest@example.com").await;
let mut msg = Message::new(Viewtype::Text);
let msg_id = chat::prepare_msg(ctx, chat.id, &mut msg).await.unwrap();
let msg_id = chat::prepare_msg(&d, chat.id, &mut msg).await.unwrap();
let _msg2 = Message::load_from_db(ctx, msg_id).await.unwrap();
let _msg2 = Message::load_from_db(&d, msg_id).await.unwrap();
assert_eq!(_msg2.get_filemime(), None);
}
@@ -2088,11 +2085,8 @@ mod tests {
use crate::config::Config;
let d = test::TestContext::new().await;
let ctx = &d.ctx;
ctx.set_config(Config::ConfiguredAddr, Some("self@example.com"))
.await
.unwrap();
d.set_raw_config(Config::ConfiguredAddr, Some("self@example.com"))
.await;
let chat = d.create_chat_with_contact("", "dest@example.com").await;
@@ -2101,18 +2095,18 @@ mod tests {
// Prepare message for sending, so it gets a Message-Id.
assert!(msg.rfc724_mid.is_empty());
let msg_id = chat::prepare_msg(ctx, chat.id, &mut msg).await.unwrap();
let msg = Message::load_from_db(ctx, msg_id).await.unwrap();
let msg_id = chat::prepare_msg(&d, chat.id, &mut msg).await.unwrap();
let msg = Message::load_from_db(&d, msg_id).await.unwrap();
assert!(!msg.rfc724_mid.is_empty());
let mut msg2 = Message::new(Viewtype::Text);
msg2.set_quote(ctx, Some(&msg))
msg2.set_quote(&d, Some(&msg))
.await
.expect("can't set quote");
assert_eq!(msg2.quoted_text().unwrap(), msg.get_text());
let quoted_msg = msg2
.quoted_message(ctx)
.quoted_message(&d)
.await
.expect("error while retrieving quoted message")
.expect("quoted message not found");
+1 -1
View File
@@ -110,7 +110,7 @@ pub(crate) struct MimeMessage {
/// The decrypted, raw mime structure.
///
/// This is non-empty only if the message was actually encrypted. It is used
/// This is non-empty iff `is_mime_modified` and the message was actually encrypted. It is used
/// for e.g. late-parsing HTML.
pub decoded_data: Vec<u8>,
+24 -3
View File
@@ -77,6 +77,24 @@ pub async fn receive_imf(
let mail = parse_mail(imf_raw).context("can't parse mail")?;
let rfc724_mid =
imap::prefetch_get_message_id(&mail.headers).unwrap_or_else(imap::create_message_id);
if let Some(download_limit) = context.download_limit().await? {
let download_limit: usize = download_limit.try_into()?;
if imf_raw.len() > download_limit {
let head = std::str::from_utf8(imf_raw)?
.split("\r\n\r\n")
.next()
.context("No empty line in the message")?;
return receive_imf_inner(
context,
&rfc724_mid,
head.as_bytes(),
seen,
Some(imf_raw.len().try_into()?),
false,
)
.await;
}
}
receive_imf_inner(context, &rfc724_mid, imf_raw, seen, None, false).await
}
@@ -578,6 +596,7 @@ async fn add_parts(
if let Some((new_chat_id, new_chat_id_blocked)) = create_or_lookup_group(
context,
mime_parser,
is_partial_download.is_some(),
if test_normal_chat.is_none() {
allow_creation
} else {
@@ -804,6 +823,7 @@ async fn add_parts(
if let Some((new_chat_id, new_chat_id_blocked)) = create_or_lookup_group(
context,
mime_parser,
is_partial_download.is_some(),
allow_creation,
Blocked::Not,
from_id,
@@ -1186,8 +1206,8 @@ INSERT INTO msgs
)
ON CONFLICT (id) DO UPDATE
SET rfc724_mid=excluded.rfc724_mid, chat_id=excluded.chat_id,
from_id=excluded.from_id, to_id=excluded.to_id, timestamp=excluded.timestamp, timestamp_sent=excluded.timestamp_sent,
timestamp_rcvd=excluded.timestamp_rcvd, type=excluded.type, state=excluded.state, msgrmsg=excluded.msgrmsg,
from_id=excluded.from_id, to_id=excluded.to_id, timestamp_sent=excluded.timestamp_sent,
type=excluded.type, msgrmsg=excluded.msgrmsg,
txt=excluded.txt, subject=excluded.subject, txt_raw=excluded.txt_raw, param=excluded.param,
bytes=excluded.bytes, mime_headers=excluded.mime_headers,
mime_compressed=excluded.mime_compressed, mime_in_reply_to=excluded.mime_in_reply_to,
@@ -1500,6 +1520,7 @@ async fn is_probably_private_reply(
async fn create_or_lookup_group(
context: &Context,
mime_parser: &mut MimeMessage,
is_partial_download: bool,
allow_creation: bool,
create_blocked: Blocked,
from_id: ContactId,
@@ -1630,7 +1651,7 @@ async fn create_or_lookup_group(
if let Some(chat_id) = chat_id {
Ok(Some((chat_id, chat_id_blocked)))
} else if mime_parser.decrypting_failed {
} else if is_partial_download || mime_parser.decrypting_failed {
// It is possible that the message was sent to a valid,
// yet unknown group, which was rejected because
// Chat-Group-Name, which is in the encrypted part, was
+113 -1
View File
@@ -10,8 +10,9 @@ use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility};
use crate::chatlist::Chatlist;
use crate::config::Config;
use crate::constants::{DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS};
use crate::download::{DownloadState, MIN_DOWNLOAD_LIMIT};
use crate::imap::prefetch_should_download;
use crate::message::Message;
use crate::message::{self, Message};
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@@ -3697,3 +3698,114 @@ async fn test_keep_member_list_if_possibly_nomember() -> Result<()> {
assert!(is_contact_in_chat(&bob, bob_chat_id, bob_alice_contact).await?);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_download_later() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
alice.set_config(Config::DownloadLimit, Some("1")).await?;
assert_eq!(alice.download_limit().await?, Some(MIN_DOWNLOAD_LIMIT));
let bob = tcm.bob().await;
let bob_chat = bob.create_chat(&alice).await;
let text = String::from_utf8(vec![b'a'; MIN_DOWNLOAD_LIMIT as usize])?;
let sent_msg = bob.send_text(bob_chat.id, &text).await;
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Available);
assert_eq!(msg.state, MessageState::InFresh);
let hi_msg = tcm.send_recv(&bob, &alice, "hi").await;
alice.set_config(Config::DownloadLimit, None).await?;
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Done);
assert_eq!(msg.state, MessageState::InFresh);
assert_eq!(alice.get_last_msg_in(msg.chat_id).await.id, hi_msg.id);
assert!(msg.timestamp_sort <= hi_msg.timestamp_sort);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_group_with_big_msg() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;
let ba_contact = Contact::create(
&bob,
"alice",
&alice.get_config(Config::Addr).await?.unwrap(),
)
.await?;
let file_bytes = include_bytes!("../../test-data/image/screenshot.png");
let bob_grp_id = create_group_chat(&bob, ProtectionStatus::Unprotected, "Group").await?;
add_contact_to_chat(&bob, bob_grp_id, ba_contact).await?;
let mut msg = Message::new(Viewtype::Image);
msg.set_file_from_bytes(&bob, "a.jpg", file_bytes, None)
.await?;
let sent_msg = bob.send_msg(bob_grp_id, &mut msg).await;
assert!(!msg.get_showpadlock());
alice.set_config(Config::DownloadLimit, Some("1")).await?;
assert_eq!(alice.download_limit().await?, Some(MIN_DOWNLOAD_LIMIT));
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Available);
let alice_grp = Chat::load_from_db(&alice, msg.chat_id).await?;
assert_eq!(alice_grp.typ, Chattype::Group);
assert_eq!(alice_grp.name, "Group");
assert_eq!(
chat::get_chat_contacts(&alice, alice_grp.id).await?.len(),
2
);
alice.set_config(Config::DownloadLimit, None).await?;
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Done);
assert_eq!(msg.state, MessageState::InFresh);
assert_eq!(msg.viewtype, Viewtype::Image);
assert_eq!(msg.chat_id, alice_grp.id);
let alice_grp = Chat::load_from_db(&alice, msg.chat_id).await?;
assert_eq!(alice_grp.typ, Chattype::Group);
assert_eq!(alice_grp.name, "Group");
assert_eq!(
chat::get_chat_contacts(&alice, alice_grp.id).await?.len(),
2
);
let ab_chat_id = tcm.send_recv_accept(&alice, &bob, "hi").await.chat_id;
// Now Bob can send encrypted messages to Alice.
let bob_grp_id = create_group_chat(&bob, ProtectionStatus::Unprotected, "Group1").await?;
add_contact_to_chat(&bob, bob_grp_id, ba_contact).await?;
let mut msg = Message::new(Viewtype::Image);
msg.set_file_from_bytes(&bob, "a.jpg", file_bytes, None)
.await?;
let sent_msg = bob.send_msg(bob_grp_id, &mut msg).await;
assert!(msg.get_showpadlock());
alice.set_config(Config::DownloadLimit, Some("1")).await?;
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Available);
// Until fully downloaded, an encrypted message must sit in the 1:1 chat.
assert_eq!(msg.chat_id, ab_chat_id);
alice.set_config(Config::DownloadLimit, None).await?;
let msg = alice.recv_msg(&sent_msg).await;
assert_eq!(msg.download_state, DownloadState::Done);
assert_eq!(msg.state, MessageState::InFresh);
assert_eq!(msg.viewtype, Viewtype::Image);
assert_ne!(msg.chat_id, ab_chat_id);
let alice_grp = Chat::load_from_db(&alice, msg.chat_id).await?;
assert_eq!(alice_grp.typ, Chattype::Group);
assert_eq!(alice_grp.name, "Group1");
assert_eq!(
chat::get_chat_contacts(&alice, alice_grp.id).await?.len(),
2
);
// The big message must go away from the 1:1 chat.
assert_eq!(alice.get_last_msg_in(ab_chat_id).await.text, "hi");
Ok(())
}
+8 -8
View File
@@ -381,20 +381,20 @@ impl TestContext {
self.event_senders.write().await.push(sink)
}
/// Set private configuration value for testing purposes.
pub async fn set_raw_config(&self, key: Config, value: Option<&str>) {
self.sql.set_raw_config(key.as_ref(), value).await.unwrap()
}
/// Configure as a given email address.
///
/// 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();
self.set_raw_config(Config::ConfiguredAddr, Some(addr))
.await;
self.set_raw_config(Config::Configured, Some("1")).await;
if let Some(name) = addr.split('@').next() {
self.set_name(name);
}