From 610c6ef3234589b038bfa19e9e6a6e18aad731f2 Mon Sep 17 00:00:00 2001 From: George Boukeas Date: Mon, 21 Oct 2024 14:30:26 +0100 Subject: [PATCH] fix(agent): make sure phase exit codes are in the 0-255 range (#385) * fix(agent): make sure phase exit codes are in the 0-255 range * chore: add test to check for phase status after timeout --- agent/testflinger_agent/job.py | 3 +++ agent/testflinger_agent/tests/test_agent.py | 26 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/agent/testflinger_agent/job.py b/agent/testflinger_agent/job.py index da275abb..3c4a8e96 100644 --- a/agent/testflinger_agent/job.py +++ b/agent/testflinger_agent/job.py @@ -120,6 +120,9 @@ def run_test_phase(self, phase, rundir): # Set exit_event to fail for this phase in case of an exception exit_event = f"{phase}_fail" exitcode, exit_event, exit_reason = runner.run(cmd) + # make sure the exit code is within the expected 0-255 range + # (this also handles negative numbers) + exitcode = exitcode % 256 except Exception as exc: logger.exception(exc) exitcode = 100 diff --git a/agent/testflinger_agent/tests/test_agent.py b/agent/testflinger_agent/tests/test_agent.py index a0aee422..badc9441 100644 --- a/agent/testflinger_agent/tests/test_agent.py +++ b/agent/testflinger_agent/tests/test_agent.py @@ -315,6 +315,32 @@ def test_phase_failed(self, agent, requests_mock): assert outcome_data.get("provision_status") == 1 assert outcome_data.get("test_status") is None + def test_phase_timeout(self, agent, requests_mock): + # Make sure the status code of a timed-out phase is correct + self.config["test_command"] = "sleep 12" + mock_job_data = { + "job_id": str(uuid.uuid1()), + "job_queue": "test", + "output_timeout": 1, + "test_data": {"test_cmds": "foo"}, + } + requests_mock.get( + rmock.ANY, [{"text": json.dumps(mock_job_data)}, {"text": "{}"}] + ) + requests_mock.post(rmock.ANY, status_code=200) + with patch("shutil.rmtree"), patch("os.unlink"): + agent.process_jobs() + outcome_file = os.path.join( + os.path.join( + self.tmpdir, + mock_job_data.get("job_id"), + "testflinger-outcome.json", + ) + ) + with open(outcome_file) as f: + outcome_data = json.load(f) + assert outcome_data.get("test_status") == 247 + def test_retry_transmit(self, agent, requests_mock): # Make sure we retry sending test results self.config["provision_command"] = "/bin/false"