|
| 1 | +# Description: This script averages the test durations from all the artifacts |
| 2 | +import glob |
| 3 | +import json |
| 4 | +import os |
| 5 | +import subprocess |
| 6 | +from collections import defaultdict |
| 7 | + |
| 8 | + |
| 9 | +# Function to collect test names using pytest |
| 10 | +def collect_tests_with_pytest(): |
| 11 | + # Run pytest with --collect-only to get the list of test cases |
| 12 | + result = subprocess.run(["pytest", "--collect-only"], capture_output=True, text=True, check=False) |
| 13 | + |
| 14 | + collected_tests = defaultdict(list) |
| 15 | + |
| 16 | + # Parse the output to organize tests under their respective modules |
| 17 | + for line in result.stdout.splitlines(): |
| 18 | + if line.startswith("tests/"): |
| 19 | + collected_tests[line] = 0 |
| 20 | + |
| 21 | + return collected_tests |
| 22 | + |
| 23 | + |
| 24 | +# Consolidate durations from existing artifacts |
| 25 | +def consolidate_durations(): |
| 26 | + durations = defaultdict(lambda: {"total_duration": 0, "count": 0}) |
| 27 | + |
| 28 | + # Iterate over all downloaded duration artifacts |
| 29 | + for folder in glob.glob("test-durations-*"): |
| 30 | + # The path to the duration file in each directory |
| 31 | + duration_file_path = os.path.join(folder, ".pytest-split-durations") |
| 32 | + |
| 33 | + if os.path.isfile(duration_file_path): |
| 34 | + with open(duration_file_path) as f: |
| 35 | + data = json.load(f) |
| 36 | + for test, duration in data.items(): |
| 37 | + durations[test]["total_duration"] += duration |
| 38 | + durations[test]["count"] += 1 |
| 39 | + |
| 40 | + # Calculate the average duration for each test |
| 41 | + return {test: info["total_duration"] / info["count"] for test, info in durations.items()} |
| 42 | + |
| 43 | + |
| 44 | +# Define the path to the consolidated durations file |
| 45 | +CONSOLIDATED_FILE = "tests/test_data/.pytest-split-durations" |
| 46 | + |
| 47 | + |
| 48 | +# Main script logic |
| 49 | +def main(): |
| 50 | + # Collect tests grouped by modules using pytest |
| 51 | + collected_tests = collect_tests_with_pytest() |
| 52 | + |
| 53 | + # Consolidate durations from artifacts |
| 54 | + consolidated_durations = consolidate_durations() |
| 55 | + |
| 56 | + # Merge and update with consolidated durations |
| 57 | + updated_durations = {} |
| 58 | + for test, duration in collected_tests.items(): |
| 59 | + # Update average test durations and exclude test which not exists (can happen on renaming or removing tests) |
| 60 | + if test in consolidated_durations: |
| 61 | + updated_durations[test] = consolidated_durations[test] |
| 62 | + |
| 63 | + # Load the existing durations file if it exists |
| 64 | + existing_durations = {} |
| 65 | + if os.path.isfile(CONSOLIDATED_FILE): |
| 66 | + with open(CONSOLIDATED_FILE) as f: |
| 67 | + existing_durations = json.load(f) |
| 68 | + |
| 69 | + # Sort the keys to compare the tests in both dictionaries |
| 70 | + updated_durations_key = sorted(updated_durations.keys()) |
| 71 | + existing_durations_key = sorted(existing_durations.keys()) |
| 72 | + |
| 73 | + # Check if all keys in updated_durations are in existing_durations |
| 74 | + if updated_durations_key == existing_durations_key: |
| 75 | + print("No new tests detected; durations file remains unchanged.") |
| 76 | + else: |
| 77 | + # Write the updated durations to the consolidated file |
| 78 | + with open(CONSOLIDATED_FILE, "w") as f: |
| 79 | + json.dump(updated_durations, f, indent=4) |
| 80 | + print("New tests detected; updated the durations file.") |
| 81 | + |
| 82 | + |
| 83 | +if __name__ == "__main__": |
| 84 | + main() |
0 commit comments