Skip to content

Integration Tests

These integration tests illustrate what side effects are handled how.

Running these tests

By running

poetry run pytest tests/test_runner.py

one can run the integration tests, that tests the pure bovine_process functions. By running

poetry run pytest tests/test_rabbit.py

One can run the integration tests with an in memory AMQP server. This then also tests the implementation of bovine_propan.

Defining tests

Current tests definitions can be found here. The basic process is that each file defines a function build_step that returns a list of Steps defined by

tests.data.Step dataclass

Defines a test step for integration testing bovine_process

Parameters:

Name Type Description Default
incoming_activities Optional[list]

Activities received at inbox endpoint

None
outgoing_activities Optional[list]

Activities send to the Fediverse

None
database_content Optional[list]

content of the database (as JSON objects)

None
database_collections Optional[list]

The values contained in collections (inbox, outbox, likes, …)

None
send_items Optional[list]

Activities send to remote inboxes

None
responses Optional[dict]

Mock response for remote requests

None
Source code in bovine_process/tests/data/__init__.py
@dataclass
class Step:
    """Defines a test step for integration testing bovine_process

    :param incoming_activities: Activities received at inbox endpoint
    :param outgoing_activities: Activities send to the Fediverse
    :param database_content: content of the database (as JSON objects)
    :param database_collections: The values contained in collections (inbox, outbox, likes, ...)
    :param send_items: Activities send to remote inboxes
    :param responses: Mock response for remote requests
    """

    incoming_activities: Optional[list] = None
    outgoing_activities: Optional[list] = None
    database_content: Optional[list] = None
    database_collections: Optional[list] = None
    send_items: Optional[list] = None
    responses: Optional[dict] = None

The simplest example is the empty test, given by

from . import Step


def build_steps(local_actor, local_activity_factory, local_object_factory):
    return [
        Step(
            incoming_activities=[],
            outgoing_activities=[],
            database_content=[],
            database_collections=[],
        )
    ]

This test can shows that if nothing comes in or goes out, nothing happens.

The build_steps function

We note that local_actor is a dictionary containing the result from the build() method of the bovine.activitystreams.Actor who is the recipient/sender of the Activities. local_activity_factory is the corresponding ActivityFactory and local_object_factory is the ObjectFactory. These can be used to create the objects that are being tested.

We note that as bovine currently uses the with_bovine_context to sanitize incoming json-ld, the objects stored in the database will be slightly different to the once created by the methods.

Test discovery

First the available test cases are collected using

tests.utils.files_to_test()

Lists test files to run integration test with. This is done by collecting all python files in test/data/ excluding __init__.py.

By specifying the environment variable TEST_NAME one can restrict tests to ones containing its value.

Source code in bovine_process/tests/utils.py
def files_to_test():
    """Lists test files to run integration test with. This is
    done by collecting all python files in `test/data/` excluding
    `__init__.py`.

    By specifying the environment variable `TEST_NAME` one can
    restrict tests to ones containing its value."""
    if os.environ.get("TEST_NAME"):
        return [
            (x, y)
            for x in glob("tests/data/*.py")
            for y in [True, False]
            if os.environ.get("TEST_NAME") in x and "__init__" not in x
        ]

    return [
        (x, y)
        for x in glob("tests/data/*.py")
        for y in [True, False]
        if "__init__" not in x
    ]

Then the tests are loaded using

tests.load.load_test_data(file_path, local_actor)

Loads the build_step function contained in file_path

Parameters:

Name Type Description Default
file_path str

path to file

required
local_actor dict

actor from whose point of view the test is executed

required

Returns:

Type Description
List[Step]

steps to execute

Source code in bovine_process/tests/load.py
def load_test_data(file_path: str, local_actor: dict) -> List[Step]:  # noqa F811
    """Loads the `build_step` function contained in
    `file_path`

    :param file_path: path to file
    :param local_actor: actor from whose point of view the test is executed

    :return: steps to execute
    """
    local_activity_factory, local_object_factory = factories_for_actor_object(
        local_actor
    )

    module_name = ".".join(file_path.split(".")[0].split("/"))

    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)

    return module.build_steps(local_actor, local_activity_factory, local_object_factory)