Python · 3120 bytes Raw Blame History
1 #!/usr/bin/env python3
2 """
3 Fix exit code tests by running commands in /bin/sh and capturing actual exit codes.
4 """
5
6 import yaml
7 import subprocess
8 import sys
9 from pathlib import Path
10
11
12 def get_exit_code(command: str) -> int:
13 """Run command in /bin/sh and return exit code."""
14 try:
15 result = subprocess.run(
16 ['/bin/sh', '-c', command],
17 capture_output=True,
18 text=True,
19 timeout=5
20 )
21 return result.returncode
22 except Exception as e:
23 print(f" ⚠️ Failed to run: {command[:50]}... - {e}")
24 return None
25
26
27 def fix_exit_code_test(test: dict) -> tuple[dict, bool]:
28 """
29 Fix a single exit code test.
30 Returns (updated_test, was_fixed)
31 """
32 # Check if this is an exit code test that needs review
33 if test.get('note') != 'MANUAL REVIEW NEEDED: Check expected exit code':
34 return test, False
35
36 steps = test.get('steps', [])
37 if len(steps) < 2:
38 return test, False
39
40 # Last step should be: echo "EXIT=$?"
41 last_step = steps[-1]
42 if not last_step.get('send_line', '').startswith('echo "EXIT=$?"'):
43 return test, False
44
45 # Expect output should be EXIT=
46 if test.get('expect_output') != 'EXIT=':
47 return test, False
48
49 # Get all commands before the echo
50 commands = []
51 for step in steps[:-1]:
52 cmd = step.get('send_line', '')
53 if cmd:
54 commands.append(cmd)
55
56 # Combine commands with ; and run to get exit code
57 full_command = '; '.join(commands)
58 exit_code = get_exit_code(full_command)
59
60 if exit_code is None:
61 return test, False
62
63 # Update the test
64 test['expect_output'] = f'EXIT={exit_code}'
65 test.pop('note', None) # Remove the manual review note
66
67 return test, True
68
69
70 def main():
71 if len(sys.argv) < 2:
72 print(f"Usage: {sys.argv[0]} <yaml_file>")
73 sys.exit(1)
74
75 yaml_file = Path(sys.argv[1])
76 if not yaml_file.exists():
77 print(f"Error: File not found: {yaml_file}")
78 sys.exit(1)
79
80 # Load YAML
81 with open(yaml_file, 'r') as f:
82 data = yaml.safe_load(f)
83
84 # Count before
85 before_count = sum(1 for t in data['tests']
86 if t.get('note') == 'MANUAL REVIEW NEEDED: Check expected exit code')
87
88 # Fix tests
89 fixed_count = 0
90 for i, test in enumerate(data['tests']):
91 updated_test, was_fixed = fix_exit_code_test(test)
92 data['tests'][i] = updated_test
93 if was_fixed:
94 fixed_count += 1
95 # Print progress
96 if fixed_count % 10 == 0:
97 print(f" Fixed {fixed_count} tests...")
98
99 # Write back
100 with open(yaml_file, 'w') as f:
101 yaml.dump(data, f, default_flow_style=False, sort_keys=False)
102
103 print(f"\n✓ Fixed {fixed_count}/{before_count} exit code tests")
104 print(f" File: {yaml_file}")
105
106 remaining = before_count - fixed_count
107 if remaining > 0:
108 print(f"\n⚠️ {remaining} exit code tests still need manual review")
109
110
111 if __name__ == '__main__':
112 main()