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")