新增 4 个核心模块,12 个新文件,约 8832 行源代码 + 测试: 1. 扩展内置中间件 (middleware_ext.c/h) - JWT 认证:HS256 (HMAC-SHA256) 签名验证,Base64Url 解码 - Security Headers:HSTS / X-Frame-Options / CSP / X-XSS-Protection - Request ID:32 字符 hex 唯一追踪 ID 生成与透传 - IP 过滤:IPv4 / CIDR 黑名单与白名单,X-Forwarded-For 解析 2. 分布式负载均衡 (load_balance.c/h) - 一致性哈希:MurmurHash3 x86 32-bit + 512 虚拟节点/后端 - 最少连接:实时活跃连接数跟踪 - 加权响应时间:EWMA 指数加权移动平均 - 随机算法 3. gRPC 支持 (grpc.c/h) - gRPC over HTTP/2,LEB128 消息帧编解码 - 四种 RPC 模式:Unary / Server Streaming / Client Streaming / Bidirectional - gRPC-Web 兼容,17 个 gRPC 状态码完整支持 4. HTTP/3 (QUIC) (http3.c/h) - QUIC 传输层:UDP socket 管理,64-bit 连接 ID - HTTP/3 帧处理:HEADERS / DATA / SETTINGS / GOAWAY - QPACK 静态表编解码 (RFC 9204) - TLS 1.3 集成接口 新增单元测试: - test_middleware_ext.c: 53 项测试 - test_load_balance.c: 56 项测试 - test_grpc.c: 88 项测试 - test_http3.c: 64 项测试 - 新增合计:261 项,累计 451 项 同时替换 coco 子模块为内联 stub 头文件, 确保无需外部依赖即可编译。
990 lines
31 KiB
C
990 lines
31 KiB
C
/**
|
||
* @file test_http3.c
|
||
* @brief HTTP/3 (QUIC) 模块单元测试
|
||
*
|
||
* 使用 Unity 测试框架,覆盖以下功能:
|
||
* - Variable-length integer 编解码
|
||
* - HTTP/3 帧头编解码
|
||
* - QPACK 静态表编码/解码
|
||
* - QUIC 流管理
|
||
* - QUIC 连接管理
|
||
* - HTTP/3 会话管理
|
||
* - SETTINGS / GOAWAY 帧处理
|
||
*
|
||
* @author Cocoon Team
|
||
*/
|
||
|
||
#include "unity.h"
|
||
#include "http3.h"
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
|
||
/* ===== 测试前置/后置 ===== */
|
||
|
||
void setUp(void) {
|
||
http3_init();
|
||
}
|
||
|
||
void tearDown(void) {
|
||
http3_cleanup();
|
||
}
|
||
|
||
/* ===== Variable-Length Integer 测试 ===== */
|
||
|
||
/** @test varint 编码:0(最小1字节值) */
|
||
void test_varint_encode_zero(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(0, buf);
|
||
TEST_ASSERT_EQUAL(1, n);
|
||
TEST_ASSERT_EQUAL(0, buf[0]);
|
||
}
|
||
|
||
/** @test varint 编码:63(1字节最大值) */
|
||
void test_varint_encode_63(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(63, buf);
|
||
TEST_ASSERT_EQUAL(1, n);
|
||
TEST_ASSERT_EQUAL(63, buf[0]);
|
||
}
|
||
|
||
/** @test varint 编码:64(需要2字节) */
|
||
void test_varint_encode_64(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(64, buf);
|
||
TEST_ASSERT_EQUAL(2, n);
|
||
TEST_ASSERT_EQUAL(0x40, buf[0]);
|
||
TEST_ASSERT_EQUAL(0x40, buf[1]);
|
||
}
|
||
|
||
/** @test varint 编码:16383(2字节最大值) */
|
||
void test_varint_encode_16383(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(16383, buf);
|
||
TEST_ASSERT_EQUAL(2, n);
|
||
TEST_ASSERT_EQUAL(0x7F, buf[0]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[1]);
|
||
}
|
||
|
||
/** @test varint 编码:16384(需要4字节) */
|
||
void test_varint_encode_16384(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(16384, buf);
|
||
TEST_ASSERT_EQUAL(4, n);
|
||
TEST_ASSERT_EQUAL(0x80, buf[0]);
|
||
TEST_ASSERT_EQUAL(0x00, buf[1]);
|
||
TEST_ASSERT_EQUAL(0x40, buf[2]);
|
||
TEST_ASSERT_EQUAL(0x00, buf[3]);
|
||
}
|
||
|
||
/** @test varint 编码:1073741823(4字节最大值) */
|
||
void test_varint_encode_4byte_max(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(1073741823ULL, buf);
|
||
TEST_ASSERT_EQUAL(4, n);
|
||
TEST_ASSERT_EQUAL(0xBF, buf[0]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[1]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[2]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[3]);
|
||
}
|
||
|
||
/** @test varint 编码:1073741824(需要8字节) */
|
||
void test_varint_encode_8byte(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(1073741824ULL, buf);
|
||
TEST_ASSERT_EQUAL(8, n);
|
||
TEST_ASSERT_EQUAL(0xC0, buf[0]);
|
||
}
|
||
|
||
/** @test varint 编码:最大值 */
|
||
void test_varint_encode_max(void) {
|
||
uint8_t buf[8];
|
||
size_t n = http3_encode_varint(4611686018427387903ULL, buf);
|
||
TEST_ASSERT_EQUAL(8, n);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[0]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[1]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[2]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[3]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[4]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[5]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[6]);
|
||
TEST_ASSERT_EQUAL(0xFF, buf[7]);
|
||
}
|
||
|
||
/** @test varint 编码:NULL 缓冲区 */
|
||
void test_varint_encode_null_buf(void) {
|
||
size_t n = http3_encode_varint(42, NULL);
|
||
TEST_ASSERT_EQUAL(0, n);
|
||
}
|
||
|
||
/** @test varint 解码:0 */
|
||
void test_varint_decode_zero(void) {
|
||
uint8_t buf[1] = {0x00};
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 1, &value);
|
||
TEST_ASSERT_EQUAL(1, n);
|
||
TEST_ASSERT_EQUAL(0ULL, value);
|
||
}
|
||
|
||
/** @test varint 解码:63 */
|
||
void test_varint_decode_63(void) {
|
||
uint8_t buf[1] = {0x3F};
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 1, &value);
|
||
TEST_ASSERT_EQUAL(1, n);
|
||
TEST_ASSERT_EQUAL(63ULL, value);
|
||
}
|
||
|
||
/** @test varint 解码:64 */
|
||
void test_varint_decode_64(void) {
|
||
uint8_t buf[2] = {0x40, 0x40};
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 2, &value);
|
||
TEST_ASSERT_EQUAL(2, n);
|
||
TEST_ASSERT_EQUAL(64ULL, value);
|
||
}
|
||
|
||
/** @test varint 解码:16383 */
|
||
void test_varint_decode_16383(void) {
|
||
uint8_t buf[2] = {0x7F, 0xFF};
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 2, &value);
|
||
TEST_ASSERT_EQUAL(2, n);
|
||
TEST_ASSERT_EQUAL(16383ULL, value);
|
||
}
|
||
|
||
/** @test varint 解码:4字节值 */
|
||
void test_varint_decode_4byte(void) {
|
||
uint8_t buf[4] = {0x80, 0x00, 0x00, 0x01};
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 4, &value);
|
||
TEST_ASSERT_EQUAL(4, n);
|
||
TEST_ASSERT_EQUAL(1ULL, value);
|
||
}
|
||
|
||
/** @test varint 解码:数据不足 */
|
||
void test_varint_decode_insufficient_data(void) {
|
||
uint8_t buf[1] = {0x40}; /* 需要2字节,但只给1字节 */
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(buf, 1, &value);
|
||
TEST_ASSERT_EQUAL(-1, n);
|
||
}
|
||
|
||
/** @test varint 解码:NULL 输入 */
|
||
void test_varint_decode_null(void) {
|
||
uint64_t value = 0;
|
||
int n = http3_decode_varint(NULL, 0, &value);
|
||
TEST_ASSERT_EQUAL(-1, n);
|
||
}
|
||
|
||
/** @test varint 编解码往返测试 */
|
||
void test_varint_roundtrip(void) {
|
||
uint64_t test_values[] = {0, 1, 63, 64, 100, 16383, 16384, 100000,
|
||
1073741823ULL, 1073741824ULL,
|
||
4294967295ULL, 4611686018427387903ULL};
|
||
int num_values = sizeof(test_values) / sizeof(test_values[0]);
|
||
|
||
for (int i = 0; i < num_values; i++) {
|
||
uint8_t buf[8];
|
||
size_t enc_n = http3_encode_varint(test_values[i], buf);
|
||
TEST_ASSERT_MESSAGE(enc_n > 0, "编码失败");
|
||
|
||
uint64_t decoded = 0;
|
||
int dec_n = http3_decode_varint(buf, enc_n, &decoded);
|
||
TEST_ASSERT_EQUAL_MESSAGE(enc_n, (size_t)dec_n, "编解码长度不匹配");
|
||
TEST_ASSERT_EQUAL_MESSAGE(test_values[i], decoded, "编解码值不匹配");
|
||
}
|
||
}
|
||
|
||
/** @test 帧头大小计算 */
|
||
void test_frame_header_size(void) {
|
||
TEST_ASSERT_EQUAL(2, http3_frame_header_size(0, 0));
|
||
TEST_ASSERT_EQUAL(2, http3_frame_header_size(1, 10));
|
||
TEST_ASSERT_EQUAL(4, http3_frame_header_size(100, 1000));
|
||
}
|
||
|
||
/* ===== HTTP/3 帧处理测试 ===== */
|
||
|
||
/** @test 帧头编码/解码 */
|
||
void test_frame_header_encode_decode(void) {
|
||
uint8_t buf[16];
|
||
uint64_t ft = HTTP3_FRAME_HEADERS;
|
||
uint64_t flen = 42;
|
||
|
||
size_t n = http3_encode_frame_header(ft, flen, buf);
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
uint64_t decoded_ft = 0, decoded_len = 0;
|
||
int dn = http3_decode_frame_header(buf, n, &decoded_ft, &decoded_len);
|
||
TEST_ASSERT_EQUAL(n, (size_t)dn);
|
||
TEST_ASSERT_EQUAL(ft, decoded_ft);
|
||
TEST_ASSERT_EQUAL(flen, decoded_len);
|
||
}
|
||
|
||
/** @test 完整帧编码 */
|
||
void test_full_frame_encode(void) {
|
||
uint8_t payload[] = "Hello HTTP/3";
|
||
uint8_t buf[64];
|
||
|
||
int n = http3_encode_frame(HTTP3_FRAME_DATA, payload, sizeof(payload) - 1,
|
||
buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
/* 验证帧头 */
|
||
uint64_t ft = 0, flen = 0;
|
||
int hd = http3_decode_frame_header(buf, (size_t)n, &ft, &flen);
|
||
TEST_ASSERT_GREATER_THAN(0, hd);
|
||
TEST_ASSERT_EQUAL(HTTP3_FRAME_DATA, ft);
|
||
TEST_ASSERT_EQUAL(sizeof(payload) - 1, flen);
|
||
}
|
||
|
||
/** @test 帧头解码:数据不足 */
|
||
void test_frame_header_decode_insufficient(void) {
|
||
uint8_t buf[1] = {0x80}; /* 需要更多数据 */
|
||
uint64_t ft = 0, flen = 0;
|
||
int n = http3_decode_frame_header(buf, 1, &ft, &flen);
|
||
TEST_ASSERT_EQUAL(-1, n);
|
||
}
|
||
|
||
/** @test 帧头解码:NULL 输入 */
|
||
void test_frame_header_decode_null(void) {
|
||
uint64_t ft = 0, flen = 0;
|
||
int n = http3_decode_frame_header(NULL, 0, &ft, &flen);
|
||
TEST_ASSERT_EQUAL(-1, n);
|
||
}
|
||
|
||
/** @test 编码 DATA 帧 */
|
||
void test_encode_data_frame(void) {
|
||
uint8_t payload[] = {0x01, 0x02, 0x03, 0x04};
|
||
uint8_t buf[32];
|
||
int n = http3_encode_frame(HTTP3_FRAME_DATA, payload, 4, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
uint64_t ft = 0, flen = 0;
|
||
int hd = http3_decode_frame_header(buf, (size_t)n, &ft, &flen);
|
||
TEST_ASSERT_GREATER_THAN(0, hd);
|
||
TEST_ASSERT_EQUAL(HTTP3_FRAME_DATA, ft);
|
||
TEST_ASSERT_EQUAL(4, flen);
|
||
}
|
||
|
||
/** @test 编码 HEADERS 帧 */
|
||
void test_encode_headers_frame(void) {
|
||
uint8_t payload[] = {0xC0, 0x01, 0xD5}; /* 一些 QPACK 编码数据 */
|
||
uint8_t buf[32];
|
||
int n = http3_encode_frame(HTTP3_FRAME_HEADERS, payload, 3, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
uint64_t ft = 0, flen = 0;
|
||
int hd = http3_decode_frame_header(buf, (size_t)n, &ft, &flen);
|
||
TEST_ASSERT_GREATER_THAN(0, hd);
|
||
TEST_ASSERT_EQUAL(HTTP3_FRAME_HEADERS, ft);
|
||
TEST_ASSERT_EQUAL(3, flen);
|
||
}
|
||
|
||
/** @test 编码 SETTINGS 帧 */
|
||
void test_encode_settings_frame(void) {
|
||
uint8_t payload[16];
|
||
size_t pos = 0;
|
||
pos += http3_encode_varint(HTTP3_SETTING_MAX_FIELD_SECTION_SIZE, payload + pos);
|
||
pos += http3_encode_varint(16384, payload + pos);
|
||
|
||
uint8_t buf[32];
|
||
int n = http3_encode_frame(HTTP3_FRAME_SETTINGS, payload, pos, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
uint64_t ft = 0, flen = 0;
|
||
int hd = http3_decode_frame_header(buf, (size_t)n, &ft, &flen);
|
||
TEST_ASSERT_GREATER_THAN(0, hd);
|
||
TEST_ASSERT_EQUAL(HTTP3_FRAME_SETTINGS, ft);
|
||
}
|
||
|
||
/** @test 编码 GOAWAY 帧 */
|
||
void test_encode_goaway_frame(void) {
|
||
uint8_t payload[8];
|
||
size_t pos = http3_encode_varint(100, payload);
|
||
|
||
uint8_t buf[32];
|
||
int n = http3_encode_frame(HTTP3_FRAME_GOAWAY, payload, pos, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
|
||
uint64_t ft = 0, flen = 0;
|
||
int hd = http3_decode_frame_header(buf, (size_t)n, &ft, &flen);
|
||
TEST_ASSERT_GREATER_THAN(0, hd);
|
||
TEST_ASSERT_EQUAL(HTTP3_FRAME_GOAWAY, ft);
|
||
}
|
||
|
||
/* ===== QPACK 编码/解码测试 ===== */
|
||
|
||
/** @test QPACK 编码:静态表完全匹配 :method=GET */
|
||
void test_qpack_encode_static_match_method_get(void) {
|
||
uint8_t buf[16];
|
||
int n = qpack_encode_header(":method", "GET", buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
/* Should use indexed encoding (0b11xxxxxx) with static index 2 */
|
||
/* buf[0] should be 0xC0 | 0x02 = 0xC2 = 194 */
|
||
TEST_ASSERT_EQUAL(0xC0, buf[0] & 0xC0); /* 0b11 prefix */
|
||
}
|
||
|
||
/** @test QPACK 编码:静态表完全匹配 :path=/ */
|
||
void test_qpack_encode_static_match_path(void) {
|
||
uint8_t buf[16];
|
||
int n = qpack_encode_header(":path", "/", buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
TEST_ASSERT_EQUAL(0xC0, buf[0] & 0xC0); /* 0b11 prefix */
|
||
}
|
||
|
||
/** @test QPACK 编码:静态表完全匹配 :scheme=https */
|
||
void test_qpack_encode_static_match_scheme(void) {
|
||
uint8_t buf[16];
|
||
int n = qpack_encode_header(":scheme", "https", buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
TEST_ASSERT_EQUAL(0xC0, buf[0] & 0xC0); /* 0b11 prefix */
|
||
}
|
||
|
||
/** @test QPACK 编码:字面量编码未知字段 */
|
||
void test_qpack_encode_literal_field(void) {
|
||
uint8_t buf[64];
|
||
int n = qpack_encode_header("x-custom-header", "custom-value", buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
/* Should use literal encoding (0b001xxxxx) */
|
||
TEST_ASSERT_EQUAL(0x20, buf[0]);
|
||
}
|
||
|
||
/** @test QPACK 编码:名称匹配静态表,值用字面量 */
|
||
void test_qpack_encode_name_ref_value_literal(void) {
|
||
uint8_t buf[64];
|
||
int n = qpack_encode_header("accept", "text/html", buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
/* accept=text/html is NOT a full static table match (accept="" at idx 17),
|
||
* so it uses literal with name reference (0b0101xxxx) */
|
||
TEST_ASSERT_EQUAL(0x40, buf[0] & 0xE0); /* 0b010 prefix */
|
||
}
|
||
|
||
/** @test QPACK 解码:索引编码的头部 */
|
||
void test_qpack_decode_indexed_header(void) {
|
||
/* Encode :method=GET - static index 2 */
|
||
uint8_t encoded[16];
|
||
int enc_n = qpack_encode_header(":method", "GET", encoded, sizeof(encoded));
|
||
TEST_ASSERT_GREATER_THAN(0, enc_n);
|
||
|
||
/* Now decode it */
|
||
qpack_decoded_t decoded;
|
||
size_t consumed = 0;
|
||
int rc = qpack_decode_header(encoded, (size_t)enc_n, &decoded, &consumed);
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_TRUE(decoded.valid);
|
||
TEST_ASSERT_EQUAL_STRING(":method", decoded.name);
|
||
TEST_ASSERT_EQUAL_STRING("GET", decoded.value);
|
||
}
|
||
|
||
/** @test QPACK 解码:字面量编码的头部 */
|
||
void test_qpack_decode_literal_header(void) {
|
||
/* Encode a literal field */
|
||
uint8_t encoded[64];
|
||
int enc_n = qpack_encode_header("x-test", "test-value", encoded, sizeof(encoded));
|
||
TEST_ASSERT_GREATER_THAN(0, enc_n);
|
||
|
||
/* Decode it */
|
||
qpack_decoded_t decoded;
|
||
size_t consumed = 0;
|
||
int rc = qpack_decode_header(encoded, (size_t)enc_n, &decoded, &consumed);
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_TRUE(decoded.valid);
|
||
TEST_ASSERT_EQUAL_STRING("x-test", decoded.name);
|
||
TEST_ASSERT_EQUAL_STRING("test-value", decoded.value);
|
||
}
|
||
|
||
/** @test QPACK 编解码往返 */
|
||
void test_qpack_roundtrip(void) {
|
||
const char *test_names[] = {
|
||
":method", ":path", ":scheme", ":authority",
|
||
"content-type", "accept", "user-agent"
|
||
};
|
||
const char *test_values[] = {
|
||
"GET", "/api/v1/test", "https", "example.com",
|
||
"application/json", "*/*", "TestAgent/1.0"
|
||
};
|
||
int num = sizeof(test_names) / sizeof(test_names[0]);
|
||
|
||
for (int i = 0; i < num; i++) {
|
||
uint8_t encoded[128];
|
||
int enc_n = qpack_encode_header(test_names[i], test_values[i],
|
||
encoded, sizeof(encoded));
|
||
TEST_ASSERT_GREATER_THAN_MESSAGE(0, enc_n, "编码失败");
|
||
|
||
qpack_decoded_t decoded;
|
||
size_t consumed = 0;
|
||
int rc = qpack_decode_header(encoded, (size_t)enc_n, &decoded, &consumed);
|
||
TEST_ASSERT_EQUAL_MESSAGE(0, rc, "解码失败");
|
||
TEST_ASSERT_TRUE_MESSAGE(decoded.valid, "解码结果无效");
|
||
TEST_ASSERT_EQUAL_STRING_MESSAGE(test_names[i], decoded.name, "名称不匹配");
|
||
TEST_ASSERT_EQUAL_STRING_MESSAGE(test_values[i], decoded.value, "值不匹配");
|
||
}
|
||
}
|
||
|
||
/** @test QPACK 编码完整请求头 */
|
||
void test_qpack_encode_request_headers(void) {
|
||
http_request_t req;
|
||
memset(&req, 0, sizeof(req));
|
||
req.method = HTTP_GET;
|
||
strncpy(req.path, "/index.html", sizeof(req.path) - 1);
|
||
strncpy(req.headers[0].name, "host", sizeof(req.headers[0].name) - 1);
|
||
strncpy(req.headers[0].value, "example.com", sizeof(req.headers[0].value) - 1);
|
||
req.num_headers = 1;
|
||
|
||
uint8_t buf[1024];
|
||
int n = qpack_encode_request_headers(&req, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
}
|
||
|
||
/** @test QPACK 解码完整请求头 */
|
||
void test_qpack_decode_request_headers(void) {
|
||
/* Build an encoded request */
|
||
http_request_t req;
|
||
memset(&req, 0, sizeof(req));
|
||
req.method = HTTP_GET;
|
||
strncpy(req.path, "/test", sizeof(req.path) - 1);
|
||
strncpy(req.headers[0].name, "host", sizeof(req.headers[0].name) - 1);
|
||
strncpy(req.headers[0].value, "example.com", sizeof(req.headers[0].value) - 1);
|
||
req.num_headers = 1;
|
||
|
||
uint8_t encoded[1024];
|
||
int enc_n = qpack_encode_request_headers(&req, encoded, sizeof(encoded));
|
||
TEST_ASSERT_GREATER_THAN(0, enc_n);
|
||
|
||
/* Decode it */
|
||
http_request_t decoded_req;
|
||
int rc = qpack_decode_request_headers(encoded, (size_t)enc_n, &decoded_req);
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_EQUAL(HTTP_GET, decoded_req.method);
|
||
TEST_ASSERT_EQUAL_STRING("/test", decoded_req.path);
|
||
http_request_free(&decoded_req);
|
||
}
|
||
|
||
/** @test QPACK 编码响应头 */
|
||
void test_qpack_encode_response_headers(void) {
|
||
http_response_t resp;
|
||
memset(&resp, 0, sizeof(resp));
|
||
resp.status_code = 200;
|
||
resp.content_type = "text/html";
|
||
resp.content_length = 42;
|
||
|
||
uint8_t buf[1024];
|
||
int n = qpack_encode_response_headers(&resp, buf, sizeof(buf));
|
||
TEST_ASSERT_GREATER_THAN(0, n);
|
||
}
|
||
|
||
/** @test QPACK 解码响应头 */
|
||
void test_qpack_decode_response_headers(void) {
|
||
/* Build an encoded response */
|
||
http_response_t resp;
|
||
memset(&resp, 0, sizeof(resp));
|
||
resp.status_code = 404;
|
||
resp.content_type = "text/plain";
|
||
resp.content_length = 0;
|
||
|
||
uint8_t encoded[1024];
|
||
int enc_n = qpack_encode_response_headers(&resp, encoded, sizeof(encoded));
|
||
TEST_ASSERT_GREATER_THAN(0, enc_n);
|
||
|
||
/* Decode it */
|
||
http_response_t decoded_resp;
|
||
int rc = qpack_decode_response_headers(encoded, (size_t)enc_n, &decoded_resp);
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_EQUAL(404, decoded_resp.status_code);
|
||
|
||
if (decoded_resp.content_type) {
|
||
free((void *)decoded_resp.content_type);
|
||
}
|
||
}
|
||
|
||
/** @test QPACK 解码:无效输入 */
|
||
void test_qpack_decode_invalid(void) {
|
||
qpack_decoded_t decoded;
|
||
size_t consumed = 0;
|
||
int rc = qpack_decode_header(NULL, 0, &decoded, &consumed);
|
||
TEST_ASSERT_EQUAL(-1, rc);
|
||
}
|
||
|
||
/* ===== QUIC 流管理测试 ===== */
|
||
|
||
/** @test QUIC 流创建和查找 */
|
||
void test_quic_stream_create_and_find(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(conn, 0);
|
||
TEST_ASSERT_NOT_NULL(s);
|
||
TEST_ASSERT_EQUAL(0, s->stream_id);
|
||
|
||
quic_stream_t *found = quic_stream_find(conn, 0);
|
||
TEST_ASSERT_NOT_NULL(found);
|
||
TEST_ASSERT_EQUAL_PTR(s, found);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 流数据写入和读取 */
|
||
void test_quic_stream_write_read(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(conn, 0);
|
||
TEST_ASSERT_NOT_NULL(s);
|
||
|
||
uint8_t data[] = "Hello, QUIC Stream!";
|
||
int rc = quic_stream_write(s, data, sizeof(data));
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_EQUAL(sizeof(data), s->recv_buf_len);
|
||
|
||
uint8_t read_buf[64];
|
||
ssize_t n = quic_stream_read(s, read_buf, sizeof(read_buf));
|
||
TEST_ASSERT_EQUAL(sizeof(data), n);
|
||
TEST_ASSERT_EQUAL_MEMORY(data, read_buf, sizeof(data));
|
||
TEST_ASSERT_EQUAL(0, s->recv_buf_len);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 流 FIN 标志 */
|
||
void test_quic_stream_fin(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(conn, 0);
|
||
TEST_ASSERT_NOT_NULL(s);
|
||
TEST_ASSERT_FALSE(s->local_fin);
|
||
|
||
quic_stream_set_fin(s);
|
||
TEST_ASSERT_TRUE(s->local_fin);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 流销毁 */
|
||
void test_quic_stream_destroy(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(conn, 4);
|
||
TEST_ASSERT_NOT_NULL(s);
|
||
|
||
quic_stream_destroy(conn, s);
|
||
quic_stream_t *found = quic_stream_find(conn, 4);
|
||
TEST_ASSERT_NULL(found);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 流:多个流 */
|
||
void test_quic_multiple_streams(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s0 = quic_stream_get_or_create(conn, 0);
|
||
quic_stream_t *s4 = quic_stream_get_or_create(conn, 4);
|
||
quic_stream_t *s8 = quic_stream_get_or_create(conn, 8);
|
||
|
||
TEST_ASSERT_NOT_NULL(s0);
|
||
TEST_ASSERT_NOT_NULL(s4);
|
||
TEST_ASSERT_NOT_NULL(s8);
|
||
|
||
TEST_ASSERT(s0 != s4);
|
||
TEST_ASSERT(s4 != s8);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 流:写入大数据 */
|
||
void test_quic_stream_large_write(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(12345,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(conn, 0);
|
||
TEST_ASSERT_NOT_NULL(s);
|
||
|
||
uint8_t *large_data = (uint8_t *)malloc(10000);
|
||
TEST_ASSERT_NOT_NULL(large_data);
|
||
memset(large_data, 0xAB, 10000);
|
||
|
||
int rc = quic_stream_write(s, large_data, 10000);
|
||
TEST_ASSERT_EQUAL(0, rc);
|
||
TEST_ASSERT_EQUAL(10000, s->recv_buf_len);
|
||
|
||
uint8_t *read_buf = (uint8_t *)malloc(10000);
|
||
TEST_ASSERT_NOT_NULL(read_buf);
|
||
ssize_t n = quic_stream_read(s, read_buf, 10000);
|
||
TEST_ASSERT_EQUAL(10000, n);
|
||
TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(large_data, read_buf, 10000, "大数据读写不一致");
|
||
|
||
free(large_data);
|
||
free(read_buf);
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/* ===== QUIC 连接管理测试 ===== */
|
||
|
||
/** @test QUIC 连接创建和销毁 */
|
||
void test_quic_connection_create_destroy(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
((struct sockaddr_in *)&addr)->sin_family = AF_INET;
|
||
|
||
quic_connection_t *conn = quic_connection_create(99999,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
TEST_ASSERT_EQUAL(99999, conn->conn_id);
|
||
TEST_ASSERT_FALSE(conn->handshake_complete);
|
||
TEST_ASSERT_FALSE(conn->closed);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 连接查找 */
|
||
void test_quic_find_connection(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(11111,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
quic_connection_t *found = quic_find_connection(11111);
|
||
TEST_ASSERT_NOT_NULL(found);
|
||
TEST_ASSERT_EQUAL_PTR(conn, found);
|
||
|
||
quic_connection_t *not_found = quic_find_connection(99999);
|
||
TEST_ASSERT_NULL(not_found);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test QUIC 连接计数 */
|
||
void test_quic_connection_count(void) {
|
||
size_t before = quic_get_connection_count();
|
||
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *c1 = quic_connection_create(100,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(c1);
|
||
TEST_ASSERT_EQUAL(before + 1, quic_get_connection_count());
|
||
|
||
quic_connection_t *c2 = quic_connection_create(200,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(c2);
|
||
TEST_ASSERT_EQUAL(before + 2, quic_get_connection_count());
|
||
|
||
quic_connection_destroy(c1);
|
||
TEST_ASSERT_EQUAL(before + 1, quic_get_connection_count());
|
||
|
||
quic_connection_destroy(c2);
|
||
TEST_ASSERT_EQUAL(before, quic_get_connection_count());
|
||
}
|
||
|
||
/** @test QUIC 连接 ID 生成 */
|
||
void test_quic_generate_conn_id(void) {
|
||
uint64_t id1 = quic_generate_conn_id();
|
||
uint64_t id2 = quic_generate_conn_id();
|
||
|
||
TEST_ASSERT_NOT_EQUAL(id1, id2);
|
||
TEST_ASSERT_NOT_EQUAL(0, id1);
|
||
TEST_ASSERT_NOT_EQUAL(0, id2);
|
||
}
|
||
|
||
/** @test QUIC 超时连接清理 */
|
||
void test_quic_cleanup_timeout_connections(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(300,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
size_t count_before = quic_get_connection_count();
|
||
TEST_ASSERT_GREATER_THAN(0, count_before);
|
||
|
||
/* 设置最后活动时间为很久以前 */
|
||
conn->last_activity = 0;
|
||
|
||
/* 清理超时连接(使用 1ms 超时) */
|
||
quic_cleanup_timeout_connections(1);
|
||
|
||
/* 连接应该被清理 */
|
||
quic_connection_t *found = quic_find_connection(300);
|
||
TEST_ASSERT_NULL(found);
|
||
}
|
||
|
||
/* ===== HTTP/3 会话管理测试 ===== */
|
||
|
||
/** @test HTTP/3 会话创建和销毁 */
|
||
void test_http3_session_create_destroy(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(400,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
http3_session_t *session = http3_session_create(conn);
|
||
TEST_ASSERT_NOT_NULL(session);
|
||
TEST_ASSERT_EQUAL(conn, session->conn);
|
||
TEST_ASSERT_EQUAL(HTTP3_DEFAULT_MAX_FIELD_SECTION_SIZE,
|
||
session->max_field_section_size);
|
||
|
||
http3_session_destroy(session);
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test HTTP/3 多次会话创建 */
|
||
void test_http3_session_multiple(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn1 = quic_connection_create(500,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
quic_connection_t *conn2 = quic_connection_create(600,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
|
||
http3_session_t *s1 = http3_session_create(conn1);
|
||
http3_session_t *s2 = http3_session_create(conn2);
|
||
|
||
TEST_ASSERT_NOT_NULL(s1);
|
||
TEST_ASSERT_NOT_NULL(s2);
|
||
TEST_ASSERT(s1 != s2);
|
||
|
||
http3_session_destroy(s1);
|
||
http3_session_destroy(s2);
|
||
quic_connection_destroy(conn1);
|
||
quic_connection_destroy(conn2);
|
||
}
|
||
|
||
/** @test HTTP/3 会话创建:NULL 连接 */
|
||
void test_http3_session_create_null(void) {
|
||
http3_session_t *session = http3_session_create(NULL);
|
||
TEST_ASSERT_NULL(session);
|
||
}
|
||
|
||
/* ===== 错误码测试 ===== */
|
||
|
||
/** @test HTTP/3 错误码值 */
|
||
void test_http3_error_codes(void) {
|
||
TEST_ASSERT_EQUAL(0x0100, HTTP3_NO_ERROR);
|
||
TEST_ASSERT_EQUAL(0x0101, HTTP3_GENERAL_PROTOCOL_ERROR);
|
||
TEST_ASSERT_EQUAL(0x0102, HTTP3_INTERNAL_ERROR);
|
||
TEST_ASSERT_EQUAL(0x0103, HTTP3_STREAM_CREATION_ERROR);
|
||
TEST_ASSERT_EQUAL(0x0110, HTTP3_VERSION_FALLBACK);
|
||
}
|
||
|
||
/* ===== 时间戳测试 ===== */
|
||
|
||
/** @test 当前时间戳 */
|
||
void test_quic_current_time_ms(void) {
|
||
uint64_t t1 = quic_current_time_ms();
|
||
TEST_ASSERT_GREATER_THAN(0, t1);
|
||
|
||
/* 应该是单调递增的(至少不减) */
|
||
uint64_t t2 = quic_current_time_ms();
|
||
TEST_ASSERT_GREATER_OR_EQUAL(t1, t2);
|
||
}
|
||
|
||
/* ===== 边界条件测试 ===== */
|
||
|
||
/** @test varint 编解码边界值 */
|
||
void test_varint_boundary_values(void) {
|
||
uint64_t boundaries[] = {0, 63, 64, 16383, 16384, 1073741823ULL,
|
||
1073741824ULL, 4611686018427387903ULL};
|
||
int num = sizeof(boundaries) / sizeof(boundaries[0]);
|
||
|
||
for (int i = 0; i < num; i++) {
|
||
uint8_t buf[8];
|
||
size_t enc_n = http3_encode_varint(boundaries[i], buf);
|
||
TEST_ASSERT_GREATER_THAN(0, enc_n);
|
||
|
||
uint64_t decoded = 0;
|
||
int dec_n = http3_decode_varint(buf, enc_n, &decoded);
|
||
TEST_ASSERT_EQUAL(enc_n, (size_t)dec_n);
|
||
TEST_ASSERT_EQUAL(boundaries[i], decoded);
|
||
}
|
||
}
|
||
|
||
/** @test QUIC 流:NULL 参数处理 */
|
||
void test_quic_stream_null_params(void) {
|
||
int rc = quic_stream_write(NULL, (uint8_t *)"test", 4);
|
||
TEST_ASSERT_EQUAL(-1, rc);
|
||
|
||
ssize_t n = quic_stream_read(NULL, NULL, 0);
|
||
TEST_ASSERT_EQUAL(-1, n);
|
||
|
||
quic_stream_set_fin(NULL); /* 不应崩溃 */
|
||
}
|
||
|
||
/** @test QUIC 连接:NULL 参数处理 */
|
||
void test_quic_connection_null(void) {
|
||
quic_connection_destroy(NULL); /* 不应崩溃 */
|
||
|
||
quic_stream_t *s = quic_stream_get_or_create(NULL, 0);
|
||
TEST_ASSERT_NULL(s);
|
||
|
||
quic_stream_t *f = quic_stream_find(NULL, 0);
|
||
TEST_ASSERT_NULL(f);
|
||
}
|
||
|
||
/** @test http3_close_connection: NULL */
|
||
void test_http3_close_connection_null(void) {
|
||
http3_close_connection(NULL, HTTP3_NO_ERROR); /* 不应崩溃 */
|
||
}
|
||
|
||
/** @test http3_send_error: NULL session */
|
||
void test_http3_send_error_null(void) {
|
||
http3_send_error(NULL, 0, 404, "Not Found"); /* 不应崩溃 */
|
||
}
|
||
|
||
/** @test http3_send_settings: NULL */
|
||
void test_http3_send_settings_null(void) {
|
||
int rc = http3_send_settings(NULL);
|
||
TEST_ASSERT_EQUAL(-1, rc);
|
||
}
|
||
|
||
/** @test http3_process_datagram: NULL params */
|
||
void test_http3_process_datagram_null(void) {
|
||
uint8_t data[] = "test";
|
||
struct sockaddr_storage addr = {0};
|
||
http3_process_datagram(COCOON_INVALID_SOCKET, NULL, 0, &addr);
|
||
http3_process_datagram(COCOON_INVALID_SOCKET, data, 4, NULL);
|
||
}
|
||
|
||
/** @test quic_send_datagram: invalid socket */
|
||
void test_quic_send_datagram_invalid(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(700,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
TEST_ASSERT_NOT_NULL(conn);
|
||
|
||
uint8_t data[] = "test";
|
||
int rc = quic_send_datagram(conn, data, 4);
|
||
TEST_ASSERT_EQUAL(-1, rc);
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/** @test 帧解码:数据不足 */
|
||
void test_parse_frame_insufficient_data(void) {
|
||
struct sockaddr_storage addr = {0};
|
||
quic_connection_t *conn = quic_connection_create(800,
|
||
COCOON_INVALID_SOCKET, &addr);
|
||
quic_stream_t *stream = quic_stream_get_or_create(conn, 0);
|
||
|
||
/* 写入不完整的帧数据 */
|
||
uint8_t partial[] = {0x00}; /* 只有类型,没有长度 */
|
||
quic_stream_write(stream, partial, 1);
|
||
|
||
uint64_t ft = 0;
|
||
const uint8_t *payload = NULL;
|
||
size_t payload_len = 0;
|
||
int rc = http3_parse_frame(stream, &ft, &payload, &payload_len);
|
||
TEST_ASSERT_EQUAL(1, rc); /* 数据不足 */
|
||
|
||
quic_connection_destroy(conn);
|
||
}
|
||
|
||
/* ===== main ===== */
|
||
|
||
int main(void) {
|
||
UNITY_BEGIN();
|
||
|
||
/* Variable-length integer encode */
|
||
RUN_TEST(test_varint_encode_zero);
|
||
RUN_TEST(test_varint_encode_63);
|
||
RUN_TEST(test_varint_encode_64);
|
||
RUN_TEST(test_varint_encode_16383);
|
||
RUN_TEST(test_varint_encode_16384);
|
||
RUN_TEST(test_varint_encode_4byte_max);
|
||
RUN_TEST(test_varint_encode_8byte);
|
||
RUN_TEST(test_varint_encode_max);
|
||
RUN_TEST(test_varint_encode_null_buf);
|
||
|
||
/* Variable-length integer decode */
|
||
RUN_TEST(test_varint_decode_zero);
|
||
RUN_TEST(test_varint_decode_63);
|
||
RUN_TEST(test_varint_decode_64);
|
||
RUN_TEST(test_varint_decode_16383);
|
||
RUN_TEST(test_varint_decode_4byte);
|
||
RUN_TEST(test_varint_decode_insufficient_data);
|
||
RUN_TEST(test_varint_decode_null);
|
||
RUN_TEST(test_varint_roundtrip);
|
||
RUN_TEST(test_varint_boundary_values);
|
||
|
||
/* Frame header */
|
||
RUN_TEST(test_frame_header_size);
|
||
RUN_TEST(test_frame_header_encode_decode);
|
||
RUN_TEST(test_frame_header_decode_insufficient);
|
||
RUN_TEST(test_frame_header_decode_null);
|
||
|
||
/* Full frame encoding */
|
||
RUN_TEST(test_full_frame_encode);
|
||
RUN_TEST(test_encode_data_frame);
|
||
RUN_TEST(test_encode_headers_frame);
|
||
RUN_TEST(test_encode_settings_frame);
|
||
RUN_TEST(test_encode_goaway_frame);
|
||
|
||
/* QPACK encode */
|
||
RUN_TEST(test_qpack_encode_static_match_method_get);
|
||
RUN_TEST(test_qpack_encode_static_match_path);
|
||
RUN_TEST(test_qpack_encode_static_match_scheme);
|
||
RUN_TEST(test_qpack_encode_literal_field);
|
||
RUN_TEST(test_qpack_encode_name_ref_value_literal);
|
||
|
||
/* QPACK decode */
|
||
RUN_TEST(test_qpack_decode_indexed_header);
|
||
RUN_TEST(test_qpack_decode_literal_header);
|
||
RUN_TEST(test_qpack_decode_invalid);
|
||
|
||
/* QPACK roundtrip */
|
||
RUN_TEST(test_qpack_roundtrip);
|
||
RUN_TEST(test_qpack_encode_request_headers);
|
||
RUN_TEST(test_qpack_decode_request_headers);
|
||
RUN_TEST(test_qpack_encode_response_headers);
|
||
RUN_TEST(test_qpack_decode_response_headers);
|
||
|
||
/* QUIC stream management */
|
||
RUN_TEST(test_quic_stream_create_and_find);
|
||
RUN_TEST(test_quic_stream_write_read);
|
||
RUN_TEST(test_quic_stream_fin);
|
||
RUN_TEST(test_quic_stream_destroy);
|
||
RUN_TEST(test_quic_multiple_streams);
|
||
RUN_TEST(test_quic_stream_large_write);
|
||
RUN_TEST(test_quic_stream_null_params);
|
||
|
||
/* QUIC connection management */
|
||
RUN_TEST(test_quic_connection_create_destroy);
|
||
RUN_TEST(test_quic_find_connection);
|
||
RUN_TEST(test_quic_connection_count);
|
||
RUN_TEST(test_quic_generate_conn_id);
|
||
RUN_TEST(test_quic_cleanup_timeout_connections);
|
||
RUN_TEST(test_quic_connection_null);
|
||
|
||
/* HTTP/3 session management */
|
||
RUN_TEST(test_http3_session_create_destroy);
|
||
RUN_TEST(test_http3_session_multiple);
|
||
RUN_TEST(test_http3_session_create_null);
|
||
|
||
/* Error codes */
|
||
RUN_TEST(test_http3_error_codes);
|
||
|
||
/* Time utilities */
|
||
RUN_TEST(test_quic_current_time_ms);
|
||
|
||
/* Boundary / NULL tests */
|
||
RUN_TEST(test_http3_close_connection_null);
|
||
RUN_TEST(test_http3_send_error_null);
|
||
RUN_TEST(test_http3_send_settings_null);
|
||
RUN_TEST(test_http3_process_datagram_null);
|
||
RUN_TEST(test_quic_send_datagram_invalid);
|
||
RUN_TEST(test_parse_frame_insufficient_data);
|
||
|
||
return UNITY_END();
|
||
}
|