Framework tests / test validators now return exit codes (-1) when failures are detected#9
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the multi-server test framework so individual validators/tests return explicit result codes (0 on success, non-zero on failure) and attempts to propagate those codes up to the framework’s top-level execution.
Changes:
Validator.get_results_str()now returns(results_str, result_code)whereresult_codeis0or-1.Test.run()/Test.__run()now return an integer exit code derived from per-state validator results (and timeout handling).multi_server_test.run_tests()/main()were updated to aggregate test return codes and exit non-zero on failures.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/multi_server_test.py |
Propagates async test return codes to main() and attempts to convert failures into a non-zero process exit. |
src/custom_test.py |
Makes Test.run() and internal state runner return an int result code; logs validator result codes per state. |
src/Validator.py |
Extends validator result reporting to include an explicit pass/fail result code alongside the formatted output. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "%s %s", f"Test.{self.name}.{self.compose_file.stem}", result | ||
| ) | ||
|
|
||
| return ExitCodes.VALIDATION_FAILURE if any(has_failure for has_failure in test_has_failures) else ExitCodes.SUCCESS |
There was a problem hiding this comment.
return ExitCodes.VALIDATION_FAILURE if (True in test_has_failures) else ExitCodes.SUCCESS
| tests (list[Test]): List of Test objects to run. | ||
|
|
||
| Returns: | ||
| int: 0 if all tests passed, -1 if any test had failures. |
There was a problem hiding this comment.
Does not return -1. Returns a specific ExitCode
| for task in tasks: | ||
| if task.cancelled(): | ||
| logger.error("A test task was cancelled: %s", task.get_name()) | ||
| return ExitCodes.GENERAL_EXCEPTION | ||
| exc = task.exception() | ||
| if exc is not None: | ||
| logger.error("A test task raised an exception: %s", exc) | ||
| return ExitCodes.GENERAL_EXCEPTION | ||
| if task.result() != 0: | ||
| return ExitCodes.VALIDATION_FAILURE |
There was a problem hiding this comment.
This is going to exit at the first test that had a problem. In that case, you would loose the results of the other tests.
| codes.append(ExitCodes.GENERAL_EXCEPTION if isinstance(result, BaseException) else result) | ||
| await cleanup_and_shutdown() | ||
|
|
||
| loop.create_task(run_all_tests_and_shutdown()) |
There was a problem hiding this comment.
This means that the shutdown of the tests is going to be blocked/waiting for all of the tests to finish up.
Instead, look at the callback that is being registered for when the test_task is "done". That method should look at the "result" and then track that using some shared thing. It looks like currently that could be the "codes" list.
| logger.info("Multi-server tests completed.") | ||
|
|
||
| # If any of the test exit codes are non-zero, return 1 to indicate a failure | ||
| if any(code != ExitCodes.SUCCESS for code in codes): |
There was a problem hiding this comment.
Might be able to just do if ExitCodes.SUCCESS in codes:
| ) | ||
| logger.info("Exiting.") | ||
| sys.exit(1) | ||
| #sys.exit(1) |
There was a problem hiding this comment.
Remove commented code
| if ret: | ||
| sys.exit(ret) |
There was a problem hiding this comment.
Set a default return value for ret at the top. Let it be overwritten by the other returns. Then, just do sys.exit(ret) here with no conditional
| logger = logging_helper.get_logger() | ||
|
|
||
| async def cleanup_and_shutdown() -> None: | ||
| ret = ExitCodes.SUCCESS |
There was a problem hiding this comment.
This should be at the top of interface() since it does not need to be globally scoped.
0e76f88 to
971cd1f
Compare
|
@ethan-thompson last minor update included, all commits squashed. I think we are good to merge. |
sys.exitusessys.exit(1)inrun_tests()async coroutine → usehad_exceptionflag andreturn -1task.result()calls against cancelled/exceptional tasks inrun_tests()isinstance(result, Exception)→isinstance(result, BaseException)inrun_all_tests_and_shutdown()main()to returnintinstead of callingsys.exitinterface()to callsys.exitbased onmain()return valuesys.exitcalls are properly ininterface()(topmost entry point)⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.