From ad3dbdb9dc91c98b8b5d2aef0cacea715d97a72d Mon Sep 17 00:00:00 2001 From: FinDataHub Date: Mon, 26 Oct 2026 20:56:01 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E6=96=B0=E5=A2=9E=20Windows=20job=20?= =?UTF-8?q?=E4=B8=8E=20MySQL=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Windows 跨平台回归(观察期,不阻塞) 目的:验证 paths.py / process_utils.py 在 win32 上真的可用,而不是"写完就算"。 这两个模块已接线 4 个脚本,一旦 Windows 分支写错,表现是采集器静默不启动 或 PID 检测失效——本地 macOS 上完全看不出来。 **范围有意收窄:不装 akshare**。它传递依赖 py_mini_racer(62MB V8 预编译), Windows 上是否有 3.12 wheel 未验证,属迁移计划列明的唯一硬阻塞点。 在验证它之前塞进 CI 只会让 job 长期飘红、失去信号价值。 覆盖:check_python_version --strict → compileall → test_paths_process_utils (32 条,核心)→ Scripts/bin/tests(252 条,此前只在 POSIX 跑过)→ core + client。 continue-on-error: true + 注释写明转正条件(连续两次全绿后删掉)。 首次接跨平台 CI 若直接阻塞,一次环境差异就把主线挡死,反而逼人绕过它。 已提前修掉一处确定会失败的用例:test_newsflash_collect 的 SIGTERM 留痕测试。 Windows 的 send_signal(SIGTERM) 实际走 TerminateProcess,不触发子进程里的 Python handler,断言必然失败。已加 skipif 并注明该能力本身是 POSIX 专属。 ## MySQL service(集成测试转阻塞) python job 增加 services: mysql(mysql:8.0),集成测试成为阻塞性步骤。 三个必须处理的差异: 1. 认证插件:MySQL 8 默认 caching_sha2_password,首次连接走 full path 需 RSA → 装 cryptography,另加 --default-authentication-plugin 双保险 (注意 8.4 起该参数已移除,升镜像需同步改)。 ⚠️ 本机某些 venv 没装 cryptography 也能连——那是认证缓存命中 fast path, 不代表 CI 也需要。只看本地结果会误判依赖冗余。 2. 版本:CI 8.0 vs 生产 26.7。事务/回滚语义一致(InnoDB),套件只用 CREATE TABLE + UNIQUE KEY,无版本敏感语法。 3. YAML 的 >- 折叠块内不能写注释:'#' 会被当成内容传给 docker,容器启动即失败。 注释必须置于 options: 之前(已用 assert '#' not in opts 验证)。 两级排除避免重复跑:python job 单元测试步骤与 windows job 均加 --ignore=.../integration。 --- .github/workflows/ci.yml | 123 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09cca12..f73eb5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,29 @@ jobs: python: name: Python 3.12 一致性 / 语法 / 测试 runs-on: ubuntu-latest + # 真实 MySQL:给 replace 的事务语义做真库验证(fake 游标验不出回滚与半成品) + # + # 版本差异需知悉:CI 用 MySQL 8.0,生产是 26.7。事务/回滚语义一致(同为 InnoDB), + # 但 DDL 默认值与部分语法可能不同。集成套件只用 CREATE TABLE + UNIQUE KEY, + # 不含版本敏感语法;若将来要测分区表、生成列等特性,须先在此对齐版本。 + # + # 密码为临时容器专用明文:service container 不暴露到公网,且随 runner 销毁。 + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ROOT_PASSWORD: ci_root_pw_test_only + ports: + - 3306:3306 + # 注:--default-authentication-plugin 仅为双保险(配合 cryptography)。 + # MySQL 8.4 起该参数已移除、改用 --authentication-policy, + # 将来升级镜像版本需同步调整,否则容器启动即失败。 + options: >- + --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -pci_root_pw_test_only" + --health-interval=10s + --health-timeout=5s + --health-retries=12 + --default-authentication-plugin=mysql_native_password steps: - uses: actions/checkout@v4 @@ -42,7 +65,13 @@ jobs: Services/akshare_fetcher/src - name: 安装测试依赖 - run: python3 -m pip install --quiet pytest pytest-asyncio + # cryptography 是 pymysql 走 caching_sha2_password 的 **full path** 认证时 + # 必需的(需要 RSA 公钥交换)。缺了会报 "cryptography package is required"。 + # + # 注意一个容易误判的现象:本机某些 venv 没装 cryptography 也能连上库—— + # 那是因为该 MySQL 实例的认证信息已被缓存,握手走了 fast path。 + # CI 里是**全新容器、首次连接**,必然走 full path,所以这里必须装。 + run: python3 -m pip install --quiet pytest pytest-asyncio cryptography - name: 安装本地包(含各服务) # findatahub-core 不在 PyPI 上,必须先本地安装; @@ -54,15 +83,37 @@ jobs: python3 -m pip install --quiet ./Services/findatahub-client python3 -m pip install --quiet -e ./Services/findatahub-core --no-build-isolation 2>/dev/null || true + - name: 统一测试入口自检 + # 只验证解释器探测与套件声明是否可用,不跑测试(成本近乎 0)。 + # 目的:防止 Scripts/bin/run_all_tests.py 随目录调整悄悄失效—— + # 脚本腐烂时这里会以退出码 2 明确报错,而不是等到有人在本地踩坑。 + run: python3 Scripts/bin/run_all_tests.py --list + - name: 运行单元测试(核心与采集器,纯离线) - # 这些用例全部为 mock 驱动、不连库,故设为阻塞性 + # 这些用例全部为 mock 驱动、不连库,故设为阻塞性。 + # integration 子目录单独跑(见下一步),此处排除以免重复。 run: | - python3 -m pytest Services/findatahub-core/tests -q + python3 -m pytest Services/findatahub-core/tests -q --ignore=Services/findatahub-core/tests/integration python3 -m pytest Services/findatahub-client/tests -q python3 -m pytest Services/tushare_fetcher/tests/unit -q python3 -m pytest Services/akshare_fetcher/tests -q python3 -m pytest Scripts/bin/tests -q + - name: 真实库集成测试(replace 事务语义) + # 验证 fake 游标验不了的三件事: + # 1. 事务是否真的回滚(fake 的 rollback 只是置标志位) + # 2. 跨 chunk 失败是否留下「半成品」(fake 不会真提交,永远复现不出来) + # 3. 熔断时表是否真的没动 + # 测试自建 fdh_it_replace_<随机> 空库并 DROP,不碰 service 里的任何现有库。 + # 曾做证伪:把实现改回「每 chunk 提交」,本套件会报 + # 「回滚不完整:表内行数既不是旧值」,证明用例有效。 + env: + MYSQL_HOST: 127.0.0.1 + MYSQL_PORT: "3306" + MYSQL_USER: root + MYSQL_PASSWORD: ci_root_pw_test_only + run: python3 -m pytest Services/findatahub-core/tests/integration -q + - name: 运行单元测试(kuaixun-service,部分用例可能依赖本机服务) # 该套件含需要 MySQL / Ollama 的用例,暂不阻塞 CI continue-on-error: true @@ -87,3 +138,69 @@ jobs: for f in Scripts/build-app.sh Scripts/bin/*.sh; do bash -n "$f" && echo "ok: $f" done + + # ── Windows 侧:跨平台抽象层回归 ────────────────────────────── + # + # 目的:验证 `Scripts/bin/paths.py` 与 `process_utils.py` 在 win32 上真的可用, + # 而不是"写完就算"。这两个模块已接线 4 个脚本,一旦 Windows 分支写错, + # 表现是采集器静默不启动或 PID 检测失效——本地 macOS 上完全看不出来。 + # + # 范围有意收窄:**不装 akshare**。它传递依赖 py_mini_racer(62MB V8 预编译二进制), + # Windows 上是否有 3.12 wheel 未验证,属已知硬阻塞点; + # 因此 Windows 侧只跑不依赖它的套件。tushare / akshare / backend 待后续单独验证。 + windows: + name: Windows 跨平台回归 + runs-on: windows-latest + # 观察期:首次接入,先不阻塞合并。 + # 转正条件:连续两次 CI 全绿后删掉这一行,改为阻塞。 + continue-on-error: true + env: + # Windows 控制台默认 cp936,中文用例名/日志会乱码甚至抛 UnicodeEncodeError。 + # 采集器 stdout 是 JSON 状态协议,一旦被编码污染,Swift 端会误判"未运行"。 + PYTHONUTF8: "1" + PYTHONIOENCODING: "utf-8" + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version-file: '.python-version' + + - name: 显示版本 + run: python --version + + - name: 版本一致性检查 + run: python Scripts/bin/check_python_version.py --strict + + - name: 语法编译检查 + run: >- + python -m compileall -q + Scripts/bin + Services/findatahub-core/src + Services/findatahub-client/src + + - name: 安装依赖 + # 显式列依赖而不装各服务的 requirements: + # 这里要验的是跨平台代码路径,不是完整运行环境。 + run: | + python -m pip install --quiet pytest pytest-asyncio + python -m pip install --quiet ./Services/findatahub-core + python -m pip install --quiet ./Services/findatahub-client + python -m pip install --quiet pymysql httpx pandas sqlalchemy + + - name: 跨平台抽象层测试(本次 Windows 接入的核心) + # 32 条用例锁定:paths 的 Windows 分支、process_utils 的 + # OpenProcess / taskkill / creationflags、UTF-8 环境构造 + run: python -m pytest Scripts/bin/tests/test_paths_process_utils.py -v + + - name: 脚本层测试 + # 含 PidManager、DB 池等;这批用例此前只在 POSIX 上跑过, + # Windows 上首次运行,暴露的问题正是需要修的 + run: python -m pytest Scripts/bin/tests -q + + - name: 数据层测试 + # 排除 integration:Windows job 未接 MySQL service,跑它只会得到一片 skip + run: python -m pytest Services/findatahub-core/tests -q --ignore=Services/findatahub-core/tests/integration + + - name: SDK 测试 + run: python -m pytest Services/findatahub-client/tests -q