Buildspec Overview

What is a buildspec?

A buildspec is a YAML file that defines your test in buildtest which is validated by schema followed by building a shell script and running the generated test. Buildtest will parse the buildspec with the global schema file which defines the top-level structure of buildspec file.

Example

Let’s start off with a simple example that declares two variables X and Y and prints the sum of X+Y.

buildspecs:
  add_numbers:
    type: script
    executor: generic.local.bash
    description: Add X+Y
    tags: [tutorials]
    vars:
      X: 1
      Y: 2
    run: echo "$X+$Y=" $(($X+$Y))

buildtest will validate the entire buildspec with global.schema.json, and use one of the sub-schema to validate the test defined in buildspec section. The buildspec is where you define a test, in the example above the name of the test is add_numbers. The test requires a type field which is the sub-schema used to validate the test section. In this example type: script informs buildtest to use the Script Schema when validating test section.

Each subschema has a list of field attributes that are supported, for example the fields: type, executor, vars and run are all valid fields supported by the script schema.

Let’s look at a more interesting example, shown below is a multi line run example using the script schema with test name called systemd_default_target, shown below is the content of test:

buildspecs:
  systemd_default_target:
    executor: generic.local.bash
    type: script
    tags: [system]
    description: check if default target is multi-user.target
    run: |
      if [ "multi-user.target" == `systemctl get-default` ]; then
        echo "multi-user is the default target";
        exit 0
      fi
      echo "multi-user is not the default target";
      exit 1

The test name systemd_default_target defined in buildspec section is validated with the following pattern "^[A-Za-z_][A-Za-z0-9_]*$". This test will use the executor generic.local.bash which means it will use the Local Executor with an executor name bash defined in the buildtest settings. The default buildtest settings will provide a bash executor as follows:

 system:
   generic:
     hostnames: ["localhost"]
     executors:
       local:
         bash:
           description: submit jobs on local machine using bash shell
           shell: bash

The shell: bash indicates this executor will use bash to run the test scripts. To reference this executor use the format <system>.<type>.<name> in this case generic.local.bash refers to bash executor.

The description field is an optional key that can be used to provide a brief summary of the test. The description field is limited to 80 characters. In this example we can specify multiple commands in run section, this can be done in YAML using run: | followed by content of run section tab indented 2 spaces.

In this next example, we introduce the summary field, which can be used as an extended description of test. It has no impact on the test. Unlike the description field, the summary field has no limit on character count and one can define multi-line string using the pipe symbol |.

buildspecs:
  summary_example:
    type: script
    executor: generic.local.bash
    description: The summary field can be a multi-line string and exceed 80 char
    tags: [tutorials]
    summary: |
      This is a long description of test that
      can exceed 80 characters and be multiline
    run: hostname

Script Schema

The script schema is used for writing simple scripts (bash, sh, python) in Buildspec. To use this schema you must set type: script. The run field is responsible for writing the content of test.

Shown below is schema header for script.schema.json.

{
  "$id": "script.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "script schema version",
  "description": "The script schema is of ``type: script`` in sub-schema which is used for running shell scripts",
  "type": "object",
  "required": [
    "type",
    "run",
    "executor"
  ],
  "additionalProperties": false,

The "type": "object" means sub-schema is a JSON object where we define a list of key/value pair. The "required" field specifies a list of fields that must be specified in order to validate the Buildspec. In this example, type, run, and executor are required fields. The additionalProperties: false informs schema to reject any extra properties not defined in the schema.

The executor key is required for all sub-schemas which instructs buildtest which executor to use when running the test. The executors are defined in How to configure buildtest. In our first example we define variables using the vars property which is a Key/Value pair for variable assignment. The run section is required for script schema which defines the content of the test script.

Declaring Environment Variables

You can define environment variables using the env property, this is compatible with shells: bash, sh, zsh, csh and tcsh. It does not work with shell: python. In example below we declare three tests using environment variable with default shell (bash), csh, and tcsh

buildspecs:
  bash_env_variables:
    executor: generic.local.bash
    description: Declare environment variables in default shell (bash)
    type: script
    env:
      FIRST_NAME: avocado
      LAST_NAME: dinosaur
    tags: [tutorials]
    run: |
      hostname
      whoami
      echo $USER
      printf "${FIRST_NAME} ${LAST_NAME}\n"

  csh_env_declaration:
    executor: generic.local.csh
    type: script
    description: "csh shell example to declare environment variables"
    shell: /bin/csh
    tags: [tutorials]
    env:
      SHELL_NAME: "csh"
    run: echo "This is running $SHELL_NAME"

  tcsh_env_declaration:
    executor: generic.local.csh
    type: script
    description: "tcsh shell example to declare environment variables"
    shell: /bin/tcsh
    tags: [tutorials]
    env:
      path: "/usr/local/bin:$PATH"
    run: echo $path

This test can be run by issuing the following command: buildtest build -b tutorials/environment.yml. If we inspect one of the test script we will see that buildtest generates a build script that invokes the test using the shell wrapper /bin/csh for the csh test and gets the returncode.

#!/bin/bash


############# START VARIABLE DECLARATION ########################
export BUILDTEST_TEST_NAME=csh_env_declaration
export BUILDTEST_TEST_ROOT=/Users/siddiq90/Documents/GitHubDesktop/buildtest/var/tests/generic.local.csh/environment/csh_env_declaration/0
export BUILDTEST_BUILDSPEC_DIR=/Users/siddiq90/Documents/GitHubDesktop/buildtest/tutorials
export BUILDTEST_STAGE_DIR=/Users/siddiq90/Documents/GitHubDesktop/buildtest/var/tests/generic.local.csh/environment/csh_env_declaration/0/stage
export BUILDTEST_TEST_ID=501ec5d3-e614-4ae8-9c1e-4849ce340c76
############# END VARIABLE DECLARATION   ########################


# source executor startup script
source /Users/siddiq90/Documents/GitHubDesktop/buildtest/var/executor/generic.local.csh/before_script.sh
# Run generated script
/bin/csh /Users/siddiq90/Documents/GitHubDesktop/buildtest/var/tests/generic.local.csh/environment/csh_env_declaration/0/stage/csh_env_declaration.csh
# Get return code
returncode=$?
# Exit with return code
exit $returncode

This generated test looks something like this

#!/bin/csh
# Declare environment variables
setenv SHELL_NAME csh


# Content of run section
echo "This is running $SHELL_NAME"

Environment variables are defined using export in bash, sh, zsh while csh and tcsh use setenv.

Declaring Variables

Variables can be defined using vars property, this is compatible with all shells except for python. The variables are defined slightly different in csh, tcsh as pose to bash, sh, and zsh. In example below we define tests with bash and csh.

In YAML strings can be specified with or without quotes however in bash, variables need to be enclosed in quotes " if you are defining a multi word string (name="First Last").

If you need define a literal string it is recommended to use the literal block | that is a special character in YAML. If you want to specify " or ' in string you can use the escape character \ followed by any of the special character. In example below we define several variables such as X, Y that contain numbers, variable literalstring is a literal string processed by YAML. The variable singlequote and doublequote defines a variable with the special character ' and ". The variables current_user and num_files store result of a shell command. This can be done using var=$(<command>) or var=`<command>` where <command> is a Linux command.

buildspecs:
  variables_bash:
    type: script
    executor: generic.local.bash
    description: Declare shell variables in bash
    tags: [tutorials]
    vars:
      X: 1
      Y: 2
      literalstring: this is a literal string
      singlequote: \'singlequote\'
      doublequote: \"doublequote\"
      current_user: "$(whoami)"
      num_files: "`find $HOME -type f -maxdepth 1 | wc -l`"
      multiline_string: |
        Hello my name is Bob \n
        I am 30 years old


    run: |
      echo "$X+$Y="$(($X+$Y))
      echo $literalstring
      echo $singlequote
      echo $doublequote
      echo "current user:" $current_user
      echo "number of files:" $num_files
      echo -e $multiline_string

Next we build this test by running buildtest build -b $BUILDTEST_ROOT/tutorials/vars.yml.

buildtest build -b $BUILDTEST_ROOT/tutorials/vars.yml
$ buildtest build -b $BUILDTEST_ROOT/tutorials/vars.yml
Buildspec Paths: ['/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials', '/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/general_tests']
Updating buildspec cache file: /tmp/tmpq07_ocbs/var/buildspecs/cache.json
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:39                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/vars.yml                                                            ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/vars.yml: VALID
Total builder objects created: 1
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ variable │ script │ generic. │ None     │ None  │ None  │ Declare  │ /home/d │
│ s_bash/2 │        │ local.ba │          │       │       │ shell    │ ocs/che │
│ 6a15409  │        │ sh       │          │       │       │ variable │ ckouts/ │
│          │        │          │          │       │       │ s in     │ readthe │
│          │        │          │          │       │       │ bash     │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /vars.y │
│          │        │          │          │       │       │          │ ml      │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
variables_bash/26a15409: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
variables_bash/26a15409 does not have any dependencies adding test to queue
 Builders Eligible to Run  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ variables_bash/26a15409 │
└─────────────────────────┘
variables_bash/26a15409: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/stage
variables_bash/26a15409: Running Test via command: bash variables_bash_build.sh
variables_bash/26a15409: Test completed in 0.0142 seconds with returncode: 0
variables_bash/26a15409: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash.out
variables_bash/26a15409: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash.err
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ variables_bash/26a15409 │ generic.local.bash │ PASS   │ 0          │ 0.014   │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/1 Percentage: 100.000%
Failed Tests: 0/1 Percentage: 0.000%


Adding 1 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_7br16jf5.log

Let’s check the generated script from the previous build, you can run buildtest inspect query -o variables_bash where -o refers to output file for testname variables_bash. Take note of the output file we

buildtest inspect query -o variables_bash
$ buildtest inspect query -o variables_bash
───────────── variables_bash/26a15409-30d0-4457-9397-acb5c6632bcf ──────────────
Executor: generic.local.bash
Description: Declare shell variables in bash
State: PASS
Returncode: 0
Runtime: 0.0142 sec
Starttime: 2024/02/22 20:29:39
Endtime: 2024/02/22 20:29:39
Command: bash variables_bash_build.sh
Test Script: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash.sh
Build Script: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash_build.sh
Output File: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash.out
Error File: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_bash/26a15409/variables_bash.err
Log File: /tmp/tmpq07_ocbs/var/logs/buildtest_7br16jf5.log
─ Output File: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/vars/variables_b… ─
1+2=3                                                                           
this is a literal string                                                        
\'singlequote\'                                                                 
"doublequote"                                                                   
current user: docs                                                              
number of files: 4                                                              
Hello my name is Bob                                                            
 I am 30 years old

Defining Tags

The tags field can be used to classify tests which can be used to organize tests or if you want to Building By Tags (buildtest build --tags) (buildtest build --tags <TAGNAME>). Tags can be defined as a string or list of strings. In this example, the test string_tag defines a tag name network while test list_of_strings_tags define a list of tags named network and ping.

buildspecs:
  string_tag:
    type: script
    executor: generic.local.bash
    description: tags can be a string
    tags: network
    run: hostname

  list_of_strings_tags:
    type: script
    executor: generic.local.bash
    description: tags can be a list of strings
    tags: [network, ping]
    run: ping -c 4 www.google.com

Each item in tags must be a string and no duplicates are allowed, for example in this test, we define a duplicate tag network which is not allowed.

buildspecs:
  duplicate_string_tags:
    type: script
    executor: generic.local.bash
    description: duplicate strings in tags list is not allowed
    tags: [network, network]
    run: hostname

If tags is a list, it must contain atleast one item.

Test Status

buildtest will record state of each test which can be PASS or FAIL. By default a 0 exit code is PASS and everything else is a FAIL. The status property can be used to determine how test will report its state. Currently, we can match state based on the following:

Return Code Matching

buildtest can report PASS/FAIL based on returncode, by default a 0 exit code is PASS and everything else is FAIL. The returncode can be a list of exit codes to match. In this example we have four tests called exit1_fail, exit1_pass, returncode_list_mismatch and returncode_int_match. We expect exit1_fail and returncode_mismatch to FAIL while exit1_pass and returncode_int_match will PASS.

buildspecs:

  exit1_fail:
    executor: generic.local.bash
    type: script
    description: exit 1 by default is FAIL
    tags: [tutorials, fail]
    run: exit 1

  exit1_pass:
    executor: generic.local.bash
    type: script
    description: report exit 1 as PASS
    run: exit 1
    tags: [tutorials, pass]
    status:
      returncode: [1]

  returncode_list_mismatch:
    executor: generic.local.bash
    type: script
    description: exit 2 failed since it failed to match returncode 1
    run: exit 2
    tags: [tutorials, fail]
    status:
      returncode: [1, 3]

  returncode_int_match:
    executor: generic.local.bash
    type: script
    description: exit 128 matches returncode 128
    run: exit 128
    tags: [tutorials, pass]
    status:
      returncode: 128

Let’s build this test and pay close attention to the status column in output.

buildtest build -b tutorials/test_status/pass_returncode.yml
$ buildtest build -b tutorials/test_status/pass_returncode.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:40                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/pass_returncode.yml                                     ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/pass_returncode.yml: VALID
Total builder objects created: 4
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ exit1_fa │ script │ generic. │ None     │ None  │ None  │ exit 1   │ /home/d │
│ il/b72ed │        │ local.ba │          │       │       │ by       │ ocs/che │
│ 665      │        │ sh       │          │       │       │ default  │ ckouts/ │
│          │        │          │          │       │       │ is FAIL  │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/p │
│          │        │          │          │       │       │          │ ass_ret │
│          │        │          │          │       │       │          │ urncode │
│          │        │          │          │       │       │          │ .yml    │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ exit1_pa │ script │ generic. │ None     │ None  │ None  │ report   │ /home/d │
│ ss/ba20e │        │ local.ba │          │       │       │ exit 1   │ ocs/che │
│ 26d      │        │ sh       │          │       │       │ as PASS  │ ckouts/ │
│          │        │          │          │       │       │          │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/p │
│          │        │          │          │       │       │          │ ass_ret │
│          │        │          │          │       │       │          │ urncode │
│          │        │          │          │       │       │          │ .yml    │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ returnco │ script │ generic. │ None     │ None  │ None  │ exit 2   │ /home/d │
│ de_list_ │        │ local.ba │          │       │       │ failed   │ ocs/che │
│ mismatch │        │ sh       │          │       │       │ since it │ ckouts/ │
│ /1b4070f │        │          │          │       │       │ failed   │ readthe │
│ 0        │        │          │          │       │       │ to match │ docs.or │
│          │        │          │          │       │       │ returnco │ g/user_ │
│          │        │          │          │       │       │ de 1     │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/p │
│          │        │          │          │       │       │          │ ass_ret │
│          │        │          │          │       │       │          │ urncode │
│          │        │          │          │       │       │          │ .yml    │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ returnco │ script │ generic. │ None     │ None  │ None  │ exit 128 │ /home/d │
│ de_int_m │        │ local.ba │          │       │       │ matches  │ ocs/che │
│ atch/004 │        │ sh       │          │       │       │ returnco │ ckouts/ │
│ 772b0    │        │          │          │       │       │ de 128   │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/p │
│          │        │          │          │       │       │          │ ass_ret │
│          │        │          │          │       │       │          │ urncode │
│          │        │          │          │       │       │          │ .yml    │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
exit1_fail/b72ed665: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_fail/b72ed665
exit1_pass/ba20e26d: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_pass/ba20e26d
returncode_list_mismatch/1b4070f0: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_list_mismatch/1b4070f0
returncode_int_match/004772b0: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_int_match/004772b0
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
exit1_fail/b72ed665 does not have any dependencies adding test to queue
returncode_list_mismatch/1b4070f0 does not have any dependencies adding test to queue
returncode_int_match/004772b0 does not have any dependencies adding test to queue
exit1_pass/ba20e26d does not have any dependencies adding test to queue
      Builders Eligible to Run       
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ exit1_fail/b72ed665               │
│ returncode_list_mismatch/1b4070f0 │
│ exit1_pass/ba20e26d               │
│ returncode_int_match/004772b0     │
└───────────────────────────────────┘
exit1_fail/b72ed665: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_fail/b72ed665/stage
exit1_fail/b72ed665: Running Test via command: bash exit1_fail_build.sh
exit1_fail/b72ed665: failed to submit job with returncode: 1
──────────────────── Error Message for exit1_fail/b72ed665 ─────────────────────

exit1_fail/b72ed665: Detected failure in running test, will attempt to retry test: 1 times
exit1_fail/b72ed665: Run - 1/1
exit1_fail/b72ed665: Running Test via command: bash exit1_fail_build.sh
exit1_fail/b72ed665: failed to submit job with returncode: 1
exit1_fail/b72ed665: Test completed in 0.014668 seconds with returncode: 1
exit1_fail/b72ed665: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_fail/b72ed665/exit1_fail.out
exit1_fail/b72ed665: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_fail/b72ed665/exit1_fail.err
returncode_list_mismatch/1b4070f0: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_list_mismatch/1b4070f0/stage
returncode_list_mismatch/1b4070f0: Running Test via command: bash returncode_list_mismatch_build.sh
returncode_list_mismatch/1b4070f0: failed to submit job with returncode: 2
───────────── Error Message for returncode_list_mismatch/1b4070f0 ──────────────

returncode_list_mismatch/1b4070f0: Detected failure in running test, will attempt to retry test: 1 times
returncode_list_mismatch/1b4070f0: Run - 1/1
returncode_list_mismatch/1b4070f0: Running Test via command: bash returncode_list_mismatch_build.sh
returncode_list_mismatch/1b4070f0: failed to submit job with returncode: 2
returncode_list_mismatch/1b4070f0: Test completed in 0.014182 seconds with returncode: 2
returncode_list_mismatch/1b4070f0: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_list_mismatch/1b4070f0/returncode_list_mismatch.out
returncode_list_mismatch/1b4070f0: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_list_mismatch/1b4070f0/returncode_list_mismatch.err
returncode_list_mismatch/1b4070f0: Checking returncode - 2 is matched in list [1, 3]
exit1_pass/ba20e26d: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_pass/ba20e26d/stage
exit1_pass/ba20e26d: Running Test via command: bash exit1_pass_build.sh
exit1_pass/ba20e26d: failed to submit job with returncode: 1
──────────────────── Error Message for exit1_pass/ba20e26d ─────────────────────

exit1_pass/ba20e26d: Detected failure in running test, will attempt to retry test: 1 times
exit1_pass/ba20e26d: Run - 1/1
exit1_pass/ba20e26d: Running Test via command: bash exit1_pass_build.sh
exit1_pass/ba20e26d: failed to submit job with returncode: 1
exit1_pass/ba20e26d: Test completed in 0.01436 seconds with returncode: 1
exit1_pass/ba20e26d: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_pass/ba20e26d/exit1_pass.out
exit1_pass/ba20e26d: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/exit1_pass/ba20e26d/exit1_pass.err
exit1_pass/ba20e26d: Checking returncode - 1 is matched in list [1]
returncode_int_match/004772b0: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_int_match/004772b0/stage
returncode_int_match/004772b0: Running Test via command: bash returncode_int_match_build.sh
returncode_int_match/004772b0: failed to submit job with returncode: 128
─────────────── Error Message for returncode_int_match/004772b0 ────────────────

returncode_int_match/004772b0: Detected failure in running test, will attempt to retry test: 1 times
returncode_int_match/004772b0: Run - 1/1
returncode_int_match/004772b0: Running Test via command: bash returncode_int_match_build.sh
returncode_int_match/004772b0: failed to submit job with returncode: 128
returncode_int_match/004772b0: Test completed in 0.014366 seconds with returncode: 128
returncode_int_match/004772b0: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_int_match/004772b0/returncode_int_match.out
returncode_int_match/004772b0: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/pass_returncode/returncode_int_match/004772b0/returncode_int_match.err
returncode_int_match/004772b0: Checking returncode - 128 is matched in list [128]
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ returncode_list_mismatc │ generic.local.bash │ FAIL   │ 2          │ 0.014   │
│ h/1b4070f0              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ exit1_fail/b72ed665     │ generic.local.bash │ FAIL   │ 1          │ 0.015   │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ exit1_pass/ba20e26d     │ generic.local.bash │ PASS   │ 1          │ 0.014   │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ returncode_int_match/00 │ generic.local.bash │ PASS   │ 128        │ 0.014   │
│ 4772b0                  │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/4 Percentage: 50.000%
Failed Tests: 2/4 Percentage: 50.000%


Adding 4 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_oumg69i8.log

The returncode field can be an integer or list of integers but it may not accept duplicate values. If you specify a list of exit codes, buildtest will check actual returncode with list of expected returncodes specified by returncode field.

Shown below are examples of invalid returncodes:

# empty list is not allowed
returncode: []

# floating point is not accepted in list
returncode: [1, 1.5]

# floating point not accepted
returncode: 1.5

# duplicates are not allowed
returncode: [1, 2, 5, 5]

Passing Test based on regular expression

buildtest can configure PASS/FAIL of test based on regular expression on output or error file. This can be useful if you are expecting a certain output from the test as pose to returncode check.

In this example we introduce, the regex field which is part of status that expects a regular expression via exp. The stream property must be stdout or stderr which indicates buildtest will read output or error file and apply regular expression. If there is a match, buildtest will record the test state as PASS otherwise it will be a FAIL. In this example, we have four tests that will apply two regular expression on output file and two regular expression on error file.

buildspecs:
  status_regex_stdout_pass:
    executor: generic.local.bash
    type: script
    tags: [system]
    description: Pass test based on regular expression
    run: echo "PASS"
    status:
      regex:
        stream: stdout
        exp: "^(PASS)$"

  status_regex_stdout_fail:
    executor: generic.local.bash
    type: script
    tags: [system]
    description: Pass test based on regular expression
    run: echo "FAIL"
    status:
      regex:
        stream: stdout
        exp: "^(123FAIL)$"

  status_regex_stderr_pass:
    executor: generic.local.bash
    type: script
    tags: [system]
    description: Pass test based on regular expression
    run: echo "PASS" 1>&2
    status:
      regex:
        stream: stderr
        exp: '^(PASS)$'

  status_regex_stderr_fail:
    executor: generic.local.bash
    type: script
    tags: [system]
    description: Pass test based on regular expression
    run: echo "FAIL" 1>&2
    status:
      regex:
        stream: stderr
        exp: "^(123FAIL)$"

Now if we run this test, we will see first test will pass while second one will fail even though the returncode is a 0. Take a close look at the status property

buildtest build -b tutorials/test_status/status_regex.yml
$ buildtest build -b tutorials/test_status/status_regex.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:41                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/status_regex.yml                                        ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/status_regex.yml: VALID
Total builder objects created: 4
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ status_r │ script │ generic. │ None     │ None  │ None  │ Pass     │ /home/d │
│ egex_std │        │ local.ba │          │       │       │ test     │ ocs/che │
│ out_pass │        │ sh       │          │       │       │ based on │ ckouts/ │
│ /76cc727 │        │          │          │       │       │ regular  │ readthe │
│ e        │        │          │          │       │       │ expressi │ docs.or │
│          │        │          │          │       │       │ on       │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/s │
│          │        │          │          │       │       │          │ tatus_r │
│          │        │          │          │       │       │          │ egex.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ status_r │ script │ generic. │ None     │ None  │ None  │ Pass     │ /home/d │
│ egex_std │        │ local.ba │          │       │       │ test     │ ocs/che │
│ out_fail │        │ sh       │          │       │       │ based on │ ckouts/ │
│ /728cbf0 │        │          │          │       │       │ regular  │ readthe │
│ 7        │        │          │          │       │       │ expressi │ docs.or │
│          │        │          │          │       │       │ on       │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/s │
│          │        │          │          │       │       │          │ tatus_r │
│          │        │          │          │       │       │          │ egex.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ status_r │ script │ generic. │ None     │ None  │ None  │ Pass     │ /home/d │
│ egex_std │        │ local.ba │          │       │       │ test     │ ocs/che │
│ err_pass │        │ sh       │          │       │       │ based on │ ckouts/ │
│ /be49e27 │        │          │          │       │       │ regular  │ readthe │
│ c        │        │          │          │       │       │ expressi │ docs.or │
│          │        │          │          │       │       │ on       │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/s │
│          │        │          │          │       │       │          │ tatus_r │
│          │        │          │          │       │       │          │ egex.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ status_r │ script │ generic. │ None     │ None  │ None  │ Pass     │ /home/d │
│ egex_std │        │ local.ba │          │       │       │ test     │ ocs/che │
│ err_fail │        │ sh       │          │       │       │ based on │ ckouts/ │
│ /b8b0b05 │        │          │          │       │       │ regular  │ readthe │
│ 8        │        │          │          │       │       │ expressi │ docs.or │
│          │        │          │          │       │       │ on       │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/s │
│          │        │          │          │       │       │          │ tatus_r │
│          │        │          │          │       │       │          │ egex.ym │
│          │        │          │          │       │       │          │ l       │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
status_regex_stdout_pass/76cc727e: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_pass/76cc727e
status_regex_stdout_fail/728cbf07: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_fail/728cbf07
status_regex_stderr_pass/be49e27c: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_pass/be49e27c
status_regex_stderr_fail/b8b0b058: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_fail/b8b0b058
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
status_regex_stderr_fail/b8b0b058 does not have any dependencies adding test to queue
status_regex_stderr_pass/be49e27c does not have any dependencies adding test to queue
status_regex_stdout_pass/76cc727e does not have any dependencies adding test to queue
status_regex_stdout_fail/728cbf07 does not have any dependencies adding test to queue
      Builders Eligible to Run       
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ status_regex_stderr_fail/b8b0b058 │
│ status_regex_stderr_pass/be49e27c │
│ status_regex_stdout_pass/76cc727e │
│ status_regex_stdout_fail/728cbf07 │
└───────────────────────────────────┘
status_regex_stderr_fail/b8b0b058: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_fail/b8b0b058/stage
status_regex_stderr_fail/b8b0b058: Running Test via command: bash status_regex_stderr_fail_build.sh
status_regex_stderr_fail/b8b0b058: Test completed in 0.00623 seconds with returncode: 0
status_regex_stderr_fail/b8b0b058: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_fail/b8b0b058/status_regex_stderr_fail.out
status_regex_stderr_fail/b8b0b058: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_fail/b8b0b058/status_regex_stderr_fail.err
status_regex_stderr_fail/b8b0b058: performing regular expression - '^(123FAIL)$' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_fail/b8b0b058/status_regex_stderr_fail.err
status_regex_stderr_fail/b8b0b058: Regular Expression Match - Failed!
status_regex_stderr_pass/be49e27c: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_pass/be49e27c/stage
status_regex_stderr_pass/be49e27c: Running Test via command: bash status_regex_stderr_pass_build.sh
status_regex_stderr_pass/be49e27c: Test completed in 0.006045 seconds with returncode: 0
status_regex_stderr_pass/be49e27c: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_pass/be49e27c/status_regex_stderr_pass.out
status_regex_stderr_pass/be49e27c: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_pass/be49e27c/status_regex_stderr_pass.err
status_regex_stderr_pass/be49e27c: performing regular expression - '^(PASS)$' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stderr_pass/be49e27c/status_regex_stderr_pass.err
status_regex_stderr_pass/be49e27c: Regular Expression Match - Success!
status_regex_stdout_pass/76cc727e: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_pass/76cc727e/stage
status_regex_stdout_pass/76cc727e: Running Test via command: bash status_regex_stdout_pass_build.sh
status_regex_stdout_pass/76cc727e: Test completed in 0.00581 seconds with returncode: 0
status_regex_stdout_pass/76cc727e: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_pass/76cc727e/status_regex_stdout_pass.out
status_regex_stdout_pass/76cc727e: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_pass/76cc727e/status_regex_stdout_pass.err
status_regex_stdout_pass/76cc727e: performing regular expression - '^(PASS)$' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_pass/76cc727e/status_regex_stdout_pass.out
status_regex_stdout_pass/76cc727e: Regular Expression Match - Success!
status_regex_stdout_fail/728cbf07: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_fail/728cbf07/stage
status_regex_stdout_fail/728cbf07: Running Test via command: bash status_regex_stdout_fail_build.sh
status_regex_stdout_fail/728cbf07: Test completed in 0.005623 seconds with returncode: 0
status_regex_stdout_fail/728cbf07: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_fail/728cbf07/status_regex_stdout_fail.out
status_regex_stdout_fail/728cbf07: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_fail/728cbf07/status_regex_stdout_fail.err
status_regex_stdout_fail/728cbf07: performing regular expression - '^(123FAIL)$' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/status_regex/status_regex_stdout_fail/728cbf07/status_regex_stdout_fail.out
status_regex_stdout_fail/728cbf07: Regular Expression Match - Failed!
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ status_regex_stdout_pas │ generic.local.bash │ PASS   │ 0          │ 0.006   │
│ s/76cc727e              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ status_regex_stderr_fai │ generic.local.bash │ FAIL   │ 0          │ 0.006   │
│ l/b8b0b058              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ status_regex_stderr_pas │ generic.local.bash │ PASS   │ 0          │ 0.006   │
│ s/be49e27c              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ status_regex_stdout_fai │ generic.local.bash │ FAIL   │ 0          │ 0.006   │
│ l/728cbf07              │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/4 Percentage: 50.000%
Failed Tests: 2/4 Percentage: 50.000%


Adding 4 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_us9r8esf.log

Specify Regular Expression on arbitrary filenames

In the previous example, we applied regular expression on output or error file; however, you may want to apply regular expression on arbitrary files. This can be done by specifying file_regex property. The file_regex property is an array of assertions, where each assertion must have filename and exp property. The filename property is the path to filename and exp is the regular expression you want to apply.

In this example, we have three tests that make use of file_regex property. The first test will perform a regular expression on multiple file names. The second test will attempt to check on a directory name which is not supported since regular expression must be applied to file name. The third test will show that variable expansion and environment variable expansion is supported.

buildspecs:
  regex_on_multiple_files:
    type: script
    executor: generic.local.bash
    description: Test regex on multiple files
    run: |
      echo "Hello" > hello.txt
      buildtest --help > buildtest_help.txt
    status:
      file_regex:
        - file: hello.txt
          exp: '^(Hello)$'
        - file: buildtest_help.txt
          exp: '^(usage: buildtest)'

  regex_on_directory_not_supported:
    type: script
    executor: generic.local.bash
    description: Test regex on directory is not supported
    run: |
      mkdir -p hello
      echo "Hello" > hello/hello.txt
    status:
      file_regex:
        - file: hello
          exp: '^(Hello)$'

  file_expansion_supported:
    type: script
    executor: generic.local.bash
    description: Test regex with variable and shell expansion
    run: |
      echo "Hello" > $BUILDTEST_ROOT/hello.txt
      echo "Hello" > $HOME/hello.txt
    status:
      file_regex:
        - file: $BUILDTEST_ROOT/hello.txt
          exp: '^(Hello)$'
        - file: ~/hello.txt
          exp: '^(Hello)$'

We can build this test by running the following command:

buildtest build -b tutorials/test_status/regex_on_filename.yml
$ buildtest build -b tutorials/test_status/regex_on_filename.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:41                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/regex_on_filename.yml                                   ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/regex_on_filename.yml: VALID
Total builder objects created: 3
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ regex_on │ script │ generic. │ None     │ None  │ None  │ Test     │ /home/d │
│ _multipl │        │ local.ba │          │       │       │ regex on │ ocs/che │
│ e_files/ │        │ sh       │          │       │       │ multiple │ ckouts/ │
│ f7b39a64 │        │          │          │       │       │ files    │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ egex_on │
│          │        │          │          │       │       │          │ _filena │
│          │        │          │          │       │       │          │ me.yml  │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ regex_on │ script │ generic. │ None     │ None  │ None  │ Test     │ /home/d │
│ _directo │        │ local.ba │          │       │       │ regex on │ ocs/che │
│ ry_not_s │        │ sh       │          │       │       │ director │ ckouts/ │
│ upported │        │          │          │       │       │ y is not │ readthe │
│ /dc235f3 │        │          │          │       │       │ supporte │ docs.or │
│ 9        │        │          │          │       │       │ d        │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ egex_on │
│          │        │          │          │       │       │          │ _filena │
│          │        │          │          │       │       │          │ me.yml  │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ file_exp │ script │ generic. │ None     │ None  │ None  │ Test     │ /home/d │
│ ansion_s │        │ local.ba │          │       │       │ regex    │ ocs/che │
│ upported │        │ sh       │          │       │       │ with     │ ckouts/ │
│ /0497df4 │        │          │          │       │       │ variable │ readthe │
│ 3        │        │          │          │       │       │ and      │ docs.or │
│          │        │          │          │       │       │ shell    │ g/user_ │
│          │        │          │          │       │       │ expansio │ builds/ │
│          │        │          │          │       │       │ n        │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ egex_on │
│          │        │          │          │       │       │          │ _filena │
│          │        │          │          │       │       │          │ me.yml  │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
regex_on_multiple_files/f7b39a64: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64
regex_on_directory_not_supported/dc235f39: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_directory_not_supported/dc235f39
file_expansion_supported/0497df43: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/file_expansion_supported/0497df43
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_expansion_supported/0497df43 does not have any dependencies adding test to queue
regex_on_directory_not_supported/dc235f39 does not have any dependencies adding test to queue
regex_on_multiple_files/f7b39a64 does not have any dependencies adding test to queue
          Builders Eligible to Run           
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                                   ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_expansion_supported/0497df43         │
│ regex_on_directory_not_supported/dc235f39 │
│ regex_on_multiple_files/f7b39a64          │
└───────────────────────────────────────────┘
file_expansion_supported/0497df43: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/file_expansion_supported/0497df43/stage
file_expansion_supported/0497df43: Running Test via command: bash file_expansion_supported_build.sh
file_expansion_supported/0497df43: Test completed in 0.006215 seconds with returncode: 0
file_expansion_supported/0497df43: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/file_expansion_supported/0497df43/file_expansion_supported.out
file_expansion_supported/0497df43: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/file_expansion_supported/0497df43/file_expansion_supported.err
file_expansion_supported/0497df43: Performing regex expression '^(Hello)$' on file /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/hello.txt
file_expansion_supported/0497df43: Regular expression on file /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/hello.txt is a MATCH!
file_expansion_supported/0497df43: Performing regex expression '^(Hello)$' on file /home/docs/hello.txt
file_expansion_supported/0497df43: Regular expression on file /home/docs/hello.txt is a MATCH!
regex_on_directory_not_supported/dc235f39: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_directory_not_supported/dc235f39/stage
regex_on_directory_not_supported/dc235f39: Running Test via command: bash regex_on_directory_not_supported_build.sh
regex_on_directory_not_supported/dc235f39: Test completed in 0.007654 seconds with returncode: 0
regex_on_directory_not_supported/dc235f39: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_directory_not_supported/dc235f39/regex_on_directory_not_supported.out
regex_on_directory_not_supported/dc235f39: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_directory_not_supported/dc235f39/regex_on_directory_not_supported.err
regex_on_directory_not_supported/dc235f39: File: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_directory_not_supported/dc235f39/stage/hello is not a file
regex_on_multiple_files/f7b39a64: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/stage
regex_on_multiple_files/f7b39a64: Running Test via command: bash regex_on_multiple_files_build.sh
regex_on_multiple_files/f7b39a64: Test completed in 0.508474 seconds with returncode: 0
regex_on_multiple_files/f7b39a64: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/regex_on_multiple_files.out
regex_on_multiple_files/f7b39a64: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/regex_on_multiple_files.err
regex_on_multiple_files/f7b39a64: Performing regex expression '^(Hello)$' on file /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/stage/hello.txt
regex_on_multiple_files/f7b39a64: Regular expression on file /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/stage/hello.txt is a MATCH!
regex_on_multiple_files/f7b39a64: Performing regex expression '^(usage: buildtest)' on file /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/stage/buildtest_help.txt
regex_on_multiple_files/f7b39a64: Regular expression on file /tmp/tmpq07_ocbs/var/tests/generic.local.bash/regex_on_filename/regex_on_multiple_files/f7b39a64/stage/buildtest_help.txt is a MATCH!
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_expansion_supporte │ generic.local.bash │ PASS   │ 0          │ 0.006   │
│ d/0497df43              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ regex_on_directory_not_ │ generic.local.bash │ FAIL   │ 0          │ 0.008   │
│ supported/dc235f39      │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ regex_on_multiple_files │ generic.local.bash │ PASS   │ 0          │ 0.508   │
│ /f7b39a64               │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/3 Percentage: 66.667%
Failed Tests: 1/3 Percentage: 33.333%


Adding 3 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_lm67vjxw.log

Passing Test based on runtime

buildtest can determine state of test based on runtime property which is part of status object. This can be used if you want to control how test PASS or FAIL based on execution time of test. In example below we have five tests that make use of runtime property for passing a test. The runtime property support min and max property that can mark test pass based on minimum and maximum runtime. A test will pass if it’s execution time is greater than min time and less than max time. If min is specified without max property the upperbound is not set, likewise max without min will pass if test is less than max time. The lower bound is not set, but test runtime will be greater than 0 sec.

In test timelimit_min, we sleep for 2 seconds and it will pass because minimum runtime is 1.0 seconds. Similarly, timelimit_max will pass because we sleep for 2 seconds with a max time of 5.0.

buildspecs:
  timelimit_min_max:
    type: script
    executor: generic.local.sh
    description: "Run a sleep job for 2 seconds and test pass if its within 1.0-3.0sec"
    tags: ["tutorials"]
    run: sleep 2
    status:
      runtime:
        min: 1.0
        max: 3.0

  timelimit_min:
    type: script
    executor: generic.local.sh
    description: "Run a sleep job for 2 seconds and test pass if its exceeds min time of 1.0 sec"
    tags: ["tutorials"]
    run: sleep 2
    status:
      runtime:
        min: 1.0

  timelimit_max:
    type: script
    executor: generic.local.sh
    description: "Run a sleep job for 2 seconds and test pass if it's within max time: 5.0 sec"
    tags: ["tutorials"]
    run: sleep 2
    status:
      runtime:
        max: 5.0

  timelimit_min_fail:
    type: script
    executor: generic.local.sh
    description: "This test fails because it runs less than mintime of 10 second"
    tags: ["tutorials"]
    run: sleep 2
    status:
      runtime:
        min: 10.0

  timelimit_max_fail:
    type: script
    executor: generic.local.sh
    description: "This test fails because it exceeds maxtime of 1.0 second"
    tags: ["tutorials"]
    run: sleep 3
    status:
      runtime:
        max: 1.0
buildtest build -b tutorials/test_status/runtime_status_test.yml
$ buildtest build -b tutorials/test_status/runtime_status_test.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:43                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/runtime_status_test.yml                                 ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/runtime_status_test.yml: VALID
Total builder objects created: 5
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ timelimi │ script │ generic. │ None     │ None  │ None  │ Run a    │ /home/d │
│ t_min_ma │        │ local.sh │          │       │       │ sleep    │ ocs/che │
│ x/ae52d8 │        │          │          │       │       │ job for  │ ckouts/ │
│ 77       │        │          │          │       │       │ 2        │ readthe │
│          │        │          │          │       │       │ seconds  │ docs.or │
│          │        │          │          │       │       │ and test │ g/user_ │
│          │        │          │          │       │       │ pass if  │ builds/ │
│          │        │          │          │       │       │ its      │ buildte │
│          │        │          │          │       │       │ within   │ st/chec │
│          │        │          │          │       │       │ 1.0-3.0s │ kouts/d │
│          │        │          │          │       │       │ ec       │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ untime_ │
│          │        │          │          │       │       │          │ status_ │
│          │        │          │          │       │       │          │ test.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ timelimi │ script │ generic. │ None     │ None  │ None  │ Run a    │ /home/d │
│ t_min/96 │        │ local.sh │          │       │       │ sleep    │ ocs/che │
│ eaca7a   │        │          │          │       │       │ job for  │ ckouts/ │
│          │        │          │          │       │       │ 2        │ readthe │
│          │        │          │          │       │       │ seconds  │ docs.or │
│          │        │          │          │       │       │ and test │ g/user_ │
│          │        │          │          │       │       │ pass if  │ builds/ │
│          │        │          │          │       │       │ its      │ buildte │
│          │        │          │          │       │       │ exceeds  │ st/chec │
│          │        │          │          │       │       │ min time │ kouts/d │
│          │        │          │          │       │       │ of 1.0   │ evel/tu │
│          │        │          │          │       │       │ sec      │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ untime_ │
│          │        │          │          │       │       │          │ status_ │
│          │        │          │          │       │       │          │ test.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ timelimi │ script │ generic. │ None     │ None  │ None  │ Run a    │ /home/d │
│ t_max/40 │        │ local.sh │          │       │       │ sleep    │ ocs/che │
│ 3d711d   │        │          │          │       │       │ job for  │ ckouts/ │
│          │        │          │          │       │       │ 2        │ readthe │
│          │        │          │          │       │       │ seconds  │ docs.or │
│          │        │          │          │       │       │ and test │ g/user_ │
│          │        │          │          │       │       │ pass if  │ builds/ │
│          │        │          │          │       │       │ it's     │ buildte │
│          │        │          │          │       │       │ within   │ st/chec │
│          │        │          │          │       │       │ max      │ kouts/d │
│          │        │          │          │       │       │ time:    │ evel/tu │
│          │        │          │          │       │       │ 5.0 sec  │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ untime_ │
│          │        │          │          │       │       │          │ status_ │
│          │        │          │          │       │       │          │ test.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ timelimi │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ t_min_fa │        │ local.sh │          │       │       │ test     │ ocs/che │
│ il/7bff2 │        │          │          │       │       │ fails    │ ckouts/ │
│ 900      │        │          │          │       │       │ because  │ readthe │
│          │        │          │          │       │       │ it runs  │ docs.or │
│          │        │          │          │       │       │ less     │ g/user_ │
│          │        │          │          │       │       │ than     │ builds/ │
│          │        │          │          │       │       │ mintime  │ buildte │
│          │        │          │          │       │       │ of 10    │ st/chec │
│          │        │          │          │       │       │ second   │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ untime_ │
│          │        │          │          │       │       │          │ status_ │
│          │        │          │          │       │       │          │ test.ym │
│          │        │          │          │       │       │          │ l       │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ timelimi │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ t_max_fa │        │ local.sh │          │       │       │ test     │ ocs/che │
│ il/0942f │        │          │          │       │       │ fails    │ ckouts/ │
│ aed      │        │          │          │       │       │ because  │ readthe │
│          │        │          │          │       │       │ it       │ docs.or │
│          │        │          │          │       │       │ exceeds  │ g/user_ │
│          │        │          │          │       │       │ maxtime  │ builds/ │
│          │        │          │          │       │       │ of 1.0   │ buildte │
│          │        │          │          │       │       │ second   │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/r │
│          │        │          │          │       │       │          │ untime_ │
│          │        │          │          │       │       │          │ status_ │
│          │        │          │          │       │       │          │ test.ym │
│          │        │          │          │       │       │          │ l       │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
timelimit_min_max/ae52d877: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_max/ae52d877
timelimit_min/96eaca7a: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min/96eaca7a
timelimit_max/403d711d: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max/403d711d
timelimit_min_fail/7bff2900: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_fail/7bff2900
timelimit_max_fail/0942faed: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max_fail/0942faed
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
timelimit_min/96eaca7a does not have any dependencies adding test to queue
timelimit_min_fail/7bff2900 does not have any dependencies adding test to queue
timelimit_min_max/ae52d877 does not have any dependencies adding test to queue
timelimit_max_fail/0942faed does not have any dependencies adding test to queue
timelimit_max/403d711d does not have any dependencies adding test to queue
   Builders Eligible to Run    
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                     ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ timelimit_min/96eaca7a      │
│ timelimit_min_fail/7bff2900 │
│ timelimit_min_max/ae52d877  │
│ timelimit_max_fail/0942faed │
│ timelimit_max/403d711d      │
└─────────────────────────────┘
timelimit_min/96eaca7a: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min/96eaca7a/stage
timelimit_min/96eaca7a: Running Test via command: bash timelimit_min_build.sh
timelimit_min/96eaca7a: Test completed in 2.006399 seconds with returncode: 0
timelimit_min/96eaca7a: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min/96eaca7a/timelimit_min.out
timelimit_min/96eaca7a: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min/96eaca7a/timelimit_min.err
timelimit_min/96eaca7a: Checking  mintime < runtime: 1.0 < 2.006399
timelimit_min_fail/7bff2900: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_fail/7bff2900/stage
timelimit_min_fail/7bff2900: Running Test via command: bash timelimit_min_fail_build.sh
timelimit_min_fail/7bff2900: Test completed in 2.006387 seconds with returncode: 0
timelimit_min_fail/7bff2900: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_fail/7bff2900/timelimit_min_fail.out
timelimit_min_fail/7bff2900: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_fail/7bff2900/timelimit_min_fail.err
timelimit_min_fail/7bff2900: Checking  mintime < runtime: 10.0 < 2.006387
timelimit_min_max/ae52d877: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_max/ae52d877/stage
timelimit_min_max/ae52d877: Running Test via command: bash timelimit_min_max_build.sh
timelimit_min_max/ae52d877: Test completed in 2.006636 seconds with returncode: 0
timelimit_min_max/ae52d877: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_max/ae52d877/timelimit_min_max.out
timelimit_min_max/ae52d877: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_min_max/ae52d877/timelimit_min_max.err
timelimit_min_max/ae52d877: Checking mintime < runtime < maxtime: 1.0 < 2.006636 < 3.0
timelimit_max_fail/0942faed: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max_fail/0942faed/stage
timelimit_max_fail/0942faed: Running Test via command: bash timelimit_max_fail_build.sh
timelimit_max_fail/0942faed: Test completed in 3.006666 seconds with returncode: 0
timelimit_max_fail/0942faed: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max_fail/0942faed/timelimit_max_fail.out
timelimit_max_fail/0942faed: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max_fail/0942faed/timelimit_max_fail.err
timelimit_max_fail/0942faed: Checking runtime < maxtime: 3.006666 < 1.0 
timelimit_max/403d711d: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max/403d711d/stage
timelimit_max/403d711d: Running Test via command: bash timelimit_max_build.sh
timelimit_max/403d711d: Test completed in 2.006987 seconds with returncode: 0
timelimit_max/403d711d: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max/403d711d/timelimit_max.out
timelimit_max/403d711d: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/runtime_status_test/timelimit_max/403d711d/timelimit_max.err
timelimit_max/403d711d: Checking runtime < maxtime: 2.006987 < 5.0 
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                   ┃ executor         ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ timelimit_max_fail/0942fa │ generic.local.sh │ FAIL   │ 0          │ 3.007   │
│ ed                        │                  │        │            │         │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ timelimit_max/403d711d    │ generic.local.sh │ PASS   │ 0          │ 2.007   │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ timelimit_min_fail/7bff29 │ generic.local.sh │ FAIL   │ 0          │ 2.006   │
│ 00                        │                  │        │            │         │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ timelimit_min/96eaca7a    │ generic.local.sh │ PASS   │ 0          │ 2.006   │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ timelimit_min_max/ae52d87 │ generic.local.sh │ PASS   │ 0          │ 2.007   │
│ 7                         │                  │        │            │         │
└───────────────────────────┴──────────────────┴────────┴────────────┴─────────┘



Passed Tests: 3/5 Percentage: 60.000%
Failed Tests: 2/5 Percentage: 40.000%


Adding 5 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_lopsf8cb.log

If we look at the test results, we expect the first three tests timelimit_min, timelimit_max, timelimit_min_max will pass while the last two tests fail because it fails to comply with runtime property.

buildtest report --filter buildspec=tutorials/test_status/runtime_status_test.yml --format name,id,state,runtime --latest
$ buildtest report --filter buildspec=tutorials/test_status/runtime_status_test.yml --format name,id,state,runtime --latest
                 Report File: /tmp/tmpq07_ocbs/var/report.json                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ name                           ┃ id             ┃ state      ┃ runtime       ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ timelimit_max_fail             │ 0942faed       │ FAIL       │ 3.006666      │
├────────────────────────────────┼────────────────┼────────────┼───────────────┤
│ timelimit_max                  │ 403d711d       │ PASS       │ 2.006987      │
├────────────────────────────────┼────────────────┼────────────┼───────────────┤
│ timelimit_min_fail             │ 7bff2900       │ FAIL       │ 2.006387      │
├────────────────────────────────┼────────────────┼────────────┼───────────────┤
│ timelimit_min                  │ 96eaca7a       │ PASS       │ 2.006399      │
├────────────────────────────────┼────────────────┼────────────┼───────────────┤
│ timelimit_min_max              │ ae52d877       │ PASS       │ 2.006636      │
└────────────────────────────────┴────────────────┴────────────┴───────────────┘

Explicitly Declaring Status of Test

You can explicitly define status of test regardless of what buildtest does for checking status of test. This can be useful if you want to explicitly mark a test as PASS or FAIL regardless of how test behaves. This can be done via state property which expects one of two types PASS or FAIL. If state property is specified, buildtest will ignore any checks including returncode, regex, or runtime match.

In this next example we will demonstrate how one can use state property for marking test state. In this example we have four tests. The first test always_pass will PASS even though we have a non-zero returncode. The second test always_fail will FAIL even though it has a 0 returncode. The last two test demonstrate how one can define state regardless of what is specified for returncode match. buildtest will honor the state property even if their is a match on the returncode.

buildspecs:
  always_pass:
    type: script
    executor: 'generic.local.sh'
    description: This test will always 'PASS'
    run: exit 1
    status:
      state: PASS

  always_fail:
    type: script
    executor: 'generic.local.sh'
    description: This test will always 'FAIL'
    run: exit 0
    status:
      state: FAIL

  test_fail_returncode_match:
    type: script
    executor: 'generic.local.sh'
    description: This test will 'FAIL' even if we have returncode match
    run: exit 1
    status:
      state: FAIL
      returncode: 1

  test_pass_returncode_mismatch:
    type: script
    executor: 'generic.local.sh'
    description: This test will 'PASS' even if we have returncode mismatch
    run: exit 1
    status:
      state: PASS
      returncode: 2

If we build this test, we expect buildtest to honor the value of state property

buildtest build -b tutorials/test_status/explicit_state.yml
$ buildtest build -b tutorials/test_status/explicit_state.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:55                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/explicit_state.yml                                      ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/explicit_state.yml: VALID
Total builder objects created: 4
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ always_p │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ ass/e763 │        │ local.sh │          │       │       │ test     │ ocs/che │
│ 0729     │        │          │          │       │       │ will     │ ckouts/ │
│          │        │          │          │       │       │ always   │ readthe │
│          │        │          │          │       │       │ 'PASS'   │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xplicit │
│          │        │          │          │       │       │          │ _state. │
│          │        │          │          │       │       │          │ yml     │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ always_f │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ ail/b2ba │        │ local.sh │          │       │       │ test     │ ocs/che │
│ 3ea6     │        │          │          │       │       │ will     │ ckouts/ │
│          │        │          │          │       │       │ always   │ readthe │
│          │        │          │          │       │       │ 'FAIL'   │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xplicit │
│          │        │          │          │       │       │          │ _state. │
│          │        │          │          │       │       │          │ yml     │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ test_fai │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ l_return │        │ local.sh │          │       │       │ test     │ ocs/che │
│ code_mat │        │          │          │       │       │ will     │ ckouts/ │
│ ch/82cc8 │        │          │          │       │       │ 'FAIL'   │ readthe │
│ 63f      │        │          │          │       │       │ even if  │ docs.or │
│          │        │          │          │       │       │ we have  │ g/user_ │
│          │        │          │          │       │       │ returnco │ builds/ │
│          │        │          │          │       │       │ de match │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xplicit │
│          │        │          │          │       │       │          │ _state. │
│          │        │          │          │       │       │          │ yml     │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ test_pas │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ s_return │        │ local.sh │          │       │       │ test     │ ocs/che │
│ code_mis │        │          │          │       │       │ will     │ ckouts/ │
│ match/00 │        │          │          │       │       │ 'PASS'   │ readthe │
│ 5f4039   │        │          │          │       │       │ even if  │ docs.or │
│          │        │          │          │       │       │ we have  │ g/user_ │
│          │        │          │          │       │       │ returnco │ builds/ │
│          │        │          │          │       │       │ de       │ buildte │
│          │        │          │          │       │       │ mismatch │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xplicit │
│          │        │          │          │       │       │          │ _state. │
│          │        │          │          │       │       │          │ yml     │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
always_pass/e7630729: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_pass/e7630729
always_fail/b2ba3ea6: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_fail/b2ba3ea6
test_fail_returncode_match/82cc863f: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_fail_returncode_match/82cc863f
test_pass_returncode_mismatch/005f4039: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_pass_returncode_mismatch/005f4039
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
always_pass/e7630729 does not have any dependencies adding test to queue
always_fail/b2ba3ea6 does not have any dependencies adding test to queue
test_fail_returncode_match/82cc863f does not have any dependencies adding test to queue
test_pass_returncode_mismatch/005f4039 does not have any dependencies adding test to queue
         Builders Eligible to Run         
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                                ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ always_pass/e7630729                   │
│ always_fail/b2ba3ea6                   │
│ test_fail_returncode_match/82cc863f    │
│ test_pass_returncode_mismatch/005f4039 │
└────────────────────────────────────────┘
always_pass/e7630729: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_pass/e7630729/stage
always_pass/e7630729: Running Test via command: bash always_pass_build.sh
always_pass/e7630729: failed to submit job with returncode: 1
──────────────────── Error Message for always_pass/e7630729 ────────────────────

always_pass/e7630729: Detected failure in running test, will attempt to retry test: 1 times
always_pass/e7630729: Run - 1/1
always_pass/e7630729: Running Test via command: bash always_pass_build.sh
always_pass/e7630729: failed to submit job with returncode: 1
always_pass/e7630729: Test completed in 0.013714 seconds with returncode: 1
always_pass/e7630729: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_pass/e7630729/always_pass.out
always_pass/e7630729: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_pass/e7630729/always_pass.err
always_fail/b2ba3ea6: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_fail/b2ba3ea6/stage
always_fail/b2ba3ea6: Running Test via command: bash always_fail_build.sh
always_fail/b2ba3ea6: Test completed in 0.004813 seconds with returncode: 0
always_fail/b2ba3ea6: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_fail/b2ba3ea6/always_fail.out
always_fail/b2ba3ea6: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/always_fail/b2ba3ea6/always_fail.err
test_fail_returncode_match/82cc863f: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_fail_returncode_match/82cc863f/stage
test_fail_returncode_match/82cc863f: Running Test via command: bash test_fail_returncode_match_build.sh
test_fail_returncode_match/82cc863f: failed to submit job with returncode: 1
──────────── Error Message for test_fail_returncode_match/82cc863f ─────────────

test_fail_returncode_match/82cc863f: Detected failure in running test, will attempt to retry test: 1 times
test_fail_returncode_match/82cc863f: Run - 1/1
test_fail_returncode_match/82cc863f: Running Test via command: bash test_fail_returncode_match_build.sh
test_fail_returncode_match/82cc863f: failed to submit job with returncode: 1
test_fail_returncode_match/82cc863f: Test completed in 0.013081 seconds with returncode: 1
test_fail_returncode_match/82cc863f: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_fail_returncode_match/82cc863f/test_fail_returncode_match.out
test_fail_returncode_match/82cc863f: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_fail_returncode_match/82cc863f/test_fail_returncode_match.err
test_pass_returncode_mismatch/005f4039: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_pass_returncode_mismatch/005f4039/stage
test_pass_returncode_mismatch/005f4039: Running Test via command: bash test_pass_returncode_mismatch_build.sh
test_pass_returncode_mismatch/005f4039: failed to submit job with returncode: 1
─────────── Error Message for test_pass_returncode_mismatch/005f4039 ───────────

test_pass_returncode_mismatch/005f4039: Detected failure in running test, will attempt to retry test: 1 times
test_pass_returncode_mismatch/005f4039: Run - 1/1
test_pass_returncode_mismatch/005f4039: Running Test via command: bash test_pass_returncode_mismatch_build.sh
test_pass_returncode_mismatch/005f4039: failed to submit job with returncode: 1
test_pass_returncode_mismatch/005f4039: Test completed in 0.013256 seconds with returncode: 1
test_pass_returncode_mismatch/005f4039: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_pass_returncode_mismatch/005f4039/test_pass_returncode_mismatch.out
test_pass_returncode_mismatch/005f4039: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.sh/explicit_state/test_pass_returncode_mismatch/005f4039/test_pass_returncode_mismatch.err
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                   ┃ executor         ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ always_fail/b2ba3ea6      │ generic.local.sh │ FAIL   │ 0          │ 0.005   │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ test_pass_returncode_mism │ generic.local.sh │ PASS   │ 1          │ 0.013   │
│ atch/005f4039             │                  │        │            │         │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ test_fail_returncode_matc │ generic.local.sh │ FAIL   │ 1          │ 0.013   │
│ h/82cc863f                │                  │        │            │         │
├───────────────────────────┼──────────────────┼────────┼────────────┼─────────┤
│ always_pass/e7630729      │ generic.local.sh │ PASS   │ 1          │ 0.014   │
└───────────────────────────┴──────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/4 Percentage: 50.000%
Failed Tests: 2/4 Percentage: 50.000%


Adding 4 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_p6q0e9i5.log

File Checks

buildtest supports various file checks that can be used as means for passing test. This can include checking for File Existence, File and Directory Checks, Symbolic Link Check, and File Count.

File Existence

For instance, if you want to check for file existence, you can use exists property which expects a list of file or directory names to check. This can be useful if your test will write some output file or directory and test will pass based on existence of file/directory.

In the example below we have two tests, first test will pass, where all files exist. We check for files and directory path, note variable and shell expansion is supported.

In the second example, we expect this test to fail because filename bar does not exist.

buildspecs:
  status_exists:
    type: script
    executor: generic.local.bash
    description: status check based for file and directory
    run: |
      mkdir -p $HOME/dirA
      mkdir -p /tmp/ABC
      touch file1
    status:
      exists:
        - $HOME/dirA
        - ~/.bashrc
        - /tmp/ABC
        - file1
  status_exists_failure:
    type: script
    executor: generic.local.bash
    description: status check failure for existence
    run: touch foo
    status:
      exists:
        - bar

We can run this test by running the following, take note of the output.

buildtest build -b tutorials/test_status/exists.yml
$ buildtest build -b tutorials/test_status/exists.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:56                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/exists.yml                                              ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/exists.yml: VALID
Total builder objects created: 2
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ status_e │ script │ generic. │ None     │ None  │ None  │ status   │ /home/d │
│ xists/00 │        │ local.ba │          │       │       │ check    │ ocs/che │
│ 98ecc3   │        │ sh       │          │       │       │ based    │ ckouts/ │
│          │        │          │          │       │       │ for file │ readthe │
│          │        │          │          │       │       │ and      │ docs.or │
│          │        │          │          │       │       │ director │ g/user_ │
│          │        │          │          │       │       │ y        │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xists.y │
│          │        │          │          │       │       │          │ ml      │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ status_e │ script │ generic. │ None     │ None  │ None  │ status   │ /home/d │
│ xists_fa │        │ local.ba │          │       │       │ check    │ ocs/che │
│ ilure/ee │        │ sh       │          │       │       │ failure  │ ckouts/ │
│ 42eda9   │        │          │          │       │       │ for      │ readthe │
│          │        │          │          │       │       │ existenc │ docs.or │
│          │        │          │          │       │       │ e        │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/e │
│          │        │          │          │       │       │          │ xists.y │
│          │        │          │          │       │       │          │ ml      │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
status_exists/0098ecc3: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists/0098ecc3
status_exists_failure/ee42eda9: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists_failure/ee42eda9
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
status_exists/0098ecc3 does not have any dependencies adding test to queue
status_exists_failure/ee42eda9 does not have any dependencies adding test to queue
     Builders Eligible to Run     
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                        ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ status_exists/0098ecc3         │
│ status_exists_failure/ee42eda9 │
└────────────────────────────────┘
status_exists/0098ecc3: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists/0098ecc3/stage
status_exists/0098ecc3: Running Test via command: bash status_exists_build.sh
status_exists/0098ecc3: Test completed in 0.009248 seconds with returncode: 0
status_exists/0098ecc3: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists/0098ecc3/status_exists.out
status_exists/0098ecc3: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists/0098ecc3/status_exists.err
status_exists/0098ecc3: Test all files:  ['$HOME/dirA', '~/.bashrc', '/tmp/ABC', 'file1']  existences
status_exists/0098ecc3: file: /home/docs/dirA exists
status_exists/0098ecc3: file: /home/docs/.bashrc exists
status_exists/0098ecc3: file: /tmp/ABC exists
status_exists/0098ecc3: file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists/0098ecc3/stage/file1 exists
status_exists/0098ecc3: Exist Check: True
status_exists_failure/ee42eda9: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists_failure/ee42eda9/stage
status_exists_failure/ee42eda9: Running Test via command: bash status_exists_failure_build.sh
status_exists_failure/ee42eda9: Test completed in 0.006826 seconds with returncode: 0
status_exists_failure/ee42eda9: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists_failure/ee42eda9/status_exists_failure.out
status_exists_failure/ee42eda9: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/exists/status_exists_failure/ee42eda9/status_exists_failure.err
status_exists_failure/ee42eda9: Test all files:  ['bar']  existences 
status_exists_failure/ee42eda9: file: bar does not exist
status_exists_failure/ee42eda9: Exist Check: False
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ status_exists/0098ecc3  │ generic.local.bash │ PASS   │ 0          │ 0.009   │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ status_exists_failure/e │ generic.local.bash │ FAIL   │ 0          │ 0.007   │
│ e42eda9                 │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/2 Percentage: 50.000%
Failed Tests: 1/2 Percentage: 50.000%


Adding 2 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_gh5ix6bp.log

Each item in the exists field must be a string, which can lead to issue in example below let’s assume we want a test to pass based on a directory name 1, if we specify as follows, this test will fail validation.

buildspecs:
  file_exists_failure:
   type: script
   executor: generic.local.bash
   description: this test will fail validation, because item must be a string
   run: mkdir -p 1
   status:
     exists: [1]

We can validate this buildspec by running the following

buildtest bc validate -b tutorials/test_status/file_exists_exception.yml
$ buildtest bc validate -b tutorials/test_status/file_exists_exception.yml
─ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/… ─
1 is not of type 'string'

Failed validating 'type' in schema['properties']['status']['properties']['exists']['items']:
    {'type': 'string'}

On instance['status']['exists'][0]:
    1


1 buildspecs failed to validate

In order to run this test, we need to enclose each item in quotes. Shown below is the same test with quotations.

buildspecs:
  file_exists_pass:
    type: script
    executor: generic.local.bash
    description: this test will pass
    run: mkdir -p 1
    status:
      exists: [ '1' ]

Let’s validate and build this test.

buildtest bc validate -b tutorials/test_status/file_exists_with_number.yml
$ buildtest bc validate -b tutorials/test_status/file_exists_with_number.yml
buildspec: /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_exists_with_number.yml is valid
All buildspecs passed validation!!!
buildtest build -b tutorials/test_status/file_exists_with_number.yml
$ buildtest build -b tutorials/test_status/file_exists_with_number.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:57                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_exists_with_number.yml                             ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_exists_with_number.yml: VALID
Total builder objects created: 1
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_exi │ script │ generic. │ None     │ None  │ None  │ this     │ /home/d │
│ sts_pass │        │ local.ba │          │       │       │ test     │ ocs/che │
│ /b3025a2 │        │ sh       │          │       │       │ will     │ ckouts/ │
│ 2        │        │          │          │       │       │ pass     │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_exi │
│          │        │          │          │       │       │          │ sts_wit │
│          │        │          │          │       │       │          │ h_numbe │
│          │        │          │          │       │       │          │ r.yml   │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_exists_pass/b3025a22: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_exists_with_number/file_exists_pass/b3025a22
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_exists_pass/b3025a22 does not have any dependencies adding test to queue
  Builders Eligible to Run   
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                   ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_exists_pass/b3025a22 │
└───────────────────────────┘
file_exists_pass/b3025a22: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_exists_with_number/file_exists_pass/b3025a22/stage
file_exists_pass/b3025a22: Running Test via command: bash file_exists_pass_build.sh
file_exists_pass/b3025a22: Test completed in 0.007404 seconds with returncode: 0
file_exists_pass/b3025a22: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_exists_with_number/file_exists_pass/b3025a22/file_exists_pass.out
file_exists_pass/b3025a22: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_exists_with_number/file_exists_pass/b3025a22/file_exists_pass.err
file_exists_pass/b3025a22: Test all files:  ['1']  existences 
file_exists_pass/b3025a22: file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_exists_with_number/file_exists_pass/b3025a22/stage/1 exists
file_exists_pass/b3025a22: Exist Check: True
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_exists_pass/b3025a │ generic.local.bash │ PASS   │ 0          │ 0.007   │
│ 22                      │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/1 Percentage: 100.000%
Failed Tests: 0/1 Percentage: 0.000%


Adding 1 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_377epqi9.log

File and Directory Checks

In the next example, we introduce checks for files and directory via is_file and is_dir property, which behaves similar to exists except they will check if each item is a file or directory. We expect the first test to fail, because $HOME/.bashrc is not a directory but a file. The second test will incorporate the same test and use is_file for status check.

buildspecs:
  file_and_dir_checks:
    type: script
    executor: generic.local.bash
    description: status check for files and directories
    run: hostname
    status:
      is_dir:
        - $HOME
        - $HOME/.bashrc
        - /tmp
  combined_file_and_dir_checks:
    type: script
    executor: generic.local.bash
    description: status check for files and directories
    run: hostname
    status:
      is_dir:
        - $HOME
        - /tmp
      is_file:
        - $HOME/.bashrc

Let’s build the test and see the output.

buildtest build -b tutorials/test_status/file_and_dir_check.yml
$ buildtest build -b tutorials/test_status/file_and_dir_check.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:58                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_and_dir_check.yml                                  ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_and_dir_check.yml: VALID
Total builder objects created: 2
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_and │ script │ generic. │ None     │ None  │ None  │ status   │ /home/d │
│ _dir_che │        │ local.ba │          │       │       │ check    │ ocs/che │
│ cks/a241 │        │ sh       │          │       │       │ for      │ ckouts/ │
│ 2758     │        │          │          │       │       │ files    │ readthe │
│          │        │          │          │       │       │ and      │ docs.or │
│          │        │          │          │       │       │ director │ g/user_ │
│          │        │          │          │       │       │ ies      │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_and │
│          │        │          │          │       │       │          │ _dir_ch │
│          │        │          │          │       │       │          │ eck.yml │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ combined │ script │ generic. │ None     │ None  │ None  │ status   │ /home/d │
│ _file_an │        │ local.ba │          │       │       │ check    │ ocs/che │
│ d_dir_ch │        │ sh       │          │       │       │ for      │ ckouts/ │
│ ecks/c8a │        │          │          │       │       │ files    │ readthe │
│ c8a63    │        │          │          │       │       │ and      │ docs.or │
│          │        │          │          │       │       │ director │ g/user_ │
│          │        │          │          │       │       │ ies      │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_and │
│          │        │          │          │       │       │          │ _dir_ch │
│          │        │          │          │       │       │          │ eck.yml │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_and_dir_checks/a2412758: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/file_and_dir_checks/a2412758
combined_file_and_dir_checks/c8ac8a63: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/combined_file_and_dir_checks/c8ac8a63
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_and_dir_checks/a2412758 does not have any dependencies adding test to queue
combined_file_and_dir_checks/c8ac8a63 does not have any dependencies adding test to queue
        Builders Eligible to Run         
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                               ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_and_dir_checks/a2412758          │
│ combined_file_and_dir_checks/c8ac8a63 │
└───────────────────────────────────────┘
file_and_dir_checks/a2412758: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/file_and_dir_checks/a2412758/stage
file_and_dir_checks/a2412758: Running Test via command: bash file_and_dir_checks_build.sh
file_and_dir_checks/a2412758: Test completed in 0.008077 seconds with returncode: 0
file_and_dir_checks/a2412758: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/file_and_dir_checks/a2412758/file_and_dir_checks.out
file_and_dir_checks/a2412758: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/file_and_dir_checks/a2412758/file_and_dir_checks.err
file_and_dir_checks/a2412758: Test all files:  ['$HOME', '$HOME/.bashrc', '/tmp']  existences
file_and_dir_checks/a2412758: file: /home/docs is a directory 
file_and_dir_checks/a2412758: file: $HOME/.bashrc is not a directory
file_and_dir_checks/a2412758: file: /tmp is a directory 
file_and_dir_checks/a2412758: Directory Existence Check: False
combined_file_and_dir_checks/c8ac8a63: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/combined_file_and_dir_checks/c8ac8a63/stage
combined_file_and_dir_checks/c8ac8a63: Running Test via command: bash combined_file_and_dir_checks_build.sh
combined_file_and_dir_checks/c8ac8a63: Test completed in 0.006406 seconds with returncode: 0
combined_file_and_dir_checks/c8ac8a63: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/combined_file_and_dir_checks/c8ac8a63/combined_file_and_dir_checks.out
combined_file_and_dir_checks/c8ac8a63: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_and_dir_check/combined_file_and_dir_checks/c8ac8a63/combined_file_and_dir_checks.err
combined_file_and_dir_checks/c8ac8a63: Test all files:  ['$HOME', '/tmp']  existences
combined_file_and_dir_checks/c8ac8a63: file: /home/docs is a directory 
combined_file_and_dir_checks/c8ac8a63: file: /tmp is a directory 
combined_file_and_dir_checks/c8ac8a63: Directory Existence Check: True
combined_file_and_dir_checks/c8ac8a63: Test all files:  ['$HOME/.bashrc']  existences
combined_file_and_dir_checks/c8ac8a63: file: /home/docs/.bashrc is a file 
combined_file_and_dir_checks/c8ac8a63: File Existence Check: True
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ combined_file_and_dir_c │ generic.local.bash │ PASS   │ 0          │ 0.006   │
│ hecks/c8ac8a63          │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ file_and_dir_checks/a24 │ generic.local.bash │ FAIL   │ 0          │ 0.008   │
│ 12758                   │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/2 Percentage: 50.000%
Failed Tests: 1/2 Percentage: 50.000%


Adding 2 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_81oz2kig.log

File Count

buildtest can check for number of files in a directory. This can be useful if your test writes number of files and you want to check if the number of files is as expected. You can use the file_count property to perform file count. This property is a list of assertion, where each item is an object. The dir and count are required keys.

The dir is the path to directory to perform directory traversal, and count key is the number of expected files that will be used for comparison. In the first test, we perform a directory walk and expect 5 files in the directory. We can perform directory search based on file extension by using ext key. The ext property can be a string or a list. The second test will perform directory walk on directory named foo and search for file extensions .sh, .py, .txt. The depth property controls the maximum depth for directory traversal, this must be of an integer type. The depth property is optional and if not specified, we will perform full directory traversal.

buildspecs:
  file_count_on_directory:
    type: script
    executor: generic.local.bash
    description: file count check in directory
    run: |
      mkdir -p foo
      touch foo/{1..5}
    status:
      file_count:
        - dir: foo
          count: 5
  file_count_by_extension:
    type: script
    executor: generic.local.bash
    description: file count by extension
    run: |
      mkdir -p foo/bar
      touch foo/{1..5}.sh
      touch foo/bar/{1..3}.py foo/bar/{1..3}.txt
    status:
      file_count:
        - dir: foo
          ext: '.sh'
          depth: 1
          count: 5
        - dir: foo/bar
          ext: ['.py', '.txt']
          count: 6

We can run this test by running the following.

buildtest build -b tutorials/test_status/file_count.yml
$ buildtest build -b tutorials/test_status/file_count.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:29:59                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_count.yml                                          ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_count.yml: VALID
Total builder objects created: 2
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_cou │ script │ generic. │ None     │ None  │ None  │ file     │ /home/d │
│ nt_on_di │        │ local.ba │          │       │       │ count    │ ocs/che │
│ rectory/ │        │ sh       │          │       │       │ check in │ ckouts/ │
│ e42e9af7 │        │          │          │       │       │ director │ readthe │
│          │        │          │          │       │       │ y        │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt.yml  │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ file_cou │ script │ generic. │ None     │ None  │ None  │ file     │ /home/d │
│ nt_by_ex │        │ local.ba │          │       │       │ count by │ ocs/che │
│ tension/ │        │ sh       │          │       │       │ extensio │ ckouts/ │
│ 7bab9b79 │        │          │          │       │       │ n        │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt.yml  │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_count_on_directory/e42e9af7: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_on_directory/e42e9af7
file_count_by_extension/7bab9b79: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_count_by_extension/7bab9b79 does not have any dependencies adding test to queue
file_count_on_directory/e42e9af7 does not have any dependencies adding test to queue
      Builders Eligible to Run      
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_count_by_extension/7bab9b79 │
│ file_count_on_directory/e42e9af7 │
└──────────────────────────────────┘
file_count_by_extension/7bab9b79: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79/stage
file_count_by_extension/7bab9b79: Running Test via command: bash file_count_by_extension_build.sh
file_count_by_extension/7bab9b79: Test completed in 0.009464 seconds with returncode: 0
file_count_by_extension/7bab9b79: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79/file_count_by_extension.out
file_count_by_extension/7bab9b79: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79/file_count_by_extension.err
file_count_by_extension/7bab9b79: Found 5 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79/stage/foo. Comparing with reference count: 5. Comparison check is 5 == 5 which evaluates to True
file_count_by_extension/7bab9b79: Found 6 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_by_extension/7bab9b79/stage/foo/bar. Comparing with reference count: 6. Comparison check is 6 == 6 which evaluates to True
file_count_by_extension/7bab9b79: File Count Check: True
file_count_on_directory/e42e9af7: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_on_directory/e42e9af7/stage
file_count_on_directory/e42e9af7: Running Test via command: bash file_count_on_directory_build.sh
file_count_on_directory/e42e9af7: Test completed in 0.008019 seconds with returncode: 0
file_count_on_directory/e42e9af7: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_on_directory/e42e9af7/file_count_on_directory.out
file_count_on_directory/e42e9af7: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_on_directory/e42e9af7/file_count_on_directory.err
file_count_on_directory/e42e9af7: Found 5 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count/file_count_on_directory/e42e9af7/stage/foo. Comparing with reference count: 5. Comparison check is 5 == 5 which evaluates to True
file_count_on_directory/e42e9af7: File Count Check: True
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_count_on_directory │ generic.local.bash │ PASS   │ 0          │ 0.008   │
│ /e42e9af7               │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ file_count_by_extension │ generic.local.bash │ PASS   │ 0          │ 0.009   │
│ /7bab9b79               │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/2 Percentage: 100.000%
Failed Tests: 0/2 Percentage: 0.000%


Adding 2 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_1vywbjk4.log

In the next example, we introduce filepattern property which allows you to check for files based on a pattern. The filepattern property is a regular expression which is compiled via re.compile and applied to a directory path. Please note the regular expression must be valid, otherwise buildtest will not return any files during directory traversal.

You can use filepattern and ext property together to search for files. If both are specified, then we will search for files with both methods and join the two list prior to performing comparison.

buildspecs:
  file_count_by_expression:
    type: script
    executor: generic.local.bash
    description: file count by expression
    run: |
      mkdir -p /tmp
      touch /tmp/foo{1..5}.txt
      ls -l /tmp/foo*.txt
      filenames=$(find $BUILDTEST_ROOT/buildtest -type f  \( -name "defaults.py" -o -name "main.py" \) -maxdepth 1)
      totalfiles=$(find $BUILDTEST_ROOT/buildtest -type f  \( -name "defaults.py" -o -name "main.py" \) -maxdepth 1 | wc -l)
      echo "Filenames: $filenames"
      echo "Total files: $totalfiles"
    status:
      file_count:
        - dir: /tmp
          filepattern: 'foo[1-5].txt$'
          count: 5
        - dir: '$BUILDTEST_ROOT/buildtest'
          filepattern: '(defaults|main).py$'
          count: 2
          depth: 1

  file_extension_and_filepattern:
    type: script
    executor: generic.local.bash
    description: file count by file extension and file pattern
    run: |
      touch foo{1..5}.txt
      touch {conf,main}.py
      ls -l
    status:
      file_count:
        - dir: .
          ext: '.txt'
          filepattern: '(conf|main).py$'
          count: 7

Let’s build this test by running the following:

buildtest build -b tutorials/test_status/file_count_pattern.yml
$ buildtest build -b tutorials/test_status/file_count_pattern.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:00                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_count_pattern.yml                                  ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_count_pattern.yml: VALID
Total builder objects created: 2
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_cou │ script │ generic. │ None     │ None  │ None  │ file     │ /home/d │
│ nt_by_ex │        │ local.ba │          │       │       │ count by │ ocs/che │
│ pression │        │ sh       │          │       │       │ expressi │ ckouts/ │
│ /3c4ee1e │        │          │          │       │       │ on       │ readthe │
│ a        │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt_patt │
│          │        │          │          │       │       │          │ ern.yml │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ file_ext │ script │ generic. │ None     │ None  │ None  │ file     │ /home/d │
│ ension_a │        │ local.ba │          │       │       │ count by │ ocs/che │
│ nd_filep │        │ sh       │          │       │       │ file     │ ckouts/ │
│ attern/c │        │          │          │       │       │ extensio │ readthe │
│ 64f7039  │        │          │          │       │       │ n and    │ docs.or │
│          │        │          │          │       │       │ file     │ g/user_ │
│          │        │          │          │       │       │ pattern  │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt_patt │
│          │        │          │          │       │       │          │ ern.yml │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_count_by_expression/3c4ee1ea: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_count_by_expression/3c4ee1ea
file_extension_and_filepattern/c64f7039: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_extension_and_filepattern/c64f7039
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_extension_and_filepattern/c64f7039 does not have any dependencies adding test to queue
file_count_by_expression/3c4ee1ea does not have any dependencies adding test to queue
         Builders Eligible to Run          
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                                 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_extension_and_filepattern/c64f7039 │
│ file_count_by_expression/3c4ee1ea       │
└─────────────────────────────────────────┘
file_extension_and_filepattern/c64f7039: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_extension_and_filepattern/c64f7039/stage
file_extension_and_filepattern/c64f7039: Running Test via command: bash file_extension_and_filepattern_build.sh
file_extension_and_filepattern/c64f7039: Test completed in 0.012072 seconds with returncode: 0
file_extension_and_filepattern/c64f7039: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_extension_and_filepattern/c64f7039/file_extension_and_filepattern.out
file_extension_and_filepattern/c64f7039: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_extension_and_filepattern/c64f7039/file_extension_and_filepattern.err
file_extension_and_filepattern/c64f7039: Found 7 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_extension_and_filepattern/c64f7039/stage. Comparing with reference count: 7. Comparison check is 7 == 7 which evaluates to True
file_extension_and_filepattern/c64f7039: File Count Check: True
file_count_by_expression/3c4ee1ea: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_count_by_expression/3c4ee1ea/stage
file_count_by_expression/3c4ee1ea: Running Test via command: bash file_count_by_expression_build.sh
file_count_by_expression/3c4ee1ea: Test completed in 0.013617 seconds with returncode: 0
file_count_by_expression/3c4ee1ea: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_count_by_expression/3c4ee1ea/file_count_by_expression.out
file_count_by_expression/3c4ee1ea: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_pattern/file_count_by_expression/3c4ee1ea/file_count_by_expression.err
file_count_by_expression/3c4ee1ea: Found 10 file in directory: /tmp. Comparing with reference count: 5. Comparison check is 10 == 5 which evaluates to False
file_count_by_expression/3c4ee1ea: Found 2 file in directory: /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/buildtest. Comparing with reference count: 2. Comparison check is 2 == 2 which evaluates to True
file_count_by_expression/3c4ee1ea: File Count Check: False
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_count_by_expressio │ generic.local.bash │ FAIL   │ 0          │ 0.014   │
│ n/3c4ee1ea              │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ file_extension_and_file │ generic.local.bash │ PASS   │ 0          │ 0.012   │
│ pattern/c64f7039        │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/2 Percentage: 50.000%
Failed Tests: 1/2 Percentage: 50.000%


Adding 2 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_96un7_wx.log

In the next example, we will introduce filetype property that can be used to filter directory search based on file type. The filetype property can one of the following values file, dir, symlink. Once set, the directory traversal will seek out files based on the file type. Note that when filetype is set to dir we will return the parent directory and all sub-directories. This test will create a few subdirectories and create symbolic link, next we will perform directory search by directory and symbolic link. We expect this test to pass as we will find 3 directories and 2 symbolic links.

buildspecs:
  file_count_by_filetype:
    type: script
    executor: generic.local.bash
    description: Count the number of directories and symbolic links
    run: |
      mkdir -p foo/{bar,baz}
      find foo -type dir
      ln -s foo/bar foo/bar.link
      ln -s foo/baz foo/baz.link
    status:
      file_count:
        - dir: foo
          count: 3
          filetype: 'dir'
        - dir: foo
          count: 2
          filetype: 'symlink'

Let’s build this test by running the following:

buildtest build -b tutorials/test_status/file_count_filetype.yml
$ buildtest build -b tutorials/test_status/file_count_filetype.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:00                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_count_filetype.yml                                 ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_count_filetype.yml: VALID
Total builder objects created: 1
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_cou │ script │ generic. │ None     │ None  │ None  │ Count    │ /home/d │
│ nt_by_fi │        │ local.ba │          │       │       │ the      │ ocs/che │
│ letype/e │        │ sh       │          │       │       │ number   │ ckouts/ │
│ 274aa36  │        │          │          │       │       │ of       │ readthe │
│          │        │          │          │       │       │ director │ docs.or │
│          │        │          │          │       │       │ ies and  │ g/user_ │
│          │        │          │          │       │       │ symbolic │ builds/ │
│          │        │          │          │       │       │ links    │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt_file │
│          │        │          │          │       │       │          │ type.ym │
│          │        │          │          │       │       │          │ l       │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_count_by_filetype/e274aa36: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_count_by_filetype/e274aa36 does not have any dependencies adding test to queue
     Builders Eligible to Run      
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                         ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_count_by_filetype/e274aa36 │
└─────────────────────────────────┘
file_count_by_filetype/e274aa36: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36/stage
file_count_by_filetype/e274aa36: Running Test via command: bash file_count_by_filetype_build.sh
file_count_by_filetype/e274aa36: failed to submit job with returncode: 1
────────────── Error Message for file_count_by_filetype/e274aa36 ───────────────
find: Must separate multiple arguments to -type using: ','

file_count_by_filetype/e274aa36: Detected failure in running test, will attempt to retry test: 1 times
file_count_by_filetype/e274aa36: Run - 1/1
file_count_by_filetype/e274aa36: Running Test via command: bash file_count_by_filetype_build.sh
file_count_by_filetype/e274aa36: failed to submit job with returncode: 1
file_count_by_filetype/e274aa36: Test completed in 0.022261 seconds with returncode: 1
file_count_by_filetype/e274aa36: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36/file_count_by_filetype.out
file_count_by_filetype/e274aa36: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36/file_count_by_filetype.err
file_count_by_filetype/e274aa36: Found 3 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36/stage/foo. Comparing with reference count: 3. Comparison check is 3 == 3 which evaluates to True
file_count_by_filetype/e274aa36: Found 0 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_filetype/file_count_by_filetype/e274aa36/stage/foo. Comparing with reference count: 2. Comparison check is 0 == 2 which evaluates to False
file_count_by_filetype/e274aa36: File Count Check: False
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_count_by_filetype/ │ generic.local.bash │ FAIL   │ 1          │ 0.022   │
│ e274aa36                │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 0/1 Percentage: 0.000%
Failed Tests: 1/1 Percentage: 100.000%


Adding 1 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_yo5kh_25.log

Buildtest will perform a directory walk when using file_count, which can run into performance issues if you have a large directory. We have added a safety check during directory traversal to a maximum of 999999 files. You have the option to configure the directory traversal limit using file_traversal_limit which is an integer, the default value is 10000 if not specified. The minimum value and maximum value can be 1 and 999999 respectively.

In this next example, we will illustrate how this feature works. We will create 99 .txt files in directory foo. We will perform two assertions with different values for file_traversal_limit. In the first example, we will set this to 50 and expect 50 files returned. We expect this check to be True. In the next example, we will set file_traversal_limit to 20 and set count: 10 where we should expect a failure. In principle, we should retrieve 20 files but this will mismatch the comparison check.

buildspecs:
  file_traverse_limit:
    type: script
    executor: generic.local.bash
    description: Use of file_traverse_limit to limit number of files searched in a directory
    run: |
      mkdir foo
      touch foo/{1..99}.txt
    status:
      file_count:
        - dir: foo
          count: 50
          file_traverse_limit: 50
        - dir: foo
          count: 10
          file_traverse_limit: 20

We can try building this test by running the following:

buildtest build -b tutorials/test_status/file_count_file_traverse_limit.yml
$ buildtest build -b tutorials/test_status/file_count_file_traverse_limit.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:01                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/file_count_file_traverse_limit.yml                      ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/file_count_file_traverse_limit.yml: VALID
Total builder objects created: 1
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ file_tra │ script │ generic. │ None     │ None  │ None  │ Use of   │ /home/d │
│ verse_li │        │ local.ba │          │       │       │ file_tra │ ocs/che │
│ mit/4ba1 │        │ sh       │          │       │       │ verse_li │ ckouts/ │
│ ffd5     │        │          │          │       │       │ mit to   │ readthe │
│          │        │          │          │       │       │ limit    │ docs.or │
│          │        │          │          │       │       │ number   │ g/user_ │
│          │        │          │          │       │       │ of files │ builds/ │
│          │        │          │          │       │       │ searched │ buildte │
│          │        │          │          │       │       │ in a     │ st/chec │
│          │        │          │          │       │       │ director │ kouts/d │
│          │        │          │          │       │       │ y        │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/f │
│          │        │          │          │       │       │          │ ile_cou │
│          │        │          │          │       │       │          │ nt_file │
│          │        │          │          │       │       │          │ _traver │
│          │        │          │          │       │       │          │ se_limi │
│          │        │          │          │       │       │          │ t.yml   │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
file_traverse_limit/4ba1ffd5: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
file_traverse_limit/4ba1ffd5 does not have any dependencies adding test to queue
    Builders Eligible to Run    
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                      ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_traverse_limit/4ba1ffd5 │
└──────────────────────────────┘
file_traverse_limit/4ba1ffd5: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5/stage
file_traverse_limit/4ba1ffd5: Running Test via command: bash file_traverse_limit_build.sh
file_traverse_limit/4ba1ffd5: Test completed in 0.009973 seconds with returncode: 0
file_traverse_limit/4ba1ffd5: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5/file_traverse_limit.out
file_traverse_limit/4ba1ffd5: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5/file_traverse_limit.err
file_traverse_limit/4ba1ffd5: Found 50 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5/stage/foo. Comparing with reference count: 50. Comparison check is 50 == 50 which evaluates to True
file_traverse_limit/4ba1ffd5: Found 20 file in directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/file_count_file_traverse_limit/file_traverse_limit/4ba1ffd5/stage/foo. Comparing with reference count: 10. Comparison check is 20 == 10 which evaluates to False
file_traverse_limit/4ba1ffd5: File Count Check: False
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ file_traverse_limit/4ba │ generic.local.bash │ FAIL   │ 0          │ 0.010   │
│ 1ffd5                   │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 0/1 Percentage: 0.000%
Failed Tests: 1/1 Percentage: 100.000%


Adding 1 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_tv7rnayd.log

Status Mode

By default, the status check performed by buildtest is a logical OR, where if any of the status check is True, then the test will PASS. However, if you want to change this behavior to logical AND, you can use the mode property. The valid values can be [AND, and, OR, or]. In the example below, we have two tests that illustrate the use of mode.

buildspecs:
  status_logical_and:
    type: script
    executor: 'generic.local.bash'
    description: 'Using logical AND to check status'
    run: |
      echo "This is a test"
      exit 1
    status:
      mode: and
      returncode: 1
      regex:
        stream: stdout
        exp: 'This is a test'

  status_logical_or:
    type: script
    executor: 'generic.local.bash'
    description: 'Using logical OR to check status'
    run: |
      echo "This is a test"
      exit 1
    status:
      mode: or
      returncode: 0
      regex:
        stream: stdout
        exp: 'This is a test'

The first test uses mode: and which implies all status check are evaluated as logical AND, we expect this test to PASS. In the second test, we use mode: or where status check are evaluated as logical OR which is the default behavior. Note if mode is not specified, it is equivalent to mode: or. In second test, we expect this to pass because regex check will PASS however, the returncode check will fail due to mismatch in returncode. If we changed this to mode: and then we would expect this test to fail.

Shown below is the output of running this test.

buildtest build -b tutorials/test_status/mode.yml
$ buildtest build -b tutorials/test_status/mode.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:02                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/test_status/mode.yml                                                ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/test_status/mode.yml: VALID
Total builder objects created: 2
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ status_l │ script │ generic. │ None     │ None  │ None  │ Using    │ /home/d │
│ ogical_a │        │ local.ba │          │       │       │ logical  │ ocs/che │
│ nd/bf930 │        │ sh       │          │       │       │ AND to   │ ckouts/ │
│ ad6      │        │          │          │       │       │ check    │ readthe │
│          │        │          │          │       │       │ status   │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/m │
│          │        │          │          │       │       │          │ ode.yml │
├──────────┼────────┼──────────┼──────────┼───────┼───────┼──────────┼─────────┤
│ status_l │ script │ generic. │ None     │ None  │ None  │ Using    │ /home/d │
│ ogical_o │        │ local.ba │          │       │       │ logical  │ ocs/che │
│ r/fde2eb │        │ sh       │          │       │       │ OR to    │ ckouts/ │
│ 59       │        │          │          │       │       │ check    │ readthe │
│          │        │          │          │       │       │ status   │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /test_s │
│          │        │          │          │       │       │          │ tatus/m │
│          │        │          │          │       │       │          │ ode.yml │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
status_logical_and/bf930ad6: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_and/bf930ad6
status_logical_or/fde2eb59: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_or/fde2eb59
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
status_logical_and/bf930ad6 does not have any dependencies adding test to queue
status_logical_or/fde2eb59 does not have any dependencies adding test to queue
   Builders Eligible to Run    
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Builder                     ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ status_logical_and/bf930ad6 │
│ status_logical_or/fde2eb59  │
└─────────────────────────────┘
status_logical_and/bf930ad6: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_and/bf930ad6/stage
status_logical_and/bf930ad6: Running Test via command: bash status_logical_and_build.sh
status_logical_and/bf930ad6: failed to submit job with returncode: 1
──────────────── Error Message for status_logical_and/bf930ad6 ─────────────────

status_logical_and/bf930ad6: Detected failure in running test, will attempt to retry test: 1 times
status_logical_and/bf930ad6: Run - 1/1
status_logical_and/bf930ad6: Running Test via command: bash status_logical_and_build.sh
status_logical_and/bf930ad6: failed to submit job with returncode: 1
status_logical_and/bf930ad6: Test completed in 0.015943 seconds with returncode: 1
status_logical_and/bf930ad6: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_and/bf930ad6/status_logical_and.out
status_logical_and/bf930ad6: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_and/bf930ad6/status_logical_and.err
status_logical_and/bf930ad6: Checking returncode - 1 is matched in list [1]
status_logical_and/bf930ad6: performing regular expression - 'This is a test' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_and/bf930ad6/status_logical_and.out
status_logical_and/bf930ad6: Regular Expression Match - Success!
status_logical_or/fde2eb59: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_or/fde2eb59/stage
status_logical_or/fde2eb59: Running Test via command: bash status_logical_or_build.sh
status_logical_or/fde2eb59: failed to submit job with returncode: 1
───────────────── Error Message for status_logical_or/fde2eb59 ─────────────────

status_logical_or/fde2eb59: Detected failure in running test, will attempt to retry test: 1 times
status_logical_or/fde2eb59: Run - 1/1
status_logical_or/fde2eb59: Running Test via command: bash status_logical_or_build.sh
status_logical_or/fde2eb59: failed to submit job with returncode: 1
status_logical_or/fde2eb59: Test completed in 0.015346 seconds with returncode: 1
status_logical_or/fde2eb59: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_or/fde2eb59/status_logical_or.out
status_logical_or/fde2eb59: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_or/fde2eb59/status_logical_or.err
status_logical_or/fde2eb59: Checking returncode - 1 is matched in list [0]
status_logical_or/fde2eb59: performing regular expression - 'This is a test' on file: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/mode/status_logical_or/fde2eb59/status_logical_or.out
status_logical_or/fde2eb59: Regular Expression Match - Success!
                                  Test Summary                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder                 ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ status_logical_or/fde2e │ generic.local.bash │ PASS   │ 1          │ 0.015   │
│ b59                     │                    │        │            │         │
├─────────────────────────┼────────────────────┼────────┼────────────┼─────────┤
│ status_logical_and/bf93 │ generic.local.bash │ PASS   │ 1          │ 0.016   │
│ 0ad6                    │                    │        │            │         │
└─────────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 2/2 Percentage: 100.000%
Failed Tests: 0/2 Percentage: 0.000%


Adding 2 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_xt2piul7.log

Skipping test

By default, buildtest will run all tests defined in buildspecs section, if you want to skip a test use the skip field which expects a boolean value. Shown below is an example test.

buildspecs:
  skip:
    type: script
    executor: generic.local.bash
    description: This test is skipped
    skip: Yes
    tags: [tutorials]
    run: hostname

  unskipped:
    type: script
    executor: generic.local.bash
    description: This test is not skipped
    skip: No
    tags: [tutorials]
    run: hostname

The first test skip will be ignored by buildtest because skip: true is defined while unskipped will be processed as usual.

Note

YAML and JSON have different representation for boolean. For json schema valid values are true and false see https://json-schema.org/understanding-json-schema/reference/boolean.html however YAML has many more representation for boolean see https://yaml.org/type/bool.html. You may use any of the YAML boolean, however it’s best to stick with json schema values true and false.

Here is an example build, notice message [skip] test is skipped during the build stage

buildtest build -b tutorials/skip_tests.yml
$ buildtest build -b tutorials/skip_tests.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:02                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/skip_tests.yml                                                      ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
skip: skipping test due to 'skip' property.
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/skip_tests.yml: VALID
Total builder objects created: 1
                            Builders by type=script                             
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
┃          ┃        ┃          ┃          ┃       ┃       ┃ descript ┃ buildsp ┃
┃ builder  ┃ type   ┃ executor ┃ compiler ┃ nodes ┃ procs ┃ ion      ┃ ecs     ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
│ unskippe │ script │ generic. │ None     │ None  │ None  │ This     │ /home/d │
│ d/8302c8 │        │ local.ba │          │       │       │ test is  │ ocs/che │
│ 2e       │        │ sh       │          │       │       │ not      │ ckouts/ │
│          │        │          │          │       │       │ skipped  │ readthe │
│          │        │          │          │       │       │          │ docs.or │
│          │        │          │          │       │       │          │ g/user_ │
│          │        │          │          │       │       │          │ builds/ │
│          │        │          │          │       │       │          │ buildte │
│          │        │          │          │       │       │          │ st/chec │
│          │        │          │          │       │       │          │ kouts/d │
│          │        │          │          │       │       │          │ evel/tu │
│          │        │          │          │       │       │          │ torials │
│          │        │          │          │       │       │          │ /skip_t │
│          │        │          │          │       │       │          │ ests.ym │
│          │        │          │          │       │       │          │ l       │
└──────────┴────────┴──────────┴──────────┴───────┴───────┴──────────┴─────────┘
──────────────────────────────── Building Test ─────────────────────────────────
unskipped/8302c82e: Creating Test Directory: /tmp/tmpq07_ocbs/var/tests/generic.local.bash/skip_tests/unskipped/8302c82e
──────────────────────────────── Running Tests ─────────────────────────────────
Spawning 1 processes for processing builders
───────────────────────────────── Iteration 1 ──────────────────────────────────
unskipped/8302c82e does not have any dependencies adding test to queue
Builders Eligible to Run
┏━━━━━━━━━━━━━━━━━━━━┓
┃ Builder            ┃
┡━━━━━━━━━━━━━━━━━━━━┩
│ unskipped/8302c82e │
└────────────────────┘
unskipped/8302c82e: Current Working Directory : /tmp/tmpq07_ocbs/var/tests/generic.local.bash/skip_tests/unskipped/8302c82e/stage
unskipped/8302c82e: Running Test via command: bash unskipped_build.sh
unskipped/8302c82e: Test completed in 0.006879 seconds with returncode: 0
unskipped/8302c82e: Writing output file -  /tmp/tmpq07_ocbs/var/tests/generic.local.bash/skip_tests/unskipped/8302c82e/unskipped.out
unskipped/8302c82e: Writing error file - /tmp/tmpq07_ocbs/var/tests/generic.local.bash/skip_tests/unskipped/8302c82e/unskipped.err
                               Test Summary                                
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┓
┃ builder            ┃ executor           ┃ status ┃ returncode ┃ runtime ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━┩
│ unskipped/8302c82e │ generic.local.bash │ PASS   │ 0          │ 0.007   │
└────────────────────┴────────────────────┴────────┴────────────┴─────────┘



Passed Tests: 1/1 Percentage: 100.000%
Failed Tests: 0/1 Percentage: 0.000%


Adding 1 test results to /tmp/tmpq07_ocbs/var/report.json
Writing Logfile to /tmp/tmpq07_ocbs/var/logs/buildtest_nfo_j3m2.log

Skipping a buildspec

Sometimes you may want to skip all test in a buildspec instead of updating every test with skip property, this can be done by setting skip at the top-level. This can be useful if you are running several test in a directory such as buildtest build -b dir1/ and you don’t want to explicitly exclude file via -x option every time, instead you can hardcode this into the buildspec. A typical use-case of skipping test is when a test is broken and you don’t want to run it then its good idea to set skip: yes on the buildspec and fix it later.

In this next example we set skip: yes, buildtest will skip the buildspec and no test will be processed even if skip is set in each test.

skip: yes
buildspecs:
  skip_all_tests:
    type: script
    executor: generic.local.bash
    description: "All test in this buildspec are skipped"
    tags: [tutorials]
    run: hostname

  this_test_is_also_skipped:
    type: script
    skip: no
    executor: generic.local.bash
    description: "This test is also skipped even if skip is defined in test"
    tags: [ tutorials ]
    run: hostname

If you try building this buildspec, you will see buildtest will skip the buildspec and terminate.

buildtest build -b tutorials/skip_buildspec.yml
$ buildtest build -b tutorials/skip_buildspec.yml
╭───────────────────────────── buildtest summary ──────────────────────────────╮
│                                                                              │
│ User:               docs                                                     │
│ Hostname:           build-23532485-project-280831-buildtest                  │
│ Platform:           Linux                                                    │
│ Current Time:       2024/02/22 20:30:03                                      │
│ buildtest path:     /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ buildtest version:  1.8                                                      │
│ python path:        /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│ python version:     3.8.18                                                   │
│ Configuration File: /tmp/tmpq07_ocbs/config.yml                              │
│ Test Directory:     /tmp/tmpq07_ocbs/var/tests                               │
│ Report File:        /tmp/tmpq07_ocbs/var/report.json                         │
│ Command:            /home/docs/checkouts/readthedocs.org/user_builds/buildte │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
───────────────────────────  Discovering Buildspecs ────────────────────────────
                             Discovered buildspecs                              
╔══════════════════════════════════════════════════════════════════════════════╗
║ buildspec                                                                    ║
╟──────────────────────────────────────────────────────────────────────────────╢
║ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/t ║
║ utorials/skip_buildspec.yml                                                  ║
╚══════════════════════════════════════════════════════════════════════════════╝


Total Discovered Buildspecs:  1
Total Excluded Buildspecs:  0
Detected Buildspecs after exclusion:  1
────────────────────────────── Parsing Buildspecs ──────────────────────────────
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/skip_buildspec.yml: skipping all test since 'skip' is defined
Valid Buildspecs: 1
Invalid Buildspecs: 0
/home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/tutorials/skip_buildspec.yml: VALID
                            Buildspecs Filtered out                             
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ buildspecs                                                                   ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ /home/docs/checkouts/readthedocs.org/user_builds/buildtest/checkouts/devel/… │
└──────────────────────────────────────────────────────────────────────────────┘

buildtest is unable to create any tests because there are no valid buildspecs. 

Please see logfile: /tmp/tmpq07_ocbs/var/buildtest.log