aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/test
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2026-09-29 23:44:16 +0500
committerEgor Tensin <egor@tensin.name>2026-09-29 23:45:40 +0500
commiteec673b5c0122e359bf00b0136783a32e8a77df9 (patch)
tree61457ccf0d65331f1411b28aa7ba2ad964191ba2 /test
parentremove annoying trailing period from repo URLs (diff)
downloadvk-scripts-eec673b5c0122e359bf00b0136783a32e8a77df9.tar.gz
vk-scripts-eec673b5c0122e359bf00b0136783a32e8a77df9.zip
test: rework using the approach from my other projectsv1.2.0
The tests are now run using a framework common to my other projects, like config-links & tag-release.
Diffstat (limited to 'test')
-rwxr-xr-xtest/bin/main.sh19
-rwxr-xr-xtest/bin/mutuals.sh23
-rwxr-xr-xtest/bin/sessions.sh69
-rwxr-xr-xtest/bin/status.sh60
-rwxr-xr-xtest/bin/status_once.sh22
-rw-r--r--test/data/test_db.csv (renamed from test/share/test_db.csv)0
-rw-r--r--test/lib/log.sh139
-rw-r--r--[-rwxr-xr-x]test/lib/test.sh32
-rwxr-xr-xtest/main.sh77
-rw-r--r--test/tst-mutuals.sh38
-rw-r--r--test/tst-sessions.sh51
-rw-r--r--test/tst-status-once.sh25
-rw-r--r--test/tst-status.sh45
13 files changed, 390 insertions, 210 deletions
diff --git a/test/bin/main.sh b/test/bin/main.sh
deleted file mode 100755
index 6b6e409..0000000
--- a/test/bin/main.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2019 Egor Tensin <egor@tensin.name>
-# This file is part of the "VK scripts" project.
-# For details, see https://github.com/egor-tensin/vk-scripts
-# Distributed under the MIT License.
-
-set -o errexit -o nounset -o pipefail
-
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
-
-"$script_dir/mutuals.sh"
-
-"$script_dir/sessions.sh"
-
-"$script_dir/status_once.sh"
-"$script_dir/status.sh"
diff --git a/test/bin/mutuals.sh b/test/bin/mutuals.sh
deleted file mode 100755
index b5d3eb4..0000000
--- a/test/bin/mutuals.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2019 Egor Tensin <egor@tensin.name>
-# This file is part of the "VK scripts" project.
-# For details, see https://github.com/egor-tensin/vk-scripts
-# Distributed under the MIT License.
-
-set -o errexit -o nounset -o pipefail
-
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
-
-test_users() {
- "$script_dir/../lib/test.sh" vk.mutuals --format csv "$@"
- "$script_dir/../lib/test.sh" vk.mutuals --format json "$@"
-}
-
-main() {
- test_users kreed58 korya_mc
-}
-
-main
diff --git a/test/bin/sessions.sh b/test/bin/sessions.sh
deleted file mode 100755
index d952831..0000000
--- a/test/bin/sessions.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2019 Egor Tensin <egor@tensin.name>
-# This file is part of the "VK scripts" project.
-# For details, see https://github.com/egor-tensin/vk-scripts
-# Distributed under the MIT License.
-
-set -o errexit -o nounset -o pipefail
-
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
-script_name="$( basename -- "${BASH_SOURCE[0]}" )"
-readonly script_name
-
-readonly db_path="$script_dir/../share/test_db.csv"
-
-dump() {
- local msg
- for msg; do
- echo "$script_name: $msg"
- done
-}
-
-test_output() {
- local output_path
- output_path="$( mktemp --dry-run )"
-
- local rm_aux_files
- rm_aux_files="$( printf -- 'rm -f -- %q' "$output_path" )"
-
- trap "$rm_aux_files" RETURN
-
- "$script_dir/../lib/test.sh" vk.tracking.sessions "$@" "$db_path" "$output_path"
-
- if file --brief --dereference --mime -- "$output_path" | grep --quiet -- 'charset=binary$'; then
- dump 'Output is a binary file, not going to show that'
- return 0
- fi
-
- cat "$output_path"
-}
-
-group_by() {
- test_output --output-format csv --group-by "$@"
- test_output --output-format json --group-by "$@"
- test_output --output-format plot --group-by "$@"
-}
-
-online_sessions() {
- group_by user
- group_by hour
- group_by date
- group_by weekday
-}
-
-fix_matplotlib() {
- # Get rid of:
- # tkinter.TclError: no display name and no $DISPLAY environment variable
- mkdir -p -- ~/.config/matplotlib
- echo 'backend: Agg' > ~/.config/matplotlib/matplotlibrc
-}
-
-main() {
- fix_matplotlib
- online_sessions
-}
-
-main
diff --git a/test/bin/status.sh b/test/bin/status.sh
deleted file mode 100755
index ab12805..0000000
--- a/test/bin/status.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2019 Egor Tensin <egor@tensin.name>
-# This file is part of the "VK scripts" project.
-# For details, see https://github.com/egor-tensin/vk-scripts
-# Distributed under the MIT License.
-
-set -o errexit -o nounset -o pipefail
-
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
-script_name="$( basename -- "${BASH_SOURCE[0]}" )"
-readonly script_name
-
-dump() {
- local msg
- for msg; do
- echo "$script_name: $msg"
- done
-}
-
-test_users() {
- local log_path
- log_path="$( mktemp )"
- local db_path
- db_path="$( mktemp --dry-run )"
-
- local rm_aux_files
- rm_aux_files="$( printf -- 'rm -f -- %q %q' "$log_path" "$db_path" )"
- trap "$rm_aux_files" RETURN
-
- "$script_dir/../lib/test.sh" vk.tracking.status "$@" --log "$log_path" --format csv --output "$db_path" &
- local pid="$!"
-
- sleep 3
- dump "Log file path: $log_path"
- dump "DB file path: $db_path"
- dump "PID: $pid"
-
- local timeout=10
- dump "Sleeping for $timeout seconds..."
- sleep "$timeout"
-
- dump 'Terminating track_status.py...'
- kill "$pid"
- dump 'Waiting for track_status.py to terminate...'
- wait "$pid" || true
-
- dump "Log file:"
- cat "$log_path"
- dump "DB:"
- cat "$db_path"
-}
-
-main() {
- test_users egor.tensin
-}
-
-main "$@"
diff --git a/test/bin/status_once.sh b/test/bin/status_once.sh
deleted file mode 100755
index 8d8878d..0000000
--- a/test/bin/status_once.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2019 Egor Tensin <egor@tensin.name>
-# This file is part of the "VK scripts" project.
-# For details, see https://github.com/egor-tensin/vk-scripts
-# Distributed under the MIT License.
-
-set -o errexit -o nounset -o pipefail
-
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
-
-test_users() {
- "$script_dir/../lib/test.sh" vk.tracking.status --only-once "$@"
-}
-
-main() {
- test_users egor.tensin
-}
-
-main
diff --git a/test/share/test_db.csv b/test/data/test_db.csv
index 2b087a8..2b087a8 100644
--- a/test/share/test_db.csv
+++ b/test/data/test_db.csv
diff --git a/test/lib/log.sh b/test/lib/log.sh
new file mode 100644
index 0000000..48a34cc
--- /dev/null
+++ b/test/lib/log.sh
@@ -0,0 +1,139 @@
+# Copyright (c) 2026 Egor Tensin <egor@tensin.name>
+# This file is part of the "VK scripts" project.
+# For details, see https://github.com/egor-tensin/vk-scripts
+# Distributed under the MIT License.
+
+log() {
+ local msg
+ for msg; do
+ echo -e "$test_file | $msg" >&2
+ done
+}
+
+log_run() {
+ if [ "$#" -lt 1 ]; then
+ log "usage: ${FUNCNAME[0]} ARGV0 [ARG...]"
+ return 1
+ fi
+
+ local msg='Running:'
+ msg="$msg$( printf -- ' %q' "$@" )"
+ log "$msg"
+}
+
+fail() {
+ local msg
+ for msg; do
+ log "FAIL: $msg"
+ done
+}
+
+fail_details() {
+ local msg
+ for msg; do
+ fail " $msg"
+ done
+}
+
+log_numof_tests_ok=0
+log_numof_tests_failed=0
+declare -a log_tests_failed=()
+declare -A log_tests_should_fail=()
+
+log_test_start() {
+ if [ "$#" -ne 1 ]; then
+ echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
+ return 1
+ fi
+
+ local test_file="$1"
+
+ if [ -n "${test_should_fail:-}" ]; then
+ log_tests_should_fail["$test_file"]=1
+ fi
+
+ cat <<EOF >&2
+
+======================================================================
+TEST: $test_file
+======================================================================
+EOF
+
+ log "Should fail: ${test_should_fail:-No}"
+}
+
+log_test_ok() {
+ if [ "$#" -ne 1 ]; then
+ echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
+ return 1
+ fi
+
+ log_numof_tests_ok=$((log_numof_tests_ok + 1))
+
+ cat <<EOF >&2
+----------------------------------------------------------------------
+OK: $1
+----------------------------------------------------------------------
+EOF
+}
+
+log_test_fail() {
+ if [ "$#" -ne 1 ]; then
+ echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
+ return 1
+ fi
+
+ log_numof_tests_failed=$((log_numof_tests_failed + 1))
+ log_tests_failed+=("$1")
+
+ cat <<EOF >&2
+----------------------------------------------------------------------
+FAIL: $1
+----------------------------------------------------------------------
+EOF
+}
+
+log_test_finish() {
+ if [ "$#" -ne 2 ]; then
+ echo "usage: ${FUNCNAME[0]} TEST_FILE EXIT_CODE" >&2
+ return 1
+ fi
+
+ local test_file="$1"
+ local ret="$2"
+ local test_should_fail
+ test_should_fail="${log_tests_should_fail["$test_file"]:+x}"
+
+ if [ "$ret" -eq 0 ] || [ -n "$test_should_fail" ]; then
+ log_test_ok "$test_file"
+ else
+ log_test_fail "$test_file"
+ fi
+}
+
+log_tests_summary() {
+ cat <<EOF >&2
+
+======================================================================
+SUMMARY
+======================================================================
+OK: $log_numof_tests_ok
+FAIL: $log_numof_tests_failed
+EOF
+
+ local test_file
+ for test_file in ${log_tests_failed[@]+"${log_tests_failed[@]}"}; do
+ cat <<EOF >&2
+FAIL: $test_file
+EOF
+ done
+
+ cat <<EOF >&2
+----------------------------------------------------------------------
+EOF
+
+ local ret=0
+ [ "$log_numof_tests_failed" -gt 0 ] && ret=1
+
+ return "$ret"
+}
diff --git a/test/lib/test.sh b/test/lib/test.sh
index 56b3235..30c4ce1 100755..100644
--- a/test/lib/test.sh
+++ b/test/lib/test.sh
@@ -1,27 +1,25 @@
-#!/usr/bin/env bash
-
# Copyright (c) 2020 Egor Tensin <egor@tensin.name>
# This file is part of the "VK scripts" project.
# For details, see https://github.com/egor-tensin/vk-scripts
# Distributed under the MIT License.
-set -o errexit -o nounset -o pipefail
+test_should_fail=
+test_root_dir=
-script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
-script_dir="$( cd -- "$script_dir" && pwd )"
-readonly script_dir
+test_setup() {
+ test_root_dir="$( mktemp -d )"
-run_test() {
- local arg
- echo
- echo ======================================================================
- for arg; do
- echo -n "$arg "
- done
- echo
- echo ======================================================================
+ log "Root directory: $test_root_dir"
+}
- PYTHONPATH="$script_dir/../.." python -m "$@"
+test_cleanup_default() {
+ if [ -n "$test_root_dir" ]; then
+ log "Removing test's root directory: $test_root_dir"
+ rm -rf -- "$test_root_dir"
+ fi
}
-run_test "$@"
+test_run_module() {
+ log_run python -m "$@"
+ PYTHONPATH="$script_dir/.." python -m "$@"
+}
diff --git a/test/main.sh b/test/main.sh
new file mode 100755
index 0000000..07889ac
--- /dev/null
+++ b/test/main.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+# Copyright (c) 2026 Egor Tensin <egor@tensin.name>
+# This file is part of the "VK scripts" project.
+# For details, see https://github.com/egor-tensin/vk-scripts
+# Distributed under the MIT License.
+
+set -o errexit -o nounset -o pipefail
+shopt -s inherit_errexit lastpipe
+
+script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
+script_dir="$( cd -- "$script_dir" && pwd )"
+readonly script_dir
+script_name="$( basename -- "${BASH_SOURCE[0]}" )"
+readonly script_name
+
+source "$script_dir/lib/log.sh"
+
+run_test_file() {
+ local test_file
+ for test_file; do
+ source "$script_dir/lib/test.sh"
+ source "$script_dir/$test_file"
+
+ log_test_start "$test_file"
+
+ set +e
+ (
+ set -o errexit -o nounset -o pipefail
+ shopt -s inherit_errexit lastpipe
+
+ if [ "$( type -t test_cleanup )" == function ]; then
+ trap test_cleanup EXIT
+ else
+ trap test_cleanup_default EXIT
+ fi
+
+ test_run
+ )
+ local ret="$?"
+ set -e
+
+ log_test_finish "$test_file" "$ret"
+ done
+}
+
+main() {
+ if [ "$#" -gt 1 ]; then
+ echo "usage: $script_name [PATTERN]" >&2
+ return 1
+ fi
+
+ local -a test_files=()
+ local test_file
+
+ local pattern='*'
+ [ "$#" -gt 0 ] && pattern="$1"
+
+ find "$script_dir" \
+ -mindepth 1 \
+ -maxdepth 1 \
+ -type f \
+ -regex '.*/tst-.*\.sh$' \
+ -regextype posix-basic \
+ -name "$pattern" \
+ -printf '%P\0' \
+ | sort -z \
+ | \
+ while IFS= read -d '' -r test_file; do
+ test_files+=("$test_file")
+ done
+
+ run_test_file ${test_files[@]+"${test_files[@]}"}
+ log_tests_summary
+}
+
+main "$@"
diff --git a/test/tst-mutuals.sh b/test/tst-mutuals.sh
new file mode 100644
index 0000000..3f40780
--- /dev/null
+++ b/test/tst-mutuals.sh
@@ -0,0 +1,38 @@
+test_run() {
+ test_setup
+
+ local users=(kreed58 korya_mc)
+
+ test_run_module vk.mutuals --format csv "${users[@]}" > "$test_root_dir/mutuals.csv"
+ test_run_module vk.mutuals --format json "${users[@]}" > "$test_root_dir/mutuals.json"
+
+ local expected=10
+
+ local actual_csv
+ actual_csv="$( cat -- "$test_root_dir/mutuals.csv" | wc -l )"
+ log "Mutuals in CSV: $actual_csv"
+
+ if [ "$actual_csv" -lt "$expected" ]; then
+ fail "Expected a lot more mutual friends in CSV output"
+ fail_details "Expected: $expected"
+ fail_details "Actual: $actual_csv"
+ return 1
+ fi
+
+ local actual_json
+ actual_json="$( grep -F -- '"id":' "$test_root_dir/mutuals.json" | wc -l )"
+ log "Mutuals in JSON: $actual_json"
+
+ if [ "$actual_json" -lt "$expected" ]; then
+ fail "Expected a lot more mutual friends in JSON output"
+ fail_details "Expected: $expected"
+ fail_details "Actual: $actual_json"
+ return 1
+ fi
+
+ if [ "$actual_csv" -ne "$actual_json" ]; then
+ fail "Number of mutuals in CSV unequal to that in JSON"
+ fail_details "Can technically happen, because it's kind of a race"
+ return 1
+ fi
+}
diff --git a/test/tst-sessions.sh b/test/tst-sessions.sh
new file mode 100644
index 0000000..2885d0c
--- /dev/null
+++ b/test/tst-sessions.sh
@@ -0,0 +1,51 @@
+test_db_path="$script_dir/data/test_db.csv"
+readonly test_db_path
+
+_test_format() {
+ local output_path
+ output_path="$( mktemp --tmpdir="$test_root_dir" )"
+
+ test_run_module vk.tracking.sessions "$@" "$test_db_path" "$output_path"
+
+ if [ ! -s "$output_path" ]; then
+ fail "Output file '$output_path' either doesn't exists or is empty"
+ return 1
+ fi
+
+ if file --brief --dereference --mime -- "$output_path" | grep --quiet -- 'charset=binary$'; then
+ log 'Output is a binary file, not going to show that'
+ return 0
+ fi
+
+ cat -- "$output_path" >&2
+}
+
+_test_group_by() {
+ local group_by
+ for group_by; do
+ local format
+ for format in csv json plot; do
+ _test_format --output-format "$format" --group-by "$group_by"
+ done
+ done
+}
+
+_test_main() {
+ _test_group_by user
+ _test_group_by hour
+ _test_group_by date
+ _test_group_by weekday
+}
+
+_fix_matplotlib() {
+ # Get rid of:
+ # tkinter.TclError: no display name and no $DISPLAY environment variable
+ mkdir -p -- ~/.config/matplotlib
+ echo 'backend: Agg' > ~/.config/matplotlib/matplotlibrc
+}
+
+test_run() {
+ test_setup
+ _fix_matplotlib
+ _test_main
+}
diff --git a/test/tst-status-once.sh b/test/tst-status-once.sh
new file mode 100644
index 0000000..1623d25
--- /dev/null
+++ b/test/tst-status-once.sh
@@ -0,0 +1,25 @@
+test_run() {
+ test_setup
+
+ local users=(egor.tensin kreed58)
+ local db_path
+ db_path="$test_root_dir/db.csv"
+
+ test_run_module vk.tracking.status --only-once -o "$db_path" "${users[@]}"
+
+ if [ ! -s "$db_path" ]; then
+ fail "Database file '$db_path' either doesn't exists or is empty"
+ return 1
+ fi
+
+ log "Database:"
+ cat -- "$db_path" >&2
+
+ local lines
+ lines="$( cat -- "$db_path" | wc -l )"
+
+ if [ "$lines" -ne 2 ]; then
+ fail "Database '$db_path' has the wrong number of entries"
+ return 1
+ fi
+}
diff --git a/test/tst-status.sh b/test/tst-status.sh
new file mode 100644
index 0000000..e967ae5
--- /dev/null
+++ b/test/tst-status.sh
@@ -0,0 +1,45 @@
+test_run() {
+ test_setup
+
+ local users=(egor.tensin)
+
+ local log_path
+ log_path="$test_root_dir/status.log"
+ local db_path
+ db_path="$test_root_dir/status.csv"
+
+ test_run_module vk.tracking.status \
+ --log "$log_path" \
+ --format csv \
+ --output "$db_path" \
+ "${users[@]}" &
+ local pid="$!"
+
+ sleep 3
+ log "Log file: $log_path"
+ log "Database file: $db_path"
+ log "PID: $pid"
+
+ local timeout=10
+ log "Sleeping for $timeout seconds..."
+ sleep "$timeout"
+
+ log 'Terminating track_status.py...'
+ kill "$pid"
+ log 'Waiting for track_status.py to terminate...'
+ wait "$pid" || true
+
+ if [ ! -s "$log_path" ]; then
+ fail "Log file '$log_path' either doesn't exists or is empty"
+ return 1
+ fi
+ log 'Log file:'
+ cat -- "$log_path" >&2
+
+ if [ ! -s "$db_path" ]; then
+ fail "Database file '$db_path' either doesn't exists or is empty"
+ return 1
+ fi
+ log 'Database:'
+ cat -- "$db_path" >&2
+}