diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb035a234a..5cc20deeb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -211,7 +211,7 @@ jobs: - name: Run python tests env: - DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} + CHATMAIL_DOMAIN: ${{ secrets.CHATMAIL_DOMAIN }} DCC_RS_TARGET: debug DCC_RS_DEV: ${{ github.workspace }} working-directory: python @@ -274,6 +274,6 @@ jobs: - name: Run deltachat-rpc-client tests env: - DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} + CHATMAIL_DOMAIN: ${{ secrets.CHATMAIL_DOMAIN }} working-directory: deltachat-rpc-client run: tox -e py diff --git a/.github/workflows/jsonrpc.yml b/.github/workflows/jsonrpc.yml index f479cf7c1c..493dabc8bd 100644 --- a/.github/workflows/jsonrpc.yml +++ b/.github/workflows/jsonrpc.yml @@ -31,7 +31,7 @@ jobs: working-directory: deltachat-jsonrpc/typescript run: npm run test env: - DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} + CHATMAIL_DOMAIN: ${{ secrets.CHATMAIL_DOMAIN }} - name: make sure websocket server version still builds working-directory: deltachat-jsonrpc run: cargo build --bin deltachat-jsonrpc-server --features webserver diff --git a/.github/workflows/node-tests.yml b/.github/workflows/node-tests.yml index 6dda52c39c..e41b971b55 100644 --- a/.github/workflows/node-tests.yml +++ b/.github/workflows/node-tests.yml @@ -63,5 +63,5 @@ jobs: working-directory: node run: npm run test env: - DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} + CHATMAIL_DOMAIN: ${{ secrets.CHATMAIL_DOMAIN }} NODE_OPTIONS: "--force-node-api-uncaught-exceptions-policy=true" diff --git a/deltachat-jsonrpc/README.md b/deltachat-jsonrpc/README.md index 3c8dad4dd7..7e8110652f 100644 --- a/deltachat-jsonrpc/README.md +++ b/deltachat-jsonrpc/README.md @@ -108,10 +108,10 @@ This will build the `deltachat-jsonrpc-server` binary and then run a test suite The test suite includes some tests that need online connectivity and a way to create test email accounts. To run these tests, talk to DeltaChat developers to get a token for the `testrun.org` service, or use a local instance of [`mailadm`](https://github.com/deltachat/docker-mailadm). -Then, set the `DCC_NEW_TMP_EMAIL` environment variable to your mailadm token before running the tests. +Then, set the `CHATMAIL_DOMAIN` environment variable to your testing email server domain. ``` -DCC_NEW_TMP_EMAIL=https://testrun.org/new_email?t=yourtoken npm run test +CHATMAIL_DOMAIN=chat.example.org npm run test ``` #### Test Coverage diff --git a/deltachat-jsonrpc/typescript/test/online.ts b/deltachat-jsonrpc/typescript/test/online.ts index c85376b095..92e42776b2 100644 --- a/deltachat-jsonrpc/typescript/test/online.ts +++ b/deltachat-jsonrpc/typescript/test/online.ts @@ -13,16 +13,16 @@ describe("online tests", function () { before(async function () { this.timeout(60000); - if (!process.env.DCC_NEW_TMP_EMAIL) { + if (!process.env.CHATMAIL_DOMAIN) { if (process.env.COVERAGE && !process.env.COVERAGE_OFFLINE) { console.error( - "CAN NOT RUN COVERAGE correctly: Missing DCC_NEW_TMP_EMAIL environment variable!\n\n", + "CAN NOT RUN COVERAGE correctly: Missing CHATMAIL_DOMAIN environment variable!\n\n", "You can set COVERAGE_OFFLINE=1 to circumvent this check and skip the online tests, but those coverage results will be wrong, because some functions can only be tested in the online test" ); process.exit(1); } console.log( - "Missing DCC_NEW_TMP_EMAIL environment variable!, skip integration tests" + "Missing CHATMAIL_DOMAIN environment variable!, skip integration tests" ); this.skip(); } @@ -33,7 +33,7 @@ describe("online tests", function () { if (kind !== "Info") console.log(contextId, kind); }); - account1 = await createTempUser(process.env.DCC_NEW_TMP_EMAIL); + account1 = createTempUser(process.env.CHATMAIL_DOMAIN); if (!account1 || !account1.email || !account1.password) { console.log( "We didn't got back an account from the api, skip integration tests" @@ -41,7 +41,7 @@ describe("online tests", function () { this.skip(); } - account2 = await createTempUser(process.env.DCC_NEW_TMP_EMAIL); + account2 = createTempUser(process.env.CHATMAIL_DOMAIN); if (!account2 || !account2.email || !account2.password) { console.log( "We didn't got back an account2 from the api, skip integration tests" diff --git a/deltachat-jsonrpc/typescript/test/test_base.ts b/deltachat-jsonrpc/typescript/test/test_base.ts index e8f6046329..935e5223dc 100644 --- a/deltachat-jsonrpc/typescript/test/test_base.ts +++ b/deltachat-jsonrpc/typescript/test/test_base.ts @@ -57,15 +57,14 @@ export async function startServer(): Promise { }; } -export async function createTempUser(url: string) { - const response = await fetch(url, { - method: "POST", - headers: { - "cache-control": "no-cache", - }, - }); - if (!response.ok) throw new Error("Received invalid response"); - return response.json(); +export function createTempUser(chatmailDomain: String) { + const charset = "2345789acdefghjkmnpqrstuvwxyz"; + let user = "ci-"; + for (let i = 0; i < 6; i++) { + user += charset[Math.floor(Math.random() * charset.length)]; + } + const email = user + "@" + chatmailDomain; + return { email: email, password: user + "$" + user }; } function getTargetDir(): Promise { diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py b/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py index 4d569d3ea9..3b276cae87 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py @@ -1,6 +1,5 @@ -import json import os -import urllib.request +import random from typing import AsyncGenerator, List, Optional import pytest @@ -10,12 +9,11 @@ def get_temp_credentials() -> dict: - url = os.getenv("DCC_NEW_TMP_EMAIL") - assert url, "Failed to get online account, DCC_NEW_TMP_EMAIL is not set" - - request = urllib.request.Request(url, method="POST") - with urllib.request.urlopen(request, timeout=60) as f: - return json.load(f) + domain = os.getenv("CHATMAIL_DOMAIN") + username = "ci-" + "".join(random.choice("2345789acdefghjkmnpqrstuvwxyz") for i in range(6)) + password = f"{username}${username}" + addr = f"{username}@{domain}" + return {"email": addr, "password": password} class ACFactory: diff --git a/deltachat-rpc-client/tox.ini b/deltachat-rpc-client/tox.ini index 81bb6c2638..3acc1dc3a3 100644 --- a/deltachat-rpc-client/tox.ini +++ b/deltachat-rpc-client/tox.ini @@ -11,7 +11,7 @@ setenv = # Avoid stack overflow when Rust core is built without optimizations. RUST_MIN_STACK=8388608 passenv = - DCC_NEW_TMP_EMAIL + CHATMAIL_DOMAIN deps = pytest pytest-timeout diff --git a/node/README.md b/node/README.md index 5628ac4a8b..8f75b0672a 100644 --- a/node/README.md +++ b/node/README.md @@ -204,10 +204,10 @@ Running `npm test` ends with showing a code coverage report, which is produced b The coverage report from `nyc` in the console is rather limited. To get a more detailed coverage report you can run `npm run coverage-html-report`. This will produce a html report from the `nyc` data and display it in a browser on your local machine. -To run the integration tests you need to set the `DCC_NEW_TMP_EMAIL` environment variables. E.g.: +To run the integration tests you need to set the `CHATMAIL_DOMAIN` environment variables. E.g.: ``` -$ export DCC_NEW_TMP_EMAIL=https://testrun.org/new_email?t=[token] +$ export CHATMAIL_DOMAIN=chat.example.org $ npm run test ``` diff --git a/node/test/test.js b/node/test/test.js index a8f72aa9fd..a467c2494b 100644 --- a/node/test/test.js +++ b/node/test/test.js @@ -12,22 +12,14 @@ import fetch from 'node-fetch' chai.use(chaiAsPromised) chai.config.truncateThreshold = 0 // Do not truncate assertion errors. -async function createTempUser(url) { - async function postData(url = '') { - // Default options are marked with * - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - headers: { - 'cache-control': 'no-cache', - }, - }) - if (!response.ok) { - throw new Error('request failed: ' + response.body.read()) - } - return response.json() // parses JSON response into native JavaScript objects +function createTempUser(chatmailDomain) { + const charset = "2345789acdefghjkmnpqrstuvwxyz"; + let user = "ci-"; + for (let i = 0; i < 6; i++) { + user += charset[Math.floor(Math.random() * charset.length)]; } - - return await postData(url) + const email = user + "@" + chatmailDomain; + return { email: email, password: user + "$" + user }; } describe('static tests', function () { @@ -768,14 +760,7 @@ describe('Integration tests', function () { }) this.beforeAll(async function () { - if (!process.env.DCC_NEW_TMP_EMAIL) { - console.log( - 'Missing DCC_NEW_TMP_EMAIL environment variable!, skip integration tests' - ) - this.skip() - } - - account = await createTempUser(process.env.DCC_NEW_TMP_EMAIL) + account = createTempUser(process.env.CHATMAIL_DOMAIN) if (!account || !account.email || !account.password) { console.log( "We didn't got back an account from the api, skip integration tests" diff --git a/python/README.rst b/python/README.rst index c5f0489129..c79185b365 100644 --- a/python/README.rst +++ b/python/README.rst @@ -53,14 +53,14 @@ end-to-end tests that require accounts on real e-mail servers. Running "live" tests with temporary accounts -------------------------------------------- -If you want to run live functional tests you can set ``DCC_NEW_TMP_EMAIL`` to a URL that creates e-mail accounts. Most developers use https://testrun.org URLs created and managed by `mailadm `_. +If you want to run live functional tests +you can set ``CHATMAIL_DOMAIN`` to a domain of the email server +that creates e-mail accounts like this:: -Please feel free to contact us through a github issue or by e-mail and we'll send you a URL that you can then use for functional tests like this:: + export CHATMAIL_DOMAIN=nine.testrun.org - export DCC_NEW_TMP_EMAIL= - -With this account-creation setting, pytest runs create ephemeral e-mail accounts on the http://testrun.org server. -These accounts are removed automatically as they expire. +With this account-creation setting, pytest runs create ephemeral e-mail accounts on the server. +These accounts have the pattern `ci-{6 characters}@{CHATMAIL_DOMAIN}`. After setting the variable, either rerun `scripts/run-python-test.sh` or run offline and online tests with `tox` directly:: @@ -159,6 +159,6 @@ find it with:: This docker image can be used to run tests and build Python wheels for all interpreters:: - $ docker run -e DCC_NEW_TMP_EMAIL \ + $ docker run -e CHATMAIL_DOMAIN \ --rm -it -v $(pwd):/mnt -w /mnt \ deltachat/coredeps scripts/run_all.sh diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index 944982475d..13904913b9 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -8,11 +8,11 @@ import threading import time import weakref +import random from queue import Queue from typing import Callable, Dict, List, Optional, Set import pytest -import requests from _pytest._code import Source import deltachat @@ -29,6 +29,12 @@ def pytest_addoption(parser): default=None, help="a file with >=2 lines where each line contains NAME=VALUE config settings for one account", ) + group.addoption( + "--chatmail", + action="store", + default=None, + help="chatmail server domain name", + ) group.addoption( "--ignored", action="store_true", @@ -53,10 +59,12 @@ def pytest_addoption(parser): def pytest_configure(config): cfg = config.getoption("--liveconfig") + + cfg = config.getoption("--chatmail") if not cfg: - cfg = os.getenv("DCC_NEW_TMP_EMAIL") + cfg = os.getenv("CHATMAIL_DOMAIN") if cfg: - config.option.liveconfig = cfg + config.option.chatmail = cfg # Make sure we don't get garbled output because threads keep running # collect all ever created accounts in a weakref-set (so we don't @@ -157,13 +165,29 @@ def get_liveconfig_producer(self): """provide live account configs, cached on a per-test-process scope so that test functions can re-use already known live configs. Depending on the --liveconfig option this comes from - a HTTP provider or a file with a line specifying each accounts config. + a file with a line specifying each accounts config + or a --chatmail domain. """ liveconfig_opt = self.pytestconfig.getoption("--liveconfig") - if not liveconfig_opt: - pytest.skip("specify DCC_NEW_TMP_EMAIL or --liveconfig to provide live accounts") - - if not liveconfig_opt.startswith("http"): + chatmail_opt = self.pytestconfig.getoption("--chatmail") + if chatmail_opt: + # Use a chatmail instance. + domain = chatmail_opt + MAX_LIVE_CREATED_ACCOUNTS = 10 + for index in range(MAX_LIVE_CREATED_ACCOUNTS): + try: + yield self._configlist[index] + except IndexError: + username = "ci-" + "".join(random.choice("2345789acdefghjkmnpqrstuvwxyz") for i in range(6)) + password = f"{username}${username}" + addr = f"{username}@{domain}" + 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.") + elif liveconfig_opt: + # Read a list of accounts from file. for line in open(liveconfig_opt): if line.strip() and not line.strip().startswith("#"): d = {} @@ -174,20 +198,9 @@ def get_liveconfig_producer(self): yield from iter(self._configlist) else: - MAX_LIVE_CREATED_ACCOUNTS = 10 - for index in range(MAX_LIVE_CREATED_ACCOUNTS): - try: - yield self._configlist[index] - except IndexError: - res = requests.post(liveconfig_opt, timeout=60) - if res.status_code != 200: - pytest.fail(f"newtmpuser count={index} code={res.status_code}: '{res.text}'") - d = res.json() - config = {"addr": d["email"], "mail_pw": d["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.skip( + "specify --liveconfig, 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) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 431463952f..915c87916c 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -2208,7 +2208,17 @@ def test_delete_multiple_messages(acfactory, lp): def test_trash_multiple_messages(acfactory, lp): ac1, ac2 = acfactory.get_online_accounts(2) + + # Create the Trash folder on IMAP server + # and recreate the account so Trash folder is configured. + lp.sec("Creating trash folder") + ac2.direct_imap.create_folder("Trash") + lp.sec("Creating new accounts") + ac2 = acfactory.new_online_configuring_account(cloned_from=ac2) + acfactory.bring_accounts_online() + ac2.set_config("delete_to_trash", "1") + assert ac2.get_config("configured_trash_folder") chat12 = acfactory.get_accepted_chat(ac1, ac2) lp.sec("ac1: sending 3 messages") @@ -2239,13 +2249,15 @@ def test_trash_multiple_messages(acfactory, lp): def test_configure_error_msgs_wrong_pw(acfactory): - configdict = acfactory.get_next_liveconfig() - ac1 = acfactory.get_unconfigured_account() - ac1.update_config(configdict) - ac1.set_config("mail_pw", "abc") # Wrong mail pw - ac1.configure() + (ac1,) = acfactory.get_online_accounts(1) + + ac2 = acfactory.get_unconfigured_account() + ac2.set_config("addr", ac1.get_config("addr")) + ac2.set_config("mail_pw", "abc") # Wrong mail pw + ac2.configure() while True: - ev = ac1._evtracker.get_matching("DC_EVENT_CONFIGURE_PROGRESS") + ev = ac2._evtracker.get_matching("DC_EVENT_CONFIGURE_PROGRESS") + print(f"Configuration progress: {ev.data1}") if ev.data1 == 0: break # Password is wrong so it definitely has to say something about "password" @@ -2548,7 +2560,7 @@ def test_invalid_password(self, acfactory): def test_invalid_user(self, acfactory): configdict = acfactory.get_next_liveconfig() ac1 = acfactory.get_unconfigured_account() - configdict["addr"] = "x" + configdict["addr"] + configdict["addr"] = "$" + configdict["addr"] ac1.update_config(configdict) configtracker = ac1.configure() configtracker.wait_progress(500) @@ -2557,7 +2569,7 @@ def test_invalid_user(self, acfactory): def test_invalid_domain(self, acfactory): configdict = acfactory.get_next_liveconfig() ac1 = acfactory.get_unconfigured_account() - configdict["addr"] += "x" + configdict["addr"] += "$" ac1.update_config(configdict) configtracker = ac1.configure() configtracker.wait_progress(500) diff --git a/python/tox.ini b/python/tox.ini index c7ccd95c37..5f9cc5094b 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -16,7 +16,7 @@ setenv = passenv = DCC_RS_DEV DCC_RS_TARGET - DCC_NEW_TMP_EMAIL + CHATMAIL_DOMAIN CARGO_TARGET_DIR RUSTC_WRAPPER deps = diff --git a/scripts/remote_tests_python.sh b/scripts/remote_tests_python.sh index c45003659d..e6aa740825 100755 --- a/scripts/remote_tests_python.sh +++ b/scripts/remote_tests_python.sh @@ -28,7 +28,7 @@ ssh $SSHTARGET <<_HERE export RUSTC_WRAPPER=\`which sccache\` cd $BUILDDIR export TARGET=release - export DCC_NEW_TMP_EMAIL=$DCC_NEW_TMP_EMAIL + export CHATMAIL_DOMAIN=$CHATMAIL_DOMAIN #we rely on tox/virtualenv being available in the host #rm -rf virtualenv venv diff --git a/scripts/run_all.sh b/scripts/run_all.sh index 42edb094f2..e465bddc64 100755 --- a/scripts/run_all.sh +++ b/scripts/run_all.sh @@ -27,7 +27,7 @@ mkdir -p $TOXWORKDIR # XXX we may switch on some live-tests on for better ensurances # Note that the independent remote_tests_python step does all kinds of # live-testing already. -unset DCC_NEW_TMP_EMAIL +unset CHATMAIL_DOMAIN # Try to build wheels for a range of interpreters, but don't fail if they are not available. # E.g. musllinux_1_1 does not have PyPy interpreters as of 2022-07-10