Skip to content

Commit 71c4634

Browse files
authored
[kong] strengthen tests to lift mutation score (DataDog#24334)
1 parent dca97e8 commit 71c4634

1 file changed

Lines changed: 122 additions & 1 deletion

File tree

kong/tests/test_unit.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
# (C) Datadog, Inc. 2021-present
22
# All rights reserved
33
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
import json
45
import os
6+
from collections import namedtuple
57

68
import pytest
79

810
from datadog_checks.dev.utils import get_metadata_metrics
911
from datadog_checks.kong import Kong
12+
from datadog_checks.kong.check import KongCheck
1013

11-
from .common import HERE, METRICS_URL
14+
from .common import HERE, METRICS_URL, STATUS_URL
1215

1316
pytestmark = [pytest.mark.unit]
1417

18+
FakeSample = namedtuple('FakeSample', ['value', 'labels'])
19+
1520
EXPECTED_METRICS = {
1621
'kong.bandwidth.count': 'monotonic_count',
1722
'kong.http.consumer.status.count': 'monotonic_count',
@@ -115,3 +120,119 @@ def test_check(aggregator, dd_run_check, mock_http_response):
115120
tags=['address:localhost:1004', 'endpoint:{}'.format(METRICS_URL), 'target:target4', 'upstream:upstream4'],
116121
count=1,
117122
)
123+
124+
125+
def test_v2_default_metric_limit_is_zero():
126+
# Kills the core/NumberReplacer mutant at check.py:12 (DEFAULT_METRIC_LIMIT 0 -> -1).
127+
assert KongCheck.DEFAULT_METRIC_LIMIT == 0
128+
129+
130+
def test_v2_transformer_only_processes_sample_with_value_exactly_one(aggregator):
131+
# Kills the core/ReplaceComparisonOperator_NotEq_Lt mutant at check.py:28 (sample.value != 1 -> < 1).
132+
check = KongCheck('kong', {}, [{'openmetrics_endpoint': METRICS_URL}])
133+
service_check = check.configure_transformer_upstream_target_health()
134+
135+
sample = FakeSample(value=2, labels={'state': 'healthy'})
136+
service_check(None, [(sample, ['state:healthy'], 'host1')], None)
137+
138+
assert len(aggregator.service_checks('kong.upstream.target.health')) == 0
139+
140+
141+
def test_v2_transformer_processes_samples_after_skipping_one(aggregator):
142+
# Kills the core/ReplaceContinueWithBreak mutant at check.py:29 (continue -> break drops later samples).
143+
check = KongCheck('kong', {}, [{'openmetrics_endpoint': METRICS_URL}])
144+
service_check = check.configure_transformer_upstream_target_health()
145+
146+
sample_data = [
147+
(FakeSample(value=2, labels={'state': 'irrelevant'}), ['state:irrelevant'], 'host1'),
148+
(FakeSample(value=1, labels={'state': 'healthy'}), ['state:healthy'], 'host2'),
149+
]
150+
service_check(None, sample_data, None)
151+
152+
aggregator.assert_service_check(
153+
'kong.upstream.target.health', status=KongCheck.OK, tags=[], hostname='host2', count=1
154+
)
155+
156+
157+
def test_legacy_new_uses_first_instance_to_choose_check_class():
158+
# Kills the core/NumberReplacer mutant at kong.py:25 (instances[0] -> instances[-1]).
159+
check = Kong('kong', {}, [{'openmetrics_endpoint': METRICS_URL}, {'kong_status_url': STATUS_URL}])
160+
assert isinstance(check, KongCheck)
161+
162+
163+
def test_legacy_fetch_data_raises_when_status_url_missing():
164+
# Kills the core/AddNot mutant at kong.py:42 (double negation flips the missing-config check).
165+
check = Kong('kong', {}, [{'tags': []}])
166+
with pytest.raises(Exception, match='missing "kong_status_url" value'):
167+
check._fetch_data()
168+
169+
170+
def test_legacy_fetch_data_can_connect_tags_use_default_port_and_appended_tags(
171+
aggregator, dd_run_check, mock_http_response
172+
):
173+
# Kills the core/NumberReplacer and ReplaceOrWithAnd mutants at kong.py:49 (default port 80 -> 79/81 or "or"->"and")
174+
# and the ReplaceBinaryOperator_Add_* / ReplaceBinaryOperator_Mod_* mutants at kong.py:51
175+
# (tag list "+" and the "%" string formatting inside it).
176+
mock_http_response(json_data={'server': {}})
177+
instance = {'kong_status_url': 'http://myhost/status/', 'tags': ['env:test']}
178+
check = Kong('kong', {}, [instance])
179+
dd_run_check(check)
180+
181+
aggregator.assert_service_check(
182+
'kong.can_connect', status=Kong.OK, tags=['kong_host:myhost', 'kong_port:80', 'env:test'], count=1
183+
)
184+
185+
186+
def test_legacy_parse_json_defaults_tags_and_prefixes_metric_names():
187+
# Kills the core/ReplaceComparisonOperator_Is_IsNot and AddNot mutants at kong.py:70 (tags is None check),
188+
# the ZeroIterationForLoop mutant at kong.py:76, and the ReplaceBinaryOperator_Add_* mutants at kong.py:77.
189+
check = Kong('kong', {}, [{'kong_status_url': 'http://myhost/status/'}])
190+
raw = json.dumps({'server': {'total_requests': 42}}).encode('utf-8')
191+
192+
output = check._parse_json(raw)
193+
194+
assert output == [('kong.total_requests', 42, [])]
195+
196+
197+
def test_legacy_check_continues_after_metric_submission_error(aggregator, dd_run_check, mock_http_response):
198+
# Kills the core/ZeroIterationForLoop mutant at kong.py:34 and the ExceptionReplacer mutant at kong.py:38
199+
# (a bad metric value must not stop later metrics in the loop from being submitted).
200+
mock_http_response(json_data={'server': {'bad_metric': 'oops', 'good_metric': 5}})
201+
instance = {'kong_status_url': 'http://myhost/status/', 'tags': []}
202+
check = Kong('kong', {}, [instance])
203+
dd_run_check(check)
204+
205+
aggregator.assert_metric('kong.good_metric', value=5, count=1)
206+
aggregator.assert_metric('kong.bad_metric', count=0)
207+
208+
209+
def test_legacy_check_submits_critical_service_check_on_http_error(aggregator, mock_http_response):
210+
# Kills the core/ExceptionReplacer mutant at kong.py:58 (except Exception -> except CosmicRayTestingException).
211+
mock_http_response(status_code=500)
212+
instance = {'kong_status_url': 'http://myhost/status/', 'tags': []}
213+
check = Kong('kong', {}, [instance])
214+
215+
with pytest.raises(Exception):
216+
check.check(None)
217+
218+
aggregator.assert_service_check('kong.can_connect', status=Kong.CRITICAL, count=1)
219+
220+
221+
def test_legacy_check_treats_status_code_below_200_as_critical(aggregator, mock_http_response):
222+
# Kills the core/ReplaceComparisonOperator_Eq_LtE mutant at kong.py:62 (status_code == 200 -> <= 200).
223+
mock_http_response(status_code=100, json_data={'server': {}})
224+
instance = {'kong_status_url': 'http://myhost/status/', 'tags': []}
225+
check = Kong('kong', {}, [instance])
226+
check.check(None)
227+
228+
aggregator.assert_service_check('kong.can_connect', status=Kong.CRITICAL, count=1)
229+
230+
231+
def test_legacy_check_treats_status_code_above_200_as_critical(aggregator, mock_http_response):
232+
# Kills the core/ReplaceComparisonOperator_Eq_GtE mutant at kong.py:62 (status_code == 200 -> >= 200).
233+
mock_http_response(status_code=204, json_data={'server': {}})
234+
instance = {'kong_status_url': 'http://myhost/status/', 'tags': []}
235+
check = Kong('kong', {}, [instance])
236+
check.check(None)
237+
238+
aggregator.assert_service_check('kong.can_connect', status=Kong.CRITICAL, count=1)

0 commit comments

Comments
 (0)