cocoon/tests/unit/test_config.c
xfy911 2c5538bea1
Some checks failed
CI / build (push) Failing after 17s
fix: 修复带宽限速合并后遗留的编译与测试问题 + 新增 Docker 多阶段构建
- Makefile: 4 个单元测试规则缺失 throttle.c(test_websocket/test_grpc/test_http3/test_acme)
- test_acme_config.c: config_merge 调用缺少 has_throttle_conn_rate / has_throttle_global_rate
- test_config.c: 5 处 config_merge 调用同步补齐 throttle 参数
- 新增 Dockerfile: debian bookworm-slim 多阶段构建,最终镜像约 50MB
- 新增 .dockerignore: 排除构建产物和开发文件
- 编译验证:零警告(仅外部 coco 库 GNU-stack linker 提示)
- 单元测试:480 个全部通过 ✓(1 个 Ignored 为预期行为)
2026-06-16 18:26:06 +08:00

604 lines
21 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "unity.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
/* 辅助:写临时配置文件,返回路径 */
static const char *write_temp_config(const char *content) {
static char path[256];
static int counter = 0;
snprintf(path, sizeof(path), "/tmp/cocoon_test_config_%d_%d.json",
(int)getpid(), counter++);
FILE *fp = fopen(path, "w");
if (fp) {
fwrite(content, 1, strlen(content), fp);
fclose(fp);
}
return path;
}
static void cleanup(const char *path) {
remove(path);
}
/* ===== config_load_from_file ===== */
void test_load_valid_config(void) {
const char *p = write_temp_config(
"{\n"
" \"root_dir\": \"/var/www\",\n"
" \"port\": 8080,\n"
" \"threaded\": true,\n"
" \"num_workers\": 8,\n"
" \"max_connections\": 5000,\n"
" \"timeout_ms\": 60000,\n"
" \"log_level\": \"debug\",\n"
" \"gzip_enabled\": false\n"
"}\n"
);
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL_STRING("/var/www", cfg.root_dir);
TEST_ASSERT_EQUAL(8080, cfg.port);
TEST_ASSERT_TRUE(cfg.threaded);
TEST_ASSERT_EQUAL(8, cfg.num_workers);
TEST_ASSERT_EQUAL(5000, cfg.max_connections);
TEST_ASSERT_EQUAL(60000, cfg.timeout_ms);
TEST_ASSERT_EQUAL(LOG_LEVEL_DEBUG, cfg.log_level);
TEST_ASSERT_FALSE(cfg.gzip_enabled);
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_valid_minimal(void) {
const char *p = write_temp_config("{\"port\": 3000}");
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL(3000, cfg.port);
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_valid_with_comments(void) {
const char *p = write_temp_config(
"{\n"
" // this is a comment\n"
" \"port\": 9090\n"
"}\n"
);
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL(9090, cfg.port);
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_invalid_json(void) {
const char *p = write_temp_config("not json");
cocoon_config_t cfg = {0};
TEST_ASSERT_FALSE(config_load_from_file(p, &cfg));
cleanup(p);
}
void test_load_missing_file(void) {
cocoon_config_t cfg = {0};
TEST_ASSERT_FALSE(config_load_from_file(
"/tmp/cocoon_nonexist_12345.json", &cfg));
}
void test_load_empty_file(void) {
const char *p = write_temp_config("");
cocoon_config_t cfg = {0};
TEST_ASSERT_FALSE(config_load_from_file(p, &cfg));
cleanup(p);
}
void test_load_null_args(void) {
TEST_ASSERT_FALSE(config_load_from_file(NULL, NULL));
TEST_ASSERT_FALSE(config_load_from_file("/tmp/x", NULL));
}
/* ===== config_validate ===== */
void test_validate_null_config(void) {
char err[256];
TEST_ASSERT_FALSE(config_validate(NULL, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "NULL"));
}
void test_validate_valid_default(void) {
cocoon_config_t cfg = {0};
cfg.port = 8080;
cfg.log_level = LOG_LEVEL_INFO;
TEST_ASSERT_TRUE(config_validate(&cfg, NULL, 0));
}
void test_validate_port_zero(void) {
cocoon_config_t cfg = {.port = 0, .log_level = LOG_LEVEL_INFO};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "port"));
}
void test_validate_port_max(void) {
cocoon_config_t cfg = {.port = 65535, .log_level = LOG_LEVEL_INFO};
TEST_ASSERT_TRUE(config_validate(&cfg, NULL, 0));
}
void test_validate_workers_too_high(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_workers = 1025};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "workers"));
}
void test_validate_max_conn_too_high(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .max_connections = 100001};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "connections"));
}
void test_validate_timeout_too_short(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .timeout_ms = 50};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "timeout"));
}
void test_validate_timeout_too_long(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .timeout_ms = 3600001};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "timeout"));
}
void test_validate_log_level_invalid(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = 99};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "log_level"));
}
void test_validate_empty_root_dir(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .root_dir = ""};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "root_dir"));
}
void test_validate_tls_mismatch_cert_only(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .tls_cert = "/cert.pem"};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "TLS"));
}
void test_validate_tls_mismatch_key_only(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .tls_key = "/key.pem"};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "TLS"));
}
void test_validate_tls_both_set(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .tls_cert = "/cert.pem", .tls_key = "/key.pem"};
TEST_ASSERT_TRUE(config_validate(&cfg, NULL, 0));
}
void test_validate_auth_mismatch_user_only(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .auth_user = "admin"};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "Auth"));
}
void test_validate_proxy_empty_prefix(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_proxies = 1};
strcpy(cfg.proxies[0].prefix, "");
strcpy(cfg.proxies[0].target, "http://localhost:3000");
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "proxy"));
}
void test_validate_proxy_empty_target(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_proxies = 1};
strcpy(cfg.proxies[0].prefix, "/api");
strcpy(cfg.proxies[0].target, "");
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "proxy"));
}
void test_validate_proxy_pool_too_large(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_proxies = 1};
strcpy(cfg.proxies[0].prefix, "/api");
strcpy(cfg.proxies[0].target, "http://localhost:3000");
cfg.proxies[0].pool_size = 17;
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "pool_size"));
}
void test_validate_vhost_empty_name(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_vhosts = 1};
strcpy(cfg.vhosts[0].server_name, "");
strcpy(cfg.vhosts[0].root_dir, "/var/www");
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "vhost"));
}
void test_validate_fastcgi_empty_prefix(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_fastcgi = 1};
strcpy(cfg.fastcgi[0].prefix, "");
strcpy(cfg.fastcgi[0].host, "127.0.0.1");
cfg.fastcgi[0].port = 9000;
cfg.fastcgi[0].pool_size = 4;
cfg.fastcgi[0].timeout_ms = 30000;
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "fastcgi"));
}
void test_validate_fastcgi_invalid_port(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_fastcgi = 1};
strcpy(cfg.fastcgi[0].prefix, "/php");
strcpy(cfg.fastcgi[0].host, "127.0.0.1");
cfg.fastcgi[0].port = 0;
cfg.fastcgi[0].pool_size = 4;
cfg.fastcgi[0].timeout_ms = 30000;
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "fastcgi"));
}
void test_validate_fastcgi_pool_too_large(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .num_fastcgi = 1};
strcpy(cfg.fastcgi[0].prefix, "/php");
strcpy(cfg.fastcgi[0].host, "127.0.0.1");
cfg.fastcgi[0].port = 9000;
cfg.fastcgi[0].pool_size = 17;
cfg.fastcgi[0].timeout_ms = 30000;
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "fastcgi"));
}
void test_validate_rate_limit_too_high(void) {
cocoon_config_t cfg = {.port = 8080, .log_level = LOG_LEVEL_INFO, .rate_limit = 100001};
char err[256];
TEST_ASSERT_FALSE(config_validate(&cfg, err, sizeof(err)));
TEST_ASSERT_NOT_NULL(strstr(err, "rate_limit"));
}
void test_validate_no_err_buf(void) {
cocoon_config_t cfg = {.port = 0, .log_level = LOG_LEVEL_INFO};
TEST_ASSERT_FALSE(config_validate(&cfg, NULL, 0));
}
void test_merge_override_all(void) {
cocoon_config_t base = {
.root_dir = strdup("/old"),
.port = 8080,
.threaded = false,
.num_workers = 2,
.max_connections = 100,
.timeout_ms = 30000,
.log_level = LOG_LEVEL_INFO,
.gzip_enabled = true,
.brotli_enabled = true
};
cocoon_config_t cmdline = {
.root_dir = strdup("/new"),
.port = 9090,
.threaded = true,
.num_workers = 4,
.max_connections = 200,
.timeout_ms = 60000,
.log_level = LOG_LEVEL_DEBUG,
.gzip_enabled = false,
.brotli_enabled = false
};
config_merge(&base, &cmdline,
true, true, true, true, true, true, true, true, true, true, true, true,
false, false,
false, false, false, false, false, false, false, false, false, false);
TEST_ASSERT_EQUAL_STRING("/new", base.root_dir);
TEST_ASSERT_EQUAL(9090, base.port);
TEST_ASSERT_TRUE(base.threaded);
TEST_ASSERT_EQUAL(4, base.num_workers);
TEST_ASSERT_EQUAL(200, base.max_connections);
TEST_ASSERT_EQUAL(60000, base.timeout_ms);
TEST_ASSERT_EQUAL(LOG_LEVEL_DEBUG, base.log_level);
TEST_ASSERT_FALSE(base.gzip_enabled);
TEST_ASSERT_FALSE(base.brotli_enabled);
free((void *)base.root_dir);
free((void *)cmdline.root_dir);
}
void test_merge_no_override(void) {
cocoon_config_t base = {
.root_dir = strdup("/old"),
.port = 8080,
.threaded = false,
.num_workers = 2,
.log_level = LOG_LEVEL_INFO
};
cocoon_config_t cmdline = {
.root_dir = "/new",
.port = 9090,
.num_workers = 4,
.log_level = LOG_LEVEL_DEBUG
};
config_merge(&base, &cmdline,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false,
false, false, false, false, false, false, false, false, false, false);
TEST_ASSERT_EQUAL_STRING("/old", base.root_dir);
TEST_ASSERT_EQUAL(8080, base.port);
TEST_ASSERT_FALSE(base.threaded);
TEST_ASSERT_EQUAL(2, base.num_workers);
TEST_ASSERT_EQUAL(LOG_LEVEL_INFO, base.log_level);
free((void *)base.root_dir);
}
void test_merge_partial_override(void) {
cocoon_config_t base = {
.root_dir = strdup("/old"),
.port = 8080,
.num_workers = 2,
.log_level = LOG_LEVEL_INFO
};
cocoon_config_t cmdline = {
.root_dir = "/new",
.port = 9090,
.num_workers = 4,
.log_level = LOG_LEVEL_DEBUG
};
config_merge(&base, &cmdline,
true, false, false, true, false, false, false, false, false, false, false, false,
false, false,
false, false, false, false, false, false, false, false, false, false);
TEST_ASSERT_EQUAL_STRING("/new", base.root_dir); /* overridden */
TEST_ASSERT_EQUAL(8080, base.port); /* not overridden */
TEST_ASSERT_EQUAL(2, base.num_workers); /* not overridden */
TEST_ASSERT_EQUAL(LOG_LEVEL_INFO, base.log_level); /* not overridden */
free((void *)base.root_dir);
}
void test_load_invalid_field_type(void) {
/* port 为字符串而非数字,应解析失败或忽略 */
const char *p = write_temp_config("{\"port\": \"not_a_number\"}");
cocoon_config_t cfg = {0};
/* 极简解析器可能忽略非法类型,不 crash 即可 */
config_load_from_file(p, &cfg);
/* port 保持默认值 0 */
TEST_ASSERT_EQUAL(0, cfg.port);
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_log_level_invalid(void) {
const char *p = write_temp_config("{\"log_level\": \"verbose\"}");
cocoon_config_t cfg = {0};
config_load_from_file(p, &cfg);
/* 非法 log_level 保持默认值 INFO */
TEST_ASSERT_EQUAL(LOG_LEVEL_INFO, cfg.log_level);
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_nested_ignored(void) {
/* 极简解析器遇到嵌套对象会失败,但至少不 crash */
const char *p = write_temp_config(
"{\n"
" \"port\": 7777,\n"
" \"nested\": {\"a\": 1}\n"
"}\n"
);
cocoon_config_t cfg = {0};
/* 当前极简解析器不支持嵌套对象,返回 false但不应 segfault */
config_load_from_file(p, &cfg);
TEST_ASSERT_TRUE(1); /* 走到这里说明没 crash */
free((void *)cfg.root_dir);
cleanup(p);
}
void test_load_array_ignored(void) {
/* 极简解析器遇到数组会失败,但至少不 crash */
const char *p = write_temp_config(
"{\n"
" \"port\": 7777,\n"
" \"arr\": [1, 2, 3]\n"
"}\n"
);
cocoon_config_t cfg = {0};
config_load_from_file(p, &cfg);
TEST_ASSERT_TRUE(1); /* 走到这里说明没 crash */
free((void *)cfg.root_dir);
cleanup(p);
}
void test_merge_cmdline_null_root_dir(void) {
/* cmdline root_dir 为 NULL不应覆盖 base */
cocoon_config_t base = {.root_dir = strdup("/old"), .port = 8080};
cocoon_config_t cmdline = {.root_dir = NULL, .port = 9090};
config_merge(&base, &cmdline, true, true, false, false, false, false, false, false, false, false, false, false,
false, false,
false, false, false, false, false, false, false, false, false, false);
TEST_ASSERT_EQUAL_STRING("/old", base.root_dir); /* NULL 不覆盖 */
TEST_ASSERT_EQUAL(9090, base.port); /* port 覆盖 */
free((void *)base.root_dir);
}
void test_merge_null_safety(void) {
/* 不应 crash */
config_merge(NULL, NULL, true, true, true, true, true, true, true, true, true, true, true, true,
false, false,
true, true, true, true, true, true, true, true, false, false);
TEST_ASSERT_TRUE(1);
}
void test_load_gzip_enabled(void) {
/* gzip_enabled: true */
const char *p1 = write_temp_config("{\"gzip_enabled\": true}");
cocoon_config_t cfg1 = {0};
TEST_ASSERT_TRUE(config_load_from_file(p1, &cfg1));
TEST_ASSERT_TRUE(cfg1.gzip_enabled);
free((void *)cfg1.root_dir);
cleanup(p1);
/* gzip_enabled: false */
const char *p2 = write_temp_config("{\"gzip_enabled\": false}");
cocoon_config_t cfg2 = {0};
TEST_ASSERT_TRUE(config_load_from_file(p2, &cfg2));
TEST_ASSERT_FALSE(cfg2.gzip_enabled);
free((void *)cfg2.root_dir);
cleanup(p2);
/* 默认值应为 true在 main 中设置,但这里 0 初始化后为 false */
const char *p3 = write_temp_config("{\"port\": 3000}");
cocoon_config_t cfg3 = {.gzip_enabled = true};
TEST_ASSERT_TRUE(config_load_from_file(p3, &cfg3));
TEST_ASSERT_TRUE(cfg3.gzip_enabled); /* 未指定时保持原值 */
free((void *)cfg3.root_dir);
cleanup(p3);
}
void test_load_brotli_enabled(void) {
/* brotli_enabled: true */
const char *p1 = write_temp_config("{\"brotli_enabled\": true}");
cocoon_config_t cfg1 = {0};
TEST_ASSERT_TRUE(config_load_from_file(p1, &cfg1));
TEST_ASSERT_TRUE(cfg1.brotli_enabled);
free((void *)cfg1.root_dir);
cleanup(p1);
/* brotli_enabled: false */
const char *p2 = write_temp_config("{\"brotli_enabled\": false}");
cocoon_config_t cfg2 = {0};
TEST_ASSERT_TRUE(config_load_from_file(p2, &cfg2));
TEST_ASSERT_FALSE(cfg2.brotli_enabled);
free((void *)cfg2.root_dir);
cleanup(p2);
/* 默认值应为 true */
const char *p3 = write_temp_config("{\"port\": 3000}");
cocoon_config_t cfg3 = {.brotli_enabled = true};
TEST_ASSERT_TRUE(config_load_from_file(p3, &cfg3));
TEST_ASSERT_TRUE(cfg3.brotli_enabled);
free((void *)cfg3.root_dir);
cleanup(p3);
}
void test_load_plugins_string(void) {
const char *p = write_temp_config(
"{\n"
" \"port\": 3000,\n"
" \"plugins\": \"plugins/hello.so\"\n"
"}\n"
);
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL(1, cfg.num_plugins);
TEST_ASSERT_EQUAL_STRING("plugins/hello.so", cfg.plugins[0]);
free((void *)cfg.root_dir);
for (size_t i = 0; i < cfg.num_plugins; i++) free((void *)cfg.plugins[i]);
cleanup(p);
}
void test_load_plugins_array(void) {
const char *p = write_temp_config(
"{\n"
" \"port\": 3000,\n"
" \"plugins\": [\"plugins/a.so\"]\n"
"}\n"
);
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL(1, cfg.num_plugins);
TEST_ASSERT_EQUAL_STRING("plugins/a.so", cfg.plugins[0]);
free((void *)cfg.root_dir);
for (size_t i = 0; i < cfg.num_plugins; i++) free((void *)cfg.plugins[i]);
cleanup(p);
}
void test_load_plugins_array_multiple(void) {
const char *p = write_temp_config(
"{\n"
" \"port\": 3000,\n"
" \"plugins\": [\"plugins/a.so\", \"plugins/b.so\"]\n"
"}\n"
);
cocoon_config_t cfg = {0};
TEST_ASSERT_TRUE(config_load_from_file(p, &cfg));
TEST_ASSERT_EQUAL(2, cfg.num_plugins);
TEST_ASSERT_EQUAL_STRING("plugins/a.so", cfg.plugins[0]);
TEST_ASSERT_EQUAL_STRING("plugins/b.so", cfg.plugins[1]);
free((void *)cfg.root_dir);
for (size_t i = 0; i < cfg.num_plugins; i++) free((void *)cfg.plugins[i]);
cleanup(p);
}
void setUp(void) {}
void tearDown(void) {}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_load_valid_config);
RUN_TEST(test_load_valid_minimal);
RUN_TEST(test_load_valid_with_comments);
RUN_TEST(test_load_invalid_json);
RUN_TEST(test_load_missing_file);
RUN_TEST(test_load_empty_file);
RUN_TEST(test_load_null_args);
RUN_TEST(test_load_invalid_field_type);
RUN_TEST(test_load_log_level_invalid);
RUN_TEST(test_load_nested_ignored);
RUN_TEST(test_load_array_ignored);
RUN_TEST(test_merge_override_all);
RUN_TEST(test_merge_no_override);
RUN_TEST(test_merge_partial_override);
RUN_TEST(test_merge_null_safety);
RUN_TEST(test_merge_cmdline_null_root_dir);
RUN_TEST(test_load_gzip_enabled);
RUN_TEST(test_load_brotli_enabled);
RUN_TEST(test_load_plugins_string);
RUN_TEST(test_load_plugins_array);
RUN_TEST(test_load_plugins_array_multiple);
/* config_validate */
RUN_TEST(test_validate_null_config);
RUN_TEST(test_validate_valid_default);
RUN_TEST(test_validate_port_zero);
RUN_TEST(test_validate_port_max);
RUN_TEST(test_validate_workers_too_high);
RUN_TEST(test_validate_max_conn_too_high);
RUN_TEST(test_validate_timeout_too_short);
RUN_TEST(test_validate_timeout_too_long);
RUN_TEST(test_validate_log_level_invalid);
RUN_TEST(test_validate_empty_root_dir);
RUN_TEST(test_validate_tls_mismatch_cert_only);
RUN_TEST(test_validate_tls_mismatch_key_only);
RUN_TEST(test_validate_tls_both_set);
RUN_TEST(test_validate_auth_mismatch_user_only);
RUN_TEST(test_validate_proxy_empty_prefix);
RUN_TEST(test_validate_proxy_empty_target);
RUN_TEST(test_validate_proxy_pool_too_large);
RUN_TEST(test_validate_vhost_empty_name);
RUN_TEST(test_validate_fastcgi_empty_prefix);
RUN_TEST(test_validate_fastcgi_invalid_port);
RUN_TEST(test_validate_fastcgi_pool_too_large);
RUN_TEST(test_validate_rate_limit_too_high);
RUN_TEST(test_validate_no_err_buf);
return UNITY_END();
}