diff --git a/README.md b/README.md index af914a0..75e979c 100644 --- a/README.md +++ b/README.md @@ -95,9 +95,9 @@ The following systems integrate Avionics as a submodule: Unit tests are part of this repository under `test/`, and can run on a laptop/desktop without embedded hardware. 1. Install PlatformIO Core (`pip install -U platformio`) or the PlatformIO IDE extension. -2. Place test CSV files in `data/` (or let CI download them). +2. Place test CSV files in `data/` (or either let CI download them or use the `data_downloader.py` script in the data folder). 3. Run tests from the repo root: - - `pio test -e native` + - `pio test -e native-for_mac_and_windows` or `pio test -e native` ## Hardware Abstraction Note: diff --git a/data/data_downloader.py b/data/data_downloader.py new file mode 100644 index 0000000..181e1b7 --- /dev/null +++ b/data/data_downloader.py @@ -0,0 +1,193 @@ + +import json +import shutil +import subprocess +import sys +import urllib.request +from pathlib import Path + + +# --------------------------------------------------------- +# Configuration +# --------------------------------------------------------- + + +REPO_API = ( + "https://api.github.com/repos/" + "CURocketEngineering/Rocket-Test-Data/releases/tags/v1.0.0" +) + +DATA_DIR = Path("data") + +BAD_FILENAME = "AA.Data.Collection.-.Second.Launch.Trimmed.csv" +GOOD_FILENAME = "AA Data Collection - Second Launch Trimmed.csv" + + +# --------------------------------------------------------- +# Helpers +# --------------------------------------------------------- + +def run_command(command): + """Run a command and stop if it fails.""" + print(f"\n> {' '.join(command)}") + result = subprocess.run(command) + + if result.returncode != 0: + print(f"\nCommand failed with exit code {result.returncode}") + sys.exit(result.returncode) + + +# --------------------------------------------------------- +# check if the data already exists +#--------------------------------------------------------- + +def check_data_exists(): + """Check if the test data has already been downloaded.""" + good_path = DATA_DIR / GOOD_FILENAME + bad_path = DATA_DIR / BAD_FILENAME + + if good_path.exists(): + print("\nTest data already exists:") + print(f" {good_path}") + return True + + if bad_path.exists(): + print("\nTest data already exists but needs filename fixing:") + print(f" {bad_path}") + return True + + print("\nTest data not found. Downloading...") + return False + + + +# --------------------------------------------------------- +# Download Rocket Test Data +# --------------------------------------------------------- + +def download_test_data(): + print("\n========================================") + print("Downloading Rocket Test Data") + print("========================================") + + DATA_DIR.mkdir(parents=True, exist_ok=True) + + request = urllib.request.Request( + REPO_API, + headers={ + "Accept": "application/vnd.github+json", + "User-Agent": "Avionics-Test-Runner", + }, + ) + + try: + with urllib.request.urlopen(request) as response: + release = json.load(response) + except Exception as e: + print(f"Failed to get GitHub release information: {e}") + sys.exit(1) + + assets = release.get("assets", []) + + if not assets: + print("No release assets found.") + sys.exit(1) + + for asset in assets: + filename = asset["name"] + download_url = asset["browser_download_url"] + + output_path = DATA_DIR / filename + + print(f"\nDownloading:") + print(f" {download_url}") + print(f" -> {output_path}") + + try: + download_request = urllib.request.Request( + download_url, + headers={ + "User-Agent": "Avionics-Test-Runner", + }, + ) + + with urllib.request.urlopen(download_request) as response: + with open(output_path, "wb") as output: + shutil.copyfileobj(response, output) + + except Exception as e: + print(f"Failed to download {filename}: {e}") + sys.exit(1) + + +# --------------------------------------------------------- +# Fix Filename +# --------------------------------------------------------- + +def fix_filename(): + print("\n========================================") + print("Fixing Test Data Filename") + print("========================================") + + old_path = DATA_DIR / BAD_FILENAME + new_path = DATA_DIR / GOOD_FILENAME + + if not old_path.exists(): + # It may already have been renamed. + if new_path.exists(): + print(f"Already fixed:") + print(f" {new_path}") + return + + print(f"Could not find:") + print(f" {old_path}") + sys.exit(1) + + if new_path.exists(): + print(f"Removing existing:") + print(f" {new_path}") + new_path.unlink() + + print(f"Moving:") + print(f" {old_path}") + print(f" -> {new_path}") + + old_path.rename(new_path) + + + + +# --------------------------------------------------------- +# Main +# --------------------------------------------------------- + +def main(): + print("========================================") + print("CURE Avionics Native Test Runner") + print("========================================") + + if check_data_exists(): + print("========================================") + print("Test Data Already Exists") + print("========================================") + print("\nWould you like to download the test data again? (y/n)") + answer = input() + if answer.lower() == "y": + print("\n") + + else: + print("\nexiting") + return + + download_test_data() + + fix_filename() + + print("========================================") + print("Test Data Ready") + print("========================================") + print("\nYou can now run the tests with: pio test -e native-for_mac_and_windows") + + +if __name__ == "__main__": + main() diff --git a/platformio.ini b/platformio.ini index 7215bae..922c013 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,3 +1,5 @@ +; PlatformIO Project Configuration to run on linux or on github actions +; This is the default configuration and does more checks [env:native] platform = native test_framework = unity @@ -41,4 +43,44 @@ check_flags = check_src_filters = + + - + \ No newline at end of file + + + + + + +; PlatformIO Project Configuration to run on mac and windows +; This configuration is for testing on personal devices and does all the main tests +[env:native-for_mac_and_windows] +platform = native +test_framework = unity +test_build_src = yes + +build_flags = + -std=c++17 + + ; Warnings + -Wall + -Wextra + -Wpedantic + -Wshadow + + -Wconversion + -Wsign-conversion + -Wformat=2 + -Wundef + -Wnull-dereference + -Wdouble-promotion + + ; Better analysis/debuggability + -O1 + -g3 + -fno-omit-frame-pointer + + ; Runtime checks + -fno-sanitize-recover=all + -D_GLIBCXX_ASSERTIONS + + ; Project includes + -DUNITY_INCLUDE_DETAILS + -Ihal + -Itest \ No newline at end of file