def test_config_changed(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "cert-path": "/cert/path", "chain-path": "/chain/path", "combined-path": "/combined/path", "deploy-command": "/bin/deploy", "fullchain-path": "/fullchain/path", "key-path": "/key/path", } harness.update_config(self._config(harness.charm, **config)) charm._host.write_config.assert_called_once() args = charm._host.write_config.call_args.args self.assertEqual(args[0], "/etc/certbot-charm/config.ini") self.assertEqual(args[1], { 'DEFAULT': { 'cert-path': '/cert/path', 'chain-path': '/chain/path', 'combined-path': '/combined/path', 'fullchain-path': '/fullchain/path', 'key-path': '/key/path'}, 'deploy': { 'command': '/bin/deploy'}}) charm._host.write_file.assert_called_once_with( "/etc/certbot-charm/dns-google.json", b"", mode=0o600)
def test_cron_schedule_set(self, mock_open_call, os_path_isdir, os_makedirs, os_symlink): harness = Harness(SimpleStreamsCharm) self.addCleanup(harness.cleanup) harness.begin() default_config = self.default_config() default_config['cron-schedule'] = str(uuid4()) self.assertEqual(harness.charm._stored.config, {}) harness.update_config(default_config) self.assertEqual(harness.charm._stored.config, default_config) mock_open_call.assert_called_with( '/etc/cron.d/{}'.format(harness.charm.model.app.name), "w") mock_open_call.return_value.write.assert_called_once_with( "{} root sstream-mirror --keep" " --keyring={} --path={} --log-file={} --max={} {} {} \'{}\'\n". format( default_config['cron-schedule'], default_config['keyring-file'], default_config['path'], default_config['log-file'], default_config['image-max'], default_config['image-source'], "{}/latest".format(default_config['image-dir']), default_config['image-selectors'], )) self.assertTrue(os_path_isdir.called) self.assertFalse(os_makedirs.called) self.assertFalse(os_symlink.called)
def test_config_changed(self): harness = Harness(OpenfaasQueueWorkerCharm) self.addCleanup(harness.cleanup) harness.begin() self.assertEqual(list(harness.charm._stored.things), []) harness.update_config({"thing": "foo"}) self.assertEqual(list(harness.charm._stored.things), ["foo"])
def test_get_certificate_action_fail(self): os.environ["JUJU_ACTION_UUID"] = "1" charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) event = Mock( params={ "agree-tos": True, "credentials": "AAAA", "domains": "action.example.com", "email": "*****@*****.**", "plugin": "dns-google", "propagation-seconds": 30 }) charm._host.run.side_effect = subprocess.CalledProcessError( 1, "certbot") charm._host.exists.return_value = True harness.charm._on_get_certificate_action(event) event.fail.assert_called_once_with( "cannot get certificate: Command 'certbot' returned non-zero exit status 1." ) charm._host.unlink.assert_called_once_with( "/etc/certbot-charm/action-1.cred")
class KafkaCharmTest(unittest.TestCase): def setUp(self) -> None: self.harness = Harness(KafkaOperator) self.addCleanup(self.harness.cleanup) self.harness.begin() self.harness.add_oci_resource("kafka-image") self.harness.update_config(BASE_CONFIG) def test_kafka_layer(self): expected = { "summary": "kafka layer", "description": "kafka layer", "services": { "kafka-setup": { "override": "replace", "summary": "kafka setup step - initialize & format storage", "command": "/opt/bitnami/kafka/bin/kafka-storage.sh format -t test-id -c /opt/bitnami/kafka/config/kraft/server.properties", "startup": "enabled", }, "kafka": { "override": "replace", "summary": "kafka service", "command": "/opt/bitnami/kafka/bin/kafka-server-start.sh /opt/bitnami/kafka/config/kraft/server.properties", "startup": "enabled", "requires": ["kafka-setup"], }, }, } assert self.harness.charm._kafka_layer() == expected
def test_config_changed(self): harness = Harness(JujuDashboardCharm) self.addCleanup(harness.cleanup) harness.begin() self.assertEqual(list(harness.charm._stored.things), []) harness.update_config({"thing": "foo"}) self.assertEqual(list(harness.charm._stored.things), ["foo"])
def test_run_certbot_params(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "agree-tos": False, "domains": "charm.example.com,www.charm.example.com", "email": "*****@*****.**" } harness.update_config(self._config(harness.charm, **config)) harness.charm._run_certbot( "test", True, "*****@*****.**", "params.example.com,www.params.example.com", ["--extra-1", "--extra-2"], { "ENV1": "e1", "ENV2": "e2" }) charm._host.run.assert_called_once_with([ "certbot", "certonly", "-n", "--no-eff-email", "--test", "--agree-tos", "[email protected]", "--domains=params.example.com,www.params.example.com", "--extra-1", "--extra-2" ], env={ "ENV1": "e1", "ENV2": "e2" })
def test_get_dns_google_certificate_action_defaults(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "agree-tos": True, "dns-google-credentials": "AAAA", "dns-google-propagation-seconds": 40, "domains": "charm.example.com", "email": "*****@*****.**"} harness.update_config(self._config(harness.charm, **config)) event = Mock(params={}) harness.charm._on_get_dns_google_certificate_action(event) self.assertEqual(len(charm._host.run.call_args_list), 2) self.assertEqual( charm._host.run.call_args_list[0], call(["certbot", "certonly", "-n", "--no-eff-email", "--dns-google", "--agree-tos", "[email protected]", "--domains=charm.example.com", "--dns-google-credentials=/etc/certbot-charm/dns-google.json", "--dns-google-propagation-seconds=40"])) self.assertEqual(charm._host.run.call_args_list[1][0], ([ '/etc/letsencrypt/renewal-hooks/deploy/certbot-charm'],)) self.assertEqual(charm._host.run.call_args_list[1][1]["env"] ["RENEWED_LINEAGE"], "/etc/letsencrypt/live/charm.example.com")
def test_get_certificate_action_dns_rfc2136(self): os.environ["JUJU_ACTION_UUID"] = "1" charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) event = Mock( params={ "agree-tos": True, "credentials": "AAAA", "domains": "action.example.com", "email": "*****@*****.**", "propagation-seconds": 30, "plugin": "dns-rfc2136" }) harness.charm._on_get_certificate_action(event) self.assertEqual(len(charm._host.run.call_args_list), 2) self.assertEqual( charm._host.run.call_args_list[0], call([ "certbot", "certonly", "-n", "--no-eff-email", "--dns-rfc2136", "--agree-tos", "[email protected]", "--domains=action.example.com", "--dns-rfc2136-credentials=/etc/certbot-charm/action-1.cred", "--dns-rfc2136-propagation-seconds=30" ], env=None)) self.assertEqual( charm._host.run.call_args_list[1][0], (['/etc/letsencrypt/renewal-hooks/deploy/certbot-charm'], )) self.assertEqual( charm._host.run.call_args_list[1][1]["env"]["RENEWED_LINEAGE"], "/etc/letsencrypt/live/action.example.com")
class TestCharm(unittest.TestCase): def setUp(self): self.harness = Harness(MongoDBCharm) self.addCleanup(self.harness.cleanup) mongo_resource = { "registrypath": "mongodb:4.4.1", "username": "******", "password": "******" } self.harness.add_oci_resource("mongodb-image", mongo_resource) self.harness.begin() def test_replica_set_name_can_be_changed(self): self.harness.set_leader(True) # check default replica set name self.harness.charm.on.config_changed.emit() pod_spec = self.harness.get_pod_spec() self.assertEqual(replica_set_name(pod_spec), "rs0") # check replica set name can be changed self.harness.update_config({"replica_set_name": "new_name"}) pod_spec = self.harness.get_pod_spec() self.assertEqual(replica_set_name(pod_spec), "new_name") @patch("mongoserver.MongoDB.reconfigure_replica_set") def test_replica_set_is_reconfigured_when_peer_joins(self, mock_reconf): self.harness.set_leader(True) rel_id = self.harness.add_relation('mongodb', 'mongodb') self.harness.add_relation_unit(rel_id, 'mongodb/1') self.harness.update_relation_data(rel_id, 'mongodb/1', {'private-address': '10.0.0.1'}) peers = ['mongodb-0.mongodb-endpoints', 'mongodb-1.mongodb-endpoints'] mock_reconf.assert_called_once_with(peers) def test_uri_data_is_generated_correctly(self): self.harness.set_leader(True) standalone_uri = self.harness.charm.mongo.standalone_uri replica_set_uri = self.harness.charm.mongo.replica_set_uri self.assertEqual(standalone_uri, 'mongodb://mongodb:27017/') self.assertEqual(replica_set_uri, 'mongodb://mongodb-0.mongodb-endpoints:27017/') def test_database_relation_data_is_set_correctly(self): self.harness.set_leader(True) rel_id = self.harness.add_relation('database', 'client') self.harness.add_relation_unit(rel_id, 'client/1') rel = self.harness.framework.model.get_relation('database', rel_id) unit = self.harness.framework.model.get_unit('client/1') self.harness.charm.on['database'].relation_changed.emit(rel, unit) got = self.harness.get_relation_data(rel_id, self.harness.framework.model.unit.name) expected = { 'replicated': 'False', 'replica_set_name': 'rs0', 'standalone_uri': 'mongodb://mongodb:27017/', 'replica_set_uri': 'mongodb://mongodb-0.mongodb-endpoints:27017/' } self.assertDictEqual(got, expected)
def test_config_changed(self): harness = Harness(JujuControllerCharm) self.addCleanup(harness.cleanup) harness.begin() self.assertEqual(list(harness.charm._stored.things), []) harness.update_config({"controller-url": "https://controller"}) self.assertEqual(list(harness.charm._stored.things), ["https://controller"])
def test_config_changed(self): harness = Harness(CharmK8SCassandraCharm) # from 0.8 you should also do: # self.addCleanup(harness.cleanup) harness.begin() self.assertEqual(list(harness.charm._stored.things), []) harness.update_config({"thing": "foo"}) self.assertEqual(list(harness.charm._stored.things), ["foo"])
def test_get_certificate_unknown_plugin(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) with self.assertRaises(charm.UnsupportedPluginError): harness.charm._get_certificate("no-such-plugin", False, "", "")
def test_start_no_certificate(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) harness.charm.on.start.emit() self.assertEqual(harness.charm.model.unit.status, BlockedStatus('certificate not yet acquired.'))
def test_run_certbot_nothing_set(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) harness.charm._run_certbot("test", False, "", "") charm._host.run.assert_called_once_with( ["certbot", "certonly", "-n", "--no-eff-email", "--test"])
class TestCharm(unittest.TestCase): def setUp(self): self.harness = Harness(HookTestCharm) self.addCleanup(self.harness.cleanup) self.harness.begin() def test_config_changed(self): self.assertEqual(list(self.harness.charm._stored.things), []) self.harness.update_config({"thing": "foo"}) self.assertEqual(list(self.harness.charm._stored.things), ["foo"]) def test_action(self): # the harness doesn't (yet!) help much with actions themselves action_event = Mock(params={"fail": ""}) self.harness.charm._on_fortune_action(action_event) self.assertTrue(action_event.set_results.called) def test_action_fail(self): action_event = Mock(params={"fail": "fail this"}) self.harness.charm._on_fortune_action(action_event) self.assertEqual(action_event.fail.call_args, [("fail this", )]) def test_httpbin_pebble_ready(self): # Check the initial Pebble plan is empty initial_plan = self.harness.get_container_pebble_plan("httpbin") self.assertEqual(initial_plan.to_yaml(), "{}\n") # Expected plan after Pebble ready with default config expected_plan = { "services": { "httpbin": { "override": "replace", "summary": "httpbin", "command": "gunicorn -b 0.0.0.0:80 httpbin:app -k gevent", "startup": "enabled", "environment": { "thing": "🎁" }, } }, } # Get the httpbin container from the model container = self.harness.model.unit.get_container("httpbin") # Emit the PebbleReadyEvent carrying the httpbin container self.harness.charm.on.httpbin_pebble_ready.emit(container) # Get the plan now we've run PebbleReady updated_plan = self.harness.get_container_pebble_plan( "httpbin").to_dict() # Check we've got the plan we expected self.assertEqual(expected_plan, updated_plan) # Check the service was started service = self.harness.model.unit.get_container("httpbin").get_service( "httpbin") self.assertTrue(service.is_running()) # Ensure we set an ActiveStatus with no message self.assertEqual(self.harness.model.unit.status, ActiveStatus())
class TestCharm(unittest.TestCase): def setUp(self): self.harness = Harness(PlanServicesTestCharm) self.addCleanup(self.harness.cleanup) self.harness.begin() def test_config_changed(self): self.harness.update_config({"thing": "foo"}) self.assertEqual(self.harness.model.unit.status, ActiveStatus())
def test_repo_register(self, run, wt, rm): """Test repo registration""" harness = Harness(GithubRunnerOperator) harness.update_config({ "path": "mockorg/repo", "token": "mocktoken", "reconcile-interval": 5 }) harness.begin() harness.charm.on.config_changed.emit() rm.assert_called_with("mockorg/repo", "mocktoken", "github-runner", 5)
def test_publish_relation_joined(self, mock_open_call, os_path_isdir, os_makedirs, os_symlink): harness = Harness(SimpleStreamsCharm) harness.begin() default_config = self.default_config() self.assertEqual(harness.charm._stored.config, {}) harness.update_config(default_config) relation_id = harness.add_relation('publish', 'webserver') harness.add_relation_unit(relation_id, 'webserver/0') assert harness.get_relation_data(relation_id, harness._unit_name)\ == {'path': '{}/publish'.format(default_config['image-dir'])}
class TestCharm(unittest.TestCase): def setUp(self) -> None: self.harness = Harness(TrainingCharm) self.addCleanup(self.harness.cleanup) self.harness.begin() def test__grafana_port_config_changed(self): self.harness.set_leader(True) self.harness.update_config({"grafana_port": 4000}) pod_spec = self.harness.get_pod_spec()[0] self.assertEqual(pod_spec["containers"][0]["ports"][0]["containerPort"], 4000) self.assertEqual(pod_spec["containers"][0]["readinessProbe"]["httpGet"]["port"], 4000)
def test_config_changed(self, os_path_isdir, os_makedirs, os_symlink): harness = Harness(SimpleStreamsCharm) self.addCleanup(harness.cleanup) os_path_isdir.return_value = False harness.begin() default_config = self.default_config() self.assertEqual(harness.charm._stored.config, {}) harness.update_config(default_config) self.assertTrue(os_path_isdir.called) self.assertTrue(os_makedirs.called) self.assertTrue(os_symlink.called) assert harness.charm._stored.config == default_config
def test_config_changed(self): harness = Harness(SubCephMonCharm) self.addCleanup(harness.cleanup) harness.begin() self.assertEqual(harness.charm._stored.rados_gw, { 'hostname': '', 'port': '' }) harness.update_config() self.assertEqual(harness.charm._stored.rados_gw, { 'hostname': '', 'port': '' })
def test_hooks_enabled_and_disabled(self): harness = Harness(RecordingCharm, meta=''' name: test-charm ''') # Before begin() there are no events. harness.update_config({'value': 'first'}) # By default, after begin the charm is set up to receive events. harness.begin() harness.update_config({'value': 'second'}) self.assertEqual(harness.charm.get_changes(reset=True), [{ 'name': 'config', 'data': { 'value': 'second' } }]) # Once disabled, we won't see config-changed when we make an update harness.disable_hooks() harness.update_config({'third': '3'}) self.assertEqual(harness.charm.get_changes(reset=True), []) harness.enable_hooks() harness.update_config({'value': 'fourth'}) self.assertEqual(harness.charm.get_changes(reset=True), [{ 'name': 'config', 'data': { 'value': 'fourth', 'third': '3' } }])
def test_run_certbot_charm_config(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "agree-tos": True, "domains": "charm.example.com,www.charm.example.com", "email": "*****@*****.**"} harness.update_config(self._config(harness.charm, **config)) harness.charm._run_certbot(plugin="test") charm._host.run.assert_called_once_with( ["certbot", "certonly", "-n", "--no-eff-email", "--test", "--agree-tos", "[email protected]", "--domains=charm.example.com,www.charm.example.com"])
def test_start_get_certificate(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "agree-tos": True, "domains": "example.com", "email": "*****@*****.**", "plugin": "dns-google", } harness.update_config(self._config(harness.charm, **config)) harness.charm.on.start.emit() self.assertEqual(harness.charm.model.unit.status, ActiveStatus('maintaining certificate for example.com.'))
def test_get_dns_google_certificate_action_fail(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() harness.update_config(self._config(harness.charm)) event = Mock(params={ "agree-tos": True, "credentials": "AAAA", "domains": "action.example.com", "email": "*****@*****.**", "propagation-seconds": 30}) charm._host.run.side_effect = subprocess.CalledProcessError(1, "certbot") harness.charm._on_get_dns_google_certificate_action(event) event.fail.assert_called_once_with( "cannot get certificate: Command 'certbot' returned non-zero exit status 1.")
class TestCharm(unittest.TestCase): """MetalLB Controller Charm Unit Tests.""" @patch.dict('charm.os.environ', {'JUJU_MODEL_NAME': 'unit-test-metallb'}) def setUp(self): """Test setup.""" self.harness = Harness(MetallbControllerCharm) self.harness.set_leader(is_leader=True) self.harness.begin() @patch.dict('charm.os.environ', {'JUJU_MODEL_NAME': 'unit-test-metallb'}) @patch("utils.bind_role_with_api") @patch("utils.create_namespaced_role_with_api") @patch("utils.create_pod_security_policy_with_api") def test_on_start(self, create_psp, create_ns_role, create_ns_role_binding): """Test installation.""" mock_pod_spec = self.harness.charm.set_pod_spec = Mock() self.assertFalse(self.harness.charm._stored.started) self.harness.charm.on.start.emit() mock_pod_spec.assert_called_once() create_psp.assert_called_once() create_ns_role.assert_called_once() create_ns_role_binding.assert_called_once() self.assertTrue(self.harness.charm._stored.started) def test_config_changed(self): """Test update config upon change.""" mock_pod_spec = self.harness.charm.set_pod_spec = Mock() self.assertFalse(self.harness.charm._stored.configured) self.harness.update_config({"iprange": "192.168.1.88-192.168.1.89"}) mock_pod_spec.assert_called_once() self.assertTrue(self.harness.charm._stored.configured) @patch("utils.delete_namespaced_role_with_api") @patch("utils.delete_namespaced_role_binding_with_api") @patch("utils.delete_pod_security_policy_with_api") def test_on_remove(self, delete_psp, delete_ns_role_binding, delete_ns_role): """Test remove hook.""" self.harness.charm.on.remove.emit() delete_psp.assert_called_once() delete_ns_role_binding.assert_called_once() delete_ns_role.assert_called_once() self.assertFalse(self.harness.charm._stored.configured) self.assertFalse(self.harness.charm._stored.started)
def test_get_certificate_action_dns_route53_defaults(self): charm._host = Mock() harness = Harness(charm.CertbotCharm) self.addCleanup(harness.cleanup) harness.begin() config = { "agree-tos": True, "dns-route53-aws-access-key-id": "test-key-id", "dns-route53-aws-secret-access-key": "test-secret-key", "domains": "charm.example.com", "email": "*****@*****.**", "plugin": "dns-route53", "propagation-seconds": 40 } harness.update_config(self._config(harness.charm, **config)) event = Mock(params={}) with tempfile.TemporaryDirectory() as dir: harness.charm._aws_config_file = pathlib.Path(dir).joinpath( ".aws", "config") harness.charm._on_get_certificate_action(event) awsconfig = configparser.ConfigParser() awsconfig.read(harness.charm._aws_config_file) self.assertEqual(awsconfig["default"]["aws_access_key_id"], "test-key-id") self.assertEqual(awsconfig["default"]["aws_secret_access_key"], "test-secret-key") self.assertEqual(len(charm._host.run.call_args_list), 2) self.assertEqual(len(charm._host.run.call_args_list), 2) expectCmd = [ "certbot", "certonly", "-n", "--no-eff-email", "--dns-route53", "--agree-tos", "[email protected]", "--domains=charm.example.com", "--dns-route53-propagation-seconds=40" ] self.assertEqual(charm._host.run.call_args_list[0], call(expectCmd)) self.assertEqual( charm._host.run.call_args_list[1][0], (['/etc/letsencrypt/renewal-hooks/deploy/certbot-charm'], )) self.assertEqual( charm._host.run.call_args_list[1][1]["env"]["RENEWED_LINEAGE"], "/etc/letsencrypt/live/charm.example.com")
class TestCharm(unittest.TestCase): def setUp(self): """Setup the test harness.""" self.harness = Harness(PostgreSQLCharm) self.harness.begin() self.harness.disable_hooks() self.maxDiff = None def test_check_for_empty_config_no_image(self): """Check for correctly reported empty required image.""" self.harness.update_config(CONFIG_NO_IMAGE) expected = "required setting(s) empty: image" self.assertEqual(self.harness.charm._check_for_config_problems(), expected) def test_check_for_missing_config_no_image_password(self): """Check for correctly reported empty required image_password.""" self.harness.update_config(CONFIG_NO_IMAGE_PASSWORD) expected = "required setting(s) empty: image_password" self.assertEqual(self.harness.charm._check_for_config_problems(), expected)
def test_update_config(self, run, wt, rm): rm.return_value = mock_rm = MagicMock() harness = Harness(GithubRunnerOperator) harness.update_config({"path": "mockorg/repo", "token": "mocktoken"}) harness.begin() # update to 10 containers harness.update_config({"containers": 10, "virtual-machines": 0}) harness.charm.on.reconcile_runners.emit() rm.assert_called_with("mockorg/repo", "mocktoken", "github-runner", 5) mock_rm.reconcile.assert_has_calls([ call("container", 10), call("virtual-machine", 0, VMResources(2, "7GiB", "10GiB")), ]) mock_rm.reset_mock() # update to 10 VMs with 4 cpu and 7GiB memory harness.update_config({ "containers": 0, "virtual-machines": 10, "vm-cpu": 4 }) harness.charm.on.reconcile_runners.emit() rm.assert_called_with("mockorg/repo", "mocktoken", "github-runner", 5) mock_rm.reconcile.assert_has_calls([ # 3 containers from quantity call("container", 3), call("virtual-machine", 10, VMResources(4, "7GiB", "10GiB")), ]) mock_rm.reset_mock()