Skip to content

Commit 953dbb7

Browse files
committed
Fix: use event.fail() instead of set_results(success=False)
1 parent 57441ed commit 953dbb7

File tree

2 files changed

+102
-16
lines changed

2 files changed

+102
-16
lines changed

lib/charms/mysql/v0/mysql.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -571,23 +571,27 @@ def _on_set_password(self, event: ActionEvent) -> None:
571571

572572
def _get_cluster_status(self, event: ActionEvent) -> None:
573573
"""Action used to retrieve the cluster status."""
574-
if event.params.get("cluster-set"):
575-
logger.debug("Getting cluster set status")
576-
status = self._mysql.get_cluster_set_status(extended=0)
577-
else:
578-
logger.debug("Getting cluster status")
579-
status = self._mysql.get_cluster_status()
574+
try:
575+
if event.params.get("cluster-set"):
576+
logger.debug("Getting cluster set status")
577+
status = self._mysql.get_cluster_set_status(extended=0)
578+
else:
579+
logger.debug("Getting cluster status")
580+
status = self._mysql.get_cluster_status()
580581

581-
if status:
582-
event.set_results({
583-
"success": True,
584-
"status": status,
585-
})
586-
else:
587-
event.set_results({
588-
"success": False,
589-
"message": "Failed to read cluster status. See logs for more information.",
590-
})
582+
except Exception:
583+
logger.exception("Failed to read cluster status")
584+
event.fail("Failed to read cluster status. See logs for more information.")
585+
return
586+
587+
if not status:
588+
event.fail("Failed to read cluster status. See logs for more information.")
589+
return
590+
591+
event.set_results({
592+
"success": True,
593+
"status": status,
594+
})
591595

592596
def _on_promote_to_primary(self, event: ActionEvent) -> None:
593597
"""Action for setting this unit as the cluster primary."""
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright 2025 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
from unittest.mock import Mock, PropertyMock, patch
5+
6+
import pytest
7+
from ops.charm import ActionEvent
8+
from ops.testing import Harness
9+
10+
from charm import MySQLOperatorCharm
11+
12+
13+
class FakeMySQLBackend:
14+
"""Simulates the real MySQL backend, either returning a dict or raising."""
15+
16+
def __init__(self, response=None, error=None):
17+
self._response = response
18+
self._error = error
19+
20+
def get_cluster_status(self):
21+
"""Return the preset response or raise the preset error."""
22+
if self._error:
23+
raise self._error
24+
return self._response
25+
26+
27+
@pytest.fixture
28+
def harness():
29+
"""Start the charm so harness.charm exists and peer databag works."""
30+
h = Harness(MySQLOperatorCharm)
31+
h.begin()
32+
return h
33+
34+
35+
def make_event():
36+
"""Create a dummy ActionEvent with spies on set_results() and fail()."""
37+
evt = Mock(spec=ActionEvent)
38+
evt.set_results = Mock()
39+
evt.fail = Mock()
40+
evt.params = {} # ensure .params.get() won’t AttributeError
41+
return evt
42+
43+
44+
def test_get_cluster_status_action_success(harness):
45+
"""On success, the action wraps and forwards the status dict."""
46+
# Prepare peer-databag so handler finds a cluster-name
47+
rel = harness.add_relation("database-peers", "database-peers")
48+
harness.update_relation_data(rel, harness.charm.app.name, {"cluster-name": "my-cluster"})
49+
50+
# Patch out the MySQL backend to return a known dict
51+
sample = {"clusterrole": "primary", "status": "ok"}
52+
fake = FakeMySQLBackend(response=sample)
53+
with patch.object(MySQLOperatorCharm, "_mysql", new_callable=PropertyMock, return_value=fake):
54+
evt = make_event()
55+
56+
# Invoke the action
57+
harness.charm._get_cluster_status(evt)
58+
59+
# Expect set_results called once with {'success': True, 'status': sample}
60+
evt.set_results.assert_called_once_with({"success": True, "status": sample})
61+
evt.fail.assert_not_called()
62+
63+
64+
def test_get_cluster_status_action_failure(harness):
65+
"""On backend error, the action calls event.fail() and does not set_results()."""
66+
# Seed peer-databag for cluster-name lookup
67+
rel = harness.add_relation("database-peers", "database-peers")
68+
harness.update_relation_data(rel, harness.charm.app.name, {"cluster-name": "my-cluster"})
69+
70+
# Patch MySQL backend to always raise
71+
fake = FakeMySQLBackend(error=RuntimeError("boom"))
72+
with patch.object(MySQLOperatorCharm, "_mysql", new_callable=PropertyMock, return_value=fake):
73+
evt = make_event()
74+
75+
# Invoke the action
76+
harness.charm._get_cluster_status(evt)
77+
78+
# It should report failure and never set_results
79+
evt.fail.assert_called_once_with(
80+
"Failed to read cluster status. See logs for more information."
81+
)
82+
evt.set_results.assert_not_called()

0 commit comments

Comments
 (0)