def test_handle_message_unicode_not_damaged(mocker, flask_app, subtests): mocker.patch("app.queue.queue.build_event") add_host = mocker.patch("app.queue.queue.add_host", return_value=(mocker.MagicMock(), None, None, None)) operation_raw = "🧜🏿♂️" operation_escaped = json.dumps(operation_raw)[1:-1] messages = ( f'{{"operation": "", "data": {{"display_name": "{operation_raw}{operation_raw}", "account": "test"}}}}', f'{{"operation": "", "data": {{"display_name": "{operation_escaped}{operation_escaped}","account": "test"}}}}', f'{{"operation": "", "data": {{"display_name": "{operation_raw}{operation_escaped}", "account": "test"}}}}', ) for message in messages: with subtests.test(message=message): host_id = generate_uuid() add_host.reset_mock() add_host.return_value = ({ "id": host_id }, host_id, None, AddHostResult.updated) handle_message(message, mocker.Mock()) add_host.assert_called_once_with( { "display_name": f"{operation_raw}{operation_raw}", "account": "test" }, Identity(USER_IDENTITY))
def test_update_host_with_tags_doesnt_change_tags(self): create_host_data = HostWrapper( test_data(tags=[{"namespace": "ns", "key": "some_key", "value": "val"}], fqdn="fqdn") ) message = {"operation": "add_host", "data": create_host_data.data()} mock_event_producer = MockEventProducer() with self.app.app_context(): handle_message(json.dumps(message), mock_event_producer) event = json.loads(mock_event_producer.event) host_id = event["host"]["id"] # attempt to update update_host_data = HostWrapper( test_data(tags=[{"namespace": "other_ns", "key": "other_key", "value": "other_val"}], fqdn="fqdn") ) update_response = self.post(HOST_URL, [update_host_data.data()], 207) self._verify_host_status(update_response, 0, 200) tags_response = self.get(f"{HOST_URL}/{host_id}/tags") # check the tags haven't updated self.assertEqual(create_host_data.tags, tags_response["results"][host_id])
def test_handle_message_with_different_account(mocker, flask_app, subtests): mocker.patch("app.queue.queue.build_event") add_host = mocker.patch("app.queue.queue.add_host", return_value=(mocker.MagicMock(), None, None, None)) operation_raw = "🧜🏿♂️" messages = ( f'{{"operation": "", "data": {{"display_name": "{operation_raw}{operation_raw}", "account": "dummy"}}}}', ) identity = Identity(SYSTEM_IDENTITY) identity.account_number = "dummy" for message in messages: with subtests.test(message=message): host_id = generate_uuid() add_host.reset_mock() add_host.return_value = ({ "id": host_id }, host_id, None, AddHostResult.updated) handle_message(message, mocker.Mock()) add_host.assert_called_once_with( { "display_name": f"{operation_raw}{operation_raw}", "account": "dummy" }, identity)
def test_handle_message_happy_path(mocker, event_datetime_mock, flask_app): expected_insights_id = generate_uuid() host_id = generate_uuid() timestamp_iso = event_datetime_mock.isoformat() mocker.patch( "app.queue.queue.add_host", return_value=( {"id": host_id, "insights_id": expected_insights_id}, host_id, expected_insights_id, AddHostResult.created, ), ) mock_event_producer = mocker.Mock() host = minimal_host(insights_id=expected_insights_id) message = wrap_message(host.data()) handle_message(json.dumps(message), mock_event_producer) mock_event_producer.write_event.assert_called_once() assert json.loads(mock_event_producer.write_event.call_args[0][0]) == { "timestamp": timestamp_iso, "type": "created", "host": {"id": host_id, "insights_id": expected_insights_id}, "platform_metadata": {}, "metadata": {"request_id": "-1"}, }
def test_events_sent_to_correct_topic(mocker, flask_app, secondary_topic_enabled): host_id = generate_uuid() insights_id = generate_uuid() host = minimal_host(id=host_id, insights_id=insights_id) add_host = mocker.patch( "app.queue.queue.add_host", return_value=({"id": host_id}, host_id, insights_id, AddHostResult.created) ) mock_event_producer = mocker.Mock() message = wrap_message(host.data()) handle_message(json.dumps(message), mock_event_producer) # checking events sent to both egress and events topic assert mock_event_producer.write_event.call_count == 2 assert mock_event_producer.write_event.call_args_list[0][0][3] == Topic.egress assert mock_event_producer.write_event.call_args_list[1][0][3] == Topic.events mock_event_producer.reset_mock() # for host update events add_host.return_value = ({"id": host_id}, host_id, insights_id, AddHostResult.updated) message["data"].update(stale_timestamp=(now() + timedelta(hours=26)).isoformat()) handle_message(json.dumps(message), mock_event_producer) # checking events sent to both egress and events topic assert mock_event_producer.write_event.call_count == 2 assert mock_event_producer.write_event.call_args_list[0][0][3] == Topic.egress assert mock_event_producer.write_event.call_args_list[1][0][3] == Topic.events
def test_handle_message_failure_invalid_json_message(mocker): invalid_message = "failure {} " mock_event_producer = mocker.Mock() with pytest.raises(json.decoder.JSONDecodeError): handle_message(invalid_message, mock_event_producer) mock_event_producer.assert_not_called()
def test_handle_message_failure_invalid_message_format(mocker): invalid_message = json.dumps({"operation": "add_host", "NOTdata": {}}) # Missing data field mock_event_producer = mocker.Mock() with pytest.raises(marshmallow.exceptions.ValidationError): handle_message(invalid_message, mock_event_producer) mock_event_producer.assert_not_called()
def test_handle_message_failure_invalid_surrogates(mocker, display_name): mocker.patch("app.queue.queue.build_event") add_host = mocker.patch("app.queue.queue.add_host", return_value=(mocker.MagicMock(), None)) invalid_message = f'{{"operation": "", "data": {{"display_name": "hello{display_name}"}}}}' with pytest.raises(UnicodeError): handle_message(invalid_message, mocker.Mock()) add_host.assert_not_called()
def _mq_create_or_update_host( host_data, platform_metadata=None, return_all_data=False, event_producer=event_producer_mock ): message = wrap_message(host_data.data(), platform_metadata=platform_metadata) handle_message(json.dumps(message), event_producer) event = json.loads(event_producer.event) if return_all_data: return event_producer_mock.key, event, event_producer.headers # add facts object since it's not returned by event message return HostWrapper({**event["host"], **{"facts": host_data.facts}})
def test_handle_message_side_effect(mocker, flask_app): fake_add_host = mocker.patch("lib.host_repository.add_host", side_effect=OperationalError( "DB Problem", "fake_param", "fake_orig")) expected_insights_id = generate_uuid() host = minimal_host(insights_id=expected_insights_id) fake_add_host.reset_mock() message = json.dumps(wrap_message(host.data())) with pytest.raises(expected_exception=OperationalError): handle_message(message, mocker.MagicMock())
def test_get_host_with_escaped_special_characters(self): host_wrapper = HostWrapper({ "account": ACCOUNT, "insights_id": generate_uuid(), "stale_timestamp": now().isoformat(), "reporter": "test", "tags": [ { "namespace": ";,/?:@&=+$", "key": "-_.!~*'()", "value": "#" }, { "namespace": " \t\n\r\f\v", "key": " \t\n\r\f\v", "value": " \t\n\r\f\v" }, ], }) message = {"operation": "add_host", "data": host_wrapper.data()} with self.app.app_context(): mock_event_producer = MockEventProducer() handle_message(json.dumps(message), mock_event_producer) response_data = json.loads(mock_event_producer.event) created_host = response_data["host"] for namespace, key, value in ((";,/?:@&=+$", "-_.!~*'()", "#"), (" \t\n\r\f\v", " \t\n\r\f\v", " \t\n\r\f\v")): with self.subTest(namespace=namespace, key=key, value=value): tags_query = url_quote( f"{quote_everything(namespace)}/{quote_everything(key)}={quote_everything(value)}" ) get_response = self.get(f"{HOST_URL}?tags={tags_query}", 200) self.assertEqual(get_response["count"], 1) self.assertEqual(get_response["results"][0]["id"], created_host["id"])
def _mq_create_or_update_host( host_data, platform_metadata=None, return_all_data=False, event_producer=event_producer_mock, message_operation=add_host, ): if not platform_metadata: platform_metadata = get_platform_metadata() host_data.data()["account"] = SYSTEM_IDENTITY.get("account_number") message = wrap_message(host_data.data(), platform_metadata=platform_metadata) handle_message(json.dumps(message), event_producer, message_operation) event = json.loads(event_producer.event) if return_all_data: return event_producer_mock.key, event, event_producer.headers # add facts object since it's not returned by event message return HostWrapper({**event["host"], **{"facts": host_data.facts}})
def create_hosts(self): hosts_to_create = [ ( "host1", generate_uuid(), "host1.domain.test", [ { "namespace": "NS1", "key": "key1", "value": "val1" }, { "namespace": "NS1", "key": "key2", "value": "val1" }, { "namespace": "SPECIAL", "key": "tag", "value": "ToFind" }, { "namespace": "no", "key": "key", "value": None }, ], ), ( "host2", generate_uuid(), "host1.domain.test", [ { "namespace": "NS1", "key": "key1", "value": "val1" }, { "namespace": "NS2", "key": "key2", "value": "val2" }, { "namespace": "NS3", "key": "key3", "value": "val3" }, ], ), # the same fqdn is intentional ( "host3", generate_uuid(), "host2.domain.test", [ { "namespace": "NS2", "key": "key2", "value": "val2" }, { "namespace": "NS3", "key": "key3", "value": "val3" }, { "namespace": "NS1", "key": "key3", "value": "val3" }, { "namespace": None, "key": "key4", "value": "val4" }, { "namespace": None, "key": "key5", "value": None }, ], ), ] if hasattr(self, "hosts_to_create"): self.hosts_to_create = hosts_to_create + self.hosts_to_create else: self.hosts_to_create = hosts_to_create host_list = [] mock_event_producer = MockEventProducer() for host in self.hosts_to_create: host_wrapper = HostWrapper() host_wrapper.account = ACCOUNT host_wrapper.display_name = host[0] host_wrapper.insights_id = generate_uuid() host_wrapper.rhel_machine_id = generate_uuid() host_wrapper.subscription_manager_id = generate_uuid() host_wrapper.satellite_id = generate_uuid() host_wrapper.bios_uuid = generate_uuid() host_wrapper.ip_addresses = ["10.0.0.2"] host_wrapper.fqdn = host[2] host_wrapper.mac_addresses = ["aa:bb:cc:dd:ee:ff"] host_wrapper.external_id = generate_uuid() host_wrapper.facts = [{ "namespace": "ns1", "facts": { "key1": "value1" } }] host_wrapper.tags = host[3] host_wrapper.stale_timestamp = now().isoformat() host_wrapper.reporter = "test" message = {"operation": "add_host", "data": host_wrapper.data()} with self.app.app_context(): handle_message(json.dumps(message), mock_event_producer) response_data = json.loads(mock_event_producer.event) # add facts object since it's not returned by message host_data = { **response_data["host"], "facts": message["data"]["facts"] } host_list.append(HostWrapper(host_data)) return host_list