Skip to content

Commit f1a673e

Browse files
TimPansinolrafeeihmstepanekumaannamalaimergify[bot]
authored
Fix Normalization Rules (#894)
* Fix cross agent tests to run from anywhere * Cover failures in rules engine with testing Co-authored-by: Lalleh Rafeei <[email protected]> Co-authored-by: Hannah Stepanek <[email protected]> Co-authored-by: Uma Annamalai <[email protected]> * Patch metrics not being properly ignored * Patch normalization rule init default arguments * Clean up to match other fixture setups --------- Co-authored-by: Lalleh Rafeei <[email protected]> Co-authored-by: Hannah Stepanek <[email protected]> Co-authored-by: Uma Annamalai <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 7d76243 commit f1a673e

8 files changed

+89
-16
lines changed

newrelic/core/rules_engine.py

+21
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@
2222

2323

2424
class NormalizationRule(_NormalizationRule):
25+
def __new__(
26+
cls,
27+
match_expression="",
28+
replacement="",
29+
ignore=False,
30+
eval_order=0,
31+
terminate_chain=False,
32+
each_segment=False,
33+
replace_all=False,
34+
):
35+
return _NormalizationRule.__new__(
36+
cls,
37+
match_expression=match_expression,
38+
replacement=replacement,
39+
ignore=ignore,
40+
eval_order=eval_order,
41+
terminate_chain=terminate_chain,
42+
each_segment=each_segment,
43+
replace_all=replace_all,
44+
)
45+
2546
def __init__(self, *args, **kwargs):
2647
self.match_expression_re = re.compile(self.match_expression, re.IGNORECASE)
2748

newrelic/core/stats_engine.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,11 @@ def metric_data(self, normalizer=None):
11291129

11301130
if normalizer is not None:
11311131
for key, value in six.iteritems(self.__stats_table):
1132-
key = (normalizer(key[0])[0], key[1])
1132+
normalized_name, ignored = normalizer(key[0])
1133+
if ignored:
1134+
continue
1135+
1136+
key = (normalized_name, key[1])
11331137
stats = normalized_stats.get(key)
11341138
if stats is None:
11351139
normalized_stats[key] = copy.copy(value)

tests/cross_agent/test_agent_attributes.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ def _default_settings():
4040
'browser_monitoring.attributes.exclude': [],
4141
}
4242

43-
FIXTURE = os.path.join(os.curdir, 'fixtures', 'attribute_configuration.json')
43+
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
44+
FIXTURE = os.path.join(CURRENT_DIR, 'fixtures', 'attribute_configuration.json')
4445

4546
def _load_tests():
4647
with open(FIXTURE, 'r') as fh:

tests/cross_agent/test_datstore_instance.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
from newrelic.core.database_node import DatabaseNode
2424
from newrelic.core.stats_engine import StatsEngine
2525

26-
FIXTURE = os.path.join(os.curdir,
26+
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
27+
FIXTURE = os.path.join(CURRENT_DIR,
2728
'fixtures', 'datastores', 'datastore_instances.json')
2829

2930
_parameters_list = ['name', 'system_hostname', 'db_hostname',

tests/cross_agent/test_docker.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
import newrelic.common.utilization as u
2121

22-
DOCKER_FIXTURE = os.path.join(os.curdir, 'fixtures', 'docker_container_id')
22+
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
23+
DOCKER_FIXTURE = os.path.join(CURRENT_DIR, 'fixtures', 'docker_container_id')
2324

2425

2526
def _load_docker_test_attributes():

tests/cross_agent/test_labels_and_rollups.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222
from testing_support.fixtures import override_application_settings
2323

24-
FIXTURE = os.path.join(os.curdir, 'fixtures', 'labels.json')
24+
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
25+
FIXTURE = os.path.join(CURRENT_DIR, 'fixtures', 'labels.json')
2526

2627
def _load_tests():
2728
with open(FIXTURE, 'r') as fh:

tests/cross_agent/test_rules.py

+52-9
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@
1616
import os
1717
import pytest
1818

19-
from newrelic.core.rules_engine import RulesEngine, NormalizationRule
19+
from newrelic.api.application import application_instance
20+
from newrelic.api.background_task import background_task
21+
from newrelic.api.transaction import record_custom_metric
22+
from newrelic.core.rules_engine import RulesEngine
23+
24+
from testing_support.validators.validate_metric_payload import validate_metric_payload
2025

2126
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
2227
FIXTURE = os.path.normpath(os.path.join(
2328
CURRENT_DIR, 'fixtures', 'rules.json'))
2429

30+
2531
def _load_tests():
2632
with open(FIXTURE, 'r') as fh:
2733
js = fh.read()
2834
return json.loads(js)
2935

30-
def _prepare_rules(test_rules):
31-
# ensure all keys are present, if not present set to an empty string
32-
for rule in test_rules:
33-
for key in NormalizationRule._fields:
34-
rule[key] = rule.get(key, '')
35-
return test_rules
3636

3737
def _make_case_insensitive(rules):
3838
# lowercase each rule
@@ -42,14 +42,14 @@ def _make_case_insensitive(rules):
4242
rule['replacement'] = rule['replacement'].lower()
4343
return rules
4444

45+
4546
@pytest.mark.parametrize('test_group', _load_tests())
4647
def test_rules_engine(test_group):
4748

4849
# FIXME: The test fixture assumes that matching is case insensitive when it
4950
# is not. To avoid errors, just lowercase all rules, inputs, and expected
5051
# values.
51-
insense_rules = _make_case_insensitive(test_group['rules'])
52-
test_rules = _prepare_rules(insense_rules)
52+
test_rules = _make_case_insensitive(test_group['rules'])
5353
rules_engine = RulesEngine(test_rules)
5454

5555
for test in test_group['tests']:
@@ -66,3 +66,46 @@ def test_rules_engine(test_group):
6666
assert expected == ''
6767
else:
6868
assert result == expected
69+
70+
71+
@pytest.mark.parametrize('test_group', _load_tests())
72+
def test_rules_engine_metric_harvest(test_group):
73+
# FIXME: The test fixture assumes that matching is case insensitive when it
74+
# is not. To avoid errors, just lowercase all rules, inputs, and expected
75+
# values.
76+
test_rules = _make_case_insensitive(test_group['rules'])
77+
rules_engine = RulesEngine(test_rules)
78+
79+
# Set rules engine on core application
80+
api_application = application_instance(activate=False)
81+
api_name = api_application.name
82+
core_application = api_application._agent.application(api_name)
83+
old_rules = core_application._rules_engine["metric"] # save previoius rules
84+
core_application._rules_engine["metric"] = rules_engine
85+
86+
def send_metrics():
87+
# Send all metrics in this test batch in one transaction, then harvest so the normalizer is run.
88+
@background_task(name="send_metrics")
89+
def _test():
90+
for test in test_group['tests']:
91+
# lowercase each value
92+
input_str = test['input'].lower()
93+
record_custom_metric(input_str, {"count": 1})
94+
_test()
95+
core_application.harvest()
96+
97+
try:
98+
# Create a map of all result metrics to validate after harvest
99+
test_metrics = []
100+
for test in test_group['tests']:
101+
expected = (test['expected'] or '').lower()
102+
if expected == '': # Ignored
103+
test_metrics.append((expected, None))
104+
else:
105+
test_metrics.append((expected, 1))
106+
107+
# Harvest and validate resulting payload
108+
validate_metric_payload(metrics=test_metrics)(send_metrics)()
109+
finally:
110+
# Replace original rules engine
111+
core_application._rules_engine["metric"] = old_rules

tests/cross_agent/test_rum_client_config.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@
2626
)
2727
from newrelic.api.wsgi_application import wsgi_application
2828

29+
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
30+
FIXTURE = os.path.join(CURRENT_DIR, "fixtures", "rum_client_config.json")
2931

3032
def _load_tests():
31-
fixture = os.path.join(os.curdir, "fixtures", "rum_client_config.json")
32-
with open(fixture, "r") as fh:
33+
with open(FIXTURE, "r") as fh:
3334
js = fh.read()
3435
return json.loads(js)
3536

0 commit comments

Comments
 (0)