func tests improvements (#2759)

* faster reload test
* decode-jwt script
* replace 'netcat' requirement with python script
* fix lapi status test
This commit is contained in:
mmetc 2024-01-19 13:55:28 +01:00 committed by GitHub
parent 6ffb68322f
commit ce32fc019e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 102 additions and 49 deletions

View file

@ -42,7 +42,7 @@ jobs:
env:
GOBIN: /usr/local/bin
run: |
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq netcat-openbsd libre2-dev
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq libre2-dev
- name: "Build crowdsec and fixture"
run: make bats-clean bats-build bats-fixture BUILD_STATIC=1

View file

@ -49,7 +49,7 @@ jobs:
env:
GOBIN: /usr/local/bin
run: |
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq netcat-openbsd libre2-dev
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq libre2-dev
- name: "Build crowdsec and fixture"
run: |

View file

@ -58,7 +58,7 @@ jobs:
env:
GOBIN: /usr/local/bin
run: |
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq netcat-openbsd libre2-dev
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq libre2-dev
- name: "Build crowdsec and fixture (DB_BACKEND: pgx)"
run: |

View file

@ -39,7 +39,7 @@ jobs:
env:
GOBIN: /usr/local/bin
run: |
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq netcat-openbsd libre2-dev
sudo apt -qq -y -o=Dpkg::Use-Pty=0 install build-essential daemonize jq libre2-dev
- name: "Build crowdsec and fixture"
run: |

View file

@ -63,7 +63,6 @@ architectures.
- `jq`
- `nc`
- `openssl`
- `openbsd-netcat`
- `python3`
## Running all tests

View file

@ -18,7 +18,7 @@ installation and run the tests, or run the playbooks separately to iterate while
- run-all.yml: run the other playbooks in the correct order.
- provision-dependencies.yml: install the bats requirements (bash, netcat, cfssl, etc.), compilers, and database.
- provision-dependencies.yml: install the bats requirements (bash, cfssl, etc.), compilers, and database.
- provision-test-suite.yml: install the tests scripts and bats environment, and the crowdsec sources if we want to build the `crowdsec under test`.

View file

@ -3,5 +3,5 @@ unset IFS
set -euf
# coreutils -> for timeout (busybox is not enough)
sudo apk add python3 go tar procps netcat-openbsd coreutils
sudo apk add python3 go tar procps coreutils

View file

@ -1,3 +1,3 @@
#!/bin/sh
sudo emerge --quiet app-portage/gentoolkit dev-vcs/git net-misc/curl app-misc/jq net-analyzer/openbsd-netcat
sudo emerge --quiet app-portage/gentoolkit dev-vcs/git net-misc/curl app-misc/jq

View file

@ -84,7 +84,7 @@ teardown() {
config_disable_agent
sleep 5
sleep 2
rune -0 kill -HUP "$PID"
@ -107,13 +107,13 @@ teardown() {
assert_file_contains "$log_old" "Bucket routine exiting"
assert_file_contains "$log_old" "serve: shutting down api server"
sleep 5
sleep 2
assert_file_exists "$log_new"
for ((i=0; i<10; i++)); do
sleep 1
grep -q "Reload is finished" <"$log_old" && break
grep -q "Reload is finished" <"$log_new" && break
done
echo "waited $i seconds"

View file

@ -80,7 +80,6 @@ teardown() {
@test "lapi status shouldn't be ok without api.server" {
config_disable_lapi
./instance-crowdsec start || true
rune -1 cscli machines list
assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
}

View file

@ -36,12 +36,6 @@ check_jq() {
fi
}
check_nc() {
if ! command -v nc >/dev/null; then
die "missing required program 'nc' (package 'netcat-openbsd')"
fi
}
check_base64() {
if ! command -v base64 >/dev/null; then
die "missing required program 'base64'"
@ -66,7 +60,6 @@ check_bats_core
check_curl
check_daemonizer
check_jq
check_nc
check_base64
check_python3
check_pkill

40
test/bin/decode-jwt Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env python3
import base64
import json
import sys
def decode_base64url(data):
# Not the same as "bin/base64 -d":
# + -> -
# / -> _
# = -> ''
pad = len(data) % 4
if pad > 0:
data += '=' * (4 - pad)
return base64.urlsafe_b64decode(data)
def decode_jwt(token):
token = token.rstrip('\n')
header, payload, signature = token.split('.')
decoded_header = json.loads(decode_base64url(header))
decoded_payload = json.loads(decode_base64url(payload))
# the signature is binary, so we don't decode it
return decoded_header, decoded_payload, signature
def main():
header, payload, signature = decode_jwt(sys.stdin.read())
out = {
'header': header,
'payload': payload,
'signature': signature,
}
print(json.dumps(out, indent=4))
if __name__ == '__main__':
main()

View file

@ -1,42 +1,64 @@
#!/usr/bin/env bash
#!/usr/bin/env python3
set -eu
import argparse
import os
import socket
import sys
import time
script_name=$0
initial_interval = 0.02
max_interval = 0.5
die() {
echo >&2 "$@"
exit 1
}
about() {
die "usage: ${script_name} [-q] <port_number>"
}
def is_fd_open(fd):
try:
os.fstat(fd)
return True
except OSError:
return False
[[ $# -lt 1 ]] && about
QUIET=
if [[ "$1" == "-q" ]]; then
QUIET=quiet
shift
fi
# write to file descriptor 3 if it is open (during bats tests), otherwise stderr
def write_error(ex):
fd = 2
if is_fd_open(3):
fd = 3
os.write(fd, str(ex).encode())
[[ $# -lt 1 ]] && about
port_number=$1
def wait(host, port, timeout):
t0 = time.perf_counter()
current_interval = initial_interval
while True:
try:
with socket.create_connection((host, port), timeout=timeout):
break
except OSError as ex:
if time.perf_counter() - t0 >= timeout:
raise TimeoutError(f'Timeout waiting for {host}:{port} after {timeout}s') from ex
time.sleep(current_interval)
current_interval = min(current_interval * 1.5, max_interval)
# 4 seconds may seem long, but the tests must work on embedded, slow arm boxes too
for _ in $(seq 40); do
nc -z localhost "${port_number}" >/dev/null 2>&1 && exit 0
sleep .1
done
# send to &3 if open
if { true >&3; } 2>/dev/null; then
[[ -z "${QUIET}" ]] && echo "Can't connect to port ${port_number}" >&3
else
[[ -z "${QUIET}" ]] && echo "Can't connect to port ${port_number}" >&2
fi
def main(argv):
parser = argparse.ArgumentParser(description="Check if a port is open.")
parser.add_argument("port", type=int, help="Port number to check")
parser.add_argument("--host", type=str, default="localhost", help="Host to check")
parser.add_argument("-t", "--timeout", type=float, default=10.0, help="Timeout duration in seconds")
parser.add_argument("-q", "--quiet", action="store_true", help="Enable quiet mode")
args = parser.parse_args(argv)
exit 1
try:
wait(args.host, args.port, args.timeout)
except TimeoutError as ex:
if not args.quiet:
write_error(ex)
sys.exit(1)
else:
sys.exit(0)
sys.exit(1)
if __name__ == "__main__":
main(sys.argv[1:])