Tags: how-to, developer, end-to-end-test

Safely writing system/end-to-end tests#

Note

This page has been migrated from the old documentation, and has not yet been fully revised. There might be inconsistencies or errors when using with current LinkAhead versions.

When writing system or end-to-end tests, both when developing LinkAhead itself and when developing your LinkAhead custom code, we often need to write/update/or delete entities – we might even want to clear the entire database before and after running the tests, as it is done, for example, in the LinkAhead Python Integration Tests. Of course, we do not want to accidentally run such a test suite against a production LinkAhead instance.

Luckily LinkAhead offers infrastructure that ensures that system tests are only run against the LinkAhead instance that they are intended to, and no other instance. This tutorial explains how to set up this infrastructure.

The test infrastructure is implemented in the linkahead.utils.register_tests and requires an environment variable _CAOSDB_INTEGRATION_TEST_SUITE_KEY in the LinkAhead server. If you’re using LinkAhead control, you can set this variable in your profile.yml.

profile-name: # Usually, this is "default"
  conf:
    server:
      conf:
        # Sets the environment variable for the LinkAhead server
        # inside the docker container.
        _CAOSDB_INTEGRATION_TEST_SUITE_KEY: "MY_TEST_KEY_STRING"

Warning

For safety reasons, never set _CAOSDB_INTEGRATION_TEST_SUITE_KEY on a server used for production.

Once this environment variable is set, we can use the linkahead.utils.register_tests.set_key function to register our system test file(s). Assume you’re writing your tests in a file called test_system.py, you import this function and use it at the top of your code.

from linkahead.utils import register_tests

register_tests.set_key("MY_TEST_KEY_STRING")

Afterward you can use, e.g., the clear_database fixture to wipe the database before and after executing a specific test.

import linkahead as db
from linkahead.utils import register_tests

register_tests.set_key("MY_TEST_KEY_STRING")


# You can use a pytest fixture as an argument of your test function,
# see https://docs.pytest.org/en/7.1.x/how-to/fixtures.html.
def test_is_empty(register_tests.clear_database):
	# Test that there is no entity in the database
	assert db.execute_query("COUNT ENTITY") == 0

If you had registered the tests with a different key, i.e., called register_tests.set_key with argument that doesn’t match the value of _CAOSDB_INTEGRATION_TEST_SUITE_KEY, the clear_database fixture would have raised an error and would not have deleted anything.

In case you want to use more specific write or delete actions before or after running your tests, you can use the register_tests._assure_test_is_registered method which compares the registered key with the server environment variable and raises an error if they don’t match. This method needs to be called before any write transaction is executed, of course. In a test function, this could look the following.

def test_insert_and_delete():
	# Check before writing
	register_tests._assure_test_is_registered()
	# Test that a RecordType can be inserted and deleted
	rt = db.RecordType(name="TestType").insert()
	assert len(db.execute_query(f"FIND RECORDTYPE WITH id={rt.id}")) == 1
	rt.delete()
	assert len(db.execute_query(f"FIND RECORDTYPE WITH id={rt.id}")) == 0

Setting the test key interactively#

The above explanations work when running your system tests manually by executing pytest on the command line yourself and in an automated setting like a CI pipeline. When running a test that uses the register_tests module interactively against a server that does not have the _CAOSDB_INTEGRATION_TEST_SUITE_KEY environment variable, you will be asked whether you want to register the test the first time you run it. If you agree, the environment variable is set by the register_tests module. This requires your server to run in debug mode, e.g., by having

profile-name: # Usually, this is "default"
  conf:
    debug: true

in your profile.yml. Otherwise, the environment variable can’t be set by the client.