Centralize runtime config defaults

This commit is contained in:
m1ngsama 2026-05-28 11:42:31 +08:00
parent 0da5f51e2e
commit d4b260c160
15 changed files with 271 additions and 81 deletions

View file

@ -26,7 +26,7 @@ OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
DEPS = $(OBJECTS:.o=.d) $(CTL_OBJECTS:.o=.d)
TARGET = tnt
CTL_TARGET = tntctl
CTL_OBJECTS = $(OBJ_DIR)/tntctl.o $(OBJ_DIR)/tntctl_text.o $(OBJ_DIR)/exec_catalog.o $(OBJ_DIR)/common.o $(OBJ_DIR)/i18n.o
CTL_OBJECTS = $(OBJ_DIR)/tntctl.o $(OBJ_DIR)/tntctl_text.o $(OBJ_DIR)/exec_catalog.o $(OBJ_DIR)/common.o $(OBJ_DIR)/config_defaults.o $(OBJ_DIR)/i18n.o
TARGETS = $(TARGET) $(CTL_TARGET)
PREFIX ?= /usr/local

View file

@ -7,6 +7,8 @@
`vX.Y.Z` tag must match `TNT_VERSION` before release assets are built.
- Added `make package-publish-check` for verifying Arch/Homebrew source
checksums against the final GitHub source archive after a tag exists.
- Added a `config_defaults` module and unit coverage for runtime default
values, env keys, and accepted numeric ranges.
- Added a dedicated `tntctl_text` module with unit coverage for local
`tntctl` help and validation diagnostics.
- Documented the stable SSH exec interface contract, including exit statuses

View file

@ -11,6 +11,8 @@
#include <limits.h>
#include <pthread.h>
#include "config_defaults.h"
/* Project Metadata */
#define TNT_VERSION "1.0.1"
@ -23,7 +25,6 @@
#define TNT_EXIT_CONFIG 78
/* Configuration constants */
#define DEFAULT_PORT 2222
#define MAX_MESSAGES 100
#define MAX_USERNAME_LEN 64
#define MAX_MESSAGE_LEN 1024
@ -31,13 +32,17 @@
#define MAX_COMMAND_OUTPUT_LEN 8192
#define CLIENT_OUTBOX_CAPACITY (128 * 1024)
#define CLIENT_OUTBOX_FLUSH_BUDGET 32768
#define DEFAULT_MAX_CLIENTS 64
#define MAX_CONFIGURED_CLIENTS 1024
#define LOG_FILE "messages.log"
#define MAX_LOG_SIZE (10 * 1024 * 1024) /* 10 MiB */
#define HOST_KEY_FILE "host_key"
#define TNT_DEFAULT_STATE_DIR "."
#define DEFAULT_IDLE_TIMEOUT 1800 /* 30 minutes */
/* Backward-compatible names for older modules while config_defaults owns the
* actual runtime defaults and accepted ranges. */
#define DEFAULT_PORT TNT_DEFAULT_PORT
#define DEFAULT_MAX_CLIENTS TNT_DEFAULT_MAX_CONNECTIONS
#define MAX_CONFIGURED_CLIENTS TNT_MAX_CONFIGURED_CLIENTS
#define DEFAULT_IDLE_TIMEOUT TNT_DEFAULT_IDLE_TIMEOUT
/* ANSI color codes */
#define ANSI_RESET "\033[0m"

47
include/config_defaults.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef CONFIG_DEFAULTS_H
#define CONFIG_DEFAULTS_H
#include <stdbool.h>
#define TNT_STRINGIFY_VALUE(value) #value
#define TNT_STRINGIFY(value) TNT_STRINGIFY_VALUE(value)
#define TNT_DEFAULT_PORT 2222
#define TNT_DEFAULT_PORT_TEXT TNT_STRINGIFY(TNT_DEFAULT_PORT)
#define TNT_DEFAULT_MAX_CONNECTIONS 64
#define TNT_DEFAULT_MAX_CONN_PER_IP 5
#define TNT_DEFAULT_MAX_CONN_RATE_PER_IP 10
#define TNT_DEFAULT_RATE_LIMIT_ENABLED 1
#define TNT_DEFAULT_IDLE_TIMEOUT 1800
#define TNT_MIN_PORT 1
#define TNT_MAX_PORT 65535
#define TNT_MIN_CONFIGURED_CLIENTS 1
#define TNT_MAX_CONFIGURED_CLIENTS 1024
#define TNT_MIN_RATE_LIMIT_ENABLED 0
#define TNT_MAX_RATE_LIMIT_ENABLED 1
#define TNT_MIN_IDLE_TIMEOUT 0
#define TNT_MAX_IDLE_TIMEOUT 86400
#define TNT_MIN_SSH_LOG_LEVEL 0
#define TNT_MAX_SSH_LOG_LEVEL 4
typedef struct {
const char *env_name;
int fallback;
int min_value;
int max_value;
} tnt_int_config_spec_t;
extern const tnt_int_config_spec_t TNT_CONFIG_PORT;
extern const tnt_int_config_spec_t TNT_CONFIG_MAX_CONNECTIONS;
extern const tnt_int_config_spec_t TNT_CONFIG_MAX_CONN_PER_IP;
extern const tnt_int_config_spec_t TNT_CONFIG_MAX_CONN_RATE_PER_IP;
extern const tnt_int_config_spec_t TNT_CONFIG_RATE_LIMIT;
extern const tnt_int_config_spec_t TNT_CONFIG_IDLE_TIMEOUT;
extern const tnt_int_config_spec_t TNT_CONFIG_SSH_LOG_LEVEL;
int tnt_config_env_int(const tnt_int_config_spec_t *spec);
bool tnt_config_parse_int(const char *value, const tnt_int_config_spec_t *spec,
int *out);
#endif /* CONFIG_DEFAULTS_H */

View file

@ -1,11 +1,11 @@
#include "chat_room.h"
#include "config_defaults.h"
/* Global chat room instance */
chat_room_t *g_room = NULL;
static int room_capacity_from_env(void) {
return env_int("TNT_MAX_CONNECTIONS", DEFAULT_MAX_CLIENTS, 1,
MAX_CONFIGURED_CLIENTS);
return tnt_config_env_int(&TNT_CONFIG_MAX_CONNECTIONS);
}
/* Initialize chat room */

View file

@ -1,5 +1,6 @@
#include "cli_text.h"
#include "config_defaults.h"
#include "i18n.h"
void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos,
@ -12,7 +13,7 @@ void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos,
" -d, --state-dir DIR Store host key and logs in DIR\n"
" --bind ADDR Bind to ADDR (default: 0.0.0.0)\n"
" --public-host HOST Show HOST in startup connection hints\n"
" --max-connections N Global connection limit (default: 64)\n"
" --max-connections N Global connection limit (default: %d)\n"
" --max-conn-per-ip N Per-IP concurrent session limit\n"
" --max-conn-rate-per-ip N Per-IP connection-rate limit\n"
" --rate-limit 0|1 Disable/enable rate-based blocking\n"
@ -28,9 +29,9 @@ void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos,
" TNT_STATE_DIR State directory\n"
" TNT_ACCESS_TOKEN Require this password for SSH auth\n"
" TNT_LANG UI language: en or zh (default: locale)\n"
" TNT_MAX_CONNECTIONS Global connection limit (default: 64)\n"
" TNT_MAX_CONNECTIONS Global connection limit (default: %d)\n"
" TNT_RATE_LIMIT Set to 0 to disable rate limiting\n"
" TNT_IDLE_TIMEOUT Idle disconnect timeout in seconds (default: 1800)\n",
" TNT_IDLE_TIMEOUT Idle disconnect timeout in seconds (default: %d)\n",
"tnt %s - 匿名 SSH 聊天服务器\n\n"
"用法: %s [options]\n\n"
"选项:\n"
@ -38,7 +39,7 @@ void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos,
" -d, --state-dir DIR 将主机密钥和日志存放在 DIR\n"
" --bind ADDR 绑定到 ADDR (默认: 0.0.0.0)\n"
" --public-host HOST 在启动提示中显示 HOST\n"
" --max-connections N 全局连接数限制 (默认: 64)\n"
" --max-connections N 全局连接数限制 (默认: %d)\n"
" --max-conn-per-ip N 单 IP 并发会话限制\n"
" --max-conn-rate-per-ip N 单 IP 连接速率限制\n"
" --rate-limit 0|1 禁用/启用速率封禁\n"
@ -54,16 +55,19 @@ void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos,
" TNT_STATE_DIR 状态目录\n"
" TNT_ACCESS_TOKEN 要求 SSH 认证使用此密码\n"
" TNT_LANG UI 语言: en 或 zh (默认跟随 locale)\n"
" TNT_MAX_CONNECTIONS 全局连接数限制 (默认: 64)\n"
" TNT_MAX_CONNECTIONS 全局连接数限制 (默认: %d)\n"
" TNT_RATE_LIMIT 设为 0 可禁用速率限制\n"
" TNT_IDLE_TIMEOUT 空闲断开时间,单位秒 (默认: 1800)\n"
" TNT_IDLE_TIMEOUT 空闲断开时间,单位秒 (默认: %d)\n"
);
const char *program = (program_name && program_name[0] != '\0')
? program_name
: "tnt";
buffer_appendf(buffer, buf_size, pos, i18n_string(help_format, lang),
TNT_VERSION, program, DEFAULT_PORT);
TNT_VERSION, program, TNT_DEFAULT_PORT,
TNT_DEFAULT_MAX_CONNECTIONS,
TNT_DEFAULT_MAX_CONNECTIONS,
TNT_DEFAULT_IDLE_TIMEOUT);
}
const char *cli_text_invalid_port_format(ui_lang_t lang) {

80
src/config_defaults.c Normal file
View file

@ -0,0 +1,80 @@
#include "config_defaults.h"
#include "common.h"
#include <stdlib.h>
const tnt_int_config_spec_t TNT_CONFIG_PORT = {
"PORT",
TNT_DEFAULT_PORT,
TNT_MIN_PORT,
TNT_MAX_PORT,
};
const tnt_int_config_spec_t TNT_CONFIG_MAX_CONNECTIONS = {
"TNT_MAX_CONNECTIONS",
TNT_DEFAULT_MAX_CONNECTIONS,
TNT_MIN_CONFIGURED_CLIENTS,
TNT_MAX_CONFIGURED_CLIENTS,
};
const tnt_int_config_spec_t TNT_CONFIG_MAX_CONN_PER_IP = {
"TNT_MAX_CONN_PER_IP",
TNT_DEFAULT_MAX_CONN_PER_IP,
TNT_MIN_CONFIGURED_CLIENTS,
TNT_MAX_CONFIGURED_CLIENTS,
};
const tnt_int_config_spec_t TNT_CONFIG_MAX_CONN_RATE_PER_IP = {
"TNT_MAX_CONN_RATE_PER_IP",
TNT_DEFAULT_MAX_CONN_RATE_PER_IP,
TNT_MIN_CONFIGURED_CLIENTS,
TNT_MAX_CONFIGURED_CLIENTS,
};
const tnt_int_config_spec_t TNT_CONFIG_RATE_LIMIT = {
"TNT_RATE_LIMIT",
TNT_DEFAULT_RATE_LIMIT_ENABLED,
TNT_MIN_RATE_LIMIT_ENABLED,
TNT_MAX_RATE_LIMIT_ENABLED,
};
const tnt_int_config_spec_t TNT_CONFIG_IDLE_TIMEOUT = {
"TNT_IDLE_TIMEOUT",
TNT_DEFAULT_IDLE_TIMEOUT,
TNT_MIN_IDLE_TIMEOUT,
TNT_MAX_IDLE_TIMEOUT,
};
const tnt_int_config_spec_t TNT_CONFIG_SSH_LOG_LEVEL = {
"TNT_SSH_LOG_LEVEL",
0,
TNT_MIN_SSH_LOG_LEVEL,
TNT_MAX_SSH_LOG_LEVEL,
};
int tnt_config_env_int(const tnt_int_config_spec_t *spec) {
if (!spec) {
return 0;
}
return env_int(spec->env_name, spec->fallback, spec->min_value,
spec->max_value);
}
bool tnt_config_parse_int(const char *value, const tnt_int_config_spec_t *spec,
int *out) {
char *end = NULL;
long val;
if (!value || value[0] == '\0' || !spec || !out) {
return false;
}
val = strtol(value, &end, 10);
if (!end || *end != '\0' || val < spec->min_value ||
val > spec->max_value) {
return false;
}
*out = (int)val;
return true;
}

View file

@ -2,6 +2,7 @@
#include "chat_room.h"
#include "client.h"
#include "commands.h"
#include "config_defaults.h"
#include "common.h"
#include "exec.h"
#include "history_view.h"
@ -20,11 +21,11 @@
#include <string.h>
#include <time.h>
static int g_idle_timeout = DEFAULT_IDLE_TIMEOUT;
static int g_idle_timeout = TNT_DEFAULT_IDLE_TIMEOUT;
static ui_lang_t g_default_ui_lang = UI_LANG_EN;
void input_init(void) {
g_idle_timeout = env_int("TNT_IDLE_TIMEOUT", DEFAULT_IDLE_TIMEOUT, 0, 86400);
g_idle_timeout = tnt_config_env_int(&TNT_CONFIG_IDLE_TIMEOUT);
g_default_ui_lang = i18n_default_ui_lang();
}

View file

@ -1,5 +1,6 @@
#include "chat_room.h"
#include "cli_text.h"
#include "config_defaults.h"
#include "common.h"
#include "i18n.h"
#include "message.h"
@ -19,24 +20,6 @@ static void signal_handler(int sig) {
_exit(0);
}
static bool parse_int_arg(const char *value, int min_val, int max_val,
int *out) {
char *end = NULL;
long val;
if (!value || value[0] == '\0' || !out) {
return false;
}
val = strtol(value, &end, 10);
if (!end || *end != '\0' || val < min_val || val > max_val) {
return false;
}
*out = (int)val;
return true;
}
static bool is_config_token(const char *value) {
const unsigned char *p = (const unsigned char *)value;
@ -60,16 +43,16 @@ static int set_env_option(const char *name, const char *value) {
return 0;
}
static int set_numeric_env_option(const char *env_name, const char *opt_name,
const char *value, int min_val,
int max_val, ui_lang_t lang) {
static int set_numeric_env_option(const tnt_int_config_spec_t *spec,
const char *opt_name, const char *value,
ui_lang_t lang) {
int parsed;
if (!parse_int_arg(value, min_val, max_val, &parsed)) {
if (!tnt_config_parse_int(value, spec, &parsed)) {
fprintf(stderr, cli_text_invalid_value_format(lang), opt_name, value);
return TNT_EXIT_USAGE;
}
if (set_env_option(env_name, value) != 0) {
if (set_env_option(spec->env_name, value) != 0) {
return TNT_EXIT_ERROR;
}
return TNT_EXIT_OK;
@ -86,21 +69,11 @@ static bool require_option_arg(int argc, char **argv, int index,
}
int main(int argc, char **argv) {
int port = DEFAULT_PORT;
int port = tnt_config_env_int(&TNT_CONFIG_PORT);
ui_lang_t lang = i18n_default_ui_lang();
const char *log_check_path = NULL;
const char *log_recover_path = NULL;
/* Environment provides defaults; command-line flags override it. */
const char *port_env = getenv("PORT");
if (port_env && port_env[0] != '\0') {
char *end;
long val = strtol(port_env, &end, 10);
if (*end == '\0' && val > 0 && val <= 65535) {
port = (int)val;
}
}
/* Parse command line arguments */
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) {
@ -108,7 +81,7 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
if (!parse_int_arg(argv[i + 1], 1, 65535, &val)) {
if (!tnt_config_parse_int(argv[i + 1], &TNT_CONFIG_PORT, &val)) {
fprintf(stderr, cli_text_invalid_port_format(lang),
argv[i + 1]);
return TNT_EXIT_USAGE;
@ -154,9 +127,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_MAX_CONNECTIONS", argv[i],
argv[i + 1], 1,
MAX_CONFIGURED_CLIENTS, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_MAX_CONNECTIONS,
argv[i], argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}
@ -165,9 +137,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_MAX_CONN_PER_IP", argv[i],
argv[i + 1], 1,
MAX_CONFIGURED_CLIENTS, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_MAX_CONN_PER_IP,
argv[i], argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}
@ -176,9 +147,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_MAX_CONN_RATE_PER_IP",
argv[i], argv[i + 1], 1,
MAX_CONFIGURED_CLIENTS, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_MAX_CONN_RATE_PER_IP,
argv[i], argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}
@ -187,8 +157,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_RATE_LIMIT", argv[i],
argv[i + 1], 0, 1, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_RATE_LIMIT, argv[i],
argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}
@ -197,8 +167,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_IDLE_TIMEOUT", argv[i],
argv[i + 1], 0, 86400, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_IDLE_TIMEOUT, argv[i],
argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}
@ -207,8 +177,8 @@ int main(int argc, char **argv) {
if (!require_option_arg(argc, argv, i, lang)) {
return TNT_EXIT_USAGE;
}
int rc = set_numeric_env_option("TNT_SSH_LOG_LEVEL", argv[i],
argv[i + 1], 0, 4, lang);
int rc = set_numeric_env_option(&TNT_CONFIG_SSH_LOG_LEVEL,
argv[i], argv[i + 1], lang);
if (rc != TNT_EXIT_OK) {
return rc;
}

View file

@ -1,4 +1,5 @@
#include "ratelimit.h"
#include "config_defaults.h"
#include "common.h"
#include <arpa/inet.h>
#include <pthread.h>
@ -27,16 +28,20 @@ static pthread_mutex_t g_rate_limit_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_total_connections = 0;
static pthread_mutex_t g_conn_count_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_max_connections = 64;
static int g_max_conn_per_ip = 5;
static int g_max_conn_rate_per_ip = 10;
static int g_rate_limit_enabled = 1;
static int g_max_connections = TNT_DEFAULT_MAX_CONNECTIONS;
static int g_max_conn_per_ip = TNT_DEFAULT_MAX_CONN_PER_IP;
static int g_max_conn_rate_per_ip = TNT_DEFAULT_MAX_CONN_RATE_PER_IP;
static int g_rate_limit_enabled = TNT_DEFAULT_RATE_LIMIT_ENABLED;
void ratelimit_init(void) {
g_max_connections = env_int("TNT_MAX_CONNECTIONS", 64, 1, 1024);
g_max_conn_per_ip = env_int("TNT_MAX_CONN_PER_IP", 5, 1, 1024);
g_max_conn_rate_per_ip = env_int("TNT_MAX_CONN_RATE_PER_IP", 10, 1, 1024);
g_rate_limit_enabled = env_int("TNT_RATE_LIMIT", 1, 0, 1);
g_max_connections =
tnt_config_env_int(&TNT_CONFIG_MAX_CONNECTIONS);
g_max_conn_per_ip =
tnt_config_env_int(&TNT_CONFIG_MAX_CONN_PER_IP);
g_max_conn_rate_per_ip =
tnt_config_env_int(&TNT_CONFIG_MAX_CONN_RATE_PER_IP);
g_rate_limit_enabled =
tnt_config_env_int(&TNT_CONFIG_RATE_LIMIT);
}
/* Caller MUST hold g_rate_limit_lock. */

View file

@ -1,6 +1,7 @@
#include "ssh_server.h"
#include "bootstrap.h"
#include "commands.h"
#include "config_defaults.h"
#include "exec.h"
#include "input.h"
#include "ratelimit.h"
@ -23,7 +24,7 @@
/* Global SSH bind instance */
static ssh_bind g_sshbind = NULL;
static int g_listen_port = DEFAULT_PORT;
static int g_listen_port = TNT_DEFAULT_PORT;
static time_t g_server_start_time = 0;

View file

@ -1,4 +1,5 @@
#include "common.h"
#include "config_defaults.h"
#include "exec_catalog.h"
#include "i18n.h"
#include "tntctl_text.h"
@ -145,7 +146,7 @@ static int run_ssh(char **ssh_argv) {
}
int main(int argc, char **argv) {
const char *port = "2222";
const char *port = TNT_DEFAULT_PORT_TEXT;
const char *login = NULL;
const char *host_key_checking = NULL;
const char *known_hosts = NULL;

View file

@ -1,5 +1,6 @@
#include "tntctl_text.h"
#include "config_defaults.h"
#include "exec_catalog.h"
#include "i18n.h"
@ -61,7 +62,7 @@ void tntctl_text_append_usage(char *buffer, size_t buf_size, size_t *pos,
"Usage: tntctl [options] host command [args...]\n"
"\n"
"Options:\n"
" -p, --port PORT SSH port (default: 2222)\n"
" -p, --port PORT SSH port (default: " TNT_DEFAULT_PORT_TEXT ")\n"
" -l, --login USER SSH login name for exec identity\n"
" --host-key-checking MODE\n"
" OpenSSH host-key mode: yes, accept-new, no\n"
@ -74,7 +75,7 @@ void tntctl_text_append_usage(char *buffer, size_t buf_size, size_t *pos,
"用法: tntctl [options] host command [args...]\n"
"\n"
"选项:\n"
" -p, --port PORT SSH 端口 (默认: 2222)\n"
" -p, --port PORT SSH 端口 (默认: " TNT_DEFAULT_PORT_TEXT ")\n"
" -l, --login USER SSH 登录名,用作 exec 身份\n"
" --host-key-checking MODE\n"
" OpenSSH 主机密钥模式: yes, accept-new, no\n"

View file

@ -14,6 +14,7 @@ UTF8_SRC = ../../src/utf8.c
MESSAGE_SRC = ../../src/message.c
MESSAGE_LOG_SRC = ../../src/message_log.c
COMMON_SRC = ../../src/common.c
CONFIG_DEFAULTS_SRC = ../../src/config_defaults.c
COMMAND_CATALOG_SRC = ../../src/command_catalog.c
CLI_TEXT_SRC = ../../src/cli_text.c
TNTCTL_TEXT_SRC = ../../src/tntctl_text.c
@ -27,7 +28,7 @@ HELP_TEXT_SRC = ../../src/help_text.c
MANUAL_TEXT_SRC = ../../src/manual_text.c
RATELIMIT_SRC = ../../src/ratelimit.c
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_command_catalog test_exec_catalog test_help_text test_manual_text test_cli_text test_tntctl_text test_ratelimit
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_command_catalog test_exec_catalog test_help_text test_manual_text test_cli_text test_tntctl_text test_ratelimit test_config_defaults
.PHONY: all clean run
@ -39,7 +40,7 @@ test_utf8: test_utf8.c $(UTF8_SRC)
test_message: test_message.c $(MESSAGE_SRC) $(MESSAGE_LOG_SRC) $(UTF8_SRC) $(COMMON_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_chat_room: test_chat_room.c $(CHAT_ROOM_SRC) $(MESSAGE_SRC) $(MESSAGE_LOG_SRC) $(UTF8_SRC) $(COMMON_SRC)
test_chat_room: test_chat_room.c $(CHAT_ROOM_SRC) $(MESSAGE_SRC) $(MESSAGE_LOG_SRC) $(UTF8_SRC) $(COMMON_SRC) $(CONFIG_DEFAULTS_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_history_view: test_history_view.c $(HISTORY_VIEW_SRC)
@ -69,7 +70,10 @@ test_cli_text: test_cli_text.c $(CLI_TEXT_SRC) $(COMMON_SRC)
test_tntctl_text: test_tntctl_text.c $(TNTCTL_TEXT_SRC) $(EXEC_CATALOG_SRC) $(COMMON_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_ratelimit: test_ratelimit.c $(RATELIMIT_SRC) $(COMMON_SRC)
test_ratelimit: test_ratelimit.c $(RATELIMIT_SRC) $(COMMON_SRC) $(CONFIG_DEFAULTS_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_config_defaults: test_config_defaults.c $(CONFIG_DEFAULTS_SRC) $(COMMON_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: all
@ -111,6 +115,9 @@ run: all
@echo ""
@echo "=== Running Rate Limit Tests ==="
./test_ratelimit
@echo ""
@echo "=== Running Config Defaults Tests ==="
./test_config_defaults
clean:
rm -f $(TESTS) *.o test_messages.log

View file

@ -0,0 +1,66 @@
#include "config_defaults.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define TEST(name) static void test_##name(void)
#define RUN_TEST(name) do { \
printf("Running %s... ", #name); \
test_##name(); \
printf("ok\n"); \
} while (0)
TEST(specs_expose_runtime_defaults) {
assert(TNT_CONFIG_PORT.fallback == TNT_DEFAULT_PORT);
assert(TNT_CONFIG_MAX_CONNECTIONS.fallback ==
TNT_DEFAULT_MAX_CONNECTIONS);
assert(TNT_CONFIG_MAX_CONN_PER_IP.fallback ==
TNT_DEFAULT_MAX_CONN_PER_IP);
assert(TNT_CONFIG_MAX_CONN_RATE_PER_IP.fallback ==
TNT_DEFAULT_MAX_CONN_RATE_PER_IP);
assert(TNT_CONFIG_RATE_LIMIT.fallback ==
TNT_DEFAULT_RATE_LIMIT_ENABLED);
assert(TNT_CONFIG_IDLE_TIMEOUT.fallback == TNT_DEFAULT_IDLE_TIMEOUT);
assert(TNT_CONFIG_PORT.min_value == TNT_MIN_PORT);
assert(TNT_CONFIG_PORT.max_value == TNT_MAX_PORT);
}
TEST(parse_uses_spec_ranges) {
int out = 0;
assert(tnt_config_parse_int("2222", &TNT_CONFIG_PORT, &out));
assert(out == 2222);
assert(!tnt_config_parse_int("0", &TNT_CONFIG_PORT, &out));
assert(!tnt_config_parse_int("65536", &TNT_CONFIG_PORT, &out));
assert(!tnt_config_parse_int("abc", &TNT_CONFIG_PORT, &out));
assert(!tnt_config_parse_int("", &TNT_CONFIG_PORT, &out));
assert(tnt_config_parse_int("0", &TNT_CONFIG_IDLE_TIMEOUT, &out));
assert(out == 0);
assert(!tnt_config_parse_int("86401", &TNT_CONFIG_IDLE_TIMEOUT, &out));
}
TEST(env_reader_uses_fallback_and_range) {
unsetenv(TNT_CONFIG_MAX_CONNECTIONS.env_name);
assert(tnt_config_env_int(&TNT_CONFIG_MAX_CONNECTIONS) ==
TNT_DEFAULT_MAX_CONNECTIONS);
setenv(TNT_CONFIG_MAX_CONNECTIONS.env_name, "128", 1);
assert(tnt_config_env_int(&TNT_CONFIG_MAX_CONNECTIONS) == 128);
setenv(TNT_CONFIG_MAX_CONNECTIONS.env_name, "0", 1);
assert(tnt_config_env_int(&TNT_CONFIG_MAX_CONNECTIONS) ==
TNT_DEFAULT_MAX_CONNECTIONS);
unsetenv(TNT_CONFIG_MAX_CONNECTIONS.env_name);
}
int main(void) {
printf("Running config defaults unit tests...\n\n");
RUN_TEST(specs_expose_runtime_defaults);
RUN_TEST(parse_uses_spec_ranges);
RUN_TEST(env_reader_uses_fallback_and_range);
printf("\nAll 3 tests passed!\n");
return 0;
}