A Parallel test runner for DevOps.
Download the latest binary for linux or osx from here: https://github.com/cetra3/lorikeet/releases
Lorikeet is a command line tool and a rust library to run tests for smoke testing and integration testing. Lorikeet currently supports bash commands and simple http requests along with system information (ram, cpu).
Test plans are defined within a yaml file and can be templated using tera. Each step within a test plan can have multiple dependencies (run some steps before others) and can have expectations about the output of each command.
Steps are run in parallel by default, using the number of threads that are available to your system. If a step has dependencies either by require or required_by attributes, then it will wait until those steps are finished.
As an example, here's a test plan to check to see whether reddit is up, and then tries to login if it is:
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
( As a side note, we have added jmespath: length(json.errors) & matches: 0 because an invalid login to reddit still returns a status of 200 OK )
And the output of 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
The name comes from the Rainbow Lorikeet, an Australian Bird which is very colourful. Like a canary in a coal mine, lorikeet is meant to provide a way of notifying when things go wrong. Rather than running one test framework (one colour), it is meant to be more full spectrum, hence the choice of a bird with rainbow plumage.
They are also very noisy birds.
0.16.020240.15.0on_fail_example:
value: true
matches: false
on_fail:
bash: notify-send "Lorikeet Failed!"
0.14.0timeout_ms) for http requests to 30000 milliseconds (30 seconds), This default can be changed as per http options below.0.13.1lorikeet -s https://hooks.slack.com/services/<your_webhook_here> test
0.13.0run_steps method returns a stream of steps as they complete, rather than waiting for them all to finish0.12.1${step_output.<step_name>} where <step_name> is the name of the step to include as output. Currently you will still need to "require" this stepexample_output:
require: another_step
http:
url: http://example.com
body: |
${step_output.another_step}
0.12.00.11.00.10.00.9.0Upgrade to Reqwest 0.9.x branch, thanks norcali!
Added multipart support, body, and headers support to the HTTP request type:
To add custom headers, supply a map of header_name: header_value:
Example Header:
http:
url: https://example.com
headers:
my-custom-header: my-custom-value
Multipart works in the same way as the existing form option, but allows you to also specify files to upload:
Example Multipart:
http:
url: https://example.com
multipart:
multipart_field: multipart_value
file_upload:
file: /path/to/file
You can also just set a generic body via a string:
Example Body:
http:
url: https://example.com
body: |
This is a generic POST body
0.8.0The cli app will not panic if there is an issue reading, parsing or running steps, instead it will output a lorikeet step to display what the error is, and still submit it via webhooks, etc..
Added in initial delay for a step. If you want to wait an arbitrary period of time before running a step, then you can set an initial delay with the delay_ms parameter. This delay is only executed when the step would normally start, so if you have dependent steps, they will run first, then the delay, then the step.
retry_count property. You can also delay retries by setting the retry_delay_ms parameter.Both delay_ms and retry_delay_ms are in milliseconds and must be a positive integer value.
Added initial junit output so you can use lorikeet with jenkins or another CI server that supports junit xml reports. Use -j report.xml to output junit reports.
0.7.0Result<Vec<Step>> which is a breaking changeget_steps_raw which takes a &str yaml & anything that implements Serialize as a config context. This mainly allows the library to be used without touching the file system for configs or steps. get_steps still can be provided with pathsLorikeet is on crates.io, so you can either run:
cargo install lorikeet
Or clone and build this repo:
cargo build --release
Alternatively, you can download prebuilt from the releases page
Command line usage is given by 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]
The test plan is the main driver for lorikeet and is already quite flexible. See below for examples and test syntax. By default lorikeet will expect a file test.yml in the current directory.
Lorikeet uses tera as a template engine so you can include variables within your yaml test plan. Using -c you can provide the context of the test plan as a seperate yaml file. This file can be in any shape, as long as it's valid yaml.
As an example, say you want to check that a number of servers are up and connected. You can have a config like so:
instances:
- server1
- server2
- server3
And then write your test plan:
{% for instance in instances %}
ping_server_{{instance}}:
bash: ping -c 1 {{instance}} 2>&1 >/dev/null
{% endfor %}
And run it:
$ 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
You can submit your results to a server using a webhook when the test run is finished. This will POST a json object with the submitter::WebHook shape:
{
"hostname": "example.hostname",
"has_errors": true,
"tests": [{
"name": "Example Webhook",
"pass": false,
"output": "Example Output",
"error": "Example Error",
"duration": 7.70
}]
}
The test plan is a yaml file that is divided up into steps:
<step_name>:
<step_type>: <options>
(<description>: <value>)
(<expect_type>: <value>)
(<filter_type>: <list or value>)
(<dependence_type>: <list or value>)
Each step has a unique name and a step type. Optionally, there can be an expect type, and a list of dependencies or dependents.
You can also include a description of what the test does alongside a name, so you can provide a more detailed explanation of what the test is doing
There are currently 5 step types that can be configured: bash, http, system, step and value
The bash step type simply runs the bash command to execute shell scripts:
say_hello:
bash: echo "hello"
Optionally you can specify not to return the output if you're only interested in the return code of the application:
dont_say_hello:
bash:
cmd: echo "hello"
get_output: false
The HTTP step type can execute HTTP commands to web servers using reqwest. Currently this is a very simple step type but does support status codes and storing cookies per domain.
You can specify just the URL:
check_reddit:
http: https://www.reddit.com
matches: the front page of the internet
Or provide the following options:
url: The URL of the request to submitmethod: The HTTP method to use, such as POST, GET, DELETE. Defaults to GETheaders: Key/Value pairs for any custom headers on your requestget_output: Return the output of the request. Defaults to truesave_cookies: Save any set cookies on this domain. Defaults to falsestatus: Check the return status is equal to this value. Defaults to 200user: Username for Basic Authpass: Password for Basic Authtimeout_ms: Timeout in milliseconds for the request, defaults to 30000 (30 seconds). If set to null or ~ it will never timeout.form: Key/Value pairs for a form POST submission. If method is set to GET, then this will set the method to POSTmultipart: Multipart request. Key/Value pairs Like the form option but allows file upload as well.body: Like the form/multipart options but a raw string instead of form data for JSON uploadsverify_ssl: Verify SSL on the remote host. Defaults to true. Warning: Disabling SSL verification will cause Lorikeet to trust any host it communicates with, which can expose you to numerous vulnerabilities. You should only use this as a last resort.As a more elaborate example:
login_to_reddit:
http:
url: https://www.reddit.com/api/login/{{user}}
save_cookies: true
form:
user: {{user}}
passwd: {{pass}}
api_type: json
For Multipart, you can specify files like so:
Example Multipart:
http:
url: https://www.example.com
multipart:
multipart_field: multipart_value
file_upload:
file: /path/to/file
For a JSON upload you can use the body field:
Example Raw JSON:
http:
url: https://www.example.com
body: |
{ "json_key": "json_value" }
The system step type will return information about the system such as available memory or system load using the sys-info crate.
As an example, to check memory:
check_memory:
description: Checks to see if the available memory is greater than 1gb
system: mem_available
greater_than: 1048000
The system type has a fixed list of values that returns various system info:
load_avg_1m: The load average over 1 minuteload_avg_5m: The load average over 5 minutesload_avg_15m: The load average over 15 minutesmem_available: The amount of available memorymem_free: The amount of free memorymem_total: The amount of total memorydisk_free: The amount of free disk spacedisk_total: The total amount of disk spaceUsing the greater_than or less_than expect types means you can set thresholds for environment resources:
system_load:
description: Checks the System Load over the last 15 minutes is below 80%
system: load_avg15m
less_than: 1.6
If you want to make more assertions on the one step, you can use the 'step' step type. This type simply returns the output of the other step:
say_hello:
value: hello
test_step:
step: say_hello
matches: hello
This will also implicitly require that the step it gets it output from is run first as a dependency so you don't have to worry about the order.
The value step type will simply return a value, rather than executing anything.
say_hello:
value: hello
You can filter your output either via regex, jmespath, or remove the output completely. Filters can be provided once off, or as a list, so you can chain filters together:
example_step:
value: some example
filters:
- regex: some (.*)
You can also shorthand provide a filter on the step like so:
example_step:
value: some example
regex: some
Note: If the filter can't match against a value, it counts as a test error
Simply filters out the output of the step based upon the matched value.
```yaml say_hello: value: hello world! regex: (.*)
$ claude mcp add lorikeet \
-- python -m otcore.mcp_server <graph>