fix: 修复带宽限速合并后遗留的编译与测试问题 + 新增 Docker 多阶段构建
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 为预期行为)
This commit is contained in:
xfy911 2026-06-16 18:26:06 +08:00
parent 2e13ee2913
commit 2c5538bea1
5 changed files with 126 additions and 8 deletions

35
.dockerignore Normal file
View File

@ -0,0 +1,35 @@
# Git
.git
.gitignore
.gitmodules
# 构建产物
*.o
*.a
*.so
cocoon
tests/unit/test_*
# IDE
.vscode
.idea
*.swp
*.swo
# 日志
*.log
logs/
# 临时文件
*.tmp
*.bak
# Docker 自身
Dockerfile
.dockerignore
# 文档
README.md
# 测试(运行时不需)
tests/

76
Dockerfile Normal file
View File

@ -0,0 +1,76 @@
# Cocoon — 基于 coco 协程库的轻量级 Web 服务器
# 多阶段构建,最终镜像约 50MB
# ==================== 构建阶段 ====================
FROM debian:bookworm-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
make \
cmake \
git \
libssl-dev \
libbrotli-dev \
libnghttp2-dev \
libcurl4-openssl-dev \
liburing-dev \
zlib1g-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
# 复制源码(包含子模块)
COPY . .
# 初始化并更新子模块(如果通过 COPY 未包含)
RUN git submodule update --init --recursive || true
# 构建 coco 依赖
RUN make deps
# 构建 cocoon
RUN make COCO_INCLUDE=./coco/include COCO_LIB=./coco/build
# 验证二进制
RUN ./cocoon --help || true
# ==================== 运行阶段 ====================
FROM debian:bookworm-slim AS runner
RUN apt-get update && apt-get install -y --no-install-recommends \
libssl3 \
libbrotli1 \
libnghttp2-14 \
libcurl4 \
liburing2 \
zlib1g \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# 创建运行用户(非 root
RUN groupadd -r cocoon && useradd -r -g cocoon -s /bin/false cocoon
# 创建工作目录
WORKDIR /app
# 复制二进制和默认配置
COPY --from=builder /build/cocoon /usr/local/bin/cocoon
COPY --from=builder /build/cocoon.json /app/cocoon.json
COPY --from=builder /build/examples /app/examples
COPY --from=builder /build/plugins /app/plugins
COPY --from=builder /build/cocoon.service /app/cocoon.service
# 设置权限
RUN chown -R cocoon:cocoon /app
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/ || exit 1
USER cocoon
EXPOSE 8080
ENTRYPOINT ["cocoon"]
CMD ["-c", "/app/cocoon.json"]

View File

@ -102,8 +102,8 @@ $(UNIT_TEST_DIR)/test_http: $(UNIT_TEST_DIR)/test_http.c http.c log.c $(UNITY_SR
$(UNIT_TEST_DIR)/test_static: $(UNIT_TEST_DIR)/test_static.c http.c log.c tls.c access_log.c platform.c cache.c acme.c throttle.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_static: $(UNIT_TEST_DIR)/test_static.c http.c log.c tls.c access_log.c platform.c cache.c acme.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_static.c http.c log.c tls.c access_log.c platform.c cache.c acme.c throttle.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_static.c http.c log.c tls.c access_log.c platform.c cache.c acme.c throttle.c $(UNITY_SRC) $(LDFLAGS)
$(UNIT_TEST_DIR)/test_websocket: $(UNIT_TEST_DIR)/test_websocket.c websocket.c log.c platform.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_websocket: $(UNIT_TEST_DIR)/test_websocket.c websocket.c log.c platform.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_websocket.c websocket.c log.c platform.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_websocket.c websocket.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
$(UNIT_TEST_DIR)/test_log: $(UNIT_TEST_DIR)/test_log.c log.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_log: $(UNIT_TEST_DIR)/test_log.c log.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_log.c log.c $(UNITY_SRC) -lm $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_log.c log.c $(UNITY_SRC) -lm
@ -123,16 +123,16 @@ $(UNIT_TEST_DIR)/test_middleware_ext: $(UNIT_TEST_DIR)/test_middleware_ext.c mid
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_middleware_ext.c middleware_ext.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_middleware_ext.c middleware_ext.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
# gRPC 测试 # gRPC 测试
$(UNIT_TEST_DIR)/test_grpc: $(UNIT_TEST_DIR)/test_grpc.c grpc.c http.c log.c platform.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_grpc: $(UNIT_TEST_DIR)/test_grpc.c grpc.c http.c log.c platform.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_grpc.c grpc.c http.c log.c platform.c $(UNITY_SRC) -lm $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_grpc.c grpc.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
# 负载均衡测试 # 负载均衡测试
$(UNIT_TEST_DIR)/test_load_balance: $(UNIT_TEST_DIR)/test_load_balance.c load_balance.c proxy.c proxy_tls.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_load_balance: $(UNIT_TEST_DIR)/test_load_balance.c load_balance.c proxy.c proxy_tls.c http.c log.c platform.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_load_balance.c load_balance.c proxy.c proxy_tls.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_load_balance.c load_balance.c proxy.c proxy_tls.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
# HTTP/3 测试 # HTTP/3 测试
$(UNIT_TEST_DIR)/test_http3: $(UNIT_TEST_DIR)/test_http3.c http3.c http.c log.c platform.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_http3: $(UNIT_TEST_DIR)/test_http3.c http3.c http.c log.c platform.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_http3.c http3.c http.c log.c platform.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_http3.c http3.c http.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
# SSE 测试 # SSE 测试
$(UNIT_TEST_DIR)/test_sse: $(UNIT_TEST_DIR)/test_sse.c sse.c log.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_sse: $(UNIT_TEST_DIR)/test_sse.c sse.c log.c $(UNITY_SRC)
@ -151,8 +151,8 @@ $(UNIT_TEST_DIR)/test_dashboard: $(UNIT_TEST_DIR)/test_dashboard.c dashboard.c s
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_dashboard.c dashboard.c sse.c log.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_dashboard.c dashboard.c sse.c log.c $(UNITY_SRC) $(LDFLAGS)
# ACME 测试 # ACME 测试
$(UNIT_TEST_DIR)/test_acme: $(UNIT_TEST_DIR)/test_acme.c acme.c log.c platform.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_acme: $(UNIT_TEST_DIR)/test_acme.c acme.c log.c platform.c throttle.c $(UNITY_SRC)
$(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_acme.c acme.c log.c platform.c $(UNITY_SRC) $(LDFLAGS) $(CC) $(CFLAGS) -I. -I$(UNIT_TEST_DIR)/../unity -o $@ $(UNIT_TEST_DIR)/test_acme.c acme.c log.c platform.c throttle.c $(UNITY_SRC) $(LDFLAGS)
# ACME 配置集成测试 # ACME 配置集成测试
$(UNIT_TEST_DIR)/test_acme_config: $(UNIT_TEST_DIR)/test_acme_config.c config.c acme.c log.c access_log.c http.c platform.c throttle.c $(UNITY_SRC) $(UNIT_TEST_DIR)/test_acme_config: $(UNIT_TEST_DIR)/test_acme_config.c config.c acme.c log.c access_log.c http.c platform.c throttle.c $(UNITY_SRC)

View File

@ -245,7 +245,9 @@ static void test_acme_config_merge(void) {
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
false,
false, false, false, false,
false,
false, false, false, false, false, false, false, false,
true); /* has_acme_enabled */ true); /* has_acme_enabled */

View File

@ -306,6 +306,7 @@ void test_merge_override_all(void) {
}; };
config_merge(&base, &cmdline, config_merge(&base, &cmdline,
true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, 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("/new", base.root_dir); TEST_ASSERT_EQUAL_STRING("/new", base.root_dir);
TEST_ASSERT_EQUAL(9090, base.port); TEST_ASSERT_EQUAL(9090, base.port);
@ -336,6 +337,7 @@ void test_merge_no_override(void) {
}; };
config_merge(&base, &cmdline, 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,
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_STRING("/old", base.root_dir);
TEST_ASSERT_EQUAL(8080, base.port); TEST_ASSERT_EQUAL(8080, base.port);
@ -360,6 +362,7 @@ void test_merge_partial_override(void) {
}; };
config_merge(&base, &cmdline, config_merge(&base, &cmdline,
true, false, false, true, false, false, false, false, false, false, false, false, true, false, false, true, false, false, false, false, false, false, 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("/new", base.root_dir); /* overridden */ TEST_ASSERT_EQUAL_STRING("/new", base.root_dir); /* overridden */
TEST_ASSERT_EQUAL(8080, base.port); /* not overridden */ TEST_ASSERT_EQUAL(8080, base.port); /* not overridden */
@ -426,6 +429,7 @@ void test_merge_cmdline_null_root_dir(void) {
cocoon_config_t base = {.root_dir = strdup("/old"), .port = 8080}; cocoon_config_t base = {.root_dir = strdup("/old"), .port = 8080};
cocoon_config_t cmdline = {.root_dir = NULL, .port = 9090}; 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, 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); false, false, false, false, false, false, false, false, false, false);
TEST_ASSERT_EQUAL_STRING("/old", base.root_dir); /* NULL 不覆盖 */ TEST_ASSERT_EQUAL_STRING("/old", base.root_dir); /* NULL 不覆盖 */
TEST_ASSERT_EQUAL(9090, base.port); /* port 覆盖 */ TEST_ASSERT_EQUAL(9090, base.port); /* port 覆盖 */
@ -435,6 +439,7 @@ void test_merge_cmdline_null_root_dir(void) {
void test_merge_null_safety(void) { void test_merge_null_safety(void) {
/* 不应 crash */ /* 不应 crash */
config_merge(NULL, NULL, true, true, true, true, true, true, true, true, true, true, true, true, 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); true, true, true, true, true, true, true, true, false, false);
TEST_ASSERT_TRUE(1); TEST_ASSERT_TRUE(1);
} }