diff --git a/newrelic/api/cat_header_mixin.py b/newrelic/api/cat_header_mixin.py deleted file mode 100644 index f4a3e02bc9..0000000000 --- a/newrelic/api/cat_header_mixin.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from newrelic.common.encoding_utils import ( - base64_decode, - base64_encode, - deobfuscate, - json_decode, - json_encode, - obfuscate, -) - - -# CatHeaderMixin assumes the mixin class also inherits from TimeTrace -class CatHeaderMixin: - cat_id_key = "X-NewRelic-ID" - cat_transaction_key = "X-NewRelic-Transaction" - cat_appdata_key = "X-NewRelic-App-Data" - cat_synthetics_key = "X-NewRelic-Synthetics" - cat_synthetics_info_key = "X-NewRelic-Synthetics-Info" - cat_metadata_key = "x-newrelic-trace" - cat_distributed_trace_key = "newrelic" - settings = None - - def __enter__(self): - result = super().__enter__() - if result is self and self.transaction: - self.settings = self.transaction.settings or None - return result - - def process_response_headers(self, response_headers): - """ - Decode the response headers and create appropriate metrics based on the - header values. The response_headers are passed in as a list of tuples. - [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)] - - """ - - settings = self.settings - if not settings: - return - - if not settings.cross_application_tracer.enabled: - return - - appdata = None - try: - for k, v in response_headers: - if k.upper() == self.cat_appdata_key.upper(): - appdata = json_decode(deobfuscate(v, settings.encoding_key)) - break - - if appdata: - self.params["cross_process_id"] = appdata[0] - self.params["external_txn_name"] = appdata[1] - self.params["transaction_guid"] = appdata[5] - - except Exception: - pass - - def process_response_metadata(self, cat_linking_value): - payload = base64_decode(cat_linking_value) - nr_headers = json_decode(payload) - self.process_response_headers(nr_headers.items()) - - @classmethod - def generate_request_headers(cls, transaction): - """ - Return a list of NewRelic specific headers as tuples - [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)] - - """ - - if transaction is None or transaction.settings is None: - return [] - - settings = transaction.settings - - nr_headers = [] - - if settings.distributed_tracing.enabled: - transaction.insert_distributed_trace_headers(nr_headers) - - elif settings.cross_application_tracer.enabled: - transaction.is_part_of_cat = True - path_hash = transaction.path_hash - if path_hash is None: - # Disable cat if path_hash fails to generate. - transaction.is_part_of_cat = False - else: - encoded_cross_process_id = obfuscate(settings.cross_process_id, settings.encoding_key) - nr_headers.append((cls.cat_id_key, encoded_cross_process_id)) - - transaction_data = [transaction.guid, transaction.record_tt, transaction.trip_id, path_hash] - encoded_transaction = obfuscate(json_encode(transaction_data), settings.encoding_key) - nr_headers.append((cls.cat_transaction_key, encoded_transaction)) - - if transaction.synthetics_header: - nr_headers.append((cls.cat_synthetics_key, transaction.synthetics_header)) - if transaction.synthetics_info_header: - nr_headers.append((cls.cat_synthetics_info_key, transaction.synthetics_info_header)) - - return nr_headers - - @staticmethod - def _convert_to_cat_metadata_value(nr_headers): - payload = json_encode(nr_headers) - cat_linking_value = base64_encode(payload) - return cat_linking_value - - @classmethod - def get_request_metadata(cls, transaction): - nr_headers = dict(cls.generate_request_headers(transaction)) - - if not nr_headers: - return None - - return cls._convert_to_cat_metadata_value(nr_headers) diff --git a/newrelic/api/external_trace.py b/newrelic/api/external_trace.py index 372eb2ca09..f2fa11ccba 100644 --- a/newrelic/api/external_trace.py +++ b/newrelic/api/external_trace.py @@ -14,14 +14,14 @@ import functools -from newrelic.api.cat_header_mixin import CatHeaderMixin +from newrelic.api.header_mixin import HeaderMixin from newrelic.api.time_trace import TimeTrace, current_trace from newrelic.common.async_wrapper import async_wrapper as get_async_wrapper from newrelic.common.object_wrapper import FunctionWrapper, wrap_object from newrelic.core.external_node import ExternalNode -class ExternalTrace(CatHeaderMixin, TimeTrace): +class ExternalTrace(HeaderMixin, TimeTrace): def __init__(self, library, url, method=None, **kwargs): parent = kwargs.pop("parent", None) source = kwargs.pop("source", None) @@ -38,9 +38,8 @@ def __init__(self, library, url, method=None, **kwargs): def __repr__(self): return f"<{self.__class__.__name__} object at 0x{id(self):x} { {'library': self.library, 'url': self.url, 'method': self.method} }>" - def process_response(self, status_code, headers): + def process_response(self, status_code, headers=None): self._add_agent_attribute("http.statusCode", status_code) - self.process_response_headers(headers) def terminal_node(self): return True diff --git a/newrelic/api/header_mixin.py b/newrelic/api/header_mixin.py new file mode 100644 index 0000000000..0fdf777735 --- /dev/null +++ b/newrelic/api/header_mixin.py @@ -0,0 +1,51 @@ +# Copyright 2010 New Relic, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# HeaderMixin assumes the mixin class also inherits from TimeTrace +class HeaderMixin: + synthetics_key = "X-NewRelic-Synthetics" + synthetics_info_key = "X-NewRelic-Synthetics-Info" + settings = None + + def __enter__(self): + result = super().__enter__() + if result is self and self.transaction: + self.settings = self.transaction.settings or None + return result + + @classmethod + def generate_request_headers(cls, transaction): + """ + Return a list of NewRelic specific headers as tuples + [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)] + + """ + + if transaction is None or transaction.settings is None: + return [] + + settings = transaction.settings + + nr_headers = [] + + if settings.distributed_tracing.enabled: + transaction.insert_distributed_trace_headers(nr_headers) + + if transaction.synthetics_header: + nr_headers.append((cls.synthetics_key, transaction.synthetics_header)) + if transaction.synthetics_info_header: + nr_headers.append((cls.synthetics_info_key, transaction.synthetics_info_header)) + + return nr_headers diff --git a/newrelic/api/message_trace.py b/newrelic/api/message_trace.py index 5f6f9a76d0..560bdfa3b0 100644 --- a/newrelic/api/message_trace.py +++ b/newrelic/api/message_trace.py @@ -14,19 +14,16 @@ import functools -from newrelic.api.cat_header_mixin import CatHeaderMixin +from newrelic.api.header_mixin import HeaderMixin from newrelic.api.time_trace import TimeTrace, current_trace from newrelic.common.async_wrapper import async_wrapper as get_async_wrapper from newrelic.common.object_wrapper import FunctionWrapper, wrap_object from newrelic.core.message_node import MessageNode -class MessageTrace(CatHeaderMixin, TimeTrace): - cat_id_key = "NewRelicID" - cat_transaction_key = "NewRelicTransaction" - cat_appdata_key = "NewRelicAppData" - cat_synthetics_key = "NewRelicSynthetics" - cat_synthetics_info_key = "NewRelicSyntheticsInfo" +class MessageTrace(HeaderMixin, TimeTrace): + synthetics_key = "NewRelicSynthetics" + synthetics_info_key = "NewRelicSyntheticsInfo" def __init__(self, library, operation, destination_type, destination_name, params=None, terminal=True, **kwargs): parent = kwargs.pop("parent", None) diff --git a/newrelic/api/message_transaction.py b/newrelic/api/message_transaction.py index 0c94b83fbb..5383c72dca 100644 --- a/newrelic/api/message_transaction.py +++ b/newrelic/api/message_transaction.py @@ -16,7 +16,6 @@ from newrelic.api.application import Application, application_instance from newrelic.api.background_task import BackgroundTask -from newrelic.api.message_trace import MessageTrace from newrelic.api.transaction import current_transaction from newrelic.common.async_proxy import TransactionContext, async_proxy from newrelic.common.object_wrapper import FunctionWrapper, wrap_object @@ -47,10 +46,6 @@ def __init__( if headers is not None and self.settings is not None: if self.settings.distributed_tracing.enabled: self.accept_distributed_trace_headers(headers, transport_type=transport_type) - elif self.settings.cross_application_tracer.enabled: - self._process_incoming_cat_headers( - headers.pop(MessageTrace.cat_id_key, None), headers.pop(MessageTrace.cat_transaction_key, None) - ) self.routing_key = routing_key self.exchange_type = exchange_type diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index d856982a1b..aa456e4ab8 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -33,14 +33,7 @@ NrTraceState, W3CTraceParent, W3CTraceState, - base64_decode, - convert_to_cat_metadata_value, - deobfuscate, ensure_str, - generate_path_hash, - json_decode, - json_encode, - obfuscate, snake_case, ) from newrelic.core.attribute import ( @@ -289,15 +282,9 @@ def __init__(self, application, enabled=None, source=None): self._distributed_trace_state = 0 - self.client_cross_process_id = None self.client_account_id = None self.client_application_id = None - self.referring_transaction_guid = None self.record_tt = False - self._trip_id = None - self._referring_path_hash = None - self._alternate_path_hashes = {} - self.is_part_of_cat = False # Synthetics Header self.synthetics_resource_id = None @@ -534,13 +521,8 @@ def __exit__(self, exc, value, tb): ) # Add transaction exclusive time to total exclusive time - # self.total_time += exclusive - if self.client_cross_process_id is not None: - metric_name = f"ClientApplication/{self.client_cross_process_id}/all" - self.record_custom_metric(metric_name, duration) - # Record supportability metrics for api calls for key, value in self._transaction_metrics.items(): @@ -599,8 +581,6 @@ def __exit__(self, exc, value, tb): guid=self.guid, cpu_time=self._cpu_user_time_value, suppress_transaction_trace=self.suppress_transaction_trace, - client_cross_process_id=self.client_cross_process_id, - referring_transaction_guid=self.referring_transaction_guid, record_tt=self.record_tt, synthetics_resource_id=self.synthetics_resource_id, synthetics_job_id=self.synthetics_job_id, @@ -610,11 +590,6 @@ def __exit__(self, exc, value, tb): synthetics_initiator=self.synthetics_initiator, synthetics_attributes=self.synthetics_attributes, synthetics_info_header=self.synthetics_info_header, - is_part_of_cat=self.is_part_of_cat, - trip_id=self.trip_id, - path_hash=self.path_hash, - referring_path_hash=self._referring_path_hash, - alternate_path_hashes=self.alternate_path_hashes, trace_intrinsics=self.trace_intrinsics, distributed_trace_intrinsics=self.distributed_trace_intrinsics, agent_attributes=agent_attributes, @@ -732,70 +707,10 @@ def path(self): return f"{self.type}/{self.name_for_metric}" - @property - def trip_id(self): - return self._trip_id or self.guid - @property def trace_id(self): return self._trace_id - @property - def alternate_path_hashes(self): - """Return the alternate path hashes but not including the current path - hash. - - """ - return sorted(set(self._alternate_path_hashes.values()) - {self.path_hash}) - - @property - def path_hash(self): - """Path hash is a 32-bit digest of the string "appname;txn_name" - XORed with the referring_path_hash. Since the txn_name can change - during the course of a transaction, up to 10 path_hashes are stored - in _alternate_path_hashes. Before generating the path hash, check the - _alternate_path_hashes to determine if we've seen this identifier and - return the value. - - """ - - if not self.is_part_of_cat: - return None - - identifier = f"{self.application.name};{self.path}" - - # Check if identifier is already part of the _alternate_path_hashes and - # return the value if available. - - if self._alternate_path_hashes.get(identifier): - return self._alternate_path_hashes[identifier] - - # If the referring_path_hash is unavailable then we use '0' as the - # seed. - - try: - seed = int((self._referring_path_hash or "0"), base=16) - except Exception: - seed = 0 - - try: - path_hash = generate_path_hash(identifier, seed) - except ValueError: - _logger.warning( - "Unable to generate cross application tracer headers. " - "MD5 hashing may not be available. (Is this system FIPS compliant?) " - "We recommend enabling distributed tracing instead. For details and a transition guide see " - "https://docs.newrelic.com/docs/agents/python-agent/configuration/python-agent-configuration#distributed-tracing-settings" - ) - return None - - # Only store up to 10 alternate path hashes. - - if len(self._alternate_path_hashes) < 10: - self._alternate_path_hashes[identifier] = path_hash - - return path_hash - @property def attribute_filter(self): return self._settings.attribute_filter @@ -833,14 +748,6 @@ def trace_intrinsics(self): """Intrinsic attributes for transaction traces and error traces""" i_attrs = {} - if self.referring_transaction_guid: - i_attrs["referring_transaction_guid"] = self.referring_transaction_guid - if self.client_cross_process_id: - i_attrs["client_cross_process_id"] = self.client_cross_process_id - if self.trip_id: - i_attrs["trip_id"] = self.trip_id - if self.path_hash: - i_attrs["path_hash"] = self.path_hash if self.synthetics_resource_id: i_attrs["synthetics_resource_id"] = self.synthetics_resource_id if self.synthetics_job_id: @@ -1339,141 +1246,6 @@ def accept_distributed_trace_headers(self, headers, transport_type="HTTP"): # metric for the lack of payload/distributed_header self._accept_distributed_trace_payload(distributed_header, transport_type) - def _process_incoming_cat_headers(self, encoded_cross_process_id, encoded_txn_header): - settings = self._settings - - if not self.enabled: - return - - if not ( - settings.cross_application_tracer.enabled - and settings.cross_process_id - and settings.trusted_account_ids - and settings.encoding_key - ): - return - - if encoded_cross_process_id is None: - return - - try: - client_cross_process_id = deobfuscate(encoded_cross_process_id, settings.encoding_key) - - # The cross process ID consists of the client - # account ID and the ID of the specific application - # the client is recording requests against. We need - # to validate that the client account ID is in the - # list of trusted account IDs and ignore it if it - # isn't. The trusted account IDs list has the - # account IDs as integers, so save the client ones - # away as integers here so easier to compare later. - - client_account_id, client_application_id = map(int, client_cross_process_id.split("#")) - - if client_account_id not in settings.trusted_account_ids: - return - - self.client_cross_process_id = client_cross_process_id - self.client_account_id = client_account_id - self.client_application_id = client_application_id - - txn_header = json_decode(deobfuscate(encoded_txn_header, settings.encoding_key)) - - if txn_header: - self.is_part_of_cat = True - self.referring_transaction_guid = txn_header[0] - - # Incoming record_tt is OR'd with existing - # record_tt. In the scenario where we make multiple - # ext request, this will ensure we don't set the - # record_tt to False by a later request if it was - # set to True by an earlier request. - - self.record_tt = self.record_tt or txn_header[1] - - if isinstance(txn_header[2], str): - self._trip_id = txn_header[2] - if isinstance(txn_header[3], str): - self._referring_path_hash = txn_header[3] - except Exception: - pass - - def _generate_response_headers(self, read_length=None): - nr_headers = [] - - # Generate metrics and response headers for inbound cross - # process web external calls. - - if self.client_cross_process_id is not None: - # Need to work out queueing time and duration up to this - # point for inclusion in metrics and response header. If the - # recording of the transaction had been prematurely stopped - # via an API call, only return time up until that call was - # made so it will match what is reported as duration for the - # transaction. - - if self.queue_start: - queue_time = self.start_time - self.queue_start - else: - queue_time = 0 - - if self.end_time: - duration = self.end_time - self.start_time - else: - duration = time.time() - self.start_time - - # Generate the additional response headers which provide - # information back to the caller. We need to freeze the - # transaction name before adding to the header. - - self._freeze_path() - - if read_length is None: - read_length = self._read_length - - read_length = read_length if read_length is not None else -1 - - payload = ( - self._settings.cross_process_id, - self.path, - queue_time, - duration, - read_length, - self.guid, - self.record_tt, - ) - app_data = json_encode(payload) - - nr_headers.append(("X-NewRelic-App-Data", obfuscate(app_data, self._settings.encoding_key))) - - return nr_headers - - # This function is CAT related and has been deprecated. - # Eventually, this will be removed. Until then, coverage - # does not need to factor this function into its analysis. - def get_response_metadata(self): # pragma: no cover - nr_headers = dict(self._generate_response_headers()) - return convert_to_cat_metadata_value(nr_headers) - - # This function is CAT related and has been deprecated. - # Eventually, this will be removed. Until then, coverage - # does not need to factor this function into its analysis. - def process_request_metadata(self, cat_linking_value): # pragma: no cover - try: - payload = base64_decode(cat_linking_value) - except: - # `cat_linking_value` should always be able to be base64_decoded. - # If this is encountered, the data being sent is corrupt. No - # exception should be raised. - return - - nr_headers = json_decode(payload) - # TODO: All the external CAT APIs really need to - # be refactored into the transaction class. - encoded_cross_process_id = nr_headers.get("X-NewRelic-ID") - encoded_txn_header = nr_headers.get("X-NewRelic-Transaction") - return self._process_incoming_cat_headers(encoded_cross_process_id, encoded_txn_header) - def set_transaction_name(self, name, group=None, priority=None): # Always perform this operation even if the transaction # is not active at the time as will be called from diff --git a/newrelic/api/web_transaction.py b/newrelic/api/web_transaction.py index c305663273..4de3bf7c86 100644 --- a/newrelic/api/web_transaction.py +++ b/newrelic/api/web_transaction.py @@ -300,10 +300,6 @@ def _process_context_headers(self): # the relevant details. if self._settings.distributed_tracing.enabled: self.accept_distributed_trace_headers(self._request_headers) - else: - client_cross_process_id = self._request_headers.get("x-newrelic-id") - txn_header = self._request_headers.get("x-newrelic-transaction") - self._process_incoming_cat_headers(client_cross_process_id, txn_header) def process_response(self, status_code, response_headers): """Processes response status and headers, extracting any @@ -313,7 +309,7 @@ def process_response(self, status_code, response_headers): """ if not self.enabled: - return [] + return # Extract response headers if response_headers: @@ -333,20 +329,11 @@ def process_response(self, status_code, response_headers): # If response code is 304 do not insert CAT headers. See: # https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 if self._response_code == 304: - return [] + return None except Exception: pass - if self.client_cross_process_id is None: - return [] - - # Generate CAT response headers - try: - read_length = int(self._request_headers.get("content-length")) - except Exception: - read_length = -1 - - return self._generate_response_headers(read_length) + return None def _update_agent_attributes(self): if "accept" in self._request_headers: diff --git a/newrelic/api/wsgi_application.py b/newrelic/api/wsgi_application.py index 2749be9ab5..e0cefc0bef 100644 --- a/newrelic/api/wsgi_application.py +++ b/newrelic/api/wsgi_application.py @@ -634,9 +634,9 @@ def _args(environ, start_response, *args, **kwargs): transaction.set_transaction_name(name, group, priority=1) def _start_response(status, response_headers, *args): - additional_headers = transaction.process_response(status, response_headers, *args) + transaction.process_response(status, response_headers, *args) - _write = start_response(status, response_headers + additional_headers, *args) + _write = start_response(status, response_headers, *args) def write(data): if not transaction._sent_start: diff --git a/newrelic/common/agent_http.py b/newrelic/common/agent_http.py index 5534142547..c85f7d060a 100644 --- a/newrelic/common/agent_http.py +++ b/newrelic/common/agent_http.py @@ -521,7 +521,6 @@ class DeveloperModeClient(SupportabilityMixin, BaseClient): "url_rules": [], "collect_errors": True, "account_id": "12345", - "cross_process_id": "12345#67890", "messages": [{"message": "Reporting to fake collector", "level": "INFO"}], "sampling_rate": 0, "collect_traces": True, diff --git a/newrelic/common/encoding_utils.py b/newrelic/common/encoding_utils.py index 6f7e9d199f..ddd6a5ddad 100644 --- a/newrelic/common/encoding_utils.py +++ b/newrelic/common/encoding_utils.py @@ -19,7 +19,6 @@ import base64 import gzip -import hashlib import io import itertools import json @@ -232,23 +231,6 @@ def unpack_field(field): return data -def generate_path_hash(name, seed): - """Algorithm for generating the path hash: - * Rotate Left the seed value and truncate to 32-bits. - * Compute the md5 digest of the name, take the last 4 bytes (32-bits). - * XOR the 4 bytes of digest with the seed and return the result. - - """ - - rotated = ((seed << 1) | (seed >> 31)) & 0xFFFFFFFF - - if not isinstance(name, bytes): - name = name.encode("UTF-8") - - path_hash = rotated ^ int(hashlib.md5(name).hexdigest()[-8:], base=16) # noqa: S324 - return f"{path_hash:08x}" - - def base64_encode(text): """Base 64 encodes the UTF-8 encoded representation of the text. In Python 2 either a byte string or Unicode string can be provided for the text @@ -368,15 +350,6 @@ def decode_newrelic_header(encoded_header, encoding_key): return decoded_header -def convert_to_cat_metadata_value(nr_headers): - if not nr_headers: - return None - - payload = json_encode(nr_headers) - cat_linking_value = base64_encode(payload) - return cat_linking_value - - class DistributedTracePayload(dict): version = (0, 1) diff --git a/newrelic/config.py b/newrelic/config.py index 52b631a637..19e04b78d7 100644 --- a/newrelic/config.py +++ b/newrelic/config.py @@ -453,7 +453,6 @@ def _process_configuration(section): _process_setting(section, "debug.disable_harvest_until_shutdown", "getboolean", None) _process_setting(section, "debug.connect_span_stream_in_developer_mode", "getboolean", None) _process_setting(section, "debug.otlp_content_encoding", "get", None) - _process_setting(section, "cross_application_tracer.enabled", "getboolean", None) _process_setting(section, "message_tracer.segment_parameters_enabled", "getboolean", None) _process_setting(section, "process_host.display_name", "get", None) _process_setting(section, "utilization.detect_aws", "getboolean", None) @@ -711,15 +710,6 @@ def translate_deprecated_settings(settings, cached_settings): "attributes.exclude." ) - if "cross_application_tracer.enabled" in cached: - # CAT Deprecation Warning - _logger.info( - "Deprecated setting found: cross_application_tracer.enabled. Please replace Cross Application Tracing " - "(CAT) with the newer Distributed Tracing by setting 'distributed_tracing.enabled' to True in your agent " - "configuration. For further details on distributed tracing, please refer to our documentation: " - "https://docs.newrelic.com/docs/distributed-tracing/concepts/distributed-tracing-planning-guide/#changes." - ) - return settings @@ -3020,12 +3010,6 @@ def _process_module_builtin_defaults(): _process_module_definition("aiohttp.wsgi", "newrelic.hooks.framework_aiohttp", "instrument_aiohttp_wsgi") _process_module_definition("aiohttp.web", "newrelic.hooks.framework_aiohttp", "instrument_aiohttp_web") - _process_module_definition( - "aiohttp.web_reqrep", "newrelic.hooks.framework_aiohttp", "instrument_aiohttp_web_response" - ) - _process_module_definition( - "aiohttp.web_response", "newrelic.hooks.framework_aiohttp", "instrument_aiohttp_web_response" - ) _process_module_definition( "aiohttp.web_urldispatcher", "newrelic.hooks.framework_aiohttp", "instrument_aiohttp_web_urldispatcher" ) diff --git a/newrelic/core/agent_protocol.py b/newrelic/core/agent_protocol.py index de0cab678b..3544fd0032 100644 --- a/newrelic/core/agent_protocol.py +++ b/newrelic/core/agent_protocol.py @@ -522,7 +522,7 @@ def finalize(self): @classmethod def connect(cls, app_name, linked_applications, environment, settings, client_cls=ServerlessModeClient): aws_lambda_metadata = settings.aws_lambda_metadata - settings = finalize_application_settings({"cross_application_tracer.enabled": False}, settings) + settings = finalize_application_settings(settings=settings) # Metadata must come from the original settings object since it # can be modified later settings.aws_lambda_metadata = aws_lambda_metadata diff --git a/newrelic/core/config.py b/newrelic/core/config.py index eebc598877..ae7f855617 100644 --- a/newrelic/core/config.py +++ b/newrelic/core/config.py @@ -256,10 +256,6 @@ class DebugSettings(Settings): pass -class CrossApplicationTracerSettings(Settings): - pass - - class TransactionEventsSettings(Settings): pass @@ -497,7 +493,6 @@ class EventHarvestConfigHarvestLimitSettings(Settings): _settings.browser_monitoring.attributes = BrowserMonitorAttributesSettings() _settings.code_level_metrics = CodeLevelMetricsSettings() _settings.console = ConsoleSettings() -_settings.cross_application_tracer = CrossApplicationTracerSettings() _settings.custom_insights_events = CustomInsightsEventsSettings() _settings.ml_insights_events = MlInsightsEventsSettings() _settings.datastore_tracer = DatastoreTracerSettings() @@ -792,7 +787,6 @@ def default_otlp_host(host): _settings.transaction_segment_terms = [] _settings.account_id = os.environ.get("NEW_RELIC_ACCOUNT_ID") -_settings.cross_process_id = None _settings.primary_application_id = os.environ.get("NEW_RELIC_PRIMARY_APPLICATION_ID", "Unknown") _settings.trusted_account_ids = [] _settings.trusted_account_key = os.environ.get("NEW_RELIC_TRUSTED_ACCOUNT_KEY") @@ -808,7 +802,6 @@ def default_otlp_host(host): _settings.attributes.include = [] _settings.thread_profiler.enabled = True -_settings.cross_application_tracer.enabled = False _settings.gc_runtime_metrics.enabled = _environ_as_bool("NEW_RELIC_GC_RUNTIME_METRICS_ENABLED", default=False) _settings.gc_runtime_metrics.top_object_count_limit = 5 @@ -1347,24 +1340,6 @@ def apply_server_side_settings(server_side_config=None, settings=_settings): min(settings_snapshot.custom_insights_events.max_attribute_value, 4095), ) - # This will be removed at some future point - # Special case for account_id which will be sent instead of - # cross_process_id in the future - - if settings_snapshot.cross_process_id is not None: - vals = [settings_snapshot.account_id, settings_snapshot.application_id] - derived_vals = settings_snapshot.cross_process_id.split("#") - - if len(derived_vals) == 2: - for idx, _val in enumerate(derived_vals): - # only override the value if the server side does not provide - # the value specifically - if vals[idx] is None: - vals[idx] = derived_vals[idx] - - settings_snapshot.account_id = vals[0] - settings_snapshot.application_id = vals[1] - # Reapply on top any local setting overrides. for name in _settings.debug.local_settings_overrides: diff --git a/newrelic/core/external_node.py b/newrelic/core/external_node.py index 9165d2081f..5b80a2e7d7 100644 --- a/newrelic/core/external_node.py +++ b/newrelic/core/external_node.py @@ -40,9 +40,6 @@ class ExternalNode(_ExternalNode, GenericNodeMixin): - cross_process_id = None - external_txn_name = None - @property def details(self): if hasattr(self, "_details"): @@ -107,49 +104,24 @@ def time_metrics(self, stats, root, parent): netloc = self.netloc - try: - # Remove cross_process_id from the params dict otherwise it shows - # up in the UI. - - self.cross_process_id = self.params.pop("cross_process_id") - self.external_txn_name = self.params.pop("external_txn_name") - except KeyError: - self.cross_process_id = None - self.external_txn_name = None - name = f"External/{netloc}/all" yield TimeMetric(name=name, scope="", duration=self.duration, exclusive=self.exclusive) - if self.cross_process_id is None: - method = self.method or "" - - name = f"External/{netloc}/{self.library}/{method}" - - yield TimeMetric(name=name, scope="", duration=self.duration, exclusive=self.exclusive) - - yield TimeMetric(name=name, scope=root.path, duration=self.duration, exclusive=self.exclusive) - - else: - name = f"ExternalTransaction/{netloc}/{self.cross_process_id}/{self.external_txn_name}" - - yield TimeMetric(name=name, scope="", duration=self.duration, exclusive=self.exclusive) + method = self.method or "" - yield TimeMetric(name=name, scope=root.path, duration=self.duration, exclusive=self.exclusive) + name = f"External/{netloc}/{self.library}/{method}" - name = f"ExternalApp/{netloc}/{self.cross_process_id}/all" + yield TimeMetric(name=name, scope="", duration=self.duration, exclusive=self.exclusive) - yield TimeMetric(name=name, scope="", duration=self.duration, exclusive=self.exclusive) + yield TimeMetric(name=name, scope=root.path, duration=self.duration, exclusive=self.exclusive) def trace_node(self, stats, root, connections): netloc = self.netloc method = self.method or "" - if self.cross_process_id is None: - name = f"External/{netloc}/{self.library}/{method}" - else: - name = f"ExternalTransaction/{netloc}/{self.cross_process_id}/{self.external_txn_name}" + name = f"External/{netloc}/{self.library}/{method}" name = root.string_table.cache(name) diff --git a/newrelic/core/transaction_node.py b/newrelic/core/transaction_node.py index 34871d8b21..11740465e3 100644 --- a/newrelic/core/transaction_node.py +++ b/newrelic/core/transaction_node.py @@ -66,8 +66,6 @@ "guid", "cpu_time", "suppress_transaction_trace", - "client_cross_process_id", - "referring_transaction_guid", "record_tt", "synthetics_resource_id", "synthetics_job_id", @@ -77,11 +75,6 @@ "synthetics_initiator", "synthetics_attributes", "synthetics_info_header", - "is_part_of_cat", - "trip_id", - "path_hash", - "referring_path_hash", - "alternate_path_hashes", "trace_intrinsics", "agent_attributes", "distributed_trace_intrinsics", @@ -470,18 +463,8 @@ def _add_if_not_empty(key, value): if self.errors: intrinsics["error"] = True - if self.path_hash: - intrinsics["nr.guid"] = self.guid - intrinsics["nr.tripId"] = self.trip_id - intrinsics["nr.pathHash"] = self.path_hash - - _add_if_not_empty("nr.referringPathHash", self.referring_path_hash) - _add_if_not_empty("nr.alternatePathHashes", ",".join(self.alternate_path_hashes)) - _add_if_not_empty("nr.referringTransactionGuid", self.referring_transaction_guid) - if self.synthetics_resource_id: intrinsics["nr.guid"] = self.guid - if self.parent_tx: intrinsics["parentId"] = self.parent_tx @@ -542,9 +525,6 @@ def error_event_intrinsics(self, error, stats_table): intrinsics["spanId"] = error.span_id intrinsics["nr.transactionGuid"] = self.guid - if self.referring_transaction_guid: - guid = self.referring_transaction_guid - intrinsics["nr.referringTransactionGuid"] = guid return intrinsics diff --git a/newrelic/hooks/application_celery.py b/newrelic/hooks/application_celery.py index e5856141f0..71e51a66e2 100644 --- a/newrelic/hooks/application_celery.py +++ b/newrelic/hooks/application_celery.py @@ -127,11 +127,6 @@ def wrapper(wrapped, instance, args, kwargs): headers.update(dict(dt_headers)) except Exception: pass - elif transaction.settings.cross_application_tracer.enabled: - transaction._process_incoming_cat_headers( - headers.get(MessageTrace.cat_id_key, None), - headers.get(MessageTrace.cat_transaction_key, None), - ) except Exception: pass @@ -247,11 +242,6 @@ def wrap_task_call(wrapped, instance, args, kwargs): headers.update(dict(dt_headers)) except Exception: pass - elif transaction.settings.cross_application_tracer.enabled: - transaction._process_incoming_cat_headers( - headers.get(MessageTrace.cat_id_key, None), - headers.get(MessageTrace.cat_transaction_key, None), - ) except Exception: pass diff --git a/newrelic/hooks/external_httplib.py b/newrelic/hooks/external_httplib.py index f9f5621287..48b1d080e4 100644 --- a/newrelic/hooks/external_httplib.py +++ b/newrelic/hooks/external_httplib.py @@ -103,7 +103,7 @@ def httplib_putheader_wrapper(wrapped, instance, args, kwargs): # it if we see either, but they should always both be getting set. def nr_header(header, *args, **kwargs): - return header.upper() in ("NEWRELIC", "X-NEWRELIC-ID", "X-NEWRELIC-TRANSACTION") + return header.upper() == "NEWRELIC" connection = instance diff --git a/newrelic/hooks/framework_aiohttp.py b/newrelic/hooks/framework_aiohttp.py index e43ffaddef..05db1d9d76 100644 --- a/newrelic/hooks/framework_aiohttp.py +++ b/newrelic/hooks/framework_aiohttp.py @@ -19,7 +19,7 @@ from newrelic.api.function_trace import function_trace from newrelic.api.transaction import current_transaction, ignore_transaction from newrelic.api.web_transaction import web_transaction -from newrelic.common.async_wrapper import async_wrapper, is_coroutine_callable +from newrelic.common.async_wrapper import is_coroutine_callable from newrelic.common.object_names import callable_name from newrelic.common.object_wrapper import ObjectProxy, function_wrapper, wrap_function_wrapper from newrelic.core.config import is_expected_error, should_ignore_error @@ -33,17 +33,6 @@ def aiohttp_version_info(): return tuple(int(_) for _ in aiohttp.__version__.split(".")[:2]) -def headers_preserve_casing(): - try: - from multidict import CIMultiDict - except: - return True - - d = CIMultiDict() - d.update({"X-NewRelic-ID": "value"}) - return "X-NewRelic-ID" in dict(d.items()) - - def should_ignore(transaction): settings = transaction.settings @@ -70,16 +59,8 @@ def _is_expected(exc, value, tb): return _is_expected -def _nr_process_response_proxy(response, transaction): - nr_headers = transaction.process_response(response.status, response.headers) - - response._headers = HeaderProxy(response.headers, nr_headers) - - def _nr_process_response(response, transaction): - nr_headers = transaction.process_response(response.status, response.headers) - - response._headers.update(nr_headers) + transaction.process_response(response.status, response.headers) @function_wrapper @@ -156,20 +137,6 @@ def __getattr__(self, name): return result -def _nr_aiohttp_response_prepare_(wrapped, instance, args, kwargs): - def _bind_params(request): - return request - - request = _bind_params(*args, **kwargs) - - nr_headers = getattr(request, "_nr_headers", None) - if nr_headers: - nr_headers.update(instance.headers) - instance._headers = nr_headers - - return wrapped(*args, **kwargs) - - @function_wrapper def _nr_aiohttp_wrap_middleware_(wrapped, instance, args, kwargs): async def _inner(): @@ -214,18 +181,18 @@ def items(self): return itertools.chain(self.__wrapped__.items(), nr_headers.items()) -def _nr_aiohttp_add_cat_headers_(wrapped, instance, args, kwargs): +def _nr_aiohttp_add_dt_headers_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) try: - cat_headers = ExternalTrace.generate_request_headers(transaction) + dt_headers = ExternalTrace.generate_request_headers(transaction) except: return wrapped(*args, **kwargs) tmp = instance.headers - instance.headers = HeaderProxy(tmp, cat_headers) + instance.headers = HeaderProxy(tmp, dt_headers) if is_coroutine_callable(wrapped): @@ -244,21 +211,21 @@ async def new_coro(): instance.headers = tmp -def _nr_aiohttp_add_cat_headers_simple_(wrapped, instance, args, kwargs): +def _nr_aiohttp_add_dt_headers_simple_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) try: - cat_headers = ExternalTrace.generate_request_headers(transaction) + dt_headers = ExternalTrace.generate_request_headers(transaction) except: return wrapped(*args, **kwargs) - for k, _ in cat_headers: + for k, _ in dt_headers: if k in instance.headers: return wrapped(*args, **kwargs) - instance.headers.update(cat_headers) + instance.headers.update(dt_headers) return wrapped(*args, **kwargs) @@ -273,26 +240,8 @@ def _nr_aiohttp_request_wrapper_(wrapped, instance, args, kwargs): method, url = _bind_request(*args, **kwargs) trace = ExternalTrace("aiohttp", str(url), method) - - async def _coro(): - try: - response = await wrapped(*args, **kwargs) - - try: - trace.process_response_headers(response.headers.items()) - except: - pass - - return response - except Exception as e: - try: - trace.process_response_headers(e.headers.items()) - except: - pass - - raise - - return async_wrapper(wrapped)(_coro, trace)() + with trace: + return wrapped(*args, **kwargs) def instrument_aiohttp_client(module): @@ -303,16 +252,11 @@ def instrument_aiohttp_client_reqrep(module): version_info = aiohttp_version_info() if version_info >= (2, 0): - if headers_preserve_casing(): - cat_wrapper = _nr_aiohttp_add_cat_headers_simple_ - else: - cat_wrapper = _nr_aiohttp_add_cat_headers_ - - wrap_function_wrapper(module, "ClientRequest.send", cat_wrapper) + wrap_function_wrapper(module, "ClientRequest.send", _nr_aiohttp_add_dt_headers_simple_) def instrument_aiohttp_protocol(module): - wrap_function_wrapper(module, "Request.send_headers", _nr_aiohttp_add_cat_headers_) + wrap_function_wrapper(module, "Request.send_headers", _nr_aiohttp_add_dt_headers_) def instrument_aiohttp_web_urldispatcher(module): @@ -362,8 +306,7 @@ async def _coro(*_args, **_kwargs): _nr_process_response(e, transaction) raise except Exception: - nr_headers = transaction.process_response(500, ()) - request._nr_headers = dict(nr_headers) + transaction.process_response(500, ()) raise _nr_process_response(response, transaction) @@ -380,17 +323,9 @@ async def _coro(*_args, **_kwargs): def instrument_aiohttp_web(module): - global _nr_process_response - if not headers_preserve_casing(): - _nr_process_response = _nr_process_response_proxy - wrap_function_wrapper(module, "Application._handle", _nr_request_wrapper) wrap_function_wrapper(module, "Application.__init__", _nr_aiohttp_wrap_application_init_) def instrument_aiohttp_wsgi(module): wrap_function_wrapper(module, "WsgiResponse.__init__", _nr_aiohttp_wrap_wsgi_response_) - - -def instrument_aiohttp_web_response(module): - wrap_function_wrapper(module, "Response.prepare", _nr_aiohttp_response_prepare_) diff --git a/newrelic/hooks/framework_sanic.py b/newrelic/hooks/framework_sanic.py index 14077eb6d9..3738bd6180 100644 --- a/newrelic/hooks/framework_sanic.py +++ b/newrelic/hooks/framework_sanic.py @@ -170,12 +170,7 @@ def _nr_sanic_response_get_headers(wrapped, instance, args, kwargs): return result # instance is the response object - cat_headers = transaction.process_response(str(instance.status), instance.headers.items()) - - for header_name, header_value in cat_headers: - if header_name not in instance.headers: - instance.headers[header_name] = header_value - + transaction.process_response(str(instance.status), instance.headers.items()) return wrapped(*args, **kwargs) @@ -189,12 +184,7 @@ async def _nr_sanic_response_send(wrapped, instance, args, kwargs): return result # instance is the response object - cat_headers = transaction.process_response(str(instance.status), instance.headers.items()) - - for header_name, header_value in cat_headers: - if header_name not in instance.headers: - instance.headers[header_name] = header_value - + transaction.process_response(str(instance.status), instance.headers.items()) return result @@ -205,12 +195,7 @@ def _nr_sanic_response_parse_headers(wrapped, instance, args, kwargs): return wrapped(*args, **kwargs) # instance is the response object - cat_headers = transaction.process_response(str(instance.status), instance.headers.items()) - - for header_name, header_value in cat_headers: - if header_name not in instance.headers: - instance.headers[header_name] = header_value - + transaction.process_response(str(instance.status), instance.headers.items()) return wrapped(*args, **kwargs) diff --git a/newrelic/hooks/framework_tornado.py b/newrelic/hooks/framework_tornado.py index 636be31250..cd08c9af2e 100644 --- a/newrelic/hooks/framework_tornado.py +++ b/newrelic/hooks/framework_tornado.py @@ -132,10 +132,7 @@ def wrap_write_headers(wrapped, instance, args, kwargs): if transaction: http_status, headers = _bind_response_headers(*args, **kwargs) - cat_headers = transaction.process_response(http_status, headers) - - for name, value in cat_headers: - headers.add(name, value) + transaction.process_response(http_status, headers) return wrapped(*args, **kwargs) @@ -253,7 +250,7 @@ async def wrapper(req, raise_error): raise finally: if response: - trace.process_response_headers(response.headers.get_all()) + trace.process_response(response.code) return response return wrapper @@ -269,7 +266,7 @@ def wrap_httpclient_fetch(wrapped, instance, args, kwargs): outgoing_headers = trace.generate_request_headers(current_transaction()) for header_name, header_value in outgoing_headers: - # User headers should override our CAT headers + # User headers should override our headers if header_name in req.headers: continue req.headers[header_name] = header_value diff --git a/newrelic/hooks/messagebroker_pika.py b/newrelic/hooks/messagebroker_pika.py index 821d05a318..d246d2c46f 100644 --- a/newrelic/hooks/messagebroker_pika.py +++ b/newrelic/hooks/messagebroker_pika.py @@ -62,9 +62,7 @@ def _add_consume_rabbitmq_trace(transaction, method, properties, nr_start_time, # Do not record dt headers in the segment parameters if headers: - headers.pop(MessageTrace.cat_id_key, None) - headers.pop(MessageTrace.cat_transaction_key, None) - headers.pop(MessageTrace.cat_distributed_trace_key, None) + headers.pop("newrelic", None) headers.pop("traceparent", None) headers.pop("tracestate", None) @@ -124,9 +122,7 @@ def _nr_wrapper_basic_publish(wrapped, instance, args, kwargs): user_headers = properties.headers.copy() # Do not record dt headers in the segment parameters - user_headers.pop(MessageTrace.cat_id_key, None) - user_headers.pop(MessageTrace.cat_transaction_key, None) - user_headers.pop(MessageTrace.cat_distributed_trace_key, None) + user_headers.pop("newrelic", None) user_headers.pop("traceparent", None) user_headers.pop("tracestate", None) @@ -150,8 +146,8 @@ def _nr_wrapper_basic_publish(wrapped, instance, args, kwargs): params=params, source=wrapped, ) as trace: - cat_headers = MessageTrace.generate_request_headers(transaction) - properties.headers.update(cat_headers) + headers = MessageTrace.generate_request_headers(transaction) + properties.headers.update(headers) # Extract host from channel to add as an agent attribute host = instance_info(instance) diff --git a/tests/agent_features/test_asgi_distributed_tracing.py b/tests/agent_features/test_asgi_distributed_tracing.py index ae50d45cf3..01140279f6 100644 --- a/tests/agent_features/test_asgi_distributed_tracing.py +++ b/tests/agent_features/test_asgi_distributed_tracing.py @@ -104,7 +104,6 @@ async def target_asgi_application(scope, receive, send): def test_distributed_tracing_web_transaction(): headers = {"newrelic": json.dumps(payload)} response = test_application.make_request("GET", "/", headers=headers) - assert "X-NewRelic-App-Data" not in response.headers class TestAsgiRequest: diff --git a/tests/agent_features/test_attribute.py b/tests/agent_features/test_attribute.py index a8410eab6b..4e6c0998be 100644 --- a/tests/agent_features/test_attribute.py +++ b/tests/agent_features/test_attribute.py @@ -56,7 +56,7 @@ def target_wsgi_application(environ, start_response): return [output] -_required_intrinsics = ["trip_id", "totalTime"] +_required_intrinsics = ["totalTime"] _forgone_intrinsics = [] diff --git a/tests/agent_features/test_attributes_in_action.py b/tests/agent_features/test_attributes_in_action.py index 4d12e8b059..da3768aaaa 100644 --- a/tests/agent_features/test_attributes_in_action.py +++ b/tests/agent_features/test_attributes_in_action.py @@ -16,7 +16,6 @@ import webtest from testing_support.asgi_testing import AsgiTest from testing_support.fixtures import ( - cat_enabled, dt_enabled, override_application_settings, reset_core_stats_engine, @@ -165,7 +164,7 @@ def normal_application(request): # Tests for checking the presence and format of agent attributes. # Test default settings. -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = { "agent": TRACE_ERROR_AGENT_KEYS, @@ -173,22 +172,19 @@ def normal_application(request): "intrinsic": ERROR_EVENT_INTRINSICS, } -_expected_absent_attributes = {"agent": REQ_PARAMS, "user": [], "intrinsic": DISTRIBUTED_TRACE_ATTRS} +_expected_absent_attributes = {"agent": REQ_PARAMS, "user": [], "intrinsic": []} -@cat_enabled @validate_error_event_attributes(_expected_attributes_event, _expected_absent_attributes) @validate_transaction_error_trace_attributes(_expected_attributes, _expected_absent_attributes) def test_error_in_transaction_default_settings(normal_application): normal_application.get(REQUEST_URL, headers=REQUEST_HEADERS) -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} -@cat_enabled @validate_transaction_trace_attributes(_expected_attributes, _expected_absent_attributes) -@override_application_settings({}) def test_transaction_trace_default_attribute_settings(normal_application): normal_application.get(REQUEST_URL, headers=REQUEST_HEADERS) @@ -230,7 +226,7 @@ def test_browser_default_attribute_settings(normal_application): _override_settings = {"error_collector.attributes.exclude": ["request.parameters.*"]} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = { "agent": TRACE_ERROR_AGENT_KEYS, @@ -250,7 +246,7 @@ def test_error_in_transaction_exclude_request_params(normal_application): _override_settings = {"transaction_tracer.attributes.exclude": ["request.parameters.*"]} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes, _expected_absent_attributes) @@ -261,7 +257,7 @@ def test_transaction_trace_exclude_request_params(normal_application): _override_settings = {"capture_params": True, "error_collector.attributes.exclude": ["request.parameters.*"]} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} _expected_absent_attributes = {"agent": REQ_PARAMS, "user": [], "intrinsic": []} @@ -285,7 +281,7 @@ def test_transaction_trace_capture_params_exclude_request_params(normal_applicat _override_settings = {"error_collector.attributes.include": ["request.parameters.*"]} -_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": ERROR_EVENT_INTRINSICS} @@ -299,7 +295,7 @@ def test_error_in_transaction_include_request_params(normal_application): _override_settings = {"transaction_tracer.attributes.include": ["request.parameters.*"]} -_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": USER_ATTRS, "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes) @@ -352,7 +348,7 @@ def test_browser_include_request_params(normal_application): _expected_attributes = { "agent": [*TRACE_ERROR_AGENT_KEYS, f"request.parameters.{URL_PARAM}"], "user": ERROR_USER_ATTRS, - "intrinsic": ["trip_id"], + "intrinsic": [], } _expected_attributes_event = { @@ -379,7 +375,7 @@ def test_error_in_transaction_include_exclude(normal_application): _expected_attributes = { "agent": [*TRACE_ERROR_AGENT_KEYS, f"request.parameters.{URL_PARAM}"], "user": USER_ATTRS, - "intrinsic": ["trip_id"], + "intrinsic": [], } @@ -434,7 +430,7 @@ def test_browser_include_exclude_request_params(normal_application): _override_settings = {"error_collector.attributes.exclude": ["puppies"]} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ["sunshine", "ohnoes"], "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ["sunshine", "ohnoes"], "intrinsic": []} _expected_attributes_event = { "agent": TRACE_ERROR_AGENT_KEYS, @@ -454,7 +450,7 @@ def test_error_in_transaction_exclude_user_attribute(normal_application): _override_settings = {"transaction_tracer.attributes.exclude": ["puppies"]} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ["sunshine"], "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ["sunshine"], "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes, _expected_absent_attributes) @@ -509,7 +505,7 @@ def test_browser_exclude_user_attribute(normal_application): _expected_attributes = { "agent": ["response.status", "request.headers.contentType", "request.headers.contentLength"], "user": ERROR_USER_ATTRS, - "intrinsic": ["trip_id"], + "intrinsic": [], } _expected_attributes_event = { @@ -531,7 +527,7 @@ def test_error_in_transaction_exclude_agent_attribute(normal_application): _expected_attributes = { "agent": ["response.status", "request.headers.contentType", "request.headers.contentLength"], "user": USER_ATTRS, - "intrinsic": ["trip_id"], + "intrinsic": [], } @@ -577,7 +573,7 @@ def test_span_event_exclude_agent_attribute(normal_application): _override_settings = {"capture_params": True} -_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = {"agent": AGENT_KEYS_ALL, "user": ERROR_USER_ATTRS, "intrinsic": ERROR_EVENT_INTRINSICS} @@ -589,7 +585,7 @@ def test_error_in_transaction_deprecated_capture_params_true(normal_application) normal_application.get(REQUEST_URL, headers=REQUEST_HEADERS) -_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": AGENT_KEYS_ALL, "user": USER_ATTRS, "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes) @@ -628,7 +624,7 @@ def test_browser_deprecated_capture_params_true(normal_application): _override_settings = {"capture_params": False} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = { "agent": TRACE_ERROR_AGENT_KEYS, @@ -646,7 +642,7 @@ def test_error_in_transaction_deprecated_capture_params_false(normal_application normal_application.get(REQUEST_URL, headers=REQUEST_HEADERS) -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes, _expected_absent_attributes) @@ -683,9 +679,9 @@ def test_browser_deprecated_capture_params_false(normal_application): # Test attempt to exclude intrinsic. -_override_settings = {"error_collector.attributes.exclude": ["trip_id"]} +_override_settings = {"error_collector.attributes.exclude": []} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": ERROR_USER_ATTRS, "intrinsic": []} _expected_attributes_event = { "agent": TRACE_ERROR_AGENT_KEYS, @@ -703,9 +699,9 @@ def test_error_in_transaction_exclude_intrinsic(normal_application): normal_application.get(REQUEST_URL, headers=REQUEST_HEADERS) -_override_settings = {"transaction_tracer.attributes.exclude": ["trip_id"]} +_override_settings = {"transaction_tracer.attributes.exclude": []} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} @validate_transaction_trace_attributes(_expected_attributes, _expected_absent_attributes) @@ -747,7 +743,7 @@ def test_browser_exclude_intrinsic(normal_application): _override_settings = {"error_collector.attributes.enabled": False} -_expected_attributes = {"user": [], "agent": [], "intrinsic": ["trip_id"]} +_expected_attributes = {"user": [], "agent": [], "intrinsic": []} _expected_attributes_event = {"user": [], "agent": [], "intrinsic": ERROR_EVENT_INTRINSICS} @@ -800,7 +796,7 @@ def test_browser_attributes_disabled(normal_application): _override_settings = {"error_collector.attributes.exclude": ERROR_PARAMS} -_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ["trip_id"]} +_expected_attributes = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": []} _expected_attributes_event = {"agent": TRACE_ERROR_AGENT_KEYS, "user": USER_ATTRS, "intrinsic": ERROR_EVENT_INTRINSICS} diff --git a/tests/agent_features/test_cat.py b/tests/agent_features/test_cat.py deleted file mode 100644 index 41c7b0d6ae..0000000000 --- a/tests/agent_features/test_cat.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -This file contains a special case test for CAT. Most CAT testing is found at -`tests/cross_agent/test_cat_map.py` and -`newrelic/api/tests/test_cross_process.py`. This test does not fit either of -those spaces, the former being reserved for cross agent testing and the latter -being a unittest for the `process_response` method. Since this is a more end to -end style test, it does not fit as a unittest. -""" - -import pytest -import webtest -from testing_support.fixtures import cat_enabled, make_cross_agent_headers, override_application_settings - -from newrelic.api.background_task import background_task -from newrelic.api.external_trace import ExternalTrace -from newrelic.api.wsgi_application import wsgi_application - -ENCODING_KEY = "1234567890123456789012345678901234567890" - - -@wsgi_application() -def target_wsgi_application(environ, start_response): - status_code = int(environ["PATH_INFO"].strip("/")) - status = f"{status_code} STATUS" - - if status_code == 304: - output = b"" - response_headers = [] - else: - output = b"hello world" - response_headers = [("Content-type", "text/html; charset=utf-8"), ("Content-Length", str(len(output)))] - start_response(status, response_headers) - - return [output] - - -test_application = webtest.TestApp(target_wsgi_application) - -_override_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "browser_monitoring.enabled": False, -} - -payload = ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"] - - -@cat_enabled -@override_application_settings(_override_settings) -def test_cat_disabled_browser_monitoring(): - headers = make_cross_agent_headers(payload, ENCODING_KEY, "1#1") - response = test_application.get("/200", headers=headers) - assert "X-NewRelic-App-Data" in response.headers - - -@override_application_settings(_override_settings) -def test_cat_insertion_disabled_on_304(): - headers = make_cross_agent_headers(payload, ENCODING_KEY, "1#1") - response = test_application.get("/304", headers=headers) - assert "X-NewRelic-App-Data" not in response.headers - - -_override_settings = {"cross_application_tracer.enabled": True, "distributed_tracing.enabled": False} - - -@cat_enabled -@override_application_settings(_override_settings) -@pytest.mark.parametrize("fips_enabled", (False, True)) -@background_task() -def test_cat_fips_compliance(monkeypatch, fips_enabled): - # Set md5 to raise a ValueError to simulate FIPS compliance issues. - def md5_crash(*args, **kwargs): - raise ValueError - - if fips_enabled: - # monkeypatch.setattr("hashlib.md5", md5_crash) - import hashlib - - monkeypatch.setattr(hashlib, "md5", md5_crash) - - # Generate and send request using actual transaction api instead of fixture. - # Otherwise the proper code paths are not exercised. - with ExternalTrace("cat_test", "http://localhost/200") as tracer: - headers = tracer.generate_request_headers(tracer.transaction) - - expected = not fips_enabled # Invert to make more human readable - assert ("X-NewRelic-Transaction" in dict(headers)) == expected diff --git a/tests/agent_features/test_distributed_tracing.py b/tests/agent_features/test_distributed_tracing.py index 36261d97e2..b6043c166a 100644 --- a/tests/agent_features/test_distributed_tracing.py +++ b/tests/agent_features/test_distributed_tracing.py @@ -111,7 +111,6 @@ def target_wsgi_application(environ, start_response): def test_distributed_tracing_web_transaction(): headers = {"newrelic": json.dumps(payload)} response = test_application.get("/", headers=headers) - assert "X-NewRelic-App-Data" not in response.headers @pytest.mark.parametrize("span_events", (True, False)) diff --git a/tests/agent_features/test_error_events.py b/tests/agent_features/test_error_events.py index 30a89c9044..98219b8c4e 100644 --- a/tests/agent_features/test_error_events.py +++ b/tests/agent_features/test_error_events.py @@ -17,8 +17,6 @@ import webtest from testing_support.fixtures import ( - cat_enabled, - make_cross_agent_headers, make_synthetics_headers, override_application_settings, reset_core_stats_engine, @@ -108,18 +106,13 @@ def test_transaction_error_background_task(): "error.message": ERR_MESSAGE, "error.expected": False, "transactionName": "WebTransaction/Uri/", - "nr.referringTransactionGuid": 7, } -@cat_enabled @validate_error_event_sample_data(required_attrs=_intrinsic_attributes, required_user_attrs=True) -def test_transaction_error_cross_agent(): +def test_transaction_error_dt_headers(): test_environ = {"err_message": ERR_MESSAGE} - settings = application_settings() - transaction_data = [7, 1, 77, "/path-hash"] - headers = make_cross_agent_headers(transaction_data, settings.encoding_key, settings.cross_process_id) - response = fully_featured_application.get("/", headers=headers, extra_environ=test_environ) + response = fully_featured_application.get("/", extra_environ=test_environ) _intrinsic_attributes = { diff --git a/tests/agent_features/test_serverless_mode.py b/tests/agent_features/test_serverless_mode.py index 048b96aa23..dedab37260 100644 --- a/tests/agent_features/test_serverless_mode.py +++ b/tests/agent_features/test_serverless_mode.py @@ -17,7 +17,6 @@ import pytest from testing_support.fixtures import override_generic_settings from testing_support.validators.validate_serverless_data import validate_serverless_data -from testing_support.validators.validate_serverless_metadata import validate_serverless_metadata from testing_support.validators.validate_serverless_payload import validate_serverless_payload from newrelic.api.application import application_instance @@ -65,24 +64,6 @@ def _test(): payload = json.loads(out) -def test_no_cat_headers(serverless_application): - @background_task(application=serverless_application, name="test_cat_headers") - def _test_cat_headers(): - transaction = current_transaction() - - payload = ExternalTrace.generate_request_headers(transaction) - assert not payload - - trace = ExternalTrace("testlib", "http://example.com") - response_headers = [("X-NewRelic-App-Data", "Cookies")] - with trace: - trace.process_response_headers(response_headers) - - assert transaction.settings.cross_application_tracer.enabled is False - - _test_cat_headers() - - @pytest.mark.parametrize("trusted_account_key", ("1", None), ids=("tk_set", "tk_unset")) def test_outbound_dt_payload_generation(serverless_application, trusted_account_key): @override_generic_settings( diff --git a/tests/agent_features/test_synthetics.py b/tests/agent_features/test_synthetics.py index f584a12237..2b4c864509 100644 --- a/tests/agent_features/test_synthetics.py +++ b/tests/agent_features/test_synthetics.py @@ -15,7 +15,7 @@ import pytest import webtest from testing_support.external_fixtures import validate_synthetics_external_trace_header -from testing_support.fixtures import cat_enabled, make_synthetics_headers, override_application_settings +from testing_support.fixtures import make_synthetics_headers, override_application_settings from testing_support.validators.validate_synthetics_event import validate_synthetics_event from testing_support.validators.validate_synthetics_transaction_trace import validate_synthetics_transaction_trace @@ -187,7 +187,6 @@ def test_synthetics_event_mismatched_info_encoding_key(): } -@cat_enabled @validate_synthetics_transaction_trace(_test_valid_synthetics_tt_required) @override_application_settings(_override_settings) def test_valid_synthetics_in_transaction_trace(): @@ -220,7 +219,6 @@ def test_synthetics_disabled(): _external_synthetics_info_header = _external_synthetics_headers["X-NewRelic-Synthetics-Info"] -@cat_enabled @validate_synthetics_external_trace_header(_external_synthetics_header, _external_synthetics_info_header) @override_application_settings(_override_settings) def test_valid_synthetics_external_trace_header(): @@ -228,7 +226,6 @@ def test_valid_synthetics_external_trace_header(): response = target_application.get("/", headers=headers) -@cat_enabled @validate_synthetics_external_trace_header(_external_synthetics_header, None) @override_application_settings(_override_settings) def test_valid_synthetics_external_trace_header_without_info(): @@ -236,7 +233,6 @@ def test_valid_synthetics_external_trace_header_without_info(): response = target_application.get("/", headers=headers) -@cat_enabled @validate_synthetics_external_trace_header(_external_synthetics_header, _external_synthetics_info_header) @override_application_settings(_override_settings) def test_valid_external_trace_header_with_byte_inbound_header(): diff --git a/tests/agent_unittests/test_agent_protocol.py b/tests/agent_unittests/test_agent_protocol.py index f87f48f7f6..d7c760c762 100644 --- a/tests/agent_unittests/test_agent_protocol.py +++ b/tests/agent_unittests/test_agent_protocol.py @@ -488,9 +488,6 @@ def test_serverless_protocol_connect(): # No client calls should be made assert len(HttpClientRecorder.SENT) == 0 - # cross application tracing must be disabled - assert not protocol.configuration.cross_application_tracer.enabled - def test_serverless_protocol_finalize(capsys): protocol = ServerlessModeProtocol( diff --git a/tests/agent_unittests/test_harvest_loop.py b/tests/agent_unittests/test_harvest_loop.py index b9c1ea25b8..813e642d4e 100644 --- a/tests/agent_unittests/test_harvest_loop.py +++ b/tests/agent_unittests/test_harvest_loop.py @@ -134,8 +134,6 @@ def transaction_node(request): guid="4485b89db608aece", cpu_time=0.0, suppress_transaction_trace=False, - client_cross_process_id=None, - referring_transaction_guid=None, record_tt=False, synthetics_resource_id=None, synthetics_job_id=None, @@ -145,11 +143,6 @@ def transaction_node(request): synthetics_initiator=None, synthetics_attributes=None, synthetics_info_header=None, - is_part_of_cat=False, - trip_id="4485b89db608aece", - path_hash=None, - referring_path_hash=None, - alternate_path_hashes=[], trace_intrinsics={}, distributed_trace_intrinsics={}, agent_attributes=[], diff --git a/tests/cross_agent/fixtures/cat_map.json b/tests/cross_agent/fixtures/cat_map.json deleted file mode 100644 index b91265f44f..0000000000 --- a/tests/cross_agent/fixtures/cat_map.json +++ /dev/null @@ -1,597 +0,0 @@ -[ - { - "name": "new_cat", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - "5d2957be" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "815b96d3", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "5d2957be" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_path_hash_with_leading_zero", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/txn4", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - "5d2957be" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "0e258e4e", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "5d2957be" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_path_hash_with_unicode_name", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/txn\u221a\u221a\u221a", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - "5d2957be" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "3d015d23", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "5d2957be" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_no_referring_payload", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": null, - "expectedIntrinsicFields": {}, - "nonExpectedIntrinsicFields": [ - "nr.guid", - "nr.tripId", - "nr.pathHash", - "nr.referringTransactionGuid", - "nr.referringPathHash", - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_with_call_out", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": null, - "outboundRequests": [ - { - "outboundTxnName": "WebTransaction/Custom/testTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "3b0939af" - ] - } - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af" - }, - "nonExpectedIntrinsicFields": [ - "nr.referringTransactionGuid", - "nr.referringPathHash", - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_with_multiple_calls_out", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": null, - "outboundRequests": [ - { - "outboundTxnName": "WebTransaction/Custom/otherTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "f1c8adf5" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/otherTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "f1c8adf5" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/moreOtherTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "ea19b61c" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/moreDifferentTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "e00736cc" - ] - } - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af", - "nr.alternatePathHashes": "e00736cc,ea19b61c,f1c8adf5" - }, - "nonExpectedIntrinsicFields": [ - "nr.referringTransactionGuid", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_with_many_unique_calls_out", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": null, - "outboundRequests": [ - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn2", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "a67c2da4" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn3", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "0d932b2b" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn4", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "b4772132" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn5", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "51a1a337" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn6", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "77b5cb70" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn7", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "8a842c7f" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn8", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "b968edb8" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn9", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "2691f90e" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn10", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "b46aec87" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn11", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "10bb3bf3" - ] - } - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af", - "nr.alternatePathHashes": "0d932b2b,2691f90e,51a1a337,77b5cb70,8a842c7f,93fb4310,a67c2da4,b46aec87,b4772132,b968edb8" - }, - "nonExpectedIntrinsicFields": [ - "nr.referringTransactionGuid", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_with_many_calls_out", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": null, - "outboundRequests": [ - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn1", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "93fb4310" - ] - }, - { - "outboundTxnName": "WebTransaction/Custom/txn2", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "9323dc260548ed0e", - "a67c2da4" - ] - } - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af", - "nr.alternatePathHashes": "93fb4310,a67c2da4" - }, - "nonExpectedIntrinsicFields": [ - "nr.referringTransactionGuid", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_with_referring_info_and_call_out", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - "5d2957be" - ], - "outboundRequests": [ - { - "outboundTxnName": "WebTransaction/Custom/otherTxnName", - "expectedOutboundPayload": [ - "9323dc260548ed0e", - false, - "7e249074f277923d", - "4b9a0289" - ] - } - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "815b96d3", - "nr.alternatePathHashes": "4b9a0289", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "5d2957be" - }, - "nonExpectedIntrinsicFields": [] - }, - { - "name": "new_cat_missing_path_hash", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_null_path_hash", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - null - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_malformed_path_hash", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - [ - "scrambled", - "eggs" - ] - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes", - "nr.referringPathHash" - ] - }, - { - "name": "new_cat_corrupt_path_hash", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - "7e249074f277923d", - "ZXYQEDABC" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "7e249074f277923d", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "ZXYQEDABC" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_malformed_trip_id", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - ["scrambled"], - "5d2957be" - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "815b96d3", - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.referringPathHash": "5d2957be" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_missing_trip_id", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06" - }, - "nonExpectedIntrinsicFields": [ - "nr.referringPathHash", - "nr.alternatePathHashes" - ] - }, - { - "name": "new_cat_null_trip_id", - "appName": "testAppName", - "transactionName": "WebTransaction/Custom/testTxnName", - "transactionGuid": "9323dc260548ed0e", - "inboundPayload": [ - "b854df4feb2b1f06", - false, - null - ], - "expectedIntrinsicFields": { - "nr.guid": "9323dc260548ed0e", - "nr.tripId": "9323dc260548ed0e", - "nr.pathHash": "3b0939af", - "nr.referringTransactionGuid": "b854df4feb2b1f06" - }, - "nonExpectedIntrinsicFields": [ - "nr.alternatePathHashes", - "nr.referringPathHash" - ] - } -] diff --git a/tests/cross_agent/test_cat_map.py b/tests/cross_agent/test_cat_map.py deleted file mode 100644 index 01ede0b19a..0000000000 --- a/tests/cross_agent/test_cat_map.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -This is an implementation of the cross agent tests for cat map using a wsgi -application. Another implementation of these tests using a tornado application -can be found in test/framework_tornado_r3/test_cat_map.py -""" - -import json -from pathlib import Path -from urllib.request import urlopen - -import pytest -import webtest -from testing_support.fixtures import ( - make_cross_agent_headers, - override_application_name, - override_application_settings, - validate_analytics_catmap_data, -) -from testing_support.mock_external_http_server import MockExternalHTTPHResponseHeadersServer -from testing_support.validators.validate_tt_parameters import validate_tt_parameters - -from newrelic.api.external_trace import ExternalTrace -from newrelic.api.transaction import ( - current_transaction, - get_browser_timing_header, - set_background_task, - set_transaction_name, -) -from newrelic.api.wsgi_application import wsgi_application -from newrelic.common.encoding_utils import json_encode, obfuscate - -ENCODING_KEY = "1234567890123456789012345678901234567890" -FIXTURE = Path(__file__).parent / "fixtures" / "cat_map.json" -OUTBOUD_REQUESTS = {} - -_parameters_list = [ - "name", - "appName", - "transactionName", - "transactionGuid", - "inboundPayload", - "outboundRequests", - "expectedIntrinsicFields", - "nonExpectedIntrinsicFields", -] - - -@pytest.fixture(scope="module") -def server(): - with MockExternalHTTPHResponseHeadersServer() as _server: - yield _server - - -def load_tests(): - result = [] - with FIXTURE.open() as fh: - tests = json.load(fh) - - for test in tests: - values = tuple([test.get(param, None) for param in _parameters_list]) - result.append(values) - - return result - - -_parameters = ",".join(_parameters_list) - - -@wsgi_application() -def target_wsgi_application(environ, start_response): - status = "200 OK" - - txn_name = environ.get("txn").split("/", 3) - - guid = environ.get("guid") - old_cat = environ.get("old_cat") == "True" - txn = current_transaction() - - txn.guid = guid - for req in OUTBOUD_REQUESTS: - # Change the transaction name before making an outbound call. - outgoing_name = req["outboundTxnName"].split("/", 3) - if outgoing_name[0] != "WebTransaction": - set_background_task(True) - - set_transaction_name(outgoing_name[2], group=outgoing_name[1]) - - expected_outbound_header = obfuscate(json_encode(req["expectedOutboundPayload"]), ENCODING_KEY) - generated_outbound_header = dict(ExternalTrace.generate_request_headers(txn)) - - # A 500 error is returned because 'assert' statements in the wsgi app - # are ignored. - - if old_cat: - if expected_outbound_header != generated_outbound_header["X-NewRelic-Transaction"]: - status = "500 Outbound Headers Check Failed." - else: - if "X-NewRelic-Transaction" in generated_outbound_header: - status = "500 Outbound Headers Check Failed." - r = urlopen(environ["server_url"]) - r.read(10) - - # Set the final transaction name. - - if txn_name[0] != "WebTransaction": - set_background_task(True) - set_transaction_name(txn_name[2], group=txn_name[1]) - - text = "
%sRESPONSE
" - - output = (text % get_browser_timing_header()).encode("UTF-8") - - response_headers = [("Content-type", "text/html; charset=utf-8"), ("Content-Length", str(len(output)))] - start_response(status, response_headers) - - return [output] - - -target_application = webtest.TestApp(target_wsgi_application) - - -@pytest.mark.parametrize(_parameters, load_tests()) -@pytest.mark.parametrize("old_cat", (True, False)) -def test_cat_map( - name, - appName, - transactionName, - transactionGuid, - inboundPayload, - outboundRequests, - expectedIntrinsicFields, - nonExpectedIntrinsicFields, - old_cat, - server, -): - global OUTBOUD_REQUESTS - OUTBOUD_REQUESTS = outboundRequests or {} - - _custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": True, - "distributed_tracing.enabled": not old_cat, - "transaction_tracer.transaction_threshold": 0.0, - } - - if expectedIntrinsicFields and old_cat: - _external_node_params = { - "path_hash": expectedIntrinsicFields["nr.pathHash"], - "trip_id": expectedIntrinsicFields["nr.tripId"], - } - else: - _external_node_params = [] - - if not old_cat: - # since no better cat headers will be generated, no intrinsics should - # be added - expectedIntrinsicFields = {} - - @validate_tt_parameters(required_params=_external_node_params) - @validate_analytics_catmap_data( - transactionName, expected_attributes=expectedIntrinsicFields, non_expected_attributes=nonExpectedIntrinsicFields - ) - @override_application_settings(_custom_settings) - @override_application_name(appName) - def run_cat_test(): - txn_name = transactionName - guid = transactionGuid - - # Only generate old cat style headers. This will test to make sure we - # are properly ignoring these headers when the agent is using better - # cat. - - headers = make_cross_agent_headers(inboundPayload, ENCODING_KEY, "1#1") - response = target_application.get( - "/", - headers=headers, - extra_environ={ - "txn": txn_name, - "guid": guid, - "old_cat": str(old_cat), - "server_url": f"http://localhost:{server.port}", - }, - ) - - # Validation of analytic data happens in the decorator. - - assert response.status == "200 OK" - - content = response.html.html.body.p.string - - # Validate actual body content as sanity check. - - assert content == "RESPONSE" - - run_cat_test() diff --git a/tests/cross_agent/test_distributed_tracing.py b/tests/cross_agent/test_distributed_tracing.py index a3536fcce5..21baa9e45d 100644 --- a/tests/cross_agent/test_distributed_tracing.py +++ b/tests/cross_agent/test_distributed_tracing.py @@ -219,7 +219,6 @@ def test_distributed_tracing( @override_application_settings(override_settings) def _test(): response = test_application.get("/", headers=headers) - assert "X-NewRelic-App-Data" not in response.headers if "Span" in intrinsics: span_intrinsics = intrinsics.get("Span") diff --git a/tests/external_http/test_http.py b/tests/external_http/test_http.py index 590e659600..0ba4c7d740 100644 --- a/tests/external_http/test_http.py +++ b/tests/external_http/test_http.py @@ -15,10 +15,9 @@ import http.client import pytest -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled, override_application_settings -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from newrelic.api.background_task import background_task @@ -72,10 +71,10 @@ def _test(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_http_cross_process_request(distributed_tracing, span_events, server): - @background_task(name="test_http:test_http_cross_process_request") +def test_http_distributed_tracing_request(distributed_tracing, span_events, server): + @background_task(name="test_http:test_http_distributed_tracing_request") @cache_outgoing_headers - @validate_cross_process_headers + @validate_distributed_tracing_headers def _test(): connection = http.client.HTTPConnection("localhost", server.port) connection.request("GET", "/") @@ -84,48 +83,7 @@ def _test(): connection.close() _test = override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "cross_application_tracer.enabled": not distributed_tracing, - "span_events.enabled": span_events, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} )(_test) _test() - - -@cat_enabled -def test_http_cross_process_response(server): - _test_http_cross_process_response_scoped_metrics = [(f"ExternalTransaction/localhost:{server.port}/1#2/test", 1)] - - _test_http_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_http_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_metrics( - "test_http:test_http_cross_process_response", - scoped_metrics=_test_http_cross_process_response_scoped_metrics, - rollup_metrics=_test_http_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_http_cross_process_response_external_node_params) - @background_task(name="test_http:test_http_cross_process_response") - def _test(): - connection = http.client.HTTPConnection("localhost", server.port) - connection.request("GET", "/") - response = connection.getresponse() - response.read() - connection.close() - - _test() diff --git a/tests/external_httplib/test_httplib.py b/tests/external_httplib/test_httplib.py index 64b7c94f77..cf0d42f7b7 100644 --- a/tests/external_httplib/test_httplib.py +++ b/tests/external_httplib/test_httplib.py @@ -12,13 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +import base64 import http.client as httplib +import json import pytest -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled, override_application_settings -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_span_events import validate_span_events from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from testing_support.validators.validate_tt_segment_params import validate_tt_segment_params @@ -110,10 +111,10 @@ def _test(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_httplib_cross_process_request(server, distributed_tracing, span_events): - @background_task(name="test_httplib:test_httplib_cross_process_request") +def test_httplib_distributed_tracing_request(server, distributed_tracing, span_events): + @background_task(name="test_httplib:test_httplib_distributed_tracing_request") @cache_outgoing_headers - @validate_cross_process_headers + @validate_distributed_tracing_headers def _test(): connection = httplib.HTTPConnection("localhost", server.port) connection.request("GET", "/") @@ -122,86 +123,12 @@ def _test(): connection.close() _test = override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "cross_application_tracer.enabled": not distributed_tracing, - "span_events.enabled": span_events, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} )(_test) _test() -_test_httplib_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), -] - - -@cat_enabled -@insert_incoming_headers -def test_httplib_cross_process_response(server): - scoped = [(f"ExternalTransaction/localhost:{server.port}/1#2/test", 1)] - - rollup = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - @validate_transaction_metrics( - "test_httplib:test_httplib_cross_process_response", - scoped_metrics=scoped, - rollup_metrics=rollup, - background_task=True, - ) - @validate_external_node_params(params=_test_httplib_cross_process_response_external_node_params) - @background_task(name="test_httplib:test_httplib_cross_process_response") - def _test(): - connection = httplib.HTTPConnection("localhost", server.port) - connection.request("GET", "/") - response = connection.getresponse() - response.read() - connection.close() - - _test() - - -@cat_enabled -def test_httplib_multiple_requests_cross_process_response(server): - connection = httplib.HTTPConnection("localhost", server.port) - - scoped = [(f"ExternalTransaction/localhost:{server.port}/1#2/test", 1)] - - rollup = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - @validate_transaction_metrics( - "test_httplib:test_transaction", scoped_metrics=scoped, rollup_metrics=rollup, background_task=True - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_httplib_cross_process_response_external_node_params) - @background_task(name="test_httplib:test_transaction") - def test_transaction(): - connection.request("GET", "/") - response = connection.getresponse() - response.read() - - # make multiple requests with the same connection - for _ in range(2): - test_transaction() - - connection.close() - - def process_response(response): response = response.decode("utf-8").strip() values = response.splitlines() @@ -256,7 +183,7 @@ def test_transaction(): )(test_transaction) test_transaction() connection.close() - # verify newrelic headers already added do not get overrode + # verify newrelic headers already added do not get overridden assert headers[0][key] == value diff --git a/tests/external_httplib/test_urllib.py b/tests/external_httplib/test_urllib.py index 9b2fde3500..d6cec86e8f 100644 --- a/tests/external_httplib/test_urllib.py +++ b/tests/external_httplib/test_urllib.py @@ -21,10 +21,8 @@ except ImportError: import urllib -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from newrelic.api.background_task import background_task @@ -138,49 +136,12 @@ def test_urlopener_file_request(): @SKIP_IF_PYTHON_3_14_OR_ABOVE @background_task() @cache_outgoing_headers -@validate_cross_process_headers -def test_urlopener_cross_process_request(server): +@validate_distributed_tracing_headers +def test_urlopener_distributed_tracing_request(server): opener = urllib.URLopener() opener.open(f"http://localhost:{server.port}/") -@SKIP_IF_PYTHON_3_14_OR_ABOVE -@cat_enabled -def test_urlopener_cross_process_response(server): - _test_urlopener_cross_process_response_scoped_metrics = [ - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1) - ] - - _test_urlopener_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_urlopener_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_metrics( - "test_urllib:test_urlopener_cross_process_response", - scoped_metrics=_test_urlopener_cross_process_response_scoped_metrics, - rollup_metrics=_test_urlopener_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_urlopener_cross_process_response_external_node_params) - @background_task(name="test_urllib:test_urlopener_cross_process_response") - def _test(): - opener = urllib.URLopener() - opener.open(f"http://localhost:{server.port}/") - - _test() - - def test_urlretrieve_http_request(server, metrics): @validate_transaction_metrics( "test_urllib:test_urlretrieve_http_request", @@ -214,41 +175,6 @@ def _test(): @background_task() @cache_outgoing_headers -@validate_cross_process_headers -def test_urlretrieve_cross_process_request(server): +@validate_distributed_tracing_headers +def test_urlretrieve_distributed_tracing_request(server): urllib.urlretrieve(f"http://localhost:{server.port}/") - - -@cat_enabled -def test_urlretrieve_cross_process_response(server): - _test_urlretrieve_cross_process_response_scoped_metrics = [ - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1) - ] - - _test_urlretrieve_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_urlretrieve_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_metrics( - "test_urllib:test_urlretrieve_cross_process_response", - scoped_metrics=_test_urlretrieve_cross_process_response_scoped_metrics, - rollup_metrics=_test_urlretrieve_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_urlretrieve_cross_process_response_external_node_params) - @background_task(name="test_urllib:test_urlretrieve_cross_process_response") - def _test(): - urllib.urlretrieve(f"http://localhost:{server.port}/") - - _test() diff --git a/tests/external_httplib/test_urllib2.py b/tests/external_httplib/test_urllib2.py index c744614be8..3e23bd7f9f 100644 --- a/tests/external_httplib/test_urllib2.py +++ b/tests/external_httplib/test_urllib2.py @@ -15,10 +15,8 @@ import urllib.request as urllib2 import pytest -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from newrelic.api.background_task import background_task @@ -115,39 +113,6 @@ def test_urlopen_file_request(): @background_task() @cache_outgoing_headers -@validate_cross_process_headers -def test_urlopen_cross_process_request(server): +@validate_distributed_tracing_headers +def test_urlopen_distributed_tracing_request(server): urllib2.urlopen(f"http://localhost:{server.port}/") - - -@cat_enabled -def test_urlopen_cross_process_response(server): - _test_urlopen_cross_process_response_scoped_metrics = [(f"ExternalTransaction/localhost:{server.port}/1#2/test", 1)] - - _test_urlopen_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_urlopen_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_metrics( - "test_urllib2:test_urlopen_cross_process_response", - scoped_metrics=_test_urlopen_cross_process_response_scoped_metrics, - rollup_metrics=_test_urlopen_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_urlopen_cross_process_response_external_node_params) - @background_task(name="test_urllib2:test_urlopen_cross_process_response") - def _test(): - urllib2.urlopen(f"http://localhost:{server.port}/") - - _test() diff --git a/tests/external_httplib2/test_httplib2.py b/tests/external_httplib2/test_httplib2.py index e2ffd9f46a..a2956dc2bf 100644 --- a/tests/external_httplib2/test_httplib2.py +++ b/tests/external_httplib2/test_httplib2.py @@ -14,10 +14,9 @@ import httplib2 import pytest -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled, override_application_settings -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from newrelic.api.background_task import background_task @@ -90,10 +89,10 @@ def _test(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_httplib2_cross_process_request(distributed_tracing, span_events, server): - @background_task(name="test_httplib2:test_httplib2_cross_process_response") +def test_httplib2_distributed_tracing_request(distributed_tracing, span_events, server): + @background_task(name="test_httplib2:test_httplib2_distributed_tracing_response") @cache_outgoing_headers - @validate_cross_process_headers + @validate_distributed_tracing_headers def _test(): connection = httplib2.HTTPConnectionWithTimeout("localhost", server.port) connection.request("GET", "/") @@ -102,50 +101,7 @@ def _test(): connection.close() _test = override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "cross_application_tracer.enabled": not distributed_tracing, - "span_events.enabled": span_events, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} )(_test) _test() - - -@cat_enabled -def test_httplib2_cross_process_response(server): - _test_httplib2_cross_process_response_scoped_metrics = [ - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1) - ] - - _test_httplib2_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_httplib2_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_metrics( - "test_httplib2:test_httplib2_cross_process_response", - scoped_metrics=_test_httplib2_cross_process_response_scoped_metrics, - rollup_metrics=_test_httplib2_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_httplib2_cross_process_response_external_node_params) - @background_task(name="test_httplib2:test_httplib2_cross_process_response") - def _test(): - connection = httplib2.HTTPConnectionWithTimeout("localhost", server.port) - connection.request("GET", "/") - response = connection.getresponse() - response.read() - connection.close() - - _test() diff --git a/tests/external_httpx/test_client.py b/tests/external_httpx/test_client.py index 6f442fb87d..994f1360b4 100644 --- a/tests/external_httpx/test_client.py +++ b/tests/external_httpx/test_client.py @@ -17,48 +17,35 @@ import pytest from testing_support.fixtures import dt_enabled, override_application_settings, override_generic_settings from testing_support.mock_external_http_server import MockExternalHTTPHResponseHeadersServer -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_span_events import validate_span_events from testing_support.validators.validate_transaction_errors import validate_transaction_errors from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics -from testing_support.validators.validate_tt_segment_params import validate_tt_segment_params from newrelic.api.background_task import background_task from newrelic.api.time_trace import current_trace from newrelic.api.transaction import current_transaction from newrelic.core.config import global_settings -ENCODING_KEY = "1234567890123456789012345678901234567890" SCOPED_METRICS = [] ROLLUP_METRICS = [("External/all", 2), ("External/allOther", 2)] -CAT_RESPONSE_CODE = None +RESPONSE_CODE = None -def cat_response_handler(self): - if not CAT_RESPONSE_CODE: - raise ValueError("CAT_RESPONSE_CODE must be a valid status_code.") +def dt_response_handler(self): + if not RESPONSE_CODE: + raise ValueError("RESPONSE_CODE must be a valid status_code.") - # payload - # ( - # u'1#1', u'WebTransaction/Function/app:beep', - # 0, 1.23, -1, - # 'dd4a810b7cb7f937', - # False, - # ) - cat_response_header = ( - "X-NewRelic-App-Data", - "ahACFwQUGxpuVVNmQVVbRVZbTVleXBxyQFhUTFBfXx1SREUMVV1cQBMeAxgEGAULFR0AHhFQUQJWAAgAUwVQVgJQDgsOEh1UUlhGU2o=", - ) - self.send_response(CAT_RESPONSE_CODE) - self.send_header(*cat_response_header) + response = str(self.headers).encode("utf-8") # Might need to put headers here + self.send_response(RESPONSE_CODE) self.end_headers() - self.wfile.write(b"Example Data") + self.wfile.write(response) @pytest.fixture(scope="session") def mock_server(): - external = MockExternalHTTPHResponseHeadersServer(handler=cat_response_handler) + external = MockExternalHTTPHResponseHeadersServer(handler=dt_response_handler) with external: yield external @@ -85,8 +72,8 @@ def exercise_sync_client(server, client, method, protocol="http"): ) @background_task(name="test_sync_client") def test_sync_client(httpx, sync_client, mock_server, method): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 assert exercise_sync_client(mock_server, sync_client, method).status_code == 200 @@ -108,28 +95,24 @@ async def exercise_async_client(server, client, method, protocol="http"): ) @background_task(name="test_async_client") def test_async_client(httpx, async_client, mock_server, loop, method): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 responses = loop.run_until_complete(exercise_async_client(mock_server, async_client, method)) assert all(response.status_code == 200 for response in responses) @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_sync_cross_process_request(httpx, sync_client, mock_server, distributed_tracing, span_events): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 +def test_sync_distributed_tracing_request(httpx, sync_client, mock_server, distributed_tracing, span_events): + global RESPONSE_CODE + RESPONSE_CODE = 200 @override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "span_events.enabled": span_events, - "cross_application_tracer.enabled": not distributed_tracing, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} ) @validate_transaction_errors(errors=[]) - @background_task(name="test_sync_cross_process_request") - @validate_cross_process_headers + @background_task(name="test_sync_distributed_tracing_request") + @validate_distributed_tracing_headers def _test(): transaction = current_transaction() @@ -145,11 +128,11 @@ def _test(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) @validate_transaction_errors(errors=[]) -@background_task(name="test_async_cross_process_request") -@validate_cross_process_headers -def test_async_cross_process_request(httpx, async_client, mock_server, loop, distributed_tracing, span_events): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 +@background_task(name="test_async_distributed_tracing_request") +@validate_distributed_tracing_headers +def test_async_distributed_tracing_request(httpx, async_client, mock_server, loop, distributed_tracing, span_events): + global RESPONSE_CODE + RESPONSE_CODE = 200 @override_application_settings( {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} @@ -168,13 +151,13 @@ async def _test(): @override_application_settings( - {"distributed_tracing.enabled": True, "span_events.enabled": True, "cross_application_tracer.enabled": True} + {"distributed_tracing.enabled": True, "span_events.enabled": True} # , "cross_application_tracer.enabled": True} ) @validate_transaction_errors(errors=[]) -@background_task(name="test_sync_cross_process_override_headers") -def test_sync_cross_process_override_headers(httpx, sync_client, mock_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 +@background_task(name="test_sync_distributed_tracing_override_headers") +def test_sync_distributed_tracing_override_headers(httpx, sync_client, mock_server, loop): + global RESPONSE_CODE + RESPONSE_CODE = 200 transaction = current_transaction() @@ -189,10 +172,10 @@ def test_sync_cross_process_override_headers(httpx, sync_client, mock_server, lo @override_application_settings({"distributed_tracing.enabled": True, "span_events.enabled": True}) @validate_transaction_errors(errors=[]) -@background_task(name="test_async_cross_process_override_headers") -def test_async_cross_process_override_headers(httpx, async_client, mock_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 +@background_task(name="test_async_distributed_tracing_override_headers") +def test_async_distributed_tracing_override_headers(httpx, async_client, mock_server, loop): + global RESPONSE_CODE + RESPONSE_CODE = 200 async def _test(): async with async_client: @@ -206,91 +189,10 @@ async def _test(): assert response.request.headers["newrelic"] == "1234" -@pytest.mark.parametrize("cat_enabled", [True, False]) -@pytest.mark.parametrize("response_code", [200, 500]) -def test_sync_client_cat_response_processing(cat_enabled, response_code, sync_client, mock_server, httpx): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = response_code - - _custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": cat_enabled, - "distributed_tracing.enabled": False, - "transaction_tracer.transaction_threshold": 0.0, - } - - expected_metrics = [ - ( - f"ExternalTransaction/localhost:{mock_server.port}/1#1/WebTransaction/Function/app:beep", - 1 if cat_enabled else None, - ) - ] - - @validate_transaction_metrics( - "test_sync_client_cat_response_processing", - background_task=True, - rollup_metrics=expected_metrics, - scoped_metrics=expected_metrics, - ) - @validate_tt_segment_params(exact_params={"http.statusCode": response_code}) - @override_application_settings(_custom_settings) - @background_task(name="test_sync_client_cat_response_processing") - def _test(): - with sync_client: - response = sync_client.get(f"http://localhost:{mock_server.port}") - - _test() - - -@pytest.mark.parametrize("cat_enabled", [True, False]) -@pytest.mark.parametrize("response_code", [200, 500]) -def test_async_client_cat_response_processing(cat_enabled, response_code, httpx, async_client, mock_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = response_code - - _custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": cat_enabled, - "distributed_tracing.enabled": False, - "transaction_tracer.transaction_threshold": 0.0, - } - - expected_metrics = [ - ( - f"ExternalTransaction/localhost:{mock_server.port}/1#1/WebTransaction/Function/app:beep", - 1 if cat_enabled else None, - ) - ] - - @validate_transaction_metrics( - "test_async_client_cat_response_processing", - background_task=True, - rollup_metrics=expected_metrics, - scoped_metrics=expected_metrics, - ) - @validate_tt_segment_params(exact_params={"http.statusCode": response_code}) - @override_application_settings(_custom_settings) - @background_task(name="test_async_client_cat_response_processing") - def _test(): - async def coro(): - async with async_client: - response = await async_client.get(f"http://localhost:{mock_server.port}") - - return response - - response = loop.run_until_complete(coro()) - - _test() - - @dt_enabled def test_sync_client_event_hook_exception(httpx, mock_server): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 500 + global RESPONSE_CODE + RESPONSE_CODE = 500 def exception_event_hook(response): if response.status_code >= 400: @@ -302,7 +204,7 @@ def empty_hook(response): @validate_span_events( count=1, exact_intrinsics={"name": f"External/localhost:{mock_server.port}/httpx/GET"}, - exact_agents={"http.statusCode": CAT_RESPONSE_CODE}, + exact_agents={"http.statusCode": RESPONSE_CODE}, ) @background_task(name="test_sync_client_event_hook_exception") def make_request(client, exc_expected=True): @@ -335,8 +237,8 @@ def make_request(client, exc_expected=True): @override_application_settings({"distributed_tracing.enabled": True, "span_events.enabled": True}) def test_async_client_event_hook_exception(httpx, mock_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 500 + global RESPONSE_CODE + RESPONSE_CODE = 500 def exception_event_hook(response): if response.status_code >= 400: @@ -348,7 +250,7 @@ def empty_hook(response): @validate_span_events( count=1, exact_intrinsics={"name": f"External/localhost:{mock_server.port}/httpx/GET"}, - exact_agents={"http.statusCode": CAT_RESPONSE_CODE}, + exact_agents={"http.statusCode": RESPONSE_CODE}, ) @background_task(name="test_sync_client_event_hook_exception") def make_request(client, exc_expected=True): @@ -385,8 +287,8 @@ def _test(): @override_generic_settings(global_settings(), {"enabled": False}) def test_sync_nr_disabled(httpx, mock_server): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 with httpx.Client() as client: trace = current_trace() @@ -398,8 +300,8 @@ def test_sync_nr_disabled(httpx, mock_server): @override_generic_settings(global_settings(), {"enabled": False}) def test_async_nr_disabled(httpx, mock_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 async def _test(): async with httpx.AsyncClient() as client: @@ -415,8 +317,8 @@ async def _test(): @pytest.mark.parametrize("client", ("Client", "AsyncClient")) def test_invalid_import_order_client(monkeypatch, httpx, mock_server, loop, client): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 if "Async" in client: is_async = True @@ -447,8 +349,8 @@ def test_invalid_import_order_client(monkeypatch, httpx, mock_server, loop, clie ) @background_task(name="test_sync_client_http2") def test_sync_client_http2(httpx, real_server): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 client = httpx.Client(http1=False, http2=True, verify=False) response = exercise_sync_client(real_server, client, "get", protocol="https") @@ -462,8 +364,8 @@ def test_sync_client_http2(httpx, real_server): ) @background_task(name="test_async_client_http2") def test_async_client_http2(httpx, real_server, loop): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = 200 + global RESPONSE_CODE + RESPONSE_CODE = 200 client = httpx.AsyncClient(http1=False, http2=True, verify=False) diff --git a/tests/external_requests/test_requests.py b/tests/external_requests/test_requests.py index bb67691451..a5fe242077 100644 --- a/tests/external_requests/test_requests.py +++ b/tests/external_requests/test_requests.py @@ -15,10 +15,9 @@ import pytest import requests import requests.exceptions -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled, override_application_settings, validate_tt_parenting -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.fixtures import override_application_settings, validate_tt_parenting +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_errors import validate_transaction_errors from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics @@ -123,10 +122,8 @@ def test_none_url_get(): try: requests.get(None) except requests.exceptions.MissingSchema: - # Python 2. pass except TypeError: - # Python 3. pass @@ -156,56 +153,16 @@ def test_wrong_datatype_url_get(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_requests_cross_process_request(distributed_tracing, span_events, server): +def test_requests_distributed_tracing_request(distributed_tracing, span_events, server): @validate_transaction_errors(errors=[]) - @background_task(name="test_requests:test_requests_cross_process_request") + @background_task(name="test_requests:test_requests_distributed_tracing_request") @cache_outgoing_headers - @validate_cross_process_headers + @validate_distributed_tracing_headers def _test(): requests.get(f"http://localhost:{server.port}/") _test = override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "cross_application_tracer.enabled": not distributed_tracing, - "span_events.enabled": span_events, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} )(_test) _test() - - -@cat_enabled -def test_requests_cross_process_response(server): - _test_requests_cross_process_response_scoped_metrics = [ - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1) - ] - - _test_requests_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_requests_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_errors(errors=[]) - @validate_transaction_metrics( - "test_requests:test_requests_cross_process_response", - scoped_metrics=_test_requests_cross_process_response_scoped_metrics, - rollup_metrics=_test_requests_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_requests_cross_process_response_external_node_params) - @background_task(name="test_requests:test_requests_cross_process_response") - def _test(): - requests.get(f"http://localhost:{server.port}/") - - _test() diff --git a/tests/external_urllib3/test_urllib3.py b/tests/external_urllib3/test_urllib3.py index 6827fcf4cc..b098296569 100644 --- a/tests/external_urllib3/test_urllib3.py +++ b/tests/external_urllib3/test_urllib3.py @@ -14,17 +14,15 @@ import pytest import urllib3 -import urllib3.connectionpool try: import urllib3.connection except ImportError: pass -from testing_support.external_fixtures import cache_outgoing_headers, insert_incoming_headers -from testing_support.fixtures import cat_enabled, override_application_settings -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params +from testing_support.external_fixtures import cache_outgoing_headers +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_distributed_tracing_headers import validate_distributed_tracing_headers from testing_support.validators.validate_transaction_errors import validate_transaction_errors from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics @@ -204,56 +202,17 @@ def _test(): @pytest.mark.parametrize("distributed_tracing,span_events", ((True, True), (True, False), (False, False))) -def test_urlopen_cross_process_request(distributed_tracing, span_events, server): +def test_urlopen_distributed_tracing_request(distributed_tracing, span_events, server): @validate_transaction_errors(errors=[]) - @background_task(name="test_urllib3:test_urlopen_cross_process_request") + @background_task(name="test_urllib3:test_urlopen_distributed_tracing_request") @cache_outgoing_headers - @validate_cross_process_headers + @validate_distributed_tracing_headers def _test(): pool = urllib3.HTTPConnectionPool(f"localhost:{server.port}") pool.urlopen("GET", "/") _test = override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "cross_application_tracer.enabled": not distributed_tracing, - "span_events.enabled": span_events, - } + {"distributed_tracing.enabled": distributed_tracing, "span_events.enabled": span_events} )(_test) _test() - - -@cat_enabled -def test_urlopen_cross_process_response(server): - _test_urlopen_cross_process_response_scoped_metrics = [(f"ExternalTransaction/localhost:{server.port}/1#2/test", 1)] - - _test_urlopen_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/localhost:{server.port}/all", 1), - (f"ExternalApp/localhost:{server.port}/1#2/all", 1), - (f"ExternalTransaction/localhost:{server.port}/1#2/test", 1), - ] - - _test_urlopen_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - @validate_transaction_errors(errors=[]) - @validate_transaction_metrics( - "test_urllib3:test_urlopen_cross_process_response", - scoped_metrics=_test_urlopen_cross_process_response_scoped_metrics, - rollup_metrics=_test_urlopen_cross_process_response_rollup_metrics, - background_task=True, - ) - @insert_incoming_headers - @validate_external_node_params(params=_test_urlopen_cross_process_response_external_node_params) - @background_task(name="test_urllib3:test_urlopen_cross_process_response") - def _test(): - pool = urllib3.HTTPConnectionPool(f"localhost:{server.port}") - pool.urlopen("GET", "/") - - _test() diff --git a/tests/framework_aiohttp/conftest.py b/tests/framework_aiohttp/conftest.py index 3c2a783b24..108778b44b 100644 --- a/tests/framework_aiohttp/conftest.py +++ b/tests/framework_aiohttp/conftest.py @@ -115,7 +115,7 @@ def handler(self): def mock_external_http_server(): response_values = [] - def respond_with_cat_header(self): + def response_handler(self): headers, response_code = response_values.pop() self.send_response(response_code) for header, value in headers: @@ -123,7 +123,7 @@ def respond_with_cat_header(self): self.end_headers() self.wfile.write(b"") - with MockExternalHTTPServer(handler=respond_with_cat_header) as server: + with MockExternalHTTPServer(handler=response_handler) as server: yield (server, response_values) diff --git a/tests/framework_aiohttp/test_client.py b/tests/framework_aiohttp/test_client.py deleted file mode 100644 index 751ad4c965..0000000000 --- a/tests/framework_aiohttp/test_client.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import asyncio - -import aiohttp -import pytest -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics -from yarl import URL - -from newrelic.api.background_task import background_task -from newrelic.api.function_trace import function_trace - -version_info = tuple(int(_) for _ in aiohttp.__version__.split(".")[:2]) -skipif_aiohttp3 = pytest.mark.skipif( - version_info >= (3, 0), reason="This version of aiohttp does not support yield from syntax" -) - - -async def fetch(method, url): - with aiohttp.ClientSession() as session: - _method = getattr(session, method) - response = await asyncio.wait_for(_method(url), timeout=None) - response.raise_for_status() - await response.text() - - -@background_task(name="fetch_multiple") -async def fetch_multiple(method, url): - coros = [fetch(method, url) for _ in range(2)] - return asyncio.gather(*coros, return_exceptions=True) - - -if version_info < (2, 0): - _expected_error_class = aiohttp.errors.HttpProcessingError -else: - _expected_error_class = aiohttp.client_exceptions.ClientResponseError - - -def task(loop, method, exc_expected, url): - future = asyncio.ensure_future(fetch_multiple(method, url)) - text_list = loop.run_until_complete(future) - if exc_expected: - assert isinstance(text_list[0], _expected_error_class) - assert isinstance(text_list[1], _expected_error_class) - else: - assert text_list[0] == text_list[1] - - -test_matrix = ( - ("get", False), - ("post", True), - ("options", True), - ("head", True), - ("put", True), - ("patch", True), - ("delete", True), -) - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_client_yield_from(event_loop, local_server_info, method, exc_expected): - @validate_transaction_metrics( - "fetch_multiple", - background_task=True, - scoped_metrics=[(local_server_info.base_metric + method.upper(), 2)], - rollup_metrics=[(local_server_info.base_metric + method.upper(), 2)], - ) - def task_test(): - task(event_loop, method, exc_expected, local_server_info.url) - - task_test() - - -@skipif_aiohttp3 -def test_client_yarl_yield_from(event_loop, local_server_info): - method = "get" - - @validate_transaction_metrics( - "fetch_multiple", - background_task=True, - scoped_metrics=[(local_server_info.base_metric + method.upper(), 2)], - rollup_metrics=[(local_server_info.base_metric + method.upper(), 2)], - ) - def task_test(): - task(event_loop, method, False, URL(local_server_info.url)) - - task_test() - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_client_no_txn_yield_from(event_loop, local_server_info, method, exc_expected): - def task_test(): - task(event_loop, method, exc_expected, local_server_info.url) - - task_test() - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_client_throw_yield_from(event_loop, local_server_info, method, exc_expected): - class ThrowerException(ValueError): - pass - - @background_task(name="test_client_throw_yield_from") - async def self_driving_thrower(): - with aiohttp.ClientSession() as session: - coro = session._request(method.upper(), local_server_info.url) - - # activate the coroutine - coro.send(None) - - # inject error - coro.throw(ThrowerException()) - - @validate_transaction_metrics( - "test_client_throw_yield_from", - background_task=True, - scoped_metrics=[(local_server_info.base_metric + method.upper(), 1)], - rollup_metrics=[(local_server_info.base_metric + method.upper(), 1)], - ) - def task_test(): - with pytest.raises(ThrowerException): - event_loop.run_until_complete(self_driving_thrower()) - - task_test() - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_client_close_yield_from(event_loop, local_server_info, method, exc_expected): - @background_task(name="test_client_close_yield_from") - async def self_driving_closer(): - with aiohttp.ClientSession() as session: - coro = session._request(method.upper(), local_server_info.url) - - # activate the coroutine - coro.send(None) - - # force close - coro.close() - - @validate_transaction_metrics( - "test_client_close_yield_from", - background_task=True, - scoped_metrics=[(local_server_info.base_metric + method.upper(), 1)], - rollup_metrics=[(local_server_info.base_metric + method.upper(), 1)], - ) - def task_test(): - event_loop.run_until_complete(self_driving_closer()) - - task_test() - - -test_ws_matrix = ( - # the 127.0.0.1 server does not accept websocket requests, hence an - # exception is expected but a metric will still be created - ("ws_connect", True), -) - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_ws_matrix) -def test_ws_connect_yield_from(event_loop, local_server_info, method, exc_expected): - @validate_transaction_metrics( - "fetch_multiple", - background_task=True, - scoped_metrics=[(f"{local_server_info.base_metric}GET", 2)], - rollup_metrics=[(f"{local_server_info.base_metric}GET", 2)], - ) - def task_test(): - task(event_loop, method, exc_expected, local_server_info.url) - - task_test() - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_create_task_yield_from(event_loop, local_server_info, method, exc_expected): - # `loop.create_task` returns a Task object which uses the coroutine's - # `send` method, not `__next__` - - async def fetch_task(loop): - with aiohttp.ClientSession() as session: - coro = getattr(session, method) - resp = await loop.create_task(coro(local_server_info.url)) - resp.raise_for_status() - await resp.text() - - @background_task(name="test_create_task_yield_from") - async def fetch_multiple(loop): - coros = [fetch_task(loop) for _ in range(2)] - return asyncio.gather(*coros, return_exceptions=True) - - @validate_transaction_metrics( - "test_create_task_yield_from", - background_task=True, - scoped_metrics=[(local_server_info.base_metric + method.upper(), 2)], - rollup_metrics=[(local_server_info.base_metric + method.upper(), 2)], - ) - def task_test(): - result = event_loop.run_until_complete(fetch_multiple(event_loop)) - if exc_expected: - assert isinstance(result[0], _expected_error_class) - assert isinstance(result[1], _expected_error_class) - else: - assert result[0] == result[1] - - task_test() - - -@skipif_aiohttp3 -@pytest.mark.parametrize("method,exc_expected", test_matrix) -def test_terminal_node_yield_from(event_loop, local_server_info, method, exc_expected): - """ - This test injects a terminal node into a simple background task workflow. - It was added to validate a bug where our coro.send() wrapper would fail - when transaction's current node was terminal. - """ - - def task_test(): - @function_trace(terminal=True) - def execute_task(): - task(event_loop, method, exc_expected, local_server_info.url) - - execute_task() - - task_test() diff --git a/tests/framework_aiohttp/test_client_async_await.py b/tests/framework_aiohttp/test_client_async_await.py index 4ca83b9432..0de1e083e6 100644 --- a/tests/framework_aiohttp/test_client_async_await.py +++ b/tests/framework_aiohttp/test_client_async_await.py @@ -16,7 +16,6 @@ import aiohttp import pytest -from testing_support.fixtures import cat_enabled from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from yarl import URL @@ -52,7 +51,8 @@ def task(loop, method, exc_expected, url): assert isinstance(text_list[0], _expected_error_class), text_list[0].__class__ assert isinstance(text_list[1], _expected_error_class), text_list[1].__class__ else: - assert text_list[0] == text_list[1], text_list + assert text_list[0] + assert text_list[1] test_matrix = ( @@ -66,7 +66,6 @@ def task(loop, method, exc_expected, url): ) -@cat_enabled @pytest.mark.parametrize("method,exc_expected", test_matrix) def test_client_async_await(event_loop, local_server_info, method, exc_expected): @validate_transaction_metrics( @@ -81,7 +80,6 @@ def task_test(): task_test() -@cat_enabled def test_client_yarl_async_await(event_loop, local_server_info): method = "get" @@ -98,7 +96,6 @@ def task_test(): @pytest.mark.parametrize("method,exc_expected", test_matrix) -@cat_enabled def test_client_no_txn_async_await(event_loop, local_server_info, method, exc_expected): def task_test(): task(event_loop, method, exc_expected, local_server_info.url) @@ -107,7 +104,6 @@ def task_test(): @pytest.mark.parametrize("method,exc_expected", test_matrix) -@cat_enabled def test_await_request_async_await(event_loop, local_server_info, method, exc_expected): async def request_with_await(): async with aiohttp.ClientSession() as session: @@ -133,7 +129,8 @@ def task_test(): assert isinstance(text_list[0], _expected_error_class), text_list[0].__class__ assert isinstance(text_list[1], _expected_error_class), text_list[1].__class__ else: - assert text_list[0] == text_list[1], text_list + assert text_list[0] + assert text_list[1] task_test() @@ -160,7 +157,6 @@ def task_test(): @pytest.mark.parametrize("method,exc_expected", test_matrix) -@cat_enabled def test_create_task_async_await(event_loop, local_server_info, method, exc_expected): # `loop.create_task` returns a Task object which uses the coroutine's # `send` method, not `__next__` @@ -189,13 +185,13 @@ def task_test(): assert isinstance(result[0], _expected_error_class), result[0].__class__ assert isinstance(result[1], _expected_error_class), result[1].__class__ else: - assert result[0] == result[1] + assert result[0] + assert result[1] task_test() @pytest.mark.parametrize("method,exc_expected", test_matrix) -@cat_enabled def test_terminal_parent_async_await(event_loop, local_server_info, method, exc_expected): """ This test injects a terminal node into a simple background task workflow. diff --git a/tests/framework_aiohttp/test_client_cat.py b/tests/framework_aiohttp/test_client_cat.py deleted file mode 100644 index bbba2f88b9..0000000000 --- a/tests/framework_aiohttp/test_client_cat.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import asyncio - -import aiohttp -import pytest -from testing_support.external_fixtures import create_incoming_headers -from testing_support.fixtures import override_application_settings -from testing_support.validators.validate_cross_process_headers import validate_cross_process_headers -from testing_support.validators.validate_external_node_params import validate_external_node_params -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics - -from newrelic.api.background_task import background_task -from newrelic.api.external_trace import ExternalTrace -from newrelic.api.transaction import current_transaction - -version_info = tuple(int(_) for _ in aiohttp.__version__.split(".")[:2]) - -if version_info < (2, 0): - _expected_error_class = aiohttp.errors.HttpProcessingError -else: - _expected_error_class = aiohttp.client_exceptions.ClientResponseError - - -async def fetch(url, headers=None, raise_for_status=False, connector=None): - kwargs = {} - if version_info >= (2, 0): - kwargs = {"raise_for_status": raise_for_status} - - session = aiohttp.ClientSession(connector=connector, **kwargs) - request = session._request("GET", url, headers=headers) - headers = {} - - try: - response = await request - if raise_for_status and version_info < (2, 0): - response.raise_for_status() - except _expected_error_class: - return headers - - response_text = await response.text() - for header in response_text.split("\n"): - if not header: - continue - try: - h, v = header.split(":", 1) - except ValueError: - continue - headers[h.strip()] = v.strip() - f = session.close() - await asyncio.ensure_future(f) - return headers - - -@pytest.mark.parametrize("cat_enabled", (True, False)) -@pytest.mark.parametrize("distributed_tracing", (True, False)) -@pytest.mark.parametrize("span_events", (True, False)) -def test_outbound_cross_process_headers(event_loop, cat_enabled, distributed_tracing, span_events, mock_header_server): - @background_task(name="test_outbound_cross_process_headers") - async def _test(): - headers = await fetch(f"http://127.0.0.1:{mock_header_server.port}") - - transaction = current_transaction() - transaction._test_request_headers = headers - - if distributed_tracing: - assert "newrelic" in headers - elif cat_enabled: - assert ExternalTrace.cat_id_key in headers - assert ExternalTrace.cat_transaction_key in headers - else: - assert "newrelic" not in headers - assert ExternalTrace.cat_id_key not in headers - assert ExternalTrace.cat_transaction_key not in headers - - def _validate(): - pass - - if cat_enabled or distributed_tracing: - _validate = validate_cross_process_headers(_validate) - - _validate() - - @override_application_settings( - { - "cross_application_tracer.enabled": cat_enabled, - "distributed_tracing.enabled": distributed_tracing, - "span_events.enabled": span_events, - } - ) - def test(): - event_loop.run_until_complete(_test()) - - test() - - -_nr_key = ExternalTrace.cat_id_key -_customer_headers_tests = [{"Test-Header": "Test Data 1"}, {_nr_key.title(): "Test Data 2"}] - - -@pytest.mark.parametrize("customer_headers", _customer_headers_tests) -def test_outbound_cross_process_headers_custom_headers(event_loop, customer_headers, mock_header_server): - headers = event_loop.run_until_complete( - background_task()(fetch)(f"http://127.0.0.1:{mock_header_server.port}", customer_headers.copy()) - ) - - # always honor customer headers - for expected_header, expected_value in customer_headers.items(): - assert headers.get(expected_header) == expected_value - - -def test_outbound_cross_process_headers_no_txn(event_loop, mock_header_server): - headers = event_loop.run_until_complete(fetch(f"http://127.0.0.1:{mock_header_server.port}")) - - assert not headers.get(ExternalTrace.cat_id_key) - assert not headers.get(ExternalTrace.cat_transaction_key) - - -def test_outbound_cross_process_headers_exception(event_loop, mock_header_server): - @background_task(name="test_outbound_cross_process_headers_exception") - async def test(): - # corrupt the transaction object to force an error - transaction = current_transaction() - guid = transaction.guid - delattr(transaction, "guid") - - try: - headers = await fetch(f"http://127.0.0.1:{mock_header_server.port}") - - assert not headers.get(ExternalTrace.cat_id_key) - assert not headers.get(ExternalTrace.cat_transaction_key) - finally: - transaction.guid = guid - - event_loop.run_until_complete(test()) - - -class PoorResolvingConnector(aiohttp.TCPConnector): - async def _resolve_host(self, host, port, *args, **kwargs): - res = [{"hostname": host, "host": host, "port": 1234, "family": self._family, "proto": 0, "flags": 0}] - hosts = await super()._resolve_host(host, port, *args, **kwargs) - res.extend(hosts) - return res - - -@pytest.mark.parametrize("cat_enabled", [True, False]) -@pytest.mark.parametrize("response_code", [200, 404]) -@pytest.mark.parametrize("raise_for_status", [True, False]) -@pytest.mark.parametrize("connector_class", [None, PoorResolvingConnector]) # None will use default -def test_process_incoming_headers( - event_loop, cat_enabled, response_code, raise_for_status, connector_class, mock_external_http_server -): - # It was discovered via packnsend that the `throw` method of the `_request` - # coroutine is used in the case of poorly resolved hosts. An older version - # of the instrumentation ended the ExternalTrace anytime `throw` was called - # which meant that incoming CAT headers were never processed. The - # `PoorResolvingConnector` connector in this test ensures that `throw` is - # always called and thus makes sure the trace is not ended before - # StopIteration is called. - server, response_values = mock_external_http_server - address = f"http://127.0.0.1:{server.port}" - port = server.port - - _test_cross_process_response_scoped_metrics = [ - (f"ExternalTransaction/127.0.0.1:{port}/1#2/test", 1 if cat_enabled else None) - ] - - _test_cross_process_response_rollup_metrics = [ - ("External/all", 1), - ("External/allOther", 1), - (f"External/127.0.0.1:{port}/all", 1), - (f"ExternalApp/127.0.0.1:{port}/1#2/all", 1 if cat_enabled else None), - (f"ExternalTransaction/127.0.0.1:{port}/1#2/test", 1 if cat_enabled else None), - ] - - _test_cross_process_response_external_node_params = [ - ("cross_process_id", "1#2"), - ("external_txn_name", "test"), - ("transaction_guid", "0123456789012345"), - ] - - _test_cross_process_response_external_node_forgone_params = [ - k for k, v in _test_cross_process_response_external_node_params - ] - - @background_task(name="test_process_incoming_headers") - async def _test(): - transaction = current_transaction() - headers = create_incoming_headers(transaction) - - response_values.append((headers, response_code)) - - connector = connector_class() if connector_class else None - - await fetch(address, raise_for_status=raise_for_status, connector=connector) - - @override_application_settings( - {"cross_application_tracer.enabled": cat_enabled, "distributed_tracing.enabled": False} - ) - @validate_transaction_metrics( - "test_process_incoming_headers", - scoped_metrics=_test_cross_process_response_scoped_metrics, - rollup_metrics=_test_cross_process_response_rollup_metrics, - background_task=True, - ) - @validate_external_node_params( - params=(_test_cross_process_response_external_node_params if cat_enabled else []), - forgone_params=([] if cat_enabled else _test_cross_process_response_external_node_forgone_params), - ) - def test(): - event_loop.run_until_complete(_test()) - - test() diff --git a/tests/framework_aiohttp/test_server_cat.py b/tests/framework_aiohttp/test_server_cat.py deleted file mode 100644 index 5af4933ca3..0000000000 --- a/tests/framework_aiohttp/test_server_cat.py +++ /dev/null @@ -1,221 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json - -import pytest -from testing_support.fixtures import ( - make_cross_agent_headers, - override_application_settings, - validate_analytics_catmap_data, -) -from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes - -from newrelic.common.encoding_utils import deobfuscate -from newrelic.common.object_wrapper import transient_function_wrapper - -ENCODING_KEY = "1234567890123456789012345678901234567890" -test_uris = [ - ("/error?hello=world", "_target_application:error"), - ("/coro?hello=world", "_target_application:index"), - ("/class?hello=world", "_target_application:HelloWorldView._respond"), -] - - -def record_aiohttp1_raw_headers(raw_headers): - try: - import aiohttp.protocol - except ImportError: - - def pass_through(function): - return function - - return pass_through - - @transient_function_wrapper("aiohttp.protocol", "HttpParser.parse_headers") - def recorder(wrapped, instance, args, kwargs): - def _bind_params(lines): - return lines - - lines = _bind_params(*args, **kwargs) - for line in lines: - line = line.decode("utf-8") - - # This is the request, not the response - if line.startswith("GET"): - break - - if ":" in line: - key, value = line.split(":", maxsplit=1) - raw_headers[key.strip()] = value.strip() - - return wrapped(*args, **kwargs) - - return recorder - - -@pytest.mark.parametrize( - "inbound_payload,expected_intrinsics,forgone_intrinsics,cat_id", - [ - # Valid payload from trusted account - ( - ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"], - { - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.tripId": "7e249074f277923d", - "nr.referringPathHash": "5d2957be", - }, - [], - "1#1", - ), - # Valid payload from an untrusted account - ( - ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"], - {}, - ["nr.referringTransactionGuid", "nr.tripId", "nr.referringPathHash"], - "80#1", - ), - ], -) -@pytest.mark.parametrize("method", ["GET"]) -@pytest.mark.parametrize("uri,metric_name", test_uris) -def test_cat_headers( - method, uri, metric_name, inbound_payload, expected_intrinsics, forgone_intrinsics, cat_id, aiohttp_app -): - _raw_headers = {} - - async def fetch(): - headers = make_cross_agent_headers(inbound_payload, ENCODING_KEY, cat_id) - resp = await aiohttp_app.client.request(method, uri, headers=headers) - - if _raw_headers: - raw_headers = _raw_headers - else: - raw_headers = {k.decode("utf-8"): v.decode("utf-8") for k, v in resp.raw_headers} - - if expected_intrinsics: - # test valid CAT response header - assert "X-NewRelic-App-Data" in raw_headers - - app_data = json.loads(deobfuscate(raw_headers["X-NewRelic-App-Data"], ENCODING_KEY)) - assert app_data[0] == cat_id - assert app_data[1] == f"WebTransaction/Function/{metric_name}" - else: - assert "X-NewRelic-App-Data" not in resp.headers - - _custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": True, - "distributed_tracing.enabled": False, - } - - # NOTE: the logic-flow of this test can be a bit confusing. - # the override settings and attribute validation occur - # not when the request is made (above) since it does not - # occur inside a transaction. instead, the settings and - # validation are for the new transaction that is made - # asynchronously on the *server side* when the request - # is received and subsequently processed. that code is - # a fixture from conftest.py/_target_application.py - - @validate_analytics_catmap_data( - f"WebTransaction/Function/{metric_name}", - expected_attributes=expected_intrinsics, - non_expected_attributes=forgone_intrinsics, - ) - @override_application_settings(_custom_settings) - @record_aiohttp1_raw_headers(_raw_headers) - def _test(): - aiohttp_app.loop.run_until_complete(fetch()) - - _test() - - -account_id = "33" -primary_application_id = "2827902" - -inbound_payload = { - "v": [0, 1], - "d": { - "ac": account_id, - "ap": primary_application_id, - "id": "7d3efb1b173fecfa", - "tx": "e8b91a159289ff74", - "pr": 1.234567, - "sa": True, - "ti": 1518469636035, - "tr": "d6b4ba0c3a712ca", - "ty": "App", - }, -} - -expected_attributes = { - "agent": [], - "user": [], - "intrinsic": { - "traceId": "d6b4ba0c3a712ca", - "priority": 1.234567, - "sampled": True, - "parent.type": "App", - "parent.app": primary_application_id, - "parent.account": account_id, - "parent.transportType": "HTTP", - "parentId": "e8b91a159289ff74", - "parentSpanId": "7d3efb1b173fecfa", - }, -} - -unexpected_attributes = { - "agent": [], - "user": [], - "intrinsic": ["grandparentId", "cross_process_id", "nr.tripId", "nr.pathHash"], -} - - -@pytest.mark.parametrize("uri,metric_name", test_uris) -def test_distributed_tracing_headers(uri, metric_name, aiohttp_app): - async def fetch(): - headers = {"newrelic": json.dumps(inbound_payload)} - resp = await aiohttp_app.client.request("GET", uri, headers=headers) - - # better cat does not send a response in the headers - assert "newrelic" not in resp.headers - - # old-cat headers should not be in the response - assert "X-NewRelic-App-Data" not in resp.headers - - # NOTE: the logic-flow of this test can be a bit confusing. - # the override settings and attribute validation occur - # not when the request is made (above) since it does not - # occur inside a transaction. instead, the settings and - # validation are for the new transaction that is made - # asynchronously on the *server side* when the request - # is received and subsequently processed. that code is - # a fixture from conftest.py/_target_application.py - - @validate_transaction_event_attributes(expected_attributes, unexpected_attributes) - @override_application_settings( - { - "account_id": "33", - "trusted_account_key": "33", - "primary_application_id": primary_application_id, - "distributed_tracing.enabled": True, - } - ) - def _test(): - aiohttp_app.loop.run_until_complete(fetch()) - - _test() diff --git a/tests/framework_aiohttp/test_server_dt.py b/tests/framework_aiohttp/test_server_dt.py new file mode 100644 index 0000000000..0b9350d04c --- /dev/null +++ b/tests/framework_aiohttp/test_server_dt.py @@ -0,0 +1,92 @@ +# Copyright 2010 New Relic, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +import pytest +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes + +test_uris = [ + ("/error?hello=world", "_target_application:error"), + ("/coro?hello=world", "_target_application:index"), + ("/class?hello=world", "_target_application:HelloWorldView._respond"), +] + +account_id = "33" +primary_application_id = "2827902" + +inbound_payload = { + "v": [0, 1], + "d": { + "ac": account_id, + "ap": primary_application_id, + "id": "7d3efb1b173fecfa", + "tx": "e8b91a159289ff74", + "pr": 1.234567, + "sa": True, + "ti": 1518469636035, + "tr": "d6b4ba0c3a712ca", + "ty": "App", + }, +} + +expected_attributes = { + "agent": [], + "user": [], + "intrinsic": { + "traceId": "d6b4ba0c3a712ca", + "priority": 1.234567, + "sampled": True, + "parent.type": "App", + "parent.app": primary_application_id, + "parent.account": account_id, + "parent.transportType": "HTTP", + "parentId": "e8b91a159289ff74", + "parentSpanId": "7d3efb1b173fecfa", + }, +} + + +@pytest.mark.parametrize("uri,metric_name", test_uris) +def test_distributed_tracing_headers(uri, metric_name, aiohttp_app): + async def fetch(): + headers = {"newrelic": json.dumps(inbound_payload)} + resp = await aiohttp_app.client.request("GET", uri, headers=headers) + + # DT does not send a response in the headers + assert "newrelic" not in resp.headers + + # NOTE: the logic-flow of this test can be a bit confusing. + # the override settings and attribute validation occur + # not when the request is made (above) since it does not + # occur inside a transaction. instead, the settings and + # validation are for the new transaction that is made + # asynchronously on the *server side* when the request + # is received and subsequently processed. that code is + # a fixture from conftest.py/_target_application.py + + @validate_transaction_event_attributes(expected_attributes) + @override_application_settings( + { + "account_id": "33", + "trusted_account_key": "33", + "primary_application_id": primary_application_id, + "distributed_tracing.enabled": True, + } + ) + def _test(): + aiohttp_app.loop.run_until_complete(fetch()) + + _test() diff --git a/tests/framework_sanic/conftest.py b/tests/framework_sanic/conftest.py index 08c8bec3bb..f86a9cf10d 100644 --- a/tests/framework_sanic/conftest.py +++ b/tests/framework_sanic/conftest.py @@ -17,8 +17,6 @@ import pytest from testing_support.fixtures import collector_agent_registration_fixture, collector_available_fixture -from newrelic.common.object_wrapper import transient_function_wrapper - _default_settings = { "package_reporting.enabled": False, # Turn off package reporting for testing as it causes slow downs. "transaction_tracer.explain_threshold": 0.0, diff --git a/tests/framework_sanic/test_cross_application.py b/tests/framework_sanic/test_cross_application.py deleted file mode 100644 index a327166419..0000000000 --- a/tests/framework_sanic/test_cross_application.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import random - -# import re -import string - -import pytest -from testing_support.fixtures import ( - make_cross_agent_headers, - override_application_settings, - validate_analytics_catmap_data, -) -from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics - -from newrelic.api.application import application_instance -from newrelic.api.external_trace import ExternalTrace -from newrelic.api.transaction import Transaction -from newrelic.common.encoding_utils import deobfuscate - -BASE_METRICS = [("Function/_target_application:index", 1)] -DT_METRICS = [ - ("Supportability/DistributedTrace/AcceptPayload/Success", None), - ("Supportability/TraceContext/TraceParent/Accept/Success", 1), -] -BASE_ATTRS = ["response.status", "response.headers.contentType", "response.headers.contentLength"] - - -def raw_headers(response): - try: - # Manually encode into bytes - return " ".join(f"{k}: {v}" for k, v in response.processed_headers).encode() - except AttributeError: - try: - return response.get_headers() - except AttributeError: - return response.output() - - -@validate_transaction_metrics( - "_target_application:index", scoped_metrics=BASE_METRICS, rollup_metrics=BASE_METRICS + DT_METRICS -) -@override_application_settings({"distributed_tracing.enabled": True}) -@validate_transaction_event_attributes(required_params={"agent": BASE_ATTRS, "user": [], "intrinsic": []}) -def test_inbound_distributed_trace(app): - transaction = Transaction(application_instance()) - dt_headers = ExternalTrace.generate_request_headers(transaction) - - response = app.fetch("get", "/", headers=dict(dt_headers)) - assert response.status == 200 - - -ENCODING_KEY = "".join(random.choice(string.ascii_lowercase) for _ in range(40)) -_cat_response_header_urls_to_test = ( - ("/", "_target_application:index"), - ("/streaming", "_target_application:streaming"), - ("/error", "_target_application:error"), -) -_custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": True, - "distributed_tracing.enabled": False, -} - - -@pytest.mark.parametrize( - "inbound_payload,expected_intrinsics,forgone_intrinsics,cat_id", - [ - # Valid payload from trusted account - ( - ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"], - { - "nr.referringTransactionGuid": "b854df4feb2b1f06", - "nr.tripId": "7e249074f277923d", - "nr.referringPathHash": "5d2957be", - }, - [], - "1#1", - ), - # Valid payload from an untrusted account - ( - ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"], - {}, - ["nr.referringTransactionGuid", "nr.tripId", "nr.referringPathHash"], - "80#1", - ), - ], -) -@pytest.mark.parametrize("url,metric_name", _cat_response_header_urls_to_test) -def test_cat_response_headers(app, inbound_payload, expected_intrinsics, forgone_intrinsics, cat_id, url, metric_name): - _base_metrics = [(f"Function/{metric_name}", 1)] - - @validate_transaction_metrics(metric_name, scoped_metrics=_base_metrics, rollup_metrics=_base_metrics) - @validate_analytics_catmap_data( - f"WebTransaction/Function/{metric_name}", - expected_attributes=expected_intrinsics, - non_expected_attributes=forgone_intrinsics, - ) - @override_application_settings(_custom_settings) - def _test(): - cat_headers = make_cross_agent_headers(inbound_payload, ENCODING_KEY, cat_id) - response = app.fetch("get", url, headers=dict(cat_headers)) - if expected_intrinsics: - # test valid CAT response header - assert b"X-NewRelic-App-Data" in raw_headers(response) - cat_response_header = response.headers.get("X-NewRelic-App-Data", None) - - app_data = json.loads(deobfuscate(cat_response_header, ENCODING_KEY)) - assert app_data[0] == cat_id - assert app_data[1] == f"WebTransaction/Function/{metric_name}" - else: - assert b"X-NewRelic-App-Data" not in raw_headers(response) - - _test() - - -@override_application_settings(_custom_settings) -def test_cat_response_custom_header(app): - inbound_payload = ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"] - cat_id = "1#1" - custom_header_value = b"my-custom-header-value" - cat_headers = make_cross_agent_headers(inbound_payload, ENCODING_KEY, cat_id) - - response = app.fetch("get", f"/custom-header/X-NewRelic-App-Data/{custom_header_value}", headers=dict(cat_headers)) - assert custom_header_value in raw_headers(response), raw_headers(response) diff --git a/tests/framework_sanic/test_distributed_trace.py b/tests/framework_sanic/test_distributed_trace.py new file mode 100644 index 0000000000..d4f10abb72 --- /dev/null +++ b/tests/framework_sanic/test_distributed_trace.py @@ -0,0 +1,52 @@ +# Copyright 2010 New Relic, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes +from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics + +from newrelic.api.application import application_instance +from newrelic.api.external_trace import ExternalTrace +from newrelic.api.transaction import Transaction + +BASE_METRICS = [("Function/_target_application:index", 1)] +DT_METRICS = [ + ("Supportability/DistributedTrace/AcceptPayload/Success", None), + ("Supportability/TraceContext/TraceParent/Accept/Success", 1), +] +BASE_ATTRS = ["response.status", "response.headers.contentType", "response.headers.contentLength"] + + +def raw_headers(response): + try: + # Manually encode into bytes + return " ".join(f"{k}: {v}" for k, v in response.processed_headers).encode() + except AttributeError: + try: + return response.get_headers() + except AttributeError: + return response.output() + + +@validate_transaction_metrics( + "_target_application:index", scoped_metrics=BASE_METRICS, rollup_metrics=BASE_METRICS + DT_METRICS +) +@override_application_settings({"distributed_tracing.enabled": True}) +@validate_transaction_event_attributes(required_params={"agent": BASE_ATTRS, "user": [], "intrinsic": []}) +def test_inbound_distributed_trace(app): + transaction = Transaction(application_instance()) + dt_headers = ExternalTrace.generate_request_headers(transaction) + + response = app.fetch("get", "/", headers=dict(dt_headers)) + assert response.status == 200 diff --git a/tests/framework_tornado/_target_application.py b/tests/framework_tornado/_target_application.py index 2570b72d0e..49383b216b 100644 --- a/tests/framework_tornado/_target_application.py +++ b/tests/framework_tornado/_target_application.py @@ -15,7 +15,6 @@ import time import tornado.gen -import tornado.httpclient import tornado.httputil import tornado.ioloop import tornado.web @@ -35,35 +34,6 @@ def get_status(self, *args, **kwargs): raise ValueError("Bad Status") -class ProcessCatHeadersHandler(tornado.web.RequestHandler): - def __init__(self, application, request, response_code=200, **kwargs): - super().__init__(application, request, **kwargs) - self.response_code = response_code - - def get(self, client_cross_process_id, txn_header, flush=None): - import newrelic.api.transaction as _transaction - - txn = _transaction.current_transaction() - if txn: - txn._process_incoming_cat_headers(client_cross_process_id, txn_header) - - if self.response_code != 200: - self.set_status(self.response_code) - return - - self.write("Hello, world") - - if flush == "flush": - # Force a flush prior to calling finish - # This causes the headers to get written immediately. The tests - # which hit this endpoint will check that the response has been - # properly processed even though we send the headers here. - self.flush() - - # change the headers to garbage - self.set_header("Content-Type", "garbage") - - class EchoHeaderHandler(tornado.web.RequestHandler): def get(self): response = str(self.request.headers.__dict__).encode("utf-8") @@ -250,8 +220,6 @@ def make_app(custom=False): (r"/init", InitializeHandler), (r"/html-insertion", HTMLInsertionHandler), (r"/bad-get-status", BadGetStatusHandler), - (r"/force-cat-response/(\S+)/(\S+)/(\S+)", ProcessCatHeadersHandler), - (r"/304-cat-response/(\S+)/(\S+)", ProcessCatHeadersHandler, {"response_code": 304}), (r"/echo-headers", EchoHeaderHandler), (r"/native-simple", NativeSimpleHandler), (r"/multi-trace", MultiTraceHandler), diff --git a/tests/framework_tornado/test_externals.py b/tests/framework_tornado/test_externals.py index fd40b9423f..e872b3bdfc 100644 --- a/tests/framework_tornado/test_externals.py +++ b/tests/framework_tornado/test_externals.py @@ -13,21 +13,15 @@ # limitations under the License. import io -import socket import sys import pytest from testing_support.fixtures import override_application_settings -from testing_support.mock_external_http_server import MockExternalHTTPHResponseHeadersServer, MockExternalHTTPServer -from testing_support.validators.validate_distributed_tracing_header import validate_distributed_tracing_header -from testing_support.validators.validate_outbound_headers import validate_outbound_headers +from testing_support.mock_external_http_server import MockExternalHTTPHResponseHeadersServer from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics from newrelic.api.background_task import background_task from newrelic.api.function_trace import FunctionTrace -from newrelic.api.transaction import current_transaction - -ENCODING_KEY = "1234567890123456789012345678901234567890" is_pypy = hasattr(sys, "pypy_version_info") @@ -123,46 +117,15 @@ def _make_request(): ("HTTPClient", True), ], ) -@pytest.mark.parametrize( - "cat_enabled,user_header,span_events,distributed_tracing", - [ - (True, None, False, False), - (True, "X-NewRelic-ID", False, False), - (True, "X-NewRelic-Transaction", False, False), - (False, None, True, True), - (False, None, False, True), - ], -) -# @pytest.mark.parametrize('cat_enabled,user_header', [ -# (True, None), -# (True, 'X-NewRelic-ID'), -# (True, 'X-NewRelic-Transaction'), -# (False, None), -# ]) +@pytest.mark.parametrize("span_events", [True, False]) @pytest.mark.parametrize("request_type", ["uri", "class"]) @pytest.mark.parametrize("num_requests", [1, 2]) -def test_httpclient( - cat_enabled, - request_type, - client_class, - user_header, - num_requests, - distributed_tracing, - span_events, - external, - as_kwargs, -): +def test_httpclient(request_type, client_class, num_requests, span_events, external, as_kwargs): port = external.port expected_metrics = [(f"External/localhost:{port}/tornado/GET", num_requests)] - @override_application_settings( - { - "distributed_tracing.enabled": distributed_tracing, - "span_events.enabled": span_events, - "cross_application_tracer.enabled": not distributed_tracing, - } - ) + @override_application_settings({"distributed_tracing.enabled": True, "span_events.enabled": span_events}) @validate_transaction_metrics( "test_externals:test_httpclient", background_task=True, @@ -172,8 +135,6 @@ def test_httpclient( @background_task(name="test_externals:test_httpclient") def _test(): headers = {} - if user_header: - headers = {user_header: "USER"} response = make_request( port, request_type, client_class, headers=headers, count=num_requests, as_kwargs=as_kwargs @@ -193,97 +154,6 @@ def _test(): header_val = header_val.strip() headers[header_key] = header_val - # User headers override all inserted NR headers - if user_header: - assert headers[user_header] == "USER" - elif cat_enabled: - t = current_transaction() - assert t - t._test_request_headers = headers - - if distributed_tracing: - validate_distributed_tracing_header(header="Newrelic") - else: - validate_outbound_headers() - else: - # new relic shouldn't add anything to the outgoing - assert "x-newrelic" not in body, body - - assert "X-NewRelic-App-Data" not in headers - - _test() - - -CAT_RESPONSE_CODE = None - - -def cat_response_handler(self): - # payload - # ( - # u'1#1', u'WebTransaction/Function/app:beep', - # 0, 1.23, -1, - # 'dd4a810b7cb7f937', - # False, - # ) - cat_response_header = ( - "X-NewRelic-App-Data", - "ahACFwQUGxpuVVNmQVVbRVZbTVleXBxyQFhUTFBfXx1SREUMVV1cQBMeAxgEGAULFR0AHhFQUQJWAAgAUwVQVgJQDgsOEh1UUlhGU2o=", - ) - self.send_response(CAT_RESPONSE_CODE) - self.send_header(*cat_response_header) - self.end_headers() - self.wfile.write(b"Example Data") - - -@pytest.fixture(scope="module") -def cat_response_server(): - external = MockExternalHTTPServer(handler=cat_response_handler) - with external: - yield external - - -@pytest.mark.parametrize("client_class", ["AsyncHTTPClient", "CurlAsyncHTTPClient", "HTTPClient"]) -@pytest.mark.parametrize("cat_enabled", [True, False]) -@pytest.mark.parametrize("request_type", ["uri", "class"]) -@pytest.mark.parametrize("response_code,raise_error", [(500, True), (500, False), (200, False)]) -def test_client_cat_response_processing( - cat_enabled, request_type, client_class, raise_error, response_code, cat_response_server -): - global CAT_RESPONSE_CODE - CAT_RESPONSE_CODE = response_code - - _custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": cat_enabled, - "distributed_tracing.enabled": not cat_enabled, - "transaction_tracer.transaction_threshold": 0.0, - } - - port = cat_response_server.port - expected_metrics = [ - (f"ExternalTransaction/localhost:{port}/1#1/WebTransaction/Function/app:beep", 1 if cat_enabled else None) - ] - - @validate_transaction_metrics( - "make_request", background_task=True, rollup_metrics=expected_metrics, scoped_metrics=expected_metrics - ) - @override_application_settings(_custom_settings) - def _test(): - import tornado - import tornado.httpclient - - try: - response = make_request(port, request_type, client_class, raise_error=raise_error) - except tornado.httpclient.HTTPError as e: - assert raise_error - response = e.response - else: - assert not raise_error - - assert response.code == response_code - _test() diff --git a/tests/framework_tornado/test_inbound_cat.py b/tests/framework_tornado/test_inbound_cat.py deleted file mode 100644 index a0773dcb5d..0000000000 --- a/tests/framework_tornado/test_inbound_cat.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json - -import pytest -from testing_support.fixtures import make_cross_agent_headers, override_application_settings -from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics - -ENCODING_KEY = "1234567890123456789012345678901234567890" - - -_custom_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "cross_application_tracer.enabled": True, - "distributed_tracing.enabled": False, - "transaction_tracer.transaction_threshold": 0.0, -} - - -@override_application_settings(_custom_settings) -@validate_transaction_event_attributes( - required_params={"agent": (), "user": (), "intrinsic": ()}, - forgone_params={"agent": (), "user": (), "intrinsic": ()}, - exact_attrs={ - "agent": {"response.status": "200", "response.headers.contentType": "text/html; charset=UTF-8"}, - "user": {}, - "intrinsic": {}, - }, -) -@pytest.mark.parametrize("manual_flush", ["flush", "no-flush"]) -def test_response_to_inbound_cat(app, manual_flush): - payload = ("1#1", "WebTransaction/Function/app:beep", 0, 1.23, -1, "dd4a810b7cb7f937", False) - headers = make_cross_agent_headers(payload, ENCODING_KEY, "1#1") - - client_cross_process_id = headers["X-NewRelic-ID"] - txn_header = headers["X-NewRelic-Transaction"] - - response = app.fetch(f"/force-cat-response/{client_cross_process_id}/{txn_header}/{manual_flush}") - assert response.code == 200 - assert "X-NewRelic-App-Data" in list(response.headers.keys()) - - -@validate_transaction_event_attributes( - required_params={"agent": (), "user": (), "intrinsic": ()}, - forgone_params={"agent": ("response.headers",), "user": (), "intrinsic": ()}, - exact_attrs={"agent": {"request.method": "GET", "response.status": "304"}, "user": {}, "intrinsic": {}}, -) -@override_application_settings(_custom_settings) -def test_cat_headers_not_inserted(app): - payload = ("1#1", "WebTransaction/Function/app:beep", 0, 1.23, -1, "dd4a810b7cb7f937", False) - headers = make_cross_agent_headers(payload, ENCODING_KEY, "1#1") - - client_cross_process_id = headers["X-NewRelic-ID"] - txn_header = headers["X-NewRelic-Transaction"] - - response = app.fetch(f"/304-cat-response/{client_cross_process_id}/{txn_header}") - assert response.code == 304 - assert "X-NewRelic-App-Data" not in list(response.headers.keys()) - - -@override_application_settings(_custom_settings) -@validate_transaction_metrics( - "_target_application:SimpleHandler.get", rollup_metrics=[("ClientApplication/1#1/all", 1)] -) -@validate_transaction_event_attributes( - required_params={"agent": [], "user": [], "intrinsic": []}, - forgone_params={"agent": [], "user": [], "intrinsic": []}, - exact_attrs={"agent": {}, "user": {}, "intrinsic": {"nr.referringTransactionGuid": "b854df4feb2b1f06"}}, -) -def test_inbound_cat_metrics_and_intrinsics(app): - payload = ["b854df4feb2b1f06", False, "7e249074f277923d", "5d2957be"] - headers = make_cross_agent_headers(payload, ENCODING_KEY, "1#1") - - response = app.fetch("/simple", headers=headers) - assert response.code == 200 - - -@override_application_settings( - {"account_id": 1, "trusted_account_key": 1, "primary_application_id": 1, "distributed_tracing.enabled": True} -) -@validate_transaction_metrics( - "_target_application:SimpleHandler.get", - rollup_metrics=(("Supportability/DistributedTrace/AcceptPayload/Success", 1),), -) -def test_inbound_dt(app): - PAYLOAD = { - "v": [0, 1], - "d": { - "ac": 1, - "ap": 1, - "id": "7d3efb1b173fecfa", - "tx": "e8b91a159289ff74", - "pr": 1.234567, - "sa": True, - "ti": 1518469636035, - "tr": "d6b4ba0c3a712ca", - "ty": "App", - }, - } - headers = {"newrelic": json.dumps(PAYLOAD)} - response = app.fetch("/simple", headers=headers) - assert response.code == 200 diff --git a/tests/framework_tornado/test_inbound_dt.py b/tests/framework_tornado/test_inbound_dt.py new file mode 100644 index 0000000000..f8358338c6 --- /dev/null +++ b/tests/framework_tornado/test_inbound_dt.py @@ -0,0 +1,55 @@ +# Copyright 2010 New Relic, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +from testing_support.fixtures import override_application_settings +from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes +from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics + + +@validate_transaction_event_attributes( + required_params={"agent": (), "user": (), "intrinsic": ()}, + forgone_params={"agent": (), "user": (), "intrinsic": ()}, + exact_attrs={ + "agent": {"response.status": "200", "response.headers.contentType": "text/html; charset=UTF-8"}, + "user": {}, + "intrinsic": {}, + }, +) +@override_application_settings( + {"account_id": 1, "trusted_account_key": 1, "primary_application_id": 1, "distributed_tracing.enabled": True} +) +@validate_transaction_metrics( + "_target_application:SimpleHandler.get", + rollup_metrics=(("Supportability/DistributedTrace/AcceptPayload/Success", 1),), +) +def test_inbound_dt(app): + PAYLOAD = { + "v": [0, 1], + "d": { + "ac": 1, + "ap": 1, + "id": "7d3efb1b173fecfa", + "tx": "e8b91a159289ff74", + "pr": 1.234567, + "sa": True, + "ti": 1518469636035, + "tr": "d6b4ba0c3a712ca", + "ty": "App", + }, + } + headers = {"newrelic": json.dumps(PAYLOAD)} + response = app.fetch("/simple", headers=headers) + assert response.code == 200 diff --git a/tests/messagebroker_pika/test_cat.py b/tests/messagebroker_pika/test_cat.py deleted file mode 100644 index 295d988aa3..0000000000 --- a/tests/messagebroker_pika/test_cat.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import random -import string - -import pika -from compat import basic_consume -from testing_support.db_settings import rabbitmq_settings -from testing_support.fixtures import cat_enabled, override_application_settings -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics - -from newrelic.api.background_task import background_task -from newrelic.api.transaction import current_transaction - -DB_SETTINGS = rabbitmq_settings()[0] - -ENCODING_KEY = "".join(random.choice(string.ascii_lowercase) for _ in range(40)) -_override_settings = { - "cross_process_id": "1#1", - "encoding_key": ENCODING_KEY, - "trusted_account_ids": [1], - "browser_monitoring.enabled": False, -} - - -@background_task() -def do_basic_publish(channel, QUEUE, properties=None): - channel.basic_publish(exchange="", routing_key=QUEUE, body="Testing CAT 123", properties=properties) - - -_test_cat_basic_consume_scoped_metrics = [ - ("MessageBroker/RabbitMQ/Exchange/Produce/Named/Default", None), - ("MessageBroker/RabbitMQ/Exchange/Consume/Named/Default", None), -] -_test_cat_basic_consume_rollup_metrics = list(_test_cat_basic_consume_scoped_metrics) -_test_cat_basic_consume_rollup_metrics.append(("ClientApplication/1#1/all", 1)) - - -@validate_transaction_metrics( - "test_cat:test_basic_consume_cat_headers.