Skip to content

Testing

QS-Bridge has 7 test suites with 860+ assertions. Tests cover BSATN serialisation, protocol framing, server message parsing, bridge orchestration, and end-to-end SpacetimeDB interaction.


Test Summary

Suite File Tests Assertions Focus
BSATN Round-Trip test_table_roundtrip.cpp 88 131 All 44 table types — default + value round-trips
HMAC-SHA256 test_hmac.cpp 8 8 RFC 4231 test vectors
Mock Adapter test_mock_adapter.cpp 17 17 Headless engine adapter lifecycle
Protocol Framing test_protocol_framing.cpp 26 26 STDB v2 wire format
Server Messages test_server_messages.cpp 30 108 Server→client message parsing
Integration Pipeline test_integration_pipeline.cpp 45 554 Full bridge orchestration
E2E SpacetimeDB test_e2e_stdb.cpp 6 16 Live STDB v2 (CI-safe)
Total 7 files 220 860+

Test Framework

Tests use Catch2 v3, fetched via CMake FetchContent. No external test dependencies.

# Build and run all tests
cmake -B build -DQSB_BUILD_TESTS=ON
cmake --build build -j$(nproc)
cd build && ctest --output-on-failure

# Run a specific suite
./build/test_table_roundtrip
./build/test_integration_pipeline

# Run with verbose output
./build/test_integration_pipeline -v

# Run a specific test case
./build/test_integration_pipeline "game factory registration"

Suite 1 — BSATN Round-Trip (131 assertions)

Tests that every table type can serialise to BSATN and deserialise back identically.

What it tests: - Default-constructed row → write → read → compare (44 tables) - Value-constructed row → write → read → compare (44 tables) - Various field types: String, u32, u64, f32, f64, bool, Timestamp, Option, Vec - Nested types and enums

TEST_CASE("PlayerPosition round-trip") {
    PlayerPosition original{};
    original.player_id = "Steam:76561198012345678";
    original.x = 1234.5f;
    original.y = -567.8f;
    original.z = 90.0f;

    BsatnWriter writer;
    original.serialize(writer);

    BsatnReader reader(writer.data());
    auto deserialized = PlayerPosition::deserialize(reader);

    CHECK(deserialized.player_id == original.player_id);
    CHECK(deserialized.x == original.x);
    CHECK(deserialized.y == original.y);
    CHECK(deserialized.z == original.z);
}

Suite 2 — HMAC-SHA256 (8 assertions)

Validates the HMAC implementation against RFC 4231 test vectors.

What it tests: - Standard test vectors from RFC 4231 - Empty message - Known key + message → expected HMAC output - Used to verify reducer call signing


Suite 3 — Mock Adapter (17 assertions)

Tests the headless engine adapter used for CI testing without a game server.

What it tests: - Adapter init/shutdown lifecycle - Mock player add/remove - Player ID extraction - get_connected_players() returns correct list - RPC simulation dispatch


Suite 4 — Protocol Framing (26 assertions)

Tests STDB v2 binary protocol message construction and parsing.

What it tests: - Subscribe message serialisation - CallReducer message serialisation with BSATN-encoded arguments - InitialConnection parsing (Identity extraction) - SubscribeApplied parsing - ReducerResult parsing (all 4 outcomes: committed, failed, out-of-energy, timed-out) - Wire format byte order (little-endian) - UTF-8 string encoding in messages


Suite 5 — Server Messages (108 assertions, 30 tests)

Comprehensive tests for parsing server-to-client messages.

What it tests: - InitialConnection — Identity bytes, protocol version - SubscribeApplied — 2 tables, initial row data, request_id - TransactionUpdate — inserts and deletes, table_id matching - ReducerResult — all 4 outcome variants, error messages, timestamps - SubscriptionError — error string extraction - Edge cases: empty tables, unicode in strings, large payloads (>64 KB) - Malformed messages: truncated, wrong tags, zero-length


Suite 6 — Integration Pipeline (554 assertions, 45 tests)

The largest test suite. Validates the full bridge orchestration pipeline end-to-end (in-process, no network).

What it tests:

  1. Game Factory — registration, creation, duplicate rejection, unknown module
  2. GameInterface — lifecycle callbacks (init, tick, player_join, player_leave)
  3. RPC Dispatcher — handler registration, dispatch, unknown RPC handling
  4. StdbConnection — outbound message serialisation, inbound message parsing, callback delivery for SubscribeApplied/TransactionUpdate/ReducerResult
  5. GameAction Queue — all 5 variant types, enqueue/dequeue, multi-threaded safety (producer + consumer threads), 10K throughput benchmark
  6. Full Orchestration — replicates entry.cpp init_thread_func() flow: create adapter → create connection → create game → register hooks → connect → subscribe → handle callbacks
  7. Multi-Instance Isolation — two separate connection + game instances don't interfere
  8. Edge Cases — null pointers, empty strings, maximum values, rapid connect/disconnect
TEST_CASE("Full orchestration sequence") {
    // Replicate the real init_thread_func() flow
    MockAdapter adapter;
    REQUIRE(adapter.init());

    StdbConnection conn("ws://test:3000", "test-module");
    HumanitZGame game;
    game.on_init(&conn);
    game.register_hooks(&adapter);

    // Simulate SubscribeApplied
    auto msg = build_subscribe_applied(/*...*/);
    conn.handle_message(msg);

    // Verify game state updated
    CHECK(game.is_initialized());
    CHECK(adapter.hook_count() > 0);
}

Uses: tests/test_stubs.cpp — linker stubs for UE4 engine symbols (allows testing without game server binary).


Suite 7 — E2E SpacetimeDB (16 assertions)

Full real-world test against a live SpacetimeDB v2 instance.

What it tests: 1. WebSocket connection establishment 2. Identity receipt (32-byte InitialConnection) 3. Subscribe to 2 tables 4. Receive SubscribeApplied with initial rows 5. Call "ping" reducer 6. Receive ReducerResult with timestamp 7. Receive incremental TransactionUpdate (delete old + insert new)

CI Safety: Gracefully skips when SpacetimeDB is not running. Not a CI blocker, but validates the complete network path when available.

# Run E2E test (requires running SpacetimeDB)
spacetime start
spacetime publish test-module
./build/test_e2e_stdb

Test Coverage Goals

Component Current Target
BSATN codec ✅ All types Maintain 100%
Protocol framing ✅ All messages Maintain 100%
Bridge core ✅ Full pipeline Add fuzz testing
Engine adapter ✅ Mock adapter Add UE4 adapter unit tests
Game module ⚠️ Via integration Add per-reducer unit tests
STDB module (Rust) ⚠️ types.rs only Add reducer logic tests