news 2026/10/1 9:48:20

Dolt 跨版本兼容性测试体系:向前、向后与双向兼容的 BATS 验证方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dolt 跨版本兼容性测试体系:向前、向后与双向兼容的 BATS 验证方案
  • 数据库
  • 关系型数据库
  • 后端
  • CLI

【免费下载链接】dolt

Dolt – Git for Data

项目地址:https://gitcode.com/GitHub_Trending/do/dolt
点击查看免费下载

Dolt 是一款"Git for Data"数据库,其仓库格式、schema 编码与存储布局会随版本演进持续变化,因此版本间能否安全读写彼此的数据,直接决定了用户升级与多版本混部(例如滚动升级、跨版本协作)的可行性。本文以仓库中的 Compatibility Tests 文档 为主体,结合 runner.sh、setup_repo.sh 及整套 BATS 测试用例,完整讲解 Dolt 是如何通过向后兼容、向前兼容与双向兼容三组测试,系统性守护跨版本数据可读性的。读完本文,你将掌握这套测试的目录结构、运行流程、关键环境变量,以及每个测试文件所验证的具体兼容性维度。

一、兼容性测试的整体目标:三层验证矩阵

根据 README 的说明,这套测试试图保证 Dolt 各版本之间的前向与后向兼容性,整体上分为三个层次:

  1. 向后兼容(Backward Compatibility):仓库由旧版本 Dolt 创建并写入数据,由当前 HEAD 构建的 Dolt 客户端读取、修改。这保证"升级到新版本后,旧数据仍然可读、可写"。
  2. 向前兼容(Forward Compatibility):仓库由 HEAD 构建的 Dolt 创建并写入数据,由旧版本 Dolt 客户端读取。这保证"旧客户端在数据被新版本写入后仍能正常使用"。
  3. 双向兼容(Bidirectional Compatibility):旧版本与当前版本在同一个仓库上交替执行读写操作,验证"两个版本可以在同一份数据库上协作而不互相破坏"。由于向前兼容在任何时候都是限制性更强的一方(同时满足向前兼容的版本更少),双向测试只针对向前兼容版本列表进行。

这一设计的核心判断是:向前兼容是更严苛的约束。当一个新版本引入新的存储字段(如自适应编码、降序索引)后,旧客户端如果无法解析这些字段,就会拒绝读写,此时向前兼容就被打破,双向协作自然也无法成立。

二、测试套件的目录结构与文件角色

整套测试位于 integration-tests/compatibility 目录下,职责划分非常清晰:

integration-tests/compatibility/ ├── README.md # 测试设计说明(本文主体) ├── runner.sh # 总调度脚本:下载旧版本、建仓、跑 BATS └── test_files/ ├── setup_repo.sh # 用指定版本 dolt 构建"标准测试仓库" ├── setup_repo_2_0_breaking.sh # 用 HEAD + 自适应编码构建 2.0 破坏性测试仓库 ├── setup_repo_desc_index.sh # 用 HEAD 构建含降序索引的测试仓库 ├── big_table.sql # 向 big 表写入 1000 行数据的 SQL ├── backward_compatible_versions.txt # 向后兼容测试的版本清单 ├── forward_compatible_versions.txt # 向前兼容测试的版本清单 ├── 2_0_breaking_versions.txt # 2.0 破坏性变更测试的版本清单 ├── 2_0_forward_compatible_versions.txt # 降序索引 + 双向测试的版本清单 └── bats/ ├── compatibility.bats # 主兼容性用例(版本/状态/schema/diff/merge) ├── types_compatibility.bats # 全类型读写与加列用例 ├── geom_types_compatibility.bats # 空间类型兼容用例 ├── 2_0_breaking/ # 自适应编码破坏性用例 ├── desc_index_breaking/ # 降序索引破坏性用例 ├── bidirectional/ # 双向兼容用例(含 SQL server 跨版本) ├── bidirectional_remote/ # 经 file remote 的双向协作用例 └── helper/ # compat-common.bash / compat-server.bash

其中三个版本清单文件是测试矩阵的"输入数据":

  • backward_compatible_versions.txt 当前列出的版本为:v2.0.0, v1.86.6, v1.86.5, v1.80.0, v1.75.0, v1.59.3, v1.44.2, v1.20.0, v1.7.0, v1.2.0, v1.0.0,覆盖从 v1.0.0 到 v2.0.0 的长跨度。
  • forward_compatible_versions.txt 当前列为:v1.80.0, v1.75.0, v1.59.0。
  • 2_0_breaking_versions.txt 当前列为:v1.87.0, v1.84.0;2_0_forward_compatible_versions.txt 当前列为v2.0.0。

清单文件中的空行与#注释行会被 runner.sh 中的grep -v '^ *#'过滤掉,因此可以随时注释掉某个版本以临时排除它。

三、向后兼容测试:旧版本建库,HEAD 客户端读写

3.1 下载并识别旧版本二进制

runner.sh 首先通过get_platform_tuple探测运行平台:仅支持 Linux 与 macOS,并根据uname -m将架构映射为amd64、arm64或386(见 runner.sh)。随后download_release会为指定版本创建binaries/<ver>目录,下载名为dolt-<platform>.tar.gz的发布压缩包并解压(见 runner.sh)。

3.2 用旧版本构建标准测试仓库

核心步骤是setup_repo:将 PATH 临时指向旧版本二进制目录,然后执行 setup_repo.sh 在repos/<ver>下创建仓库(见 runner.sh)。该脚本是这个测试体系"数据样板"的关键,它会:

  1. dolt init初始化仓库,并自动探测默认分支名(main或master),把结果写入default_branch.var供后续使用;
  2. 创建多个分支:no-data、init、other、check_merge,分别模拟不同数据状态的仓库;
  3. 建立覆盖几乎所有 MySQL 类型的数据表:
    • abc(BIGINT 主键 + LONGTEXT/DOUBLE/BIGINT 列,作为 DML 与 DDL 演练对象);
    • big(通过 big_table.sql 灌入 1000 行,用于验证大表读写与 diff);
    • def(含CHECK (i > 0)约束,用于验证约束检查与合并);
    • all_types(TINYINT/SMALLINT/MEDIUMINT/INT/BIGINT/BIGINT UNSIGNED/FLOAT/DOUBLE/DECIMAL/CHAR/VARCHAR/TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT/VARBINARY/TINYBLOB/BLOB/MEDIUMBLOB/LONGBLOB/DATE/TIME/DATETIME/TIMESTAMP/YEAR/JSON/ENUM/SET 共 28 种列,正负值、超大值(如9223372036854775807、18446744073709551615、500 字节重复字符串)全覆盖;
    • geom_types(POINT/LINESTRING/POLYGON/GEOMETRY/MULTIPOINT/MULTILINESTRING/MULTIPOLYGON/GEOMETRYCOLLECTION,通过ST_GeomFromText写入);
    • 视图view1、all_types_view、geom_view,验证视图在版本间的序列化兼容;
  4. 在不同分支上执行差异化 DDL/DML:other分支对abc执行DROP COLUMN x; ADD COLUMN z,默认分支执行DROP COLUMN w; ADD COLUMN y,从而为后续dolt diff other测试构造真实的 schema 分叉;
  5. 最后导出abc.csv与abc_schema.json(用于dolt table import测试),并输出dolt status、dolt branch、dolt schema show、查询结果与dolt_schemas快照作为日志参考。

可见这套"标准仓库"刻意覆盖了类型系统、视图、约束、分支分叉与导出导入等最易受格式演进影响的环节,是向后兼容测试的"压力样品"。

3.3 以 HEAD 客户端跑 BATS 用例

仓库构建完成后,runner 用当前 HEAD 的 dolt 作为客户端,针对该仓库执行整批 BATS 测试(见 runner.sh)。测试通过环境变量传递上下文:

  • DOLT_OLD_BIN:旧版本 dolt 二进制路径;
  • DOLT_NEW_BIN:HEAD 构建的 dolt 路径(在 PATH 被修改前用which dolt捕获);
  • REPO_DIR:被测仓库目录(每个用例的setup()会先cp -Rpf $REPO_DIR bats_repo复制一份隔离副本);
  • DOLT_VERSION:当前被测的旧版本号,供用例做版本判断;
  • DEFAULT_BRANCH:仓库的默认分支名。

compatibility.bats 是这批用例的主体,覆盖:dolt version/status/ls/branch/diff基础命令;在init、默认分支、other分支上执行dolt schema show abc并逐一断言列定义(如pk bigint not null、a longtext、w bigint/y bigint等);对三个分支执行select * from abc并断言结果集表格布局;dolt diff other断言 schema 与数据两部分的精确 diff 输出;对big表执行 count、delete、insert 与 commit;dolt merge other断言"预期冲突"(Merge conflict in abc/Automatic merge failed);dolt table import -c -pk=pk abc2 abc.csv验证旧版本导出的 CSV 可被新客户端导入;dolt merge check_merge验证带 CHECK 约束的合并;以及构造唯一索引冲突后查询dolt_constraint_violations_cv_test系统表并清理的约束违规用例。

同批执行的 types_compatibility.bats 与 geom_types_compatibility.bats 则分别验证:旧版本写入的每种类型都能被 HEAD 正确读取(整数边界值、负数、500 字节大 TEXT/BLOB、ST_X/ST_AsText等空间函数);对旧表执行 INSERT/UPDATE/DELETE 与ALTER TABLE ADD COLUMN(逐类型新增列后再读写);以及旧版本创建的视图能被正确反序列化并查询。这些用例还大量使用assert_no_panic_shape辅助函数(见 compat-common.bash),专门拦截输出中泄漏的invalid hash length、panic recovered、runtime error等"panic 形状",确保兼容性问题以干净的报错而非崩溃暴露。

四、向前兼容测试:HEAD 建库,旧版本客户端读写

向前兼容测试的思路与向后相反:先用 HEAD 构建仓库(runner 的_main会先setup_repo HEAD),再让清单中的旧版本客户端去读写它。由于旧版本可能无法理解 HEAD 仓库存储中的某些引用形态,runner 在 test_forward_compatibility 中做了一个关键预处理:

  1. 在repos/HEAD/file-remote创建file remote(dolt remote add file-remote file://file-remote),并把$DEFAULT_BRANCH、init、no-data、other、check_merge等分支全部 push 上去。注释说明这样做是为了"裁剪掉存储中某些旧版本不兼容的引用(refs)";
  2. 旧版本 dolt 从该 remoteclone出repos/<ver>仓库,并用旧版本依次创建各本地分支(dolt branch no-data origin/no-data等);
  3. 把 HEAD 仓库导出的*.csv、*.json拷贝进旧版本仓库,保证导入类用例可用;
  4. 最后以旧版本为客户端(DOLT_OLD_BIN)跑同一批 BATS 用例,验证旧客户端能够读取、diff、merge HEAD 写入的数据。

整个 clone/setup 过程刻意使用"被测版本"的二进制执行(PATH="$relpath" dolt clone ...),并打印dolt version确认。该流程说明:向前兼容的验证不仅限于读取,还包括旧客户端能否独立完成 clone、建分支、导入导出等完整操作链。

五、双向兼容测试:新老版本交替读写同一仓库

双向兼容是这套体系中最"贴近真实混部场景"的部分。它不做setup_repo.sh的共享初始化,而是由测试自己建仓、自己组织数据。runner 对同一版本会跑两次,方向互换:第一次DOLT_OLD_BIN为旧版本、DOLT_NEW_BIN为 HEAD,第二次交换两者,从而把"谁先写、谁后写"的两个方向都覆盖到(见 runner.sh)。

5.1 同仓交替写入(bidirectional)

bidirectional_compat.bats 以"多轮交替"模式展开:每轮由一个版本写入、另一个版本验证,通常进行 4~6 轮,覆盖:

  • 标量类型 DML 往返:INT/VARCHAR/DECIMAL/DATETIME 的 insert/update/delete 跨版本可见;
  • 大 TEXT/BLOB 往返:用REPEAT生成 1000~5000 字节值,验证 out-of-band(带外存储)大值由一方写入后,另一方能用LENGTH()完整读回;测试注释明确给出了自适应编码的阈值语义——TINYTEXT/TEXT恒为 inline,MEDIUMTEXT/LONGTEXT超过 64KB 阈值时转入 out-of-band;
  • 空间类型往返:POINT/LINESTRING/POLYGON/GEOMETRY 经ST_GeomFromText写入、ST_X/ST_AsText读回;
  • 双方交替 ADD COLUMN:HEAD 加 TEXT/DATE 列、旧版本加 INT/DECIMAL 列、HEAD 再加 POINT 列,最终旧版本用包含全部新列(含空间列)的行插入,HEAD 读回;
  • 跨版本分支与合并:HEAD 建特性分支提交,旧版本建自己的分支并执行 merge;HEAD 再做 DDL 变更合并,旧版本读取新列并写入;
  • 综合类型覆盖:TINYINT/BIGINT/FLOAT/DOUBLE、VARCHAR/CHAR/VARBINARY、DATE/DATETIME/DECIMAL、ENUM/SET 逐轮由两个版本交替加列;
  • TEXT/BLOB 家族:TINYTEXT~LONGTEXT 与 TINYBLOB~LONGBLOB 的 inline↔out-of-band 双向升降级(例如把 70000 字节值写进原本小的列,或把大值改回小值),验证"编码形态变化"也能被对端正确解析;
  • JSON:含 inline 与 out-of-band 两列组合,用JSON_EXTRACT/JSON_UNQUOTE校验(当前该用例被skip,注释说明新 JSON 编码与旧版本不兼容)。

每个测试都调用clear_branch_control删除.doltcfg/branch_control.db:因为分支控制序列化存在一次前向不兼容变更,现代客户端写入后旧客户端读取会 panic,删除该文件可避免此噪声掩盖其他真实问题(见 bidirectional_compat.bats)。

5.2 SQL server 与 CLI 客户端跨版本(server_cli_compat)

server_cli_compat.bats 将兼容性验证从"文件仓库"扩展到"网络协议"层面:旧版本dolt sql-server作为服务端,HEAD 的 CLI 作为客户端通过--host/--port/--user/--password --use-db全局连接参数连接。其中 compat-server.bash 提供了服务生命周期管理:start_old_sql_server用随机端口启动旧版 server(wait_for_old_server轮询直至可连接),new_dolt_cli封装客户端连接参数,latest_commit只用旧 server 也支持的dolt_log列做查询。用例覆盖:SELECT 1连通性、通过dolt_log读取提交历史、客户端发起add/commit/revert、--author覆盖后在旧 server 侧查询dolt_log验证 committer、以及cherry-pick跨版本应用提交。测试还通过skip_if_old_lte/skip_if_new_lte(见 compat-common.bash)按版本号门槛跳过某些旧版本不具备的能力(例如1.20.0前客户端不支持全局连接参数、1.86.6前dolt_logschema 未固定),避免对"能力缺失"误判为"兼容性破坏"。

5.3 经共享 file remote 的双向协作(bidirectional_remote)

bidirectional_remote_compat.bats 模拟了更贴近生产的多机协作:两个版本通过共享的file://remote 同步。其核心run_workflow流程为:

  1. 版本 A(旧)建仓、建表、写基础行并 push 到 remote,然后不提交地ALTER TABLE tbl ADD COLUMN c_col <type>;
  2. 版本 B(新)从 remote clone,以同名同类型ADD COLUMN c_col,写入与 A 不相交的行并提交;
  3. 版本 A 用自己的c_col写入不相交行、提交并 push;
  4. 版本 Bdolt pull,断言合并成功,最终表同时包含两边的全部 6 行且c_col值正确。

该用例针对 INT、BIGINT、BIGINT UNSIGNED、FLOAT、DECIMAL、VARCHAR、TEXT、VARBINARY、BLOB、DATETIME、TIMESTAMP、ENUM、SET、POINT、LINESTRING、GEOMETRYCOLLECTION 等类型逐一验证(JSON 因编码变更被 skip)。它的特殊意义在于:两个版本独立地对同一表做了相同 schema 变更,再经 pull 合并,必须不冲突、不丢数据——这直接检验了 schema 与行存储格式在"分叉演进后合并"路径上的兼容性。

六、显式验证破坏性变更:自适应编码与降序索引

并非所有变更都能做到向前兼容。对于已知的破坏性变更,测试套件专门设计了"必须报错、且报错要友好"的断言模式。

6.1 2.0 自适应编码(adaptive encoding)

setup_repo_2_0_breaking.sh 用 HEAD(并启用自适应编码)构建包含 TEXT/BLOB 各类变体及混合类型表的仓库,随后 2_0_breaking.bats 断言:旧客户端(v1.87.0、v1.84.0)对含 TEXT/BLOB 的表执行SELECT、dolt diff、dolt schema show时必须失败且输出table has unknown fields;而对不含 TEXT/BLOB 的no_text_blob表仍可正常读取。runner 中对应注释说明了策略:"目前我们只测试它以恰当的报错信息失败"(见 runner.sh)——即破坏性变更被接受,但必须显式、可诊断地失败。

6.2 降序索引(descending index)

setup_repo_desc_index.sh 用 HEAD 构建一张含INDEX c_int_desc (c_int DESC, c_varchar)的表与一张默认升序索引的表。 desc_index_breaking.bats 断言:旧客户端对降序索引表(SELECT、schema show、dolt diff)报table has unknown fields,对默认升序索引表仍正常读写;HEAD 客户端两张表都能读(ORDER BY c_int DESC正确返回);并且 HEAD 修改默认索引表列类型后,旧客户端仍可读该表。其原理在用例注释中写明:降序列被写为索引 schema 消息的新字段,旧客户端遇到未知字段即拒绝;没有降序列的索引不写这些字段,因此不触发。

这两组"负向用例"与前面的正向用例共同构成完整矩阵:兼容性测试不仅要证明"能读",还要证明"不能读时给出明确错误"。

七、运行编排与辅助设施

7.1 runner 的主流程

runner.sh 的_main依次执行:

  1. 探测平台、导出BATS_LIB_PATH(依次指向本套件的test_files/bats/helper与主 BATS 套件的helper,使嵌套用例可bats_load_library)与DOLT_DEV_BUILD_PATH(指向新构建的 dolt,避免版本号字面匹配把 dev build 误跳过);
  2. 创建repos/binaries目录,注册 EXIT 清理钩子;
  3. 对backward_compatible_versions.txt每个版本跑向后兼容;
  4. setup_repo HEAD构建当前版本仓库;
  5. 对2_0_breaking_versions.txt跑自适应编码破坏性用例;
  6. 对2_0_forward_compatible_versions.txt跑降序索引用例;
  7. 对同一清单跑双向兼容(同仓)与双向 remote 兼容;
  8. 最后以 HEAD 对 HEAD 仓库跑一遍 BATS 作为自检基线(sanity check),确保测试体系本身在无跨版本场景下也是绿的。

7.2 关键环境变量速查

环境变量用途
DOLT_OLD_BIN旧版本 dolt 路径;未设置时回退到 PATH 上的dolt
DOLT_NEW_BIN新版本(HEAD)dolt 路径;未设置时回退到dolt
DOLT_LEGACY_BINremote 双向用例中"版本 A"的二进制
REPO_DIR被测仓库目录,用例 setup 阶段复制为bats_repo
DOLT_VERSION当前被测旧版本号,供用例按版本跳过
DEFAULT_BRANCH仓库默认分支名(main/master)
BATS_LIB_PATH帮助库加载路径
DOLT_DEV_BUILD_PATH新构建 dolt 的路径,豁免版本号字面比较

这些变量在 compat-common.bash 中被old_dolt/new_dolt两个函数封装使用;测试文件只调用old_dolt/new_dolt,从而对"哪个版本在跑"保持透明。

7.3 本地运行方式

运行前提:本机需具备 BATS 环境、可执行dolt(HEAD 构建)且能访问外网以下载历史版本二进制;支持 Linux 与 macOS(见get_platform_tuple的限定)。在integration-tests/compatibility目录下执行:

bash runner.sh

runner 会自动下载版本清单中的旧版本发布包、构建标准仓库并逐批执行 BATS(带--print-output-on-failure,失败时输出完整现场)。需要临时缩小范围时,可在对应的*_versions.txt中注释掉某些版本行(#开头的行会被忽略)。

八、从测试体系看 Dolt 的兼容性工程实践

从这套测试可以提炼出几条可迁移的工程经验:

  1. 用"数据样板"覆盖格式敏感面:setup_repo.sh刻意灌入全部 MySQL 类型、空间类型、视图、约束、大值与分支分叉,把易受编码演进影响的点全部固化为回归样本;
  2. 正反用例结合:既能读(向后/向前/双向)与必须报错(2.0 breaking/desc index)并行验证,让"破坏性变更"有明确的、可断言的失败契约;
  3. 把"方向"作为测试参数:双向测试对同一版本正反各跑一遍,且 remote 场景将"独立加列后合并"作为一等公民,覆盖了真实混部中最危险的路径;
  4. 版本能力与兼容性解耦:skip_if_old_lte/skip_if_new_lte按版本号门槛区分"旧版本没这个能力"与"跨版本不兼容",避免误报;
  5. panic 形状拦截:assert_no_panic_shape保证兼容性问题表现为干净的报错,而不是崩溃或内存误读——这对数据型数据库尤为重要。

无论你是 Dolt 的使用者(评估升级风险)、贡献者(判断改动是否破坏格式),还是其他数据系统的工程师(设计自己的跨版本兼容测试),这套位于 integration-tests/compatibility 的测试体系都是一份完整且可直接运行的参考实现。

  • 数据库
  • 关系型数据库
  • 后端
  • CLI

【免费下载链接】dolt

Dolt – Git for Data

项目地址:https://gitcode.com/GitHub_Trending/do/dolt
点击查看免费下载

相关推荐

上一篇:如何让Mac音频自由流转?揭秘Soundflower的系统级音频路由方案
下一篇:中文网页字体优化指南:PingFangSC苹果平方字体全面解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 9:45:44

Paint-Anything统一引导框架:基于FLUX.2-4B的多模态图像生成实战

1. 从标题到本质&#xff1a;Paint-Anything到底在解决什么问题第一次看到“Paint-Anything”这个名字&#xff0c;很多人会以为又是一个“输入一句话就出图”的文生图玩具。但把论文翻完、把代码跑通之后你会发现&#xff0c;它真正想啃的硬骨头&#xff0c;是任意形态的引导信…

作者头像 李华
网站建设 2026/10/1 9:44:58

滑块验证码全链路算法解析:MAC协议、UUID、轨迹与浏览器环境伪装

简介&#xff1a;Go语言实现的MAC协议UUID生成、滑块校验及滑块环境适配算法源码&#xff0c;面向网络协议开发者、安全测试工程师及验证码逆向分析人员。代码聚焦设备识别与交互行为校验两大场景&#xff0c;涵盖MAC地址格式转换与UUID唯一标识生成逻辑&#xff0c;并针对滑块…

作者头像 李华
网站建设 2026/10/1 9:43:48

AI模型完整体系与智能体编排层拆解:混合模型与四层架构实践

技术第5篇&#xff0c;AI模型完整体系与智能体编排层拆解模型不是越强越好&#xff0c;组合起来好用才是关键。这个观点是我过去大半年搭内部AI应用体系最深的一个体会。这个系列已经写到第五篇&#xff0c;前四篇讲的是单点能力&#xff0c;从模型部署、数据工程、推理优化到评…

作者头像 李华
网站建设 2026/10/1 9:42:18

游戏引擎架构导读:不是铺垫,是决策地基

1. 这不是教科书&#xff0c;是十年引擎老兵拆给你看的第一章“导读”到底在导什么“游戏引擎架构&#xff1a;第一章导读”——光看标题&#xff0c;很多人会下意识划走&#xff1a;又是一本厚得能当板砖使的理论书&#xff1f;讲架构不就是画几个框、连几条线、说几句“高内聚…

作者头像 李华