内核测试一切协议 (KTAP),版本 1

TAP,即测试一切协议,是一种用于指定多个项目使用的测试结果的格式。它的网站和规范可以在此链接找到。Linux 内核主要使用 TAP 输出作为测试结果。然而,内核测试框架对测试结果有特殊需求,这些需求与原始 TAP 规范不一致。因此,指定了“内核 TAP”(KTAP)格式来扩展和更改 TAP,以支持这些用例。本规范描述了内核中当前普遍接受的 KTAP 格式。

KTAP 测试结果描述了一系列测试(可能是嵌套的:即,测试可以有子测试),每个测试都可以包含诊断数据(例如,日志行)和最终结果。测试结构和结果是机器可读的,而诊断数据是非结构化的,用于帮助人工调试。

KTAP 输出由四种不同类型的行组成:- 版本行 - 计划行 - 测试用例结果行 - 诊断行

一般来说,有效的 KTAP 输出也应该形成有效的 TAP 输出,但一些信息,特别是嵌套测试结果,可能会丢失。另请注意,有一个关于 TAP14 的停滞草案规范,KTAP 在几个地方(特别是“子测试”标头)偏离了该规范,这将在本文档的后面进行相关描述。

版本行

所有 KTAP 格式的结果都以“版本行”开头,该行指定结果符合哪个版本的 (K)TAP 标准。

例如:- “KTAP version 1” - “TAP version 13” - “TAP version 14”

请注意,在 KTAP 中,子测试也以版本行开头,表示嵌套测试结果的开始。这与 TAP14 不同,TAP14 使用单独的“子测试”行。

虽然在未来,符合要求的测试应使用“KTAP version 1”,但预计大多数解析器和其他工具将接受此处列出的其他版本,以兼容现有的测试和框架。

计划行

测试计划提供了 KTAP 输出中测试(或子测试)的数量。

计划行必须遵循“1..N”的格式,其中 N 是测试或子测试的数量。计划行跟随版本行,以指示嵌套测试的数量。

虽然在某些情况下,测试的数量是预先未知的(在这种情况下,可以省略测试计划),但强烈建议在可能的情况下存在一个测试计划。

测试用例结果行

测试用例结果行指示测试的最终状态。它们是必需的,并且必须具有以下格式

<result> <number> [<description>][ # [<directive>] [<diagnostic data>]]

结果可以是“ok”(表示测试用例通过),也可以是“not ok”(表示测试用例失败)。

<number>表示正在执行的测试的编号。第一个测试必须具有数字 1,并且在同一嵌套级别中,每个额外的子测试的编号必须增加 1。

描述是对测试的描述,通常是测试的名称,可以是除 # 或换行符之外的任何字符串。描述是可选的,但建议使用。

指令和任何诊断数据都是可选的。如果它们存在,则必须跟随一个井号“#”。

指令是一个关键字,它指示测试的不同结果,而不是通过和失败。指令是可选的,由诊断数据前面的单个关键字组成。如果解析器遇到它不支持的指令,则应回退到“ok”/“not ok”结果。

目前接受的指令有

  • “SKIP”,表示已跳过测试(请注意,如果使用 SKIP 指令,测试用例结果行的结果可以是“ok”或“not ok”)。

  • “TODO”,表示目前不希望测试通过,例如,因为它正在测试的功能已知已损坏。虽然此指令是从 TAP 继承的,但不建议在内核中使用。

  • “XFAIL”,表示预期测试会失败。这与上面的“TODO”类似,并且被某些 kselftest 测试使用。

  • “TIMEOUT”,表示测试已超时(请注意,如果使用 TIMEOUT 指令,测试用例结果行的结果应为“not ok”)。

  • “ERROR”,表示由于诊断数据中包含的特定错误,测试的执行失败。(请注意,如果使用 ERROR 指令,测试用例结果行的结果应为“not ok”)。

诊断数据是一个纯文本字段,其中包含有关产生此结果原因的任何其他详细信息。这通常是 ERROR 或失败测试的错误消息,或 SKIP 结果的缺少依赖项的描述。

诊断数据字段是可选的,并且没有指令或任何诊断数据的结果不需要包含“#”字段分隔符。

结果行示例包括

ok 1 test_case_name

测试“test_case_name”通过。

not ok 1 test_case_name

测试“test_case_name”失败。

ok 1 test # SKIP necessary dependency unavailable

测试“test”被跳过,诊断消息为“必要的依赖项不可用”。

not ok 1 test # TIMEOUT 30 seconds

测试“test”超时,诊断数据为“30 秒”。

ok 5 check return code # rcode=0

测试“检查返回码”通过,附加诊断数据为“rcode=0”。

诊断行

如果测试希望输出任何其他信息,则应使用“诊断行”进行输出。诊断行是可选的、自由格式的文本,通常用于比最终结果和诊断数据行更详细地描述正在测试的内容和任何中间结果。

诊断行的格式为“# <diagnostic_description>”,其中描述可以是任何字符串。诊断行可以位于测试输出中的任何位置。作为规则,关于测试的诊断行直接位于该测试的测试结果行之前。

请注意,大多数工具会将未知行(请参阅下文)视为诊断行,即使它们不是以“#”开头:这是为了捕获任何其他有用的内核输出,这可能有助于调试测试。尽管如此,建议测试始终在其任何诊断输出前面加上“#”字符。

未知行

KTAP 输出中可能存在不遵循上述四种行格式之一的行。这是允许的,但是,它们不会影响测试的状态。

这是与 TAP 的一个重要区别。内核测试可能会将消息打印到系统控制台或日志文件。这两个目标都可能包含来自不相关的内核或用户空间活动的消息,或者来自测试调用的非测试代码的内核消息。测试调用的内核代码可能不知道正在进行测试,因此无法将消息打印为诊断消息。

嵌套测试

在 KTAP 中,测试可以嵌套。这是通过使测试在其输出中包含一整套 KTAP 格式的结果来完成的。这可用于对相关测试进行分类和分组,或从同一测试中分离出不同的结果。

“父”测试的结果应由其所有子测试的结果组成,从另一个 KTAP 版本行和测试计划开始,并以总体结果结束。例如,如果其中一个子测试失败,则父测试也应失败。

此外,子测试中的所有行都应缩进。一级的缩进是两个空格:“ ”。缩进应从版本行开始,并应在父测试的结果行之前结束。

“未知行”不被认为是子测试中的行,因此允许缩进或不缩进。

具有两个嵌套子测试的测试示例

KTAP version 1
1..1
  KTAP version 1
  1..2
  ok 1 test_1
  not ok 2 test_2
# example failed
not ok 1 example

具有多级嵌套测试的示例格式

KTAP version 1
1..2
  KTAP version 1
  1..2
    KTAP version 1
    1..2
    not ok 1 test_1
    ok 2 test_2
  not ok 1 test_3
  ok 2 test_4 # SKIP
not ok 1 example_test_1
ok 2 example_test_2

TAP 和 KTAP 之间的主要差异

功能

TAP

KTAP

诊断消息中的 yaml 和 json

可以

不建议

TODO 指令

可以

无法识别

允许嵌套任意数量的测试

“未知行”属于“其他任何内容”类别

“未知行”是

不正确

允许

TAP14 规范确实允许嵌套测试,但它不是使用另一个嵌套版本行,而是使用“Subtest: <name>”形式的行,其中 <name> 是父测试的名称。

KTAP 输出示例

KTAP version 1
1..1
  KTAP version 1
  1..3
    KTAP version 1
    1..1
    # test_1: initializing test_1
    ok 1 test_1
  ok 1 example_test_1
    KTAP version 1
    1..2
    ok 1 test_1 # SKIP test_1 skipped
    ok 2 test_2
  ok 2 example_test_2
    KTAP version 1
    1..3
    ok 1 test_1
    # test_2: FAIL
    not ok 2 test_2
    ok 3 test_3 # SKIP test_3 skipped
  not ok 3 example_test_3
not ok 1 main_test

此输出定义以下层次结构

一个名为“main_test”的测试失败,并且有三个子测试:- “example_test_1”通过,并且有一个子测试

  • “test_1” 通过测试,并输出诊断信息 “test_1: initializing test_1”

  • “example_test_2” 通过测试,并且有两个子测试

    • “test_1” 被跳过,原因是 “test_1 skipped”

    • “test_2” 通过测试

  • “example_test_3” 测试失败,并且有三个子测试

    • “test_1” 通过测试

    • “test_2” 输出诊断信息 “test_2: FAIL”,并测试失败。

    • “test_3” 被跳过,原因是 “test_3 skipped”

请注意,名称相同的子测试之间不会冲突,因为它们存在于不同的父测试中。此输出还展示了一些用于“冒泡”测试结果的合理规则:如果任何子测试失败,则父测试也会失败。跳过的测试不会影响父测试的结果(尽管如果_所有_子测试都被跳过,则通常将测试标记为跳过是有道理的)。

另请参阅: