内核测试一切协议 (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 不同,后者使用单独的“子测试”行。

虽然,展望未来,符合要求的测试应该使用“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 seconds”。

ok 5 check return code # rcode=0

测试“check return code”通过,附加诊断数据为“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”

请注意,具有相同名称的单个子测试不会冲突,因为它们位于不同的父测试中。此输出还展示了一些用于“冒泡”测试结果的明智规则:如果任何子测试失败,则测试失败。跳过的测试不影响父测试的结果(尽管如果_所有_子测试都已跳过,则将测试标记为跳过通常是有意义的)。

参见: