def test_full_topology(dynatrace_check, requests_mock, topology): """ Test e2e to collect full topology for all component types from Dynatrace """ set_http_responses(requests_mock, hosts=read_file("host_response.json", "samples"), applications=read_file("application_response.json", "samples"), services=read_file("service_response.json", "samples"), processes=read_file("process_response.json", "samples"), process_groups=read_file("process-group_response.json", "samples")) dynatrace_check.run() expected_topology = load_json_from_file( "expected_smartscape_full_topology.json", "samples") actual_topology = topology.get_snapshot(dynatrace_check.check_id) components, relations = sort_topology_data(actual_topology) expected_components, expected_relations = sort_topology_data( expected_topology) assert len(components) == len(expected_components) for component in components: assert component in expected_components assert len(relations) == len(expected_relations) for relation in relations: assert relation in expected_relations
def test_events_process_limit_with_batches(dynatrace_check, test_instance, requests_mock, aggregator, health): """ Respecting `events_process_limit` config setting should happen with batch event retrieval too """ url = test_instance['url'] timestamp = dynatrace_check.generate_bootstrap_timestamp( test_instance['events_boostrap_days']) # there are 3 batch calls with total 12 events, open events are 3rd and 12th in collection url1 = '{}/api/v1/events?from={}'.format(url, timestamp) url2 = '{}/api/v1/events?cursor={}'.format(url, '123') url3 = '{}/api/v1/events?cursor={}'.format(url, '345') requests_mock.get(url1, status_code=200, text=read_file('events_set1_response.json', 'samples')) requests_mock.get(url2, status_code=200, text=read_file('events_set2_response.json', 'samples')) requests_mock.get(url3, status_code=200, text=read_file('events_set3_response.json', 'samples')) dynatrace_check.run() aggregator.assert_service_check( dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.WARNING, message= 'Maximum event limit to process is 10 but received total 11 events') # 1 open event were in first 10 events gathered -> 1 health states health.assert_snapshot(dynatrace_check.check_id, dynatrace_check.health.stream, check_states=[{ 'checkStateId': 'SERVICE-FAA29C9BB1C02F9B', 'health': 'DEVIATING', 'message': 'Event: FAILURE_RATE_INCREASED Severity: ERROR ' 'Impact: SERVICE Open Since: 1600874700000 ' 'Source: builtin', 'name': 'Dynatrace event', 'topologyElementIdentifier': 'urn:dynatrace:/SERVICE-FAA29C9BB1C02F9B' }], start_snapshot={ 'expiry_interval_s': 0, 'repeat_interval_s': 15 }, stop_snapshot={})
def test_custom_cmdb_ci_field(servicenow_check, requests_mock, test_cr_instance): response = [{ 'status_code': 200, 'text': read_file('CHG0000003.json', 'samples') }, { 'status_code': 200, 'text': EMPTY_RESULT }] test_cr_instance['custom_cmdb_ci_field'] = 'u_configuration_item' request_mock_cmdb_ci_tables_setup(requests_mock, test_cr_instance.get('url'), response) servicenow_check.run() aggregator.assert_service_check(SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) topology_events = telemetry._topology_events assert len(topology_events) == 1 assert topology_events[0]['msg_title'] == to_string( 'CHG0000003: Rollback Oracle ® Version') assert to_string('urn:host:/Sales © Force Automation' ) in topology_events[0]['context']['element_identifiers'] assert to_string('urn:host:/sales © force automation' ) in topology_events[0]['context']['element_identifiers'] assert 'a9c0c8d2c6112276018f7705562f9cb0' in topology_events[0]['context'][ 'element_identifiers']
def test_cr_custom_fields(servicenow_check, requests_mock, test_cr_instance): test_cr_instance['custom_planned_start_date_field'] = 'u_custom_start_date' test_cr_instance['custom_planned_end_date_field'] = 'u_custom_end_date' response = [{ 'status_code': 200, 'text': EMPTY_RESULT }, { 'status_code': 200, 'text': read_file('CHG0040007_custom_cr_fields.json', 'samples') }] request_mock_cmdb_ci_tables_setup(requests_mock, test_cr_instance.get('url'), response) servicenow_check.run() aggregator.assert_service_check(SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) topology_events = telemetry._topology_events assert len(topology_events) == 1 assert topology_events[0][ 'msg_title'] == 'CHG0040007: Please reboot ApplicationServerPeopleSoft' assert topology_events[0]['context']['data'][ 'start_date'] == '2021-09-01 11:30:00' assert topology_events[0]['context']['data'][ 'end_date'] == '2021-09-01 12:00:00'
def test_no_events_means_empty_health_snapshot(dynatrace_check, test_instance, requests_mock, health, aggregator): """ Dynatrace health check should not produce any health states when there are no events """ timestamp = dynatrace_check.generate_bootstrap_timestamp( test_instance['events_boostrap_days']) requests_mock.get('{}/api/v1/events?from={}'.format( test_instance['url'], timestamp), status_code=200, text=read_file('no_events_response.json', 'samples')) dynatrace_check.run() aggregator.assert_service_check(dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) health.assert_snapshot(dynatrace_check.check_id, dynatrace_check.health.stream, check_states=[], start_snapshot={ 'expiry_interval_s': 0, 'repeat_interval_s': 15 }, stop_snapshot={}) assert len(aggregator.events) == 0
def test_check_udt_active(requests_mock, test_instance, solarwinds_check): orion_server = test_instance.get("url") QUERY_URL = "https://{orion_server}:17778/SolarWinds/InformationService/v3/Json/Query".format( orion_server=orion_server) requests_mock.post(QUERY_URL, text=read_file("udt_active.json", "samples")) solarwinds_check.run() udt_active = solarwinds_check.check_udt_active() assert udt_active is True
def test_get_request_headers(self): http = HTTPHelper() mock_text = read_file('data_sample.json', 'samples') response = http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 200, "mock_text": mock_text, }) self.assertEqual(response.get_request_headers(), {})
def test_add_udt_topology(solarwinds_check): global npm_topology global udt_topology_data solarwinds_check.add_udt_topology(udt_topology_data, npm_topology) # Compare serialized npm + udt topology with saved version serialized_npm_topology = json.loads( json.dumps(npm_topology, indent=4, default=lambda o: o.__dict__)) expected_npm_and_udt_topology = json.loads( read_file("npm_and_udt_topology_dumps.json", "samples")) assert serialized_npm_topology == expected_npm_and_udt_topology
def test_get_npm_topology_data(requests_mock, test_instance, solarwinds_check): orion_server = test_instance.get("url") QUERY_URL = "https://{orion_server}:17778/SolarWinds/InformationService/v3/Json/Query".format( orion_server=orion_server) requests_mock.post(QUERY_URL, text=read_file("npm_topology_data.json", "samples")) solarwinds_check.run() npm_topology_data = solarwinds_check.get_npm_topology_data("", "") assert npm_topology_data == load_json_from_file("npm_topology_data.json", "samples")["results"]
def test_collect_hosts(requests_mock, dynatrace_check, topology): """ Testing Dynatrace check should collect hosts """ set_http_responses(requests_mock, hosts=read_file("host_response.json", "samples")) dynatrace_check.run() test_topology = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file("expected_host_topology.json", "samples") assert_topology(expected_topology, test_topology)
def test_collect_services(requests_mock, dynatrace_check, topology): """ Testing Dynatrace check should collect services and tags coming from Kubernetes """ set_http_responses(requests_mock, services=read_file("service_response.json", "samples")) dynatrace_check.run() test_topology = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file("expected_service_topology.json", "samples") assert_topology(expected_topology, test_topology)
def test_events_process_limit(dynatrace_check, test_instance, aggregator, requests_mock, health): """ Check should respect `events_process_limit` config setting and just produce those number of events """ timestamp = dynatrace_check.generate_bootstrap_timestamp( test_instance['events_boostrap_days']) requests_mock.get('{}/api/v1/events?from={}'.format( test_instance['url'], timestamp), status_code=200, text=read_file('21_events_response.json', 'samples')) dynatrace_check.run() # service check returns warning about events_process_limit aggregator.assert_service_check( dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.WARNING, message= 'Maximum event limit to process is 10 but received total 11 events') # 2 open events were in first 10 events gathered -> 2 health states health.assert_snapshot(dynatrace_check.check_id, dynatrace_check.health.stream, check_states=[{ 'checkStateId': 'SERVICE-FAA29C9BB1C02F9B', 'health': 'DEVIATING', 'message': 'Event: FAILURE_RATE_INCREASED Severity: ERROR ' 'Impact: SERVICE Open Since: 1600874700000 ' 'Source: builtin', 'name': 'Dynatrace event', 'topologyElementIdentifier': 'urn:dynatrace:/SERVICE-FAA29C9BB1C02F9B' }, { 'checkStateId': 'SERVICE-9B16B9C5B03836C5', 'health': 'DEVIATING', 'message': 'Event: FAILURE_RATE_INCREASED Severity: ERROR ' 'Impact: SERVICE Open Since: 1600874820000 ' 'Source: builtin', 'name': 'Dynatrace event', 'topologyElementIdentifier': 'urn:dynatrace:/SERVICE-9B16B9C5B03836C5' }], start_snapshot={ 'expiry_interval_s': 0, 'repeat_interval_s': 15 }, stop_snapshot={})
def test_compact_unicode_response(self): http = HTTPHelper() mock_text = read_file('unicode_sample.json', 'samples') unicode_json_response = http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 200, "mock_text": mock_text }) expected_result = load_json_from_file('unicode_sample.json', 'samples') self.assertEqual(unicode_json_response.get_json(), expected_result)
def test_collect_process_groups(dynatrace_check, requests_mock, topology): """ Testing Dynatrace check should collect process-groups """ set_http_responses(requests_mock, process_groups=read_file("process-group_response.json", "samples")) dynatrace_check.run() topology_instances = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file( "expected_process-group_topology.json", "samples") assert_topology(expected_topology, topology_instances)
def test_collect_applications(dynatrace_check, requests_mock, topology): """ Testing Dynatrace check should collect applications and also the tags properly coming from dynatrace """ set_http_responses(requests_mock, applications=read_file("application_response.json", "samples")) dynatrace_check.run() topology_instances = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file( "expected_application_topology.json", "samples") assert_topology(expected_topology, topology_instances)
def test_collect_custom_devices(dynatrace_check, requests_mock, topology): """ Test Dynatrace check should produce custom devices """ set_http_responses(requests_mock, entities=read_file("custom_device_response.json", "samples")) dynatrace_check.run() topology_instances = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file( "expected_custom_device_topology.json", "samples") assert_topology(expected_topology, topology_instances)
def test_get_udt_topology_data(requests_mock, test_instance, solarwinds_check): orion_server = test_instance.get("url") QUERY_URL = "https://{orion_server}:17778/SolarWinds/InformationService/v3/Json/Query".format( orion_server=orion_server) requests_mock.post(QUERY_URL, text=read_file("udt_topology_data.json", "samples")) solarwinds_check.run() # Make sure we can re-use the topology data later global udt_topology_data udt_topology_data = solarwinds_check.get_udt_topology_data( where_clause='dummy where clause') assert udt_topology_data == load_json_from_file("udt_topology_data.json", "samples")["results"]
def test_get_json(self): http = HTTPHelper() mock_text = read_file('data_sample.json', 'samples') response = http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 200, "mock_text": mock_text, }) self.assertEqual(response.get_json(), { 'hello': 'world', 'pong': True, })
def test_collect_relations(dynatrace_check, requests_mock, topology): """ Test to check if relations are collected properly """ set_http_responses(requests_mock, hosts=read_file("host_response.json", "samples")) dynatrace_check.run() topology_instances = topology.get_snapshot(dynatrace_check.check_id) assert len(topology_instances['components']) == 2 assert len(topology_instances['relations']) == 5 # since all relations are to this host itself so target id is same relation = topology_instances['relations'][0] assert relation['target_id'] == 'HOST-6AAE0F78BCF2E0F4' assert relation['type'] in ['isProcessOf', 'runsOn']
def test_collect_custom_devices_with_pagination(dynatrace_check, requests_mock, test_instance, topology): """ Test Dynatrace check should produce custom devices with pagination """ set_http_responses(requests_mock) url = test_instance.get('url') first_url = url + "/api/v2/entities?entitySelector=type%28%22CUSTOM_DEVICE%22%29&from=now-1h&fields=%2B" \ "fromRelationships%2C%2BtoRelationships%2C%2Btags%2C%2BmanagementZones%2C%2B" \ "properties.dnsNames%2C%2Bproperties.ipAddress" second_url = url + "/api/v2/entities?nextPageKey=nextpageresultkey" requests_mock.get(first_url, status_code=200, text=read_file("custom_device_response_next_page.json", "samples")) requests_mock.get(second_url, status_code=200, text=read_file("custom_device_response.json", "samples")) dynatrace_check.run() snapshot = topology.get_snapshot(dynatrace_check.check_id) expected_topology = load_json_from_file( "expected_custom_device_pagination_full_topology.json", "samples") assert_topology(expected_topology, snapshot)
def test_creating_topology_event_from_change_request(servicenow_check, requests_mock, test_cr_instance): response = [{ 'status_code': 200, 'text': read_file('CHG0000001.json', 'samples') }, { 'status_code': 200, 'text': EMPTY_RESULT }] request_mock_cmdb_ci_tables_setup(requests_mock, test_cr_instance.get('url'), response) servicenow_check.run() aggregator.assert_service_check(SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) topology_events = telemetry._topology_events assert len(topology_events) == 1 topology_event = topology_events[0] assert topology_event['source_type_name'] == 'Change Request Normal' assert topology_event['timestamp'] == 1600951343 assert topology_event['event_type'] == 'Change Request Normal' assert topology_event['msg_title'] == to_string( 'CHG0000001: Rollback Oracle ® Version') context = topology_event['context'] assert context['source'] == 'servicenow' assert context['category'] == 'change_request' assert 'a9c0c8d2c6112276018f7705562f9cb0' in context['element_identifiers'] assert to_string( 'urn:host:/Sales © Force Automation') in context['element_identifiers'] assert to_string( 'urn:host:/sales © force automation') in context['element_identifiers'] assert context['source_links'] == [] assert context['data']['requested_by'] == 'David Loo' assert context['data']['assigned_to'] == 'ITIL User' assert context['data']['start_date'] == '2020-09-12 01:00:00' assert context['data']['end_date'] == '2020-09-12 03:00:00' assert 'number:CHG0000001' in topology_event['tags'] assert 'priority:3 - Moderate' in topology_event['tags'] assert 'impact:3 - Low' in topology_event['tags'] assert 'risk:High' in topology_event['tags'] assert 'state:New' in topology_event['tags'] assert 'category:Software' in topology_event['tags'] state = servicenow_check.state_manager.get_state( servicenow_check._get_state_descriptor()) assert 'CHG0000001' in state.get('change_requests').keys() assert 'New' == state.get('change_requests')['CHG0000001']
def test_create_npm_topology(solarwinds_check): solarwinds_domain = "StackState_Domain" npm_topology_data = load_json_from_file("npm_topology_data.json", "samples")["results"] # Make sure we can re-use the topology global npm_topology solarwinds_check.base_url = 'https://solarwinds.procyonnetworks.nl' npm_topology = solarwinds_check.create_npm_topology( npm_topology_data, solarwinds_domain) # Compare serialized npm topology with saved version serialized_npm_topology = json.loads( json.dumps(npm_topology, indent=4, default=lambda o: o.__dict__)) expected_npm_topology = json.loads( read_file("npm_topology_dumps.json", "samples")) assert serialized_npm_topology == expected_npm_topology
def test_unicode_in_response_text(dynatrace_check, test_instance, requests_mock, aggregator, telemetry): timestamp = dynatrace_check.generate_bootstrap_timestamp( test_instance['events_boostrap_days']) requests_mock.get('{}/api/v1/events?from={}'.format( test_instance['url'], timestamp), status_code=200, text=read_file('unicode_topology_event_response.json', 'samples')) dynatrace_check.run() aggregator.assert_service_check(dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) assert telemetry._topology_events[0][ 'msg_text'] == 'PROCESS_RESTART on aws-cni™'
def test_tags(dynatrace_check, requests_mock, aggregator, topology): """ Testing do dynatrace tags finish in right places """ set_http_responses(requests_mock, hosts=read_file('HOST-9106C06F228CEC6B.json', 'samples')) dynatrace_check.run() aggregator.assert_service_check(dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) components = topology.get_snapshot(dynatrace_check.check_id)['components'] assert components[0]['data']['environments'] == ['test-environment'] assert components[0]['data']['domain'] == 'test-domain' assert components[0]['data']['layer'] == 'test-layer' assert 'test-identifier' in components[0]['data']['identifiers']
def test_compact_get(self): http = HTTPHelper() mock_text = read_file('data_sample.json', 'samples') result = http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 201, "mock_text": mock_text, }) self.assertEqual(result.get_request_method(), "GET") self.assertEqual(result.get_status_code(), 201) self.assertEqual(result.get_json(), { 'hello': 'world', 'pong': True, }) self.assertEqual(result.get_request_url(), "mock://test.com")
def test_status_code_validation(self): http = HTTPHelper() mock_text = read_file('data_sample.json', 'samples') http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 200, "mock_text": mock_text, "response_status_code_validation": 200, }) self.assertRaises(ValueError, http.get, { "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 201, "mock_text": "test", "response_status_code_validation": 200, })
def test_full_get(self): http = HTTPHelper() mock_text = read_file('data_sample.json', 'samples') result = http.get({ "endpoint": "mock://test.com", "mock_enable": True, "mock_status": 200, "mock_text": mock_text, "auth_data": { 'username': '******', 'password': '******' }, "auth_type": "basic", "session_auth_data": { 'username': '******', 'password': '******' }, "session_auth_type": "basic", "body": {"hello": "world", "pong": True}, "proxy": {"hello": "world"}, "headers": {"a": "1"}, "session_headers": {"b": "1"}, "query": {"c": "1"}, "timeout": 30, "ssl_verify": True, "retry_policy": {}, "request_schematic_validation": BodyRequestSchematicTest, "request_type_validation": HTTPRequestType.JSON, "response_status_code_validation": 200, "response_type_validation": HTTPResponseType.JSON, "response_schematic_validation": BodyResponseSchematicTest, }) self.assertEqual(result.get_request_method(), "GET") self.assertEqual(result.get_status_code(), 200) self.assertEqual(result.get_json(), { 'hello': 'world', 'pong': True, }) self.assertEqual(result.get_request_url(), "mock://test.com") self.assertEqual(result.get_request_headers(), {'a': '1', 'Content-Length': '21', 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic d29ybGQ6aGVsbG8='})
def test_health(dynatrace_check, requests_mock, test_instance, aggregator, health): """ Test if we have Dynatrace monitored health state for each component. """ set_http_responses(requests_mock, hosts=read_file('host_response.json', 'samples')) dynatrace_check.run() aggregator.assert_service_check(dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) health.assert_snapshot(dynatrace_check.check_id, dynatrace_check.health.stream, check_states=[{'checkStateId': 'HOST-6AAE0F78BCF2E0F4', 'health': 'CLEAR', 'message': 'EX01.stackstate.lab is monitored by Dynatrace', 'name': 'Dynatrace monitored', 'topologyElementIdentifier': 'urn:dynatrace:/HOST-6AAE0F78BCF2E0F4'}, {'checkStateId': 'HOST-AA6A5D81A0006807', 'health': 'CLEAR', 'message': 'SQL01.stackstate.lab is monitored by Dynatrace', 'name': 'Dynatrace monitored', 'topologyElementIdentifier': 'urn:dynatrace:/HOST-AA6A5D81A0006807'}], start_snapshot={'expiry_interval_s': 0, 'repeat_interval_s': 15}, stop_snapshot={})
def test_creating_topo_event_from_cr_when_field_has_null_value( servicenow_check, requests_mock, test_cr_instance): """ SNOW CR Field can have null for display_value "category": { "display_value": null, "value": "" } """ response = [{ 'status_code': 200, 'text': read_file('CHG0000002.json', 'samples') }, { 'status_code': 200, 'text': EMPTY_RESULT }] request_mock_cmdb_ci_tables_setup(requests_mock, test_cr_instance.get('url'), response) servicenow_check.run() aggregator.assert_service_check(SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) topology_events = telemetry._topology_events assert len(topology_events) == 1 assert topology_events[0]['msg_title'] == to_string( 'CHG0000002: Rollback Oracle Version') assert 'category:None' in topology_events[0]['tags']
def test_state_data(state, dynatrace_check, test_instance, requests_mock, aggregator): """ Check is the right timestamp is writen to the state """ timestamp = dynatrace_check.generate_bootstrap_timestamp( test_instance['events_boostrap_days']) state_instance = StateDescriptor( "instance.dynatrace_health.https_instance.live.dynatrace.com", "dynatrace.d") state.assert_state(state_instance, None) events_file = 'no_events_response.json' requests_mock.get('{}/api/v1/events?from={}'.format( test_instance['url'], timestamp), status_code=200, text=read_file(events_file, 'samples')) dynatrace_check.run() aggregator.assert_service_check(dynatrace_check.SERVICE_CHECK_NAME, count=1, status=AgentCheck.OK) mocked_response_data = load_json_from_file(events_file, 'samples') new_state = State( {'last_processed_event_timestamp': mocked_response_data.get('to')}) state.assert_state(state_instance, new_state)