2023-03-30 04:56:03 -04:00
|
|
|
"""
|
|
|
|
This module contains integration tests meant to run against a test Mastodon instance.
|
|
|
|
|
|
|
|
You can set up a test instance locally by following this guide:
|
|
|
|
https://docs.joinmastodon.org/dev/setup/
|
|
|
|
|
|
|
|
To enable integration tests, export the following environment variables to match
|
|
|
|
your test server and database:
|
|
|
|
|
|
|
|
```
|
2023-06-28 08:42:44 -04:00
|
|
|
export TOOT_TEST_BASE_URL="localhost:3000"
|
2023-03-30 04:56:03 -04:00
|
|
|
```
|
|
|
|
"""
|
|
|
|
|
2023-11-21 12:16:23 -05:00
|
|
|
import json
|
2023-03-30 04:56:03 -04:00
|
|
|
import os
|
|
|
|
import pytest
|
2023-12-19 05:28:25 -05:00
|
|
|
import re
|
|
|
|
import typing as t
|
2023-03-30 04:56:03 -04:00
|
|
|
import uuid
|
|
|
|
|
2023-11-26 12:00:57 -05:00
|
|
|
from click.testing import CliRunner, Result
|
2023-03-30 04:56:03 -04:00
|
|
|
from pathlib import Path
|
|
|
|
from toot import api, App, User
|
2023-12-14 05:35:52 -05:00
|
|
|
from toot.cli import Context, TootObj
|
2023-03-30 04:56:03 -04:00
|
|
|
|
|
|
|
|
2023-06-28 08:55:28 -04:00
|
|
|
def pytest_configure(config):
|
|
|
|
import toot.settings
|
|
|
|
toot.settings.DISABLE_SETTINGS = True
|
|
|
|
|
|
|
|
|
2023-12-19 05:28:25 -05:00
|
|
|
# Type alias for run commands
|
|
|
|
Run = t.Callable[..., Result]
|
|
|
|
|
2023-03-30 04:56:03 -04:00
|
|
|
# Mastodon database name, used to confirm user registration without having to click the link
|
2023-11-30 14:08:59 -05:00
|
|
|
TOOT_TEST_BASE_URL = os.getenv("TOOT_TEST_BASE_URL")
|
2023-03-30 04:56:03 -04:00
|
|
|
|
|
|
|
# Toot logo used for testing image upload
|
|
|
|
TRUMPET = str(Path(__file__).parent.parent.parent / "trumpet.png")
|
|
|
|
|
|
|
|
ASSETS_DIR = str(Path(__file__).parent.parent / "assets")
|
|
|
|
|
2024-04-06 07:11:33 -04:00
|
|
|
PASSWORD = "83dU29170rjKilKQQwuWhJv3PKnSW59bWx0perjP6i7Nu4rkeh4mRfYuvVLYM3fM"
|
|
|
|
|
2023-03-30 04:56:03 -04:00
|
|
|
|
2023-04-07 05:07:38 -04:00
|
|
|
def create_app(base_url):
|
2023-11-21 03:55:29 -05:00
|
|
|
instance = api.get_instance(base_url).json()
|
2023-04-07 05:07:38 -04:00
|
|
|
response = api.create_app(base_url)
|
|
|
|
return App(instance["uri"], base_url, response["client_id"], response["client_secret"])
|
2023-03-30 04:56:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
def register_account(app: App):
|
|
|
|
username = str(uuid.uuid4())[-10:]
|
|
|
|
email = f"{username}@example.com"
|
|
|
|
|
2024-04-06 07:11:33 -04:00
|
|
|
response = api.register_account(app, username, email, PASSWORD, "en")
|
2023-03-30 04:56:03 -04:00
|
|
|
return User(app.instance, username, response["access_token"])
|
|
|
|
|
|
|
|
|
2023-04-07 05:07:38 -04:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Fixtures
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
# Host name of a test instance to run integration tests against
|
|
|
|
# DO NOT USE PUBLIC INSTANCES!!!
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def base_url():
|
2023-11-30 14:08:59 -05:00
|
|
|
if not TOOT_TEST_BASE_URL:
|
2023-04-07 05:07:38 -04:00
|
|
|
pytest.skip("Skipping integration tests, TOOT_TEST_BASE_URL not set")
|
|
|
|
|
2023-11-30 14:08:59 -05:00
|
|
|
return TOOT_TEST_BASE_URL
|
2023-04-07 05:07:38 -04:00
|
|
|
|
|
|
|
|
2023-03-30 04:56:03 -04:00
|
|
|
@pytest.fixture(scope="session")
|
2023-04-07 05:07:38 -04:00
|
|
|
def app(base_url):
|
|
|
|
return create_app(base_url)
|
2023-03-30 04:56:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def user(app):
|
|
|
|
return register_account(app)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def friend(app):
|
|
|
|
return register_account(app)
|
|
|
|
|
|
|
|
|
2023-11-21 12:16:23 -05:00
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def user_id(app, user):
|
|
|
|
return api.find_account(app, user, user.username)["id"]
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def friend_id(app, user, friend):
|
|
|
|
return api.find_account(app, user, friend.username)["id"]
|
|
|
|
|
|
|
|
|
2023-11-26 12:00:57 -05:00
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
|
|
def testing_env():
|
|
|
|
os.environ["TOOT_TESTING"] = "true"
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def runner():
|
|
|
|
return CliRunner(mix_stderr=False)
|
|
|
|
|
|
|
|
|
2023-03-30 04:56:03 -04:00
|
|
|
@pytest.fixture
|
2023-11-26 12:00:57 -05:00
|
|
|
def run(app, user, runner):
|
2023-12-03 01:07:18 -05:00
|
|
|
def _run(command, *params, input=None) -> Result:
|
2023-12-14 04:11:09 -05:00
|
|
|
obj = TootObj(test_ctx=Context(app, user))
|
|
|
|
return runner.invoke(command, params, obj=obj, input=input)
|
2023-03-30 04:56:03 -04:00
|
|
|
return _run
|
|
|
|
|
|
|
|
|
2023-12-03 01:07:18 -05:00
|
|
|
@pytest.fixture
|
|
|
|
def run_as(app, runner):
|
|
|
|
def _run_as(user, command, *params, input=None) -> Result:
|
2023-12-14 04:11:09 -05:00
|
|
|
obj = TootObj(test_ctx=Context(app, user))
|
|
|
|
return runner.invoke(command, params, obj=obj, input=input)
|
2023-12-03 01:07:18 -05:00
|
|
|
return _run_as
|
|
|
|
|
|
|
|
|
2023-11-21 12:16:23 -05:00
|
|
|
@pytest.fixture
|
2023-11-28 08:05:44 -05:00
|
|
|
def run_json(app, user, runner):
|
2023-11-21 12:16:23 -05:00
|
|
|
def _run_json(command, *params):
|
2023-12-14 04:11:09 -05:00
|
|
|
obj = TootObj(test_ctx=Context(app, user))
|
|
|
|
result = runner.invoke(command, params, obj=obj)
|
2023-11-28 08:05:44 -05:00
|
|
|
assert result.exit_code == 0
|
|
|
|
return json.loads(result.stdout)
|
2023-11-21 12:16:23 -05:00
|
|
|
return _run_json
|
|
|
|
|
|
|
|
|
2023-03-30 04:56:03 -04:00
|
|
|
@pytest.fixture
|
2023-11-26 12:00:57 -05:00
|
|
|
def run_anon(runner):
|
|
|
|
def _run(command, *params) -> Result:
|
2023-12-14 04:11:09 -05:00
|
|
|
obj = TootObj(test_ctx=Context(None, None))
|
|
|
|
return runner.invoke(command, params, obj=obj)
|
2023-03-30 04:56:03 -04:00
|
|
|
return _run
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Utils
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
def posted_status_id(out):
|
|
|
|
pattern = re.compile(r"Toot posted: http://([^/]+)/([^/]+)/(.+)")
|
|
|
|
match = re.search(pattern, out)
|
|
|
|
assert match
|
|
|
|
|
|
|
|
_, _, status_id = match.groups()
|
|
|
|
|
|
|
|
return status_id
|