Files
STM32F4-Base/test/host/sntp/run_unit_test.py
T
super_agent_bot ad7338365c
CI / 静态门禁 (pre-commit) (push) Failing after 6m14s
CI / 主机侧单测 (MSVC) (push) Successful in 54s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 4m35s
CI / 主机侧单测 (MSVC) (pull_request) Successful in 47s
feat(sntp): 板端 SNTP 校时接入——coreSNTP 序列化器 + [sntp] 段 + 设置页(#73)
- vendored coreSNTP v2.0.0 序列化器(MIT,仅 serializer+LICENSE,零堆),
  48 字节报文编解码在库,节奏与准入判据在本方(RFC 4330 §10 调研口径)
- App/sync/time_sntp.c 挂 timeSyncTask 的 8888 事件循环,等待切片 ≤50 ms,
  不饿任务狗与 IWDG;懒建 UDP socket,代际变化/禁用/死错误码即关闭归还
- 防伪 = OriginTimestamp 逐位等于发出时 T1(含低 16 位随机小数位);
  mode/stratum/闰秒指示/KoD 按 RFC 拒收;DENY·RSTR 换服务器、RATE 只退避
- 主备轮换 + 失败指数退避(5 s 起、60 s 封顶)+ 首轮 1~5 分钟随机错峰;
  成功恢复 poll_min 周期(1~1440 分,出厂默认 60,默认不启用不发包)
- 钟面 = 本地时间:UTC+8 固定偏移落 sys_clock_set_unix(§1.1 时基裁定,
  第三个写入口,装置仍不存时区);|offset|<2 s 只记日志不步进,冷启动或
  更大偏差步进并回写 SD2506,留痕 [SNTP] step 与 syslog OPER
- 首个校验通过的同步置 SYS_EVT_TIMESYNC_READY(就绪位,消费方按需 NoClear)
- [sntp] 配置段(enable/server1/server2/poll_min)属主 sntp_cfg.c,
  注册在 net_cfg_load();UI 页 31「SNTP 设置」(密码叶):启用开关 +
  主/备服务器 octet 编辑 + 周期(分) + 保存,复用 net_cfg_save_request 链
- 测试与门禁:test/host/sntp 新套件(报文/防伪/KoD/退避周期/阶跃域/配置
  注册表)、net_cfg 与 time_sync 套件补 fake、黄金参考 66→74 张零漂移、
  字符集 228 字、Keil 0 错 0 警(RO +5,848 B 含字体)、覆盖率基线回填
- 文档:墙钟维护说明 §16、网络配置说明 [sntp] 节、配置文件设计说明变更记录、
  产品需求 FR-TIME-3 与 8.3/9.1.2 台账、UI 补齐规划/UI补齐 31 叶口径、
  登记簿销项并登记「SNTP 校时真机判据」等台架(PC 时间源 192.168.31.161/.13)
2026-11-04 16:20:22 +08:00

64 lines
3.0 KiB
Python
Raw 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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""SNTP 客户端(time_sntp)的主机侧纯逻辑单元测试运行器(纯标准库)。
做什么:
用本机 MSVC 编译 test/host/sntp/sntp_test.c(它以 #include 纳入**生产源
文件** App/sync/time_sntp.c + Drivers/BSP/NETCFG/sntp_cfg.c + vendor
Lib/coreSNTP/core_sntp_serializer.c),在 PC 上离线跑:
RFC 4330 §10 节奏(初始 1~5min 随机散布 / 失败超时翻倍封顶 60s / 成功按
poll_min 重排)、§5.3 防欺骗(应答源 IP:port / originate 含随机低位精确
匹配 / mode / LI=3 / stratum>15 / KoD DENY·RSTR·RATE·他码)、§5.5 步进
策略(±2s 死区只记录、冷启动直采 T3、钟面 = 本地 UTC+8 恒加 28800、
值域守卫)、[sntp] 配置注册与 poll 钳位、网络代次/停用收口与 socket 生命周期。
失败即非 0 退出。零硬件、零烧录、毫秒级。
工具链探测 / 编译运行 / 退出码判定全部委托通用 harness
`test/host/common/unit_test_harness.py`(本文件只做声明)。
为什么要主机侧单测(而不是只用真机):
SNTP 的失败路径(伪造应答、KoD、超时风暴、tick 回绕)在真机上不可复现或
要等小时级;且本模块直接拨 RTC(sys_clock→SD2506 写回),拨错一次就是
事故——判据必须逐包断言。真机只做正向链路回归(PC W32Time 对端)。
用法(仓库根目录):
& '.venv\\Scripts\\python.exe' test/host/sntp/run_unit_test.py
退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。
设计依据:#57 调研(docs 见 sntp-调研报告.md)+ App/sync/time_sntp.c 文件头;
创建日期:2026-11-04
"""
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
# harness 位于 test/host/common/
sys.path.insert(0, os.path.join(ROOT, "test", "host", "common"))
from unit_test_harness import TestBuild, run_host_unit_test # noqa: E402
# 顺序敏感:stub 目录必须**先于**生产目录,才能覆盖 FreeRTOS.h / task.h /
# cmsis_os2.h / net_types.h / net_socket.h / sys_clock.h / sys_events.h /
# sys_log.h / dbg_log.h(真实头会拖入整套 FreeRTOS / HAL / CH395F)。
# cfg_file.h 用**真实头**(App/cfg,纯 stdint/stddef——注册描述符契约原汁);
# sntp_cfg.h / time_sntp.h 用真实头(接口契约原汁)。
BUILD = TestBuild(
name="SNTP Client Tests",
src=os.path.join(HERE, "sntp_test.c"),
include_dirs=[
os.path.join(HERE, "stub"),
os.path.join(ROOT, "App", "sync"),
os.path.join(ROOT, "App", "cfg"),
os.path.join(ROOT, "Drivers", "BSP", "NETCFG"),
os.path.join(ROOT, "Lib", "coreSNTP"),
os.path.join(ROOT, "Lib", "coreSNTP", "include"),
HERE,
],
summary_marker="=== SNTP Client Tests:",
)
if __name__ == "__main__":
sys.exit(run_host_unit_test(BUILD))