mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 14:26:30 +03:00
fix various integration tests with the python bindings
This commit is contained in:
@@ -572,6 +572,8 @@ int dc_is_configured (const dc_context_t* context);
|
|||||||
*/
|
*/
|
||||||
void dc_context_run (dc_context_t* context);
|
void dc_context_run (dc_context_t* context);
|
||||||
|
|
||||||
|
int dc_is_running (const dc_context_t* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Document
|
* TODO: Document
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ impl ContextWrapper {
|
|||||||
match guard.as_ref() {
|
match guard.as_ref() {
|
||||||
Some(ref ctx) => Ok(ctxfn(ctx)),
|
Some(ref ctx) => Ok(ctxfn(ctx)),
|
||||||
None => {
|
None => {
|
||||||
eprintln!("context not open");
|
eprintln!("ignoring careless call to non open context");
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ macro_rules! with_inner_async {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
eprintln!("context not open");
|
eprintln!("ignoring careless call to non open context");
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,23 @@ macro_rules! with_inner_async {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! with_inner_spawn {
|
||||||
|
($ctx:expr, $name:ident, $block:expr) => {{
|
||||||
|
let l = $ctx.inner.clone();
|
||||||
|
let lock = l.read().unwrap();
|
||||||
|
match lock.as_ref() {
|
||||||
|
Some(ctx) => {
|
||||||
|
let $name = ctx.clone();
|
||||||
|
async_std::task::spawn(async move { $block.await });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
eprintln!("ignoring careless call to non open context");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
macro_rules! try_inner_async {
|
macro_rules! try_inner_async {
|
||||||
($ctx:expr, $name:ident, $block:expr) => {{
|
($ctx:expr, $name:ident, $block:expr) => {{
|
||||||
let l = $ctx.inner.clone();
|
let l = $ctx.inner.clone();
|
||||||
@@ -443,9 +460,15 @@ pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) {
|
|||||||
eprintln!("ignoring careless call to dc_configure()");
|
eprintln!("ignoring careless call to dc_configure()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: this is now blocking, maybe change this
|
|
||||||
let ffi_context = &*context;
|
let ffi_context = &*context;
|
||||||
with_inner_async!(ffi_context, ctx, async move { ctx.configure().await }).ok();
|
|
||||||
|
with_inner_spawn!(ffi_context, ctx, async move {
|
||||||
|
ctx.configure()
|
||||||
|
.await
|
||||||
|
.log_err(ffi_context, "Configure failed")
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -472,6 +495,16 @@ pub unsafe extern "C" fn dc_context_run(context: *mut dc_context_t) {
|
|||||||
with_inner_async!(ffi_context, ctx, { ctx.run() }).unwrap_or(())
|
with_inner_async!(ffi_context, ctx, { ctx.run() }).unwrap_or(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_is_running(context: *mut dc_context_t) -> libc::c_int {
|
||||||
|
if context.is_null() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let ffi_context = &*context;
|
||||||
|
|
||||||
|
with_inner_async!(ffi_context, ctx, { ctx.is_running() }).unwrap_or_default() as libc::c_int
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_has_next_event(context: *mut dc_context_t) -> libc::c_int {
|
pub unsafe extern "C" fn dc_has_next_event(context: *mut dc_context_t) -> libc::c_int {
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
@@ -1833,7 +1866,7 @@ pub unsafe extern "C" fn dc_get_contact(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_imex(
|
pub unsafe extern "C" fn dc_imex(
|
||||||
context: *mut dc_context_t,
|
context: *mut dc_context_t,
|
||||||
what: libc::c_int,
|
what_raw: libc::c_int,
|
||||||
param1: *const libc::c_char,
|
param1: *const libc::c_char,
|
||||||
_param2: *const libc::c_char,
|
_param2: *const libc::c_char,
|
||||||
) {
|
) {
|
||||||
@@ -1841,21 +1874,24 @@ pub unsafe extern "C" fn dc_imex(
|
|||||||
eprintln!("ignoring careless call to dc_imex()");
|
eprintln!("ignoring careless call to dc_imex()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let what = match imex::ImexMode::from_i32(what as i32) {
|
let what = match imex::ImexMode::from_i32(what_raw as i32) {
|
||||||
Some(what) => what,
|
Some(what) => what,
|
||||||
None => {
|
None => {
|
||||||
eprintln!("ignoring invalid argument {} to dc_imex", what);
|
eprintln!("ignoring invalid argument {} to dc_imex", what_raw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: this is now blocking, figure out if that is okay
|
// TODO: this is now blocking, figure out if that is okay
|
||||||
let ffi_context = &*context;
|
let ffi_context = &*context;
|
||||||
with_inner_async!(
|
|
||||||
ffi_context,
|
let param1 = to_opt_string_lossy(param1);
|
||||||
ctx,
|
|
||||||
imex::imex(&ctx, what, to_opt_string_lossy(param1))
|
with_inner_spawn!(ffi_context, ctx, async move {
|
||||||
)
|
imex::imex(&ctx, what, param1)
|
||||||
|
.await
|
||||||
|
.log_err(ffi_context, "IMEX failed")
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ async fn main() {
|
|||||||
cb(event);
|
cb(event);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
async_std::task::sleep(time::Duration::from_millis(50));
|
async_std::task::sleep(time::Duration::from_millis(50)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -565,15 +565,18 @@ class IOThreads:
|
|||||||
self._thread_quitflag = False
|
self._thread_quitflag = False
|
||||||
self._name2thread = {}
|
self._name2thread = {}
|
||||||
self._log_event = log_event
|
self._log_event = log_event
|
||||||
self._running = False
|
self._log_running = True
|
||||||
|
|
||||||
|
# Make sure the current
|
||||||
|
self._start_one_thread("deltachat-log", self.dc_thread_run)
|
||||||
|
|
||||||
def is_started(self):
|
def is_started(self):
|
||||||
return self._running
|
return lib.dc_is_open(self._dc_context) and lib.dc_is_running(self._dc_context)
|
||||||
|
|
||||||
def start(self, imap=True, smtp=True, mvbox=False, sentbox=False):
|
def start(self, imap=True, smtp=True, mvbox=False, sentbox=False):
|
||||||
assert not self.is_started()
|
assert not self.is_started()
|
||||||
self._running = True
|
|
||||||
self._start_one_thread("deltachat", self.dc_thread_run)
|
lib.dc_context_run(self._dc_context)
|
||||||
|
|
||||||
def _start_one_thread(self, name, func):
|
def _start_one_thread(self, name, func):
|
||||||
self._name2thread[name] = t = threading.Thread(target=func, name=name)
|
self._name2thread[name] = t = threading.Thread(target=func, name=name)
|
||||||
@@ -581,18 +584,14 @@ class IOThreads:
|
|||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
def stop(self, wait=False):
|
def stop(self, wait=False):
|
||||||
lib.dc_context_shutdown(self._dc_context)
|
if self.is_started():
|
||||||
if wait:
|
lib.dc_context_shutdown(self._dc_context)
|
||||||
for name, thread in self._name2thread.items():
|
|
||||||
thread.join()
|
|
||||||
self._running = False
|
|
||||||
|
|
||||||
def dc_thread_run(self):
|
def dc_thread_run(self):
|
||||||
self._log_event("py-bindings-info", 0, "DC THREAD START")
|
self._log_event("py-bindings-info", 0, "DC LOG THREAD START")
|
||||||
|
|
||||||
lib.dc_context_run(self._dc_context)
|
while self._log_running:
|
||||||
while self._running:
|
if lib.dc_is_open(self._dc_context) and lib.dc_has_next_event(self._dc_context):
|
||||||
if lib.dc_has_next_event(self._dc_context):
|
|
||||||
event = lib.dc_get_next_event(self._dc_context)
|
event = lib.dc_get_next_event(self._dc_context)
|
||||||
if event != ffi.NULL:
|
if event != ffi.NULL:
|
||||||
deltachat.py_dc_callback(
|
deltachat.py_dc_callback(
|
||||||
@@ -605,7 +604,7 @@ class IOThreads:
|
|||||||
else:
|
else:
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
||||||
self._log_event("py-bindings-info", 0, "DC THREAD FINISHED")
|
self._log_event("py-bindings-info", 0, "DC LOG THREAD FINISHED")
|
||||||
|
|
||||||
def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
|
def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
|
||||||
# destructor for dc_context
|
# destructor for dc_context
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, datadir):
|
|||||||
pre_generated_key=pre_generated_key)
|
pre_generated_key=pre_generated_key)
|
||||||
configdict.update(config)
|
configdict.update(config)
|
||||||
ac.configure(**configdict)
|
ac.configure(**configdict)
|
||||||
ac.start_threads(mvbox=mvbox, sentbox=sentbox)
|
ac.start_threads()
|
||||||
return ac
|
return ac
|
||||||
|
|
||||||
def get_one_online_account(self, pre_generated_key=True):
|
def get_one_online_account(self, pre_generated_key=True):
|
||||||
|
|||||||
@@ -178,7 +178,6 @@ class TestOfflineChat:
|
|||||||
assert d["draft"] == "" if chat.get_draft() is None else chat.get_draft()
|
assert d["draft"] == "" if chat.get_draft() is None else chat.get_draft()
|
||||||
|
|
||||||
def test_group_chat_creation_with_translation(self, ac1):
|
def test_group_chat_creation_with_translation(self, ac1):
|
||||||
ac1.start_threads()
|
|
||||||
ac1.set_stock_translation(const.DC_STR_NEWGROUPDRAFT, "xyz %1$s")
|
ac1.set_stock_translation(const.DC_STR_NEWGROUPDRAFT, "xyz %1$s")
|
||||||
ac1._evlogger.consume_events()
|
ac1._evlogger.consume_events()
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@@ -198,7 +197,6 @@ class TestOfflineChat:
|
|||||||
assert not chat.is_promoted()
|
assert not chat.is_promoted()
|
||||||
msg = chat.get_draft()
|
msg = chat.get_draft()
|
||||||
assert msg.text == "xyz title1"
|
assert msg.text == "xyz title1"
|
||||||
ac1.stop_threads()
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("verified", [True, False])
|
@pytest.mark.parametrize("verified", [True, False])
|
||||||
def test_group_chat_qr(self, acfactory, ac1, verified):
|
def test_group_chat_qr(self, acfactory, ac1, verified):
|
||||||
@@ -351,6 +349,7 @@ class TestOfflineChat:
|
|||||||
ac1.configure(addr="123@example.org")
|
ac1.configure(addr="123@example.org")
|
||||||
|
|
||||||
def test_import_export_one_contact(self, acfactory, tmpdir):
|
def test_import_export_one_contact(self, acfactory, tmpdir):
|
||||||
|
print("START")
|
||||||
backupdir = tmpdir.mkdir("backup")
|
backupdir = tmpdir.mkdir("backup")
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||||
@@ -362,24 +361,27 @@ class TestOfflineChat:
|
|||||||
with bin.open("w") as f:
|
with bin.open("w") as f:
|
||||||
f.write("\00123" * 10000)
|
f.write("\00123" * 10000)
|
||||||
msg = chat.send_file(bin.strpath)
|
msg = chat.send_file(bin.strpath)
|
||||||
|
print("L1")
|
||||||
contact = msg.get_sender_contact()
|
contact = msg.get_sender_contact()
|
||||||
assert contact == ac1.get_self_contact()
|
assert contact == ac1.get_self_contact()
|
||||||
assert not backupdir.listdir()
|
assert not backupdir.listdir()
|
||||||
|
print("L2")
|
||||||
path = ac1.export_all(backupdir.strpath)
|
path = ac1.export_all(backupdir.strpath)
|
||||||
assert os.path.exists(path)
|
assert os.path.exists(path)
|
||||||
ac2 = acfactory.get_unconfigured_account()
|
ac2 = acfactory.get_unconfigured_account()
|
||||||
ac2.import_all(path)
|
ac2.import_all(path)
|
||||||
contacts = ac2.get_contacts(query="some1")
|
contacts = ac2.get_contacts(query="some1")
|
||||||
assert len(contacts) == 1
|
assert len(contacts) == 1
|
||||||
|
print("L3")
|
||||||
contact2 = contacts[0]
|
contact2 = contacts[0]
|
||||||
assert contact2.addr == "some1@hello.com"
|
assert contact2.addr == "some1@hello.com"
|
||||||
chat2 = ac2.create_chat_by_contact(contact2)
|
chat2 = ac2.create_chat_by_contact(contact2)
|
||||||
messages = chat2.get_messages()
|
messages = chat2.get_messages()
|
||||||
assert len(messages) == 2
|
assert len(messages) == 2
|
||||||
|
print("L4")
|
||||||
assert messages[0].text == "msg1"
|
assert messages[0].text == "msg1"
|
||||||
assert os.path.exists(messages[1].filename)
|
assert os.path.exists(messages[1].filename)
|
||||||
|
print("STOP")
|
||||||
|
|
||||||
def test_ac_setup_message_fails(self, ac1):
|
def test_ac_setup_message_fails(self, ac1):
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ def test_sig():
|
|||||||
|
|
||||||
def test_markseen_invalid_message_ids(acfactory):
|
def test_markseen_invalid_message_ids(acfactory):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
|
|
||||||
ac1.start_threads()
|
|
||||||
contact1 = ac1.create_contact(email="some1@example.com", name="some1")
|
contact1 = ac1.create_contact(email="some1@example.com", name="some1")
|
||||||
chat = ac1.create_chat_by_contact(contact1)
|
chat = ac1.create_chat_by_contact(contact1)
|
||||||
chat.send_text("one messae")
|
chat.send_text("one messae")
|
||||||
@@ -140,7 +139,6 @@ def test_markseen_invalid_message_ids(acfactory):
|
|||||||
msg_ids = [9]
|
msg_ids = [9]
|
||||||
lib.dc_markseen_msgs(ac1._dc_context, msg_ids, len(msg_ids))
|
lib.dc_markseen_msgs(ac1._dc_context, msg_ids, len(msg_ids))
|
||||||
ac1._evlogger.ensure_event_not_queued("DC_EVENT_WARNING|DC_EVENT_ERROR")
|
ac1._evlogger.ensure_event_not_queued("DC_EVENT_WARNING|DC_EVENT_ERROR")
|
||||||
ac1.stop_threads()
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_special_message_id_returns_empty_message(acfactory):
|
def test_get_special_message_id_returns_empty_message(acfactory):
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn inbox_loop(ctx: Context, inbox_handlers: ImapConnectionHandlers) {
|
async fn inbox_loop(ctx: Context, inbox_handlers: ImapConnectionHandlers) {
|
||||||
|
use futures::future::FutureExt;
|
||||||
|
|
||||||
info!(ctx, "starting inbox loop");
|
info!(ctx, "starting inbox loop");
|
||||||
let ImapConnectionHandlers {
|
let ImapConnectionHandlers {
|
||||||
mut connection,
|
mut connection,
|
||||||
@@ -56,7 +58,10 @@ async fn inbox_loop(ctx: Context, inbox_handlers: ImapConnectionHandlers) {
|
|||||||
} = inbox_handlers;
|
} = inbox_handlers;
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
connection.connect_configured(&ctx).await.unwrap();
|
if let Err(err) = connection.connect_configured(&ctx).await {
|
||||||
|
error!(ctx, "{}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let probe_network = ctx.scheduler.read().await.get_probe_network();
|
let probe_network = ctx.scheduler.read().await.get_probe_network();
|
||||||
@@ -101,7 +106,7 @@ async fn inbox_loop(ctx: Context, inbox_handlers: ImapConnectionHandlers) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fut.race(stop_receiver.recv()).await;
|
fut.race(stop_receiver.recv().map(|_| ())).await;
|
||||||
shutdown_sender.send(()).await;
|
shutdown_sender.send(()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +115,8 @@ async fn simple_imap_loop(
|
|||||||
inbox_handlers: ImapConnectionHandlers,
|
inbox_handlers: ImapConnectionHandlers,
|
||||||
folder: impl AsRef<str>,
|
folder: impl AsRef<str>,
|
||||||
) {
|
) {
|
||||||
|
use futures::future::FutureExt;
|
||||||
|
|
||||||
info!(ctx, "starting simple loop for {}", folder.as_ref());
|
info!(ctx, "starting simple loop for {}", folder.as_ref());
|
||||||
let ImapConnectionHandlers {
|
let ImapConnectionHandlers {
|
||||||
mut connection,
|
mut connection,
|
||||||
@@ -118,7 +125,10 @@ async fn simple_imap_loop(
|
|||||||
} = inbox_handlers;
|
} = inbox_handlers;
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
connection.connect_configured(&ctx).await.unwrap();
|
if let Err(err) = connection.connect_configured(&ctx).await {
|
||||||
|
error!(ctx, "{}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match get_watch_folder(&ctx, folder.as_ref()).await {
|
match get_watch_folder(&ctx, folder.as_ref()).await {
|
||||||
@@ -155,7 +165,7 @@ async fn simple_imap_loop(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fut.race(stop_receiver.recv()).await;
|
fut.race(stop_receiver.recv().map(|_| ())).await;
|
||||||
shutdown_sender.send(()).await;
|
shutdown_sender.send(()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user