docs/superpowers/plans/2026-08-15-real-traffic-tap-coverage.md
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Make MySQL protocol and query-cache coverage come from functional TAP tests that prove real client traffic took the intended ProxySQL path.
Architecture: Keep protocol production code unchanged. Strengthen the existing two-client EOF/OK cache test with runtime counters, then add or extend TAP executables that use only MariaDB/MySQL C APIs and verify result values, metadata, and backend-visible effects.
Tech Stack: C++17, ProxySQL TAP helpers, MariaDB/MySQL C client APIs, ProxySQL admin SQL, Docker Ubuntu 24 build/test infrastructure.
test/tap/groups/groups.json.Files:
test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cppInterfaces:
Consumes: fwd_eof_query and fwd_eof_ok_query real C-client executables.
Produces: Assertions on stats_mysql_global.Query_Cache_count_GET_OK and Query_Cache_count_SET for both conversion directions.
Step 1: Add test helpers and assertions
Add a scalar stats_mysql_global reader and a direction helper that performs:
MYSQL_QUERY(proxy_admin, "PROXYSQL FLUSH MYSQL QUERY CACHE");
const long long get_before = read_global_counter(proxy_admin, "Query_Cache_count_GET_OK");
const long long set_before = read_global_counter(proxy_admin, "Query_Cache_count_SET");
// first real client fills; incompatible real client reads
ok(read_global_counter(proxy_admin, "Query_Cache_count_SET") == set_before + 1, "first query stores cache entry");
ok(read_global_counter(proxy_admin, "Query_Cache_count_GET_OK") == get_before + 1, "second query reads cache entry");
Set cache_ttl to 10 seconds and replace the 110 ms usleep expiration with an explicit admin cache flush before the reverse direction.
Compiled through the vendored client dependency and ran the focused executable in the isolated MySQL 8.4 group: all 1,151 assertions passed. The TAP log proves both cache directions with exact Query_Cache_count_SET and Query_Cache_count_GET_OK deltas.
Files:
test/tap/tests/mysql-com_field_list-t.cpptest/tap/groups/groups.jsonInterfaces:
Consumes: mysql_list_fields(MYSQL*, const char*, const char*) from the standard MySQL C client API.
Produces: Metadata assertions and one translated backend-digest assertion.
Step 1: Add the functional TAP
Create a test table with integer, varchar, decimal, and timestamp columns. Connect through ProxySQL and call:
MYSQL_RES* fields = mysql_list_fields(proxy, "test.com_field_list_coverage", nullptr);
ok(fields != nullptr, "mysql_list_fields succeeds through ProxySQL");
MYSQL_FIELD* field = mysql_fetch_field(fields);
ok(strcmp(field->name, "id") == 0 && field->type == MYSQL_TYPE_LONG, "id metadata is returned");
Assert the complete field list and the corresponding translated SELECT in stats_mysql_query_digest.
Register mysql-com_field_list-t in the normal legacy and MySQL TAP group-1 matrices, then compile it through test/tap/tests/Makefile.
Files:
test/tap/tests/mysql-last_insert_id-t.cpptest/tap/tests/mysql-select_version_without_backend-t.cppInterfaces:
Consumes: ordinary mysql_query requests for @@IDENTITY, @@VERSION, and VERSION().
Produces: coverage for all declared identity variants and all four select-version forwarding modes.
Step 1: Execute the missing identity variant
Change the query loop bound to the actual array length, update the TAP plan by one result assertion, and verify plain SELECT @@IDENTITY returns the just-inserted identifier.
With no backend configured, issue ordinary SELECT @@VERSION and SELECT VERSION() traffic in each documented forwarding mode. Modes 0 and 2 must return the configured internal version; modes 1 and 3 must return a non-zero client error because they require backend forwarding.
ok(observed == expected_internal_version, "internal mode returns configured version");
This avoids a fragile assertion about thread-local backend-pool state while preserving functional coverage of every mode's actual client-visible behavior.
Compile both TAP binaries and run their registered isolated group.
Files:
test/tap/tests/test_ps_no_store-t.cppInterfaces:
Consumes: mysql_stmt_prepare, mysql_stmt_execute, and a second ordinary backend connection.
Produces: prepared-statement tests for a long lock-clause query and metadata refresh after ALTER TABLE.
Step 1: Add the lock-clause scenario
Prepare and execute a valid SELECT ... FOR UPDATE /* comment */ statement whose lock clause occurs in the final 128 bytes. The trailing comment bypasses the direct suffix matcher, so assert the long-query classification counter increases exactly once as well as the returned row and successful commit.
Prepare SELECT * on a uniquely named table, execute it, alter that table through a second connection, execute again, and assert mysql_stmt_result_metadata() exposes the new column count.
Compile the changed executable and run its existing isolated group.
Files:
Modify: only the test sources and groups.json above.
Step 1: Validate registration and formatting
Run:
python3 test/tap/groups/lint_groups_json.py
python3 test/tap/groups/check_groups.py --source
Run their registered groups against the isolated ProxySQL/MySQL environment and retain exact TAP logs.
Confirm the resulting LCOV/Codecov data contains hits in MySQL_Query_Cache.cpp, MySQL_Protocol.cpp, MySQL_Session.cpp, and MySQL_PreparedStatement.cpp at the named paths.
Commit the test-only changes on feature/real-traffic-coverage, push it, and open a dedicated PR targeting v3.0.