Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drl 59/implement shellspec #23

Merged
merged 5 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: lint
name: lint-and-test

on: [push]

Expand All @@ -22,3 +22,22 @@ jobs:
else
echo "No shell scripts with #!/bin/sh shebang found."
fi

test:
name: Run shellspec
runs-on: ubuntu-latest

steps:
- name: Install shellspec
run: |
cd ~
wget https://github.com/shellspec/shellspec/archive/0.28.1.tar.gz
tar xzvf 0.28.1.tar.gz
mkdir ~/.local/bin
ln -s ~/shellspec-0.28.1/bin/shellspec ~/.local/bin/

- name: Check out code
uses: actions/checkout@v4

- name: Run shellspec
run: shellspec
12 changes: 12 additions & 0 deletions .shellspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--require spec_helper

## Default kcov (coverage) options
# --kcov-options "--include-path=. --path-strip-level=1"
# --kcov-options "--include-pattern=.sh"
# --kcov-options "--exclude-pattern=/.shellspec,/spec/,/coverage/,/report/"

## Example: Include script "myprog" with no extension
# --kcov-options "--include-pattern=.sh,myprog"

## Example: Only specified files/directories
# --kcov-options "--include-pattern=myprog,/lib/"
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ To configure healthchecks via `crontab -e`, add the following in your editor of
*/2 * * * * /etc/cron.d/restart-actions.sh
```

Development
-----------

### Testing
This project uses [`shellspec`](https://github.com/shellspec/shellspec) as a test framework. To run tests locally, `shellspec` must first be installed on the local system according to the `shellspec` [installation guide](https://github.com/shellspec/shellspec?tab=readme-ov-file#installation).

Tests are defined in the `spec` directory, and are all files matching the pattern `<suite_name>_spec.sh`. Mocks, custom matchers and other fixtures can be defined in the `spec/support` directory.

The `pot` mock has already been defined and is imported into all tests. By default, all `pot` subcommands return truthy with no side effects, but these can be overloaded on a per-subcommand basis, as each subcommand has its own stub function. See [here](spec/simple_spec.sh#L47) for an example of overloading the `pot exec` subcommand, and [here](spec/support/pot_mock.sh#L5) for a list of all subcommand stubs that can be overloaded.

Wrapper scripts to run GitHub actions in a jail on FreeBSD
----------------------------------------------------------
Expand Down
70 changes: 70 additions & 0 deletions spec/simple_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#shellcheck shell=bash

Describe 'check-pots.sh'
Include ./check-pots.sh
prepare() { pot='test'; }
Before 'prepare'

Describe 'check_tree()'
It 'Does not output a warning if the given tree exists'
tree_name='some_tree'
mkdir $tree_name
When call check_tree $tree_name
The output should not include 'was not found'
rm -fr $tree_name
End

It 'Outputs a warning if the given tree does not exist'
tree_name='some_tree'
When call check_tree $tree_name
The output should include 'was not found'
End

It 'Outputs a debug message if the given tree is empty'
tree_name='some_tree'
mkdir $tree_name
When call check_tree 'some_tree'
The output should include 'is empty'
rm -fr $tree_name
End

It 'Has no output if the tree is populated'
tree_name='some_tree'
mkdir $tree_name
touch ${tree_name}/abc
When call check_tree 'some_tree'
The output should be blank
rm -fr $tree_name
End
End

Describe 'check_pot()'
It 'Should emit a warning if sshd is disabled'
check_tree() { :; }
pot_exec() {
case $3 in
sysrc) echo 'NO';;
which) echo '/usr/sbin/pkg64';;
esac
}
When call check_pot
The lines of output should equal 1
The output should include 'sshd is disabled on'
End

It 'Should emit a warning if pkg binaries cannot be found'
check_tree() { :; }
pot_exec() {
case $3 in
sysrc) echo '';;
which) echo '';;
esac
}
When call check_pot
The lines of output should equal 3
The line 1 of output should include "pkg64 on $pot was not found"
The line 2 of output should include "pkg64c on $pot was not found"
The line 3 of output should include "pk64cb on $pot was not found"
End
End
End
24 changes: 24 additions & 0 deletions spec/spec_helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# shellcheck shell=sh

# Defining variables and functions here will affect all specfiles.
# Change shell options inside a function may cause different behavior,
# so it is better to set them here.
# set -eu

# This callback function will be invoked only once before loading specfiles.
spec_helper_precheck() {
# Available functions: info, warn, error, abort, setenv, unsetenv
# Available variables: VERSION, SHELL_TYPE, SHELL_VERSION
: minimum_version "0.28.1"
}

# This callback function will be invoked after a specfile has been loaded.
spec_helper_loaded() {
:
}

# This callback function will be invoked after core modules has been loaded.
spec_helper_configure() {
# Available functions: import, before_each, after_each, before_all, after_all
import 'support/pot_mock'
}
61 changes: 61 additions & 0 deletions spec/support/pot_mock.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# shellcheck shell=sh

pot() {
case $1 in
help) fn='pot_help';;
version) fn='pot_version';;
config) fn='pot_config';;
ls|list) fn='pot_list';;
show) fn='pot_show';;
info) fn='pot_info';;
top) fn='pot_top';;
ps) fn='pot_ps';;
init) fn='pot_init';;
de-init) fn='pot_de_init';;
vnet-start) fn='pot_vnet_start';;
create-base) fn='pot_create_base';;
create-fscomp) fn='pot_create_fscomp';;
create-private-bridge) fn='pot_create_private_bridge';;
create) fn='pot_create';;
clone) fn='pot_clone';;
clone-fscomp) fn='pot_clone_fscomp';;
rename) fn='pot_rename';;
destroy) fn='pot_destroy';;
prune) fn='pot_prune';;
copy-in) fn='pot_copy_in';;
copy-out) fn='pot_copy_out';;
mount-in) fn='pot_mount_in';;
mount-out) fn='pot_mount_out';;
add-dep) fn='pot_add_dep';;
set-rss) fn='pot_set_rss';;
get-rss) fn='pot_get_rss';;
set-cmd) fn='pot_set_cmd';;
set-env) fn='pot_set_env';;
set-hosts) fn='pot_set_hosts';;
set-hook) fn='pot_set_hook';;
set-attribute|set-attr) fn='pot_set_attribute';;
get-attribute|get-attr) fn='pot_get_attribute';;
export-ports) fn='pot_export_ports';;
start) fn='pot_start';;
stop) fn='pot_stop';;
term) fn='pot_term';;
run) fn='pot_run';;
snap|snapshot) fn='pot_snapshot';;
rollback|revert) fn='pot_revert';;
purge-snapshots) fn='pot_purge_snapshots';;
export) fn='pot_export';;
import) fn='pot_import';;
prepare) fn='pot_prepare';;
update-config) fn='pot_update_config';;
last-run-stats) fn='pot_last_run_stats';;
signal) fn='pot_signal';;
exec) fn='pot_exec';;
*) fn='pot_other';;
esac
shift 1
if type "$fn" 2>/dev/null | grep -q 'function'; then
$fn "$@"
else
:
fi
}