Skip to content

Comments

ENT-13699: Add shell test framework and migrate all tests#304

Open
larsewi wants to merge 50 commits intocfengine:masterfrom
larsewi:ENT-13699/shell-test-framework
Open

ENT-13699: Add shell test framework and migrate all tests#304
larsewi wants to merge 50 commits intocfengine:masterfrom
larsewi:ENT-13699/shell-test-framework

Conversation

@larsewi
Copy link
Contributor

@larsewi larsewi commented Feb 17, 2026

Summary

  • Added tests/shell/testlib.sh with lifecycle functions (test_init, test_finish, skip_unless_unsafe), assertion helpers (assert_file_exists, assert_file_contains, assert_failure, assert_equal, etc.), and capture utilities (run, run_expect_failure)
  • Updated tests/shell/all.sh runner with per-test timing, pass/fail/skip reporting, and summary output
  • Migrated all 47 shell tests to use the new framework, eliminating repeated boilerplate
  • Consolidated common.sh git helpers into testlib.sh as assert_git_tracks and assert_git_no_diffs

🤖 Generated with Claude Code

Example output:

$ bash tests/shell/all.sh
Warning: These shell based tests use the cfbs you have installed
         If you haven't already, run: pip install .
--- PASS: 001_init (2s)
--- PASS: 002_add (2s)
--- PASS: 003_download (2s)
--- PASS: 004_build (12s)
--- PASS: 005_alias (3s)
--- PASS: 006_search (2s)
--- SKIP: 007_install (0s)
--- PASS: 008_remove (2s)
 ---snip---
--- PASS: 047_absolute_path_modules (4s)

==============================
Test Results: 46 passed, 0 failed, 1 skipped (total: 47, 156s)
==============================
All cfbs shell tests completed successfully!

If a test fails it will look like this:

$ bash tests/shell/all.sh
Warning: These shell based tests use the cfbs you have installed
         If you haven't already, run: pip install .
--- FAIL: 001_init (6s)
++ _test_name_from_path tests/shell/001_init.sh
++ basename tests/shell/001_init.sh .sh
+ _TEST_NAME=001_init
+ rm -rf ./tests/tmp/
+ mkdir -p ./tests/tmp/
+ cd ./tests/tmp/
++ date +%s
+ _TEST_START_TIME=1771345070
+ echo '--- START: 001_init ---'
--- START: 001_init ---
+ cfbs --non-interactive init
Initialized empty Git repository in /home/larsewi/ntech/cfbs/tests/tmp/.git/
[main (root-commit) bcfc025] Initialized a new CFEngine Build project
 1 file changed, 7 insertions(+)
 create mode 100644 cfbs.json
[main d75f629] Added module 'masterfiles'
 1 file changed, 16 insertions(+), 1 deletion(-)
Committing using git:


Initialized an empty project called 'Example project' in 'cfbs.json'
Added module: masterfiles
Committing using git:


+ assert_file_exists cfbs.json
+ '[' -e cfbs.json ']'
+ false
---
--- PASS: 002_add (2s)
--- PASS: 003_download (4s)
 ---snip---

larsewi and others added 30 commits February 17, 2026 16:28
Introduced tests/shell/testlib.sh with lifecycle functions (test_init,
test_finish, skip_unless_unsafe), assertion helpers, and capture utilities
for gradual migration of shell tests. Updated tests/shell/all.sh to report
per-test timing, pass/fail/skip status, and a summary.

Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… and assert_git_no_diffs

Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
larsewi and others added 20 commits February 17, 2026 16:28
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticket: ENT-13699
Signed-off-by: Lars Erik Wik <lars.erik.wik@northern.tech>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@larsewi larsewi force-pushed the ENT-13699/shell-test-framework branch from ba33364 to de17ea3 Compare February 17, 2026 15:29
@larsewi
Copy link
Contributor Author

larsewi commented Feb 17, 2026

@cf-bottom Jenkins please :)

@cf-bottom
Copy link

Copy link
Contributor

@craigcomstock craigcomstock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't say I love this PR. There is a lot of change and now the scripts can't be written free-hand in bash... you must refer to the testlib often to know what functions to use.

Also, I am not sure how much is improved other than maybe silencing "good" outputs to make analysis easier... which is a welcome change so +1 on that account.

I think all the migrated commits could be squashed into one for easier review... #next-time

_failed=$((_failed + 1))
_failures="${_failures} ${test_name}\n"
echo "--- FAIL: $test_name (${elapsed}s)"
echo "$output" | tail -30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to debug fully it would be nice to save the complete output to an artifacts directory that is then slurped up and archived with the github workflow.

# --- Lifecycle ---

skip_unless_unsafe() {
if [ "x${UNSAFE_TESTS:-}" != x1 ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is shellcheck running on this? It should complain about x-prefix comparisons that are not generally needed.

! grep -qF "$2" "$1" || _test_fail "Expected file '$1' to NOT contain: $2"
}

assert_file_matches() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert_file_matches_regex() would be more descriptive... I was thinking "entire file match" as-is.

|| _test_fail "Expected files to differ but they are identical: $1 vs $2"
}

assert_count() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe assert_string_occurrences() to be clear: not a regex (string instead) and check the number of matches.

{
reports:
"Hello from $(this.bundle)";
"Hello from \$(this.bundle)";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change? The result of the change would add a prefixed backslash for no reason right?

R: Hello from \foo

{
reports:
"Hello from $(this.bundle)";
"Hello from \$(this.bundle)";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably don't need this prefixed backslash in the output.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and at no time are we testing the output of this policy so pretty inconsequential either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants