TESTING.md
SpacetimeDB has good test coverage, but it is rather haphazardly spread across several suites. Some of the reasons for this are historical, and some have to do with our using multiple repositories. This document is an attempt to describe the test suites which would be useful to someone working on a new client SDK or module bindings library in a new language, or attempting to move an existing client SDK or module bindings library from an external repository in-tree.
crates/testing/src/sdk.rs defines a test harness which was originally designed for testing client SDKs.
The basic flow of a test using this harness is:
spacetime generate into a client project.Identity in an environment variable.This framework has since been used more generally for integration testing.
In particular, we maintain equivalent Rust, C#, TypeScript, and C++ modules in the modules/sdk-test* family,
and run the Rust SDK client project at sdks/rust/tests/test-client against them through sdks/rust/tests/test.rs.
We similarly maintain modules/sdk-test-connect-disconnect* modules
which run against sdks/rust/tests/connect_disconnect_client.
There are also related SDK-harness-driven suites for event tables, procedures, and views,
using modules such as modules/sdk-test-event-table, modules/sdk-test-procedure*, and modules/sdk-test-view*.
The Unreal SDK also uses the same underlying harness through sdks/unreal/tests/sdk_unreal_harness.rs.
The harness is designed to support running multiple tests in parallel with the same client project,
running client codegen exactly once per test suite run.
This unfortunately still conflicts with our use of the suite to test that modules in different languages behave the same,
as each test suite invocation will only run spacetime generate against one module language at a time,
never all of them in the same run.
If you are developing a new module bindings library, and wish to add it to the SDK test suite so that the existing client test projects will run against it:
modules/sdk-test-XX and modules/sdk-test-connect-disconnect-XX, where XX is some mnemonic for your language.
Populate these with module code which defines all of the same tables and reducers
as modules/sdk-test and modules/sdk-test-connect-disconnect respectively.
Take care to use the same names, including casing, for tables, columns, indexes, reducers and other database objects.sdks/rust/tests/test.rs to add an additional call to declare_tests_with_suffix! at the bottom,
like declare_tests_with_suffix!(xxlang, "-XX"), if that driver is the right place for the new language.
Some capabilities now live in separate suites in that file, such as procedures and views,
so you may need to wire those up separately as well.cargo test -p spacetimedb-sdk --test test.If you are developing a new client SDK, and wish to use the SDK test harness and existing modules
so that it will run against modules/sdk-test and modules/sdk-test-connect-disconnect:
test-client and connect_disconnect_client for your client SDK language.
If your client SDK is in-tree, put these within its directory, following the existing layout under sdks/rust/tests/ or sdks/unreal/tests/.spacetime generate manually, or via the harness, to generate those projects' module_bindings.sdks/rust/tests/test-client and sdks/rust/tests/connect_disconnect_client respectively.
http://localhost:3000.SPACETIME_SDK_TEST_DB_NAME.test-client, take a test name as a command-line argument in argv[1], and dispatch to the appropriate test to run.connect_disconnect_client, there is only one test.TestCounter defined in sdks/rust/tests/test-counter.
This is effectively a semaphore with a timeout.
You may or may not need to replicate this behavior.spacetimedb_testing::sdk::Test objects,
following sdks/rust/tests/test.rs or sdks/unreal/tests/test.rs as a template.#[test] tests for each test case you have implemented,
which construct spacetimedb_testing::sdk::Test objects containing the various subcommand strings to run your client project,
then call .run() on them.If you want to add a new test case to the SDK test suite, to test some new or yet-untested functionality of either the module libraries or client SDKs:
modules/sdk-test and friends which exercise the behavior you want to test.exec_foo, to the appropriate client project,
such as sdks/rust/tests/test-client/src/lib.rs,
which connects to the database, subscribes to tables and invokes reducers as appropriate,
and performs assertions about the events it observes.match in sdks/rust/tests/test-client/src/main.rs,
which matches the test name foo and dispatches to call your exec_foo function.#[test] test function to the relevant test driver,
such as sdks/rust/tests/test.rs,
which does make_test("foo").run(), where "foo" is the test name you chose in step 3.cargo test command for that SDK.crates/schema/tests/ensure_same_schema.rs is a separate but important companion to the SDK tests.
It compares the extracted schemas of equivalent modules across languages,
and is often the first place where casing, indexes, primary keys, or other schema details drift apart.
As of writing, it covers the benchmarks, module-test, sdk-test, and sdk-test-connect-disconnect families.
If you add or update a cross-language module family, it is worth considering whether it should also be covered here.
crates/smoketests/ defines an integration and regression test suite using a Rust harness.
These are useful primarily for testing the SpacetimeDB CLI, but can also be used to exercise publish flows,
documentation, and other end-to-end behavior.
The smoketest harness is still primarily oriented around Rust modules, and it does not use the same client-project machinery as the SDK harness. It could be extended to do more in that direction, but that may not be worth the effort. As of writing, the smoketest suite includes dedicated coverage such as:
crates/smoketests/tests/smoketests/csharp_module.rs, which smoke-tests C# module compilation.crates/smoketests/tests/smoketests/quickstart.rs, which replays the quickstart guide for Rust and C#.crates/smoketests/DEVELOP.md, which documents how to run and write these tests.One practical note is that the smoketests use prebuilt spacetimedb-cli and spacetimedb-standalone binaries,
so if you modify those crates or their dependencies, you should rebuild before running the suite.
The spacetimedb-testing crate has an integration test file, crates/testing/tests/standalone_integration_test.rs.
The tests in this file publish modules/module-test, modules/module-test-cs, modules/module-test-ts, and modules/module-test-cpp,
then invoke reducers or procedures in them and inspect their logs to verify that the behavior is expected.
These tests do not exercise the entire functionality of module-test,
but by virtue of publishing it do assert that it is syntactically valid and that it compiles.
To add a new module library to the Standalone integration test suite:
modules/module-test-XX, where XX is some mnemonic for your language.module-test family.
If you notice any discrepancies between the existing languages, those parts may be compiled but not run,
and so you are free to ignore them.crates/testing/tests/standalone_integration_test.rs to define new #[test] #[serial] test functions
which use your new module-test-XX module to do the same operations as the existing tests.cargo test -p spacetimedb-testing --test standalone_integration_test.