Skip to content

HostGroups Manager unit tests (Phase 2.6)#5506

Merged
renecannao merged 3 commits intov3.0-5473from
v3.0-5478
Mar 22, 2026
Merged

HostGroups Manager unit tests (Phase 2.6)#5506
renecannao merged 3 commits intov3.0-5473from
v3.0-5478

Conversation

@renecannao
Copy link
Contributor

@renecannao renecannao commented Mar 22, 2026

Summary

Implements Phase 2.6 (#5478) of the Unit Testing Framework: unit tests for MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager.

  • 17 TAP test cases across 8 test functions
  • Runs in <0.01 seconds with zero infrastructure dependencies
  • Tests the real managers with their internal SQLite3 databases, no network connections needed

Test Coverage

Area Tests What's Verified
Server creation 3 Single server, multiple in same HG, different HGs
Server removal 2 Existing server removed, non-existent returns -1
shun_and_killall 2 Existing returns true, non-existent returns false
Latency tracking 1 set_server_current_latency_us() without crash
HG independence 2 Shunning in one HG doesn't affect another
Duplicate handling 1 Adding same server twice doesn't crash
PgSQL create+remove 3 Using PgSQL-specific types (PgSQL_srv_info_t)
PgSQL shun 1 shun_and_killall() on PgSQL manager

Infrastructure Changes

  • New test_init_hostgroups() / test_cleanup_hostgroups() in test_init.h/.cpp
  • Creates real MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager with Prometheus registry

Notable Finding

Methods like shun_and_killall() and set_server_current_latency_us() acquire their own write locks internally. Tests must NOT wrap these calls with external wrlock()/wrunlock() or a deadlock occurs. This is documented in the commit message and test comments.

Depends On

Test plan

  • All 17 tests pass on macOS (arm64)
  • Verify on Linux (CI)

Summary by CodeRabbit

  • Tests
    • Added comprehensive unit tests for HostGroups Manager covering server add/remove, status transitions, latency updates, duplicate and missing-server edge cases.
    • Added idempotent init and cleanup test helpers for HostGroups that avoid starting background activity during tests.
    • Updated unit-test build to include the new HostGroups test suite.

Unit tests for MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager
covering 17 test cases. Runs in <0.01s with no infrastructure deps.

Test coverage:
- Server creation via create_new_server_in_hg() (single, multiple in
  same HG, different HGs)
- Server removal via remove_server_in_hg() (existing, non-existent)
- shun_and_killall() (existing server returns true, non-existent false)
- set_server_current_latency_us() (latency tracking without crash)
- Multiple hostgroups independence (shunning in one HG doesn't affect
  another)
- Duplicate server handling
- PgSQL: create, remove, and shun operations with PgSQL-specific types
  (PgSQL_srv_info_t, PgSQL_srv_opts_t)

Infrastructure:
- New test_init_hostgroups() / test_cleanup_hostgroups() helpers in
  test_init.h/.cpp
- Creates real MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager
  with internal SQLite3 databases
- Requires Prometheus registry (auto-created if nullptr)

Note: Methods like shun_and_killall() and set_server_current_latency_us()
acquire their own write locks internally — callers must NOT hold the
lock beforehand or a deadlock occurs.
Copilot AI review requested due to automatic review settings March 22, 2026 02:46
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the unit testing framework by introducing comprehensive tests for the MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager. It ensures the robust and independent operation of server management functionalities, including server lifecycle, status changes, and performance metrics, all within an isolated testing environment that uses real manager implementations but without external network dependencies.

Highlights

  • New Unit Tests: Introduced 17 TAP test cases for MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager, covering server creation, removal, status transitions, latency tracking, hostgroup independence, and duplicate handling.
  • Test Infrastructure: Added test_init_hostgroups() and test_cleanup_hostgroups() to test_init.h/.cpp for setting up and tearing down HostGroups Managers with Prometheus registry for testing.
  • Concurrency Note: Documented a critical finding that shun_and_killall() and set_server_current_latency_us() acquire internal write locks, warning against external wrlock()/wrunlock() to prevent deadlocks.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b4ba857e-f21e-4ecc-b419-5b3b7334a869

📥 Commits

Reviewing files that changed from the base of the PR and between e4972ac and 1549370.

📒 Files selected for processing (2)
  • test/tap/test_helpers/test_init.cpp
  • test/tap/test_helpers/test_init.h
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/tap/test_helpers/test_init.h
  • test/tap/test_helpers/test_init.cpp
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: CI-builds / builds (ubuntu22,-tap)
  • GitHub Check: CI-builds / builds (debian12,-dbg)
  • GitHub Check: run / trigger

📝 Walkthrough

Walkthrough

Adds idempotent test init/cleanup helpers that allocate MyHGM/PgHGM and ensure GloVars.prometheus_registry, a new hostgroups unit test binary exercising MySQL/PgSQL HostGroups operations, and a Makefile target to build the test.

Changes

Cohort / File(s) Summary
Test Helpers
test/tap/test_helpers/test_init.h, test/tap/test_helpers/test_init.cpp
Added test_init_hostgroups() and test_cleanup_hostgroups(); init lazily constructs prometheus::Registry if missing and allocates MySQL_HostGroups_Manager/PgSQL_HostGroups_Manager into MyHGM/PgHGM without invoking their init() background behavior; cleanup deletes and nulls those globals.
Build Configuration
test/tap/tests/unit/Makefile
Added hostgroups_unit-t to UNIT_TESTS and a link rule for the new unit test binary.
HostGroups Unit Tests
test/tap/tests/unit/hostgroups_unit-t.cpp
New TAP test (plan 17) exercising server add/remove, error cases, shun_and_killall(), latency updates, hostgroup isolation, duplicate-add behavior, and PgSQL parity using the global managers and test helpers.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test runner
    participant Init as test_init_hostgroups()
    participant Glo as GloVars.prometheus_registry
    participant MyHGM as MyHGM (MySQL_HostGroups_Manager)
    participant PgHGM as PgHGM (PgSQL_HostGroups_Manager)

    Test->>Init: call test_init_hostgroups()
    Init->>Glo: ensure registry exists (create if null)
    Init->>MyHGM: allocate MySQL_HostGroups_Manager -> assign to MyHGM
    Init->>PgHGM: allocate PgSQL_HostGroups_Manager -> assign to PgHGM
    Note right of Init: does NOT call managers' init() to avoid background threads

    Test->>Init: run tests using MyHGM/PgHGM
    Test->>Init: call test_cleanup_hostgroups()
    Init->>MyHGM: delete and null MyHGM
    Init->>PgHGM: delete and null PgHGM
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 Hopping through tests with a bright little squeak,

I add and I remove, I probe and I peek.
Hostgroups align as servers take part,
Latency, shun, and parity — tested with heart.
A rabbit-approved run — let's give it a tweak!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'HostGroups Manager unit tests (Phase 2.6)' clearly summarizes the main change: adding unit tests for HostGroups Manager as part of phase 2.6 of the testing framework. It is concise, specific, and directly related to the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v3.0-5478

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a comprehensive set of unit tests for the MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager, which is a great step towards improving test coverage. The tests are well-structured and cover a good range of functionalities including server creation, removal, shunning, and latency tracking.

I've identified a few minor issues:

  • A duplicate function declaration in a header file.
  • Unsafe C-style casts in the new test file, which could be improved for safety.
  • Some leftover developer comments that should be cleaned up.

Overall, this is a solid contribution. Addressing these points will further improve the code quality.

Comment on lines +130 to +131
void test_cleanup_query_processor();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function test_cleanup_query_processor() is already declared on line 110. This duplicate declaration should be removed to avoid confusion and maintain code cleanliness.

Comment on lines +114 to +115
bool shunned = MyHGM->shun_and_killall(
(char *)"192.168.1.1", 3306);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Casting a string literal to char* is unsafe because it casts away const. If shun_and_killall were to modify the string, it would result in undefined behavior. To ensure safety, please use a mutable character array. This applies to other similar calls in this file (e.g., lines 120-121, 137-138, 156, 161, and 234-235).

Suggested change
bool shunned = MyHGM->shun_and_killall(
(char *)"192.168.1.1", 3306);
char addr[] = "192.168.1.1";
bool shunned = MyHGM->shun_and_killall(addr, 3306);

Comment on lines +264 to +267
// Total: 1+1+3+2+2+1+2+1+3+1 = 17... let me recount
// init: 2, create: 3, remove: 2, status: 2, latency: 1,
// independence: 2, duplicate: 1, pgsql_create: 3, pgsql_shun: 1
// = 17. Fix plan.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These comments appear to be developer notes for tracking the test plan. They should be removed to keep the code clean.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Phase 2.6 unit coverage for HostGroups Managers, extending the TAP unit-test suite to validate basic MySQL/PgSQL hostgroup server lifecycle operations without external infrastructure.

Changes:

  • Adds a new TAP unit test binary (hostgroups_unit-t) with 17 assertions covering create/remove/shun/latency and basic PgSQL parity.
  • Introduces test_init_hostgroups() / test_cleanup_hostgroups() to construct and tear down real MySQL_HostGroups_Manager / PgSQL_HostGroups_Manager instances.
  • Registers the new unit test target in the unit-test Makefile.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
test/tap/tests/unit/hostgroups_unit-t.cpp New HostGroups Manager unit tests (MySQL + PgSQL).
test/tap/tests/unit/Makefile Adds hostgroups_unit-t to UNIT_TESTS and build rules.
test/tap/test_helpers/test_init.h Declares new hostgroups init/cleanup APIs.
test/tap/test_helpers/test_init.cpp Implements hostgroups init/cleanup (including Prometheus registry setup).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +114 to +121
bool shunned = MyHGM->shun_and_killall(
(char *)"192.168.1.1", 3306);
ok(shunned == true,
"MySQL HGM: shun_and_killall() returns true for existing server");

// shun_and_killall on non-existent server
bool not_found = MyHGM->shun_and_killall(
(char *)"10.10.10.10", 9999);
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls cast string literals to char* to satisfy the shun_and_killall(char*, int) signature. If the implementation ever writes to hostname, this becomes undefined behavior (string literals are not writable). Prefer passing a writable buffer (e.g., a local char[] or std::vector<char>), or add a small helper that builds a mutable copy before calling the API.

Suggested change
bool shunned = MyHGM->shun_and_killall(
(char *)"192.168.1.1", 3306);
ok(shunned == true,
"MySQL HGM: shun_and_killall() returns true for existing server");
// shun_and_killall on non-existent server
bool not_found = MyHGM->shun_and_killall(
(char *)"10.10.10.10", 9999);
char hostname1[] = "192.168.1.1";
bool shunned = MyHGM->shun_and_killall(
hostname1, 3306);
ok(shunned == true,
"MySQL HGM: shun_and_killall() returns true for existing server");
// shun_and_killall on non-existent server
char hostname2[] = "10.10.10.10";
bool not_found = MyHGM->shun_and_killall(
hostname2, 9999);

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +138
MyHGM->set_server_current_latency_us(
(char *)"172.16.0.1", 3306, 5000); // 5ms latency
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set_server_current_latency_us(char*, ...) is being called by casting a string literal to char*. This is unsafe if the callee ever modifies the buffer. Use a writable hostname buffer (or a helper that makes a mutable copy) rather than casting away constness of a literal.

Suggested change
MyHGM->set_server_current_latency_us(
(char *)"172.16.0.1", 3306, 5000); // 5ms latency
char hostname[] = "172.16.0.1";
MyHGM->set_server_current_latency_us(
hostname, 3306, 5000); // 5ms latency

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +164
static void test_mysql_hostgroup_independence() {
add_mysql_server(60, "hg60-server", 3306, 1, 100);
add_mysql_server(70, "hg70-server", 3306, 1, 100);

// Shun server in HG 60 — should not affect HG 70
bool s1 = MyHGM->shun_and_killall((char *)"hg60-server", 3306);
ok(s1 == true,
"MySQL HGM: shunned server in HG 60");

// HG 70 server should still be accessible
bool s2 = MyHGM->shun_and_killall((char *)"hg70-server", 3306);
ok(s2 == true,
"MySQL HGM: HG 70 server independently operable");
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_mysql_hostgroup_independence() doesn't currently assert that the HG70 server is unaffected by shunning the HG60 server; it only shuns the second server afterwards. To actually test independence, consider checking the HG70 server status after shunning HG60 (e.g., via find_server_in_hg() + get_status() / status), before performing any operation that changes HG70.

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +162
bool s1 = MyHGM->shun_and_killall((char *)"hg60-server", 3306);
ok(s1 == true,
"MySQL HGM: shunned server in HG 60");

// HG 70 server should still be accessible
bool s2 = MyHGM->shun_and_killall((char *)"hg70-server", 3306);
ok(s2 == true,
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More occurrences of casting string literals to char* for shun_and_killall(). To avoid repeating unsafe casts, it may be worth introducing a small helper (e.g., shun(MyHGM, "host", port)) that creates a mutable copy of the hostname before calling the API.

Copilot uses AI. Check for mistakes.
Comment on lines +234 to +235
bool shunned = PgHGM->shun_and_killall(
(char *)"pg-shun-server", 5432);
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PgHGM->shun_and_killall() is called by casting a string literal to char*. This relies on the function never writing to hostname; to keep the test robust against future changes, pass a writable buffer instead of casting away constness of a literal.

Suggested change
bool shunned = PgHGM->shun_and_killall(
(char *)"pg-shun-server", 5432);
char hostname[] = "pg-shun-server";
bool shunned = PgHGM->shun_and_killall(hostname, 5432);

Copilot uses AI. Check for mistakes.
* Destroys MyHGM and PgHGM, setting them back to nullptr.
*/
void test_cleanup_hostgroups();
void test_cleanup_query_processor();
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_cleanup_query_processor() is declared twice in this header (once above and again after test_cleanup_hostgroups()). While duplicate prototypes compile, this looks accidental and can confuse readers; please remove the extra declaration at the end of the file.

Suggested change
void test_cleanup_query_processor();

Copilot uses AI. Check for mistakes.
Comment on lines +175 to +178
int test_init_hostgroups() {
if (MyHGM != nullptr || PgHGM != nullptr) {
return 0;
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_init_hostgroups() returns early if either MyHGM or PgHGM is already non-null. This can leave one manager uninitialized (e.g., MyHGM!=nullptr but PgHGM==nullptr) while still reporting success, which can lead to null dereferences in tests. Consider making the idempotency check require both managers to be initialized, or initialize whichever one is still null.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/tap/tests/unit/hostgroups_unit-t.cpp (1)

264-267: Remove leftover comment block.

This appears to be debugging notes from test planning. The plan count is correct at 17, so these comments are no longer needed.

Proposed cleanup
 	test_pgsql_create_and_remove();      // 3 tests
 	test_pgsql_shun();                   // 1 test
-	// Total: 1+1+3+2+2+1+2+1+3+1 = 17... let me recount
-	// init: 2, create: 3, remove: 2, status: 2, latency: 1,
-	// independence: 2, duplicate: 1, pgsql_create: 3, pgsql_shun: 1
-	// = 17. Fix plan.

 	test_cleanup_hostgroups();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/unit/hostgroups_unit-t.cpp` around lines 264 - 267, Remove the
leftover test-planning comment block that starts with "// Total:
1+1+3+2+2+1+2+1+3+1 = 17... let me recount" and the subsequent lines listing
init/create/remove/... and "= 17. Fix plan."; simply delete that entire comment
block from the test file (hostgroups_unit-t.cpp) so only actual test code and
relevant comments remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/tap/test_helpers/test_init.cpp`:
- Around line 194-202: test_cleanup_hostgroups currently deletes MyHGM while
background threads may still access it; call
MySQL_HostGroups_Manager::shutdown() on the MyHGM instance (or
MyHGM->shutdown()) before deleting and nulling it to signal and join the
HGCU_thread and GTID_syncer_thread, then proceed to delete MyHGM and set MyHGM =
nullptr; leave PgHGM deletion as-is. Ensure you reference MyHGM and
MySQL_HostGroups_Manager::shutdown() in the fix so the threads are stopped
before freeing the object.

In `@test/tap/test_helpers/test_init.h`:
- Line 130: Remove the duplicate declaration of the function
test_cleanup_query_processor() from the header so only a single prototype
remains; locate the second copy of the declaration (the one that duplicates the
existing prototype) and delete it, leaving the original
test_cleanup_query_processor() declaration untouched to avoid duplicate-symbol
warnings.

---

Nitpick comments:
In `@test/tap/tests/unit/hostgroups_unit-t.cpp`:
- Around line 264-267: Remove the leftover test-planning comment block that
starts with "// Total: 1+1+3+2+2+1+2+1+3+1 = 17... let me recount" and the
subsequent lines listing init/create/remove/... and "= 17. Fix plan."; simply
delete that entire comment block from the test file (hostgroups_unit-t.cpp) so
only actual test code and relevant comments remain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 997d53ed-cb37-43ed-bfed-38dca92e1e9a

📥 Commits

Reviewing files that changed from the base of the PR and between c54e6e1 and f772c10.

📒 Files selected for processing (4)
  • test/tap/test_helpers/test_init.cpp
  • test/tap/test_helpers/test_init.h
  • test/tap/tests/unit/Makefile
  • test/tap/tests/unit/hostgroups_unit-t.cpp
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Agent
  • GitHub Check: CI-builds / builds (ubuntu22,-tap)
  • GitHub Check: CI-builds / builds (debian12,-dbg)
  • GitHub Check: run / trigger
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-01-20T07:40:34.938Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:24-28
Timestamp: 2026-01-20T07:40:34.938Z
Learning: In ProxySQL test files, calling `mysql_error(NULL)` after `mysql_init()` failure is safe because the MariaDB client library implementation returns an empty string for NULL handles (not undefined behavior).

Applied to files:

  • test/tap/test_helpers/test_init.h
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/unit/hostgroups_unit-t.cpp
🪛 Clang (14.0.6)
test/tap/tests/unit/hostgroups_unit-t.cpp

[error] 18-18: 'tap.h' file not found

(clang-diagnostic-error)

🪛 Cppcheck (2.20.0)
test/tap/tests/unit/hostgroups_unit-t.cpp

[error] 149-149: Common realloc mistake

(memleakOnRealloc)


[warning] 86-86: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 31-31: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 138-138: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)

🔇 Additional comments (6)
test/tap/test_helpers/test_init.h (1)

112-129: LGTM!

The new test_init_hostgroups() and test_cleanup_hostgroups() declarations follow the established pattern of other init/cleanup pairs in this header.

test/tap/test_helpers/test_init.cpp (1)

175-192: LGTM on the initialization logic.

The idempotency check and Prometheus registry setup follow the established patterns from other test_init_* functions.

test/tap/tests/unit/Makefile (2)

234-234: LGTM!

The new hostgroups_unit-t target is correctly added to the UNIT_TESTS list.


283-286: LGTM!

The build target follows the established pattern from other unit test targets.

test/tap/tests/unit/hostgroups_unit-t.cpp (2)

1-28: Well-structured test file.

The test organization is clear with logical groupings, good use of helper functions, and proper documentation of locking semantics (especially the notes about shun_and_killall() and set_server_current_latency_us() acquiring their own locks). Using distinct hostgroup IDs for each test ensures isolation.


244-273: LGTM on test main function.

The initialization order (test_init_minimal()test_init_hostgroups()) and cleanup order (reverse) follows the documented pattern. Test plan count of 17 matches the actual test assertions.

Comment on lines +194 to +202
void test_cleanup_hostgroups() {
if (MyHGM != nullptr) {
delete MyHGM;
MyHGM = nullptr;
}
if (PgHGM != nullptr) {
delete PgHGM;
PgHGM = nullptr;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Call shutdown() before deleting MyHGM to prevent use-after-free.

MySQL_HostGroups_Manager::init() spawns two background threads (HGCU_thread and GTID_syncer_thread) that continuously dereference the global MyHGM pointer. Deleting MyHGM without calling shutdown() first leaves these threads running and dereferencing freed memory.

From lib/MySQL_HostGroups_Manager.cpp:770-789, shutdown() signals the threads to exit and joins them before cleanup.

Proposed fix
 void test_cleanup_hostgroups() {
 	if (MyHGM != nullptr) {
+		MyHGM->shutdown();
 		delete MyHGM;
 		MyHGM = nullptr;
 	}
 	if (PgHGM != nullptr) {
+		PgHGM->shutdown();
 		delete PgHGM;
 		PgHGM = nullptr;
 	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void test_cleanup_hostgroups() {
if (MyHGM != nullptr) {
delete MyHGM;
MyHGM = nullptr;
}
if (PgHGM != nullptr) {
delete PgHGM;
PgHGM = nullptr;
}
void test_cleanup_hostgroups() {
if (MyHGM != nullptr) {
MyHGM->shutdown();
delete MyHGM;
MyHGM = nullptr;
}
if (PgHGM != nullptr) {
PgHGM->shutdown();
delete PgHGM;
PgHGM = nullptr;
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/test_helpers/test_init.cpp` around lines 194 - 202,
test_cleanup_hostgroups currently deletes MyHGM while background threads may
still access it; call MySQL_HostGroups_Manager::shutdown() on the MyHGM instance
(or MyHGM->shutdown()) before deleting and nulling it to signal and join the
HGCU_thread and GTID_syncer_thread, then proceed to delete MyHGM and set MyHGM =
nullptr; leave PgHGM deletion as-is. Ensure you reference MyHGM and
MySQL_HostGroups_Manager::shutdown() in the fix so the threads are stopped
before freeing the object.

MySQL_HostGroups_Manager::init() starts two background threads
(HGCU_thread and GTID_syncer_thread) that run forever in a blocking
loop. The destructor does not call shutdown() to stop them, so the
test process hangs indefinitely after main() returns — std::thread
destructor calls std::terminate() on joinable threads.

Fix: skip init() entirely. The constructor alone sets up the internal
SQLite3 database and all data structures needed for unit testing.
The background threads are only needed for real connection pool
management (connection reuse, GTID sync), not for server add/remove/
shun operations.
- test_init.h: remove duplicate test_cleanup_query_processor()
  declaration (copy-paste artifact at line 130)
- test_init.cpp: check MyHGM and PgHGM independently instead of
  using OR guard, so one can't be left null while the other exists
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
8 Security Hotspots

See analysis details on SonarQube Cloud

@renecannao renecannao merged commit b0889e1 into v3.0-5473 Mar 22, 2026
11 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants