feat: migrate from async-std to tokio

This commit is contained in:
Friedel Ziegelmayer
2022-06-27 14:05:21 +02:00
committed by GitHub
parent 997fb4061a
commit 290ee20e63
69 changed files with 1781 additions and 2231 deletions

View File

@@ -1,13 +1,12 @@
//! # Account manager module.
use std::collections::BTreeMap;
use async_std::fs;
use async_std::path::PathBuf;
use uuid::Uuid;
use std::path::{Path, PathBuf};
use anyhow::{ensure, Context as _, Result};
use serde::{Deserialize, Serialize};
use tokio::fs;
use uuid::Uuid;
use crate::context::Context;
use crate::events::{Event, EventEmitter, EventType, Events};
@@ -26,7 +25,7 @@ pub struct Accounts {
impl Accounts {
/// Loads or creates an accounts folder at the given `dir`.
pub async fn new(dir: PathBuf) -> Result<Self> {
if !dir.exists().await {
if !dir.exists() {
Accounts::create(&dir).await?;
}
@@ -47,14 +46,10 @@ impl Accounts {
/// Opens an existing accounts structure. Will error if the folder doesn't exist,
/// no account exists and no config exists.
pub async fn open(dir: PathBuf) -> Result<Self> {
ensure!(dir.exists().await, "directory does not exist");
ensure!(dir.exists(), "directory does not exist");
let config_file = dir.join(CONFIG_NAME);
ensure!(
config_file.exists().await,
"{:?} does not exist",
config_file
);
ensure!(config_file.exists(), "{:?} does not exist", config_file);
let config = Config::from_file(config_file)
.await
@@ -106,7 +101,7 @@ impl Accounts {
let account_config = self.config.new_account(&self.dir).await?;
let ctx = Context::new(
account_config.dbfile().into(),
&account_config.dbfile(),
account_config.id,
self.events.clone(),
)
@@ -121,7 +116,7 @@ impl Accounts {
let account_config = self.config.new_account(&self.dir).await?;
let ctx = Context::new_closed(
account_config.dbfile().into(),
&account_config.dbfile(),
account_config.id,
self.events.clone(),
)
@@ -148,7 +143,7 @@ impl Accounts {
loop {
counter += 1;
if let Err(err) = fs::remove_dir_all(async_std::path::PathBuf::from(&cfg.dir))
if let Err(err) = fs::remove_dir_all(&cfg.dir)
.await
.context("failed to remove account data")
{
@@ -157,7 +152,7 @@ impl Accounts {
}
// Wait 1 second and try again.
async_std::task::sleep(std::time::Duration::from_millis(1000)).await;
tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
} else {
break;
}
@@ -173,16 +168,8 @@ impl Accounts {
let blobdir = Context::derive_blobdir(&dbfile);
let walfile = Context::derive_walfile(&dbfile);
ensure!(
dbfile.exists().await,
"no database found: {}",
dbfile.display()
);
ensure!(
blobdir.exists().await,
"no blobdir found: {}",
blobdir.display()
);
ensure!(dbfile.exists(), "no database found: {}", dbfile.display());
ensure!(blobdir.exists(), "no blobdir found: {}", blobdir.display());
let old_id = self.config.get_selected_account().await;
@@ -193,7 +180,7 @@ impl Accounts {
.await
.context("failed to create new account")?;
let new_dbfile = account_config.dbfile().into();
let new_dbfile = account_config.dbfile();
let new_blobdir = Context::derive_blobdir(&new_dbfile);
let new_walfile = Context::derive_walfile(&new_dbfile);
@@ -207,7 +194,7 @@ impl Accounts {
fs::rename(&blobdir, &new_blobdir)
.await
.context("failed to rename blobdir")?;
if walfile.exists().await {
if walfile.exists() {
fs::rename(&walfile, &new_walfile)
.await
.context("failed to rename walfile")?;
@@ -217,13 +204,13 @@ impl Accounts {
match res {
Ok(_) => {
let ctx = Context::new(new_dbfile, account_config.id, self.events.clone()).await?;
let ctx = Context::new(&new_dbfile, account_config.id, self.events.clone()).await?;
self.accounts.insert(account_config.id, ctx);
Ok(account_config.id)
}
Err(err) => {
// remove temp account
fs::remove_dir_all(async_std::path::PathBuf::from(&account_config.dir))
fs::remove_dir_all(std::path::PathBuf::from(&account_config.dir))
.await
.context("failed to remove account data")?;
@@ -321,7 +308,7 @@ struct InnerConfig {
}
impl Config {
pub async fn new(dir: &PathBuf) -> Result<Self> {
pub async fn new(dir: &Path) -> Result<Self> {
let inner = InnerConfig {
accounts: Vec::new(),
selected_account: 0,
@@ -355,18 +342,14 @@ impl Config {
pub async fn load_accounts(&self, events: &Events) -> Result<BTreeMap<u32, Context>> {
let mut accounts = BTreeMap::new();
for account_config in &self.inner.accounts {
let ctx = Context::new(
account_config.dbfile().into(),
account_config.id,
events.clone(),
)
.await
.with_context(|| {
format!(
"failed to create context from file {:?}",
account_config.dbfile()
)
})?;
let ctx = Context::new(&account_config.dbfile(), account_config.id, events.clone())
.await
.with_context(|| {
format!(
"failed to create context from file {:?}",
account_config.dbfile()
)
})?;
accounts.insert(account_config.id, ctx);
}
@@ -375,7 +358,7 @@ impl Config {
}
/// Create a new account in the given root directory.
async fn new_account(&mut self, dir: &PathBuf) -> Result<AccountConfig> {
async fn new_account(&mut self, dir: &Path) -> Result<AccountConfig> {
let id = {
let id = self.inner.next_id;
let uuid = Uuid::new_v4();
@@ -383,7 +366,7 @@ impl Config {
self.inner.accounts.push(AccountConfig {
id,
dir: target_dir.into(),
dir: target_dir,
uuid,
});
self.inner.next_id += 1;
@@ -464,10 +447,10 @@ impl AccountConfig {
mod tests {
use super::*;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_account_new_open() {
let dir = tempfile::tempdir().unwrap();
let p: PathBuf = dir.path().join("accounts1").into();
let p: PathBuf = dir.path().join("accounts1");
let mut accounts1 = Accounts::new(p.clone()).await.unwrap();
accounts1.add_account().await.unwrap();
@@ -482,10 +465,10 @@ mod tests {
assert_eq!(accounts1.accounts.len(), accounts2.accounts.len());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_account_new_add_remove() {
let dir = tempfile::tempdir().unwrap();
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let mut accounts = Accounts::new(p.clone()).await.unwrap();
assert_eq!(accounts.accounts.len(), 0);
@@ -509,10 +492,10 @@ mod tests {
assert_eq!(accounts.accounts.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_accounts_remove_last() -> Result<()> {
let dir = tempfile::tempdir()?;
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let mut accounts = Accounts::new(p.clone()).await?;
assert!(accounts.get_selected_account().await.is_none());
@@ -530,17 +513,17 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_migrate_account() {
let dir = tempfile::tempdir().unwrap();
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let mut accounts = Accounts::new(p.clone()).await.unwrap();
assert_eq!(accounts.accounts.len(), 0);
assert_eq!(accounts.config.get_selected_account().await, 0);
let extern_dbfile: PathBuf = dir.path().join("other").into();
let ctx = Context::new(extern_dbfile.clone(), 0, Events::new())
let extern_dbfile: PathBuf = dir.path().join("other");
let ctx = Context::new(&extern_dbfile, 0, Events::new())
.await
.unwrap();
ctx.set_config(crate::config::Config::Addr, Some("me@mail.com"))
@@ -567,10 +550,10 @@ mod tests {
}
/// Tests that accounts are sorted by ID.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_accounts_sorted() {
let dir = tempfile::tempdir().unwrap();
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let mut accounts = Accounts::new(p.clone()).await.unwrap();
@@ -585,10 +568,10 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_accounts_ids_unique_increasing_and_persisted() -> Result<()> {
let dir = tempfile::tempdir()?;
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let dummy_accounts = 10;
let (id0, id1, id2) = {
@@ -667,10 +650,10 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_accounts_event_emitter() -> Result<()> {
let dir = tempfile::tempdir().unwrap();
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let accounts = Accounts::new(p.clone()).await?;
@@ -682,7 +665,7 @@ mod tests {
// Test that event emitter does not return `None` immediately.
let duration = std::time::Duration::from_millis(1);
assert!(async_std::future::timeout(duration, event_emitter.recv())
assert!(tokio::time::timeout(duration, event_emitter.recv())
.await
.is_err());
@@ -693,10 +676,10 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_encrypted_account() -> Result<()> {
let dir = tempfile::tempdir().context("failed to create tempdir")?;
let p: PathBuf = dir.path().join("accounts").into();
let p: PathBuf = dir.path().join("accounts");
let mut accounts = Accounts::new(p.clone())
.await

View File

@@ -4,14 +4,13 @@ use core::cmp::max;
use std::ffi::OsStr;
use std::fmt;
use std::io::Cursor;
use async_std::path::{Path, PathBuf};
use async_std::prelude::*;
use async_std::{fs, io};
use std::path::{Path, PathBuf};
use anyhow::{format_err, Context as _, Error, Result};
use image::{DynamicImage, ImageFormat};
use num_traits::FromPrimitive;
use tokio::io::AsyncWriteExt;
use tokio::{fs, io};
use crate::config::Config;
use crate::constants::{
@@ -89,7 +88,7 @@ impl<'a> BlobObject<'a> {
Err(err) => {
if attempt >= MAX_ATTEMPT {
return Err(err).context("failed to create file");
} else if attempt == 1 && !dir.exists().await {
} else if attempt == 1 && !dir.exists() {
fs::create_dir_all(dir).await.ok_or_log(context);
} else {
name = format!("{}-{}{}", stem, rand::random::<u32>(), ext);
@@ -371,108 +370,81 @@ impl<'a> BlobObject<'a> {
mut img_wh: u32,
max_bytes: Option<usize>,
) -> Result<Option<String>> {
let mut img = image::open(&blob_abs).context("image recode failure")?;
let orientation = self.get_exif_orientation(context);
let mut encoded = Vec::new();
let mut changed_name = None;
tokio::task::block_in_place(move || {
let mut img = image::open(&blob_abs).context("image recode failure")?;
let orientation = self.get_exif_orientation(context);
let mut encoded = Vec::new();
let mut changed_name = None;
fn encode_img(img: &DynamicImage, encoded: &mut Vec<u8>) -> anyhow::Result<()> {
encoded.clear();
let mut buf = Cursor::new(encoded);
img.write_to(&mut buf, image::ImageFormat::Jpeg)?;
Ok(())
}
fn encoded_img_exceeds_bytes(
context: &Context,
img: &DynamicImage,
max_bytes: Option<usize>,
encoded: &mut Vec<u8>,
) -> anyhow::Result<bool> {
if let Some(max_bytes) = max_bytes {
encode_img(img, encoded)?;
if encoded.len() > max_bytes {
info!(
context,
"image size {}B ({}x{}px) exceeds {}B, need to scale down",
encoded.len(),
img.width(),
img.height(),
max_bytes,
);
return Ok(true);
}
}
Ok(false)
}
let exceeds_width = img.width() > img_wh || img.height() > img_wh;
let exceeds_width = img.width() > img_wh || img.height() > img_wh;
let do_scale =
exceeds_width || encoded_img_exceeds_bytes(context, &img, max_bytes, &mut encoded)?;
let do_rotate = matches!(orientation, Ok(90) | Ok(180) | Ok(270));
let do_scale =
exceeds_width || encoded_img_exceeds_bytes(context, &img, max_bytes, &mut encoded)?;
let do_rotate = matches!(orientation, Ok(90) | Ok(180) | Ok(270));
if do_scale || do_rotate {
if do_rotate {
img = match orientation {
Ok(90) => img.rotate90(),
Ok(180) => img.rotate180(),
Ok(270) => img.rotate270(),
_ => img,
}
}
if do_scale {
if !exceeds_width {
// The image is already smaller than img_wh, but exceeds max_bytes
// We can directly start with trying to scale down to 2/3 of its current width
img_wh = max(img.width(), img.height()) * 2 / 3
}
loop {
let new_img = img.thumbnail(img_wh, img_wh);
if encoded_img_exceeds_bytes(context, &new_img, max_bytes, &mut encoded)? {
if img_wh < 20 {
return Err(format_err!(
"Failed to scale image to below {}B",
max_bytes.unwrap_or_default()
));
}
img_wh = img_wh * 2 / 3;
} else {
if encoded.is_empty() {
encode_img(&new_img, &mut encoded)?;
}
info!(
context,
"Final scaled-down image size: {}B ({}px)",
encoded.len(),
img_wh
);
break;
if do_scale || do_rotate {
if do_rotate {
img = match orientation {
Ok(90) => img.rotate90(),
Ok(180) => img.rotate180(),
Ok(270) => img.rotate270(),
_ => img,
}
}
if do_scale {
if !exceeds_width {
// The image is already smaller than img_wh, but exceeds max_bytes
// We can directly start with trying to scale down to 2/3 of its current width
img_wh = max(img.width(), img.height()) * 2 / 3
}
loop {
let new_img = img.thumbnail(img_wh, img_wh);
if encoded_img_exceeds_bytes(context, &new_img, max_bytes, &mut encoded)? {
if img_wh < 20 {
return Err(format_err!(
"Failed to scale image to below {}B",
max_bytes.unwrap_or_default()
));
}
img_wh = img_wh * 2 / 3;
} else {
if encoded.is_empty() {
encode_img(&new_img, &mut encoded)?;
}
info!(
context,
"Final scaled-down image size: {}B ({}px)",
encoded.len(),
img_wh
);
break;
}
}
}
// The file format is JPEG now, we may have to change the file extension
if !matches!(ImageFormat::from_path(&blob_abs), Ok(ImageFormat::Jpeg)) {
blob_abs = blob_abs.with_extension("jpg");
let file_name = blob_abs.file_name().context("No avatar file name (???)")?;
let file_name = file_name.to_str().context("Filename is no UTF-8 (???)")?;
changed_name = Some(format!("$BLOBDIR/{}", file_name));
}
if encoded.is_empty() {
encode_img(&img, &mut encoded)?;
}
std::fs::write(&blob_abs, &encoded)
.context("failed to write recoded blob to file")?;
}
// The file format is JPEG now, we may have to change the file extension
if !matches!(ImageFormat::from_path(&blob_abs), Ok(ImageFormat::Jpeg)) {
blob_abs = blob_abs.with_extension("jpg");
let file_name = blob_abs.file_name().context("No avatar file name (???)")?;
let file_name = file_name.to_str().context("Filename is no UTF-8 (???)")?;
changed_name = Some(format!("$BLOBDIR/{}", file_name));
}
if encoded.is_empty() {
encode_img(&img, &mut encoded)?;
}
fs::write(&blob_abs, &encoded)
.await
.context("failed to write recoded blob to file")?;
}
Ok(changed_name)
Ok(changed_name)
})
}
pub fn get_exif_orientation(&self, context: &Context) -> Result<i32, Error> {
@@ -500,6 +472,35 @@ impl<'a> fmt::Display for BlobObject<'a> {
}
}
fn encode_img(img: &DynamicImage, encoded: &mut Vec<u8>) -> anyhow::Result<()> {
encoded.clear();
let mut buf = Cursor::new(encoded);
img.write_to(&mut buf, image::ImageFormat::Jpeg)?;
Ok(())
}
fn encoded_img_exceeds_bytes(
context: &Context,
img: &DynamicImage,
max_bytes: Option<usize>,
encoded: &mut Vec<u8>,
) -> anyhow::Result<bool> {
if let Some(max_bytes) = max_bytes {
encode_img(img, encoded)?;
if encoded.len() > max_bytes {
info!(
context,
"image size {}B ({}x{}px) exceeds {}B, need to scale down",
encoded.len(),
img.width(),
img.height(),
max_bytes,
);
return Ok(true);
}
}
Ok(false)
}
#[cfg(test)]
mod tests {
use fs::File;
@@ -513,7 +514,16 @@ mod tests {
use super::*;
#[async_std::test]
fn check_image_size(path: impl AsRef<Path>, width: u32, height: u32) -> image::DynamicImage {
tokio::task::block_in_place(move || {
let img = image::open(path).expect("failed to open image");
assert_eq!(img.width(), width, "invalid width");
assert_eq!(img.height(), height, "invalid height");
img
})
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create() {
let t = TestContext::new().await;
let blob = BlobObject::create(&t, "foo", b"hello").await.unwrap();
@@ -524,28 +534,28 @@ mod tests {
assert_eq!(blob.to_abs_path(), t.get_blobdir().join("foo"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_lowercase_ext() {
let t = TestContext::new().await;
let blob = BlobObject::create(&t, "foo.TXT", b"hello").await.unwrap();
assert_eq!(blob.as_name(), "$BLOBDIR/foo.txt");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_as_file_name() {
let t = TestContext::new().await;
let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap();
assert_eq!(blob.as_file_name(), "foo.txt");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_as_rel_path() {
let t = TestContext::new().await;
let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap();
assert_eq!(blob.as_rel_path(), Path::new("foo.txt"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_suffix() {
let t = TestContext::new().await;
let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap();
@@ -554,16 +564,16 @@ mod tests {
assert_eq!(blob.suffix(), None);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_dup() {
let t = TestContext::new().await;
BlobObject::create(&t, "foo.txt", b"hello").await.unwrap();
let foo_path = t.get_blobdir().join("foo.txt");
assert!(foo_path.exists().await);
assert!(foo_path.exists());
BlobObject::create(&t, "foo.txt", b"world").await.unwrap();
let mut dir = fs::read_dir(t.get_blobdir()).await.unwrap();
while let Some(dirent) = dir.next().await {
let fname = dirent.unwrap().file_name();
while let Ok(Some(dirent)) = dir.next_entry().await {
let fname = dirent.file_name();
if fname == foo_path.file_name().unwrap() {
assert_eq!(fs::read(&foo_path).await.unwrap(), b"hello");
} else {
@@ -574,20 +584,20 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_double_ext_preserved() {
let t = TestContext::new().await;
BlobObject::create(&t, "foo.tar.gz", b"hello")
.await
.unwrap();
let foo_path = t.get_blobdir().join("foo.tar.gz");
assert!(foo_path.exists().await);
assert!(foo_path.exists());
BlobObject::create(&t, "foo.tar.gz", b"world")
.await
.unwrap();
let mut dir = fs::read_dir(t.get_blobdir()).await.unwrap();
while let Some(dirent) = dir.next().await {
let fname = dirent.unwrap().file_name();
while let Ok(Some(dirent)) = dir.next_entry().await {
let fname = dirent.file_name();
if fname == foo_path.file_name().unwrap() {
assert_eq!(fs::read(&foo_path).await.unwrap(), b"hello");
} else {
@@ -599,7 +609,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_long_names() {
let t = TestContext::new().await;
let s = "1".repeat(150);
@@ -608,7 +618,7 @@ mod tests {
assert!(blobname.len() < 128);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_and_copy() {
let t = TestContext::new().await;
let src = t.dir.path().join("src");
@@ -623,10 +633,10 @@ mod tests {
.await
.is_err());
let whoops = t.get_blobdir().join("whoops");
assert!(!whoops.exists().await);
assert!(!whoops.exists());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_from_path() {
let t = TestContext::new().await;
@@ -646,7 +656,7 @@ mod tests {
let data = fs::read(blob.to_abs_path()).await.unwrap();
assert_eq!(data, b"boo");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_from_name_long() {
let t = TestContext::new().await;
let src_ext = t.dir.path().join("autocrypt-setup-message-4137848473.html");
@@ -709,7 +719,7 @@ mod tests {
assert!(!stem.contains('?'));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_selfavatar_outside_blobdir() {
let t = TestContext::new().await;
let avatar_src = t.dir.path().join("avatar.jpg");
@@ -721,22 +731,17 @@ mod tests {
.await
.unwrap();
let avatar_blob = t.get_blobdir().join("avatar.jpg");
assert!(!avatar_blob.exists().await);
assert!(!avatar_blob.exists());
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
.await
.unwrap();
assert!(avatar_blob.exists().await);
assert!(std::fs::metadata(&avatar_blob).unwrap().len() < avatar_bytes.len() as u64);
assert!(avatar_blob.exists());
assert!(tokio::fs::metadata(&avatar_blob).await.unwrap().len() < avatar_bytes.len() as u64);
let avatar_cfg = t.get_config(Config::Selfavatar).await.unwrap();
assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string()));
let img = image::open(avatar_src).unwrap();
assert_eq!(img.width(), 1000);
assert_eq!(img.height(), 1000);
let img = image::open(&avatar_blob).unwrap();
assert_eq!(img.width(), BALANCED_AVATAR_SIZE);
assert_eq!(img.height(), BALANCED_AVATAR_SIZE);
check_image_size(avatar_src, 1000, 1000);
check_image_size(&avatar_blob, BALANCED_AVATAR_SIZE, BALANCED_AVATAR_SIZE);
async fn file_size(path_buf: &PathBuf) -> u64 {
let file = File::open(path_buf).await.unwrap();
@@ -750,12 +755,14 @@ mod tests {
.unwrap();
assert!(file_size(&avatar_blob).await <= 3000);
assert!(file_size(&avatar_blob).await > 2000);
let img = image::open(&avatar_blob).unwrap();
assert!(img.width() > 130);
assert_eq!(img.width(), img.height());
tokio::task::block_in_place(move || {
let img = image::open(&avatar_blob).unwrap();
assert!(img.width() > 130);
assert_eq!(img.width(), img.height());
});
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_selfavatar_in_blobdir() {
let t = TestContext::new().await;
let avatar_src = t.get_blobdir().join("avatar.png");
@@ -766,9 +773,7 @@ mod tests {
.await
.unwrap();
let img = image::open(&avatar_src).unwrap();
assert_eq!(img.width(), 900);
assert_eq!(img.height(), 900);
check_image_size(&avatar_src, 900, 900);
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
.await
@@ -779,12 +784,10 @@ mod tests {
avatar_src.with_extension("jpg").to_str().unwrap()
);
let img = image::open(avatar_cfg).unwrap();
assert_eq!(img.width(), BALANCED_AVATAR_SIZE);
assert_eq!(img.height(), BALANCED_AVATAR_SIZE);
check_image_size(avatar_cfg, BALANCED_AVATAR_SIZE, BALANCED_AVATAR_SIZE);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_selfavatar_copy_without_recode() {
let t = TestContext::new().await;
let avatar_src = t.dir.path().join("avatar.png");
@@ -796,20 +799,20 @@ mod tests {
.await
.unwrap();
let avatar_blob = t.get_blobdir().join("avatar.png");
assert!(!avatar_blob.exists().await);
assert!(!avatar_blob.exists());
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
.await
.unwrap();
assert!(avatar_blob.exists().await);
assert!(avatar_blob.exists());
assert_eq!(
std::fs::metadata(&avatar_blob).unwrap().len(),
tokio::fs::metadata(&avatar_blob).await.unwrap().len(),
avatar_bytes.len() as u64
);
let avatar_cfg = t.get_config(Config::Selfavatar).await.unwrap();
assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string()));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_recode_image_1() {
let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg");
// BALANCED_IMAGE_SIZE > 1000, the original image size, so the image is not scaled down:
@@ -829,7 +832,7 @@ mod tests {
.unwrap();
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_recode_image_2() {
// The "-rotated" files are rotated by 270 degrees using the Exif metadata
let bytes = include_bytes!("../test-data/image/rectangle2000x1800-rotated.jpg");
@@ -855,7 +858,7 @@ mod tests {
// Do this in parallel to speed up the test a bit
// (it still takes very long though)
let bytes2 = bytes.clone();
let join_handle = async_std::task::spawn(async move {
let join_handle = tokio::task::spawn(async move {
let img_rotated = send_image_check_mediaquality(
Some("0"),
&bytes2,
@@ -883,10 +886,10 @@ mod tests {
.unwrap();
assert_correct_rotation(&img_rotated);
join_handle.await;
join_handle.await.unwrap();
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_recode_image_3() {
let bytes = include_bytes!("../test-data/image/rectangle200x180-rotated.jpg");
let img_rotated = send_image_check_mediaquality(Some("0"), bytes, 200, 180, 270, 180, 200)
@@ -934,10 +937,10 @@ mod tests {
.await?;
let file = alice.get_blobdir().join("file.jpg");
File::create(&file).await?.write_all(bytes).await?;
let img = image::open(&file)?;
assert_eq!(img.width(), original_width);
assert_eq!(img.height(), original_height);
fs::write(&file, &bytes)
.await
.context("failed to write file")?;
check_image_size(&file, original_width, original_height);
let blob = BlobObject::new_from_path(&alice, &file).await?;
assert_eq!(blob.get_exif_orientation(&alice).unwrap_or(0), orientation);
@@ -949,9 +952,11 @@ mod tests {
let alice_msg = alice.get_last_msg().await;
assert_eq!(alice_msg.get_width() as u32, compressed_width);
assert_eq!(alice_msg.get_height() as u32, compressed_height);
let img = image::open(alice_msg.get_file(&alice).unwrap())?;
assert_eq!(img.width() as u32, compressed_width);
assert_eq!(img.height() as u32, compressed_height);
check_image_size(
alice_msg.get_file(&alice).unwrap(),
compressed_width,
compressed_height,
);
let bob_msg = bob.recv_msg(&sent).await;
assert_eq!(bob_msg.get_width() as u32, compressed_width);
@@ -961,13 +966,11 @@ mod tests {
let blob = BlobObject::new_from_path(&bob, &file).await?;
assert_eq!(blob.get_exif_orientation(&bob).unwrap_or(0), 0);
let img = image::open(file)?;
assert_eq!(img.width() as u32, compressed_width);
assert_eq!(img.height() as u32, compressed_height);
let img = check_image_size(file, compressed_width, compressed_height);
Ok(img)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_increation_in_blobdir() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?;
@@ -986,7 +989,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_increation_not_blobdir() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?;

View File

@@ -2,11 +2,11 @@
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::{Duration, SystemTime};
use anyhow::{bail, ensure, Context as _, Result};
use async_std::path::{Path, PathBuf};
use deltachat_derive::{FromSql, ToSql};
use serde::{Deserialize, Serialize};
@@ -3464,10 +3464,10 @@ mod tests {
use crate::contact::Contact;
use crate::dc_receive_imf::dc_receive_imf;
use crate::test_utils::TestContext;
use async_std::fs::File;
use async_std::prelude::*;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_info() {
let t = TestContext::new().await;
let chat = t.create_chat_with_contact("bob", "bob@example.com").await;
@@ -3498,7 +3498,7 @@ mod tests {
assert_eq!(info, loaded);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_draft_no_draft() {
let t = TestContext::new().await;
let chat = t.get_self_chat().await;
@@ -3506,14 +3506,14 @@ mod tests {
assert!(draft.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_draft_special_chat_id() {
let t = TestContext::new().await;
let draft = DC_CHAT_ID_LAST_SPECIAL.get_draft(&t).await.unwrap();
assert!(draft.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_draft_no_chat() {
// This is a weird case, maybe this should be an error but we
// do not get this info from the database currently.
@@ -3522,7 +3522,7 @@ mod tests {
assert!(draft.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_draft() {
let t = TestContext::new().await;
let chat_id = &t.get_self_chat().await.id;
@@ -3536,7 +3536,7 @@ mod tests {
assert_eq!(msg_text, draft_text);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete_draft() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?;
@@ -3557,7 +3557,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forwarding_draft_failing() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = &t.get_self_chat().await.id;
@@ -3571,7 +3571,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_draft_stable_ids() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = &t.get_self_chat().await.id;
@@ -3616,7 +3616,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_change_quotes_on_reused_message_object() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
@@ -3668,7 +3668,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_contact_to_chat_ex_add_self() {
// Adding self to a contact should succeed, even though it's pointless.
let t = TestContext::new_alice().await;
@@ -3681,7 +3681,7 @@ mod tests {
assert_eq!(added, false);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_modify_chat_multi_device() -> Result<()> {
let a1 = TestContext::new_alice().await;
let a2 = TestContext::new_alice().await;
@@ -3756,7 +3756,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_modify_chat_disordered() -> Result<()> {
// Alice creates a group with Bob, Claire and Daisy and then removes Claire and Daisy
// (sleep() is needed as otherwise smeared time from Alice looks to Bob like messages from the future which are all set to "now" then)
@@ -3770,47 +3770,47 @@ mod tests {
send_text_msg(&alice, alice_chat_id, "populate".to_string()).await?;
add_contact_to_chat(&alice, alice_chat_id, bob_id).await?;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
let add1 = alice.pop_sent_msg().await;
add_contact_to_chat(&alice, alice_chat_id, claire_id).await?;
let add2 = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
add_contact_to_chat(&alice, alice_chat_id, daisy_id).await?;
let add3 = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
assert_eq!(get_chat_contacts(&alice, alice_chat_id).await?.len(), 4);
remove_contact_from_chat(&alice, alice_chat_id, claire_id).await?;
let remove1 = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
remove_contact_from_chat(&alice, alice_chat_id, daisy_id).await?;
let remove2 = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
assert_eq!(get_chat_contacts(&alice, alice_chat_id).await?.len(), 2);
// Bob receives the add and deletion messages out of order
let bob = TestContext::new_bob().await;
bob.recv_msg(&add1).await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
bob.recv_msg(&add3).await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
let bob_chat_id = bob.recv_msg(&add2).await.chat_id;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
assert_eq!(get_chat_contacts(&bob, bob_chat_id).await?.len(), 4);
bob.recv_msg(&remove2).await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
bob.recv_msg(&remove1).await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
assert_eq!(get_chat_contacts(&bob, bob_chat_id).await?.len(), 2);
@@ -3818,7 +3818,7 @@ mod tests {
}
/// Test that group updates are robust to lost messages and eventual out of order arrival.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_modify_chat_lost() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -3833,11 +3833,11 @@ mod tests {
send_text_msg(&alice, alice_chat_id, "populate".to_string()).await?;
let add = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
remove_contact_from_chat(&alice, alice_chat_id, claire_id).await?;
let remove1 = alice.pop_sent_msg().await;
async_std::task::sleep(std::time::Duration::from_millis(1100)).await;
tokio::time::sleep(std::time::Duration::from_millis(1100)).await;
remove_contact_from_chat(&alice, alice_chat_id, daisy_id).await?;
let remove2 = alice.pop_sent_msg().await;
@@ -3860,7 +3860,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_leave_group() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -3889,7 +3889,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_remove_contact_for_single() {
let ctx = TestContext::new_alice().await;
let bob = Contact::create(&ctx, "", "bob@f.br").await.unwrap();
@@ -3913,7 +3913,7 @@ mod tests {
assert_eq!(get_chat_contacts(&ctx, chat.id).await.unwrap().len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_self_talk() -> Result<()> {
let t = TestContext::new_alice().await;
let chat = &t.get_self_chat().await;
@@ -3944,7 +3944,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_device_msg_unlabelled() {
let t = TestContext::new().await;
@@ -3979,7 +3979,7 @@ mod tests {
assert_eq!(msg2.chat_id.get_msg_cnt(&t).await.unwrap(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_device_msg_labelled() -> Result<()> {
let t = TestContext::new().await;
@@ -4029,7 +4029,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_device_msg_label_only() {
let t = TestContext::new().await;
let res = add_device_msg(&t, Some(""), None).await;
@@ -4049,7 +4049,7 @@ mod tests {
assert!(!msg_id.as_ref().unwrap().is_unset());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_was_device_msg_ever_added() {
let t = TestContext::new().await;
add_device_msg(&t, Some("some-label"), None).await.ok();
@@ -4069,7 +4069,7 @@ mod tests {
assert!(was_device_msg_ever_added(&t, "").await.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete_device_chat() {
let t = TestContext::new().await;
@@ -4089,7 +4089,7 @@ mod tests {
assert_eq!(chatlist_len(&t, 0).await, 0)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_device_chat_cannot_sent() {
let t = TestContext::new().await;
t.update_device_chats().await.unwrap();
@@ -4106,7 +4106,7 @@ mod tests {
assert!(forward_msgs(&t, &[msg_id], device_chat_id).await.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete_and_reset_all_device_msgs() {
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
@@ -4138,7 +4138,7 @@ mod tests {
.len()
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_archive() {
// create two chats
let t = TestContext::new().await;
@@ -4241,7 +4241,7 @@ mod tests {
assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_unarchive_if_muted() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -4335,7 +4335,7 @@ mod tests {
result
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pinned() {
let t = TestContext::new().await;
@@ -4347,9 +4347,9 @@ mod tests {
.await
.unwrap()
.chat_id;
async_std::task::sleep(std::time::Duration::from_millis(1000)).await;
tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
let chat_id2 = t.get_self_chat().await.id;
async_std::task::sleep(std::time::Duration::from_millis(1000)).await;
tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
let chat_id3 = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
.await
.unwrap();
@@ -4392,7 +4392,7 @@ mod tests {
assert_eq!(chatlist, vec![chat_id3, chat_id2, chat_id1]);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_chat_name() {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
@@ -4410,7 +4410,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_same_chat_twice() {
let context = TestContext::new().await;
let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de")
@@ -4433,7 +4433,7 @@ mod tests {
assert_eq!(chat2.name, chat.name);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_shall_attach_selfavatar() -> Result<()> {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -4451,7 +4451,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_mute_duration() {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
@@ -4502,7 +4502,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_info_msg() -> Result<()> {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -4519,7 +4519,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_info_msg_with_cmd() -> Result<()> {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -4549,7 +4549,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_protection() {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
@@ -4617,7 +4617,7 @@ mod tests {
assert_eq!(msg.get_state(), MessageState::OutDelivered); // as bcc-self is disabled and there is nobody else in the chat
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_lookup_by_contact_id() {
let ctx = TestContext::new_alice().await;
@@ -4660,7 +4660,7 @@ mod tests {
assert!(found.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_lookup_self_by_contact_id() {
let ctx = TestContext::new_alice().await;
@@ -4679,7 +4679,7 @@ mod tests {
assert_eq!(chat.blocked, Blocked::Not);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_group_with_removed_message_id() -> Result<()> {
// Alice creates a group with Bob, sends a message to bob
let alice = TestContext::new_alice().await;
@@ -4733,7 +4733,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_marknoticed_chat() -> Result<()> {
let t = TestContext::new_alice().await;
let chat = t.create_chat_with_contact("bob", "bob@example.org").await;
@@ -4778,7 +4778,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_request_fresh_messages() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -4828,7 +4828,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_request_archive() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -4868,7 +4868,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_classic_email_chat() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -4913,7 +4913,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_get_color() -> Result<()> {
let t = TestContext::new().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -4956,7 +4956,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sticker_png() -> Result<()> {
test_sticker(
"sticker.png",
@@ -4967,7 +4967,7 @@ mod tests {
.await
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sticker_jpeg() -> Result<()> {
test_sticker(
"sticker.jpg",
@@ -4978,7 +4978,7 @@ mod tests {
.await
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sticker_gif() -> Result<()> {
test_sticker(
"sticker.gif",
@@ -4989,7 +4989,7 @@ mod tests {
.await
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sticker_forward() -> Result<()> {
// create chats
let alice = TestContext::new_alice().await;
@@ -5020,7 +5020,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forward() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -5041,7 +5041,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forward_info_msg() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -5067,7 +5067,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forward_quote() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -5102,7 +5102,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forward_group() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -5152,7 +5152,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_only_minimal_data_are_forwarded() -> Result<()> {
// send a message from Alice to a group with Bob
let alice = TestContext::new_alice().await;
@@ -5194,7 +5194,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_own_message() -> Result<()> {
// Alice creates group with Bob and sends an initial message
let alice = TestContext::new_alice().await;
@@ -5247,7 +5247,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_foreign_message_fails() -> Result<()> {
let alice = TestContext::new_alice().await;
let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?;
@@ -5266,7 +5266,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_opportunistically_encryption() -> Result<()> {
// Alice creates group with Bob and sends an initial message
let alice = TestContext::new_alice().await;
@@ -5303,7 +5303,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_info_message_fails() -> Result<()> {
let alice = TestContext::new_alice().await;
let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?;
@@ -5327,7 +5327,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_can_send_group() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = Contact::create(&alice, "", "bob@f.br").await?;
@@ -5353,7 +5353,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_broadcast() -> Result<()> {
// create two context, send two messages so both know the other
let alice = TestContext::new_alice().await;
@@ -5396,7 +5396,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_for_contact_with_blocked() -> Result<()> {
let t = TestContext::new().await;
let (contact_id, _) =
@@ -5430,7 +5430,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_get_encryption_info() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;

View File

@@ -376,7 +376,7 @@ mod tests {
use crate::stock_str::StockMessage;
use crate::test_utils::TestContext;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_try_load() {
let t = TestContext::new().await;
let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat")
@@ -432,7 +432,7 @@ mod tests {
assert_eq!(chats.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sort_self_talk_up_on_forward() {
let t = TestContext::new().await;
t.update_device_chats().await.unwrap();
@@ -457,7 +457,7 @@ mod tests {
.is_self_talk());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_special_chat_names() {
let t = TestContext::new().await;
t.update_device_chats().await.unwrap();
@@ -488,7 +488,7 @@ mod tests {
assert_eq!(chats.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_single_chat() -> anyhow::Result<()> {
let t = TestContext::new_alice().await;
@@ -548,7 +548,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_single_chat_without_authname() -> anyhow::Result<()> {
let t = TestContext::new_alice().await;
@@ -610,7 +610,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_summary_unwrap() {
let t = TestContext::new().await;
let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat")

View File

@@ -454,7 +454,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_media_quality_config_option() {
let t = TestContext::new().await;
let media_quality = t.get_config_int(Config::MediaQuality).await.unwrap();
@@ -471,7 +471,7 @@ mod tests {
assert_eq!(media_quality, constants::MediaQuality::Worse);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ui_config() -> Result<()> {
let t = TestContext::new().await;
@@ -493,7 +493,7 @@ mod tests {
}
/// Regression test for https://github.com/deltachat/deltachat-core-rust/issues/3012
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_config_bool() -> Result<()> {
let t = TestContext::new().await;
@@ -505,7 +505,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_self_addrs() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -558,7 +558,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_change_primary_self_addr() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;

View File

@@ -6,9 +6,10 @@ mod read_url;
mod server_params;
use anyhow::{bail, ensure, Context as _, Result};
use async_std::prelude::*;
use async_std::task;
use futures::FutureExt;
use futures_lite::FutureExt as _;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use tokio::task;
use crate::config::Config;
use crate::context::Context;
@@ -55,8 +56,6 @@ impl Context {
/// Configures this account with the currently set parameters.
pub async fn configure(&self) -> Result<()> {
use futures::future::FutureExt;
ensure!(
self.scheduler.read().await.is_none(),
"cannot configure, already running"
@@ -404,7 +403,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
progress!(ctx, 850);
// Wait for SMTP configuration
match smtp_config_task.await {
match smtp_config_task.await.unwrap() {
Ok(smtp_param) => {
param.smtp = smtp_param;
}
@@ -447,7 +446,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
ctx.interrupt_inbox(InterruptInfo::new(false)).await;
progress!(ctx, 940);
update_device_chats_handle.await?;
update_device_chats_handle.await??;
ctx.sql.set_raw_config_bool("configured", true).await?;
@@ -549,7 +548,7 @@ async fn try_imap_one_param(
);
info!(context, "Trying: {}", inf);
let (_s, r) = async_std::channel::bounded(1);
let (_s, r) = async_channel::bounded(1);
let mut imap = match Imap::new(param, socks5_config.clone(), addr, provider_strict_tls, r).await
{
@@ -634,10 +633,13 @@ async fn nicer_configuration_error(context: &Context, errors: Vec<ConfigurationE
return "no error".to_string();
};
if errors
.iter()
.all(|e| e.msg.to_lowercase().contains("could not resolve"))
{
if errors.iter().all(|e| {
e.msg.to_lowercase().contains("could not resolve")
|| e.msg
.to_lowercase()
.contains("temporary failure in name resolution")
|| e.msg.to_lowercase().contains("name or service not known")
}) {
return stock_str::error_no_network(context).await;
}
@@ -678,7 +680,7 @@ mod tests {
use crate::config::Config;
use crate::test_utils::TestContext;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_panic_on_bad_credentials() {
let t = TestContext::new().await;
t.set_config(Config::Addr, Some("probably@unexistant.addr"))

View File

@@ -1,7 +1,6 @@
use crate::context::Context;
use anyhow::{anyhow, format_err};
use anyhow::format_err;
use anyhow::Context as _;
use crate::context::Context;
pub async fn read_url(context: &Context, url: &str) -> anyhow::Result<String> {
match read_url_inner(context, url).await {
@@ -16,24 +15,27 @@ pub async fn read_url(context: &Context, url: &str) -> anyhow::Result<String> {
}
}
pub async fn read_url_inner(context: &Context, mut url: &str) -> anyhow::Result<String> {
let mut _temp; // For the borrow checker
pub async fn read_url_inner(context: &Context, url: &str) -> anyhow::Result<String> {
let client = reqwest::Client::new();
let mut url = url.to_string();
// Follow up to 10 http-redirects
for _i in 0..10 {
let mut response = surf::get(url).send().await.map_err(|e| e.into_inner())?;
let response = client.get(&url).send().await?;
if response.status().is_redirection() {
_temp = response
.header("location")
.context("Redirection doesn't have a target location")?
let headers = response.headers();
let header = headers
.get_all("location")
.iter()
.last()
.to_string();
info!(context, "Following redirect to {}", _temp);
url = &_temp;
.ok_or_else(|| anyhow!("Redirection doesn't have a target location"))?
.to_str()?;
info!(context, "Following redirect to {}", header);
url = header.to_string();
continue;
}
return response.body_string().await.map_err(|e| e.into_inner());
return response.text().await.map_err(Into::into);
}
Err(format_err!("Followed 10 redirections"))

View File

@@ -2,9 +2,9 @@
use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::path::PathBuf;
use anyhow::{bail, ensure, Context as _, Result};
use async_std::path::PathBuf;
use deltachat_derive::{FromSql, ToSql};
use once_cell::sync::Lazy;
use regex::Regex;
@@ -1438,8 +1438,8 @@ fn split_address_book(book: &str) -> Vec<(&str, &str)> {
#[cfg(test)]
mod tests {
use async_std::fs::File;
use async_std::io::WriteExt;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use super::*;
@@ -1508,7 +1508,7 @@ mod tests {
)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_contacts() -> Result<()> {
let context = TestContext::new().await;
@@ -1572,7 +1572,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_self_addr() -> Result<()> {
let t = TestContext::new().await;
assert_eq!(t.is_self_addr("me@me.org").await?, false);
@@ -1584,7 +1584,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_or_lookup() {
// add some contacts, this also tests add_address_book()
let t = TestContext::new().await;
@@ -1685,7 +1685,7 @@ mod tests {
assert!(!contact.is_blocked());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_name_changes() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -1797,7 +1797,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -1825,7 +1825,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_remote_authnames() {
let t = TestContext::new().await;
@@ -1876,7 +1876,7 @@ mod tests {
assert_eq!(contact.get_display_name(), "bob3");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_remote_authnames_create_empty() {
let t = TestContext::new().await;
@@ -1925,7 +1925,7 @@ mod tests {
///
/// In the past, "Not Bob" name was stuck until "Bob" changed the name to "Not Bob" and back in
/// the "From:" field or user set the name to empty string manually.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_remote_authnames_update_to() -> Result<()> {
let t = TestContext::new().await;
@@ -1958,7 +1958,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_remote_authnames_edit_empty() {
let t = TestContext::new().await;
@@ -1995,7 +1995,7 @@ mod tests {
assert!(addr_cmp(" mailto:AA@AA.ORG", "Aa@Aa.orG"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_name_in_address() {
let t = TestContext::new().await;
@@ -2034,7 +2034,7 @@ mod tests {
.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_lookup_id_by_addr() {
let t = TestContext::new().await;
@@ -2059,7 +2059,7 @@ mod tests {
assert_eq!(id, Some(ContactId::SELF));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_get_color() -> Result<()> {
let t = TestContext::new().await;
let contact_id = Contact::create(&t, "name", "name@example.net").await?;
@@ -2078,7 +2078,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_get_encrinfo() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -2123,7 +2123,7 @@ CCCB 5AA9 F6E1 141C 9431
/// Tests that status is synchronized when sending encrypted BCC-self messages and not
/// synchronized when the message is not encrypted.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_synchronize_status() -> Result<()> {
// Alice has two devices.
let alice1 = TestContext::new_alice().await;
@@ -2188,7 +2188,7 @@ CCCB 5AA9 F6E1 141C 9431
}
/// Tests that DC_EVENT_SELFAVATAR_CHANGED is emitted on avatar changes.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_selfavatar_changed_event() -> Result<()> {
// Alice has two devices.
let alice1 = TestContext::new_alice().await;
@@ -2247,7 +2247,7 @@ CCCB 5AA9 F6E1 141C 9431
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_last_seen() -> Result<()> {
let alice = TestContext::new_alice().await;

View File

@@ -3,14 +3,13 @@
use std::collections::{BTreeMap, HashMap};
use std::ffi::OsString;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime};
use anyhow::{ensure, Result};
use async_std::{
channel::{self, Receiver, Sender},
path::{Path, PathBuf},
sync::{Arc, Mutex, RwLock},
};
use async_channel::{self as channel, Receiver, Sender};
use tokio::sync::{Mutex, RwLock};
use crate::chat::{get_chat_cnt, ChatId};
use crate::config::Config;
@@ -75,7 +74,7 @@ pub struct InnerContext {
/// The text of the last error logged and emitted as an event.
/// If the ui wants to display an error after a failure,
/// `last_error` should be used to avoid races with the event thread.
pub(crate) last_error: RwLock<String>,
pub(crate) last_error: std::sync::RwLock<String>,
}
/// The state of ongoing process.
@@ -115,7 +114,7 @@ pub fn get_info() -> BTreeMap<&'static str, String> {
impl Context {
/// Creates new context and opens the database.
pub async fn new(dbfile: PathBuf, id: u32, events: Events) -> Result<Context> {
pub async fn new(dbfile: &Path, id: u32, events: Events) -> Result<Context> {
let context = Self::new_closed(dbfile, id, events).await?;
// Open the database if is not encrypted.
@@ -126,15 +125,15 @@ impl Context {
}
/// Creates new context without opening the database.
pub async fn new_closed(dbfile: PathBuf, id: u32, events: Events) -> Result<Context> {
pub async fn new_closed(dbfile: &Path, id: u32, events: Events) -> Result<Context> {
let mut blob_fname = OsString::new();
blob_fname.push(dbfile.file_name().unwrap_or_default());
blob_fname.push("-blobs");
let blobdir = dbfile.with_file_name(blob_fname);
if !blobdir.exists().await {
async_std::fs::create_dir_all(&blobdir).await?;
if !blobdir.exists() {
tokio::fs::create_dir_all(&blobdir).await?;
}
let context = Context::with_blobdir(dbfile, blobdir, id, events).await?;
let context = Context::with_blobdir(dbfile.into(), blobdir, id, events).await?;
Ok(context)
}
@@ -172,7 +171,7 @@ impl Context {
events: Events,
) -> Result<Context> {
ensure!(
blobdir.is_dir().await,
blobdir.is_dir(),
"Blobdir does not exist: {}",
blobdir.display()
);
@@ -193,7 +192,7 @@ impl Context {
quota: RwLock::new(None),
creation_time: std::time::SystemTime::now(),
last_full_folder_scan: Mutex::new(None),
last_error: RwLock::new("".to_string()),
last_error: std::sync::RwLock::new("".to_string()),
};
let ctx = Context {
@@ -643,14 +642,14 @@ impl Context {
Ok(mvbox.as_deref() == Some(folder_name))
}
pub(crate) fn derive_blobdir(dbfile: &PathBuf) -> PathBuf {
pub(crate) fn derive_blobdir(dbfile: &Path) -> PathBuf {
let mut blob_fname = OsString::new();
blob_fname.push(dbfile.file_name().unwrap_or_default());
blob_fname.push("-blobs");
dbfile.with_file_name(blob_fname)
}
pub(crate) fn derive_walfile(dbfile: &PathBuf) -> PathBuf {
pub(crate) fn derive_walfile(dbfile: &Path) -> PathBuf {
let mut wal_fname = OsString::new();
wal_fname.push(dbfile.file_name().unwrap_or_default());
wal_fname.push("-wal");
@@ -679,19 +678,19 @@ mod tests {
use strum::IntoEnumIterator;
use tempfile::tempdir;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_wrong_db() -> Result<()> {
let tmp = tempfile::tempdir()?;
let dbfile = tmp.path().join("db.sqlite");
std::fs::write(&dbfile, b"123")?;
let res = Context::new(dbfile.into(), 1, Events::new()).await?;
tokio::fs::write(&dbfile, b"123").await?;
let res = Context::new(&dbfile, 1, Events::new()).await?;
// Broken database is indistinguishable from encrypted one.
assert_eq!(res.is_open().await, false);
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_fresh_msgs() {
let t = TestContext::new().await;
let fresh = t.get_fresh_msgs().await.unwrap();
@@ -718,7 +717,7 @@ mod tests {
dc_receive_imf(t, msg.as_bytes(), false).await.unwrap();
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_fresh_msgs_and_muted_chats() {
// receive various mails in 3 chats
let t = TestContext::new_alice().await;
@@ -768,7 +767,7 @@ mod tests {
assert_eq!(t.get_fresh_msgs().await.unwrap().len(), 9); // claire is counted again
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_fresh_msgs_and_muted_until() {
let t = TestContext::new_alice().await;
let bob = t.create_chat_with_contact("", "bob@g.it").await;
@@ -826,61 +825,61 @@ mod tests {
assert_eq!(t.get_fresh_msgs().await.unwrap().len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_blobdir_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
Context::new(dbfile.into(), 1, Events::new()).await.unwrap();
Context::new(&dbfile, 1, Events::new()).await.unwrap();
let blobdir = tmp.path().join("db.sqlite-blobs");
assert!(blobdir.is_dir());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_wrong_blogdir() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("db.sqlite-blobs");
std::fs::write(&blobdir, b"123").unwrap();
let res = Context::new(dbfile.into(), 1, Events::new()).await;
tokio::fs::write(&blobdir, b"123").await.unwrap();
let res = Context::new(&dbfile, 1, Events::new()).await;
assert!(res.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sqlite_parent_not_exists() {
let tmp = tempfile::tempdir().unwrap();
let subdir = tmp.path().join("subdir");
let dbfile = subdir.join("db.sqlite");
let dbfile2 = dbfile.clone();
Context::new(dbfile.into(), 1, Events::new()).await.unwrap();
Context::new(&dbfile, 1, Events::new()).await.unwrap();
assert!(subdir.is_dir());
assert!(dbfile2.is_file());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_with_empty_blobdir() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = PathBuf::new();
let res = Context::with_blobdir(dbfile.into(), blobdir, 1, Events::new()).await;
let res = Context::with_blobdir(dbfile, blobdir, 1, Events::new()).await;
assert!(res.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_with_blobdir_not_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("blobs");
let res = Context::with_blobdir(dbfile.into(), blobdir.into(), 1, Events::new()).await;
let res = Context::with_blobdir(dbfile, blobdir, 1, Events::new()).await;
assert!(res.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn no_crashes_on_context_deref() {
let t = TestContext::new().await;
std::mem::drop(t);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_info() {
let t = TestContext::new().await;
@@ -896,7 +895,7 @@ mod tests {
assert_eq!(info.get("level").unwrap(), "awesome");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_info_completeness() {
// For easier debugging,
// get_info() shall return all important information configurable by the Config-values.
@@ -944,7 +943,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_msgs() -> Result<()> {
let alice = TestContext::new_alice().await;
let self_talk = ChatId::create_for_contact(&alice, ContactId::SELF).await?;
@@ -1000,7 +999,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_limit_search_msgs() -> Result<()> {
let alice = TestContext::new_alice().await;
let chat = alice
@@ -1033,13 +1032,13 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_check_passphrase() -> Result<()> {
let dir = tempdir()?;
let dbfile = dir.path().join("db.sqlite");
let id = 1;
let context = Context::new_closed(dbfile.clone().into(), id, Events::new())
let context = Context::new_closed(&dbfile, id, Events::new())
.await
.context("failed to create context")?;
assert_eq!(context.open("foo".to_string()).await?, true);
@@ -1047,7 +1046,7 @@ mod tests {
drop(context);
let id = 2;
let context = Context::new(dbfile.into(), id, Events::new())
let context = Context::new(&dbfile, id, Events::new())
.await
.context("failed to create context")?;
assert_eq!(context.is_open().await, false);
@@ -1058,7 +1057,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ongoing() -> Result<()> {
let context = TestContext::new().await;

View File

@@ -2203,8 +2203,8 @@ async fn add_or_lookup_contact_by_addr(
#[cfg(test)]
mod tests {
use async_std::fs::{self, File};
use async_std::io::WriteExt;
use tokio::fs::{self, File};
use tokio::io::AsyncWriteExt;
use super::*;
@@ -2216,7 +2216,7 @@ mod tests {
use crate::message::Message;
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_grpid_simple() {
let context = TestContext::new().await;
let raw = b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
@@ -2234,7 +2234,7 @@ mod tests {
assert_eq!(extract_grpid(&mimeparser, HeaderDef::References), grpid);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_grpid_from_multiple() {
let context = TestContext::new().await;
let raw = b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
@@ -2283,7 +2283,7 @@ mod tests {
\n\
hello\n";
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_chats_only() {
let t = TestContext::new_alice().await;
assert_eq!(t.get_config_int(Config::ShowEmails).await.unwrap(), 0);
@@ -2306,7 +2306,7 @@ mod tests {
assert_eq!(chats.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_accepted_contact_unknown() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("1")).await.unwrap();
@@ -2317,7 +2317,7 @@ mod tests {
assert_eq!(chats.len(), 0);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_accepted_contact_known() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("1")).await.unwrap();
@@ -2330,7 +2330,7 @@ mod tests {
assert_eq!(chats.len(), 0);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_accepted_contact_accepted() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("1")).await.unwrap();
@@ -2368,7 +2368,7 @@ mod tests {
assert_eq!(chat::get_chat_contacts(&t, chat_id).await.unwrap().len(), 3);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_all() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -2387,7 +2387,7 @@ mod tests {
assert_eq!(chat::get_chat_contacts(&t, chat_id).await.unwrap().len(), 3);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_read_receipt_and_unarchive() -> Result<()> {
// create alice's account
let t = TestContext::new_alice().await;
@@ -2501,7 +2501,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_from() {
// if there is no from given, from_id stays 0 which is just fine. These messages
// are very rare, however, we have to add them to the database
@@ -2533,7 +2533,7 @@ mod tests {
assert!(chats.get_msg_id(0).is_ok());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_escaped_from() {
let t = TestContext::new_alice().await;
let contact_id = Contact::create(&t, "foobar", "foobar@example.com")
@@ -2566,7 +2566,7 @@ mod tests {
assert_eq!(msg.param.get_int(Param::WantsMdn).unwrap(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_escaped_recipients() {
let t = TestContext::new_alice().await;
Contact::create(&t, "foobar", "foobar@example.com")
@@ -2608,7 +2608,7 @@ mod tests {
assert_eq!(msg.param.get_int(Param::WantsMdn).unwrap(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_cc_to_contact() {
let t = TestContext::new_alice().await;
Contact::create(&t, "foobar", "foobar@example.com")
@@ -2643,7 +2643,7 @@ mod tests {
assert_eq!(contact.get_display_name(), "Carl");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_tiscali() {
test_parse_ndn(
"alice@tiscali.it",
@@ -2655,7 +2655,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_testrun() {
test_parse_ndn(
"alice@testrun.org",
@@ -2667,7 +2667,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_yahoo() {
test_parse_ndn(
"alice@yahoo.com",
@@ -2679,7 +2679,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_gmail() {
test_parse_ndn(
"alice@gmail.com",
@@ -2691,7 +2691,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_gmx() {
test_parse_ndn(
"alice@gmx.com",
@@ -2703,7 +2703,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_posteo() {
test_parse_ndn(
"alice@posteo.org",
@@ -2715,7 +2715,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_testrun_2() {
test_parse_ndn(
"alice@example.org",
@@ -2781,7 +2781,7 @@ mod tests {
assert_eq!(msg.error(), error_msg.map(|error| error.to_string()));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_ndn_group_msg() -> Result<()> {
let t = TestContext::new().await;
t.configure_addr("alice@gmail.com").await;
@@ -2841,7 +2841,7 @@ mod tests {
Message::load_from_db(context, msg_id).await.unwrap()
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_html_only_mail() {
let t = TestContext::new_alice().await;
let msg = load_imf_email(&t, include_bytes!("../test-data/message/wrong-html.eml")).await;
@@ -2874,7 +2874,7 @@ mod tests {
\n\
hello back\n";
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_github_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.ctx.set_config(Config::ShowEmails, Some("2")).await?;
@@ -2941,7 +2941,7 @@ mod tests {
\n\
body 4\n";
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_classic_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.ctx
@@ -2987,7 +2987,7 @@ Hello mailinglist!\r\n"
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_other_device_writes_to_mailinglist() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -3037,7 +3037,7 @@ Hello mailinglist!\r\n"
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_block_mailing_list() {
let t = TestContext::new_alice().await;
t.ctx
@@ -3071,7 +3071,7 @@ Hello mailinglist!\r\n"
assert_eq!(msgs.len(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_block_then_unblock() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3104,7 +3104,7 @@ Hello mailinglist!\r\n"
assert_eq!(msgs.len(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_not_now() {
let t = TestContext::new_alice().await;
t.ctx
@@ -3137,7 +3137,7 @@ Hello mailinglist!\r\n"
assert!(chat.is_contact_request());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_accept() {
let t = TestContext::new_alice().await;
t.ctx
@@ -3165,7 +3165,7 @@ Hello mailinglist!\r\n"
assert!(chat.can_send(&t.ctx).await.unwrap());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_majordomo_mailing_list() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3214,7 +3214,7 @@ Hello mailinglist!\r\n"
assert_eq!(chat::get_chat_msgs(&t, chat.id, 0).await.unwrap().len(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailchimp_mailing_list() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3244,7 +3244,7 @@ Hello mailinglist!\r\n"
assert_eq!(chat.name, "Atlas Obscura");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dhl_mailing_list() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3269,7 +3269,7 @@ Hello mailinglist!\r\n"
assert_eq!(chat.name, "DHL Paket");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dpd_mailing_list() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3294,7 +3294,7 @@ Hello mailinglist!\r\n"
assert_eq!(chat.name, "DPD");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_xt_local_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -3324,7 +3324,7 @@ Hello mailinglist!\r\n"
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_xing_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -3345,7 +3345,7 @@ Hello mailinglist!\r\n"
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ttline_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -3366,7 +3366,7 @@ Hello mailinglist!\r\n"
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_with_mimepart_footer() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3397,7 +3397,7 @@ Hello mailinglist!\r\n"
assert_eq!(chat.name, "Intern");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_with_mimepart_footer_signed() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3422,7 +3422,7 @@ Hello mailinglist!\r\n"
/// Test that the changes from apply_mailinglist_changes() are also applied
/// if the message is assigned to the chat by In-Reply-To
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_apply_mailinglist_changes_assigned_by_reply() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3464,7 +3464,7 @@ Hello mailinglist!\r\n"
)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dont_show_tokens_in_contacts_list() {
check_dont_show_in_contacts_list(
"reply+OGHVYCLVBEGATYBICAXBIRQATABUOTUCERABERAHNO@reply.github.com",
@@ -3472,7 +3472,7 @@ Hello mailinglist!\r\n"
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dont_show_noreply_in_contacts_list() {
check_dont_show_in_contacts_list("noreply@github.com").await;
}
@@ -3510,7 +3510,7 @@ YEAAAAAA!.
assert!(contacts.is_empty()); // The contact should not have been added to the db
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pdf_filename_simple() {
let t = TestContext::new_alice().await;
let msg = load_imf_email(
@@ -3523,7 +3523,7 @@ YEAAAAAA!.
assert_eq!(msg.param.get(Param::File).unwrap(), "$BLOBDIR/simple.pdf");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pdf_filename_continuation() {
// test filenames split across multiple header lines, see rfc 2231
let t = TestContext::new_alice().await;
@@ -3550,7 +3550,7 @@ YEAAAAAA!.
/// or mua may use multipart/related not correctly -
/// so this test is in competition with parse_thunderbird_html_embedded_image()
/// that wants the image to be kept in the chat.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_many_images() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -3571,7 +3571,7 @@ YEAAAAAA!.
/// Test that classical MUA messages are assigned to group chats based on the `In-Reply-To`
/// header.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_in_reply_to() {
let t = TestContext::new().await;
t.configure_addr("bob@example.com").await;
@@ -3636,7 +3636,7 @@ YEAAAAAA!.
/// Test that classical MUA messages are assigned to group chats
/// based on the `In-Reply-To` header for two-member groups.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_in_reply_to_two_member_group() {
let t = TestContext::new().await;
t.configure_addr("bob@example.com").await;
@@ -3738,7 +3738,7 @@ YEAAAAAA!.
assert_eq!(msg.get_text().unwrap(), "private reply");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_save_mime_headers_off() -> anyhow::Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -3753,7 +3753,7 @@ YEAAAAAA!.
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_save_mime_headers_on() -> anyhow::Result<()> {
let alice = TestContext::new_alice().await;
alice.set_config_bool(Config::SaveMimeHeaders, true).await?;
@@ -3924,7 +3924,7 @@ YEAAAAAA!.
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_alias_support_answer_from_nondc() {
// Bob, the other supporter, answers with a classic MUA.
let bob_answer = b"To: support@example.org, claire@example.org\n\
@@ -3944,7 +3944,7 @@ YEAAAAAA!.
check_alias_reply(bob_answer, false, false).await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_alias_answer_from_dc() {
// Bob, the other supporter, answers with Delta Chat.
let bob_answer = b"To: support@example.org, claire@example.org\n\
@@ -3968,7 +3968,7 @@ YEAAAAAA!.
check_alias_reply(bob_answer, false, false).await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dont_assign_to_trash_by_parent() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -4016,7 +4016,7 @@ YEAAAAAA!.
assert_eq!(msg.text.unwrap(), "Reply");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dont_show_all_outgoing_msgs_in_self_chat() {
// Regression test for <https://github.com/deltachat/deltachat-android/issues/1940>:
// Some servers add a `Bcc: <Self>` header, which caused all outgoing messages to
@@ -4043,7 +4043,7 @@ Message content",
assert_ne!(msg.chat_id, t.get_self_chat().await.id);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_classic_mail_creates_chat() {
let alice = TestContext::new_alice().await;
@@ -4073,7 +4073,7 @@ Message content",
assert_eq!(msg.get_text().unwrap(), "Subj Message content");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_duplicate_message() -> Result<()> {
// Test that duplicate messages are ignored based on the Message-ID
let alice = TestContext::new_alice().await;
@@ -4132,7 +4132,7 @@ Second signature";
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_private_classical_reply() {
for outgoing_is_classical in &[true, false] {
let t = TestContext::new_alice().await;
@@ -4216,7 +4216,7 @@ Private reply"#,
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_private_chat_reply() {
for (outgoing_is_classical, outgoing_has_multiple_recipients) in
&[(true, true), (false, true), (false, false)]
@@ -4312,7 +4312,7 @@ Sent with my Delta Chat Messenger: https://delta.chat
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_nonprivate_classical_reply() {
for outgoing_is_classical in &[true, false] {
let t = TestContext::new_alice().await;
@@ -4421,7 +4421,7 @@ Reply to all"#,
/// messages have the same recipient lists and only differ in the subject and message contents.
/// The messages can be properly assigned to chats only using the In-Reply-To or References
/// headers.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_adhoc() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_alice().await;
@@ -4501,7 +4501,7 @@ Second thread."#;
}
/// Test that read receipts don't create chats.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_read_receipts_dont_create_chats() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -4534,7 +4534,7 @@ Second thread."#;
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_gmx_forwarded_msg() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -4554,7 +4554,7 @@ Second thread."#;
}
/// Tests that user is notified about new incoming contact requests.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_incoming_contact_request() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -4579,7 +4579,7 @@ Second thread."#;
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_parent_message() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -4642,7 +4642,7 @@ Message with references."#;
}
/// Test a message with RFC 1847 encapsulation as created by Thunderbird.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_rfc1847_encapsulation() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -4668,7 +4668,7 @@ Message with references."#;
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_invalid_to_address() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -4680,7 +4680,7 @@ Message with references."#;
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_reply_from_different_addr() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;
@@ -4745,7 +4745,7 @@ Reply from different address
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_long_filenames() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;
@@ -4800,7 +4800,7 @@ Reply from different address
}
/// Tests that contact request is accepted automatically on outgoing message.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_accept_outgoing() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice1 = tcm.alice().await;
@@ -4845,7 +4845,7 @@ Reply from different address
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_private_reply_multidevice() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice1 = tcm.alice().await;
@@ -4922,7 +4922,7 @@ Reply from different address
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_private_reply_to_blocked_account() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;

View File

@@ -5,20 +5,19 @@ use core::cmp::{max, min};
use std::borrow::Cow;
use std::fmt;
use std::io::Cursor;
use std::path::{Path, PathBuf};
use std::str::from_utf8;
use std::str::FromStr;
use std::time::{Duration, SystemTime};
use async_std::path::{Path, PathBuf};
use async_std::prelude::*;
use async_std::{fs, io};
use anyhow::{bail, Error, Result};
use chrono::{Local, TimeZone};
use futures::StreamExt;
use mailparse::dateparse;
use mailparse::headers::Headers;
use mailparse::MailHeaderMap;
use rand::{thread_rng, Rng};
use tokio::{fs, io};
use crate::chat::{add_device_msg, add_device_msg_with_importance};
use crate::constants::{DC_ELLIPSIS, DC_OUTDATED_WARNING_DAYS};
@@ -278,7 +277,7 @@ pub fn dc_get_filemeta(buf: &[u8]) -> Result<(u32, u32), Error> {
///
/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path.
/// Otherwise, returns path as is.
pub(crate) fn dc_get_abs_path<P: AsRef<Path>>(context: &Context, path: P) -> PathBuf {
pub(crate) fn dc_get_abs_path(context: &Context, path: impl AsRef<Path>) -> PathBuf {
let p: &Path = path.as_ref();
if let Ok(p) = p.strip_prefix("$BLOBDIR") {
context.get_blobdir().join(p)
@@ -297,10 +296,10 @@ pub(crate) async fn dc_get_filebytes(context: &Context, path: impl AsRef<Path>)
pub(crate) async fn dc_delete_file(context: &Context, path: impl AsRef<Path>) -> bool {
let path_abs = dc_get_abs_path(context, &path);
if !path_abs.exists().await {
if !path_abs.exists() {
return false;
}
if !path_abs.is_file().await {
if !path_abs.is_file() {
warn!(
context,
"refusing to delete non-file \"{}\".",
@@ -323,8 +322,9 @@ pub(crate) async fn dc_delete_file(context: &Context, path: impl AsRef<Path>) ->
}
pub async fn dc_delete_files_in_dir(context: &Context, path: impl AsRef<Path>) {
match async_std::fs::read_dir(path).await {
Ok(mut read_dir) => {
match tokio::fs::read_dir(path).await {
Ok(read_dir) => {
let mut read_dir = tokio_stream::wrappers::ReadDirStream::new(read_dir);
while let Some(entry) = read_dir.next().await {
match entry {
Ok(file) => {
@@ -344,7 +344,7 @@ pub(crate) async fn dc_create_folder(
path: impl AsRef<Path>,
) -> Result<(), io::Error> {
let path_abs = dc_get_abs_path(context, &path);
if !path_abs.exists().await {
if !path_abs.exists() {
match fs::create_dir_all(path_abs).await {
Ok(_) => Ok(()),
Err(err) => {
@@ -655,7 +655,7 @@ mod tests {
assert_eq!(hop_info, expected)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_receive_headers_integration() {
let raw = include_bytes!("../test-data/message/mail_with_cc.txt");
let expected = r"State: Fresh
@@ -873,7 +873,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_file_handling() {
let t = TestContext::new().await;
let context = &t;
@@ -889,8 +889,8 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content")
.await
.is_ok());
assert!(dc_file_exist!(context, "$BLOBDIR/foobar").await);
assert!(!dc_file_exist!(context, "$BLOBDIR/foobarx").await);
assert!(dc_file_exist!(context, "$BLOBDIR/foobar"));
assert!(!dc_file_exist!(context, "$BLOBDIR/foobarx"));
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar").await, 7);
let abs_path = context
@@ -899,23 +899,23 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
.to_string_lossy()
.to_string();
assert!(dc_file_exist!(context, &abs_path).await);
assert!(dc_file_exist!(context, &abs_path));
assert!(dc_delete_file(context, "$BLOBDIR/foobar").await);
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder")
.await
.is_ok());
assert!(dc_file_exist!(context, "$BLOBDIR/foobar-folder").await);
assert!(dc_file_exist!(context, "$BLOBDIR/foobar-folder"));
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder").await);
let fn0 = "$BLOBDIR/data.data";
assert!(dc_write_file(context, &fn0, b"content").await.is_ok());
assert!(dc_delete_file(context, &fn0).await);
assert!(!dc_file_exist!(context, &fn0).await);
assert!(!dc_file_exist!(context, &fn0));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_smeared_timestamp() {
let t = TestContext::new().await;
assert_ne!(
@@ -931,7 +931,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_smeared_timestamps() {
let t = TestContext::new().await;
let count = MAX_SECONDS_TO_LEND_FROM_FUTURE - 1;
@@ -1001,7 +1001,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
assert_eq!(improve_single_line_input("\r\nahte\n\r"), "ahte");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_maybe_warn_on_bad_time() {
let t = TestContext::new().await;
let timestamp_now = time();
@@ -1064,7 +1064,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22
assert_eq!(msgs.len(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_maybe_warn_on_outdated() {
let t = TestContext::new().await;
let timestamp_now: i64 = time();

View File

@@ -382,7 +382,7 @@ mod tests {
assert_eq!(txt.trim(), "two\nlines");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quote_div() {
let input = include_str!("../test-data/message/gmx-quote-body.eml");
let dehtml = dehtml(input).unwrap();

View File

@@ -280,7 +280,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_download_limit() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -303,7 +303,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_update_download_state() -> Result<()> {
let t = TestContext::new_alice().await;
let chat = t.create_chat_with_contact("Bob", "bob@example.org").await;
@@ -328,7 +328,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_partial_receive_imf() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -376,7 +376,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_partial_download_and_ephemeral() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = t

View File

@@ -422,7 +422,7 @@ mod tests {
mod ensure_secret_key_exists {
use super::*;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_prexisting() {
let t = TestContext::new_alice().await;
assert_eq!(
@@ -431,7 +431,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_not_configured() {
let t = TestContext::new().await;
assert!(ensure_secret_key_exists(&t).await.is_err());
@@ -480,7 +480,7 @@ Sent with my Delta Chat Messenger: https://delta.chat";
assert_eq!(has_decrypted_pgp_armor(data), false);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_encrypted_no_autocrypt() -> anyhow::Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -588,7 +588,7 @@ Sent with my Delta Chat Messenger: https://delta.chat";
vec![(Some(peerstate), addr)]
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_should_encrypt() {
let t = TestContext::new_alice().await;
let encrypt_helper = EncryptHelper::new(&t).await.unwrap();
@@ -615,7 +615,7 @@ Sent with my Delta Chat Messenger: https://delta.chat";
assert!(!encrypt_helper.should_encrypt(&t, false, &ps).unwrap());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mixed_up_mime() -> Result<()> {
// "Mixed Up" mail as received when sending an encrypted
// message using Delta Chat Desktop via ProtonMail IMAP/SMTP

View File

@@ -62,9 +62,9 @@ use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use anyhow::{ensure, Context as _, Result};
use async_std::channel::Receiver;
use async_std::future::timeout;
use async_channel::Receiver;
use serde::{Deserialize, Serialize};
use tokio::time::timeout;
use crate::chat::{send_msg, ChatId};
use crate::constants::{DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH};
@@ -581,7 +581,7 @@ mod tests {
dc_tools::IsNoneOrEmpty,
};
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_ephemeral_messages() {
let context = TestContext::new().await;
@@ -711,7 +711,7 @@ mod tests {
}
/// Test enabling and disabling ephemeral timer remotely.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ephemeral_enable_disable() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -743,7 +743,7 @@ mod tests {
}
/// Test that timer is enabled even if the message explicitly enabling the timer is lost.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ephemeral_enable_lost() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -785,7 +785,7 @@ mod tests {
/// Test that Alice replying to the chat without a timer at the same time as Bob enables the
/// timer does not result in disabling the timer on the Bob's side.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ephemeral_timer_rollback() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -859,7 +859,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ephemeral_delete_msgs() -> Result<()> {
let t = TestContext::new_alice().await;
let self_chat = t.get_self_chat().await;
@@ -985,7 +985,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete_expired_imap_messages() -> Result<()> {
let t = TestContext::new_alice().await;
const HOUR: i64 = 60 * 60;
@@ -1096,7 +1096,7 @@ mod tests {
}
// Regression test for a bug in the timer rollback protection.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ephemeral_timer_references() -> Result<()> {
let alice = TestContext::new_alice().await;

View File

@@ -1,7 +1,8 @@
//! # Events specification.
use async_std::channel::{self, Receiver, Sender, TrySendError};
use async_std::path::PathBuf;
use std::path::PathBuf;
use async_channel::{self as channel, Receiver, Sender, TrySendError};
use crate::chat::ChatId;
use crate::contact::ContactId;
@@ -61,23 +62,18 @@ impl Events {
///
/// [`Context`]: crate::context::Context
/// [`Context::get_event_emitter`]: crate::context::Context::get_event_emitter
/// [`Stream`]: async_std::stream::Stream
/// [`Stream`]: futures::stream::Stream
#[derive(Debug, Clone)]
pub struct EventEmitter(Receiver<Event>);
impl EventEmitter {
/// Blocking recv of an event. Return `None` if the `Sender` has been droped.
pub fn recv_sync(&self) -> Option<Event> {
async_std::task::block_on(self.recv())
}
/// Async recv of an event. Return `None` if the `Sender` has been droped.
pub async fn recv(&self) -> Option<Event> {
self.0.recv().await.ok()
}
}
impl async_std::stream::Stream for EventEmitter {
impl futures::stream::Stream for EventEmitter {
type Item = Event;
fn poll_next(

View File

@@ -203,7 +203,7 @@ mod tests {
assert_eq!(format_flowed_quote(quote), expected);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_quotes() -> anyhow::Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;

View File

@@ -284,7 +284,7 @@ mod tests {
use crate::message::{MessengerMessage, Viewtype};
use crate::test_utils::TestContext;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_plain_unspecified() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_plain_unspecified.eml");
@@ -300,7 +300,7 @@ This message does not have Content-Type nor Subject.<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_plain_iso88591() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_plain_iso88591.eml");
@@ -316,7 +316,7 @@ message with a non-UTF-8 encoding: äöüßÄÖÜ<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_plain_flowed() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_plain_flowed.eml");
@@ -336,7 +336,7 @@ and will be wrapped as usual.<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_alt_plain() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_plain.eml");
@@ -355,7 +355,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_html.eml");
@@ -373,7 +373,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_alt_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_html.eml");
@@ -388,7 +388,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_alt_plain_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_plain_html.eml");
@@ -405,7 +405,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_htmlparse_apple_cid_jpg() {
// load raw mime html-data with related image-part (cid:)
// and make sure, Content-Id has angle-brackets that are removed correctly.
@@ -424,14 +424,14 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
assert!(!parser.html.contains("cid:"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_html_invalid_msgid() {
let t = TestContext::new().await;
let msg_id = MsgId::new(100);
assert!(msg_id.get_html(&t).await.is_err())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_html_forwarding() {
// alice receives a non-delta html-message
let alice = TestContext::new_alice().await;
@@ -478,7 +478,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
assert!(html.contains("this is <b>html</b>"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_html_forwarding_encrypted() {
// Alice receives a non-delta html-message
// (`ShowEmails=1` lets Alice actually receive non-delta messages for known contacts,
@@ -515,7 +515,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
assert!(html.contains("this is <b>html</b>"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_html() {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -547,7 +547,7 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
assert!(html.contains("<b>html</b> text"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_cp1252_html() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;

View File

@@ -11,11 +11,11 @@ use std::{
};
use anyhow::{bail, format_err, Context as _, Result};
use async_channel::Receiver;
use async_imap::types::{
Fetch, Flag, Mailbox, Name, NameAttribute, Quota, QuotaRoot, UnsolicitedResponse,
};
use async_std::channel::Receiver;
use async_std::prelude::*;
use futures::StreamExt;
use num_traits::FromPrimitive;
use crate::chat::{self, ChatId, ChatIdBlocked};
@@ -1922,7 +1922,7 @@ fn get_folder_meaning_by_name(folder_name: &str) -> FolderMeaning {
fn get_folder_meaning(folder_name: &Name) -> FolderMeaning {
for attr in folder_name.attributes() {
if let NameAttribute::Custom(ref label) = attr {
if let NameAttribute::Extension(ref label) = attr {
match label.as_ref() {
"\\Trash" => return FolderMeaning::Other,
"\\Sent" => return FolderMeaning::Sent,
@@ -2388,7 +2388,7 @@ mod tests {
assert_eq!(get_folder_meaning_by_name("SPAM"), FolderMeaning::Spam);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_uid_next_validity() {
let t = TestContext::new_alice().await;
assert_eq!(get_uid_next(&t.ctx, "Inbox").await.unwrap(), 0);
@@ -2570,7 +2570,7 @@ mod tests {
("Spam", true, true, "DeltaChat"),
];
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_target_folder_incoming_accepted() -> Result<()> {
for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_ACCEPTED_CHAT {
check_target_folder_combination(
@@ -2587,7 +2587,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_target_folder_incoming_request() -> Result<()> {
for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_REQUEST {
check_target_folder_combination(
@@ -2604,7 +2604,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_target_folder_outgoing() -> Result<()> {
// Test outgoing emails
for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_ACCEPTED_CHAT {
@@ -2622,7 +2622,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_target_folder_setupmsg() -> Result<()> {
// Test setupmessages
for (folder, mvbox_move, chat_msg, _expected_destination) in COMBINATIONS_ACCEPTED_CHAT {
@@ -2640,7 +2640,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_imap_search_command() -> Result<()> {
let t = TestContext::new_alice().await;
assert_eq!(

View File

@@ -8,7 +8,7 @@ use anyhow::{Context as _, Result};
use async_imap::Client as ImapClient;
use async_smtp::ServerAddress;
use async_std::net::{self, TcpStream};
use tokio::net::{self, TcpStream};
use super::session::Session;
use crate::login_param::{dc_build_tls, Socks5Config};

View File

@@ -2,7 +2,7 @@ use super::Imap;
use anyhow::{bail, Context as _, Result};
use async_imap::extensions::idle::IdleResponse;
use async_std::prelude::*;
use futures_lite::FutureExt;
use std::time::{Duration, SystemTime};
use crate::{context::Context, scheduler::InterruptInfo};
@@ -87,9 +87,7 @@ impl Imap {
}
}
let session = handle
.done()
.timeout(Duration::from_secs(15))
let session = tokio::time::timeout(Duration::from_secs(15), handle.done())
.await?
.context("IMAP IDLE protocol timed out")?;
self.session = Some(Session { inner: session });
@@ -121,7 +119,7 @@ impl Imap {
// check every minute if there are new messages
// TODO: grow sleep durations / make them more flexible
let mut interval = async_std::stream::interval(Duration::from_secs(60));
let mut interval = tokio::time::interval(Duration::from_secs(60));
enum Event {
Tick,
@@ -131,7 +129,7 @@ impl Imap {
let info = loop {
use futures::future::FutureExt;
match interval
.next()
.tick()
.map(|_| Event::Tick)
.race(
self.idle_interrupt

View File

@@ -1,14 +1,13 @@
use std::{collections::BTreeMap, time::Instant};
use anyhow::{Context as _, Result};
use futures::stream::StreamExt;
use crate::config::Config;
use crate::imap::Imap;
use crate::log::LogExt;
use crate::{context::Context, imap::FolderMeaning};
use async_std::stream::StreamExt;
use super::{get_folder_meaning, get_folder_meaning_by_name};
impl Imap {
@@ -104,7 +103,7 @@ impl Imap {
let list = session
.list(Some(""), Some("*"))
.await?
.filter_map(|f| f.ok_or_log_msg(context, "list_folders() can't get folder"));
.filter_map(|f| async { f.ok_or_log_msg(context, "list_folders() can't get folder") });
Ok(list.collect().await)
}
}

View File

@@ -2,8 +2,8 @@ use std::ops::{Deref, DerefMut};
use async_imap::Session as ImapSession;
use async_native_tls::TlsStream;
use async_std::net::TcpStream;
use fast_socks5::client::Socks5Stream;
use tokio::net::TcpStream;
#[derive(Debug)]
pub(crate) struct Session {
@@ -11,7 +11,7 @@ pub(crate) struct Session {
}
pub(crate) trait SessionStream:
async_std::io::Read + async_std::io::Write + Unpin + Send + Sync + std::fmt::Debug
tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + Sync + std::fmt::Debug
{
}

View File

@@ -2,16 +2,15 @@
use std::any::Any;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use ::pgp::types::KeyTrait;
use anyhow::{bail, ensure, format_err, Context as _, Result};
use async_std::{
fs::{self, File},
path::{Path, PathBuf},
prelude::*,
};
use async_tar::Archive;
use futures::{StreamExt, TryStreamExt};
use futures_lite::FutureExt;
use rand::{thread_rng, Rng};
use tokio::fs::{self, File};
use tokio_tar::Archive;
use crate::blob::BlobObject;
use crate::chat::{self, delete_and_reset_all_device_msgs, ChatId};
@@ -109,24 +108,22 @@ pub async fn imex(
/// Returns the filename of the backup found (otherwise an error)
pub async fn has_backup(_context: &Context, dir_name: &Path) -> Result<String> {
let mut dir_iter = async_std::fs::read_dir(dir_name).await?;
let mut dir_iter = tokio::fs::read_dir(dir_name).await?;
let mut newest_backup_name = "".to_string();
let mut newest_backup_path: Option<PathBuf> = None;
while let Some(dirent) = dir_iter.next().await {
if let Ok(dirent) = dirent {
let path = dirent.path();
let name = dirent.file_name();
let name: String = name.to_string_lossy().into();
if name.starts_with("delta-chat")
&& name.ends_with(".tar")
&& (newest_backup_name.is_empty() || name > newest_backup_name)
{
// We just use string comparison to determine which backup is newer.
// This works fine because the filenames have the form ...delta-chat-backup-2020-07-24-00.tar
newest_backup_path = Some(path);
newest_backup_name = name;
}
while let Ok(Some(dirent)) = dir_iter.next_entry().await {
let path = dirent.path();
let name = dirent.file_name();
let name: String = name.to_string_lossy().into();
if name.starts_with("delta-chat")
&& name.ends_with(".tar")
&& (newest_backup_name.is_empty() || name > newest_backup_name)
{
// We just use string comparison to determine which backup is newer.
// This works fine because the filenames have the form ...delta-chat-backup-2020-07-24-00.tar
newest_backup_path = Some(path);
newest_backup_name = name;
}
}
@@ -177,7 +174,7 @@ async fn do_initiate_key_transfer(context: &Context) -> Result<String> {
let msg_id = chat::send_msg(context, chat_id, &mut msg).await?;
info!(context, "Wait for setup message being sent ...",);
while !context.shall_stop_ongoing().await {
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
if let Ok(msg) = Message::load_from_db(context, msg_id).await {
if msg.is_sent() {
info!(context, "... setup message sent.",);
@@ -446,7 +443,7 @@ async fn import_backup(
context.sql.config_cache.write().await.clear();
let archive = Archive::new(backup_file);
let mut archive = Archive::new(backup_file);
let mut entries = archive.entries()?;
let mut last_progress = 0;
@@ -477,7 +474,7 @@ async fn import_backup(
// async_tar will unpack to blobdir/BLOBS_BACKUP_NAME, so we move the file afterwards.
f.unpack_in(context.get_blobdir()).await?;
let from_path = context.get_blobdir().join(f.path()?);
if from_path.is_file().await {
if from_path.is_file() {
if let Some(name) = from_path.file_name() {
fs::rename(&from_path, context.get_blobdir().join(name)).await?;
} else {
@@ -499,10 +496,7 @@ async fn import_backup(
/// Returns Ok((temp_db_path, temp_path, dest_path)) on success. Unencrypted database can be
/// written to temp_db_path. The backup can then be written to temp_path. If the backup succeeded,
/// it can be renamed to dest_path. This guarantees that the backup is complete.
async fn get_next_backup_path(
folder: &Path,
backup_time: i64,
) -> Result<(PathBuf, PathBuf, PathBuf)> {
fn get_next_backup_path(folder: &Path, backup_time: i64) -> Result<(PathBuf, PathBuf, PathBuf)> {
let folder = PathBuf::from(folder);
let stem = chrono::NaiveDateTime::from_timestamp(backup_time, 0)
// Don't change this file name format, in has_backup() we use string comparison to determine which backup is newer:
@@ -520,7 +514,7 @@ async fn get_next_backup_path(
let mut destfile = folder.clone();
destfile.push(format!("{}-{:02}.tar", stem, i));
if !tempdbfile.exists().await && !tempfile.exists().await && !destfile.exists().await {
if !tempdbfile.exists() && !tempfile.exists() && !destfile.exists() {
return Ok((tempdbfile, tempfile, destfile));
}
}
@@ -530,7 +524,7 @@ async fn get_next_backup_path(
async fn export_backup(context: &Context, dir: &Path, passphrase: String) -> Result<()> {
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
let now = time();
let (temp_db_path, temp_path, dest_path) = get_next_backup_path(dir, now).await?;
let (temp_db_path, temp_path, dest_path) = get_next_backup_path(dir, now)?;
let _d1 = DeleteOnDrop(temp_db_path.clone());
let _d2 = DeleteOnDrop(temp_path.clone());
@@ -584,7 +578,8 @@ impl Drop for DeleteOnDrop {
fn drop(&mut self) {
let file = self.0.clone();
// Not using dc_delete_file() here because it would send a DeletedBlobFile event
async_std::task::block_on(fs::remove_file(file)).ok();
// Hack to avoid panic in nested runtime calls of tokio
std::fs::remove_file(file).ok();
}
}
@@ -595,19 +590,21 @@ async fn export_backup_inner(
) -> Result<()> {
let file = File::create(temp_path).await?;
let mut builder = async_tar::Builder::new(file);
let mut builder = tokio_tar::Builder::new(file);
builder
.append_path_with_name(temp_db_path, DBFILE_BACKUP_NAME)
.await?;
let read_dir: Vec<_> = fs::read_dir(context.get_blobdir()).await?.collect().await;
let read_dir: Vec<_> =
tokio_stream::wrappers::ReadDirStream::new(fs::read_dir(context.get_blobdir()).await?)
.try_collect()
.await?;
let count = read_dir.len();
let mut written_files = 0;
let mut last_progress = 0;
for entry in read_dir.into_iter() {
let entry = entry?;
let name = entry.file_name();
if !entry.file_type().await?.is_file() {
warn!(
@@ -648,9 +645,9 @@ async fn import_self_keys(context: &Context, dir: &Path) -> Result<()> {
let mut imported_cnt = 0;
let dir_name = dir.to_string_lossy();
let mut dir_handle = async_std::fs::read_dir(&dir).await?;
while let Some(entry) = dir_handle.next().await {
let entry_fn = entry?.file_name();
let mut dir_handle = tokio::fs::read_dir(&dir).await?;
while let Ok(Some(entry)) = dir_handle.next_entry().await {
let entry_fn = entry.file_name();
let name_f = entry_fn.to_string_lossy();
let path_plus_name = dir.join(&entry_fn);
match dc_get_filesuffix_lc(&name_f) {
@@ -800,7 +797,7 @@ mod tests {
use ::pgp::armor::BlockType;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_render_setup_file() {
let t = TestContext::new_alice().await;
let msg = render_setup_file(&t, "hello").await.unwrap();
@@ -817,7 +814,7 @@ mod tests {
assert!(msg.contains("-----END PGP MESSAGE-----\n"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_render_setup_file_newline_replace() {
let t = TestContext::new_alice().await;
t.set_stock_translation(StockMessage::AcSetupMsgBody, "hello\r\nthere".to_string())
@@ -828,7 +825,7 @@ mod tests {
assert!(msg.contains("<p>hello<br>there</p>"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_setup_code() {
let t = TestContext::new().await;
let setupcode = create_setup_code(&t);
@@ -843,7 +840,7 @@ mod tests {
assert_eq!(setupcode.chars().nth(39).unwrap(), '-');
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_export_public_key_to_asc_file() {
let context = TestContext::new().await;
let key = alice_keypair().public;
@@ -853,12 +850,12 @@ mod tests {
.is_ok());
let blobdir = context.ctx.get_blobdir().to_str().unwrap();
let filename = format!("{}/public-key-default.asc", blobdir);
let bytes = async_std::fs::read(&filename).await.unwrap();
let bytes = tokio::fs::read(&filename).await.unwrap();
assert_eq!(bytes, key.to_asc(None).into_bytes());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_export_private_key_to_asc_file() {
let context = TestContext::new().await;
let key = alice_keypair().secret;
@@ -868,12 +865,12 @@ mod tests {
.is_ok());
let blobdir = context.ctx.get_blobdir().to_str().unwrap();
let filename = format!("{}/private-key-default.asc", blobdir);
let bytes = async_std::fs::read(&filename).await.unwrap();
let bytes = tokio::fs::read(&filename).await.unwrap();
assert_eq!(bytes, key.to_asc(None).into_bytes());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_export_and_import_key() {
let context = TestContext::new_alice().await;
let blobdir = context.ctx.get_blobdir();
@@ -887,7 +884,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_export_and_import_backup() -> Result<()> {
let backup_dir = tempfile::tempdir().unwrap();
@@ -896,26 +893,21 @@ mod tests {
let context2 = TestContext::new().await;
assert!(!context2.is_configured().await?);
assert!(has_backup(&context2, backup_dir.path().as_ref())
.await
.is_err());
assert!(has_backup(&context2, backup_dir.path()).await.is_err());
// export from context1
assert!(imex(
&context1,
ImexMode::ExportBackup,
backup_dir.path().as_ref(),
None,
)
.await
.is_ok());
assert!(
imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None)
.await
.is_ok()
);
let _event = context1
.evtracker
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
.await;
// import to context2
let backup = has_backup(&context2, backup_dir.path().as_ref()).await?;
let backup = has_backup(&context2, backup_dir.path()).await?;
// Import of unencrypted backup with incorrect "foobar" backup passphrase fails.
assert!(imex(
@@ -961,7 +953,7 @@ mod tests {
const S_EM_SETUPCODE: &str = "1742-0185-6197-1303-7016-8412-3581-4441-0597";
const S_EM_SETUPFILE: &str = include_str!("../test-data/message/stress.txt");
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_split_and_decrypt() {
let buf_1 = S_EM_SETUPFILE.as_bytes().to_vec();
let (typ, headers, base64) = split_armored_data(&buf_1).unwrap();
@@ -984,20 +976,20 @@ mod tests {
assert!(headers.get(HEADER_SETUPCODE).is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_key_transfer() -> Result<()> {
let alice = TestContext::new_alice().await;
let alice_clone = alice.clone();
let key_transfer_task = async_std::task::spawn(async move {
let key_transfer_task = tokio::task::spawn(async move {
let ctx = alice_clone;
initiate_key_transfer(&ctx).await
});
// Wait for the message to be added to the queue.
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let sent = alice.pop_sent_msg().await;
let setup_code = key_transfer_task.await?;
let setup_code = key_transfer_task.await??;
// Alice sets up a second device.
let alice2 = TestContext::new().await;

View File

@@ -448,7 +448,7 @@ mod tests {
.unwrap();
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_next_job_two() -> Result<()> {
// We want to ensure that loading jobs skips over jobs which
// fails to load from the database instead of failing to load
@@ -464,7 +464,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_next_job_one() -> Result<()> {
let t = TestContext::new().await;

View File

@@ -11,6 +11,7 @@ use num_traits::FromPrimitive;
use pgp::composed::Deserializable;
use pgp::ser::Serialize;
use pgp::types::{KeyTrait, SecretKeyTrait};
use tokio::runtime::Handle;
use crate::config::Config;
use crate::constants::KeyGenType;
@@ -219,9 +220,10 @@ async fn generate_keypair(context: &Context) -> Result<KeyPair> {
let keytype = KeyGenType::from_i32(context.get_config_int(Config::KeyGenType).await?)
.unwrap_or_default();
info!(context, "Generating keypair with type {}", keytype);
let keypair =
async_std::task::spawn_blocking(move || crate::pgp::create_keypair(addr, keytype))
.await?;
let keypair = Handle::current()
.spawn_blocking(move || crate::pgp::create_keypair(addr, keytype))
.await??;
store_self_keypair(context, &keypair, KeyPairUse::Default).await?;
info!(
context,
@@ -397,8 +399,8 @@ mod tests {
use super::*;
use crate::test_utils::{alice_keypair, TestContext};
use async_std::sync::Arc;
use once_cell::sync::Lazy;
use std::sync::Arc;
static KEYPAIR: Lazy<KeyPair> = Lazy::new(alice_keypair);
@@ -520,7 +522,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert_eq!(key, key2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_self_existing() {
let alice = alice_keypair();
let t = TestContext::new_alice().await;
@@ -530,7 +532,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert_eq!(alice.secret, seckey);
}
#[async_std::test]
#[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"))
@@ -540,7 +542,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert!(key.is_ok());
}
#[async_std::test]
#[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"))
@@ -550,7 +552,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert!(key.is_ok());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_load_self_generate_concurrent() {
use std::thread;
@@ -560,11 +562,19 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
.unwrap();
let thr0 = {
let ctx = t.clone();
thread::spawn(move || async_std::task::block_on(SignedPublicKey::load_self(&ctx)))
thread::spawn(move || {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(SignedPublicKey::load_self(&ctx))
})
};
let thr1 = {
let ctx = t.clone();
thread::spawn(move || async_std::task::block_on(SignedPublicKey::load_self(&ctx)))
thread::spawn(move || {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(SignedPublicKey::load_self(&ctx))
})
};
let res0 = thr0.join().unwrap();
let res1 = thr1.join().unwrap();
@@ -577,7 +587,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_save_self_key_twice() {
// Saving the same key twice should result in only one row in
// the keypairs table.

View File

@@ -76,7 +76,7 @@ mod tests {
assert_eq!(sec_ring.keys(), [alice.secret]);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_keyring_load_self() {
// new_self() implies load_self()
let t = TestContext::new_alice().await;

View File

@@ -1,5 +1,6 @@
//! # Delta Chat Core Library.
#![recursion_limit = "256"]
#![forbid(unsafe_code)]
#![deny(
unused,

View File

@@ -1,12 +1,12 @@
//! Location handling.
use std::convert::TryFrom;
use std::time::Duration;
use anyhow::{ensure, Context as _, Result};
use async_std::channel::Receiver;
use async_std::future::timeout;
use async_channel::Receiver;
use bitflags::bitflags;
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use std::time::Duration;
use tokio::time::timeout;
use crate::chat::{self, ChatId};
use crate::contact::ContactId;
@@ -731,7 +731,7 @@ mod tests {
use crate::dc_receive_imf::dc_receive_imf;
use crate::test_utils::TestContext;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_kml_parse() {
let context = TestContext::new().await;
@@ -763,7 +763,7 @@ mod tests {
assert_eq!(locations_ref[1].timestamp, 1544739072);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_message_kml() {
let context = TestContext::new().await;
let timestamp = 1598490000;
@@ -791,7 +791,7 @@ mod tests {
}
/// Tests that location.kml is hidden.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn receive_location_kml() -> Result<()> {
let alice = TestContext::new_alice().await;

View File

@@ -1,7 +1,6 @@
//! # Logging.
use crate::context::Context;
use async_std::task::block_on;
#[macro_export]
macro_rules! info {
@@ -49,15 +48,13 @@ impl Context {
/// Set last error string.
/// Implemented as blocking as used from macros in different, not always async blocks.
pub fn set_last_error(&self, error: &str) {
block_on(async move {
let mut last_error = self.last_error.write().await;
*last_error = error.to_string();
});
let mut last_error = self.last_error.write().unwrap();
*last_error = error.to_string();
}
/// Get last error string.
pub async fn get_last_error(&self) -> String {
let last_error = &*self.last_error.read().await;
pub fn get_last_error(&self) -> String {
let last_error = &*self.last_error.read().unwrap();
last_error.clone()
}
}
@@ -159,24 +156,24 @@ mod tests {
use crate::test_utils::TestContext;
use anyhow::Result;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_last_error() -> Result<()> {
let t = TestContext::new().await;
assert_eq!(t.get_last_error().await, "");
assert_eq!(t.get_last_error(), "");
error!(t, "foo-error");
assert_eq!(t.get_last_error().await, "foo-error");
assert_eq!(t.get_last_error(), "foo-error");
warn!(t, "foo-warning");
assert_eq!(t.get_last_error().await, "foo-error");
assert_eq!(t.get_last_error(), "foo-error");
info!(t, "foo-info");
assert_eq!(t.get_last_error().await, "foo-error");
assert_eq!(t.get_last_error(), "foo-error");
error!(t, "bar-error");
error!(t, "baz-error");
assert_eq!(t.get_last_error().await, "baz-error");
assert_eq!(t.get_last_error(), "baz-error");
Ok(())
}

View File

@@ -4,18 +4,16 @@ use std::borrow::Cow;
use std::fmt;
use std::time::Duration;
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2};
use crate::provider::{get_provider_by_id, Provider};
use crate::{context::Context, provider::Socket};
use anyhow::{ensure, Result};
use async_std::io;
use async_std::net::TcpStream;
use async_native_tls::Certificate;
pub use async_smtp::ServerAddress;
use fast_socks5::client::Socks5Stream;
use once_cell::sync::Lazy;
use tokio::{io, net::TcpStream};
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2};
use crate::provider::{get_provider_by_id, Provider};
use crate::{context::Context, provider::Socket};
#[derive(Copy, Clone, Debug, Display, FromPrimitive, PartialEq, Eq)]
#[repr(u32)]
@@ -424,7 +422,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_save_load_login_param() -> Result<()> {
let t = TestContext::new().await;
@@ -460,7 +458,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_build_tls() -> Result<()> {
// we are using some additional root certificates.
// make sure, they do not break construction of TlsConnector

View File

@@ -1,9 +1,9 @@
//! # Messages and their identifiers.
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use anyhow::{ensure, format_err, Context as _, Result};
use async_std::path::{Path, PathBuf};
use deltachat_derive::{FromSql, ToSql};
use rusqlite::types::ValueRef;
use serde::{Deserialize, Serialize};
@@ -1857,7 +1857,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_prepare_message_and_send() {
use crate::config::Config;
@@ -1879,7 +1879,7 @@ mod tests {
}
/// Tests that message cannot be prepared if account has no configured address.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_prepare_not_configured() {
let d = test::TestContext::new().await;
let ctx = &d.ctx;
@@ -1891,7 +1891,7 @@ mod tests {
assert!(chat::prepare_msg(ctx, chat.id, &mut msg).await.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_webrtc_instance() {
let (webrtc_type, url) = Message::parse_webrtc_instance("basicwebrtc:https://foo/bar");
assert_eq!(webrtc_type, VideochatType::BasicWebrtc);
@@ -1910,7 +1910,7 @@ mod tests {
assert_eq!(url, "https://j.si/foo");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_webrtc_instance() {
// webrtc_instance may come from an input field of the ui, be pretty tolerant on input
let instance = Message::create_webrtc_instance("https://meet.jit.si/", "123");
@@ -1947,7 +1947,7 @@ mod tests {
assert_eq!(instance, "basicwebrtc:https://basic.stuff/12345ab");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_webrtc_instance_noroom() {
// webrtc_instance may come from an input field of the ui, be pretty tolerant on input
let instance = Message::create_webrtc_instance("bla.foo$NOROOM", "123");
@@ -1967,7 +1967,7 @@ mod tests {
assert_eq!(instance, "https://bla.foo/?$NOROOM=123");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_width_height() {
let t = test::TestContext::new().await;
@@ -1997,7 +1997,7 @@ mod tests {
assert!(has_image);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quote() {
use crate::config::Config;
@@ -2033,7 +2033,7 @@ mod tests {
assert!(quoted_msg.get_text() == msg2.quoted_text());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_chat_id() {
// Alice receives a message that pops up as a contact request
let alice = TestContext::new_alice().await;
@@ -2057,7 +2057,7 @@ mod tests {
assert_eq!(msg.get_text().unwrap(), "hello".to_string());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_override_sender_name() {
// send message with overridden sender name
let alice = TestContext::new_alice().await;
@@ -2105,7 +2105,7 @@ mod tests {
assert_ne!(chat.typ, Chattype::Mailinglist);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_markseen_msgs() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -2178,7 +2178,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_state() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -2234,7 +2234,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_bot() -> Result<()> {
let alice = TestContext::new_alice().await;

View File

@@ -3,9 +3,9 @@
use std::convert::TryInto;
use anyhow::{bail, ensure, Context as _, Result};
use async_std::fs;
use chrono::TimeZone;
use lettre_email::{mime, Address, Header, MimeMultipartType, PartBuilder};
use tokio::fs;
use crate::blob::BlobObject;
use crate::chat::Chat;
@@ -1451,9 +1451,9 @@ fn maybe_encode_words(words: &str) -> String {
#[cfg(test)]
mod tests {
use async_std::fs::File;
use async_std::prelude::*;
use mailparse::{addrparse_header, MailHeaderMap};
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use crate::chat::ChatId;
use crate::chat::{
@@ -1556,7 +1556,7 @@ mod tests {
assert_eq!(maybe_encode_words("äöü"), "=?utf-8?b?w6TDtsO8?=");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_from_mua() {
// 1.: Receive a mail from an MUA
assert_eq!(
@@ -1590,7 +1590,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_from_dc() {
// 2. Receive a message from Delta Chat
assert_eq!(
@@ -1610,7 +1610,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_outgoing() {
// 3. Send the first message to a new contact
let t = TestContext::new_alice().await;
@@ -1624,7 +1624,7 @@ mod tests {
assert_eq!(first_subject_str(t).await, "Message from Alice");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_unicode() {
// 4. Receive messages with unicode characters and make sure that we do not panic (we do not care about the result)
msg_to_subject_str(
@@ -1656,7 +1656,7 @@ mod tests {
.await;
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_mdn() {
// 5. Receive an mdn (read receipt) and make sure the mdn's subject is not used
let t = TestContext::new_alice().await;
@@ -1706,7 +1706,7 @@ mod tests {
assert_eq!("Re: Hello, Bob", mf.subject_str(&t).await.unwrap());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_subject_in_group() -> Result<()> {
async fn send_msg_get_subject(
t: &TestContext,
@@ -1914,7 +1914,7 @@ mod tests {
new_msg
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
// This test could still be extended
async fn test_render_reply() {
let t = TestContext::new_alice().await;
@@ -2008,7 +2008,7 @@ mod tests {
assert!(!headers.lines().any(|l| l.trim().is_empty()));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_selfavatar_unencrypted() -> anyhow::Result<()> {
// create chat with bob, set selfavatar
let t = TestContext::new_alice().await;
@@ -2065,7 +2065,7 @@ mod tests {
}
/// Test that removed member address does not go into the `To:` field.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_remove_member_bcc() -> Result<()> {
// Alice creates a group with Bob and Claire and then removes Bob.
let alice = TestContext::new_alice().await;
@@ -2096,7 +2096,7 @@ mod tests {
}
/// Tests that standard IMF header "From:" comes before non-standard "Autocrypt:" header.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_from_before_autocrypt() -> Result<()> {
// create chat with bob
let t = TestContext::new_alice().await;

View File

@@ -2,7 +2,6 @@
use std::collections::{HashMap, HashSet};
use std::future::Future;
use std::io::Cursor;
use std::pin::Pin;
use anyhow::{bail, Context as _, Result};
@@ -1029,9 +1028,8 @@ impl MimeMessage {
if decoded_data.is_empty() {
return;
}
let reader = Cursor::new(decoded_data);
let msg_type = if context
.is_webxdc_file(filename, reader)
.is_webxdc_file(filename, decoded_data)
.await
.unwrap_or(false)
{
@@ -1750,7 +1748,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mimeparser_fromheader() {
let ctx = TestContext::new_alice().await;
@@ -1808,7 +1806,7 @@ mod tests {
assert_eq!(contact.display_name, Some("Götz C".to_string()));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dc_mimeparser_crash() {
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/issue_523.txt");
@@ -1820,7 +1818,7 @@ mod tests {
assert_eq!(mimeparser.parts.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_rfc724_mid_exists() {
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/mail_with_message_id.txt");
@@ -1834,7 +1832,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_rfc724_mid_not_exists() {
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/issue_523.txt");
@@ -1876,7 +1874,7 @@ mod tests {
mail
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1887,7 +1885,7 @@ mod tests {
assert_eq!(filename, Some("test.html".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_encoded_words() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1898,7 +1896,7 @@ mod tests {
assert_eq!(filename, Some("Maßnahmen Okt. 2020.html".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_encoded_words_binary() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1909,7 +1907,7 @@ mod tests {
assert_eq!(filename, Some(" § 165 Abs".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_encoded_words_windows1251() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1920,7 +1918,7 @@ mod tests {
assert_eq!(filename, Some("file Что нового 2020.pdf".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_encoded_words_cont() {
// test continued encoded-words and also test apostropes work that way
let t = TestContext::new().await;
@@ -1932,7 +1930,7 @@ mod tests {
assert_eq!(filename, Some("Maßn'ah'men Okt. 2020.html".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_encoded_words_bad_delimiter() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1944,7 +1942,7 @@ mod tests {
assert_eq!(filename, Some("=?utf-8?q?foo?=.bar".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_apostrophed() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1955,7 +1953,7 @@ mod tests {
assert_eq!(filename, Some("Maßnahmen Okt. 2021.html".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_apostrophed_cont() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1966,7 +1964,7 @@ mod tests {
assert_eq!(filename, Some("Maßnahmen März 2022.html".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_apostrophed_windows1251() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1977,7 +1975,7 @@ mod tests {
assert_eq!(filename, Some("программирование.HTM".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_apostrophed_cp1252() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1988,7 +1986,7 @@ mod tests {
assert_eq!(filename, Some("Auftragsbestätigung.pdf".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_apostrophed_invalid() {
let t = TestContext::new().await;
let mail = load_mail_with_attachment(
@@ -1999,7 +1997,7 @@ mod tests {
assert_eq!(filename, Some("somedäüta.html.zip".to_string()))
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_attachment_filename_combined() {
// test that if `filename` and `filename*0` are given, the filename is not doubled
let t = TestContext::new().await;
@@ -2024,7 +2022,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_first_addr() {
let context = TestContext::new().await;
let raw = b"From: hello@one.org, world@two.org\n\
@@ -2045,7 +2043,7 @@ mod tests {
assert!(mimeparser.chat_disposition_notification_to.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_parent_timestamp() {
let context = TestContext::new().await;
let raw = b"From: foo@example.org\n\
@@ -2078,7 +2076,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mimeparser_with_context() {
let context = TestContext::new().await;
let raw = b"From: hello\n\
@@ -2130,7 +2128,7 @@ mod tests {
.is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mimeparser_with_avatars() {
let t = TestContext::new().await;
@@ -2171,7 +2169,7 @@ mod tests {
assert!(mimeparser.group_avatar.unwrap().is_change());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mimeparser_with_videochat() {
let t = TestContext::new().await;
@@ -2193,7 +2191,7 @@ mod tests {
assert_eq!(mimeparser.group_avatar, None);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mimeparser_message_kml() {
let context = TestContext::new().await;
let raw = b"Chat-Version: 1.0\n\
@@ -2238,7 +2236,7 @@ Content-Disposition: attachment; filename=\"message.kml\"\n\
assert_eq!(mimeparser.parts.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_mdn() {
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
@@ -2288,7 +2286,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
///
/// RFC 6522 specifically allows MDNs to be nested inside
/// multipart MIME messages.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_multiple_mdns() {
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
@@ -2364,7 +2362,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
assert_eq!(message.mdn_reports.len(), 2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_mdn_with_additional_message_ids() {
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
@@ -2419,7 +2417,7 @@ Additional-Message-IDs: <foo@example.com> <foo@example.net>\n\
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_inline_attachment() {
let context = TestContext::new().await;
let raw = br#"Date: Thu, 13 Feb 2020 22:41:20 +0000 (UTC)
@@ -2459,7 +2457,7 @@ MDYyMDYxNTE1RTlDOEE4Cj4+CnN0YXJ0eHJlZgo4Mjc4CiUlRU9GCg==
assert_eq!(message.parts[0].msg, "Mail with inline attachment Hello!");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_hide_html_without_content() {
let t = TestContext::new().await;
let raw = br#"Date: Thu, 13 Feb 2020 22:41:20 +0000 (UTC)
@@ -2503,12 +2501,12 @@ MDYyMDYxNTE1RTlDOEE4Cj4+CnN0YXJ0eHJlZgo4Mjc4CiUlRU9GCg==
.await
.unwrap()
.unwrap();
let f = async_std::fs::File::open(blob.to_abs_path()).await.unwrap();
let f = tokio::fs::File::open(blob.to_abs_path()).await.unwrap();
let size = f.metadata().await.unwrap().len();
assert_eq!(size, 154);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_inline_image() {
let context = TestContext::new().await;
let raw = br#"Message-ID: <foobar@example.org>
@@ -2554,7 +2552,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I=
assert_eq!(message.parts[0].msg, "example Test");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_thunderbird_html_embedded_image() {
let context = TestContext::new().await;
let raw = br#"To: Alice <alice@example.org>
@@ -2627,7 +2625,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I=
}
// Outlook specifies filename in the "name" attribute of Content-Type
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_outlook_html_embedded_image() {
let context = TestContext::new().await;
let raw = br##"From: Anonymous <anonymous@example.org>
@@ -2766,7 +2764,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I=
assert!(test.is_empty());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_format_flowed_quote() {
let context = TestContext::new().await;
let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
@@ -2802,7 +2800,7 @@ Reply
assert_eq!(message.parts[0].msg, "Reply");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_quote_without_reply() {
let context = TestContext::new().await;
let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
@@ -2834,7 +2832,7 @@ From: alice <alice@example.org>
assert_eq!(message.parts[0].msg, "");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn parse_quote_top_posting() {
let context = TestContext::new().await;
let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
@@ -2865,7 +2863,7 @@ On 2020-10-25, Bob wrote:
assert_eq!(message.parts[0].msg, "A reply.");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_attachment_quote() {
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/quote_attach.eml");
@@ -2883,7 +2881,7 @@ On 2020-10-25, Bob wrote:
assert_eq!(mimeparser.parts[0].typ, Viewtype::File);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quote_div() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/gmx-quote.eml");
@@ -2892,7 +2890,7 @@ On 2020-10-25, Bob wrote:
assert_eq!(mimeparser.parts[0].param.get(Param::Quote).unwrap(), "Now?");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_allinkl_blockquote() {
// all-inkl.com puts quotes into `<blockquote> </blockquote>`.
let t = TestContext::new().await;
@@ -2905,7 +2903,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_subj_to_multimedia_msg() {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
@@ -2938,7 +2936,7 @@ On 2020-10-25, Bob wrote:
assert_eq!(msg.get_filemime().unwrap(), "image/png");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_plain() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_plain_unspecified.eml");
@@ -2950,7 +2948,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_alt_plain_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_plain_html.eml");
@@ -2962,7 +2960,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_alt_plain() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_plain.eml");
@@ -2977,7 +2975,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_alt_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_alt_html.eml");
@@ -2989,7 +2987,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_html() {
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/text_html.eml");
@@ -3001,7 +2999,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mime_modified_large_plain() {
let t = TestContext::new().await;
@@ -3022,7 +3020,7 @@ On 2020-10-25, Bob wrote:
assert!(mimemsg.parts[0].msg.len() <= DC_DESIRED_TEXT_LEN + DC_ELLIPSIS.len());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_x_microsoft_original_message_id() {
let t = TestContext::new().await;
let message = MimeMessage::from_bytes(&t, b"Date: Wed, 17 Feb 2021 15:45:15 +0000\n\
@@ -3045,7 +3043,7 @@ On 2020-10-25, Bob wrote:
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_long_in_reply_to() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -3088,7 +3086,7 @@ Some reply
}
// Test that WantsMdn parameter is not set on outgoing messages.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_wants_mdn() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -3119,7 +3117,7 @@ Message.
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ignore_read_receipt_to_self() -> Result<()> {
let alice = TestContext::new_alice().await;
@@ -3189,7 +3187,7 @@ Message.
///
/// It does not have required Original-Message-ID field, so it is useless, but we want to
/// recognize it as MDN nevertheless to avoid displaying it in the chat as normal message.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ms_exchange_mdn() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ShowEmails, Some("2")).await?;

View File

@@ -156,21 +156,21 @@ pub async fn dc_get_oauth2_access_token(
}
// ... and POST
let mut req = surf::post(post_url).build();
if let Err(err) = req.body_form(&post_param) {
warn!(context, "Error calling OAuth2 at {}: {:?}", token_url, err);
return Ok(None);
}
let client = reqwest::Client::new();
let client = surf::Client::new();
let parsed: Result<Response, _> = client.recv_json(req).await;
let response = match parsed {
Ok(response) => response,
let response: Response = match client.post(post_url).form(&post_param).send().await {
Ok(resp) => match resp.json().await {
Ok(response) => response,
Err(err) => {
warn!(
context,
"Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err
);
return Ok(None);
}
},
Err(err) => {
warn!(
context,
"Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err
);
warn!(context, "Error calling OAuth2 at {}: {:?}", token_url, err);
return Ok(None);
}
};
@@ -288,8 +288,14 @@ impl Oauth2 {
// "verified_email": true,
// "picture": "https://lh4.googleusercontent.com/-Gj5jh_9R0BY/AAAAAAAAAAI/AAAAAAAAAAA/IAjtjfjtjNA/photo.jpg"
// }
let response: Result<HashMap<String, serde_json::Value>, surf::Error> =
surf::get(userinfo_url).recv_json().await;
let response = match reqwest::get(userinfo_url).await {
Ok(response) => response,
Err(err) => {
warn!(context, "failed to get userinfo: {}", err);
return None;
}
};
let response: Result<HashMap<String, serde_json::Value>, _> = response.json().await;
let parsed = match response {
Ok(parsed) => parsed,
Err(err) => {
@@ -360,7 +366,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_oauth_from_address() {
let t = TestContext::new().await;
assert_eq!(
@@ -382,7 +388,7 @@ mod tests {
assert_eq!(Oauth2::from_address(&t, "hello@web.de", false).await, None);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_oauth_from_mx() {
// youtube staff seems to use "google workspace with oauth2", figures this out by MX lookup
let t = TestContext::new().await;
@@ -397,7 +403,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dc_get_oauth2_addr() {
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";
@@ -407,7 +413,7 @@ mod tests {
assert_eq!(res, None);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dc_get_oauth2_url() {
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";
@@ -419,7 +425,7 @@ mod tests {
assert_eq!(res, Some("https://accounts.google.com/o/oauth2/auth?client_id=959970109878%2D4mvtgf6feshskf7695nfln6002mom908%2Eapps%2Egoogleusercontent%2Ecom&redirect_uri=chat%2Edelta%3A%2Fcom%2Eb44t%2Emessenger&response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&access_type=offline".into()));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dc_get_oauth2_token() {
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";

View File

@@ -1,9 +1,9 @@
use std::collections::BTreeMap;
use std::fmt;
use std::path::PathBuf;
use std::str;
use anyhow::{bail, Error, Result};
use async_std::path::PathBuf;
use num_traits::FromPrimitive;
use serde::{Deserialize, Serialize};
@@ -434,12 +434,13 @@ impl<'a> ParamsFile<'a> {
mod tests {
use super::*;
use std::path::Path;
use std::str::FromStr;
use anyhow::Result;
use async_std::fs;
use async_std::path::Path;
use tokio::fs;
use crate::test_utils::TestContext;
use std::str::FromStr;
#[test]
fn test_dc_param() {
@@ -485,7 +486,7 @@ mod tests {
assert_eq!(params.to_string().parse::<Params>().unwrap(), params);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_file_fs_path() {
let t = TestContext::new().await;
if let ParamsFile::FsPath(p) = ParamsFile::from_param(&t, "/foo/bar/baz").unwrap() {
@@ -495,7 +496,7 @@ mod tests {
}
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_file_blob() {
let t = TestContext::new().await;
if let ParamsFile::Blob(b) = ParamsFile::from_param(&t, "$BLOBDIR/foo").unwrap() {
@@ -506,7 +507,7 @@ mod tests {
}
// Tests for Params::get_file(), Params::get_path() and Params::get_blob().
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_get_fileparam() {
let t = TestContext::new().await;
let fname = t.dir.path().join("foo");
@@ -514,10 +515,9 @@ mod tests {
p.set(Param::File, fname.to_str().unwrap());
let file = p.get_file(Param::File, &t).unwrap().unwrap();
assert_eq!(file, ParamsFile::FsPath(fname.clone().into()));
assert_eq!(file, ParamsFile::FsPath(fname.clone()));
let path: PathBuf = p.get_path(Param::File, &t).unwrap().unwrap();
let fname: PathBuf = fname.into();
assert_eq!(path, fname);
// Blob does not exist yet, expect error.
@@ -539,7 +539,7 @@ mod tests {
assert!(p.get_blob(Param::File, &t, false).await.unwrap().is_none());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_unknown_key() -> Result<()> {
// 'Z' is used as a key that is known to be unused; these keys should be ignored silently by definition.
let p = Params::from_str("w=12\nZ=13\nh=14")?;

View File

@@ -552,7 +552,7 @@ mod tests {
use super::*;
use crate::test_utils::alice_keypair;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_peerstate_save_to_db() {
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
@@ -596,7 +596,7 @@ mod tests {
assert_eq!(peerstate, peerstate_new2);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_peerstate_double_create() {
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
@@ -628,7 +628,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_peerstate_with_empty_gossip_key_save_to_db() {
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
@@ -665,7 +665,7 @@ mod tests {
assert_eq!(Some(peerstate), peerstate_new);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_peerstate_load_db_defaults() {
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
@@ -694,7 +694,7 @@ mod tests {
assert_eq!(peerstate.verified_key_fingerprint, None);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_peerstate_degrade_reordering() {
let addr = "example@example.org";
let pub_key = alice_keypair().public;

View File

@@ -15,6 +15,7 @@ use pgp::types::{
CompressionAlgorithm, KeyTrait, Mpi, PublicKeyTrait, SecretKeyTrait, StringToKey,
};
use rand::{thread_rng, CryptoRng, Rng};
use tokio::runtime::Handle;
use crate::constants::KeyGenType;
use crate::dc_tools::EmailAddress;
@@ -224,32 +225,33 @@ pub async fn pk_encrypt(
) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
async_std::task::spawn_blocking(move || {
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
.keys()
.iter()
.filter_map(select_pk_for_encryption)
.collect();
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
Handle::current()
.spawn_blocking(move || {
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
.keys()
.iter()
.filter_map(select_pk_for_encryption)
.collect();
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
let mut rng = thread_rng();
let mut rng = thread_rng();
// TODO: measure time
let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
lit_msg
.sign(skey, || "".into(), Default::default())
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
.and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs))
} else {
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)
};
// TODO: measure time
let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
lit_msg
.sign(skey, || "".into(), Default::default())
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
.and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs))
} else {
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)
};
let msg = encrypted_msg?;
let encoded_msg = msg.to_armored_string(None)?;
let msg = encrypted_msg?;
let encoded_msg = msg.to_armored_string(None)?;
Ok(encoded_msg)
})
.await
Ok(encoded_msg)
})
.await?
}
/// Decrypts the message with keys from the private key keyring.
@@ -268,7 +270,7 @@ pub async fn pk_decrypt(
) -> Result<(Vec<u8>, HashSet<Fingerprint>)> {
let mut ret_signature_fingerprints: HashSet<Fingerprint> = Default::default();
let msgs = async_std::task::spawn_blocking(move || {
let msgs = tokio::task::spawn_blocking(move || {
let cursor = Cursor::new(ctext);
let (msg, _) = Message::from_armor_single(cursor)?;
@@ -277,7 +279,7 @@ pub async fn pk_decrypt(
let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?;
decryptor.collect::<pgp::errors::Result<Vec<_>>>()
})
.await?;
.await??;
if let Some(msg) = msgs.into_iter().next() {
// get_content() will decompress the message if needed,
@@ -342,7 +344,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
let passphrase = passphrase.to_string();
async_std::task::spawn_blocking(move || {
tokio::task::spawn_blocking(move || {
let mut rng = thread_rng();
let s2k = StringToKey::new_default(&mut rng);
let msg =
@@ -352,7 +354,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
Ok(encoded_msg)
})
.await
.await?
}
/// Symmetric decryption.
@@ -363,7 +365,7 @@ pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
let (enc_msg, _) = Message::from_armor_single(ctext)?;
let passphrase = passphrase.to_string();
async_std::task::spawn_blocking(move || {
tokio::task::spawn_blocking(move || {
let decryptor = enc_msg.decrypt_with_password(|| passphrase)?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
@@ -376,7 +378,7 @@ pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
bail!("No valid messages found")
}
})
.await
.await?
}
#[cfg(test)]
@@ -487,7 +489,7 @@ mod tests {
assert!(CTEXT_UNSIGNED.starts_with("-----BEGIN PGP MESSAGE-----"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_singed() {
// Check decrypting as Alice
let mut decrypt_keyring: Keyring<SignedSecretKey> = Keyring::new();
@@ -520,7 +522,7 @@ mod tests {
assert_eq!(valid_signatures.len(), 1);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_no_sig_check() {
let mut keyring = Keyring::new();
keyring.add(KEYS.alice_secret.clone());
@@ -533,7 +535,7 @@ mod tests {
assert_eq!(valid_signatures.len(), 0);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_signed_no_key() {
// The validation does not have the public key of the signer.
let mut decrypt_keyring = Keyring::new();
@@ -551,7 +553,7 @@ mod tests {
assert_eq!(valid_signatures.len(), 0);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_unsigned() {
let mut decrypt_keyring = Keyring::new();
decrypt_keyring.add(KEYS.bob_secret.clone());

View File

@@ -99,7 +99,7 @@ impl PlainText {
mod tests {
use super::*;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html() {
let html = PlainText {
text: r##"line 1
@@ -127,7 +127,7 @@ line with <a href="https://link-mid-of-line.org">https://link-mid-of-line.org</a
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_encapsulated() {
let html = PlainText {
text: r#"line with <http://encapsulated.link/?foo=_bar> here!"#.to_string(),
@@ -146,7 +146,7 @@ line with &lt;<a href="http://encapsulated.link/?foo=_bar">http://encapsulated.l
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_nolink() {
let html = PlainText {
text: r#"line with nohttp://no.link here"#.to_string(),
@@ -165,7 +165,7 @@ line with nohttp://no.link here<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_mailto() {
let html = PlainText {
text: r#"just an address: foo@bar.org another@one.de"#.to_string(),
@@ -184,7 +184,7 @@ just an address: <a href="mailto:foo@bar.org">foo@bar.org</a> <a href="mailto:an
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_flowed() {
let html = PlainText {
text: "line \nstill line\n>quote \n>still quote\n >no quote".to_string(),
@@ -206,7 +206,7 @@ line still line<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_flowed_delsp() {
let html = PlainText {
text: "line \nstill line\n>quote \n>still quote\n >no quote".to_string(),
@@ -228,7 +228,7 @@ linestill line<br/>
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_plain_to_html_fixed() {
let html = PlainText {
text: "line \nstill line\n>quote \n>still quote\n >no quote".to_string(),

View File

@@ -6,8 +6,8 @@ use crate::config::Config;
use crate::context::Context;
use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS, PROVIDER_UPDATED};
use anyhow::Result;
use async_std_resolver::{config, resolver, resolver_from_system_conf, AsyncStdResolver};
use chrono::{NaiveDateTime, NaiveTime};
use trust_dns_resolver::{config, AsyncResolver, TokioAsyncResolver};
#[derive(Debug, Display, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
#[repr(u8)]
@@ -85,18 +85,17 @@ pub struct Provider {
/// Get resolver to query MX records.
///
/// We first try resolver_from_system_conf() which reads the system's resolver from `/etc/resolv.conf`.
/// This does not work at least on some Androids, therefore we use use ResolverConfig::default()
/// which default eg. to google's 8.8.8.8 or 8.8.4.4 as a fallback.
async fn get_resolver() -> Result<AsyncStdResolver> {
if let Ok(resolver) = resolver_from_system_conf().await {
/// We first try to read the system's resolver from `/etc/resolv.conf`.
/// This does not work at least on some Androids, therefore we fallback
/// to the default `ResolverConfig` which uses eg. to google's `8.8.8.8` or `8.8.4.4`.
fn get_resolver() -> Result<TokioAsyncResolver> {
if let Ok(resolver) = AsyncResolver::tokio_from_system_conf() {
return Ok(resolver);
}
let resolver = resolver(
let resolver = AsyncResolver::tokio(
config::ResolverConfig::default(),
config::ResolverOpts::default(),
)
.await?;
)?;
Ok(resolver)
}
@@ -141,7 +140,7 @@ pub fn get_provider_by_domain(domain: &str) -> Option<&'static Provider> {
///
/// For security reasons, only Gmail can be configured this way.
pub async fn get_provider_by_mx(context: &Context, domain: &str) -> Option<&'static Provider> {
if let Ok(resolver) = get_resolver().await {
if let Ok(resolver) = get_resolver() {
let mut fqdn: String = domain.to_string();
if !fqdn.ends_with('.') {
fqdn.push('.');
@@ -242,7 +241,7 @@ mod tests {
assert!(provider.id == "gmail");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_provider_info() {
let t = TestContext::new().await;
assert!(get_provider_info(&t, "", false).await.is_none());
@@ -270,9 +269,9 @@ mod tests {
assert!(get_provider_update_timestamp() > timestamp_past);
}
#[async_std::test]
async fn test_get_resolver() -> Result<()> {
assert!(get_resolver().await.is_ok());
#[test]
fn test_get_resolver() -> Result<()> {
assert!(get_resolver().is_ok());
Ok(())
}
}

View File

@@ -1,6 +1,6 @@
//! # QR code module.
use anyhow::{bail, ensure, format_err, Context as _, Error, Result};
use anyhow::{bail, ensure, Context as _, Error, Result};
use once_cell::sync::Lazy;
use percent_encoding::percent_decode_str;
use serde::Deserialize;
@@ -355,13 +355,13 @@ struct CreateAccountResponse {
async fn set_account_from_qr(context: &Context, qr: &str) -> Result<()> {
let url_str = &qr[DCACCOUNT_SCHEME.len()..];
let parsed: CreateAccountResponse = surf::post(url_str).recv_json().await.map_err(|err| {
format_err!(
"Cannot create account, request to {:?} failed: {}",
url_str,
err
)
})?;
let parsed: CreateAccountResponse = reqwest::Client::new()
.post(url_str)
.send()
.await?
.json()
.await
.with_context(|| format!("Cannot create account, request to {:?} failed", url_str))?;
context
.set_config(Config::Addr, Some(&parsed.email))
@@ -565,7 +565,7 @@ mod tests {
use crate::test_utils::{alice_keypair, TestContext};
use anyhow::Result;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_http() -> Result<()> {
let ctx = TestContext::new().await;
@@ -580,7 +580,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_https() -> Result<()> {
let ctx = TestContext::new().await;
@@ -595,7 +595,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_text() -> Result<()> {
let ctx = TestContext::new().await;
@@ -610,7 +610,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_vcard() -> Result<()> {
let ctx = TestContext::new().await;
@@ -632,7 +632,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_matmsg() -> Result<()> {
let ctx = TestContext::new().await;
@@ -652,7 +652,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_mailto() -> Result<()> {
let ctx = TestContext::new().await;
@@ -682,7 +682,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_smtp() -> Result<()> {
let ctx = TestContext::new().await;
@@ -698,7 +698,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_openpgp_group() -> Result<()> {
let ctx = TestContext::new().await;
let qr = check_qr(
@@ -741,7 +741,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_openpgp_secure_join() -> Result<()> {
let ctx = TestContext::new().await;
@@ -788,7 +788,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_openpgp_fingerprint() -> Result<()> {
let ctx = TestContext::new().await;
@@ -850,7 +850,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_openpgp_without_addr() -> Result<()> {
let ctx = TestContext::new().await;
@@ -886,7 +886,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_withdraw_verifycontact() -> Result<()> {
let alice = TestContext::new_alice().await;
let qr = dc_get_securejoin_qr(&alice, None).await?;
@@ -920,7 +920,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_withdraw_verifygroup() -> Result<()> {
let alice = TestContext::new_alice().await;
let chat_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "foo").await?;
@@ -953,7 +953,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_account() -> Result<()> {
let ctx = TestContext::new().await;
@@ -985,7 +985,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_webrtc_instance() -> Result<()> {
let ctx = TestContext::new().await;
@@ -1011,7 +1011,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_account_bad_scheme() {
let ctx = TestContext::new().await;
let res = check_qr(
@@ -1030,7 +1030,7 @@ mod tests {
assert!(res.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_config_from_qr() -> Result<()> {
let ctx = TestContext::new().await;

View File

@@ -25,7 +25,7 @@ async fn generate_join_group_qr_code(context: &Context, chat_id: ChatId) -> Resu
let avatar = match chat.get_profile_image(context).await? {
Some(path) => {
let avatar_blob = BlobObject::from_path(context, &path)?;
Some(std::fs::read(avatar_blob.to_abs_path())?)
Some(tokio::fs::read(avatar_blob.to_abs_path()).await?)
}
None => None,
};
@@ -45,7 +45,7 @@ async fn generate_verification_qr(context: &Context) -> Result<String> {
let avatar = match contact.get_profile_image(context).await? {
Some(path) => {
let avatar_blob = BlobObject::from_path(context, &path)?;
Some(std::fs::read(avatar_blob.to_abs_path())?)
Some(tokio::fs::read(avatar_blob.to_abs_path()).await?)
}
None => None,
};
@@ -266,7 +266,7 @@ fn inner_generate_secure_join_qr_code(
mod tests {
use super::*;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_svg_escaping() {
let svg = inner_generate_secure_join_qr_code(
"descr123 \" < > &",

View File

@@ -180,7 +180,7 @@ mod tests {
QUOTA_WARN_THRESHOLD_PERCENTAGE,
};
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_needs_quota_warning() -> Result<()> {
assert!(!needs_quota_warning(0, 0));
assert!(!needs_quota_warning(10, 0));
@@ -199,7 +199,7 @@ mod tests {
}
#[allow(clippy::assertions_on_constants)]
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quota_thresholds() -> anyhow::Result<()> {
assert!(QUOTA_ALLCLEAR_PERCENTAGE > 50);
assert!(QUOTA_ALLCLEAR_PERCENTAGE < QUOTA_WARN_THRESHOLD_PERCENTAGE);

View File

@@ -1,9 +1,8 @@
use anyhow::{bail, Context as _, Result};
use async_std::prelude::*;
use async_std::{
channel::{self, Receiver, Sender},
future, task,
};
use async_channel::{self as channel, Receiver, Sender};
use futures::{join, try_join};
use futures_lite::FutureExt;
use tokio::task;
use crate::config::Config;
use crate::context::Context;
@@ -338,7 +337,7 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect
"smtp got rate limited, waiting for {} until can send again",
duration_to_str(duration_until_can_send)
);
async_std::future::timeout(duration_until_can_send, async {
tokio::time::timeout(duration_until_can_send, async {
idle_interrupt_receiver.recv().await.unwrap_or_default()
})
.await
@@ -367,7 +366,7 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect
"smtp has messages to retry, planning to retry {} seconds later", timeout
);
let duration = std::time::Duration::from_secs(timeout);
async_std::future::timeout(duration, async {
tokio::time::timeout(duration, async {
idle_interrupt_receiver.recv().await.unwrap_or_default()
})
.await
@@ -493,13 +492,12 @@ impl Scheduler {
};
// wait for all loops to be started
if let Err(err) = inbox_start_recv
.recv()
.try_join(mvbox_start_recv.recv())
.try_join(sentbox_start_recv.recv())
.try_join(smtp_start_recv.recv())
.await
{
if let Err(err) = try_join!(
inbox_start_recv.recv(),
mvbox_start_recv.recv(),
sentbox_start_recv.recv(),
smtp_start_recv.recv()
) {
bail!("failed to start scheduler: {}", err);
}
@@ -508,19 +506,21 @@ impl Scheduler {
}
async fn maybe_network(&self) {
self.interrupt_inbox(InterruptInfo::new(true))
.join(self.interrupt_mvbox(InterruptInfo::new(true)))
.join(self.interrupt_sentbox(InterruptInfo::new(true)))
.join(self.interrupt_smtp(InterruptInfo::new(true)))
.await;
join!(
self.interrupt_inbox(InterruptInfo::new(true)),
self.interrupt_mvbox(InterruptInfo::new(true)),
self.interrupt_sentbox(InterruptInfo::new(true)),
self.interrupt_smtp(InterruptInfo::new(true))
);
}
async fn maybe_network_lost(&self) {
self.interrupt_inbox(InterruptInfo::new(false))
.join(self.interrupt_mvbox(InterruptInfo::new(false)))
.join(self.interrupt_sentbox(InterruptInfo::new(false)))
.join(self.interrupt_smtp(InterruptInfo::new(false)))
.await;
join!(
self.interrupt_inbox(InterruptInfo::new(false)),
self.interrupt_mvbox(InterruptInfo::new(false)),
self.interrupt_sentbox(InterruptInfo::new(false)),
self.interrupt_smtp(InterruptInfo::new(false))
);
}
async fn interrupt_inbox(&self, info: InterruptInfo) {
@@ -564,24 +564,24 @@ impl Scheduler {
// Actually shutdown tasks.
let timeout_duration = std::time::Duration::from_secs(30);
future::timeout(timeout_duration, self.inbox_handle)
tokio::time::timeout(timeout_duration, self.inbox_handle)
.await
.ok_or_log(context);
if let Some(mvbox_handle) = self.mvbox_handle.take() {
future::timeout(timeout_duration, mvbox_handle)
tokio::time::timeout(timeout_duration, mvbox_handle)
.await
.ok_or_log(context);
}
if let Some(sentbox_handle) = self.sentbox_handle.take() {
future::timeout(timeout_duration, sentbox_handle)
tokio::time::timeout(timeout_duration, sentbox_handle)
.await
.ok_or_log(context);
}
future::timeout(timeout_duration, self.smtp_handle)
tokio::time::timeout(timeout_duration, self.smtp_handle)
.await
.ok_or_log(context);
self.ephemeral_handle.cancel().await;
self.location_handle.cancel().await;
self.ephemeral_handle.abort();
self.location_handle.abort();
}
}

View File

@@ -1,7 +1,7 @@
use core::fmt;
use std::{ops::Deref, sync::Arc};
use async_std::sync::{Mutex, RwLockReadGuard};
use tokio::sync::{Mutex, RwLockReadGuard};
use crate::dc_tools::time;
use crate::events::EventType;
@@ -239,7 +239,7 @@ pub(crate) async fn maybe_network_lost(
impl fmt::Debug for ConnectivityStore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(guard) = self.0.try_lock() {
if let Ok(guard) = self.0.try_lock() {
write!(f, "ConnectivityStore {:?}", &*guard)
} else {
write!(f, "ConnectivityStore [LOCKED]")

View File

@@ -696,7 +696,7 @@ mod tests {
use crate::peerstate::Peerstate;
use crate::test_utils::{TestContext, TestContextManager};
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_setup_contact() {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;
@@ -903,14 +903,14 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_setup_contact_bad_qr() {
let bob = TestContext::new_bob().await;
let ret = dc_join_securejoin(&bob.ctx, "not a qr code").await;
assert!(ret.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_setup_contact_bob_knows_alice() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;
@@ -1035,7 +1035,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_setup_contact_concurrent_calls() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;
@@ -1066,7 +1066,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_secure_join() -> Result<()> {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;
@@ -1290,7 +1290,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_no_qr() -> Result<()> {
let alice = TestContext::new_alice().await;
alice.set_config(Config::ShowEmails, Some("2")).await?;

View File

@@ -8,7 +8,7 @@ use anyhow::{bail, format_err, Context as _, Error, Result};
use async_smtp::smtp::client::net::ClientTlsParameters;
use async_smtp::smtp::response::{Category, Code, Detail};
use async_smtp::{smtp, EmailAddress, ServerAddress};
use async_std::task;
use tokio::task;
use crate::config::Config;
use crate::contact::{Contact, ContactId};

View File

@@ -1,16 +1,14 @@
//! # SQLite wrapper.
use async_std::path::Path;
use async_std::sync::RwLock;
use std::collections::{HashMap, HashSet};
use std::convert::TryFrom;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use anyhow::{bail, Context as _, Result};
use async_std::path::PathBuf;
use async_std::prelude::*;
use rusqlite::{config::DbConfig, Connection, OpenFlags};
use tokio::sync::RwLock;
use crate::blob::BlobObject;
use crate::chat::{add_device_msg, update_device_icon, update_saved_messages_icon};
@@ -126,18 +124,21 @@ impl Sql {
.to_str()
.with_context(|| format!("path {:?} is not valid unicode", path))?;
let conn = self.get_conn().await?;
conn.execute(
"ATTACH DATABASE ? AS backup KEY ?",
paramsv![path_str, passphrase],
)
.context("failed to attach backup database")?;
let res = conn
.query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(()))
.context("failed to export to attached backup database");
conn.execute("DETACH DATABASE backup", [])
.context("failed to detach backup database")?;
res?;
Ok(())
tokio::task::block_in_place(move || {
conn.execute(
"ATTACH DATABASE ? AS backup KEY ?",
paramsv![path_str, passphrase],
)
.context("failed to attach backup database")?;
let res = conn
.query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(()))
.context("failed to export to attached backup database");
conn.execute("DETACH DATABASE backup", [])
.context("failed to detach backup database")?;
res?;
Ok(())
})
}
/// Imports the database from a separate file with the given passphrase.
@@ -147,40 +148,42 @@ impl Sql {
.with_context(|| format!("path {:?} is not valid unicode", path))?;
let conn = self.get_conn().await?;
// Check that backup passphrase is correct before resetting our database.
conn.execute(
"ATTACH DATABASE ? AS backup KEY ?",
paramsv![path_str, passphrase],
)
.context("failed to attach backup database")?;
if let Err(err) = conn
.query_row("SELECT count(*) FROM sqlite_master", [], |_row| Ok(()))
.context("backup passphrase is not correct")
{
tokio::task::block_in_place(move || {
// Check that backup passphrase is correct before resetting our database.
conn.execute(
"ATTACH DATABASE ? AS backup KEY ?",
paramsv![path_str, passphrase],
)
.context("failed to attach backup database")?;
if let Err(err) = conn
.query_row("SELECT count(*) FROM sqlite_master", [], |_row| Ok(()))
.context("backup passphrase is not correct")
{
conn.execute("DETACH DATABASE backup", [])
.context("failed to detach backup database")?;
return Err(err);
}
// Reset the database without reopening it. We don't want to reopen the database because we
// don't have main database passphrase at this point.
// See <https://sqlite.org/c3ref/c_dbconfig_enable_fkey.html> for documentation.
// Without resetting import may fail due to existing tables.
conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, true)
.context("failed to set SQLITE_DBCONFIG_RESET_DATABASE")?;
conn.execute("VACUUM", [])
.context("failed to vacuum the database")?;
conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, false)
.context("failed to unset SQLITE_DBCONFIG_RESET_DATABASE")?;
let res = conn
.query_row("SELECT sqlcipher_export('main', 'backup')", [], |_row| {
Ok(())
})
.context("failed to import from attached backup database");
conn.execute("DETACH DATABASE backup", [])
.context("failed to detach backup database")?;
return Err(err);
}
// Reset the database without reopening it. We don't want to reopen the database because we
// don't have main database passphrase at this point.
// See <https://sqlite.org/c3ref/c_dbconfig_enable_fkey.html> for documentation.
// Without resetting import may fail due to existing tables.
conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, true)
.context("failed to set SQLITE_DBCONFIG_RESET_DATABASE")?;
conn.execute("VACUUM", [])
.context("failed to vacuum the database")?;
conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, false)
.context("failed to unset SQLITE_DBCONFIG_RESET_DATABASE")?;
let res = conn
.query_row("SELECT sqlcipher_export('main', 'backup')", [], |_row| {
Ok(())
})
.context("failed to import from attached backup database");
conn.execute("DETACH DATABASE backup", [])
.context("failed to detach backup database")?;
res?;
Ok(())
res?;
Ok(())
})
}
fn new_pool(
@@ -224,20 +227,22 @@ impl Sql {
{
let conn = self.get_conn().await?;
tokio::task::block_in_place(move || -> Result<()> {
// Try to enable auto_vacuum. This will only be
// applied if the database is new or after successful
// VACUUM, which usually happens before backup export.
// When auto_vacuum is INCREMENTAL, it is possible to
// use PRAGMA incremental_vacuum to return unused
// database pages to the filesystem.
conn.pragma_update(None, "auto_vacuum", &"INCREMENTAL".to_string())?;
// Try to enable auto_vacuum. This will only be
// applied if the database is new or after successful
// VACUUM, which usually happens before backup export.
// When auto_vacuum is INCREMENTAL, it is possible to
// use PRAGMA incremental_vacuum to return unused
// database pages to the filesystem.
conn.pragma_update(None, "auto_vacuum", &"INCREMENTAL".to_string())?;
// journal_mode is persisted, it is sufficient to change it only for one handle.
conn.pragma_update(None, "journal_mode", &"WAL".to_string())?;
// journal_mode is persisted, it is sufficient to change it only for one handle.
conn.pragma_update(None, "journal_mode", &"WAL".to_string())?;
// Default synchronous=FULL is much slower. NORMAL is sufficient for WAL mode.
conn.pragma_update(None, "synchronous", &"NORMAL".to_string())?;
// Default synchronous=FULL is much slower. NORMAL is sufficient for WAL mode.
conn.pragma_update(None, "synchronous", &"NORMAL".to_string())?;
Ok(())
})?;
}
self.run_migrations(context).await?;
@@ -343,15 +348,19 @@ impl Sql {
/// Execute the given query, returning the number of affected rows.
pub async fn execute(&self, query: &str, params: impl rusqlite::Params) -> Result<usize> {
let conn = self.get_conn().await?;
let res = conn.execute(query, params)?;
Ok(res)
tokio::task::block_in_place(move || {
let res = conn.execute(query, params)?;
Ok(res)
})
}
/// Executes the given query, returning the last inserted row ID.
pub async fn insert(&self, query: &str, params: impl rusqlite::Params) -> Result<i64> {
let conn = self.get_conn().await?;
conn.execute(query, params)?;
Ok(conn.last_insert_rowid())
tokio::task::block_in_place(move || {
conn.execute(query, params)?;
Ok(conn.last_insert_rowid())
})
}
/// Prepares and executes the statement and maps a function over the resulting rows.
@@ -369,9 +378,11 @@ impl Sql {
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
{
let conn = self.get_conn().await?;
let mut stmt = conn.prepare(sql)?;
let res = stmt.query_map(params, f)?;
g(res)
tokio::task::block_in_place(move || {
let mut stmt = conn.prepare(sql)?;
let res = stmt.query_map(params, f)?;
g(res)
})
}
pub async fn get_conn(
@@ -408,8 +419,10 @@ impl Sql {
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{
let conn = self.get_conn().await?;
let res = conn.query_row(query, params, f)?;
Ok(res)
tokio::task::block_in_place(move || {
let res = conn.query_row(query, params, f)?;
Ok(res)
})
}
/// Execute the function inside a transaction.
@@ -422,49 +435,55 @@ impl Sql {
G: Send + 'static + FnOnce(&mut rusqlite::Transaction<'_>) -> anyhow::Result<H>,
{
let mut conn = self.get_conn().await?;
let mut transaction = conn.transaction()?;
let ret = callback(&mut transaction);
tokio::task::block_in_place(move || {
let mut transaction = conn.transaction()?;
let ret = callback(&mut transaction);
match ret {
Ok(ret) => {
transaction.commit()?;
Ok(ret)
match ret {
Ok(ret) => {
transaction.commit()?;
Ok(ret)
}
Err(err) => {
transaction.rollback()?;
Err(err)
}
}
Err(err) => {
transaction.rollback()?;
Err(err)
}
}
})
}
/// Query the database if the requested table already exists.
pub async fn table_exists(&self, name: &str) -> anyhow::Result<bool> {
let conn = self.get_conn().await?;
let mut exists = false;
conn.pragma(None, "table_info", &name.to_string(), |_row| {
// will only be executed if the info was found
exists = true;
Ok(())
})?;
tokio::task::block_in_place(move || {
let mut exists = false;
conn.pragma(None, "table_info", &name.to_string(), |_row| {
// will only be executed if the info was found
exists = true;
Ok(())
})?;
Ok(exists)
Ok(exists)
})
}
/// Check if a column exists in a given table.
pub async fn col_exists(&self, table_name: &str, col_name: &str) -> anyhow::Result<bool> {
let conn = self.get_conn().await?;
let mut exists = false;
// `PRAGMA table_info` returns one row per column,
// each row containing 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value
conn.pragma(None, "table_info", &table_name.to_string(), |row| {
let curr_name: String = row.get(1)?;
if col_name == curr_name {
exists = true;
}
Ok(())
})?;
tokio::task::block_in_place(move || {
let mut exists = false;
// `PRAGMA table_info` returns one row per column,
// each row containing 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value
conn.pragma(None, "table_info", &table_name.to_string(), |row| {
let curr_name: String = row.get(1)?;
if col_name == curr_name {
exists = true;
}
Ok(())
})?;
Ok(exists)
Ok(exists)
})
}
/// Execute a query which is expected to return zero or one row.
@@ -478,12 +497,15 @@ impl Sql {
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{
let conn = self.get_conn().await?;
let res = match conn.query_row(sql.as_ref(), params, f) {
Ok(res) => Ok(Some(res)),
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
Err(rusqlite::Error::InvalidColumnType(_, _, rusqlite::types::Type::Null)) => Ok(None),
Err(err) => Err(err),
}?;
let res =
tokio::task::block_in_place(move || match conn.query_row(sql.as_ref(), params, f) {
Ok(res) => Ok(Some(res)),
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
Err(rusqlite::Error::InvalidColumnType(_, _, rusqlite::types::Type::Null)) => {
Ok(None)
}
Err(err) => Err(err),
})?;
Ok(res)
}
@@ -717,7 +739,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
info!(context, "{} files in use.", files_in_use.len(),);
/* go through directory and delete unused files */
let p = context.get_blobdir();
match async_std::fs::read_dir(p).await {
match tokio::fs::read_dir(p).await {
Ok(mut dir_handle) => {
/* avoid deletion of files that are just created to build a message object */
let diff = std::time::Duration::from_secs(60 * 60);
@@ -725,11 +747,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
.checked_sub(diff)
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
while let Some(entry) = dir_handle.next().await {
let entry = match entry {
Ok(entry) => entry,
Err(_) => break,
};
while let Ok(Some(entry)) = dir_handle.next_entry().await {
let name_f = entry.file_name();
let name_s = name_f.to_string_lossy();
@@ -743,7 +761,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
unreferenced_count += 1;
if let Ok(stats) = async_std::fs::metadata(entry.path()).await {
if let Ok(stats) = tokio::fs::metadata(entry.path()).await {
let recently_created =
stats.created().map_or(false, |t| t > keep_files_newer_than);
let recently_modified = stats
@@ -860,8 +878,9 @@ pub fn repeat_vars(count: usize) -> String {
#[cfg(test)]
mod tests {
use async_std::channel;
use async_std::fs::File;
use async_channel as channel;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use crate::config::Config;
use crate::{test_utils::TestContext, EventType};
@@ -894,14 +913,14 @@ mod tests {
assert!(is_file_in_use(&files, Some("-suffix"), "world.txt-suffix"));
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_table_exists() {
let t = TestContext::new().await;
assert!(t.ctx.sql.table_exists("msgs").await.unwrap());
assert!(!t.ctx.sql.table_exists("foobar").await.unwrap());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_col_exists() {
let t = TestContext::new().await;
assert!(t.ctx.sql.col_exists("msgs", "mime_modified").await.unwrap());
@@ -910,7 +929,7 @@ mod tests {
}
/// Tests that auto_vacuum is enabled for new databases.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_auto_vacuum() -> Result<()> {
let t = TestContext::new().await;
@@ -925,7 +944,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_housekeeping_db_closed() {
let t = TestContext::new().await;
@@ -945,14 +964,14 @@ mod tests {
t.add_event_sender(event_sink).await;
let a = t.get_config(Config::Selfavatar).await.unwrap().unwrap();
assert_eq!(avatar_bytes, &async_std::fs::read(&a).await.unwrap()[..]);
assert_eq!(avatar_bytes, &tokio::fs::read(&a).await.unwrap()[..]);
t.sql.close().await;
housekeeping(&t).await.unwrap_err(); // housekeeping should fail as the db is closed
t.sql.open(&t, "".to_string()).await.unwrap();
let a = t.get_config(Config::Selfavatar).await.unwrap().unwrap();
assert_eq!(avatar_bytes, &async_std::fs::read(&a).await.unwrap()[..]);
assert_eq!(avatar_bytes, &tokio::fs::read(&a).await.unwrap()[..]);
while let Ok(event) = event_source.try_recv() {
match event.typ {
@@ -969,7 +988,7 @@ mod tests {
/// Regression test for a bug where housekeeping deleted drafts since their
/// `hidden` flag is set.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_housekeeping_dont_delete_drafts() {
let t = TestContext::new_alice().await;
@@ -996,7 +1015,7 @@ mod tests {
///
/// Statements were not finalized due to a bug in sqlx:
/// <https://github.com/launchbadge/sqlx/issues/1147>
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_db_reopen() -> Result<()> {
use tempfile::tempdir;
@@ -1006,7 +1025,7 @@ mod tests {
// Create a separate empty database for testing.
let dir = tempdir()?;
let dbfile = dir.path().join("testdb.sqlite");
let sql = Sql::new(dbfile.into());
let sql = Sql::new(dbfile);
// Create database with all the tables.
sql.open(&t, "".to_string()).await.unwrap();
@@ -1028,7 +1047,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_migration_flags() -> Result<()> {
let t = TestContext::new().await;
t.evtracker.get_info_contains("Opened database").await;
@@ -1067,7 +1086,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_check_passphrase() -> Result<()> {
use tempfile::tempdir;
@@ -1077,7 +1096,7 @@ mod tests {
// Create a separate empty database for testing.
let dir = tempdir()?;
let dbfile = dir.path().join("testdb.sqlite");
let sql = Sql::new(dbfile.clone().into());
let sql = Sql::new(dbfile.clone());
sql.check_passphrase("foo".to_string()).await?;
sql.open(&t, "foo".to_string())
@@ -1086,7 +1105,7 @@ mod tests {
sql.close().await;
// Reopen the database
let sql = Sql::new(dbfile.into());
let sql = Sql::new(dbfile);
// Test that we can't open encrypted database without a passphrase.
assert!(sql.open(&t, "".to_string()).await.is_err());

View File

@@ -1167,7 +1167,7 @@ mod tests {
assert_eq!(StockMessage::NoMessages.fallback(), "No messages.");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_stock_translation() {
let t = TestContext::new().await;
t.set_stock_translation(StockMessage::NoMessages, "xyz".to_string())
@@ -1176,7 +1176,7 @@ mod tests {
assert_eq!(no_messages(&t).await, "xyz")
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_stock_translation_wrong_replacements() {
let t = TestContext::new().await;
assert!(t
@@ -1191,13 +1191,13 @@ mod tests {
.is_err());
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_str() {
let t = TestContext::new().await;
assert_eq!(no_messages(&t).await, "No messages.");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_string_repl_str() {
let t = TestContext::new().await;
let contact_id = Contact::create(&t.ctx, "Someone", "someone@example.org")
@@ -1212,13 +1212,13 @@ mod tests {
// We have no string using %1$d to test...
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_string_repl_str2() {
let t = TestContext::new().await;
assert_eq!(msg_action_by_user(&t, "foo", "bar").await, "foo by bar.");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_system_msg_simple() {
let t = TestContext::new().await;
assert_eq!(
@@ -1227,7 +1227,7 @@ mod tests {
)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_system_msg_add_member_by_me() {
let t = TestContext::new().await;
assert_eq!(
@@ -1236,7 +1236,7 @@ mod tests {
)
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_system_msg_add_member_by_me_with_displayname() {
let t = TestContext::new().await;
Contact::create(&t, "Alice", "alice@example.org")
@@ -1248,7 +1248,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stock_system_msg_add_member_by_other_with_displayname() {
let t = TestContext::new().await;
let contact_id = {
@@ -1265,7 +1265,7 @@ mod tests {
);
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quota_exceeding_stock_str() -> anyhow::Result<()> {
let t = TestContext::new().await;
let str = quota_exceeding(&t, 81).await;
@@ -1275,7 +1275,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_partial_download_msg_body() -> anyhow::Result<()> {
let t = TestContext::new().await;
let str = partial_download_msg_body(&t, 1024 * 1024).await;
@@ -1283,7 +1283,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_update_device_chats() {
let t = TestContext::new().await;
t.update_device_chats().await.ok();

View File

@@ -189,7 +189,7 @@ mod tests {
use super::*;
use crate::test_utils as test;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_summary_text() {
let d = test::TestContext::new().await;
let ctx = &d.ctx;

View File

@@ -267,7 +267,7 @@ mod tests {
use crate::token::Namespace;
use anyhow::bail;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_sync_sending_enabled() -> Result<()> {
let t = TestContext::new_alice().await;
assert!(!t.is_sync_sending_enabled().await?);
@@ -278,7 +278,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_build_sync_json() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::SendSyncMsgs, true).await?;
@@ -323,7 +323,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_build_sync_json_sync_msgs_off() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::SendSyncMsgs, false).await?;
@@ -337,7 +337,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_sync_items() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -422,7 +422,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_execute_sync_items() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -451,7 +451,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_sync_msg() -> Result<()> {
let alice = TestContext::new_alice().await;
alice.set_config_bool(Config::SendSyncMsgs, true).await?;

View File

@@ -6,17 +6,17 @@
use std::collections::BTreeMap;
use std::ops::Deref;
use std::panic;
use std::sync::Arc;
use std::time::{Duration, Instant};
use ansi_term::Color;
use async_std::channel::{self, Receiver, Sender};
use async_std::prelude::*;
use async_std::sync::{Arc, RwLock};
use async_std::task;
use async_channel::{self as channel, Receiver, Sender};
use chat::ChatItem;
use once_cell::sync::Lazy;
use rand::Rng;
use tempfile::{tempdir, TempDir};
use tokio::sync::RwLock;
use tokio::task;
use crate::chat::{self, Chat, ChatId};
use crate::chatlist::Chatlist;
@@ -250,6 +250,17 @@ impl TestContext {
Self::builder().configure_fiona().build().await
}
/// Print current chat state.
pub async fn print_chats(&self) {
println!("\n========== Chats of {}: ==========", self.name());
if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await {
for (chat, _) in chats.iter() {
self.print_chat(*chat).await;
}
}
println!();
}
/// Internal constructor.
///
/// `name` is used to identify this context in e.g. log output. This is useful mostly
@@ -266,7 +277,7 @@ impl TestContext {
let mut context_names = CONTEXT_NAMES.write().unwrap();
context_names.insert(id, name);
}
let ctx = Context::new(dbfile.into(), id, Events::new())
let ctx = Context::new(&dbfile, id, Events::new())
.await
.expect("failed to create context");
@@ -382,7 +393,7 @@ impl TestContext {
break row;
}
if start.elapsed() < Duration::from_secs(3) {
async_std::task::sleep(Duration::from_millis(100)).await;
tokio::time::sleep(Duration::from_millis(100)).await;
} else {
panic!("no sent message found in jobs table");
}
@@ -670,20 +681,6 @@ impl Deref for TestContext {
}
}
impl Drop for TestContext {
fn drop(&mut self) {
async_std::task::block_on(async {
println!("\n========== Chats of {}: ==========", self.name());
if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await {
for (chat, _) in chats.iter() {
self.print_chat(*chat).await;
}
}
println!();
});
}
}
pub enum LogEvent {
/// Logged event.
Event(Event),
@@ -828,15 +825,14 @@ impl EventTracker {
/// If no matching events are ready this will wait for new events to arrive and time out
/// after 10 seconds.
pub async fn get_matching<F: Fn(&EventType) -> bool>(&self, event_matcher: F) -> EventType {
async move {
tokio::time::timeout(Duration::from_secs(10), async move {
loop {
let event = self.0.recv().await.unwrap();
if event_matcher(&event.typ) {
return event.typ;
}
}
}
.timeout(Duration::from_secs(10))
})
.await
.expect("timeout waiting for event match")
}
@@ -1011,21 +1007,21 @@ mod tests {
// The following three tests demonstrate, when made to fail, the log output being
// directed to the correct test output.
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_with_alice() {
let alice = TestContext::builder().configure_alice().build().await;
alice.ctx.emit_event(EventType::Info("hello".into()));
// panic!("Alice fails");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_with_bob() {
let bob = TestContext::builder().configure_bob().build().await;
bob.ctx.emit_event(EventType::Info("there".into()));
// panic!("Bob fails");
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_with_both() {
let mut tcm = TestContextManager::new().await;
let alice = tcm.alice().await;

View File

@@ -63,7 +63,7 @@ mod tests {
use crate::dc_tools::time;
use crate::test_utils::TestContext;
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_update_timestamp() -> Result<()> {
let mut params = Params::new();
let ts = time();
@@ -85,7 +85,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_out_of_order_subject() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -126,7 +126,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_out_of_order_group_name() -> Result<()> {
let t = TestContext::new_alice().await;

View File

@@ -1,26 +1,27 @@
//! # Handle webxdc messages.
use std::convert::TryFrom;
use std::path::PathBuf;
use anyhow::{anyhow, bail, ensure, format_err, Result};
use deltachat_derive::FromSql;
use lettre_email::mime;
use lettre_email::PartBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tokio::io::AsyncReadExt;
use crate::chat::Chat;
use crate::contact::ContactId;
use crate::context::Context;
use crate::dc_tools::{dc_create_smeared_timestamp, dc_open_file_std};
use crate::dc_tools::dc_create_smeared_timestamp;
use crate::dc_tools::dc_get_abs_path;
use crate::message::{Message, MessageState, MsgId, Viewtype};
use crate::mimeparser::SystemMessage;
use crate::param::Param;
use crate::param::Params;
use crate::scheduler::InterruptInfo;
use crate::{chat, EventType};
use anyhow::{bail, ensure, format_err, Result};
use async_std::path::PathBuf;
use deltachat_derive::FromSql;
use lettre_email::mime;
use lettre_email::PartBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use zip::ZipArchive;
/// The current API version.
/// If `min_api` in manifest.toml is set to a larger value,
@@ -139,16 +140,12 @@ pub(crate) struct StatusUpdateItemAndSerial {
impl Context {
/// check if a file is an acceptable webxdc for sending or receiving.
pub(crate) async fn is_webxdc_file<R>(&self, filename: &str, mut reader: R) -> Result<bool>
where
R: Read + Seek,
{
pub(crate) async fn is_webxdc_file(&self, filename: &str, file: &[u8]) -> Result<bool> {
if !filename.ends_with(WEBXDC_SUFFIX) {
return Ok(false);
}
let size = reader.seek(SeekFrom::End(0))?;
if size > WEBXDC_RECEIVING_LIMIT {
if file.len() as u64 > WEBXDC_RECEIVING_LIMIT {
info!(
self,
"{} exceeds receiving limit of {} bytes", &filename, WEBXDC_RECEIVING_LIMIT
@@ -156,8 +153,7 @@ impl Context {
return Ok(false);
}
reader.seek(SeekFrom::Start(0))?;
let mut archive = match zip::ZipArchive::new(reader) {
let archive = match async_zip::read::mem::ZipFileReader::new(file).await {
Ok(archive) => archive,
Err(_) => {
info!(self, "{} cannot be opened as zip-file", &filename);
@@ -165,7 +161,7 @@ impl Context {
}
};
if archive.by_name("index.html").is_err() {
if archive.entry("index.html").is_none() {
info!(self, "{} misses index.html", &filename);
return Ok(false);
}
@@ -176,18 +172,12 @@ impl Context {
/// ensure that a file is an acceptable webxdc for sending
/// (sending has more strict size limits).
pub(crate) async fn ensure_sendable_webxdc_file(&self, path: &PathBuf) -> Result<()> {
let mut file = std::fs::File::open(path)?;
if !self
.is_webxdc_file(path.to_str().unwrap_or_default(), &mut file)
.await?
{
bail!(
"{} is not a valid webxdc file",
path.to_str().unwrap_or_default()
);
let filename = path.to_str().unwrap_or_default();
if !filename.ends_with(WEBXDC_SUFFIX) {
bail!("{} is not a valid webxdc file", filename);
}
let size = file.seek(SeekFrom::End(0))?;
let size = tokio::fs::metadata(path).await?.len();
if size > WEBXDC_SENDING_LIMIT {
bail!(
"webxdc {} exceeds acceptable size of {} bytes",
@@ -195,6 +185,26 @@ impl Context {
WEBXDC_SENDING_LIMIT
);
}
let valid = match async_zip::read::fs::ZipFileReader::new(path).await {
Ok(archive) => {
if archive.entry("index.html").is_none() {
info!(self, "{} misses index.html", filename);
false
} else {
true
}
}
Err(_) => {
info!(self, "{} cannot be opened as zip-file", filename);
false
}
};
if !valid {
bail!("{} is not a valid webxdc file", filename);
}
Ok(())
}
@@ -588,22 +598,28 @@ fn parse_webxdc_manifest(bytes: &[u8]) -> Result<WebxdcManifest> {
Ok(manifest)
}
fn get_blob(archive: &mut ZipArchive<File>, name: &str) -> Result<Vec<u8>> {
let mut file = archive.by_name(name)?;
async fn get_blob(archive: &mut async_zip::read::fs::ZipFileReader, name: &str) -> Result<Vec<u8>> {
let (i, _) = archive
.entry(name)
.ok_or_else(|| anyhow!("no entry found for {}", name))?;
let mut reader = archive.entry_reader(i).await?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
reader.read_to_end(&mut buf).await?;
Ok(buf)
}
impl Message {
/// Get handle to a webxdc ZIP-archive.
/// To check for file existance use archive.by_name(), to read a file, use get_blob(archive).
async fn get_webxdc_archive(&self, context: &Context) -> Result<ZipArchive<File>> {
async fn get_webxdc_archive(
&self,
context: &Context,
) -> Result<async_zip::read::fs::ZipFileReader> {
let path = self
.get_file(context)
.ok_or_else(|| format_err!("No webxdc instance file."))?;
let file = dc_open_file_std(context, path)?;
let archive = zip::ZipArchive::new(file)?;
let path_abs = dc_get_abs_path(context, &path);
let archive = async_zip::read::fs::ZipFileReader::new(path_abs).await?;
Ok(archive)
}
@@ -627,7 +643,7 @@ impl Message {
let mut archive = self.get_webxdc_archive(context).await?;
if name == "index.html" {
if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") {
if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await {
if let Ok(manifest) = parse_webxdc_manifest(&bytes) {
if let Some(min_api) = manifest.min_api {
if min_api > WEBXDC_API_VERSION {
@@ -640,7 +656,7 @@ impl Message {
}
}
get_blob(&mut archive, name)
get_blob(&mut archive, name).await
}
/// Return info from manifest.toml or from fallbacks.
@@ -648,7 +664,7 @@ impl Message {
ensure!(self.viewtype == Viewtype::Webxdc, "No webxdc instance.");
let mut archive = self.get_webxdc_archive(context).await?;
let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") {
let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await {
if let Ok(manifest) = parse_webxdc_manifest(&bytes) {
manifest
} else {
@@ -680,9 +696,9 @@ impl Message {
} else {
self.get_filename().unwrap_or_default()
},
icon: if archive.by_name("icon.png").is_ok() {
icon: if archive.entry("icon.png").is_some() {
"icon.png".to_string()
} else if archive.by_name("icon.jpg").is_ok() {
} else if archive.entry("icon.jpg").is_some() {
"icon.jpg".to_string()
} else {
WEBXDC_DEFAULT_ICON.to_string()
@@ -708,10 +724,8 @@ impl Message {
#[cfg(test)]
mod tests {
use std::io::Cursor;
use async_std::fs::File;
use async_std::io::WriteExt;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use crate::chat::{
add_contact_to_chat, create_group_chat, forward_msgs, resend_msgs, send_msg, send_text_msg,
@@ -726,7 +740,7 @@ mod tests {
use super::*;
#[allow(clippy::assertions_on_constants)]
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_file_limits() -> Result<()> {
assert!(WEBXDC_SENDING_LIMIT >= 32768);
assert!(WEBXDC_SENDING_LIMIT < 16777216);
@@ -735,41 +749,41 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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",
Cursor::new(include_bytes!("../test-data/message/issue_523.txt"))
include_bytes!("../test-data/message/issue_523.txt")
)
.await?
);
assert!(
!t.is_webxdc_file(
"bad-ext-good-zip.txt",
Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc"))
include_bytes!("../test-data/webxdc/minimal.xdc")
)
.await?
);
assert!(
!t.is_webxdc_file(
"good-ext-no-zip.xdc",
Cursor::new(include_bytes!("../test-data/message/issue_523.txt"))
include_bytes!("../test-data/message/issue_523.txt")
)
.await?
);
assert!(
!t.is_webxdc_file(
"good-ext-no-index-html.xdc",
Cursor::new(include_bytes!("../test-data/webxdc/no-index-html.xdc"))
include_bytes!("../test-data/webxdc/no-index-html.xdc")
)
.await?
);
assert!(
t.is_webxdc_file(
"good-ext-good-zip.xdc",
Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc"))
include_bytes!("../test-data/webxdc/minimal.xdc")
)
.await?
);
@@ -796,7 +810,7 @@ mod tests {
Message::load_from_db(t, instance_msg_id).await
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -820,7 +834,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -852,7 +866,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -895,7 +909,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_webxdc_instance_and_info() -> Result<()> {
// Alice uses webxdc in a group
let alice = TestContext::new_alice().await;
@@ -940,7 +954,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_receive_webxdc_instance() -> Result<()> {
let t = TestContext::new_alice().await;
dc_receive_imf(
@@ -966,7 +980,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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;
@@ -1010,7 +1024,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1048,7 +1062,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1142,7 +1156,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1238,7 +1252,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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?;
@@ -1338,7 +1352,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1364,7 +1378,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1402,7 +1416,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1462,7 +1476,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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;
@@ -1529,7 +1543,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1541,7 +1555,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1558,7 +1572,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1570,7 +1584,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1583,7 +1597,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1624,7 +1638,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[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());
@@ -1655,7 +1669,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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));
@@ -1669,7 +1683,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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());
@@ -1683,7 +1697,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
@@ -1702,7 +1716,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1786,7 +1800,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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;
@@ -1852,7 +1866,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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;
@@ -1894,7 +1908,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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;
@@ -1985,7 +1999,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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;
@@ -2023,7 +2037,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "c").await?;
@@ -2041,7 +2055,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_opportunistic_encryption() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -2093,7 +2107,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
@@ -2113,7 +2127,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[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;