def test_status_code_exceptions(status_code, expected_exc, log_level, caplog): caplog.set_level(logging.INFO) HttpClientRecorder.STATUS_CODE = status_code settings = finalize_application_settings({ "license_key": "123LICENSEKEY", }) protocol = AgentProtocol(settings, client_cls=HttpClientRecorder) internal_metrics = CustomMetrics() with InternalTraceContext(internal_metrics): with pytest.raises(expected_exc): protocol.send("analytic_event_data") internal_metrics = dict(internal_metrics.metrics()) if status_code == 413: assert internal_metrics[ "Supportability/Python/Collector/MaxPayloadSizeLimit/analytic_event_data"] == [ 1, 0, 0, 0, 0, 0 ] else: assert ( "Supportability/Python/Collector/MaxPayloadSizeLimit/analytic_event_data" not in internal_metrics) assert len(HttpClientRecorder.SENT) == 1 request = HttpClientRecorder.SENT[0] assert request.params["method"] == "analytic_event_data" assert len(caplog.records) == 1 assert caplog.records[0].levelname == log_level message = caplog.records[0].getMessage() assert "123LICENSEKEY" not in message
def test_max_payload_size_limit(): settings = finalize_application_settings( {"max_payload_size_in_bytes": 0, "port": -1} ) protocol = AgentProtocol(settings, host="localhost") with pytest.raises(DiscardDataForRequest): protocol.send("metric_data")
def test_full_uri_connect(): # An exception will be raised here if there's a problem with the response AgentProtocol.connect( "Python Agent Test (test_full_uri_payloads)", [], [], global_settings(), client_cls=FullUriClient, )
def test_full_uri_payload(session, method, payload): redirect_host = session._protocol.client._host if method == "agent_command_results": payload[0] = session.configuration.agent_run_id protocol = AgentProtocol(session.configuration, redirect_host, client_cls=FullUriClient) # An exception will be raised here if there's a problem with the response protocol.send(method, payload)
def test_audit_logging(): with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b"*\n") settings = finalize_application_settings({"audit_log_file": f.name}) protocol = AgentProtocol(settings, client_cls=HttpClientRecorder) protocol.send("preconnect") with open(f.name) as f: audit_log_contents = f.read() assert audit_log_contents.startswith("*\n") assert len(audit_log_contents) > 2
def test_bad_value_in_env_var(): settings = global_settings() assert settings.utilization.logical_processors == 0 local_config, = AgentProtocol._connect_payload('', [], [], settings) util_conf = local_config['utilization'].get('config') assert util_conf == {'hostname': 'env-hostname', 'total_ram_mib': 98765}
def test_billing_hostname_from_env_vars(): settings = global_settings() assert settings.utilization.billing_hostname == 'env-hostname' local_config, = AgentProtocol._connect_payload('', [], [], settings) util_conf = local_config['utilization'].get('config') assert util_conf == {'hostname': 'env-hostname'}
def test_billing_hostname_with_set_in_ini_not_in_env(): settings = global_settings() assert settings.utilization.billing_hostname == 'file-hostname' local_config, = AgentProtocol._connect_payload('', [], [], settings) util_conf = local_config['utilization'].get('config') assert util_conf == {'hostname': 'file-hostname'}
def test_protocol_context_manager(): protocol = AgentProtocol(finalize_application_settings(), client_cls=HttpClientRecorder) with protocol: assert HttpClientRecorder.STATE == 1 assert HttpClientRecorder.STATE == 0
def test_billing_hostname_precedence(): # ini-file takes precedence over env vars settings = global_settings() assert settings.utilization.billing_hostname == 'file-hostname' local_config, = AgentProtocol._connect_payload('', [], [], settings) util_conf = local_config['utilization'].get('config') assert util_conf == {'hostname': 'file-hostname'}
def test_billing_hostname_with_blank_ini_file_no_env(): settings = global_settings() assert settings.utilization.billing_hostname is None # if no utilization config settings are set, the 'config' section is not in # the payload at all local_config, = AgentProtocol._connect_payload('', [], [], settings) util_conf = local_config['utilization'].get('config') assert util_conf is None
def test_connect_metadata(monkeypatch): monkeypatch.setenv("NEW_RELIC_METADATA_FOOBAR", "foobar") monkeypatch.setenv("_NEW_RELIC_METADATA_WRONG", "wrong") protocol = AgentProtocol.connect( APP_NAME, LINKED_APPS, ENVIRONMENT, finalize_application_settings(), client_cls=HttpClientRecorder, ) connect = HttpClientRecorder.SENT[1] assert connect.params["method"] == "connect" connect_payload = json_decode(connect.payload.decode("utf-8"))[0] assert connect_payload["metadata"] == {"NEW_RELIC_METADATA_FOOBAR": "foobar"}
def test_ca_bundle_path(monkeypatch, ca_bundle_path): # Pretend CA certificates are not available class DefaultVerifyPaths(object): cafile = None def __init__(self, *args, **kwargs): pass monkeypatch.setattr(ssl, "DefaultVerifyPaths", DefaultVerifyPaths) settings = finalize_application_settings({"ca_bundle_path": ca_bundle_path}) protocol = AgentProtocol(settings) expected = ca_bundle_path or certs.where() assert protocol.client._connection_kwargs["ca_certs"] == expected
def test_send(status_code): HttpClientRecorder.STATUS_CODE = status_code settings = finalize_application_settings({ "request_headers_map": { "custom-header": u"value" }, "agent_run_id": "RUN_TOKEN", }) protocol = AgentProtocol(settings, client_cls=HttpClientRecorder) response = protocol.send("metric_data", (1, 2, 3)) assert response is None assert len(HttpClientRecorder.SENT) == 1 request = HttpClientRecorder.SENT[0] assert request.method == "POST" assert request.path == "/agent_listener/invoke_raw_method" # Verify license key was there, but no way to validate the value request.params.pop("license_key") assert request.params == { "method": "metric_data", "marshal_format": "json", "protocol_version": AgentProtocol.VERSION, "run_id": "RUN_TOKEN", } assert request.headers == { "Content-Type": "application/json", "custom-header": u"value", } assert request.payload == b"[1,2,3]" # Verify call to finalize is None assert protocol.finalize() is None
def test_span_event_harvest_config(connect_response_fields): client_cls = functools.partial( CustomTestClient, connect_response_fields=connect_response_fields) protocol = AgentProtocol.connect('app_name', LINKED_APPLICATIONS, ENVIRONMENT, global_settings(), client_cls=client_cls) if connect_response_fields and connect_response_fields[ "span_event_harvest_config"]: expected = 123 else: from newrelic.core.config import SPAN_EVENT_RESERVOIR_SIZE expected = SPAN_EVENT_RESERVOIR_SIZE assert protocol.configuration.event_harvest_config.harvest_limits.span_event_data == expected
def test_server_side_config_precedence(): connect_response_fields = { u'agent_config': { u'span_events.enabled': True }, u'span_events.enabled': False, } client_cls = functools.partial( CustomTestClient, connect_response_fields=connect_response_fields) protocol = AgentProtocol.connect('app_name', LINKED_APPLICATIONS, ENVIRONMENT, global_settings(), client_cls=client_cls) assert protocol.configuration.span_events.enabled is False
def test_blob(): request_headers_map = {u'X-Foo': u'Bar'} connect_response_fields = {u"request_headers_map": request_headers_map} client_cls = functools.partial( CustomTestClient, connect_response_fields=connect_response_fields) protocol = AgentProtocol.connect('app_name', LINKED_APPLICATIONS, ENVIRONMENT, global_settings(), client_cls=client_cls) protocol.send("shutdown") headers = protocol.client.headers[-1] assert headers == { "Content-Type": "application/json", "X-Foo": "Bar", }
def _test_utilization_data(): data = _get_response_body_for_test(test) client_cls = create_client_cls(200, data) monkeypatch.setattr(CommonUtilization, "CLIENT_CLS", client_cls) with UpdatedSettings() as settings: # Ignoring docker will ensure that there is nothing extra in the # gathered utilization data monkeypatch.setattr(settings.utilization, "detect_docker", False) local_config, = AgentProtocol._connect_payload( '', [], [], settings) util_output = local_config['utilization'] expected_output = test['expected_output_json'] # The agent does not record full_hostname and it's not required expected_output.pop("full_hostname") assert expected_output == util_output
def test_no_blob_behavior(headers_map_present): if headers_map_present: connect_response_fields = {u"request_headers_map": None} client_cls = functools.partial( CustomTestClient, connect_response_fields=connect_response_fields) else: client_cls = functools.partial(CustomTestClient, connect_response_fields=DEFAULT) protocol = AgentProtocol.connect('app_name', LINKED_APPLICATIONS, ENVIRONMENT, global_settings(), client_cls=client_cls) protocol.send("shutdown") headers = protocol.client.headers[-1] assert headers == { "Content-Type": "application/json", }
def test_connect(with_aws, with_pcf, with_gcp, with_azure, with_docker, with_kubernetes, with_ip): global AWS, AZURE, GCP, PCF, BOOT_ID, DOCKER, KUBERNETES, IP_ADDRESS if not with_aws: AWS = Exception if not with_pcf: PCF = Exception if not with_gcp: GCP = Exception if not with_azure: AZURE = Exception if not with_docker: DOCKER = Exception if not with_kubernetes: KUBERNETES = Exception if not with_ip: IP_ADDRESS = None settings = finalize_application_settings({ "browser_monitoring.loader": BROWSER_MONITORING_LOADER, "browser_monitoring.debug": BROWSER_MONITORING_DEBUG, "capture_params": CAPTURE_PARAMS, "process_host.display_name": DISPLAY_NAME, "transaction_tracer.record_sql": RECORD_SQL, "high_security": HIGH_SECURITY, "labels": LABELS, "utilization.detect_aws": with_aws, "utilization.detect_pcf": with_pcf, "utilization.detect_gcp": with_gcp, "utilization.detect_azure": with_azure, "utilization.detect_docker": with_docker, "utilization.detect_kubernetes": with_kubernetes, "event_harvest_config": { "harvest_limits": { "analytic_event_data": ANALYTIC_EVENT_DATA, "span_event_data": SPAN_EVENT_DATA, "custom_event_data": CUSTOM_EVENT_DATA, "error_event_data": ERROR_EVENT_DATA, } }, }) protocol = AgentProtocol.connect( APP_NAME, LINKED_APPS, ENVIRONMENT, settings, client_cls=HttpClientRecorder, ) # verify there are exactly 3 calls to HttpClientRecorder assert len(HttpClientRecorder.SENT) == 3 # Verify preconnect call preconnect = HttpClientRecorder.SENT[0] assert preconnect.params["method"] == "preconnect" assert preconnect.payload == b"[]" # Verify connect call connect = HttpClientRecorder.SENT[1] assert connect.params["method"] == "connect" connect_payload = json_decode(connect.payload.decode("utf-8")) connect_payload_asserts( connect_payload, with_aws=with_aws, with_pcf=with_pcf, with_gcp=with_gcp, with_azure=with_azure, with_docker=with_docker, with_kubernetes=with_kubernetes, ) # Verify agent_settings call is done with the finalized settings agent_settings = HttpClientRecorder.SENT[2] assert agent_settings.params["method"] == "agent_settings" agent_settings_payload = json_decode( agent_settings.payload.decode("utf-8")) assert len(agent_settings_payload) == 1 agent_settings_payload = agent_settings_payload[0] # Finalized settings will have a non-None agent_run_id assert agent_settings_payload["agent_run_id"] is not None assert protocol.configuration.agent_run_id is not None # Verify that agent settings sent have converted null, containers, and # unserializable types to string assert agent_settings_payload["proxy_host"] == "None" assert agent_settings_payload["attributes.include"] == "[]" assert agent_settings_payload["feature_flag"] == str(set()) assert isinstance(agent_settings_payload["attribute_filter"], six.string_types) # Verify that the connection is closed assert HttpClientRecorder.STATE == 0
def test_close_connection(): protocol = AgentProtocol(finalize_application_settings(), client_cls=HttpClientRecorder) protocol.close_connection() assert HttpClientRecorder.STATE == -1
def test_protocol_http_error_causes_retry(): protocol = AgentProtocol(finalize_application_settings(), client_cls=HttpClientException) with pytest.raises(RetryDataForRequest): protocol.send("analytic_event_data")