diff --git a/python/src/deltachat/__init__.py b/python/src/deltachat/__init__.py index db637d017..0d8a84ecc 100644 --- a/python/src/deltachat/__init__.py +++ b/python/src/deltachat/__init__.py @@ -63,6 +63,10 @@ def run_cmdline(argv=None, account_plugins=None): log = events.FFIEventLogger(ac, "bot") ac.add_account_plugin(log) + for plugin in account_plugins or []: + print("adding plugin", plugin) + ac.add_account_plugin(plugin) + if not ac.is_configured(): assert args.email and args.password, ( "you must specify --email and --password once to configure this database/account" @@ -72,12 +76,11 @@ def run_cmdline(argv=None, account_plugins=None): ac.set_config("mvbox_move", "0") ac.set_config("mvbox_watch", "0") ac.set_config("sentbox_watch", "0") - - for plugin in account_plugins or []: - ac.add_account_plugin(plugin) + ac.configure() + ac.wait_configure_finish() # start IO threads and configure if neccessary - ac.start() + ac.start_io() print("{}: waiting for message".format(ac.get_config("addr"))) diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index c5bfe4109..f09f23615 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -1,7 +1,6 @@ """ Account class implementation. """ from __future__ import print_function -import atexit from contextlib import contextmanager from email.utils import parseaddr from threading import Event @@ -48,7 +47,7 @@ class Account(object): self._dc_context = ffi.gc( lib.dc_context_new(as_dc_charpointer(os_name), db_path, ffi.NULL), - _destroy_dc_context, + lib.dc_context_unref, ) if self._dc_context == ffi.NULL: raise ValueError("Could not dc_context_new: {} {}".format(os_name, db_path)) @@ -58,7 +57,6 @@ class Account(object): self._shutdown_event = Event() self._event_thread = EventThread(self) self._configkeys = self.get_config("sys.config_keys").split() - atexit.register(self.shutdown) hook.dc_account_init(account=self) def disable_logging(self): @@ -69,8 +67,8 @@ class Account(object): """ re-enable logging. """ self._logging = True - # def __del__(self): - # self.shutdown() + def __del__(self): + self.shutdown() def log(self, msg): if self._logging: @@ -241,7 +239,7 @@ class Account(object): :returns: True if deletion succeeded (contact was deleted) """ contact_id = contact.id - assert contact._dc_context == self._dc_context + assert contact.account == self assert contact_id > const.DC_CHAT_ID_LAST_SPECIAL return bool(lib.dc_delete_contact(self._dc_context, contact_id)) @@ -289,7 +287,7 @@ class Account(object): :returns: a :class:`deltachat.chat.Chat` object. """ if hasattr(contact, "id"): - if contact._dc_context != self._dc_context: + if contact.account != self: raise ValueError("Contact belongs to a different Account") contact_id = contact.id else: @@ -309,7 +307,7 @@ class Account(object): :returns: a :class:`deltachat.chat.Chat` object. """ if hasattr(message, "id"): - if self._dc_context != message._dc_context: + if message.account != self: raise ValueError("Message belongs to a different Account") msg_id = message.id else: @@ -557,13 +555,14 @@ class Account(object): """ Stop ongoing securejoin, configuration or other core jobs. """ lib.dc_stop_ongoing_process(self._dc_context) - def start(self): + def start_io(self): """ start this account's IO scheduling (Rust-core async scheduler) - If this account is not configured but "addr" and "mail_pw" config - values are set, dc_configure() will be called. + If this account is not configured an Exception is raised. + You need to call account.configure() and account.wait_configure_finish() + before. - You may call `wait_shutdown` or `shutdown` after the + You may call `stop_scheduler`, `wait_shutdown` or `shutdown` after the account is started. :raises MissingCredentials: if `addr` and `mail_pw` values are not set. @@ -572,8 +571,7 @@ class Account(object): :returns: None (account is configured and with io-scheduling running) """ if not self.is_configured(): - self.configure() - self.wait_configure_finish() + raise ValueError("account not configured, cannot start io") lib.dc_start_io(self._dc_context) def configure(self): @@ -601,13 +599,13 @@ class Account(object): """ wait until shutdown of this account has completed. """ self._shutdown_event.wait() - def stop_scheduler(self): - """ stop core scheduler if it is running. """ + def stop_io(self): + """ stop core IO scheduler if it is running. """ self.log("stop_ongoing") self.stop_ongoing() if bool(lib.dc_is_io_running(self._dc_context)): - self.log("context_shutdown (stop core scheduler)") + self.log("dc_stop_io (stop core IO scheduler)") lib.dc_stop_io(self._dc_context) else: self.log("stop_scheduler called on non-running context") @@ -615,13 +613,12 @@ class Account(object): def shutdown(self): """ shutdown and destroy account (stop callback thread, close and remove underlying dc_context).""" - dc_context = self._dc_context - if dc_context is None: + if self._dc_context is None: return - self.stop_scheduler() + self.stop_io() - self.log("remove dc_context") + self.log("remove dc_context references") # the dc_context_unref triggers get_next_event to return ffi.NULL # which in turns makes the event thread finish execution self._dc_context = None @@ -629,18 +626,13 @@ class Account(object): self.log("wait for event thread to finish") self._event_thread.wait() - atexit.unregister(self.shutdown) self._shutdown_event.set() + hook = hookspec.Global._get_plugin_manager().hook - hook.dc_account_after_shutdown(account=self, dc_context=dc_context) + hook.dc_account_after_shutdown(account=self) self.log("shutdown finished") -def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref): - # destructor for dc_context - dc_context_unref(dc_context) - - class ScannedQRCode: def __init__(self, dc_lot): self._dc_lot = dc_lot diff --git a/python/src/deltachat/chat.py b/python/src/deltachat/chat.py index f2d6cd09a..21f4da558 100644 --- a/python/src/deltachat/chat.py +++ b/python/src/deltachat/chat.py @@ -19,12 +19,11 @@ class Chat(object): def __init__(self, account, id): self.account = account - self._dc_context = account._dc_context self.id = id def __eq__(self, other): return self.id == getattr(other, "id", None) and \ - self._dc_context == getattr(other, "_dc_context", None) + self.account._dc_context == other.account._dc_context def __ne__(self, other): return not (self == other) @@ -35,7 +34,7 @@ class Chat(object): @property def _dc_chat(self): return ffi.gc( - lib.dc_get_chat(self._dc_context, self.id), + lib.dc_get_chat(self.account._dc_context, self.id), lib.dc_chat_unref ) @@ -47,7 +46,7 @@ class Chat(object): - does not delete messages on server - the chat or contact is not blocked, new message will arrive """ - lib.dc_delete_chat(self._dc_context, self.id) + lib.dc_delete_chat(self.account._dc_context, self.id) # ------ chat status/metadata API ------------------------------ @@ -105,7 +104,7 @@ class Chat(object): :returns: None """ name = as_dc_charpointer(name) - return lib.dc_set_chat_name(self._dc_context, self.id, name) + return lib.dc_set_chat_name(self.account._dc_context, self.id, name) def mute(self, duration=None): """ mutes the chat @@ -117,7 +116,7 @@ class Chat(object): mute_duration = -1 else: mute_duration = duration - ret = lib.dc_set_chat_mute_duration(self._dc_context, self.id, mute_duration) + ret = lib.dc_set_chat_mute_duration(self.account._dc_context, self.id, mute_duration) if not bool(ret): raise ValueError("Call to dc_set_chat_mute_duration failed") @@ -126,7 +125,7 @@ class Chat(object): :returns: None """ - ret = lib.dc_set_chat_mute_duration(self._dc_context, self.id, 0) + ret = lib.dc_set_chat_mute_duration(self.account._dc_context, self.id, 0) if not bool(ret): raise ValueError("Failed to unmute chat") @@ -152,7 +151,7 @@ class Chat(object): in a second channel (typically used by mobiles with QRcode-show + scan UX) where account.join_with_qrcode(qr) needs to be called. """ - res = lib.dc_get_securejoin_qr(self._dc_context, self.id) + res = lib.dc_get_securejoin_qr(self.account._dc_context, self.id) return from_dc_charpointer(res) # ------ chat messaging API ------------------------------ @@ -174,7 +173,7 @@ class Chat(object): assert msg.id != 0 # get a fresh copy of dc_msg, the core needs it msg = Message.from_db(self.account, msg.id) - sent_id = lib.dc_send_msg(self._dc_context, self.id, msg._dc_msg) + sent_id = lib.dc_send_msg(self.account._dc_context, self.id, msg._dc_msg) if sent_id == 0: raise ValueError("message could not be sent") # modify message in place to avoid bad state for the caller @@ -189,7 +188,7 @@ class Chat(object): :returns: the resulting :class:`deltachat.message.Message` instance """ msg = as_dc_charpointer(text) - msg_id = lib.dc_send_text_msg(self._dc_context, self.id, msg) + msg_id = lib.dc_send_text_msg(self.account._dc_context, self.id, msg) if msg_id == 0: raise ValueError("message could not be send, does chat exist?") return Message.from_db(self.account, msg_id) @@ -204,7 +203,7 @@ class Chat(object): """ msg = Message.new_empty(self.account, view_type="file") msg.set_file(path, mime_type) - sent_id = lib.dc_send_msg(self._dc_context, self.id, msg._dc_msg) + sent_id = lib.dc_send_msg(self.account._dc_context, self.id, msg._dc_msg) if sent_id == 0: raise ValueError("message could not be sent") return Message.from_db(self.account, sent_id) @@ -219,7 +218,7 @@ class Chat(object): mime_type = mimetypes.guess_type(path)[0] msg = Message.new_empty(self.account, view_type="image") msg.set_file(path, mime_type) - sent_id = lib.dc_send_msg(self._dc_context, self.id, msg._dc_msg) + sent_id = lib.dc_send_msg(self.account._dc_context, self.id, msg._dc_msg) if sent_id == 0: raise ValueError("message could not be sent") return Message.from_db(self.account, sent_id) @@ -230,7 +229,7 @@ class Chat(object): :param msg: the message to be prepared. :returns: :class:`deltachat.message.Message` instance. """ - msg_id = lib.dc_prepare_msg(self._dc_context, self.id, msg._dc_msg) + msg_id = lib.dc_prepare_msg(self.account._dc_context, self.id, msg._dc_msg) if msg_id == 0: raise ValueError("message could not be prepared") # invalidate passed in message which is not safe to use anymore @@ -266,7 +265,7 @@ class Chat(object): msg = Message.from_db(self.account, message.id) # pass 0 as chat-id because core-docs say it's ok when out-preparing - sent_id = lib.dc_send_msg(self._dc_context, 0, msg._dc_msg) + sent_id = lib.dc_send_msg(self.account._dc_context, 0, msg._dc_msg) if sent_id == 0: raise ValueError("message could not be sent") assert sent_id == msg.id @@ -280,9 +279,9 @@ class Chat(object): :returns: None """ if message is None: - lib.dc_set_draft(self._dc_context, self.id, ffi.NULL) + lib.dc_set_draft(self.account._dc_context, self.id, ffi.NULL) else: - lib.dc_set_draft(self._dc_context, self.id, message._dc_msg) + lib.dc_set_draft(self.account._dc_context, self.id, message._dc_msg) def get_draft(self): """ get draft message for this chat. @@ -290,7 +289,7 @@ class Chat(object): :param message: a :class:`Message` instance :returns: Message object or None (if no draft available) """ - x = lib.dc_get_draft(self._dc_context, self.id) + x = lib.dc_get_draft(self.account._dc_context, self.id) if x == ffi.NULL: return None dc_msg = ffi.gc(x, lib.dc_msg_unref) @@ -302,7 +301,7 @@ class Chat(object): :returns: list of :class:`deltachat.message.Message` objects for this chat. """ dc_array = ffi.gc( - lib.dc_get_chat_msgs(self._dc_context, self.id, 0, 0), + lib.dc_get_chat_msgs(self.account._dc_context, self.id, 0, 0), lib.dc_array_unref ) return list(iter_array(dc_array, lambda x: Message.from_db(self.account, x))) @@ -312,18 +311,18 @@ class Chat(object): :returns: number of fresh messages """ - return lib.dc_get_fresh_msg_cnt(self._dc_context, self.id) + return lib.dc_get_fresh_msg_cnt(self.account._dc_context, self.id) def mark_noticed(self): """ mark all messages in this chat as noticed. Noticed messages are no longer fresh. """ - return lib.dc_marknoticed_chat(self._dc_context, self.id) + return lib.dc_marknoticed_chat(self.account._dc_context, self.id) def get_summary(self): """ return dictionary with summary information. """ - dc_res = lib.dc_chat_get_info_json(self._dc_context, self.id) + dc_res = lib.dc_chat_get_info_json(self.account._dc_context, self.id) s = from_dc_charpointer(dc_res) return json.loads(s) @@ -336,7 +335,7 @@ class Chat(object): :raises ValueError: if contact could not be added :returns: None """ - ret = lib.dc_add_contact_to_chat(self._dc_context, self.id, contact.id) + ret = lib.dc_add_contact_to_chat(self.account._dc_context, self.id, contact.id) if ret != 1: raise ValueError("could not add contact {!r} to chat".format(contact)) @@ -347,7 +346,7 @@ class Chat(object): :raises ValueError: if contact could not be removed :returns: None """ - ret = lib.dc_remove_contact_from_chat(self._dc_context, self.id, contact.id) + ret = lib.dc_remove_contact_from_chat(self.account._dc_context, self.id, contact.id) if ret != 1: raise ValueError("could not remove contact {!r} from chat".format(contact)) @@ -359,7 +358,7 @@ class Chat(object): """ from .contact import Contact dc_array = ffi.gc( - lib.dc_get_chat_contacts(self._dc_context, self.id), + lib.dc_get_chat_contacts(self.account._dc_context, self.id), lib.dc_array_unref ) return list(iter_array( @@ -378,7 +377,7 @@ class Chat(object): """ assert os.path.exists(img_path), img_path p = as_dc_charpointer(img_path) - res = lib.dc_set_chat_profile_image(self._dc_context, self.id, p) + res = lib.dc_set_chat_profile_image(self.account._dc_context, self.id, p) if res != 1: raise ValueError("Setting Profile Image {!r} failed".format(p)) @@ -391,7 +390,7 @@ class Chat(object): :raises ValueError: if profile image could not be reset :returns: None """ - res = lib.dc_set_chat_profile_image(self._dc_context, self.id, ffi.NULL) + res = lib.dc_set_chat_profile_image(self.account._dc_context, self.id, ffi.NULL) if res != 1: raise ValueError("Removing Profile Image failed") @@ -421,7 +420,7 @@ class Chat(object): """return True if this chat has location-sending enabled currently. :returns: True if location sending is enabled. """ - return lib.dc_is_sending_locations_to_chat(self._dc_context, self.id) + return lib.dc_is_sending_locations_to_chat(self.account._dc_context, self.id) def is_archived(self): """return True if this chat is archived. @@ -434,7 +433,7 @@ class Chat(object): all subsequent messages will carry a location with them. """ - lib.dc_send_locations_to_chat(self._dc_context, self.id, seconds) + lib.dc_send_locations_to_chat(self.account._dc_context, self.id, seconds) def get_locations(self, contact=None, timestamp_from=None, timestamp_to=None): """return list of locations for the given contact in the given timespan. @@ -458,7 +457,7 @@ class Chat(object): else: contact_id = contact.id - dc_array = lib.dc_get_locations(self._dc_context, self.id, contact_id, time_from, time_to) + dc_array = lib.dc_get_locations(self.account._dc_context, self.id, contact_id, time_from, time_to) return [ Location( latitude=lib.dc_array_get_latitude(dc_array, i), diff --git a/python/src/deltachat/contact.py b/python/src/deltachat/contact.py index 6e2cf1ae5..92e46f50c 100644 --- a/python/src/deltachat/contact.py +++ b/python/src/deltachat/contact.py @@ -12,22 +12,21 @@ class Contact(object): """ def __init__(self, account, id): self.account = account - self._dc_context = account._dc_context self.id = id def __eq__(self, other): - return self._dc_context == other._dc_context and self.id == other.id + return self.account._dc_context == other.account._dc_context and self.id == other.id def __ne__(self, other): return not (self == other) def __repr__(self): - return "".format(self.id, self.addr, self._dc_context) + return "".format(self.id, self.addr, self.account._dc_context) @property def _dc_contact(self): return ffi.gc( - lib.dc_get_contact(self._dc_context, self.id), + lib.dc_get_contact(self.account._dc_context, self.id), lib.dc_contact_unref ) diff --git a/python/src/deltachat/events.py b/python/src/deltachat/events.py index 10a59fc2c..d68f83dd3 100644 --- a/python/src/deltachat/events.py +++ b/python/src/deltachat/events.py @@ -133,8 +133,8 @@ class EventThread(threading.Thread): """ def __init__(self, account): self.account = account - self._dc_context = account._dc_context super(EventThread, self).__init__(name="events") + self.setDaemon(True) self.start() @contextmanager @@ -157,7 +157,7 @@ class EventThread(threading.Thread): def _inner_run(self): event_emitter = ffi.gc( - lib.dc_get_event_emitter(self._dc_context), + lib.dc_get_event_emitter(self.account._dc_context), lib.dc_event_emitter_unref, ) while 1: @@ -176,11 +176,15 @@ class EventThread(threading.Thread): lib.dc_event_unref(event) ffi_event = FFIEvent(name=evt_name, data1=data1, data2=data2) - self.account._pm.hook.ac_process_ffi_event(account=self, ffi_event=ffi_event) - for name, kwargs in self._map_ffi_event(ffi_event): - # self.account.log("calling hook name={} kwargs={}".format(name, kwargs)) - hook = getattr(self.account._pm.hook, name) - hook(**kwargs) + try: + self.account._pm.hook.ac_process_ffi_event(account=self, ffi_event=ffi_event) + for name, kwargs in self._map_ffi_event(ffi_event): + self.account.log("calling hook name={} kwargs={}".format(name, kwargs)) + hook = getattr(self.account._pm.hook, name) + hook(**kwargs) + except Exception: + if self.account._dc_context is not None: + raise def _map_ffi_event(self, ffi_event): name = ffi_event.name diff --git a/python/src/deltachat/hookspec.py b/python/src/deltachat/hookspec.py index b0e896aaf..b20d56027 100644 --- a/python/src/deltachat/hookspec.py +++ b/python/src/deltachat/hookspec.py @@ -89,5 +89,5 @@ class Global: """ called when `Account::__init__()` function starts executing. """ @global_hookspec - def dc_account_after_shutdown(self, account, dc_context): + def dc_account_after_shutdown(self, account): """ Called after the account has been shutdown. """ diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index 91cc738c0..706f8c8f5 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -16,8 +16,7 @@ class Message(object): """ def __init__(self, account, dc_msg): self.account = account - self._dc_context = account._dc_context - assert isinstance(self._dc_context, ffi.CData) + assert isinstance(self.account._dc_context, ffi.CData) assert isinstance(dc_msg, ffi.CData) assert dc_msg != ffi.NULL self._dc_msg = dc_msg @@ -58,7 +57,7 @@ class Message(object): """ self.account.create_chat_by_message(self) self._dc_msg = ffi.gc( - lib.dc_get_msg(self._dc_context, self.id), + lib.dc_get_msg(self.account._dc_context, self.id), lib.dc_msg_unref ) @@ -118,12 +117,12 @@ class Message(object): The text is multiline and may contain eg. the raw text of the message. """ - return from_dc_charpointer(lib.dc_get_msg_info(self._dc_context, self.id)) + return from_dc_charpointer(lib.dc_get_msg_info(self.account._dc_context, self.id)) def continue_key_transfer(self, setup_code): """ extract key and use it as primary key for this account. """ res = lib.dc_continue_key_transfer( - self._dc_context, + self.account._dc_context, self.id, as_dc_charpointer(setup_code) ) @@ -158,7 +157,7 @@ class Message(object): :returns: email-mime message object (with headers only, no body). """ import email.parser - mime_headers = lib.dc_get_mime_headers(self._dc_context, self.id) + mime_headers = lib.dc_get_mime_headers(self.account._dc_context, self.id) if mime_headers: s = ffi.string(ffi.gc(mime_headers, lib.dc_str_unref)) if isinstance(s, bytes): @@ -201,7 +200,7 @@ class Message(object): else: # load message from db to get a fresh/current state dc_msg = ffi.gc( - lib.dc_get_msg(self._dc_context, self.id), + lib.dc_get_msg(self.account._dc_context, self.id), lib.dc_msg_unref ) return lib.dc_msg_get_state(dc_msg) diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index ddc8ee9fc..a785d9cf0 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -103,7 +103,6 @@ def pytest_report_header(config, startdir): t = tempfile.mktemp() m = MonkeyPatch() try: - m.setattr(sys.stdout, "write", lambda x: len(x)) ac = Account(t) info = ac.get_info() ac.shutdown() @@ -310,16 +309,16 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, data): ac1 = self.get_online_configuring_account( pre_generated_key=pre_generated_key, mvbox=mvbox, move=move) ac1.wait_configure_finish() - ac1.start() + ac1.start_io() return ac1 def get_two_online_accounts(self, move=False, quiet=False): ac1 = self.get_online_configuring_account(move=True, quiet=quiet) ac2 = self.get_online_configuring_account(quiet=quiet) ac1.wait_configure_finish() - ac1.start() + ac1.start_io() ac2.wait_configure_finish() - ac2.start() + ac2.start_io() return ac1, ac2 def clone_online_account(self, account, pre_generated_key=True): @@ -394,6 +393,7 @@ class BotProcess: break line = line.strip() self.stdout_queue.put(line) + print("bot-stdout: ", line) finally: self.stdout_queue.put(None) diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 6315d136e..d134bc0a1 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -533,9 +533,9 @@ class TestOnlineAccount: # rsa key gen can be slow especially on CI, adjust timeout ac1._evtracker.set_timeout(120) ac1.wait_configure_finish() - ac1.start() + ac1.start_io() ac2.wait_configure_finish() - ac2.start() + ac2.start_io() chat = self.get_chat(ac1, ac2, both_created=True) lp.sec("ac1: send unencrypted message to ac2") @@ -591,11 +591,11 @@ class TestOnlineAccount: ac1_clone = acfactory.clone_online_account(ac1) ac1.wait_configure_finish() - ac1.start() + ac1.start_io() ac2.wait_configure_finish() - ac2.start() + ac2.start_io() ac1_clone.wait_configure_finish() - ac1_clone.start() + ac1_clone.start_io() chat = self.get_chat(ac1, ac2) @@ -700,11 +700,11 @@ class TestOnlineAccount: lp.sec("ac2: waiting for configuration") ac2.wait_configure_finish() - ac2.start() + ac2.start_io() lp.sec("ac1: waiting for configuration") ac1.wait_configure_finish() - ac1.start() + ac1.start_io() lp.sec("ac1: send message and wait for ac2 to receive it") chat = self.get_chat(ac1, ac2) @@ -717,9 +717,9 @@ class TestOnlineAccount: ac1 = acfactory.get_online_configuring_account() ac2 = acfactory.get_online_configuring_account(mvbox=True, move=True) ac2.wait_configure_finish() - ac2.start() + ac2.start_io() ac1.wait_configure_finish() - ac1.start() + ac1.start_io() chat = self.get_chat(ac1, ac2) chat.send_text("message1") ev = ac2._evtracker.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED") @@ -731,9 +731,9 @@ class TestOnlineAccount: ac1.set_config("bcc_self", "1") ac2 = acfactory.get_online_configuring_account() ac2.wait_configure_finish() - ac2.start() + ac2.start_io() ac1.wait_configure_finish() - ac1.start() + ac1.start_io() chat = self.get_chat(ac1, ac2) chat.send_text("message1") @@ -1162,9 +1162,9 @@ class TestOnlineAccount: ac1 = acfactory.get_online_configuring_account() ac2 = acfactory.clone_online_account(ac1) ac2.wait_configure_finish() - ac2.start() + ac2.start_io() ac1.wait_configure_finish() - ac1.start() + ac1.start_io() lp.sec("trigger ac setup message and return setupcode") assert ac1.get_info()["fingerprint"] != ac2.get_info()["fingerprint"] @@ -1188,9 +1188,9 @@ class TestOnlineAccount: ac2 = acfactory.clone_online_account(ac1) ac2._evtracker.set_timeout(30) ac2.wait_configure_finish() - ac2.start() + ac2.start_io() ac1.wait_configure_finish() - ac1.start() + ac1.start_io() lp.sec("trigger ac setup message but ignore") assert ac1.get_info()["fingerprint"] != ac2.get_info()["fingerprint"] @@ -1502,7 +1502,7 @@ class TestGroupStressTests: accounts = [acfactory.get_online_configuring_account() for i in range(5)] for acc in accounts: acc.wait_configure_finish() - acc.start() + acc.start_io() ac1 = accounts.pop() lp.sec("ac1: setting up contacts with 4 other members") @@ -1610,7 +1610,7 @@ class TestGroupStressTests: accounts = [acfactory.get_online_configuring_account() for i in range(3)] for acc in accounts: acc.wait_configure_finish() - acc.start() + acc.start_io() ac1 = accounts.pop() lp.sec("ac1: setting up contacts with 2 other members") diff --git a/python/tests/test_lowlevel.py b/python/tests/test_lowlevel.py index b8b66b61b..2e7640e36 100644 --- a/python/tests/test_lowlevel.py +++ b/python/tests/test_lowlevel.py @@ -36,13 +36,14 @@ def test_wrong_db(tmpdir): # write an invalid database file p.write("x123" * 10) - assert ffi.NULL == lib.dc_context_new(ffi.NULL, ffi.NULL, p.strpath.encode("ascii"), ffi.NULL) + assert ffi.NULL == lib.dc_context_new(ffi.NULL, p.strpath.encode("ascii"), ffi.NULL) + def test_empty_blobdir(tmpdir): db_fname = tmpdir.join("hello.db") # Apparently some client code expects this to be the same as passing NULL. ctx = ffi.gc( - lib.dc_context_new(ffi.NULL, ffi.NULL, db_fname.strpath.encode("ascii"), b""), + lib.dc_context_new(ffi.NULL, db_fname.strpath.encode("ascii"), b""), lib.dc_context_unref, ) assert ctx != ffi.NULL @@ -86,26 +87,16 @@ def test_get_special_message_id_returns_empty_message(acfactory): def test_provider_info_none(): ctx = ffi.gc( - lib.dc_context_new(ffi.NULL, ffi.NULL), + lib.dc_context_new(ffi.NULL, ffi.NULL, ffi.NULL), lib.dc_context_unref, ) assert lib.dc_provider_new_from_email(ctx, cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL -def test_get_info_closed(): - ctx = ffi.gc( - lib.dc_context_new(ffi.NULL, ffi.NULL), - lib.dc_context_unref, - ) - info = cutil.from_dc_charpointer(lib.dc_get_info(ctx)) - assert 'deltachat_core_version' in info - assert 'database_dir' not in info - - def test_get_info_open(tmpdir): db_fname = tmpdir.join("test.db") ctx = ffi.gc( - lib.dc_context_new(ffi.NULL, ffi.NULL, db_fname.strpath.encode("ascii"), ffi.NULL), + lib.dc_context_new(ffi.NULL, db_fname.strpath.encode("ascii"), ffi.NULL), lib.dc_context_unref, ) info = cutil.from_dc_charpointer(lib.dc_get_info(ctx))