|
| 1 | +# Copyright 2021 Canonical Ltd. |
| 2 | +# See LICENSE file for licensing details. |
| 3 | +from unittest.mock import Mock, PropertyMock, mock_open, patch, sentinel |
| 4 | + |
| 5 | +import pytest |
| 6 | +from single_kernel_postgresql.config.enums import Substrates |
| 7 | +from single_kernel_postgresql.core.state import CharmState |
| 8 | +from single_kernel_postgresql.managers.config import ConfigManager |
| 9 | +from single_kernel_postgresql.workload.k8s import K8sWorkload |
| 10 | +from single_kernel_postgresql.workload.vm import VMWorkload |
| 11 | + |
| 12 | + |
| 13 | +@pytest.fixture(autouse=True) |
| 14 | +def config(substrate): |
| 15 | + mock_charm = Mock() |
| 16 | + mock_container = Mock() |
| 17 | + workload = VMWorkload(".") if substrate == Substrates.VM else K8sWorkload(".", mock_container) |
| 18 | + with patch( |
| 19 | + "single_kernel_postgresql.workload.base.BaseWorkload.get_postgresql_version", |
| 20 | + return_value="16.6", |
| 21 | + ): |
| 22 | + config = ConfigManager( |
| 23 | + state=CharmState(charm=mock_charm, substrate=substrate), workload=workload |
| 24 | + ) |
| 25 | + yield config |
| 26 | + |
| 27 | + |
| 28 | +def test_dict_to_hba_string(config): |
| 29 | + mock_data = { |
| 30 | + "ldapbasedn": "dc=example,dc=net", |
| 31 | + "ldapbinddn": "cn=serviceuser,dc=example,dc=net", |
| 32 | + "ldapbindpasswd": "password", |
| 33 | + "ldaptls": False, |
| 34 | + "ldapurl": "ldap://0.0.0.0:3893", |
| 35 | + } |
| 36 | + |
| 37 | + assert config._dict_to_hba_string(mock_data) == ( |
| 38 | + 'ldapbasedn="dc=example,dc=net" ' |
| 39 | + 'ldapbinddn="cn=serviceuser,dc=example,dc=net" ' |
| 40 | + 'ldapbindpasswd="password" ' |
| 41 | + "ldaptls=0 " |
| 42 | + 'ldapurl="ldap://0.0.0.0:3893"' |
| 43 | + ) |
| 44 | + |
| 45 | + |
| 46 | +def test_render_patroni_yml_file(substrate, config): |
| 47 | + with ( |
| 48 | + patch( |
| 49 | + "single_kernel_postgresql.workload.base.BaseWorkload.get_postgresql_version", |
| 50 | + return_value="16.6", |
| 51 | + ), |
| 52 | + patch("single_kernel_postgresql.managers.config.render_file") as _render_file, |
| 53 | + patch("single_kernel_postgresql.managers.config.Template") as _template, |
| 54 | + patch( |
| 55 | + "single_kernel_postgresql.core.state.CharmState.config", new_callable=PropertyMock |
| 56 | + ) as _config, |
| 57 | + patch( |
| 58 | + "single_kernel_postgresql.core.state.CharmState.endpoint", |
| 59 | + new_callable=PropertyMock, |
| 60 | + return_value=sentinel.endpoint, |
| 61 | + ), |
| 62 | + patch( |
| 63 | + "single_kernel_postgresql.core.state.CharmState.model_name", |
| 64 | + new_callable=PropertyMock, |
| 65 | + return_value=sentinel.model_name, |
| 66 | + ), |
| 67 | + patch( |
| 68 | + "single_kernel_postgresql.core.state.CharmState.listen_ips", |
| 69 | + new_callable=PropertyMock, |
| 70 | + return_value=sentinel.listen_ips, |
| 71 | + ), |
| 72 | + patch( |
| 73 | + "single_kernel_postgresql.core.state.CharmState.unit_ip", |
| 74 | + new_callable=PropertyMock, |
| 75 | + return_value=sentinel.unit_ip, |
| 76 | + ), |
| 77 | + patch( |
| 78 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.patroni_password", |
| 79 | + new_callable=PropertyMock, |
| 80 | + return_value=sentinel.patroni_pass, |
| 81 | + ), |
| 82 | + patch( |
| 83 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.user_password", |
| 84 | + new_callable=PropertyMock, |
| 85 | + return_value=sentinel.user_pass, |
| 86 | + ), |
| 87 | + patch( |
| 88 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.replication_password", |
| 89 | + new_callable=PropertyMock, |
| 90 | + return_value=sentinel.replication_pass, |
| 91 | + ), |
| 92 | + patch( |
| 93 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.rewind_password", |
| 94 | + new_callable=PropertyMock, |
| 95 | + return_value=sentinel.rewind_pass, |
| 96 | + ), |
| 97 | + patch( |
| 98 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.raft_password", |
| 99 | + new_callable=PropertyMock, |
| 100 | + return_value=sentinel.raft_pass, |
| 101 | + ), |
| 102 | + patch( |
| 103 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.planned_units", |
| 104 | + new_callable=PropertyMock, |
| 105 | + return_value=1, |
| 106 | + ), |
| 107 | + patch( |
| 108 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.cluster_name", |
| 109 | + new_callable=PropertyMock, |
| 110 | + return_value=sentinel.cluster_name, |
| 111 | + ), |
| 112 | + patch( |
| 113 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.endpoints", |
| 114 | + new_callable=PropertyMock, |
| 115 | + return_value=["endpoint1", "endpoint2", "endpoint3"], |
| 116 | + ), |
| 117 | + patch( |
| 118 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLApplication.members_ips", |
| 119 | + new_callable=PropertyMock, |
| 120 | + return_value=["ip1", "ip2", "ip3"], |
| 121 | + ), |
| 122 | + patch( |
| 123 | + "single_kernel_postgresql.core.peer_relation.PostgreSQLPeer.member_name", |
| 124 | + new_callable=PropertyMock, |
| 125 | + return_value=sentinel.member_name, |
| 126 | + ), |
| 127 | + patch("builtins.open", mock_open(read_data="template")), |
| 128 | + ): |
| 129 | + _config.return_value.synchronous_node_count = 1 |
| 130 | + _config.return_value.durability_maximum_lag_on_failover = ( |
| 131 | + sentinel.durability_maximum_lag_on_failover |
| 132 | + ) |
| 133 | + _config.return_value.instance_password_encryption = sentinel.instance_password_encryption |
| 134 | + _template.return_value.render.return_value = sentinel.template_output |
| 135 | + |
| 136 | + config.render_patroni_yml_file() |
| 137 | + |
| 138 | + _template.assert_called_once_with("template") |
| 139 | + if substrate == Substrates.K8S: |
| 140 | + _template.return_value.render.assert_called_once_with( |
| 141 | + connectivity=False, |
| 142 | + enable_ldap=False, |
| 143 | + enable_tls=False, |
| 144 | + member_name=sentinel.member_name, |
| 145 | + superuser="operator", |
| 146 | + superuser_password=sentinel.user_pass, |
| 147 | + rewind_user="rewind", |
| 148 | + rewind_password=sentinel.rewind_pass, |
| 149 | + replication_password=sentinel.replication_pass, |
| 150 | + enable_pgbackrest_archiving=False, |
| 151 | + stanza=None, |
| 152 | + restore_stanza=None, |
| 153 | + restoring_backup=False, |
| 154 | + backup_id=None, |
| 155 | + pitr_target=None, |
| 156 | + restore_timeline=None, |
| 157 | + restore_to_latest=False, |
| 158 | + is_creating_backup=False, |
| 159 | + version="16", |
| 160 | + synchronous_node_count=0, |
| 161 | + maximum_lag_on_failover=sentinel.durability_maximum_lag_on_failover, |
| 162 | + pg_parameters=None, |
| 163 | + primary_cluster_endpoint=None, |
| 164 | + ldap_parameters="", |
| 165 | + patroni_password=sentinel.patroni_pass, |
| 166 | + user_databases_map=None, |
| 167 | + slots={}, |
| 168 | + instance_password_encryption=sentinel.instance_password_encryption, |
| 169 | + extra_replication_endpoints=[], |
| 170 | + endpoint=sentinel.endpoint, |
| 171 | + endpoints=["endpoint1", "endpoint2", "endpoint3"], |
| 172 | + is_no_sync_member=False, |
| 173 | + namespace=sentinel.model_name, |
| 174 | + storage_path="/var/lib/pg/data", |
| 175 | + logs_storage_path="/var/lib/pg/logs", |
| 176 | + pgdata_path="/var/lib/pg/data/16/main", |
| 177 | + ) |
| 178 | + _render_file.assert_called_once_with( |
| 179 | + substrate, "/var/lib/pg/data/patroni.yaml", sentinel.template_output, 0o644 |
| 180 | + ) |
| 181 | + else: |
| 182 | + _template.return_value.render.assert_called_once_with( |
| 183 | + connectivity=False, |
| 184 | + enable_ldap=False, |
| 185 | + enable_tls=False, |
| 186 | + member_name=sentinel.member_name, |
| 187 | + superuser="operator", |
| 188 | + superuser_password=sentinel.user_pass, |
| 189 | + rewind_user="rewind", |
| 190 | + rewind_password=sentinel.rewind_pass, |
| 191 | + replication_password=sentinel.replication_pass, |
| 192 | + enable_pgbackrest_archiving=False, |
| 193 | + stanza=None, |
| 194 | + restore_stanza=None, |
| 195 | + restoring_backup=False, |
| 196 | + backup_id=None, |
| 197 | + pitr_target=None, |
| 198 | + restore_timeline=None, |
| 199 | + restore_to_latest=False, |
| 200 | + is_creating_backup=False, |
| 201 | + version="16", |
| 202 | + synchronous_node_count=0, |
| 203 | + maximum_lag_on_failover=sentinel.durability_maximum_lag_on_failover, |
| 204 | + pg_parameters=None, |
| 205 | + primary_cluster_endpoint=None, |
| 206 | + ldap_parameters="", |
| 207 | + patroni_password=sentinel.patroni_pass, |
| 208 | + user_databases_map=None, |
| 209 | + slots={}, |
| 210 | + instance_password_encryption=sentinel.instance_password_encryption, |
| 211 | + extra_replication_endpoints=[], |
| 212 | + conf_path="/var/snap/charmed-postgresql/current/etc/patroni", |
| 213 | + log_path="/var/snap/charmed-postgresql/common/var/log/patroni", |
| 214 | + postgresql_log_path="/var/snap/charmed-postgresql/common/var/log/postgresql", |
| 215 | + data_path="/var/snap/charmed-postgresql/common/var/lib/postgresql/16/main", |
| 216 | + wal_dir="/var/snap/charmed-postgresql/common/data/logs/16/main", |
| 217 | + partner_addrs=[], |
| 218 | + peers_ips=["ip1", "ip2", "ip3"], |
| 219 | + pgbackrest_configuration_file="--config=/var/snap/charmed-postgresql/current/etc/pgbackrest/pgbackrest.conf", |
| 220 | + scope=sentinel.cluster_name, |
| 221 | + self_ip=sentinel.unit_ip, |
| 222 | + listen_ips=sentinel.listen_ips, |
| 223 | + raft_password=sentinel.raft_pass, |
| 224 | + watcher=None, |
| 225 | + ) |
| 226 | + _render_file.assert_called_once_with( |
| 227 | + substrate, |
| 228 | + "/var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml", |
| 229 | + sentinel.template_output, |
| 230 | + 0o600, |
| 231 | + ) |
0 commit comments