|
1 | 1 | import imaplib |
2 | | -import io |
3 | 2 | import itertools |
4 | 3 | import os |
5 | 4 | import random |
@@ -35,17 +34,24 @@ def pytest_runtest_setup(item): |
35 | 34 | pytest.skip("skipping slow test, use --slow to run") |
36 | 35 |
|
37 | 36 |
|
38 | | -@pytest.fixture(scope="session") |
39 | | -def chatmail_config(pytestconfig): |
40 | | - current = basedir = Path().resolve() |
| 37 | +def _get_chatmail_config(): |
| 38 | + current = Path().resolve() |
41 | 39 | while 1: |
42 | 40 | path = current.joinpath("chatmail.ini").resolve() |
43 | 41 | if path.exists(): |
44 | | - return read_config(path) |
| 42 | + return read_config(path), path |
45 | 43 | if current == current.parent: |
46 | 44 | break |
47 | 45 | current = current.parent |
| 46 | + return None, None |
48 | 47 |
|
| 48 | + |
| 49 | +@pytest.fixture(scope="session") |
| 50 | +def chatmail_config(pytestconfig): |
| 51 | + config, path = _get_chatmail_config() |
| 52 | + if config: |
| 53 | + return config |
| 54 | + basedir = Path().resolve() |
49 | 55 | pytest.skip(f"no chatmail.ini file found in {basedir} or parent dirs") |
50 | 56 |
|
51 | 57 |
|
@@ -73,10 +79,17 @@ def sshdomain2(maildomain2): |
73 | 79 |
|
74 | 80 |
|
75 | 81 | def pytest_report_header(): |
76 | | - domain = os.environ.get("CHATMAIL_DOMAIN") |
77 | | - if domain: |
78 | | - text = f"chatmail test instance: {domain}" |
79 | | - return ["-" * len(text), text, "-" * len(text)] |
| 82 | + config, path = _get_chatmail_config() |
| 83 | + domain2 = os.environ.get("CHATMAIL_DOMAIN2", "NOT SET") |
| 84 | + domain = config.mail_domain if config else "NOT SET" |
| 85 | + path = path if path else "NOT SET" |
| 86 | + |
| 87 | + lines = [ |
| 88 | + f"chatmail.ini {domain} location: {path}", |
| 89 | + f"chatmail2: {domain2}", |
| 90 | + ] |
| 91 | + sep = "-" * max(map(len, lines)) |
| 92 | + return [sep, *lines, sep] |
80 | 93 |
|
81 | 94 |
|
82 | 95 | @pytest.fixture |
@@ -283,78 +296,94 @@ def gen(domain=None): |
283 | 296 |
|
284 | 297 |
|
285 | 298 | # |
286 | | -# Delta Chat testplugin re-use |
| 299 | +# Delta Chat RPC-based test support |
287 | 300 | # use the cmfactory fixture to get chatmail instance accounts |
288 | 301 | # |
289 | 302 |
|
| 303 | +from deltachat_rpc_client import DeltaChat, Rpc |
290 | 304 |
|
291 | | -class ChatmailTestProcess: |
292 | | - """Provider for chatmail instance accounts as used by deltachat.testplugin.acfactory""" |
293 | 305 |
|
294 | | - def __init__(self, pytestconfig, maildomain, gencreds, chatmail_config): |
295 | | - self.pytestconfig = pytestconfig |
296 | | - self.maildomain = maildomain |
297 | | - assert "." in self.maildomain, maildomain |
| 306 | +class ChatmailACFactory: |
| 307 | + """RPC-based account factory for chatmail testing.""" |
| 308 | + |
| 309 | + def __init__(self, rpc, maildomain, gencreds, chatmail_config): |
| 310 | + self.dc = DeltaChat(rpc) |
| 311 | + self.rpc = rpc |
| 312 | + self._maildomain = maildomain |
298 | 313 | self.gencreds = gencreds |
299 | 314 | self.chatmail_config = chatmail_config |
300 | | - self._addr2files = {} |
301 | 315 |
|
302 | | - def get_liveconfig_producer(self): |
303 | | - while 1: |
304 | | - user, password = self.gencreds(self.maildomain) |
305 | | - config = { |
306 | | - "addr": user, |
307 | | - "mail_pw": password, |
308 | | - } |
309 | | - # speed up account configuration |
310 | | - config["mail_server"] = self.maildomain |
311 | | - config["send_server"] = self.maildomain |
312 | | - if self.chatmail_config.tls_cert_mode == "self": |
313 | | - # Accept self-signed TLS certificates |
314 | | - config["imap_certificate_checks"] = "3" |
315 | | - yield config |
316 | | - |
317 | | - def cache_maybe_retrieve_configured_db_files(self, cache_addr, db_target_path): |
318 | | - pass |
319 | | - |
320 | | - def cache_maybe_store_configured_db_files(self, acc): |
321 | | - pass |
| 316 | + def _make_transport(self, domain): |
| 317 | + """Build a transport config dict for the given domain.""" |
| 318 | + addr, password = self.gencreds(domain) |
| 319 | + transport = { |
| 320 | + "addr": addr, |
| 321 | + "password": password, |
| 322 | + # Setting server explicitly skips requesting autoconfig XML, |
| 323 | + # see https://datatracker.ietf.org/doc/draft-ietf-mailmaint-autoconfig/ |
| 324 | + "imapServer": domain, |
| 325 | + "smtpServer": domain, |
| 326 | + } |
| 327 | + if self.chatmail_config.tls_cert_mode == "self": |
| 328 | + transport["certificateChecks"] = "acceptInvalidCertificates" |
| 329 | + return transport |
| 330 | + |
| 331 | + def get_online_account(self, domain=None): |
| 332 | + """Create, configure and bring online a single account.""" |
| 333 | + return self.get_online_accounts(1, domain)[0] |
| 334 | + |
| 335 | + def get_online_accounts(self, num, domain=None): |
| 336 | + """Create multiple online accounts in parallel.""" |
| 337 | + domain = domain or self._maildomain |
| 338 | + futures = [] |
| 339 | + accounts = [] |
| 340 | + for _ in range(num): |
| 341 | + account = self.dc.add_account() |
| 342 | + future = account.add_or_update_transport.future( |
| 343 | + self._make_transport(domain) |
| 344 | + ) |
| 345 | + futures.append(future) |
322 | 346 |
|
| 347 | + # ensure messages stay in INBOX so that they can be |
| 348 | + # concurrently fetched via extra IMAP connections during tests |
| 349 | + account.set_config("delete_server_after", "10") |
| 350 | + accounts.append(account) |
323 | 351 |
|
324 | | -@pytest.fixture |
325 | | -def cmfactory(request, gencreds, tmpdir, maildomain, chatmail_config): |
326 | | - # cloned from deltachat.testplugin.amfactory |
327 | | - pytest.importorskip("deltachat") |
328 | | - from deltachat.testplugin import ACFactory |
| 352 | + for future in futures: |
| 353 | + future() |
329 | 354 |
|
330 | | - testproc = ChatmailTestProcess( |
331 | | - request.config, maildomain, gencreds, chatmail_config |
332 | | - ) |
| 355 | + for account in accounts: |
| 356 | + account.bring_online() |
| 357 | + return accounts |
333 | 358 |
|
334 | | - class Data: |
335 | | - def read_path(self, path): |
336 | | - return |
| 359 | + def get_accepted_chat(self, ac1, ac2): |
| 360 | + """Create a 1:1 chat between ac1 and ac2 accepted on both sides.""" |
| 361 | + ac2.create_chat(ac1) |
| 362 | + return ac1.create_chat(ac2) |
337 | 363 |
|
338 | | - am = ACFactory(request=request, tmpdir=tmpdir, testprocess=testproc, data=Data()) |
339 | 364 |
|
340 | | - # Skip upstream's init_imap to prevent extra imap connections not |
341 | | - # needed for relay testing |
342 | | - am._acsetup.init_imap = lambda acc: None |
| 365 | +@pytest.fixture(scope="session") |
| 366 | +def rpc(tmp_path_factory): |
| 367 | + """Start a deltachat-rpc-server process for the test session.""" |
343 | 368 |
|
344 | | - # nb. a bit hacky |
345 | | - # would probably be better if deltachat's test machinery grows native support |
346 | | - def switch_maildomain(maildomain2): |
347 | | - am.testprocess.maildomain = maildomain2 |
| 369 | + # NB: accounts_dir must NOT already exist as directory -- |
| 370 | + # core-rust only creates accounts.toml if the dir doesn't exist yet. |
| 371 | + accounts_dir = str(tmp_path_factory.mktemp("dc") / "accounts") |
| 372 | + rpc = Rpc(accounts_dir=accounts_dir) |
| 373 | + rpc.start() |
| 374 | + yield rpc |
| 375 | + rpc.close() |
348 | 376 |
|
349 | | - am.switch_maildomain = switch_maildomain |
350 | 377 |
|
351 | | - yield am |
352 | | - if hasattr(request.node, "rep_call") and request.node.rep_call.failed: |
353 | | - if testproc.pytestconfig.getoption("--extra-info"): |
354 | | - logfile = io.StringIO() |
355 | | - am.dump_imap_summary(logfile=logfile) |
356 | | - print(logfile.getvalue()) |
357 | | - # request.node.add_report_section("call", "imap-server-state", s) |
| 378 | +@pytest.fixture |
| 379 | +def cmfactory(rpc, gencreds, maildomain, chatmail_config): |
| 380 | + """Return a ChatmailACFactory for creating online Delta Chat accounts.""" |
| 381 | + return ChatmailACFactory( |
| 382 | + rpc=rpc, |
| 383 | + maildomain=maildomain, |
| 384 | + gencreds=gencreds, |
| 385 | + chatmail_config=chatmail_config, |
| 386 | + ) |
358 | 387 |
|
359 | 388 |
|
360 | 389 | @pytest.fixture |
|
0 commit comments