Some checks failed
CI / build (push) Failing after 17s
- 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 为预期行为)
604 lines
21 KiB
C
604 lines
21 KiB
C
#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();
|
||
}
|