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