mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
test(python): don't reuse accounts
It is easier to create new chatmail accounts than reusing existing accounts and trying to clean them via IMAP. Cleaning an account via IMAP takes around 200 ms.
This commit is contained in:
@@ -143,82 +143,31 @@ def testprocess(request):
|
|||||||
class TestProcess:
|
class TestProcess:
|
||||||
"""A pytest session-scoped instance to help with managing "live" account configurations."""
|
"""A pytest session-scoped instance to help with managing "live" account configurations."""
|
||||||
|
|
||||||
_addr2files: Dict[str, Dict[pathlib.Path, bytes]]
|
|
||||||
|
|
||||||
def __init__(self, pytestconfig) -> None:
|
def __init__(self, pytestconfig) -> None:
|
||||||
self.pytestconfig = pytestconfig
|
self.pytestconfig = pytestconfig
|
||||||
self._addr2files = {}
|
self._addr2files = {}
|
||||||
self._configlist: List[Dict[str, str]] = []
|
|
||||||
|
|
||||||
def get_liveconfig_producer(self):
|
def get_liveconfig_producer(self):
|
||||||
"""provide live account configs, cached on a per-test-process scope
|
"""Provide live account configs"""
|
||||||
so that test functions can re-use already known live configs.
|
|
||||||
"""
|
|
||||||
chatmail_opt = self.pytestconfig.getoption("--chatmail")
|
chatmail_opt = self.pytestconfig.getoption("--chatmail")
|
||||||
if chatmail_opt:
|
if chatmail_opt:
|
||||||
# Use a chatmail instance.
|
# Use a chatmail instance.
|
||||||
domain = chatmail_opt
|
domain = chatmail_opt
|
||||||
MAX_LIVE_CREATED_ACCOUNTS = 10
|
MAX_LIVE_CREATED_ACCOUNTS = 10
|
||||||
for index in range(MAX_LIVE_CREATED_ACCOUNTS):
|
for index in range(MAX_LIVE_CREATED_ACCOUNTS):
|
||||||
try:
|
part = "".join(random.choices("2345789acdefghjkmnpqrstuvwxyz", k=6))
|
||||||
yield self._configlist[index]
|
username = f"ci-{part}"
|
||||||
except IndexError:
|
password = f"{username}${username}"
|
||||||
part = "".join(random.choices("2345789acdefghjkmnpqrstuvwxyz", k=6))
|
addr = f"{username}@{domain}"
|
||||||
username = f"ci-{part}"
|
config = {"addr": addr, "mail_pw": password}
|
||||||
password = f"{username}${username}"
|
print("newtmpuser {}: addr={}".format(index, config["addr"]))
|
||||||
addr = f"{username}@{domain}"
|
yield config
|
||||||
config = {"addr": addr, "mail_pw": password}
|
|
||||||
print("newtmpuser {}: addr={}".format(index, config["addr"]))
|
|
||||||
self._configlist.append(config)
|
|
||||||
yield config
|
|
||||||
pytest.fail(f"more than {MAX_LIVE_CREATED_ACCOUNTS} live accounts requested.")
|
pytest.fail(f"more than {MAX_LIVE_CREATED_ACCOUNTS} live accounts requested.")
|
||||||
else:
|
else:
|
||||||
pytest.skip(
|
pytest.skip(
|
||||||
"specify CHATMAIL_DOMAIN or --chatmail to provide live accounts",
|
"specify CHATMAIL_DOMAIN or --chatmail to provide live accounts",
|
||||||
)
|
)
|
||||||
|
|
||||||
def cache_maybe_retrieve_configured_db_files(self, cache_addr, db_target_path):
|
|
||||||
db_target_path = pathlib.Path(db_target_path)
|
|
||||||
assert not db_target_path.exists()
|
|
||||||
|
|
||||||
try:
|
|
||||||
filescache = self._addr2files[cache_addr]
|
|
||||||
except KeyError:
|
|
||||||
print("CACHE FAIL for", cache_addr)
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
print("CACHE HIT for", cache_addr)
|
|
||||||
targetdir = db_target_path.parent
|
|
||||||
write_dict_to_dir(filescache, targetdir)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def cache_maybe_store_configured_db_files(self, acc):
|
|
||||||
addr = acc.get_config("addr")
|
|
||||||
assert acc.is_configured()
|
|
||||||
# don't overwrite existing entries
|
|
||||||
if addr not in self._addr2files:
|
|
||||||
print("storing cache for", addr)
|
|
||||||
basedir = pathlib.Path(acc.get_blobdir()).parent
|
|
||||||
self._addr2files[addr] = create_dict_from_files_in_path(basedir)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def create_dict_from_files_in_path(base):
|
|
||||||
cachedict = {}
|
|
||||||
for path in base.glob("**/*"):
|
|
||||||
if path.is_file():
|
|
||||||
cachedict[path.relative_to(base)] = path.read_bytes()
|
|
||||||
return cachedict
|
|
||||||
|
|
||||||
|
|
||||||
def write_dict_to_dir(dic, target_dir):
|
|
||||||
assert dic
|
|
||||||
for relpath, content in dic.items():
|
|
||||||
path = target_dir.joinpath(relpath)
|
|
||||||
if not path.parent.exists():
|
|
||||||
os.makedirs(path.parent)
|
|
||||||
path.write_bytes(content)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def data(request):
|
def data(request):
|
||||||
@@ -275,7 +224,6 @@ class ACSetup:
|
|||||||
def __init__(self, testprocess, init_time) -> None:
|
def __init__(self, testprocess, init_time) -> None:
|
||||||
self._configured_events = Queue()
|
self._configured_events = Queue()
|
||||||
self._account2state: Dict[Account, str] = {}
|
self._account2state: Dict[Account, str] = {}
|
||||||
self._imap_cleaned: Set[str] = set()
|
|
||||||
self.testprocess = testprocess
|
self.testprocess = testprocess
|
||||||
self.init_time = init_time
|
self.init_time = init_time
|
||||||
|
|
||||||
@@ -359,17 +307,6 @@ class ACSetup:
|
|||||||
assert acc.is_configured()
|
assert acc.is_configured()
|
||||||
if not hasattr(acc, "direct_imap"):
|
if not hasattr(acc, "direct_imap"):
|
||||||
acc.direct_imap = DirectImap(acc)
|
acc.direct_imap = DirectImap(acc)
|
||||||
addr = acc.get_config("addr")
|
|
||||||
if addr not in self._imap_cleaned:
|
|
||||||
imap = acc.direct_imap
|
|
||||||
for folder in imap.list_folders():
|
|
||||||
if folder.lower() == "inbox" or folder.lower() == "deltachat":
|
|
||||||
assert imap.select_folder(folder)
|
|
||||||
imap.delete("1:*", expunge=True)
|
|
||||||
else:
|
|
||||||
imap.conn.folder.delete(folder)
|
|
||||||
acc.log(f"imap cleaned for addr {addr}")
|
|
||||||
self._imap_cleaned.add(addr)
|
|
||||||
|
|
||||||
|
|
||||||
class ACFactory:
|
class ACFactory:
|
||||||
@@ -431,20 +368,13 @@ class ACFactory:
|
|||||||
assert "addr" in configdict and "mail_pw" in configdict
|
assert "addr" in configdict and "mail_pw" in configdict
|
||||||
return configdict
|
return configdict
|
||||||
|
|
||||||
def _get_cached_account(self, addr) -> Optional[Account]:
|
|
||||||
if addr in self.testprocess._addr2files:
|
|
||||||
return self._getaccount(addr)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_unconfigured_account(self, closed=False) -> Account:
|
def get_unconfigured_account(self, closed=False) -> Account:
|
||||||
return self._getaccount(closed=closed)
|
return self._getaccount(closed=closed)
|
||||||
|
|
||||||
def _getaccount(self, try_cache_addr=None, closed=False) -> Account:
|
def _getaccount(self, closed=False) -> Account:
|
||||||
logid = f"ac{len(self._accounts) + 1}"
|
logid = f"ac{len(self._accounts) + 1}"
|
||||||
# we need to use fixed database basename for maybe_cache_* functions to work
|
# we need to use fixed database basename for maybe_cache_* functions to work
|
||||||
path = self.tmpdir.mkdir(logid).join("dc.db")
|
path = self.tmpdir.mkdir(logid).join("dc.db")
|
||||||
if try_cache_addr:
|
|
||||||
self.testprocess.cache_maybe_retrieve_configured_db_files(try_cache_addr, path)
|
|
||||||
ac = Account(path.strpath, logging=self._logging, closed=closed)
|
ac = Account(path.strpath, logging=self._logging, closed=closed)
|
||||||
ac._logid = logid # later instantiated FFIEventLogger needs this
|
ac._logid = logid # later instantiated FFIEventLogger needs this
|
||||||
ac._evtracker = ac.add_account_plugin(FFIEventTracker(ac))
|
ac._evtracker = ac.add_account_plugin(FFIEventTracker(ac))
|
||||||
@@ -493,7 +423,7 @@ class ACFactory:
|
|||||||
self._acsetup.init_logging(ac)
|
self._acsetup.init_logging(ac)
|
||||||
return ac
|
return ac
|
||||||
|
|
||||||
def new_online_configuring_account(self, cloned_from=None, cache=False, **kwargs) -> Account:
|
def new_online_configuring_account(self, cloned_from=None, **kwargs) -> Account:
|
||||||
if cloned_from is None:
|
if cloned_from is None:
|
||||||
configdict = self.get_next_liveconfig()
|
configdict = self.get_next_liveconfig()
|
||||||
else:
|
else:
|
||||||
@@ -505,12 +435,6 @@ class ACFactory:
|
|||||||
"smtp_certificate_checks": cloned_from.get_config("smtp_certificate_checks"),
|
"smtp_certificate_checks": cloned_from.get_config("smtp_certificate_checks"),
|
||||||
}
|
}
|
||||||
configdict.update(kwargs)
|
configdict.update(kwargs)
|
||||||
ac = self._get_cached_account(addr=configdict["addr"]) if cache else None
|
|
||||||
if ac is not None:
|
|
||||||
# make sure we consume a preconfig key, as if we had created a fresh account
|
|
||||||
self._preconfigured_keys.pop(0)
|
|
||||||
self._acsetup.add_configured(ac)
|
|
||||||
return ac
|
|
||||||
ac = self.prepare_account_from_liveconfig(configdict)
|
ac = self.prepare_account_from_liveconfig(configdict)
|
||||||
self._acsetup.start_configure(ac)
|
self._acsetup.start_configure(ac)
|
||||||
return ac
|
return ac
|
||||||
@@ -536,11 +460,8 @@ class ACFactory:
|
|||||||
print("all accounts online")
|
print("all accounts online")
|
||||||
|
|
||||||
def get_online_accounts(self, num):
|
def get_online_accounts(self, num):
|
||||||
accounts = [self.new_online_configuring_account(cache=True) for i in range(num)]
|
accounts = [self.new_online_configuring_account() for i in range(num)]
|
||||||
self.bring_accounts_online()
|
self.bring_accounts_online()
|
||||||
# we cache fully configured and started accounts
|
|
||||||
for acc in accounts:
|
|
||||||
self.testprocess.cache_maybe_store_configured_db_files(acc)
|
|
||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
def run_bot_process(self, module, ffi=True):
|
def run_bot_process(self, module, ffi=True):
|
||||||
|
|||||||
Reference in New Issue
Block a user