|
4 | 4 | import sys |
5 | 5 | from contextlib import contextmanager |
6 | 6 | from pathlib import Path |
7 | | -from unittest.mock import patch |
| 7 | +from unittest.mock import MagicMock, patch |
8 | 8 |
|
9 | 9 | import pytest |
10 | 10 | from cryptography import x509 |
@@ -36,7 +36,7 @@ def __init__(self, fw): |
36 | 36 | if hostname := self._mock_san: |
37 | 37 | sans.append(hostname) |
38 | 38 |
|
39 | | - self.ch = CertHandler(self, key="ch", sans=sans, refresh_events=[self.on.config_changed]) |
| 39 | + self.ch = CertHandler(self, key="ch", sans=sans) |
40 | 40 |
|
41 | 41 | @property |
42 | 42 | def _mock_san(self): |
@@ -145,6 +145,14 @@ def _cert_renew_patch(): |
145 | 145 | yield patcher |
146 | 146 |
|
147 | 147 |
|
| 148 | +@contextmanager |
| 149 | +def _cert_generate_patch(): |
| 150 | + with patch( |
| 151 | + "charms.tls_certificates_interface.v3.tls_certificates.TLSCertificatesRequiresV3.request_certificate_creation" |
| 152 | + ) as patcher: |
| 153 | + yield patcher |
| 154 | + |
| 155 | + |
148 | 156 | @pytest.mark.parametrize("leader", (True, False)) |
149 | 157 | def test_cert_joins(ctx, certificates, leader): |
150 | 158 | with ctx.manager( |
@@ -183,48 +191,56 @@ def test_cert_joins_peer_vault_backend(ctx_juju2, certificates, leader): |
183 | 191 | assert mgr.charm.ch.private_key |
184 | 192 |
|
185 | 193 |
|
186 | | -def test_renew_csr_on_sans_change(ctx, certificates): |
187 | | - # generate a CSR |
| 194 | +# CertHandler generates a cert on `config_changed` event |
| 195 | +@pytest.mark.parametrize( |
| 196 | + "event,expected_generate_calls", |
| 197 | + (("update_status", 0), ("start", 0), ("install", 0), ("config_changed", 1)), |
| 198 | +) |
| 199 | +def test_no_renew_if_no_initial_csr_was_generated( |
| 200 | + event, expected_generate_calls, ctx, certificates |
| 201 | +): |
| 202 | + with _cert_renew_patch() as renew_patch: |
| 203 | + with _cert_generate_patch() as generate_patch: |
| 204 | + with ctx.manager( |
| 205 | + event, |
| 206 | + State(leader=True, relations=[certificates]), |
| 207 | + ) as mgr: |
| 208 | + |
| 209 | + mgr.run() |
| 210 | + assert renew_patch.call_count == 0 |
| 211 | + assert generate_patch.call_count == expected_generate_calls |
| 212 | + |
| 213 | + |
| 214 | +@patch.object(CertHandler, "_stored", MagicMock()) |
| 215 | +@pytest.mark.parametrize( |
| 216 | + "is_relation, event", |
| 217 | + ( |
| 218 | + (False, "start"), |
| 219 | + (True, "changed_event"), |
| 220 | + (False, "config_changed"), |
| 221 | + ), |
| 222 | +) |
| 223 | +def test_csr_renew_on_any_event(is_relation, event, ctx, certificates): |
188 | 224 | with ctx.manager( |
189 | | - certificates.joined_event, |
190 | | - State(leader=True, relations=[certificates]), |
| 225 | + getattr(certificates, event) if is_relation else event, |
| 226 | + State( |
| 227 | + leader=True, |
| 228 | + relations=[certificates], |
| 229 | + ), |
191 | 230 | ) as mgr: |
192 | 231 | charm = mgr.charm |
193 | 232 | state_out = mgr.run() |
194 | 233 | orig_csr = get_csr_obj(charm.ch._csr) |
195 | 234 | assert get_sans_from_csr(orig_csr) == {socket.getfqdn()} |
196 | 235 |
|
197 | | - # trigger a config_changed with a modified SAN |
198 | 236 | with _sans_patch(): |
199 | | - with ctx.manager("config_changed", state_out) as mgr: |
| 237 | + with ctx.manager("update_status", state_out) as mgr: |
200 | 238 | charm = mgr.charm |
201 | 239 | state_out = mgr.run() |
202 | 240 | csr = get_csr_obj(charm.ch._csr) |
203 | | - # assert CSR contains updated SAN |
204 | 241 | assert get_sans_from_csr(csr) == {socket.getfqdn(), MOCK_HOSTNAME} |
205 | 242 |
|
206 | 243 |
|
207 | | -def test_csr_no_change_on_wrong_refresh_event(ctx, certificates): |
208 | | - with _cert_renew_patch() as renew_patch: |
209 | | - with ctx.manager( |
210 | | - "config_changed", |
211 | | - State(leader=True, relations=[certificates]), |
212 | | - ) as mgr: |
213 | | - charm = mgr.charm |
214 | | - state_out = mgr.run() |
215 | | - orig_csr = get_csr_obj(charm.ch._csr) |
216 | | - assert get_sans_from_csr(orig_csr) == {socket.getfqdn()} |
217 | | - |
218 | | - with _sans_patch(): |
219 | | - with _cert_renew_patch() as renew_patch: |
220 | | - with ctx.manager("update_status", state_out) as mgr: |
221 | | - charm = mgr.charm |
222 | | - state_out = mgr.run() |
223 | | - csr = get_csr_obj(charm.ch._csr) |
224 | | - assert get_sans_from_csr(csr) == {socket.getfqdn()} |
225 | | - assert renew_patch.call_count == 0 |
226 | | - |
227 | | - |
228 | 244 | def test_csr_no_change(ctx, certificates): |
229 | 245 |
|
230 | 246 | with ctx.manager( |
|
0 commit comments