Skip to content

合规测试基础设施 + RFC 4475 首批 fixtures(叠加 PR #2) - #3

Draft
lixuanqun wants to merge 3 commits into
cursor/sip-stack-rewrite-3c36from
cursor/sip-rfc4475-fixtures-3c36
Draft

合规测试基础设施 + RFC 4475 首批 fixtures(叠加 PR #2)#3
lixuanqun wants to merge 3 commits into
cursor/sip-stack-rewrite-3c36from
cursor/sip-rfc4475-fixtures-3c36

Conversation

@lixuanqun

Copy link
Copy Markdown
Owner

概述

为 Phase 2(parser)做铺垫:先建 数据 + harness。本 PR 完全不动协议核心代码,只搭合规测试的基础设施和首批 fixture 数据,让后续的 parser 实现可以一边写一边让 fixture 一个一个转绿。

🔗 本 PR 基于 PR #2(骨架)。PR #2 合并后 base 会自动更新到 main

决策与设计

1. Fixture 文件格式:两段式 .fixture 源 + 生成器

直接手写 .raw 风险大(编辑器会悄悄把 CRLF 改成 LF)。改为:

1. 作者用 LF 写 .fixture 源(注释 + --- raw --- + --- expect ---)
2. tools/write_fixture.py 转码生成:
   • <id>.raw                    byte-exact CRLF 二进制
   • <id>.expect.properties      JDK Properties(零依赖)

.gitattributes*.raw 标为 binary,禁止 git/编辑器任何变换。

2. Manifest 用 java.util.Properties 而非 JSON

零依赖、零引入。schema 见 torture/README.md

3. 目录分桶

torture/
├── self-test/      我们撰写的基线(baseline / harness sanity)
├── rfc4475/        RFC 4475 32 vector(byte-exact 摘自原文)
└── rfc5118/        RFC 5118 IPv6 vector(后续)

4. 加载器:sealed + record

com.sip.compliance.fixture 包:

类型 角色
MessageKind enum: REQUEST / RESPONSE
FixtureExpectation sealed interface, permits Accept / Reject(record)
TortureFixture record(id, source, bytes, expectation)
FixtureRepository classpath 扫描 + manifest 解析

本 PR 落地的内容

工具链 (tools/)

  • write_fixture.py — 主生成器,含详细切分约定(含 no-body / with-body 两种空行语义)
  • rfc4475/rfc4475.txt — RFC 4475 原文 ASCII 副本(事实来源)
  • rfc4475/extract_message.py — 按 Message Details : <id> 摘取单条消息(去缩进、去分页符)

加载器 (sip-compliance-tests/.../fixture/)

  • 4 个核心类型(见表)
  • FixtureRepositoryTest 用 JUnit 5 DynamicTest 跑 self-test:
    • 全局排序 / 去重
    • 每个 fixture 的 CRLF 字节级一致性(禁止 lone CR / lone LF)
    • accept 一致性(CRLFCRLF 终止 + body.length 匹配实际字节 + 必填字段齐全)
    • reject 一致性(error.category 非空、kebab-case)

首批 fixtures

self-test/(4 个)

文件 verdict 用途
simple-options accept clean OPTIONS 请求基线
simple-200-ok accept clean 200 OK 响应基线
invite-with-sdp accept INVITE + 162 字节 SDP,验证 Content-Length framing
missing-sip-version reject Request-Line 缺 SIP-Version → malformed-start-line

rfc4475/(3 个,byte-exact 来自 RFC)

文件 RFC 节 verdict 考验点
3.1.1.6-lwsdisp §3.1.1.6 accept display-name 与 < 之间无 LWS
3.1.1.9-semiuri §3.1.1.9 accept URI userpart 含分号参数 + Accept 头 LWS folding
3.1.2.1-badinv01 §3.1.2.1 reject Via / Contact 头多余分隔符 → malformed-header

验证

$ mvn -B -ntp verify
[INFO] SIP Stack (parent) ................................. SUCCESS
[INFO] SIP :: Message Model ............................... SUCCESS  10 tests
[INFO] SIP :: Codec ....................................... SUCCESS   1 test
[INFO] SIP :: Transport SPI ............................... SUCCESS
[INFO] SIP :: Transport (NIO + Virtual Threads) ........... SUCCESS
[INFO] SIP :: Transaction Layer ........................... SUCCESS
[INFO] SIP :: Dialog Layer ................................ SUCCESS
[INFO] SIP :: User Agent .................................. SUCCESS
[INFO] SIP :: Compliance Tests ............................ SUCCESS  15 tests
[INFO] BUILD SUCCESS

Total: 26 tests passed, 0 failed.

字节级抽样验证(od -c):所有 fixture 的 .raw 都以正确的方式终止(no-body 以 CRLFCRLF;with-body 以 body 的最后 1 字节,body 长度严格等于 Content-Length)。

下一步(Phase 2b)

新开一个 PR,依赖本 PR 的 fixture 基础设施,开始实现真正的 SipParser

  • 起始行解析(请求行 / 状态行)
  • 头块解析 + LWS folding(RFC 3261 §7.3.1)
  • Content-Length-driven body framing
  • 每让一个 fixture 转绿,commit 一次;同时把 RFC 4475 剩余 25+ fixture 增量纳入

合并顺序建议:

  1. 先合并 #2(骨架)
  2. 再合并本 PR(fixture 基础设施)
  3. parser 实现 PR 基于 main
Open in Web Open in Cursor 

cursoragent and others added 3 commits May 11, 2026 15:04
- .gitattributes:将 *.raw 标记为 binary,禁止 git/编辑器对 SIP wire-format
  做 CRLF↔LF 转换;其他源代码文件统一 LF。
- tools/write_fixture.py:从 .fixture 源文件(LF)生成 byte-exact .raw(CRLF)
  和 .expect.properties 双文件。详细约定见脚本内文档。
- tools/rfc4475/rfc4475.txt:保留 RFC 4475 原始 ASCII 副本,作为后续 fixture
  byte-exact 提取的事实来源。
- tools/rfc4475/extract_message.py:按 'Message Details : <id>' 标记从 RFC
  正文提取单条消息(剥去 RFC 6 空格缩进、跨页符、分页页脚),便于将更多
  fixture 增量纳入仓库。

Co-authored-by: li xuanqun <793005378@qq.com>
新增 com.sip.compliance.fixture 包:
- MessageKind:sealed enum(REQUEST/RESPONSE)
- FixtureExpectation:sealed 接口(Accept/Reject 两种 verdict)
- TortureFixture:record,承载 id、source、bytes、expectation
- FixtureRepository:从 classpath 'torture/' 根递归扫描所有 .raw +
  配对的 .expect.properties,返回稳定排序的 fixture 列表
- FixtureRepositoryTest:harness 自身的 self-test,使用 JUnit 5
  DynamicTest 对每个 fixture 做:
  · CRLF 字节级一致性(不允许 lone CR / lone LF)
  · accept 一致性(CRLFCRLF 终止符、body.length 与实际字节数匹配、
    request/response 必填字段齐全)
  · reject 一致性(error.category 非空且符合 kebab-case)

manifest 走 java.util.Properties,零依赖。
本提交不引入任何 fixture 数据,下一个提交单独添加。

旧的 Rfc4475TortureSmokeTest 占位测试被新的 self-test 取代。

Co-authored-by: li xuanqun <793005378@qq.com>
self-test/(4 个我们自己撰写的基线 fixture):
- simple-options.fixture        clean OPTIONS request(accept)
- simple-200-ok.fixture         clean 200 OK response(accept)
- invite-with-sdp.fixture       INVITE + 162 字节 SDP body(accept,
                                验证 Content-Length-driven framing)
- missing-sip-version.fixture   Request-Line 缺 SIP-Version token
                                (reject, malformed-start-line)

rfc4475/(3 个从 RFC 4475 byte-exact 提取的 torture vector):
- 3.1.1.6-lwsdisp.fixture       display-name 与 < 之间无 LWS(accept)
- 3.1.1.9-semiuri.fixture       URI userpart 含分号参数 + Accept 头
                                LWS folding(accept)
- 3.1.2.1-badinv01.fixture      Via 与 Contact 头多余分隔符(reject,
                                malformed-header)

每个 fixture 通过 tools/write_fixture.py 从 .fixture 源生成
.raw(CRLF byte-exact)和 .expect.properties(JDK Properties,零依赖)。

torture/README.md 详细说明 fixture 文件格式约定和 no-body / with-body
两种结构下空行的语义。

FixtureRepositoryTest 跑通全部 15 个动态测试:
- 1 个全局排序/去重检查
- 7 个 CRLF 字节级一致性(每个 fixture 一个)
- 5 个 accept 一致性(CRLFCRLF + body.length + 必填字段)
- 2 个 reject 一致性(category 非空 + kebab-case)

Co-authored-by: li xuanqun <793005378@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants