#devops #http-request #step #test-runner #yaml #regex #bash

bin+lib lorikeet

并行测试运行器用于 DevOps

28 个版本

0.14.0 2021年9月22日
0.12.1 2021年5月18日
0.12.0 2021年2月9日
0.11.3 2020年5月7日
0.1.0 2017年7月31日

#234测试 分类中

每月下载量:32
被用于 lorikeet-dash

MIT/Apache 协议

80KB
1.5K SLoC

Lorikeet

DevOps 的并行测试运行器。

概述

Lorikeet 是一个命令行工具和 Rust 库,用于运行烟测试和集成测试。Lorikeet 目前支持 bash 命令、简单的 HTTP 请求以及系统信息(内存、CPU)。

测试计划在 YAML 文件中定义,可以使用 tera 进行模板化。测试计划中的每个步骤可以有多个依赖项(在其他步骤之前运行某些步骤)并且可以对每个命令的输出有预期。

默认情况下,步骤并行运行,使用系统可用的线程数。如果步骤有依赖项,通过 requirerequired_by 属性,则它将等待这些步骤完成。

例如,以下是一个测试计划,用于检查 Reddit 是否运行,然后如果运行则尝试登录:

check_reddit:
  http: https://www.reddit.com
  regex: the front page of the internet

login_to_reddit:
  http: 
    url: https://www.reddit.com/api/login/{{user}}
    save_cookies: true
    form:
      user: {{user}}
      passwd: {{pass}}
      api_type: json
  jmespath: length(json.errors)
  matches: 0
  require:
    - check_reddit

( 顺便提一下,我们添加了 jmespath: length(json.errors) & matches: 0 因为无效的 Reddit 登录仍然返回 200 OK 状态 )

lorikeet 的输出

$ lorikeet -c config.yml test.yml
- name: check_reddit
  pass: true
  output: the front page of the internet
  duration: 1416.591ms

- name: login_to_reddit
  pass: true
  output: 0
  duration: 1089.0276ms

该名称来自 彩虹鹦鹉,一种非常色彩鲜艳的澳大利亚鸟类。就像煤矿中的金丝雀一样,lorikeet 旨在在事情出错时提供通知方式。它不是运行一个测试框架(一种颜色),而是旨在更全面,因此选择了彩虹羽毛的鸟类。

它们也是非常吵闹的鸟类。

0.14.0 版本中的更改

  • 重大变更:为HTTP请求添加默认超时时间(timeout_ms),默认为30,000毫秒(30秒),此默认值可以根据以下HTTP选项进行更改。

0.13.1版本中的变更

  • 添加了对Slack webhook的支持。如果有任何步骤出现错误,这将发送到webhook。
lorikeet -s https://hooks.slack.com/services/<your_webhook_here> test

0.13.0版本中的变更

  • 重大变更:run_steps方法现在返回步骤完成的流,而不是等待所有步骤完成。
  • 更多Clippy Lints
  • 修复了在OS X上的编译错误。

0.12.1版本中的变更

  • 修复了所有Clippy问题。
  • JMESPath字符串不再需要加引号。
  • 添加了在后续请求中包含步骤输出的功能。您可以通过包含${step_output.<step_name>}来实现,其中<step_name>是要包含为输出的步骤名称。目前您仍然需要“require”此步骤。
example_output:
  require: another_step
  http:
    url: http://example.com
    body: |
      ${step_output.another_step}

0.12.0版本中的变更

  • 更新到Tokio 1.0。
  • 更新了所有库依赖项。

0.11.0版本中的变更

  • 初始异步版本。
  • 更新了库依赖项。

0.10.0版本中的变更

  • 升级到2018 crate格式。
  • 修复了在Ubuntu 19.10上的终端绘制问题。
  • 对库版本进行了一些小的更新。

0.9.0版本中的变更

  • 升级到Reqwest 0.9.x分支,感谢norcali

  • 为HTTP请求类型添加了multipart支持、body支持和headers支持。

要添加自定义headers,提供一个header_name: header_value的map。

Example Header:
  http:
    url: https://example.com
    headers:
      my-custom-header: my-custom-value

Multipart与现有的form选项工作方式相同,但允许您指定要上传的文件。

Example Multipart:
  http:
    url: https://example.com
    multipart:
      multipart_field: multipart_value
      file_upload:
        file: /path/to/file

您也可以通过字符串设置一个通用的body。

Example Body:
  http:
    url: https://example.com
    body: |
      This is a generic POST body

0.8.0版本中的变更

  • 如果存在读取、解析或运行步骤的问题,CLI应用程序将不会崩溃,而是会输出一个lorikeet步骤来显示错误信息,并通过webhooks等提交它。

  • 为步骤添加了初始延迟。如果您想在运行步骤之前等待任意时间,则可以使用delay_ms参数设置初始延迟。此延迟仅在步骤通常开始时执行,因此如果您的步骤有依赖关系,它们将首先运行,然后是延迟,然后是步骤。

  • 在重试策略中添加:如果测试失败,可以通过设置 retry_count 属性来重试 n 次。您还可以通过设置 retry_delay_ms 参数来延迟重试。

  • delay_msretry_delay_ms 都以毫秒为单位,必须是一个正整数。

  • 添加了初始的 junit 输出,以便您可以使用 lorikeet 与 Jenkins 或支持 junit xml 报告的另一个 CI 服务器。使用 -j report.xml 输出 junit 报告。

0.7.0 的变化

  • 这里的主要变化是将 YAML 解析更改为移除恐慌,并返回一个 Result<Vec<Step>>,这是一个破坏性更改
  • 一个新的函数 get_steps_raw,它接受一个 &str yaml 以及实现 Serialize 的任何内容作为配置上下文。这主要允许库在不需要触摸文件系统的情况下用于配置或步骤。 get_steps 仍然可以用路径提供

安装

Lorikeet 在 crates.io 上,所以您可以选择运行

cargo install lorikeet

或者克隆并构建此存储库

cargo build --release

用法

命令行用法由 lorikeet -h 提供

USAGE:
    lorikeet [FLAGS] [OPTIONS] [test_plan]

FLAGS:
    -h, --help       Prints help information
    -q, --quiet      Don't output results to console
    -V, --version    Prints version information

OPTIONS:
    -c, --config <config>         Configuration File
    -j, --junit <junit>           Output a JUnit XML Report to this file
    -w, --webhook <webhook>...    Webhook submission URL (multiple values allowed)

ARGS:
    <test_plan>    Test Plan [default: test.yml]

测试计划

测试计划是 lorikeet 的主要驱动程序,并且已经非常灵活。下面提供示例和测试语法。默认情况下,lorikeet 将期望在当前目录中有一个文件 test.yml

配置选项

Lorikeet 使用 tera 作为模板引擎,因此您可以在 yaml 测试计划中包含变量。使用 -c 您可以提供测试计划的上下文作为单独的 yaml 文件。此文件可以是任何形状,只要它是有效的 yaml。

例如,假设您想检查是否有多个服务器处于运行状态并连接。您可以有一个这样的配置

instances:
  - server1
  - server2
  - server3

然后编写您的测试计划

{% for instance in instances %}

ping_server_{{instance}}:
  bash: ping -c 1 {{instance}} 2>&1 >/dev/null

{% endfor %}

并运行它

$ lorikeet -c config.yml test.yml
- name: ping_server_server1
  pass: true
  duration: 7.859398ms

- name: ping_server_server2
  pass: true
  duration: 7.95139ms

- name: ping_server_server3
  pass: true
  duration: 7.740785ms

Webhook

测试运行完成后,您可以使用 webhook 将结果提交到服务器。这将使用 submitter::WebHook 形状 POST 一个 json 对象

{
    "hostname": "example.hostname",
    "has_errors": true,
    "tests": [{
        "name": "Example Webhook",
        "pass": false,
        "output": "Example Output",
        "error": "Example Error",
        "duration": 7.70
    }]
}

测试计划语法

测试计划是一个 yaml 文件,它被分成几个步骤

<step_name>:
  <step_type>: <options>
  (<description>: <value>)
  (<expect_type>: <value>)
  (<filter_type>: <list or value>)
  (<dependence_type>: <list or value>)

每个步骤都有一个唯一的名字和步骤类型。可选的,还可以有一个期望类型,以及一个依赖项或依赖者的列表。

您还可以在名称旁边包含测试执行描述,这样您就可以提供对测试执行更详细的解释

步骤类型

目前可以配置 5 种步骤类型:bash、http、system、step 和 value

Bash 步骤类型

Bash 步骤类型只是运行 bash 命令以执行 shell 脚本

say_hello:
  bash: echo "hello"

可选地,您可以选择不返回输出,如果您只对应用程序的返回代码感兴趣

dont_say_hello:
  bash:
    cmd: echo "hello"
    get_output: false

HTTP 步骤类型

HTTP 步骤类型可以使用 reqwest 执行对 web 服务器的 HTTP 命令。目前这是一个非常简单的步骤类型,但支持状态代码和按域名存储 cookie。

您可以指定仅 URL

check_reddit:
  http: https://www.reddit.com
  matches: the front page of the internet

或者提供以下选项

  • url:提交请求的URL
  • method:要使用的HTTP方法,例如POST、GET、DELETE。默认为GET
  • headers:请求中任何自定义头部的键/值对
  • get_output:返回请求的输出。默认为true
  • save_cookies:在此域上保存任何设置的cookies。默认为false
  • status:检查返回状态是否等于此值。默认为200
  • user:基本认证的用户名
  • pass:基本认证的密码
  • timeout_ms:请求的超时时间(毫秒),默认为30000(30秒)。如果设置为null~,则永远不会超时。
  • form:表单POST提交的键/值对。如果方法设置为GET,则此选项将方法设置为POST
  • multipart:多部分请求。与form选项类似,但允许文件上传。
  • body:类似于form/multipart选项,但用于JSON上传的是原始字符串而不是表单数据。
  • verify_ssl:验证远程主机上的SSL。默认为true。**警告**:禁用SSL验证会导致Lorikeet信任它与任何主机通信,这可能使您面临许多漏洞。您应仅作为最后的手段使用此功能。

以下是一个更详细的示例

login_to_reddit:
  http: 
    url: https://www.reddit.com/api/login/{{user}}
    save_cookies: true
    form:
      user: {{user}}
      passwd: {{pass}}
      api_type: json

对于多部分,您可以指定文件如下

Example Multipart:
  http:
    url: https://www.example.com
    multipart:
      multipart_field: multipart_value
      file_upload:
        file: /path/to/file

对于JSON上传,您可以使用body字段

Example Raw JSON:
  http:
    url: https://www.example.com
    body: |
      { "json_key": "json_value" }

系统步骤类型

系统步骤类型将使用sys-info crate返回有关系统信息,例如可用内存或系统负载。

例如,要检查内存

check_memory:
  description: Checks to see if the available memory is greater than 1gb
  system: mem_available
  greater_than: 1048000

系统类型有一个固定的值列表,返回各种系统信息

  • load_avg_1m:1分钟内的平均负载
  • load_avg_5m:5分钟内的平均负载
  • load_avg_15m:15分钟内的平均负载
  • mem_available:可用内存量
  • mem_free:空闲内存量
  • mem_total:总内存量
  • disk_free:空闲磁盘空间量
  • disk_total:总磁盘空间量

使用greater_thanless_than期望类型意味着您可以为环境资源设置阈值。

system_load:
  description: Checks the System Load over the last 15 minutes is below 80%
  system: load_avg15m
  less_than: 1.6

‘步骤’步骤类型

如果您想对单个步骤进行更多断言,可以使用‘步骤’步骤类型。此类型仅返回其他步骤的输出。

say_hello:
  value: hello
  
test_step:
  step: say_hello
  matches: hello

这也会隐式要求先运行它从中获取输出的步骤作为依赖项,这样您就不必担心顺序。

值步骤类型

值步骤类型将简单地返回一个值,而不是执行任何操作。

say_hello:
  value: hello

过滤器类型

您可以通过正则表达式、jmespath或完全删除输出来过滤您的输出。过滤器可以一次性提供,或作为列表提供,因此您可以链接过滤器。

example_step:
  value: some example
  filters:
    - regex: some (.*)

您还可以在步骤上简写提供过滤器,如下所示

example_step:
  value: some example
  regex: some

注意:如果过滤器无法匹配值,则视为测试错误

正则表达式过滤器

简单过滤器根据匹配的值过滤步骤的输出。

say_hello:
  value: hello world!
  regex: (.*) world!

您可以将它作为 regex 属性添加到步骤中,或者添加到过滤列表中

say_hello:
  value: hello world!
  filters:
    - regex: (.*) world!

默认情况下,它将匹配并返回整个正则表达式语句(例如,`hello world!`),但如果您只想匹配某个组,也可以这样做

say_hello:
  value: hello world!
  regex: 
    matches: (?P<greeting>.*) world!
    group: greeting

这将输出简单的 hello

JMES Path 过滤器

您可以使用 jmespath 过滤 JSON 文档,返回一些或更多值

show_status:
  value: "{\"status\": \"ok\"}"
  jmespath: status

与正则表达式一样,这可以是过滤链的一部分

show_status:
  value: "{\"status\": \"ok\"}"
  filters:
    - jmespath: status

无输出过滤器

如果您不想将输出打印在结果中,可以添加无输出

dont_show_hello:
  value: hello
  do_output: false

您也可以将其添加到过滤链中

dont_show_hello:
  value: hello
  filters:
    - nooutput

有时您可能从请求中返回太多内容,因此可以使用此功能确保打印的内容不包括在内

check_reddit:
  http: https://www.reddit.com
  filters:
    - regex: the front page of the internet

期望类型

目前有3种期望类型:匹配输出、大于和小于。期望类型将取步骤类型的原始输出并对其进行验证。这样,您可以使用它来匹配来自Web服务器的返回的HTML或bash文件的输出。

匹配期望类型

匹配期望类型将使用正则表达式匹配命令的输出。

say_hello_or_goodbye:
  value: hello
  matches: hello|goodbye

如果正则表达式转换为有效的正则表达式查询时出现错误,则这将被视为失败。

大于或小于

如果您的输出是数值,则可以使用大于或小于来比较它

there_are_four_lights:
  value: 4
  less_than: 5

依赖关系

默认情况下,测试并行运行并提交到线程池执行。如果一个步骤有依赖关系,则不会运行,直到依赖步骤完成。如果没有步骤的依赖关系,则一有空闲线程就运行。如果您没有指定任何依赖关系,则没有保证执行顺序。

依赖关系很重要,例如在检查API之前设置cookie,但会导致您的测试运行时间更长,因为它们在等待其他步骤完成。

定义依赖关系,您可以使用 requirerequired_by 参数来控制这个依赖关系树。所需步骤由其名称给出,可以是单个值或名称列表。

step1:
  value: hello

step2:
  value: goodbye
  require: step1

step3:
  value: yes
  require:
    - step1
    - step2

Lorikeet 如果

  • 存在循环依赖
  • 依赖关系中的步骤名称找不到

所需

required_byrequire 的逆,可以在测试计划中使它更易读。

所以这个步骤计划

step1:
  value: hello

step2:
  value: goodbye
  require: step1

等同于这个

step1:
  value: hello
  required_by: step2

step2:
  value: goodbye

更复杂的依赖关系示例

you_say_yes:
  value: yes

i_say_no:
  value: no
  require: you_say_yes

you_say_stop:
  value: stop
  require: 
    - i_say_no
    - you_say_yes
  required_by:
    - and_i_say_go_go_go

and_i_say_go_go_go:
   value: go go go

重试次数和延迟

有时您希望在另一个步骤运行后延迟一段时间执行步骤。有时如果步骤失败,您可能还希望在放弃之前重试它几次。

添加延迟

您可以通过设置 delay_ms 值来添加延迟

step1:
  value: hello
  delay_ms: 1000

输出

$ lorikeet test.yml
- name: step1
  pass: true
  output: hello
  duration: 1004.1231ms

添加重试

您可以使用 retry_count 重试步骤几次,并使用 retry_delay_ms 添加延迟。

this_will_fail_but_take_3_seconds:
  value: hello
  matches: goodbye
  retry_count: 3
  retry_delay_ms: 1000

输出

$ lorikeet test.yml
- name: this_will_fail_but_take_3_seconds
  pass: false
  output: hello
  error: Not matched against `goodbye`
  duration: 3015.933ms

JUnit 报告

您可以使用 -j 命令生成 JUnit xml 报告

lorikeet -j report.xml test.yml

输出主要用于与 Jenkins BlueOcean 一起使用,报告格式可能略有变化。

示例

将这些示例保存为 test.yml 以运行它们

从 bash 提示符回显 hello

测试计划

say_hello:
  bash: echo hello

输出

$ lorikeet test.yml
- name: say_hello
  pass: true
  output: |
    hello

  duration: 2.727446ms

匹配 bash 命令的输出

测试计划

say_hello:
  bash: echo hello
  matches: hello

输出

$ lorikeet test.yml
- name: say_hello
  pass: true
  duration: 2.68431ms

检查 Reddit 是否宕机

测试计划

check_reddit:
  http: https://www.reddit.com
  matches: the front page of the internet

输出

$ lorikeet test.yml
- name: say_hello
  pass: true
  duration: 2.68431ms

登录 Reddit

对于测试的配置参数,如用户名和密码,将其分离到不同的文件中是有意义的

配置文件

user: myuser
pass: mypass

测试计划

login_to_reddit:
  http: 
    url: https://www.reddit.com/api/login/{{user}}
    form:
      user: {{user}}
      passwd: {{pass}}
      api_type: json

输出(不要忘记使用 -c 指定配置文件)

$ lorikeet -c config.yml test.yml
- name: login_to_reddit
  pass: true
  output: {"json": {"errors": [], "data": {"need_https": true, "modhash": "....", "cookie": "..."}}}
  duration: 1420.8466ms

依赖关系

~22–39MB
~578K SLoC