Skip to content

BDD Tests and reporting Reporting

Warning

This code is meant for testing and not to be enabled in a production setting.

Running BDD tests

cattle_grid uses a set of Gherkin tests provided by fediverse-features. They are currently configured using

fediverse-features.toml
tag = "0.1.9"

features = [
    "w3c/ap_follow.feature",
    "w3c/ap_unfollow.feature",
    "w3c/ap_follow_messaging.feature",
    "w3c/ap_block.feature",
    "w3c/ap_unblock.feature",
    "fedi/node_info.feature"
]

First download the features via

uv sync --frozen
uv run fediverse-features

Second start the docker containers and the runner

docker compose up --wait
docker compose run --rm runner

Starting the containers will take some time. The BDD tests can then be run via

uv run behave

inside the runner container.

Configuration

Reporting can be enabled by setting

cattle_grid.toml
enable_reporting = true

Generated reports are stored in the reports directory. A somewhat current set of reports is available at cattle_grid_reports.

cattle_grid.testing.reporter

Made as a tool to create reports from test runs done using behave. Basically, a scenario is run, and a markdown file is created.

Currently recorded are the step, the scenario, messages received on the incoming.# and outgoing.# routing keys of the cattle_grid exchange.

Finally, fetch results from gateway are reported.

fetch_result_reporting(msg, routing_key=Context('message.raw_message.routing_key')) async

Records the result of performed fetch requests

Source code in cattle_grid/testing/reporter.py
@router.subscriber(
    RabbitQueue("reporting_fetch_result", routing_key="receive.#"),
    account_exchange(),
)
async def fetch_result_reporting(
    msg: dict,
    routing_key=Context("message.raw_message.routing_key"),
):
    """Records the result of performed fetch requests"""
    if not current_file:
        return
    if msg.get("action") != "fetch_result":
        return {}

    async with current_file_handler() as fp:
        fp.writelines(
            [
                f"""

```json title="{routing_key}"
""",
                json.dumps(msg, indent=2),
                "\n```\n\n",
            ]
        )

    return {}

reporting_incoming_outgoing(msg, routing_key=Context('message.raw_message.routing_key')) async

Records incoming and outgoing messages

Source code in cattle_grid/testing/reporter.py
@router.subscriber(
    RabbitQueue("processing_reporting_in", routing_key="incoming.#"),
    internal_exchange(),
)
@router.subscriber(
    RabbitQueue("processing_reporting_out", routing_key="outgoing.#"),
    internal_exchange(),
)
async def reporting_incoming_outgoing(
    msg: dict,
    routing_key=Context("message.raw_message.routing_key"),
):
    """Records incoming and outgoing messages"""
    if not current_file:
        return
    async with current_file_handler() as fp:
        fp.writelines(
            [
                f"""

```json title="{routing_key}"
""",
                json.dumps(msg, indent=2),
                "\n```\n\n",
            ]
        )

    return {}

reporting_scenario(msg) async

Reports the scenario.

Note every scenario is written to its own file in the reports directory.

Source code in cattle_grid/testing/reporter.py
@router.subscriber(RabbitQueue("scenario_queue", routing_key="scenario"), exchange)
async def reporting_scenario(msg):
    """Reports the scenario.

    Note every scenario is written to its own file in the `reports` directory."""
    scenario = msg.get("name")
    async with lock:
        global current_file
        scenario_alpha = "".join([x for x in scenario if x.isalpha()])
        current_file = f"reports/{scenario_alpha}.md"

    async with current_file_handler(mode="w") as fp:
        fp.writelines([f"#{scenario}\n\n"])

reporting_step(msg) async

Reports the current step

Source code in cattle_grid/testing/reporter.py
@router.subscriber(RabbitQueue("step_queue", routing_key="step"), exchange)
async def reporting_step(msg):
    """Reports the current step"""
    if not current_file:
        return

    async with current_file_handler() as fp:
        fp.writelines(["## " + msg.get("type") + ": " + msg.get("name") + "\n\n"])