Skip to content

Commit 580404a

Browse files
cfsmp3claude
andcommitted
test: Add tests for artifact diagnosis and error_message property
Add tests to improve coverage for the new code: - TestDiagnoseMissingArtifact: 6 tests covering all code paths - Build in progress - Build failed - Artifact expired (build succeeded but no artifact) - No workflow run found - Different workflow (wrong workflow name) - Exception handling - TestErrorMessage: 4 tests for Test.error_message property - Returns None when no progress entries - Returns None when completed successfully - Returns message when test is canceled - Returns last message from multiple progress entries 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4b67550 commit 580404a

File tree

2 files changed

+177
-1
lines changed

2 files changed

+177
-1
lines changed

tests/test_ci/test_controllers.py

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from flask import g
77

88
from mod_auth.models import Role
9-
from mod_ci.controllers import (Workflow_builds, get_info_for_pr_comment,
9+
from mod_ci.controllers import (Workflow_builds, _diagnose_missing_artifact,
10+
get_info_for_pr_comment,
1011
progress_type_request, start_platforms)
1112
from mod_ci.models import BlockedUsers
1213
from mod_customized.models import CustomizedTest
@@ -2047,3 +2048,129 @@ def generate_header(data, event, ci_key=None):
20472048
'utf-8'), g.github['ci_key'] if ci_key is None else ci_key)
20482049
headers = generate_git_api_header(event, sig)
20492050
return headers
2051+
2052+
2053+
class TestDiagnoseMissingArtifact(BaseTestCase):
2054+
"""Test the _diagnose_missing_artifact function."""
2055+
2056+
def test_diagnose_build_in_progress(self):
2057+
"""Test diagnosis when build is still in progress."""
2058+
mock_repo = MagicMock()
2059+
mock_log = MagicMock()
2060+
2061+
# Mock workflow
2062+
mock_workflow = MagicMock()
2063+
mock_workflow.id = 1
2064+
mock_workflow.name = "Build CCExtractor on Windows"
2065+
mock_repo.get_workflows.return_value = [mock_workflow]
2066+
2067+
# Mock workflow run - in progress
2068+
mock_run = MagicMock()
2069+
mock_run.workflow_id = 1
2070+
mock_run.status = "in_progress"
2071+
mock_repo.get_workflow_runs.return_value = [mock_run]
2072+
2073+
result = _diagnose_missing_artifact(
2074+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2075+
2076+
self.assertIn("Build still in progress", result)
2077+
self.assertIn("in_progress", result)
2078+
2079+
def test_diagnose_build_failed(self):
2080+
"""Test diagnosis when build failed."""
2081+
mock_repo = MagicMock()
2082+
mock_log = MagicMock()
2083+
2084+
mock_workflow = MagicMock()
2085+
mock_workflow.id = 1
2086+
mock_workflow.name = "Build CCExtractor on Windows"
2087+
mock_repo.get_workflows.return_value = [mock_workflow]
2088+
2089+
mock_run = MagicMock()
2090+
mock_run.workflow_id = 1
2091+
mock_run.status = "completed"
2092+
mock_run.conclusion = "failure"
2093+
mock_repo.get_workflow_runs.return_value = [mock_run]
2094+
2095+
result = _diagnose_missing_artifact(
2096+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2097+
2098+
self.assertIn("Build failed", result)
2099+
self.assertIn("failure", result)
2100+
2101+
def test_diagnose_artifact_expired(self):
2102+
"""Test diagnosis when build succeeded but artifact not found."""
2103+
mock_repo = MagicMock()
2104+
mock_log = MagicMock()
2105+
2106+
mock_workflow = MagicMock()
2107+
mock_workflow.id = 1
2108+
mock_workflow.name = "Build CCExtractor on Windows"
2109+
mock_repo.get_workflows.return_value = [mock_workflow]
2110+
2111+
mock_run = MagicMock()
2112+
mock_run.workflow_id = 1
2113+
mock_run.status = "completed"
2114+
mock_run.conclusion = "success"
2115+
mock_repo.get_workflow_runs.return_value = [mock_run]
2116+
2117+
result = _diagnose_missing_artifact(
2118+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2119+
2120+
self.assertIn("Artifact not found", result)
2121+
self.assertIn("expired", result)
2122+
2123+
def test_diagnose_no_workflow_run_found(self):
2124+
"""Test diagnosis when no workflow run exists for commit."""
2125+
mock_repo = MagicMock()
2126+
mock_log = MagicMock()
2127+
2128+
mock_workflow = MagicMock()
2129+
mock_workflow.id = 1
2130+
mock_workflow.name = "Build CCExtractor on Windows"
2131+
mock_repo.get_workflows.return_value = [mock_workflow]
2132+
2133+
# No workflow runs for this commit
2134+
mock_repo.get_workflow_runs.return_value = []
2135+
2136+
result = _diagnose_missing_artifact(
2137+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2138+
2139+
self.assertIn("No workflow run found", result)
2140+
self.assertIn("abc1234", result)
2141+
2142+
def test_diagnose_different_workflow(self):
2143+
"""Test diagnosis when only different workflows have run."""
2144+
mock_repo = MagicMock()
2145+
mock_log = MagicMock()
2146+
2147+
mock_workflow = MagicMock()
2148+
mock_workflow.id = 1
2149+
mock_workflow.name = "Build CCExtractor on Linux"
2150+
mock_repo.get_workflows.return_value = [mock_workflow]
2151+
2152+
mock_run = MagicMock()
2153+
mock_run.workflow_id = 1
2154+
mock_run.status = "completed"
2155+
mock_run.conclusion = "success"
2156+
mock_repo.get_workflow_runs.return_value = [mock_run]
2157+
2158+
result = _diagnose_missing_artifact(
2159+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2160+
2161+
self.assertIn("No workflow run found", result)
2162+
2163+
def test_diagnose_exception_handling(self):
2164+
"""Test diagnosis handles exceptions gracefully."""
2165+
mock_repo = MagicMock()
2166+
mock_log = MagicMock()
2167+
2168+
# Make get_workflows raise an exception
2169+
mock_repo.get_workflows.side_effect = Exception("API error")
2170+
2171+
result = _diagnose_missing_artifact(
2172+
mock_repo, "abc1234", "Build CCExtractor on Windows", mock_log)
2173+
2174+
self.assertIn("diagnostic check failed", result)
2175+
self.assertIn("API error", result)
2176+
mock_log.warning.assert_called_once()

tests/test_test/test_controllers.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,52 @@ def test_download_build_log_file(self, mock_g, mock_serve, mock_test, mock_os):
257257
self.assertEqual(response, mock_serve())
258258
mock_test.query.filter.assert_called_once()
259259
mock_os.path.isfile.assert_called_once()
260+
261+
262+
class TestErrorMessage(BaseTestCase):
263+
"""Test the error_message property on Test model."""
264+
265+
def test_error_message_returns_none_when_not_failed(self):
266+
"""Test error_message returns None when test has not failed."""
267+
from flask import g
268+
test = Test.query.get(1)
269+
# Test with no progress entries
270+
self.assertIsNone(test.error_message)
271+
272+
def test_error_message_returns_none_when_completed_successfully(self):
273+
"""Test error_message returns None when test completed successfully."""
274+
from flask import g
275+
test = Test.query.get(1)
276+
277+
# Add completed progress
278+
progress = TestProgress(test.id, TestStatus.completed, "Test completed")
279+
g.db.add(progress)
280+
g.db.commit()
281+
282+
self.assertIsNone(test.error_message)
283+
284+
def test_error_message_returns_message_when_canceled(self):
285+
"""Test error_message returns the message when test is canceled."""
286+
from flask import g
287+
test = Test.query.get(1)
288+
289+
# Add canceled progress with error message
290+
error_msg = "No build artifact found for this commit"
291+
progress = TestProgress(test.id, TestStatus.canceled, error_msg)
292+
g.db.add(progress)
293+
g.db.commit()
294+
295+
self.assertEqual(test.error_message, error_msg)
296+
297+
def test_error_message_returns_last_message(self):
298+
"""Test error_message returns the message from the last progress entry."""
299+
from flask import g
300+
test = Test.query.get(1)
301+
302+
# Add multiple progress entries
303+
progress1 = TestProgress(test.id, TestStatus.preparation, "Preparing")
304+
progress2 = TestProgress(test.id, TestStatus.canceled, "Build failed: workflow finished with failure")
305+
g.db.add_all([progress1, progress2])
306+
g.db.commit()
307+
308+
self.assertEqual(test.error_message, "Build failed: workflow finished with failure")

0 commit comments

Comments
 (0)