You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/test/tap/test_helpers/test_init.cpp

208 lines
5.7 KiB

/**
* @file test_init.cpp
* @brief Implementation of component initialization helpers for unit tests.
*
* Each test_init_*() function creates real instances of ProxySQL components,
* bypassing the full daemon startup sequence. Components are assigned to
* their respective Glo* global pointers so that internal cross-references
* work correctly.
*
* @see test_init.h for the public interface and usage examples.
* @see Phase 2.1 of the Unit Testing Framework (GitHub issue #5473)
*/
#include "proxysql.h"
#include "cpp.h"
#include "MySQL_Authentication.hpp"
#include "PgSQL_Authentication.h"
#include "MySQL_Query_Cache.h"
#include "PgSQL_Query_Cache.h"
#include "MySQL_Query_Processor.h"
#include "PgSQL_Query_Processor.h"
#include "test_globals.h"
#include "test_init.h"
// Extern declarations for Glo* pointers defined in test_globals.cpp.
// These are normally defined in main.cpp and have no header declarations.
extern MySQL_Authentication *GloMyAuth;
extern PgSQL_Authentication *GloPgAuth;
extern MySQL_Query_Cache *GloMyQC;
extern PgSQL_Query_Cache *GloPgQC;
extern MySQL_Query_Processor *GloMyQPro;
extern PgSQL_Query_Processor *GloPgQPro;
// GloMTH is declared extern in proxysql_utils.h.
// GloPTH has no extern declaration in any header, so we add one here.
extern PgSQL_Threads_Handler *GloPTH;
// ============================================================================
// Minimal initialization
// ============================================================================
int test_init_minimal() {
return test_globals_init();
}
void test_cleanup_minimal() {
test_globals_cleanup();
}
// ============================================================================
// Authentication
// ============================================================================
int test_init_auth() {
if (GloMyAuth != nullptr || GloPgAuth != nullptr) {
// Already initialized — idempotent
return 0;
}
GloMyAuth = new MySQL_Authentication();
GloPgAuth = new PgSQL_Authentication();
return 0;
}
void test_cleanup_auth() {
if (GloMyAuth != nullptr) {
delete GloMyAuth;
GloMyAuth = nullptr;
}
if (GloPgAuth != nullptr) {
delete GloPgAuth;
GloPgAuth = nullptr;
}
}
// ============================================================================
// Query Cache
// ============================================================================
int test_init_query_cache() {
if (GloMyQC != nullptr || GloPgQC != nullptr) {
return 0;
}
// The Query_Cache constructor registers Prometheus metrics via
// GloVars.prometheus_registry. Provide a real registry so the
// constructor doesn't crash on nullptr dereference.
if (GloVars.prometheus_registry == nullptr) {
GloVars.prometheus_registry = std::make_shared<prometheus::Registry>();
}
GloMyQC = new MySQL_Query_Cache();
GloPgQC = new PgSQL_Query_Cache();
// NOTE: We intentionally do NOT start the purge thread here.
// Unit tests should call purgeHash() explicitly for deterministic
// behavior.
return 0;
}
void test_cleanup_query_cache() {
if (GloMyQC != nullptr) {
delete GloMyQC;
GloMyQC = nullptr;
}
if (GloPgQC != nullptr) {
delete GloPgQC;
GloPgQC = nullptr;
}
}
// ============================================================================
// Query Processor
// ============================================================================
int test_init_query_processor() {
if (GloMyQPro != nullptr || GloPgQPro != nullptr) {
return 0;
}
// Query Processor constructors register Prometheus metrics and
// read variables from GloMTH/GloPTH. Ensure both are available.
if (GloVars.prometheus_registry == nullptr) {
GloVars.prometheus_registry = std::make_shared<prometheus::Registry>();
}
if (GloMTH == nullptr) {
GloMTH = new MySQL_Threads_Handler();
}
if (GloPTH == nullptr) {
GloPTH = new PgSQL_Threads_Handler();
}
// Trigger lazy initialization of VariablesPointers maps.
// The QP constructor calls get_variable_int() which requires
// these maps to be populated.
char **vl = GloMTH->get_variables_list();
if (vl) {
for (char **p = vl; *p != nullptr; ++p) free(*p);
free(vl);
}
vl = GloPTH->get_variables_list();
if (vl) {
for (char **p = vl; *p != nullptr; ++p) free(*p);
free(vl);
}
GloMyQPro = new MySQL_Query_Processor();
GloPgQPro = new PgSQL_Query_Processor();
return 0;
}
void test_cleanup_query_processor() {
if (GloMyQPro != nullptr) {
delete GloMyQPro;
GloMyQPro = nullptr;
}
if (GloPgQPro != nullptr) {
delete GloPgQPro;
GloPgQPro = nullptr;
}
// NOTE: We do NOT delete GloMTH/GloPTH here because other
// components may still reference them. Their cleanup relies
// on process exit.
}
// ============================================================================
// HostGroups Manager
// ============================================================================
int test_init_hostgroups() {
// HostGroups Manager constructors register Prometheus metrics.
if (GloVars.prometheus_registry == nullptr) {
GloVars.prometheus_registry = std::make_shared<prometheus::Registry>();
}
if (MyHGM == nullptr) {
MyHGM = new MySQL_HostGroups_Manager();
// NOTE: We intentionally do NOT call MyHGM->init() here.
// init() starts background threads (HGCU_thread, GTID_syncer)
// that run forever and would cause the test process to hang on
// exit. The constructor alone sets up the internal SQLite3
// database and all data structures needed for unit testing.
}
if (PgHGM == nullptr) {
PgHGM = new PgSQL_HostGroups_Manager();
// PgHGM->init() is a no-op, but we skip it for consistency.
}
return 0;
}
void test_cleanup_hostgroups() {
if (MyHGM != nullptr) {
delete MyHGM;
MyHGM = nullptr;
}
if (PgHGM != nullptr) {
delete PgHGM;
PgHGM = nullptr;
}
}