From f9431439d073b43ce70b90bc80bf8dc21b830e7e Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Tue, 2 Jan 2024 03:22:16 +0100 Subject: [PATCH] Add smoke tests frameworks --- flake.lock | 76 ++++++- flake.nix | 7 + nixos/homes/palo/packages/development.nix | 2 + scripts/smoke-robi.sh | 71 ++++++ scripts/smoke.sh | 264 ++++++++++++++++++++++ 5 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 scripts/smoke-robi.sh create mode 100644 scripts/smoke.sh diff --git a/flake.lock b/flake.lock index acadf27..40757df 100644 --- a/flake.lock +++ b/flake.lock @@ -434,6 +434,22 @@ "type": "github" } }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1614513358, @@ -546,6 +562,21 @@ } }, "flake-utils_8": { + "locked": { + "lastModified": 1676283394, + "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_9": { "inputs": { "systems": "systems_3" }, @@ -617,6 +648,23 @@ "type": "github" } }, + "haskellTar": { + "flake": false, + "locked": { + "lastModified": 1657046996, + "narHash": "sha256-gDxF+1L0sMzwogCCTGtiYnPgZMIg5fTWV8d062F7iR0=", + "owner": "haskell", + "repo": "tar", + "rev": "dbf8c995153c8a80450724d9f94cf33403740c80", + "type": "github" + }, + "original": { + "owner": "haskell", + "repo": "tar", + "rev": "dbf8c995153c8a80450724d9f94cf33403740c80", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -1255,6 +1303,7 @@ "private_assets": "private_assets", "retiolum": "retiolum", "secrets": "secrets", + "smoke": "smoke", "sops-nix": "sops-nix", "stylix": "stylix", "taskshell": "taskshell" @@ -1326,6 +1375,29 @@ "type": "github" } }, + "smoke": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_8", + "haskellTar": "haskellTar", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1677715661, + "narHash": "sha256-O4jQBF76GcvqtJbBZT13bh3kEnEGPEu5coW8aBtDivQ=", + "owner": "SamirTalwar", + "repo": "smoke", + "rev": "3a3c12dcfe49fc6ec847516fc49b0804f4151fe0", + "type": "github" + }, + "original": { + "owner": "SamirTalwar", + "repo": "smoke", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": "nixpkgs_7", @@ -1355,7 +1427,7 @@ "base16-kitty": "base16-kitty", "base16-tmux": "base16-tmux", "base16-vim": "base16-vim", - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "home-manager": "home-manager_2", "nixpkgs": "nixpkgs_8" }, @@ -1420,7 +1492,7 @@ }, "taskshell": { "inputs": { - "flake-utils": "flake-utils_8", + "flake-utils": "flake-utils_9", "nixpkgs": [ "nixpkgs" ] diff --git a/flake.nix b/flake.nix index c8c718b..812cdda 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,7 @@ nixpkgs-legacy_2205.url = "github:nixos/nixpkgs/nixos-22.05"; nixpkgs-legacy_2105.url = "github:nixos/nixpkgs/nixos-21.05"; nixos-hardware.url = "github:nixos/nixos-hardware"; + home-manager = { url = "github:nix-community/home-manager/release-23.11"; inputs.nixpkgs.follows = "nixpkgs"; @@ -73,6 +74,10 @@ #inputs.nixpkgs.follows = "nixpkgs"; #inputs.home-manager.follows = "home-manager"; }; + smoke = { + url = github:SamirTalwar/smoke; + inputs.nixpkgs.follows = "nixpkgs"; + }; taskshell = { url = "github:mrvandalo/taskshell"; inputs.nixpkgs.follows = "nixpkgs"; @@ -105,6 +110,7 @@ , private_assets , retiolum , secrets + , smoke , sops-nix , stylix , taskshell @@ -143,6 +149,7 @@ kmonad = kmonad.packages.${system}.kmonad; tasksh = taskshell.packages.${system}.tasksh; overviewer = overviewer.packages.${system}.overviewer; + smoke = smoke.packages.${system}.default; }) (import ./nixos/pkgs) ]; diff --git a/nixos/homes/palo/packages/development.nix b/nixos/homes/palo/packages/development.nix index 55cac9a..4ff46cb 100644 --- a/nixos/homes/palo/packages/development.nix +++ b/nixos/homes/palo/packages/development.nix @@ -110,6 +110,8 @@ with lib; in [ + # smoke + tmux nethogs diff --git a/scripts/smoke-robi.sh b/scripts/smoke-robi.sh new file mode 100644 index 0000000..9890431 --- /dev/null +++ b/scripts/smoke-robi.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +source $SCRIPT_DIR/smoke.sh + +smoke_url_ok "https://git.ingolf-wagner.de/" +smoke_assert_body "explore" + +smoke_url_ok "https://bitwarden.ingolf-wagner.de/#/login" +smoke_assert_body "Vaultwarden" + +smoke_url_ok "https://nextcloud.ingolf-wagner.de/login" +smoke_assert_body "Login" + +smoke_url_ok "https://flix.ingolf-wagner.de/web/index.html#!/login.html" +smoke_assert_body "jellyfin" + +# todo this should not show landingpage +# smoke_url_ok "http://taskserver.ingolf-wagner.de/" + +# todo this should not show landingpage +# smoke_url_ok "http://taskd.ingolf-wagner.de/" + +smoke_url_ok "http://sync.robi.private/" +smoke_assert_body "Transmission Web Interface" + +smoke_url_ok "http://transmission.robi.private/" +smoke_assert_body "Transmission Web Interface" + +smoke_url_ok "http://transmission2.robi.private/" +smoke_assert_body "Transmission Web Interface" + +smoke_url_ok "http://sonarr.robi.private/" +smoke_assert_body "Sonarr" + +smoke_url_ok "http://radarr.robi.private/" +smoke_assert_body "Radarr" + +smoke_url_ok "http://prowlarr.robi.private/" +smoke_assert_body "Prowlarr" + +smoke_url_ok "http://jellyseerr.robi.private/" +smoke_assert_body "Welcome to Jellyseerr" + +smoke_url_ok "http://grafana.robi.private/login" +smoke_assert_body "Grafana" + +smoke_url_ok "http://prometheus.robi.private/" +smoke_assert_body "Prometheus Time Series Collection and Processing Server" + +smoke_url_ok "http://robi.private:8384/" +smoke_assert_body "Syncthing admin interface" + +smoke_url_ok "http://robi.private:19999/" +smoke_assert_body "netdata dashboard" + +smoke_url_ok "https://matrix.terranix.org/#/welcome" +smoke_assert_body "Sorry, Element requires JavaScript to be enabled" + +smoke_url_ok "https://terranix.org/" +smoke_assert_body "terraform" +smoke_assert_body "terranix" +smoke_assert_body "nix" + +smoke_url_ok "https://meet.ingolf-wagner.de/test" +smoke_assert_body "Jitsi" + +smoke_url_ok "https://md.ingolf-wagner.de/test" +smoke_assert_body "HedgeDoc - Ideas grow better together" + +smoke_report diff --git a/scripts/smoke.sh b/scripts/smoke.sh new file mode 100644 index 0000000..f7bee6a --- /dev/null +++ b/scripts/smoke.sh @@ -0,0 +1,264 @@ +#!/bin/bash + +# downloaded from : https://github.com/asm89/smoke.sh + +SMOKE_TMP_DIR=$(mktemp -d) + +SMOKE_AFTER_RESPONSE="" + +SMOKE_CURL_CODE="$SMOKE_TMP_DIR/smoke_curl_code" +SMOKE_CURL_HEADERS="$SMOKE_TMP_DIR/smoke_curl_headers" +SMOKE_CURL_BODY="$SMOKE_TMP_DIR/smoke_curl_body" +SMOKE_CURL_COOKIE_JAR="$SMOKE_TMP_DIR/smoke_curl_cookie_jar" + +SMOKE_CSRF_TOKEN="" +SMOKE_CSRF_FORM_DATA="$SMOKE_TMP_DIR/smoke_csrf_form_data" + +SMOKE_TESTS_FAILED=0 +SMOKE_TESTS_RUN=0 +SMOKE_URL_PREFIX="" +SMOKE_HEADERS=() + +## "Public API" + +smoke_csrf() { + SMOKE_CSRF_TOKEN="$1" +} + +smoke_form() { + URL="$1" + FORMDATA="$2" + + if [[ ! -f $FORMDATA ]]; then + _smoke_print_failure "No formdata file" + _smoke_cleanup + exit 1 + fi + + _curl_post $URL $FORMDATA +} + +smoke_form_ok() { + URL="$1" + FORMDATA="$2" + + smoke_form "$URL" "$FORMDATA" + smoke_assert_code_ok +} + +smoke_report() { + _smoke_cleanup + if [[ $SMOKE_TESTS_FAILED -ne 0 ]]; then + _smoke_print_report_failure "FAIL ($SMOKE_TESTS_FAILED/$SMOKE_TESTS_RUN)" + exit 1 + fi + _smoke_print_report_success "OK ($SMOKE_TESTS_RUN/$SMOKE_TESTS_RUN)" +} + +smoke_response_code() { + cat $SMOKE_CURL_CODE +} + +smoke_response_body() { + cat $SMOKE_CURL_BODY +} + +smoke_response_headers() { + cat $SMOKE_CURL_HEADERS +} + +smoke_tcp_ok() { + URL="$1 $2" + _smoke_print_url "$URL" + echo EOF | telnet $URL >$SMOKE_CURL_BODY + smoke_assert_body "Connected" +} + +smoke_url() { + URL="$1" + _curl_get $URL +} + +smoke_url_ok() { + URL="$1" + smoke_url "$URL" + smoke_assert_code_ok +} + +smoke_url_prefix() { + SMOKE_URL_PREFIX="$1" +} + +smoke_header() { + SMOKE_HEADERS+=("$1") +} + +smoke_host() { + smoke_header "Host: $1" +} + +remove_smoke_headers() { + unset SMOKE_HEADERS +} + +## Assertions + +smoke_assert_code() { + EXPECTED="$1" + CODE=$(cat $SMOKE_CURL_CODE) + + if [[ $CODE == $1 ]]; then + _smoke_success "$1 Response code" + else + _smoke_fail "$1 Response code" + fi +} + +smoke_assert_code_ok() { + CODE=$(cat $SMOKE_CURL_CODE) + + if [[ $CODE == 2* ]]; then + _smoke_success "2xx Response code" + else + _smoke_fail "2xx Response code" + fi +} + +smoke_assert_body() { + STRING="$1" + + smoke_response_body | grep --quiet "$STRING" + + if [[ $? -eq 0 ]]; then + _smoke_success "Body contains \"$STRING\"" + else + _smoke_fail "Body does not contain \"$STRING\"" + fi +} + +smoke_assert_headers() { + STRING="$1" + + smoke_response_headers | grep --quiet "$STRING" + + if [[ $? -eq 0 ]]; then + _smoke_success "Headers contain \"$STRING\"" + else + _smoke_fail "Headers do not contain \"$STRING\"" + fi +} + +## Smoke "private" functions + +_smoke_after_response() { + $SMOKE_AFTER_RESPONSE +} + +_smoke_cleanup() { + rm -rf $SMOKE_TMP_DIR +} + +_smoke_fail() { + REASON="$1" + ((++SMOKE_TESTS_FAILED)) + ((++SMOKE_TESTS_RUN)) + _smoke_print_failure "$REASON" +} + +_smoke_prepare_formdata() { + FORMDATA="$1" + + if [[ "" != $SMOKE_CSRF_TOKEN ]]; then + cat $FORMDATA | sed "s/__SMOKE_CSRF_TOKEN__/$SMOKE_CSRF_TOKEN/" >$SMOKE_CSRF_FORM_DATA + echo $SMOKE_CSRF_FORM_DATA + else + echo $FORMDATA + fi +} + +_smoke_success() { + REASON="$1" + _smoke_print_success "$REASON" + ((++SMOKE_TESTS_RUN)) +} + +## Curl helpers +_curl() { + local opt=(--cookie $SMOKE_CURL_COOKIE_JAR --cookie-jar $SMOKE_CURL_COOKIE_JAR --location --dump-header $SMOKE_CURL_HEADERS --silent) + + if ((${#SMOKE_HEADERS[@]})); then + for header in "${SMOKE_HEADERS[@]}"; do + opt+=(-H "$header") + done + fi + + curl "${opt[@]}" "$@" >$SMOKE_CURL_BODY +} + +_curl_get() { + URL="$1" + + SMOKE_URL="$SMOKE_URL_PREFIX$URL" + _smoke_print_url "$SMOKE_URL" + + _curl $SMOKE_URL + + grep -oE 'HTTP[^ ]+ [0-9]{3}' $SMOKE_CURL_HEADERS | tail -n1 | grep -oE '[0-9]{3}' >$SMOKE_CURL_CODE + + $SMOKE_AFTER_RESPONSE +} + +_curl_post() { + URL="$1" + FORMDATA="$2" + FORMDATA_FILE="@"$(_smoke_prepare_formdata $FORMDATA) + + SMOKE_URL="$SMOKE_URL_PREFIX$URL" + _smoke_print_url "$SMOKE_URL" + + _curl --data "$FORMDATA_FILE" $SMOKE_URL + + grep -oE 'HTTP[^ ]+ [0-9]{3}' $SMOKE_CURL_HEADERS | tail -n1 | grep -oE '[0-9]{3}' >$SMOKE_CURL_CODE + + $SMOKE_AFTER_RESPONSE +} + +## Print helpers + +# test for color support, inspired by: +# http://unix.stackexchange.com/questions/9957/how-to-check-if-bash-can-print-colors +if [ -t 1 ]; then + ncolors=$(tput colors) + if test -n "$ncolors" && test $ncolors -ge 8; then + bold="$(tput bold)" + normal="$(tput sgr0)" + red="$(tput setaf 1)" + redbg="$(tput setab 1)" + green="$(tput setaf 2)" + greenbg="$(tput setab 2)" + fi +fi + +_smoke_print_failure() { + TEXT="$1" + echo " [${red}${bold}FAIL${normal}] $TEXT" +} + +_smoke_print_report_failure() { + TEXT="$1" + echo -e "${redbg}$TEXT${normal}" +} +_smoke_print_report_success() { + TEXT="$1" + echo -e "${greenbg}$TEXT${normal}" +} + +_smoke_print_success() { + TEXT="$1" + echo " [ ${green}${bold}OK${normal} ] $TEXT" +} + +_smoke_print_url() { + TEXT="$1" + echo "> $TEXT" +}