def test_add_peer_relation_with_initial_data_leader(self): class InitialDataTester(CharmBase): """Record the relation-changed events.""" def __init__(self, framework): super().__init__(framework) self.observed_events = [] self.framework.observe(self.on.cluster_relation_changed, self._on_cluster_relation_changed) def _on_cluster_relation_changed(self, event): self.observed_events.append(event) # language=YAML harness = Harness(InitialDataTester, meta=''' name: test-app peers: cluster: interface: cluster ''') self.addCleanup(harness.cleanup) # TODO: dmitriis 2020-04-07 test a minion unit and initial peer relation app data # events when the harness begins to emit events for initial data. harness.set_leader(is_leader=True) rel_id = harness.add_relation('cluster', 'test-app') harness.update_relation_data(rel_id, 'test-app', {'k': 'v'}) harness.update_relation_data(rel_id, 'test-app/0', {'ingress-address': '192.0.2.1'}) backend = harness._backend self.assertEqual({'k': 'v'}, backend.relation_get(rel_id, 'test-app', is_app=True)) self.assertEqual({'ingress-address': '192.0.2.1'}, backend.relation_get(rel_id, 'test-app/0', is_app=False)) harness.begin() self.assertEqual({'k': 'v'}, backend.relation_get(rel_id, 'test-app', is_app=True)) self.assertEqual({'ingress-address': '192.0.2.1'}, backend.relation_get(rel_id, 'test-app/0', is_app=False)) # Make sure no relation-changed events are emitted for our own data bags. self.assertEqual([], harness.charm.observed_events) # Updating our app relation data bag and our unit data bag does not trigger events harness.update_relation_data(rel_id, 'test-app', {'k': 'v2'}) harness.update_relation_data(rel_id, 'test-app/0', {'ingress-address': '192.0.2.2'}) self.assertEqual([], harness.charm.observed_events) # If our unit becomes a minion, updating app relation data indirectly becomes possible # and our charm gets notifications. harness.set_leader(False) harness.update_relation_data(rel_id, 'test-app', {'k': 'v3'}) self.assertEqual({'k': 'v3'}, backend.relation_get(rel_id, 'test-app', is_app=True)) self.assertTrue(len(harness.charm.observed_events), 1) self.assertIsInstance(harness.charm.observed_events[0], RelationEvent)
def test_update_peer_relation_no_local_unit_change_event(self): # language=YAML harness = Harness(CharmBase, meta=''' name: postgresql peers: db: interface: pgsql ''') harness.begin() helper = DBRelationChangedHelper(harness.charm, "helper") rel_id = harness.add_relation('db', 'postgresql') rel = harness.charm.model.get_relation('db') rel.data[harness.charm.model.unit]['key'] = 'value' rel = harness.charm.model.get_relation('db') harness.update_relation_data(rel_id, 'postgresql/0', {'key': 'v1'}) self.assertEqual({'key': 'v1'}, rel.data[harness.charm.model.unit]) # Make sure there was no event self.assertEqual([], helper.changes) rel.data[harness.charm.model.unit]['key'] = 'v2' # Our unit data bag got updated. self.assertEqual({'key': 'v2'}, dict(rel.data[harness.charm.model.unit])) # But there were no changed events registered by our unit. self.assertEqual([], helper.changes) # Same for when our unit is a leader. harness.set_leader(is_leader=True) harness.update_relation_data(rel_id, 'postgresql/0', {'key': 'v3'}) self.assertEqual({'key': 'v3'}, dict(rel.data[harness.charm.model.unit])) self.assertEqual([], helper.changes) rel.data[harness.charm.model.unit]['key'] = 'v4' self.assertEqual(rel.data[harness.charm.model.unit]['key'], 'v4') self.assertEqual([], helper.changes)
class TestMySQLProvider(unittest.TestCase): def setup_harness(self, config: dict, meta: dict) -> None: config_yaml = CONFIG_YAML.format(**config) meta_yaml = PROVIDER_META.format(**meta) self.harness = Harness(MySQLCharm, meta=meta_yaml, config=config_yaml) self.addCleanup(self.harness.cleanup) self.harness.set_leader(True) self.harness.begin() def test_databases_are_created_when_requested(self): config = CONFIG.copy() meta = METADATA.copy() self.setup_harness(config, meta) requested_database = ["mysql_database"] json_request = json.dumps(requested_database) consumer_data = {"databases": json_request} rel_id = self.harness.add_relation("database", "consumer") data = self.harness.get_relation_data(rel_id, self.harness.model.app.name) self.assertDictEqual(data, {}) self.harness.add_relation_unit(rel_id, "consumer/0") self.harness.update_relation_data(rel_id, "consumer", consumer_data) data = self.harness.get_relation_data(rel_id, self.harness.model.app.name) databases = json.loads(data["databases"]) self.assertListEqual(databases, requested_database)
def test_update_peer_relation_app_data(self): # language=YAML harness = Harness(CharmBase, meta=''' name: postgresql peers: db: interface: pgsql ''') harness.begin() harness.set_leader(is_leader=True) helper = DBRelationChangedHelper(harness.charm, "helper") rel_id = harness.add_relation('db', 'postgresql') rel = harness.charm.model.get_relation('db') rel.data[harness.charm.app]['key'] = 'value' harness.update_relation_data(rel_id, 'postgresql', {'key': 'v1'}) self.assertEqual({'key': 'v1'}, rel.data[harness.charm.app]) self.assertEqual([], helper.changes) rel.data[harness.charm.app]['key'] = 'v2' # Our unit data bag got updated. self.assertEqual(rel.data[harness.charm.model.app]['key'], 'v2') # But there were no changed events registered by our unit. self.assertEqual([], helper.changes) # If our unit is not a leader unit we get an update about peer app relation data changes. harness.set_leader(is_leader=False) harness.update_relation_data(rel_id, 'postgresql', {'k2': 'v2'}) self.assertEqual(rel.data[harness.charm.model.app]['k2'], 'v2') self.assertEqual(helper.changes, [(0, 'postgresql')])
def test_get_backend_calls_with_kwargs(self): harness = Harness(CharmBase, meta=''' name: test-charm requires: db: interface: pgsql ''') self.addCleanup(harness.cleanup) harness.begin() unit = harness.charm.model.unit # Reset the list, because we don't care what it took to get here harness._get_backend_calls(reset=True) unit.status = ActiveStatus() self.assertEqual([('status_set', 'active', '', { 'is_app': False })], harness._get_backend_calls()) harness.set_leader(True) app = harness.charm.model.app harness._get_backend_calls(reset=True) app.status = ActiveStatus('message') self.assertEqual([('is_leader', ), ('status_set', 'active', 'message', { 'is_app': True })], harness._get_backend_calls())
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(MetalLBSpeakerCharm) self.harness.set_leader(is_leader=True) self.harness.begin() @patch.dict('charm.os.environ', {'JUJU_MODEL_NAME': 'unit-test-metallb'}) @patch("utils.create_namespaced_role_binding_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() self.assertEqual(create_ns_role.call_count, 2) self.assertEqual(create_ns_role_binding.call_count, 2) self.assertTrue(self.harness.charm._stored.started) @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() self.assertEqual(delete_ns_role.call_count, 2) self.assertEqual(delete_ns_role_binding.call_count, 2) self.assertFalse(self.harness.charm._stored.started)
class TestConsumer(unittest.TestCase): def setUp(self): self.harness = Harness(DummyCharmForTestingConsumer) self.addCleanup(self.harness.cleanup) self.harness.set_leader(True) self.harness.begin() def test_relation_changed(self): # container name has to be `alertmanager` because that's what the harness expects based on # metadata.yaml container = self.harness.model.unit.get_container("alertmanager") # Emit the PebbleReadyEvent carrying the alertmanager container self.harness.charm.on.alertmanager_pebble_ready.emit(container) rel_id = self.harness.add_relation(relation_name="alerting", remote_app="alertmanager-k8s") # self.harness.add_relation_unit(rel_id, "alertmanager-k8s/0") self.harness.add_relation_unit(rel_id, "prometheus-k8s/0") rel = self.harness.charm.framework.model.get_relation( "alerting", rel_id) self.assertEqual(0, self.harness.charm._stored.on_available_emitted) self.harness.update_relation_data(rel_id, "prometheus-k8s/0", {"public_address": "1.1.1.1"}) self.harness.charm.on["alerting"].relation_changed.emit(rel) self.assertEqual(1, self.harness.charm._stored.on_available_emitted)
class TestCharm(unittest.TestCase): """Prometheus Charm unit tests.""" def setUp(self) -> NoReturn: """Test setup""" self.image_info = sys.modules["oci_image"].OCIImageResource().fetch() self.harness = Harness(CharmedOsmBase) self.harness.set_leader(is_leader=True) self.harness.begin() def test_config_changed_non_leader(self, ) -> NoReturn: self.harness.set_leader(is_leader=False) self.harness.charm.on.config_changed.emit() self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus) @mock.patch("opslib.osm.charm.CharmedOsmBase.build_pod_spec") def test_config_changed_leader(self, mock_build_pod_spec) -> NoReturn: mock_build_pod_spec.return_value = { "version": 3, "containers": [{ "name": "c1" }, { "name": "c2" }], } self.harness.charm.on.config_changed.emit() self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
def test_provide_one_relation(): harness = Harness( ProvideCharm, meta=""" name: test-app requires: app-provides: interface: serialized-data """, ) harness.set_leader(True) rel_id = harness.add_relation("app-provides", "foo") harness.add_relation_unit(rel_id, "foo/0") harness.update_relation_data( rel_id, "foo", {"_supported_versions": yaml.dump(["v1"])}, ) harness.begin() assert harness.charm.interface.get_data() == {} data = { "service": "my-service", "port": 4242, "access-key": "my-access-key", "secret-key": "my-secret-key", } harness.charm.interface.send_data(data) rel_data = harness.charm.interface.get_data() assert rel_data == {(rel, app): data for rel in harness.model.relations["app-provides"] for app, bag in rel.data.items() if isinstance(app, Application) and "data" in bag}
def test_update_relation_no_local_app_change_event(self): # language=YAML harness = Harness(CharmBase, meta=''' name: my-charm requires: db: interface: pgsql ''') harness.begin() harness.set_leader(False) helper = DBRelationChangedHelper(harness.charm, "helper") rel_id = harness.add_relation('db', 'postgresql') # TODO: remove this as soon as https://github.com/canonical/operator/issues/175 is fixed. harness.add_relation_unit(rel_id, 'postgresql/0') self.assertEqual(helper.changes, []) harness.update_relation_data(rel_id, 'my-charm', {'new': 'value'}) rel = harness.charm.model.get_relation('db') self.assertEqual(rel.data[harness.charm.app]['new'], 'value') # Our app data bag got updated. self.assertEqual(rel.data[harness.charm.model.app]['new'], 'value') # But there were no changed events registered by our unit. self.assertEqual(helper.changes, [])
class TestNonStandardProviders(unittest.TestCase): def setup(self, **kwargs): bad_provider_charm = customize_endpoint_provider( alert_rules_path=kwargs["alert_rules_path"]) self.harness = Harness(bad_provider_charm, meta=PROVIDER_META) self.addCleanup(self.harness.cleanup) self.harness.set_leader(True) self.harness.begin() @patch("ops.testing._TestingModelBackend.network_get") def test_a_bad_alert_expression_logs_an_error(self, _): self.setup(alert_rules_path="./tests/unit/bad_alert_expressions") with self.assertLogs(level="ERROR") as logger: rel_id = self.harness.add_relation(RELATION_NAME, "provider") self.harness.add_relation_unit(rel_id, "provider/0") messages = sorted(logger.output) self.assertEqual(len(messages), 1) self.assertIn("Invalid rules file: missing_expr.rule", messages[0]) @patch("ops.testing._TestingModelBackend.network_get") def test_a_bad_alert_rules_logs_an_error(self, _): self.setup(alert_rules_path="./tests/unit/bad_alert_rules") with self.assertLogs(level="ERROR") as logger: rel_id = self.harness.add_relation(RELATION_NAME, "provider") self.harness.add_relation_unit(rel_id, "provider/0") messages = sorted(logger.output) self.assertEqual(len(messages), 1) self.assertIn("Failed to read alert rules from bad_yaml.rule", messages[0])
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("mongo.Mongo.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'}) self.assertEqual(self.harness.charm.num_peers, 2) peers = ['mongodb-0.mongodb-endpoints', 'mongodb-1.mongodb-endpoints'] mock_reconf.assert_called_once_with(peers)
def test_dual_interface_charm(): harness = Harness( RequiresCharm, meta=""" name: test-app requires: app-requires: interface: serialized-data """, ) harness.set_leader(True) rel_id = harness.add_relation("app-requires", "foo") harness.add_relation_unit(rel_id, "foo/0") harness.update_relation_data( rel_id, "foo", {"_supported_versions": yaml.dump(["v2"])}, ) harness.update_relation_data( rel_id, "foo", {"data": "foo: bar"}, ) harness.begin() harness.charm.interface.send_data({"bar": None}) rel_data = harness.charm.interface.get_data() assert rel_data == {(rel, app): { "bar": None } if app._is_our_app else { "foo": "bar" } for rel in harness.model.relations["app-requires"] for app, bag in rel.data.items() if isinstance(app, Application) and "data" in bag}
def test_touch_action_fail(self): harness = Harness(SshproxyCharm) harness.set_leader(is_leader=False) harness.begin() action_event = Mock(params={"filename": "/home/ubuntu/asd"}) harness.charm.on_touch_action(action_event) self.assertEqual(action_event.fail.call_args, [("Unit is not leader",)])
def test_add_relation_with_our_initial_data(self): class InitialDataTester(CharmBase): """Record the relation-changed events.""" def __init__(self, framework): super().__init__(framework) self.observed_events = [] self.framework.observe(self.on.db_relation_changed, self._on_db_relation_changed) def _on_db_relation_changed(self, event): self.observed_events.append(event) # language=YAML harness = Harness(InitialDataTester, meta=''' name: test-app requires: db: interface: pgsql ''') self.addCleanup(harness.cleanup) rel_id = harness.add_relation('db', 'postgresql') harness.update_relation_data(rel_id, 'test-app', {'k': 'v1'}) harness.update_relation_data(rel_id, 'test-app/0', {'ingress-address': '192.0.2.1'}) backend = harness._backend self.assertEqual({'k': 'v1'}, backend.relation_get(rel_id, 'test-app', is_app=True)) self.assertEqual({'ingress-address': '192.0.2.1'}, backend.relation_get(rel_id, 'test-app/0', is_app=False)) harness.begin() self.assertEqual({'k': 'v1'}, backend.relation_get(rel_id, 'test-app', is_app=True)) self.assertEqual({'ingress-address': '192.0.2.1'}, backend.relation_get(rel_id, 'test-app/0', is_app=False)) # Make sure no relation-changed events are emitted for our own data bags. self.assertEqual([], harness.charm.observed_events) # A remote unit can still update our app relation data bag since our unit is not a leader. harness.update_relation_data(rel_id, 'test-app', {'k': 'v2'}) # And we get an event self.assertEqual([], harness.charm.observed_events) # We can also update our own relation data, even if it is a bit 'cheaty' harness.update_relation_data(rel_id, 'test-app/0', {'ingress-address': '192.0.2.2'}) # But no event happens # Updating our data app relation data bag and our unit data bag does not generate events. harness.set_leader(True) harness.update_relation_data(rel_id, 'test-app', {'k': 'v3'}) harness.update_relation_data(rel_id, 'test-app/0', {'ingress-address': '192.0.2.2'}) self.assertEqual([], harness.charm.observed_events)
def test_app_status(self): harness = Harness(CharmBase, meta='name: test-app') harness.set_leader(True) harness.begin() # default status self.assertEqual(harness.model.app.status, UnknownStatus()) status = ActiveStatus('message') harness.model.app.status = status self.assertEqual(harness.model.app.status, status)
class TestCharm(unittest.TestCase): def setUp(self): self.harness = Harness(CassandraStressOperatorCharm) self.addCleanup(self.harness.cleanup) self.harness.set_leader(True) self.harness.begin_with_initial_hooks() def test_pass(self): pass
class TestCharm(unittest.TestCase): """Test script for checking relations""" def setUp(self) -> NoReturn: """Test setup.""" self.harness = Harness(MongodbCharm) self.harness.set_leader(is_leader=True) self.harness.begin() def test_on_configure_pod(self) -> NoReturn: """Test installation without any relation.""" self.harness.charm.on.config_changed.emit() expected_result = { "version": 3, "containers": [ { "name": "mongodb", "imageDetails": self.harness.charm.image.fetch(), "imagePullPolicy": "Always", "ports": [ { "name": "mongodb", "containerPort": 27017, "protocol": "TCP", } ], "command": [ "mongod", "--bind_ip", "mongodb-endpoints", "--port", "27017", ], } ], } # Verifying status self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus) # Verifying status message self.assertGreater(len(self.harness.charm.unit.status.message), 0) pod_spec, _ = self.harness.get_pod_spec() self.assertDictEqual(expected_result, pod_spec) def test_publish_mongodb_info(self) -> NoReturn: """Test to see if mongodb relation is updated.""" expected_result = { "hostname": "mongodb", "mongodb_uri": "mongodb://mongodb:27017", } relation_id = self.harness.add_relation("mongodb", "nrf") self.harness.add_relation_unit(relation_id, "nrf/0") relation_data = self.harness.get_relation_data(relation_id, "mongodb") print("relation_data", relation_data) self.assertDictEqual(expected_result, relation_data)
def test_unit_status(self): harness = Harness(CharmBase, meta='name: test-app') harness.set_leader(True) harness.begin() # default status self.assertEqual(harness.model.unit.status, MaintenanceStatus('')) status = ActiveStatus('message') harness.model.unit.status = status self.assertEqual(harness.model.unit.status, status)
def test_provide_no_relation(): harness = Harness( ProvideCharm, meta=""" name: test-app requires: app-provides: interface: serialized-data """, ) harness.set_leader(True) harness.begin()
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)
class TestBusyboxCharm(unittest.TestCase): """Charm test class.""" def setUp(self): """Setup tests.""" self.harness = Harness(BusyboxCharm) def test_harness(self): """Verify harness.""" self.harness.begin() self.assertFalse(self.harness.charm.state.installed) def test_install(self): """Test response to an install event.""" self.harness.begin() self.harness.charm.on.install.emit() self.assertTrue(self.harness.charm.state.installed) # This pattern can't work before juju 2.8 # def test_config_changed_not_installed(self): # """Test response to config changed event without install state.""" # self.harness.begin() # self.harness.charm.on.config_changed.emit() # self.assertFalse(self.harness.charm.state.configured) def test_config_changed(self): """Test response to config changed event.""" self.harness.set_leader(True) self.harness.begin() self.harness.charm.state.installed = True self.harness.charm.on.config_changed.emit() self.assertTrue(self.harness.charm.state.configured) def test_start_not_installed(self): """Test response to start event without install state.""" self.harness.begin() self.harness.charm.on.start.emit() self.assertFalse(self.harness.charm.state.started) def test_start_not_configured(self): """Test response to start event without configured state.""" self.harness.begin() self.harness.charm.state.installed = True self.harness.charm.on.start.emit() self.assertFalse(self.harness.charm.state.started) def test_start(self): """Test response to start event.""" self.harness.begin() self.harness.charm.state.installed = True self.harness.charm.state.configured = True self.harness.charm.on.start.emit() self.assertTrue(self.harness.charm.state.started)
def test_send_data_multiple_versions(): harness = Harness( ProvideCharm, meta=""" name: test-app provides: app-provides: interface: serialized-data """, ) harness.set_leader(True) rel_id1 = harness.add_relation("app-provides", "appv1") harness.add_relation_unit(rel_id1, "appv1/0") harness.update_relation_data( rel_id1, "appv1", {"_supported_versions": "- v1"}, ) rel_id2 = harness.add_relation("app-provides", "appv2") harness.add_relation_unit(rel_id2, "appv2/0") harness.update_relation_data( rel_id2, "appv2", {"_supported_versions": "- v2"}, ) harness.begin() data = { "service": "my-service", "port": 4242, "access-key": "my-access-key", "secret-key": "my-secret-key", } harness.update_relation_data(rel_id1, "appv1", {"data": yaml.dump(data)}) harness.update_relation_data(rel_id2, "appv2", {"data": yaml.dump({"bar": None})}) harness.charm.interface.send_data(data, "appv1") harness.charm.interface.send_data( {"foo": "sillema sillema nika su"}, app_name="appv2", ) # Can't send for an invalid app with pytest.raises(sdi.errors.InvalidAppNameError): harness.charm.interface.send_data({}, "invalid-app") # Can't send invalid data with pytest.raises(sdi.errors.RelationDataError): harness.charm.interface.send_data({"bad": "guy"}, "appv2")
def test_touch_action(self, mock_ssh_proxy): mock_ssh_proxy.return_value = ("stdout", None) harness = Harness(SshproxyCharm) harness.set_leader(is_leader=True) harness.begin() action_event = Mock(params={"filename": "/home/ubuntu/asd"}) harness.charm.on_touch_action(action_event) self.assertTrue(action_event.set_results.called) self.assertEqual( action_event.set_results.call_args, call({"output": "stdout"}), )
class TestProxyListenTcpInterfaceProvides(unittest.TestCase): def setUp(self): self.harness = Harness(CharmBase, meta=''' name: tcp-server requires: proxy-listen-tcp: interface: proxy-listen-tcp ''') self.harness.begin() self.tcp_load_balancer = ProxyListenTcpInterfaceProvides(self.harness.charm, 'proxy-listen-tcp') def test_expose_server(self): relation_id = self.harness.add_relation('proxy-listen-tcp', 'tcp-server') self.harness.update_relation_data( relation_id, 'tcp-server/0', {'ingress-address': '192.0.2.1'}) self.tcp_load_balancer.expose_server( 26257, ["bind :26257", "option httpchk GET /health?ready=1"], 'server tcp-server-0.example 192.0.2.1:26257 check port 8080' ) rel = self.harness.charm.model.get_relation('proxy-listen-tcp') self.assertEqual( rel.data[self.harness.charm.unit]['server_option'], 'server tcp-server-0.example 192.0.2.1:26257 check port 8080' ) with self.assertRaises(KeyError): rel.data[self.harness.charm.app]['frontend_port'] with self.assertRaises(KeyError): rel.data[self.harness.charm.app]['listen_options'], self.harness.set_leader() self.tcp_load_balancer.expose_server( 26258, ["bind :26258", "option httpchk GET /health?ready=1"], 'server tcp-server-0.example 192.0.2.1:26258 check port 8080' ) self.assertEqual( rel.data[self.harness.charm.unit]['server_option'], 'server tcp-server-0.example 192.0.2.1:26258 check port 8080' ) self.assertEqual(rel.data[self.harness.charm.app]['frontend_port'], '26258') self.assertEqual( rel.data[self.harness.charm.app]['listen_options'], '["bind :26258", "option httpchk GET /health?ready=1"]' )
def test_mrrm(role): if role == "provides": harness = Harness(ProviderCharm, meta=ProviderCharm.META) harness.begin_with_initial_hooks() provider = harness.charm.rel requirer = MockRequirer(harness) local, remote = provider, requirer elif role == "requires": harness = Harness(RequirerCharm, meta=RequirerCharm.META) harness.begin_with_initial_hooks() provider = MockProvider(harness) requirer = harness.charm.rel local, remote = requirer, provider assert not provider.is_available() assert not provider.is_ready() assert not requirer.is_available() assert not requirer.is_ready() relation = remote.relate() # mock remote is always leader, so their versions will be sent to the local charm assert local.is_available() assert not local.is_ready() # local charm under test is not leader yet, so its will not be sent to the remote assert not remote.is_available() assert not remote.is_ready() harness.set_leader(True) assert provider.is_available() assert not provider.is_ready() assert requirer.is_available() assert not requirer.is_ready() requirer.wrap(relation, {requirer.unit: {"request": "foo"}}) assert provider.is_available() assert provider.is_ready() assert requirer.is_available() assert not requirer.is_ready() data = provider.unwrap(relation) assert data[requirer.unit] == {"request": "foo"} provider.wrap(relation, {provider.app: {"response": "bar"}}) assert provider.is_available() assert provider.is_ready() assert requirer.is_available() assert requirer.is_ready() data = requirer.unwrap(relation) assert data[provider.app] == {"response": "bar"}
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_relation_set_deletes(self): harness = Harness(CharmBase, meta=''' name: test-charm requires: db: interface: pgsql ''') harness.begin() harness.set_leader(False) rel_id = harness.add_relation('db', 'postgresql') harness.update_relation_data(rel_id, 'test-charm/0', {'foo': 'bar'}) harness.add_relation_unit(rel_id, 'postgresql/0') rel = harness.charm.model.get_relation('db', rel_id) del rel.data[harness.charm.model.unit]['foo'] self.assertEqual({}, harness.get_relation_data(rel_id, 'test-charm/0'))
class TestRemoteWriteConsumer(unittest.TestCase): def setUp(self): self.harness = Harness(RemoteWriteConsumerCharm, meta=METADATA) self.harness.add_resource( "promql-transform-amd64", open("./promql-transform", "rb").read(), ) self.addCleanup(self.harness.cleanup) self.harness.set_leader(True) self.harness.begin_with_initial_hooks() def test_address_is_set(self): rel_id = self.harness.add_relation(RELATION_NAME, "provider") self.harness.add_relation_unit(rel_id, "provider/0") self.harness.update_relation_data( rel_id, "provider/0", {"remote_write": json.dumps({"url": "http://1.1.1.1:9090/api/v1/write"})}, ) assert list(self.harness.charm.remote_write_consumer.endpoints) == [ {"url": "http://1.1.1.1:9090/api/v1/write"} ] @patch.object(RemoteWriteConsumerCharm, "_handle_endpoints_changed") def test_config_is_set(self, mock_handle_endpoints_changed): rel_id = self.harness.add_relation(RELATION_NAME, "provider") self.harness.add_relation_unit(rel_id, "provider/0") self.harness.update_relation_data( rel_id, "provider/0", {"remote_write": json.dumps({"url": "http://1.1.1.1:9090/api/v1/write"})}, ) mock_handle_endpoints_changed.assert_called() event = mock_handle_endpoints_changed.call_args.args[0] self.assertEqual(rel_id, event.relation_id) assert list(self.harness.charm.remote_write_consumer.endpoints) == [ {"url": "http://1.1.1.1:9090/api/v1/write"} ] def test_no_remote_write_endpoint_provided(self): rel_id = self.harness.add_relation(RELATION_NAME, "provider") self.harness.add_relation_unit(rel_id, "provider/0") self.harness.update_relation_data(rel_id, "provider/0", {}) assert list(self.harness.charm.remote_write_consumer.endpoints) == []
class TestCharm(unittest.TestCase): def setUp(self): self.harness = Harness(CassandraOperatorCharm) self.addCleanup(self.harness.cleanup) self.harness.begin() self.harness.set_leader(True) def test_relation_is_set(self): rel_id = self.harness.add_relation("cql", "otherapp") self.assertIsInstance(rel_id, int) self.harness.add_relation_unit(rel_id, "otherapp/0") self.harness.update_relation_data(rel_id, "otherapp", {}) self.assertEqual( self.harness.get_relation_data( rel_id, self.harness.model.app.name)["port"], "9042", )