mirror of https://github.com/sysown/proxysql
Adds the build system and initial smoke test for the unit test framework (Phase 2.1, #5473). - test/tap/tests/unit/Makefile: Compiles unit test binaries linked against libproxysql.a + test_globals.o. Compiles tap.o directly from tap.cpp to avoid the cpp-dotenv dependency chain, making unit tests buildable on both Linux and macOS. Handles platform-specific linker flags (Darwin vs Linux). - test/tap/tests/unit/smoke_test-t.cpp: Validates the test harness by exercising test_init_minimal() (GloVars setup), test_init_auth() (MySQL_Authentication add/lookup/exists cycle), and idempotency of all init/cleanup functions. Runs in <1 second with no Docker or network dependencies.pull/5486/head
parent
803eb27590
commit
43c04fb394
@ -0,0 +1,263 @@
|
||||
#!/bin/make -f
|
||||
#
|
||||
# Makefile for ProxySQL unit tests.
|
||||
#
|
||||
# Unit tests link against libproxysql.a with stub globals (test_globals.o)
|
||||
# instead of main.o, allowing individual components to be tested in
|
||||
# isolation without a running ProxySQL daemon or backend servers.
|
||||
#
|
||||
# See: GitHub issue #5473 (Phase 2.1: Test Infrastructure Foundation)
|
||||
|
||||
|
||||
PROXYSQL_PATH := $(shell while [ ! -f ./src/proxysql_global.cpp ]; do cd ..; done; pwd)
|
||||
|
||||
include $(PROXYSQL_PATH)/include/makefiles_vars.mk
|
||||
include $(PROXYSQL_PATH)/include/makefiles_paths.mk
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Include directories — mirrors test/tap/tests/Makefile
|
||||
# ===========================================================================
|
||||
|
||||
IDIRS := -I$(TAP_IDIR) \
|
||||
-I$(RE2_IDIR) \
|
||||
-I$(PROXYSQL_IDIR) \
|
||||
-I$(JEMALLOC_IDIR) \
|
||||
-I$(LIBCONFIG_IDIR) \
|
||||
-I$(MARIADB_IDIR) \
|
||||
-I$(LIBDAEMON_IDIR) \
|
||||
-I$(MICROHTTPD_IDIR) \
|
||||
-I$(LIBHTTPSERVER_IDIR) \
|
||||
-I$(CURL_IDIR) -I$(EV_IDIR) \
|
||||
-I$(PROMETHEUS_IDIR) \
|
||||
-I$(DOTENV_DYN_IDIR) \
|
||||
-I$(SQLITE3_IDIR) \
|
||||
-I$(JSON_IDIR) \
|
||||
-I$(POSTGRESQL_IDIR) \
|
||||
-I$(LIBSCRAM_IDIR) \
|
||||
-I$(LIBUSUAL_IDIR) \
|
||||
-I$(SSL_IDIR) \
|
||||
-I$(ZSTD_IDIR) \
|
||||
-I$(PROXYSQL_PATH)/include \
|
||||
-I$(PROXYSQL_PATH)/test/tap/test_helpers
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Library directories
|
||||
# ===========================================================================
|
||||
|
||||
LDIRS := -L$(TAP_LDIR) \
|
||||
-L$(RE2_LDIR) \
|
||||
-L$(PROXYSQL_LDIR) \
|
||||
-L$(JEMALLOC_LDIR) \
|
||||
-L$(LIBCONFIG_LDIR) \
|
||||
-L$(MARIADB_LDIR) \
|
||||
-L$(LIBDAEMON_LDIR) \
|
||||
-L$(MICROHTTPD_LDIR) \
|
||||
-L$(LIBHTTPSERVER_LDIR) \
|
||||
-L$(CURL_LDIR) -L$(EV_LDIR) \
|
||||
-L$(PROMETHEUS_LDIR) \
|
||||
-L$(DOTENV_DYN_LDIR) \
|
||||
-L$(PCRE_LDIR) \
|
||||
-L$(LIBINJECTION_LDIR) \
|
||||
-L$(POSTGRESQL_LDIR) \
|
||||
-L$(LIBSCRAM_LDIR) \
|
||||
-L$(LIBUSUAL_LDIR) \
|
||||
-L$(SSL_LDIR)
|
||||
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
LDIRS += -L$(COREDUMPER_LDIR)
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
IDIRS += -I/usr/local/include -I/opt/homebrew/include
|
||||
LDIRS += -L/usr/local/lib -L/opt/homebrew/lib
|
||||
endif
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# ClickHouse include/link paths (enabled by default)
|
||||
# ===========================================================================
|
||||
|
||||
CLICKHOUSE_CPP_PATH := $(DEPS_PATH)/clickhouse-cpp/clickhouse-cpp
|
||||
CLICKHOUSE_CPP_IDIR := $(CLICKHOUSE_CPP_PATH) -I$(CLICKHOUSE_CPP_PATH)/contrib/absl
|
||||
CLICKHOUSE_CPP_LDIR := $(CLICKHOUSE_CPP_PATH)/clickhouse
|
||||
LZ4_LDIR := $(DEPS_PATH)/lz4/lz4/lib
|
||||
|
||||
IDIRS += -I$(CLICKHOUSE_CPP_IDIR)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# libproxysql.a — the core library under test
|
||||
# ===========================================================================
|
||||
|
||||
LIBPROXYSQLAR := $(PROXYSQL_LDIR)/libproxysql.a
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Static libraries required at link time
|
||||
# ===========================================================================
|
||||
|
||||
STATIC_LIBS := $(CITYHASH_LDIR)/libcityhash.a \
|
||||
$(LZ4_LDIR)/liblz4.a \
|
||||
$(ZSTD_LDIR)/libzstd.a
|
||||
|
||||
ifeq ($(PROXYSQLCLICKHOUSE),1)
|
||||
STATIC_LIBS += $(CLICKHOUSE_CPP_LDIR)/libclickhouse-cpp-lib.a
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
STATIC_LIBS += $(COREDUMPER_LDIR)/libcoredumper.a
|
||||
endif
|
||||
|
||||
ifeq ($(PROXYSQLGENAI),1)
|
||||
STATIC_LIBS += $(SQLITE3_LDIR)/../libsqlite_rembed.a $(SQLITE3_LDIR)/vec.o
|
||||
endif
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Linker flags — platform-specific
|
||||
# ===========================================================================
|
||||
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
# macOS: No -Bstatic/-Bdynamic; use explicit .a paths for static linking.
|
||||
# libproxysql.a already bundles most deps on Darwin (see src/Makefile).
|
||||
LIBPROXYSQLAR_FULL := $(LIBPROXYSQLAR) \
|
||||
$(JEMALLOC_LDIR)/libjemalloc.a \
|
||||
$(MICROHTTPD_LDIR)/libmicrohttpd.a \
|
||||
$(LIBHTTPSERVER_LDIR)/libhttpserver.a \
|
||||
$(PCRE_LDIR)/libpcre.a \
|
||||
$(PCRE_LDIR)/libpcrecpp.a \
|
||||
$(LIBDAEMON_LDIR)/libdaemon.a \
|
||||
$(LIBCONFIG_LDIR)/libconfig++.a \
|
||||
$(LIBCONFIG_LDIR)/libconfig.a \
|
||||
$(CURL_LDIR)/libcurl.a \
|
||||
$(SQLITE3_LDIR)/sqlite3.o \
|
||||
$(LIBINJECTION_LDIR)/libinjection.a \
|
||||
$(EV_LDIR)/libev.a \
|
||||
$(LIBSCRAM_LDIR)/libscram.a \
|
||||
$(LIBUSUAL_LDIR)/libusual.a \
|
||||
$(MARIADB_LDIR)/libmariadbclient.a \
|
||||
$(RE2_LDIR)/libre2.a \
|
||||
$(POSTGRESQL_PATH)/interfaces/libpq/libpq.a \
|
||||
$(POSTGRESQL_PATH)/common/libpgcommon.a \
|
||||
$(POSTGRESQL_PATH)/port/libpgport.a
|
||||
|
||||
MYLIBS := -lssl -lcrypto -lpthread -lm -lz \
|
||||
-liconv -lgnutls -lprometheus-cpp-pull -lprometheus-cpp-core -luuid \
|
||||
-lzstd $(LWGCOV)
|
||||
else
|
||||
# Linux/FreeBSD: Use -Bstatic/-Bdynamic for controlled linking.
|
||||
LIBPROXYSQLAR_FULL := $(LIBPROXYSQLAR)
|
||||
|
||||
MYLIBS := -Wl,--export-dynamic -Wl,-Bdynamic -lgnutls -lcurl -lssl -lcrypto -luuid \
|
||||
-Wl,-Bstatic -lconfig -lproxysql -ldaemon -lconfig++ -lre2 -lpcrecpp -lpcre \
|
||||
-lmariadbclient -lhttpserver -lmicrohttpd -linjection -lev \
|
||||
-lprometheus-cpp-pull -lprometheus-cpp-core \
|
||||
-Wl,-Bstatic -lpq -lpgcommon -lpgport \
|
||||
-Wl,-Bdynamic -lpthread -lm -lz -lzstd -lrt -ldl \
|
||||
-lscram -lusual -Wl,--allow-multiple-definition \
|
||||
$(LWGCOV)
|
||||
endif
|
||||
|
||||
ifneq ($(NOJEMALLOC),1)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
MYLIBS += -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Compiler flags
|
||||
# ===========================================================================
|
||||
|
||||
PSQLCH :=
|
||||
ifeq ($(PROXYSQLCLICKHOUSE),1)
|
||||
PSQLCH := -DPROXYSQLCLICKHOUSE
|
||||
endif
|
||||
PSQLGA :=
|
||||
ifeq ($(PROXYSQLGENAI),1)
|
||||
PSQLGA := -DPROXYSQLGENAI
|
||||
endif
|
||||
PSQL31 :=
|
||||
ifeq ($(PROXYSQL31),1)
|
||||
PSQL31 := -DPROXYSQL31
|
||||
endif
|
||||
PSQLFFTO :=
|
||||
ifeq ($(PROXYSQLFFTO),1)
|
||||
PSQLFFTO := -DPROXYSQLFFTO
|
||||
endif
|
||||
PSQLTSDB :=
|
||||
ifeq ($(PROXYSQLTSDB),1)
|
||||
PSQLTSDB := -DPROXYSQLTSDB
|
||||
endif
|
||||
|
||||
OPT := $(STDCPP) -O0 -ggdb $(PSQLCH) $(PSQLGA) $(PSQL31) $(PSQLFFTO) $(PSQLTSDB) \
|
||||
-DGITVERSION=\"$(GIT_VERSION)\" $(NOJEM) $(WGCOV) $(WASAN) \
|
||||
-Wl,--no-as-needed -Wl,-rpath,$(TAP_LDIR)
|
||||
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
OPT := $(STDCPP) -O0 -ggdb $(PSQLCH) $(PSQLGA) $(PSQL31) $(PSQLFFTO) $(PSQLTSDB) \
|
||||
-DGITVERSION=\"$(GIT_VERSION)\" $(NOJEM) $(WGCOV) $(WASAN)
|
||||
endif
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Test helper objects
|
||||
# ===========================================================================
|
||||
|
||||
TEST_HELPERS_DIR := $(PROXYSQL_PATH)/test/tap/test_helpers
|
||||
ODIR := obj
|
||||
|
||||
TEST_HELPERS_OBJ := $(ODIR)/test_globals.o $(ODIR)/test_init.o $(ODIR)/tap.o
|
||||
|
||||
$(ODIR):
|
||||
mkdir -p $(ODIR)
|
||||
|
||||
# Compile tap.o directly from tap.cpp to avoid the full TAP build chain
|
||||
# and its cpp-dotenv dependency (which doesn't build on macOS).
|
||||
# Unit tests only need the core TAP functions: plan(), ok(), is(), etc.
|
||||
TAP_SRC := $(TAP_PATH)/tap.cpp
|
||||
$(ODIR)/tap.o: $(TAP_SRC) | $(ODIR)
|
||||
$(CXX) -c -o $@ $< $(OPT) $(IDIRS) -w
|
||||
|
||||
$(ODIR)/test_globals.o: $(TEST_HELPERS_DIR)/test_globals.cpp | $(ODIR)
|
||||
$(CXX) -c -o $@ $< $(OPT) $(IDIRS) -Wall
|
||||
|
||||
$(ODIR)/test_init.o: $(TEST_HELPERS_DIR)/test_init.cpp | $(ODIR)
|
||||
$(CXX) -c -o $@ $< $(OPT) $(IDIRS) -Wall
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Unit test targets
|
||||
# ===========================================================================
|
||||
|
||||
UNIT_TESTS := smoke_test-t
|
||||
|
||||
.DEFAULT: default
|
||||
.PHONY: default debug all
|
||||
|
||||
default: all
|
||||
debug: OPT += -DDEBUG
|
||||
debug: all
|
||||
|
||||
all: $(UNIT_TESTS)
|
||||
|
||||
ALLOW_MULTI_DEF :=
|
||||
ifneq ($(UNAME_S),Darwin)
|
||||
ALLOW_MULTI_DEF := -Wl,--allow-multiple-definition
|
||||
endif
|
||||
|
||||
smoke_test-t: smoke_test-t.cpp $(TEST_HELPERS_OBJ) $(LIBPROXYSQLAR)
|
||||
$(CXX) $< $(TEST_HELPERS_OBJ) $(IDIRS) $(LDIRS) $(OPT) \
|
||||
$(LIBPROXYSQLAR_FULL) $(STATIC_LIBS) $(MYLIBS) \
|
||||
$(ALLOW_MULTI_DEF) -o $@
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Clean
|
||||
# ===========================================================================
|
||||
|
||||
.PHONY: clean
|
||||
.SILENT: clean
|
||||
clean:
|
||||
rm -rf $(ODIR) $(UNIT_TESTS)
|
||||
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file smoke_test-t.cpp
|
||||
* @brief Smoke test for the ProxySQL unit test harness.
|
||||
*
|
||||
* Validates that the test infrastructure (test_globals + test_init)
|
||||
* works correctly by performing minimal operations on each supported
|
||||
* component. This test must pass before any component-specific unit
|
||||
* tests can be trusted.
|
||||
*
|
||||
* Test coverage:
|
||||
* 1. test_init_minimal() — GloVars is usable
|
||||
* 2. test_init_auth() — MySQL_Authentication add/lookup cycle
|
||||
* 3. test_cleanup_*() — clean shutdown without leaks
|
||||
*
|
||||
* @see Phase 2.1 of the Unit Testing Framework (GitHub issue #5473)
|
||||
*/
|
||||
|
||||
#include "tap.h"
|
||||
#include "test_globals.h"
|
||||
#include "test_init.h"
|
||||
|
||||
#include "proxysql.h"
|
||||
#include "MySQL_Authentication.hpp"
|
||||
#include "PgSQL_Authentication.h"
|
||||
|
||||
// Extern declarations for Glo* pointers (defined in test_globals.cpp)
|
||||
extern MySQL_Authentication *GloMyAuth;
|
||||
extern PgSQL_Authentication *GloPgAuth;
|
||||
|
||||
/**
|
||||
* @brief Test that minimal initialization sets up GloVars correctly.
|
||||
*/
|
||||
static void test_minimal_init() {
|
||||
int rc = test_init_minimal();
|
||||
ok(rc == 0, "test_init_minimal() returns 0");
|
||||
ok(GloVars.datadir != nullptr, "GloVars.datadir is set after init");
|
||||
ok(GloVars.global.nostart == true, "GloVars.global.nostart is true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test MySQL_Authentication add/lookup/del cycle.
|
||||
*/
|
||||
static void test_mysql_auth_basic() {
|
||||
int rc = test_init_auth();
|
||||
ok(rc == 0, "test_init_auth() returns 0");
|
||||
ok(GloMyAuth != nullptr, "GloMyAuth is initialized");
|
||||
ok(GloPgAuth != nullptr, "GloPgAuth is initialized");
|
||||
|
||||
// Add a frontend user
|
||||
bool added = GloMyAuth->add(
|
||||
(char *)"testuser", // username
|
||||
(char *)"testpass", // password
|
||||
USERNAME_FRONTEND, // user type
|
||||
false, // use_ssl
|
||||
0, // default_hostgroup
|
||||
(char *)"", // default_schema
|
||||
false, // schema_locked
|
||||
false, // transaction_persistent
|
||||
false, // fast_forward
|
||||
100, // max_connections
|
||||
(char *)"", // attributes
|
||||
(char *)"" // comment
|
||||
);
|
||||
ok(added == true, "GloMyAuth->add() succeeds for frontend user");
|
||||
|
||||
// Verify user exists
|
||||
bool exists = GloMyAuth->exists((char *)"testuser");
|
||||
ok(exists == true, "GloMyAuth->exists() returns true for added user");
|
||||
|
||||
// Verify user does not exist
|
||||
bool not_exists = GloMyAuth->exists((char *)"nonexistent");
|
||||
ok(not_exists == false, "GloMyAuth->exists() returns false for unknown user");
|
||||
|
||||
// Cleanup
|
||||
test_cleanup_auth();
|
||||
ok(GloMyAuth == nullptr, "GloMyAuth is nullptr after cleanup");
|
||||
ok(GloPgAuth == nullptr, "GloPgAuth is nullptr after cleanup");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test idempotency of init/cleanup functions.
|
||||
*/
|
||||
static void test_idempotency() {
|
||||
// Double init should be safe
|
||||
int rc1 = test_init_minimal();
|
||||
int rc2 = test_init_minimal();
|
||||
ok(rc1 == 0 && rc2 == 0, "test_init_minimal() is idempotent");
|
||||
|
||||
int rc3 = test_init_auth();
|
||||
int rc4 = test_init_auth();
|
||||
ok(rc3 == 0 && rc4 == 0, "test_init_auth() is idempotent");
|
||||
|
||||
// Double cleanup should be safe
|
||||
test_cleanup_auth();
|
||||
test_cleanup_auth(); // should not crash
|
||||
ok(1, "test_cleanup_auth() double-call does not crash");
|
||||
|
||||
test_cleanup_minimal();
|
||||
test_cleanup_minimal(); // should not crash
|
||||
ok(1, "test_cleanup_minimal() double-call does not crash");
|
||||
}
|
||||
|
||||
int main() {
|
||||
plan(15);
|
||||
|
||||
test_minimal_init();
|
||||
test_mysql_auth_basic();
|
||||
test_idempotency();
|
||||
|
||||
return exit_status();
|
||||
}
|
||||
Loading…
Reference in new issue