From 941baba5b47b6bb8d75254730b9bd63c98eec86d Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sun, 13 Apr 2025 16:28:49 +0200 Subject: [PATCH] Improve unittest for CSV export #3150 --- Makefile | 9 +- tests-data/tools/csvcheck.py | 85 +++++++++++++++++++ tests/test_export_csv.sh | 15 ++++ ...st_influxdb.sh => test_export_influxdb.sh} | 3 + 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100755 tests-data/tools/csvcheck.py create mode 100755 tests/test_export_csv.sh rename tests/{test_influxdb.sh => test_export_influxdb.sh} (97%) diff --git a/Makefile b/Makefile index 2e072107..2cf40338 100644 --- a/Makefile +++ b/Makefile @@ -114,8 +114,13 @@ test-min: ## Run core unit tests in minimal environment test-min-with-upgrade: venv-min-upgrade ## Upgrade deps and run unit tests in minimal environment $(venv_min)/python -m pytest tests/test_core.py -test-influxdb: ## Run interface tests with InfluxDB - /bin/bash ./tests/test_influxdb.sh +test-export-csv: ## Run interface tests with CSV + /bin/bash ./tests/test_export_csv.sh + +test-export-influxdb: ## Run interface tests with InfluxDB + /bin/bash ./tests/test_export_influxdb.sh + +test-export: test-export-csv test-export-influxdb ## Tests all exports # =================================================================== # Linters, profilers and cyber security diff --git a/tests-data/tools/csvcheck.py b/tests-data/tools/csvcheck.py new file mode 100755 index 00000000..0dc5417b --- /dev/null +++ b/tests-data/tools/csvcheck.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# +# Check a CSV file. +# The input CSV file should be given as an input with the -i option. +# Check the following thinks: +# - number of line (without the header) should be equal to the number given with the -l option +# - each line should have the same number of columns +# - if the optional -c option is given, each line should have the the same number of columns + +import argparse +import csv +import sys + + +def check_csv(input_file, expected_lines, expected_columns=None): + try: + with open(input_file, newline='') as csvfile: + reader = csv.reader(csvfile) + + # Read header + header = next(reader, None) + if header is None: + print("Error: CSV file is empty") + return False + + header_columns = len(header) + print(f"Header has {header_columns} columns") + + # Read all the data rows + rows = list(reader) + row_count = len(rows) + + # Check 1: Number of lines + if row_count != expected_lines: + print(f"Error: Expected {expected_lines} lines, but found {row_count}") + return False + print(f"Line count check passed: {row_count} lines (excluding header)") + + # Check 2: Consistent number of columns + column_counts = [len(row) for row in rows] + if len(set(column_counts)) > 1: + print("Error: Not all rows have the same number of columns") + for i, count in enumerate(column_counts): + if count != header_columns: + print(f"Row {i + 1} has {count} columns (different from header)") + return False + print("Column consistency check passed: All rows have the same number of columns") + + # Check 3: Optional - specific number of columns + if expected_columns is not None: + if header_columns != expected_columns: + print(f"Error: Expected {expected_columns} columns, but found {header_columns}") + return False + print(f"Column count check passed: {header_columns} columns") + + return True + + except FileNotFoundError: + print(f"Error: File '{input_file}' not found") + return False + except Exception as e: + print(f"Error processing CSV file: {str(e)}") + return False + + +def main(): + parser = argparse.ArgumentParser(description='Check a CSV file for various properties.') + parser.add_argument('-i', '--input', required=True, help='Input CSV file') + parser.add_argument('-l', '--lines', type=int, required=True, help='Expected number of lines (excluding header)') + parser.add_argument('-c', '--columns', type=int, help='Expected number of columns (optional)') + + args = parser.parse_args() + + success = check_csv(args.input, args.lines, args.columns) + + if success: + print("All checks passed successfully!") + sys.exit(0) + else: + print("CSV validation failed.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/test_export_csv.sh b/tests/test_export_csv.sh new file mode 100755 index 00000000..1a51b4c8 --- /dev/null +++ b/tests/test_export_csv.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Pre-requisites: +# - jq + +# Exit on error +set -e + +# Run glances with export to InfluxDB, stopping after 10 writes +# This will run synchronously now since we're using --stop-after +echo "Glances starts to export system stats to CSV file /tmp/glances.csv (duration: ~ 20 seconds)" +rm -f /tmp/glances.csv +./venv/bin/python -m glances --export csv --export-csv-file /tmp/glances.csv --stop-after 10 --quiet + +echo "Checking CSV file..." +./venv/bin/python ./tests-data/tools/csvcheck.py -i /tmp/glances2.csv -l 9 diff --git a/tests/test_influxdb.sh b/tests/test_export_influxdb.sh similarity index 97% rename from tests/test_influxdb.sh rename to tests/test_export_influxdb.sh index e7a6fa8d..d5757d7b 100755 --- a/tests/test_influxdb.sh +++ b/tests/test_export_influxdb.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Pre-requisites: +# - docker +# - jq # Exit on error set -e