Skip to content

Commit 10baf46

Browse files
[DPE-4820] Update unit tests after fixing GCP backup test (#528)
* Fix GCP backup test Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Reset restore flag Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Correctly access application peer data Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Remove unnecessary code Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Fix leader check Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Update library Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Update test_set_primary_status_message Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Test leadership Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Update test_on_s3_credential_changed Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Add test_patroni_logs Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Add test_last_postgresql_logs * Update test_update_synchronous_node_count Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Add test_get_patroni_restart_condition Signed-off-by: Marcelo Henrique Neppel <[email protected]> * Add test_update_patroni_restart_condition Signed-off-by: Marcelo Henrique Neppel <[email protected]> --------- Signed-off-by: Marcelo Henrique Neppel <[email protected]>
1 parent 3f061fa commit 10baf46

File tree

3 files changed

+135
-5
lines changed

3 files changed

+135
-5
lines changed

tests/unit/test_backups.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,15 @@ def test_on_s3_credential_changed(harness):
11011101
_can_initialise_stanza.assert_called_once()
11021102
_is_primary.assert_not_called()
11031103

1104-
# Test that followers will not initialise the bucket
1104+
# Test that followers will not initialise the bucket (and that only the leader will
1105+
# remove the "require-change-bucket-after-restore" flag from the application databag).
1106+
with harness.hooks_disabled():
1107+
harness.set_leader()
1108+
harness.update_relation_data(
1109+
peer_rel_id,
1110+
harness.charm.app.name,
1111+
{"require-change-bucket-after-restore": "True"},
1112+
)
11051113
harness.charm.unit.status = ActiveStatus()
11061114
_render_pgbackrest_conf_file.reset_mock()
11071115
_can_initialise_stanza.return_value = True
@@ -1116,14 +1124,20 @@ def test_on_s3_credential_changed(harness):
11161124
relation=harness.model.get_relation(S3_PARAMETERS_RELATION, s3_rel_id)
11171125
)
11181126
_render_pgbackrest_conf_file.assert_called_once()
1127+
tc.assertNotIn(
1128+
"require-change-bucket-after-restore",
1129+
harness.get_relation_data(peer_rel_id, harness.charm.app),
1130+
)
11191131
_is_primary.assert_called_once()
11201132
_create_bucket_if_not_exists.assert_not_called()
11211133
tc.assertIsInstance(harness.charm.unit.status, ActiveStatus)
11221134
_can_use_s3_repository.assert_not_called()
11231135
_initialise_stanza.assert_not_called()
11241136

11251137
# Test when the charm render the pgBackRest configuration file, but fails to
1126-
# access or create the S3 bucket.
1138+
# access or create the S3 bucket (and assert that a non-leader unit won't
1139+
# remove the "require-change-bucket-after-restore" flag from the application
1140+
# databag).
11271141
_is_primary.return_value = True
11281142
for error in [
11291143
ClientError(
@@ -1132,13 +1146,26 @@ def test_on_s3_credential_changed(harness):
11321146
),
11331147
ValueError,
11341148
]:
1149+
with harness.hooks_disabled():
1150+
harness.set_leader(False)
1151+
harness.update_relation_data(
1152+
peer_rel_id,
1153+
harness.charm.app.name,
1154+
{"require-change-bucket-after-restore": "True"},
1155+
)
11351156
_render_pgbackrest_conf_file.reset_mock()
11361157
_create_bucket_if_not_exists.reset_mock()
11371158
_create_bucket_if_not_exists.side_effect = error
11381159
harness.charm.backup.s3_client.on.credentials_changed.emit(
11391160
relation=harness.model.get_relation(S3_PARAMETERS_RELATION, s3_rel_id)
11401161
)
11411162
_render_pgbackrest_conf_file.assert_called_once()
1163+
tc.assertEqual(
1164+
harness.get_relation_data(peer_rel_id, harness.charm.app)[
1165+
"require-change-bucket-after-restore"
1166+
],
1167+
"True",
1168+
)
11421169
_create_bucket_if_not_exists.assert_called_once()
11431170
tc.assertIsInstance(harness.charm.unit.status, BlockedStatus)
11441171
tc.assertEqual(

tests/unit/test_charm.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2362,14 +2362,44 @@ def test_update_new_unit_status(harness):
23622362
assert isinstance(harness.charm.unit.status, WaitingStatus)
23632363

23642364

2365-
def test_set_primary_status_message(harness):
2365+
@pytest.mark.parametrize("is_leader", [True, False])
2366+
def test_set_primary_status_message(harness, is_leader):
23662367
with (
23672368
patch("charm.Patroni.member_started", new_callable=PropertyMock) as _member_started,
23682369
patch(
23692370
"charm.PostgresqlOperatorCharm.is_standby_leader", new_callable=PropertyMock
23702371
) as _is_standby_leader,
23712372
patch("charm.Patroni.get_primary") as _get_primary,
23722373
):
2374+
# Test scenario when it's needed to move to another S3 bucket after a restore.
2375+
databag_containing_restore_data = {
2376+
"require-change-bucket-after-restore": "True",
2377+
"restoring-backup": "2024-01-01T09:00:00Z",
2378+
"restore-stanza": "fake-stanza",
2379+
"restore-to-time": "",
2380+
}
2381+
with harness.hooks_disabled():
2382+
harness.update_relation_data(
2383+
harness.model.get_relation(PEER).id,
2384+
harness.charm.app.name,
2385+
databag_containing_restore_data,
2386+
)
2387+
harness.set_leader(is_leader)
2388+
harness.charm._set_primary_status_message()
2389+
harness.get_relation_data(harness.model.get_relation(PEER).id, harness.charm.app.name) == (
2390+
{"require-change-bucket-after-restore": "True"}
2391+
if is_leader
2392+
else databag_containing_restore_data
2393+
)
2394+
tc.assertIsInstance(harness.charm.unit.status, BlockedStatus)
2395+
2396+
# Test other scenarios.
2397+
with harness.hooks_disabled():
2398+
harness.update_relation_data(
2399+
harness.model.get_relation(PEER).id,
2400+
harness.charm.app.name,
2401+
{"require-change-bucket-after-restore": ""},
2402+
)
23732403
for values in itertools.product(
23742404
[
23752405
RetryError(last_attempt=1),

tests/unit/test_cluster.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from charms.operator_libs_linux.v2 import snap
1111
from jinja2 import Template
1212
from ops.testing import Harness
13-
from tenacity import stop_after_delay
13+
from tenacity import RetryError, stop_after_delay, wait_fixed
1414

1515
from charm import PostgresqlOperatorCharm
1616
from cluster import Patroni
@@ -429,7 +429,9 @@ def test_switchover(peers_ips, patroni):
429429

430430

431431
def test_update_synchronous_node_count(peers_ips, patroni):
432-
with patch("requests.patch") as _patch:
432+
with patch("cluster.stop_after_delay", return_value=stop_after_delay(0)) as _wait_fixed, patch(
433+
"cluster.wait_fixed", return_value=wait_fixed(0)
434+
) as _wait_fixed, patch("requests.patch") as _patch:
433435
response = _patch.return_value
434436
response.status_code = 200
435437

@@ -439,6 +441,11 @@ def test_update_synchronous_node_count(peers_ips, patroni):
439441
"http://1.1.1.1:8008/config", json={"synchronous_node_count": 0}, verify=True
440442
)
441443

444+
# Test when the request fails.
445+
response.status_code = 500
446+
with tc.assertRaises(RetryError):
447+
patroni.update_synchronous_node_count()
448+
442449

443450
def test_configure_patroni_on_unit(peers_ips, patroni):
444451
with (
@@ -542,3 +549,69 @@ def test_member_inactive_error(peers_ips, patroni):
542549
assert patroni.member_inactive
543550

544551
_get.assert_called_once_with("http://1.1.1.1:8008/health", verify=True, timeout=5)
552+
553+
554+
def test_patroni_logs(patroni):
555+
with patch("charm.snap.SnapCache") as _snap_cache:
556+
# Test when the logs are returned successfully.
557+
logs = _snap_cache.return_value.__getitem__.return_value.logs
558+
logs.return_value = "fake-logs"
559+
assert patroni.patroni_logs() == "fake-logs"
560+
561+
# Test the charm fails to get the logs.
562+
logs.side_effect = snap.SnapError
563+
assert patroni.patroni_logs() == ""
564+
565+
566+
def test_last_postgresql_logs(patroni):
567+
with patch("glob.glob") as _glob, patch(
568+
"builtins.open", mock_open(read_data="fake-logs")
569+
) as _open:
570+
# Test when there are no files to read.
571+
assert patroni.last_postgresql_logs() == ""
572+
_open.assert_not_called()
573+
574+
# Test when there are multiple files in the logs directory.
575+
_glob.return_value = [
576+
"/var/snap/charmed-postgresql/common/var/log/postgresql/postgresql.log.1",
577+
"/var/snap/charmed-postgresql/common/var/log/postgresql/postgresql.log.2",
578+
"/var/snap/charmed-postgresql/common/var/log/postgresql/postgresql.log.3",
579+
]
580+
assert patroni.last_postgresql_logs() == "fake-logs"
581+
_open.assert_called_once_with(
582+
"/var/snap/charmed-postgresql/common/var/log/postgresql/postgresql.log.3", "r"
583+
)
584+
585+
# Test when the charm fails to read the logs.
586+
_open.reset_mock()
587+
_open.side_effect = OSError
588+
assert patroni.last_postgresql_logs() == ""
589+
_open.assert_called_with(
590+
"/var/snap/charmed-postgresql/common/var/log/postgresql/postgresql.log.3", "r"
591+
)
592+
593+
594+
def test_get_patroni_restart_condition(patroni):
595+
mock = mock_open()
596+
with patch("builtins.open", mock) as _open:
597+
# Test when there is a restart condition set.
598+
_open.return_value.__enter__.return_value.read.return_value = "Restart=always"
599+
assert patroni.get_patroni_restart_condition() == "always"
600+
601+
# Test when there is no restart condition set.
602+
_open.return_value.__enter__.return_value.read.return_value = ""
603+
with tc.assertRaises(RuntimeError):
604+
patroni.get_patroni_restart_condition()
605+
606+
607+
@pytest.mark.parametrize("new_restart_condition", ["on-success", "on-failure"])
608+
def test_update_patroni_restart_condition(patroni, new_restart_condition):
609+
with patch("builtins.open", mock_open(read_data="Restart=always")) as _open, patch(
610+
"subprocess.run"
611+
) as _run:
612+
_open.return_value.__enter__.return_value.read.return_value = "Restart=always"
613+
patroni.update_patroni_restart_condition(new_restart_condition)
614+
_open.return_value.__enter__.return_value.write.assert_called_once_with(
615+
f"Restart={new_restart_condition}"
616+
)
617+
_run.assert_called_once_with(["/bin/systemctl", "daemon-reload"])

0 commit comments

Comments
 (0)