ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenSSL 测试开发指南:为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序

OpenSSL 测试开发指南:为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序 OpenSSL 测试开发指南为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序【免费下载链接】opensslGeneral purpose TLS and crypto library项目地址: https://gitcode.com/GitHub_Trending/ope/openssl本文以 OpenSSL 仓库 test/README-dev.md 为核心系统讲解如何为 OpenSSL 编写新的测试从测试脚本recipe的命名规范、编号分组到OpenSSL::Test::Simple与OpenSSL::Test两种 Perl 模块的使用再到test/build.info的构建接入和基于testutil.h的 C 测试骨架。读完本文你将掌握向 OpenSSL 测试体系贡献一个新的、可被make test自动发现与运行的测试的完整流程。测试体系全景recipe 与 C 可执行程序OpenSSL 的测试体系由两层组成测试脚本recipe位于test/recipes/文件名为{nn}-test_{name}.t用 Perl 编写是make test驱动的最小执行单元。它决定测试如何被调用、传什么参数、如何组织 TAP 输出。测试可执行程序位于test/目录下命名为{name}test.c编译而成的二进制如bntest、sanitytest承载实际断言逻辑通常基于 testutil.h 的测试框架实现。两者通过 recipe 中的一行调用关联起来。例如 test/recipes/01-test_sanity.t 与 test/recipes/02-test_lhash.t 都只有寥寥几行#! /usr/bin/env perl use OpenSSL::Test::Simple; simple_test(test_sanity, sanitytest);make test运行完毕后测试结果以 TAPTest Anything Protocol格式汇总输出这正是 Perl 的Test::Harness/TAP::Harness生态所使用的标准格式详见 test/README.md。如何新增一个测试 recipe对于任何你想执行的测试在test/recipes/下编写一个脚本即可命名规则为{nn}-test_{name}.t{nn}两位数编号用于分组{name}你自选的唯一测试名。需要注意如果测试涉及新的测试可执行程序你还需要修改test/build.info详见下文 Changes to test/build.info 一节把可执行程序的构建信息注册进去recipe 才能找到并运行它。命名约定构件命名规则示例测试可执行程序test/{name}test.ctest/bntest.c测试 recipetest/recipes/{nn}-test_{name}.ttest/recipes/10-test_bn.t其中{nn}是一个松散意义上的功能分组OpenSSL 官方给出如下分组建议编号段覆盖内容00-04sanity、内部与核心 API 测试05-09单个对称密码算法10-14数学大数 bignum15-19单个非对称密码算法20-24openssl 命令其余尚未覆盖的25-29证书格式、生成与验证30-35evp60-79API 类其中60为 X509 子系统、61为 BIO 子系统、65为 CMP 子系统、70为 PACKET 层80-89较大协议CA、CMS、OCSP、SSL、TSA90-98杂项99最耗时的测试如 test_fuzz编号是松散分组的实际仓库中可见 02-、03-、04- 开头的内部测试大量并存且make test TESTS[89]? -90这类通配用法正依赖该编号体系参见 test/README.md 的 Running Selected Tests 一节。从源码结构看test/recipes/下同时存在02-test_internal_bn.t、02-test_lhash.t等内部测试说明同段编号内还会按主题细分。最简单的 recipe仅运行一个测试可执行程序如果一个 recipe 只是直接运行某个测试程序使用OpenSSL::Test::Simple模块即可完整脚本为#! /usr/bin/env perl use OpenSSL::Test::Simple; simple_test(test_{name}, {name}test, {name});第一个参数test_{name}是测试在 TAP 输出中显示的名字第二个参数{name}test是测试可执行程序名simple_test约定它位于test/目录下第三个参数{name}是传给可执行程序的可选参数多数情况可省略如01-test_sanity.t就是两参数形式。关于OpenSSL::Test::Simple的完整文档可执行perldoc util/perl/OpenSSL/Test/Simple.pm复杂 recipe使用 OpenSSL::Test 与 Test::More对于需要准备数据、校验退出码、解析输出的复杂测试需要了解两个 Perl 模块Test::MorePerl 标准测试模块通常随 Perl 预装文档执行man Test::MoreOpenSSL::TestOpenSSL 自有的测试工具集文档执行perldoc util/perl/OpenSSL/Test.pm。一个可直接起步的骨架脚本#! /usr/bin/env perl use strict; use warnings; use OpenSSL::Test; setup(test_{name}); plan tests 2; # 本次执行的测试数量 ok(test1, test1); ok(test2, test1); sub test1 { # 测试特性 1 } sub test2 { # 测试特性 2 }要点说明setup(test_{name})必须在任何断言之前调用它负责初始化 OpenSSL 测试环境定位构建目录、设置相关环境变量等plan tests 2声明本脚本共执行 2 个测试声明数量与实际断言数不一致时 TAP 运行器会报告计划不符每个sub内可借助OpenSSL::Test提供的run()、app()、cmdstr()等辅助函数执行openssl命令或测试程序并校验其输出。值得强调的是测试基础设施会自动设置所有必需的环境变量如OPENSSL_MODULES、OPENSSL_CONF等单个测试可按需覆盖默认设置——这意味着测试脚本通常无需手工 export 这些变量直接运行即可拿到正确的 provider 模块路径与配置。修改 test/build.info 接入新可执行程序每当新测试涉及一个新的测试可执行程序时必须在 test/build.info 中做如下修改以下{NAME}与{name}一律替换为你的测试名把{name}加入PROGRAMS_NO_INST列表该列表中的程序只构建、不安装是测试专用程序的统一归宿。仓库中该列表包含sanitytest、bntest、evp_test、sslapitest、quicapitest等上百个程序并常按功能用IF[...]条件包裹如仅当!$disabled{quic}时加入 QUIC 测试仅当!$disabled{ml-dsa}时加入ml_dsa_test。编写三行构建描述若不用基础测试框架需自行调整 include 路径与源文件SOURCE[{name}]{name}.c INCLUDE[{name}].. ../include ../apps/include DEPEND[{name}]../libcrypto libtestutil.aSOURCE该程序的源文件INCLUDE头文件搜索路径基础测试框架通常需要test/本身..即仓库根目录的相对引用写法实际指代上层、公共头文件../include以及../apps/includeDEPEND链接依赖。绝大多数测试链接../libcrypto与libtestutil.a涉及 TLS 的测试还会加上../libssl例如 test/build.info 中DEPEND[sslapitest]../libcrypto.a ../libssl.a libtestutil.a。从 test/build.info 的完整内容可以看出两类常见差异内部测试需要访问共享库未导出的内部符号时如asn1_internal_test、bn_internal_test等会强制静态链接../libcrypto.a文件注释明确说明these programs are forcibly linked with the static libraries, where all symbols are always available依赖 helper 的测试SSL 类测试常额外引入helpers/ssltestlib.c例如SOURCE[dtlstest]dtlstest.c helpers/ssltestlib.c。libtestutil.a本身也在 test/build.info 中定义其源文件集合包括testutil/main.c、testutil/driver.c、testutil/tests.c、testutil/format_output.c、testutil/options.c、testutil/provider.c、testutil/fake_random.c以及mfail/mfail.c等并依赖../libcrypto——这是所有基于testutil.h的测试共享的公共设施。C 测试可执行程序的通用骨架基于testutil.h的 C 测试程序有一个标准形态源文件放在test/下命名为{name}test.c#include testutil.h static int my_test(void) { int testresult 0; /* 假定测试将失败 */ int observed; observed function(); /* 调用被测代码 */ if (!TEST_int_eq(observed, 2)) /* 检查结果是否正确 */ goto end; /* 失败则退出可选*/ testresult 1; /* 标记该用例成功 */ end: cleanup(); /* 需要的清理工作 */ return testresult; } int setup_tests(void) { ADD_TEST(my_test); /* 逐个添加测试用例 */ return 1; /* 1 表示成功返回 0 */ /* 产生带用法说明的 */ /* 错误返回 -1 表示 */ /* 设置失败且无用法 */ /* 说明 */ }两个关键约定每个测试用例函数返回1表示成功、0表示失败setup_tests()通过ADD_TEST()或参数化版本ADD_ALL_TESTS注册用例注册失败返回0设置彻底失败返回-1不输出用法说明。在 testutil.h 中可以看到更完整的注册宏家族ADD_TEST(test_function)注册单个用例ADD_ALL_TESTS(test_function, num)参数化用例对每个0 idx num调用test_function(idx)ADD_ALL_TESTS_NOSUBTEST不带 TAP 子测试输出的参数化变体需要清理的测试可实现void cleanup_tests(void)即使setup_tests()失败也会被调用需要早期初始化的可实现int global_init(void)。此外 testutil.h 还提供了 fixture 模式的宏SETUP_TEST_FIXTURE(TEST_FIXTURE_TYPE, set_up)与EXECUTE_TEST(execute_func, tear_down)适用于共享相同 setup/teardown 逻辑的一组用例以及按 FIPS provider 版本做条件断言的fips_provider_version_*系列函数。TEST_xxx 断言宏用统一格式表达失败testutil.h提供的TEST_xxx宏家族是断言的全部入口它们满足三个特性失败时输出标准格式的错误信息通过条件满足时无输出——信息包含文件、行号与表达式原文保证每个参数只被求值一次因此允许带副作用的表达式直接作为参数例如if (!TEST_ptr(ptr OPENSSL_malloc(..)))完全可以替代ptr OPENSSL_malloc(..); if (!TEST_ptr(ptr))前者的失败信息直接打印ptr OPENSSL_malloc(..)及其求值结果远比后者更有诊断价值。覆盖全类型比较从 testutil.h 可见宏家族按类型展开为eq/ne/lt/le/gt/ge六种比较覆盖int、unsigned int、char、unsigned char、long、unsigned long、int64_t、uint64_t、double、time_t、size_t以及指针TEST_ptr/TEST_ptr_null、字符串TEST_str_eq/TEST_str_ne/TEST_strn_eq、内存块TEST_mem_eq/TEST_mem_ne、布尔TEST_true/TEST_false、错误栈TEST_err_r/TEST_err_s和 BIGNUMTEST_BN_*含TEST_BN_eq_zero、TEST_BN_odd、TEST_BN_eq_word等。辅助输出宏TEST_info(fmt, ...)携带printf格式串与参数用于输出附加信息TEST_error(fmt, ...)同样是printf风格适合复杂条件的失败说明另有TEST_skip跳过测试并给出原因、test_openssl_errors()倾倒 OpenSSL 错误栈等调试利器。底层实现位于 testutil.h 声明的test_*函数与 testutil/format_output.c 等源文件宏到函数的映射全部经由__FILE__与__LINE__注入确保诊断信息自带定位。从 recipe 到make test整体衔接新增测试的完整链路为编写test/{name}test.c基于 testutil.h 实现setup_tests()与各my_test用例在 test/build.info 中把{name}加入PROGRAMS_NO_INST并补上SOURCE/INCLUDE/DEPEND三行编写test/recipes/{nn}-test_{name}.t用OpenSSL::Test::Simple或OpenSSL::Test驱动可执行程序运行make test TESTStest_{name}验证或make list-tests查看其是否被正确发现。运行与调试手段详见 test/README.md可用make V1 test查看全部输出、make test VF1只看失败用例用TESTS变量做通配与排除如make TESTS-test_fuzz* test或按编号组make TESTS10 test并可用HARNESS_JOBS4并行加速。测试涉及随机数时可用OPENSSL_TEST_RAND_SEED/OPENSSL_TEST_RAND_ORDER复现失败希望穷举内存分配失败路径时可借助ADD_MFAIL_TEST系宏与OPENSSL_TEST_MFAIL_*环境变量做分配失败注入调试详见 test/README.md 的 Memory Allocation Failure Tests 一节。编写测试时请始终遵守一个前提测试必须在非特权账户下运行test/README.md 明确警告或在你平台允许时临时禁用特权这也是 OpenSSL 测试套件一贯的安全边界要求。【免费下载链接】opensslGeneral purpose TLS and crypto library项目地址: https://gitcode.com/GitHub_Trending/ope/openssl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表