|
1 | 1 | # (c) Copyright IBM Corp. 2025 |
2 | 2 |
|
3 | | -from instana.util.span_utils import matches_rule, match_key_filter, get_span_kind |
| 3 | +from collections import defaultdict |
| 4 | + |
| 5 | +from instana.util.span_utils import ( |
| 6 | + get_span_kind, |
| 7 | + match_key_filter, |
| 8 | + matches_rule, |
| 9 | + resolve_nested_key, |
| 10 | +) |
4 | 11 |
|
5 | 12 |
|
6 | 13 | class TestSpanUtils: |
@@ -144,3 +151,92 @@ def test_matches_rule_with_none_attribute_value(self) -> None: |
144 | 151 | {"key": "http.method", "values": ["GET"], "match_type": "strict"} |
145 | 152 | ] |
146 | 153 | assert matches_rule(rule_method, span_attrs) |
| 154 | + |
| 155 | + def test_resolve_nested_key_embedded_dot_keys(self) -> None: |
| 156 | + """Resolves sdk.custom.tags.http.host through a defaultdict structure — |
| 157 | + the exact layout produced by real SDK spans.""" |
| 158 | + sdk_custom = defaultdict(dict) |
| 159 | + sdk_custom["tags"] = defaultdict(str) |
| 160 | + sdk_custom["tags"]["http.host"] = "agent.com.instana.io" |
| 161 | + |
| 162 | + assert ( |
| 163 | + resolve_nested_key( |
| 164 | + {"sdk.custom": sdk_custom}, ["sdk", "custom", "tags", "http", "host"] |
| 165 | + ) |
| 166 | + == "agent.com.instana.io" |
| 167 | + ) |
| 168 | + |
| 169 | + def test_resolve_nested_key_returns_none_when_missing(self) -> None: |
| 170 | + """Returns None when the dotted path does not exist in the data.""" |
| 171 | + assert ( |
| 172 | + resolve_nested_key( |
| 173 | + {"sdk.custom": {"tags": {}}}, ["sdk", "custom", "tags", "http", "host"] |
| 174 | + ) |
| 175 | + is None |
| 176 | + ) |
| 177 | + |
| 178 | + def test_matches_rule_sdk_span_host_match(self) -> None: |
| 179 | + """SDK span whose sdk.custom.tags.http.host contains 'com.instana' should be filtered.""" |
| 180 | + sdk_custom = defaultdict(dict) |
| 181 | + sdk_custom["tags"] = {"http.host": "agent.com.instana.io"} |
| 182 | + span_attrs = { |
| 183 | + "type": "sdk", |
| 184 | + "kind": 3, |
| 185 | + "sdk.name": "my-span", |
| 186 | + "sdk.custom": sdk_custom, |
| 187 | + } |
| 188 | + |
| 189 | + rule = [ |
| 190 | + { |
| 191 | + "key": "sdk.custom.tags.http.host", |
| 192 | + "values": ["com.instana"], |
| 193 | + "match_type": "contains", |
| 194 | + } |
| 195 | + ] |
| 196 | + assert matches_rule(rule, span_attrs) |
| 197 | + |
| 198 | + def test_matches_rule_sdk_span_host_no_match(self) -> None: |
| 199 | + """SDK span with an unrelated host should NOT be filtered.""" |
| 200 | + sdk_custom = defaultdict(dict) |
| 201 | + sdk_custom["tags"] = {"http.host": "myapp.example.com"} |
| 202 | + span_attrs = { |
| 203 | + "type": "sdk", |
| 204 | + "kind": 3, |
| 205 | + "sdk.name": "my-span", |
| 206 | + "sdk.custom": sdk_custom, |
| 207 | + } |
| 208 | + |
| 209 | + rule = [ |
| 210 | + { |
| 211 | + "key": "sdk.custom.tags.http.host", |
| 212 | + "values": ["com.instana"], |
| 213 | + "match_type": "contains", |
| 214 | + } |
| 215 | + ] |
| 216 | + assert not matches_rule(rule, span_attrs) |
| 217 | + |
| 218 | + def test_matches_rule_sdk_span_url_match(self) -> None: |
| 219 | + """SDK span whose sdk.custom.tags.http.url contains 'com.instana' should be filtered. |
| 220 | +
|
| 221 | + Covers the span shape: |
| 222 | + data.sdk.custom.tags.http.url = 'http://localhost:42699/com.instana.plugin.python.89262' |
| 223 | + """ |
| 224 | + sdk_custom = defaultdict(dict) |
| 225 | + sdk_custom["tags"] = { |
| 226 | + "http.url": "http://localhost:42699/com.instana.plugin.python.89262" |
| 227 | + } |
| 228 | + span_attrs = { |
| 229 | + "type": "sdk", |
| 230 | + "kind": 3, |
| 231 | + "sdk.name": "HEAD", |
| 232 | + "sdk.custom": sdk_custom, |
| 233 | + } |
| 234 | + |
| 235 | + rule = [ |
| 236 | + { |
| 237 | + "key": "sdk.custom.tags.http.url", |
| 238 | + "values": ["com.instana"], |
| 239 | + "match_type": "contains", |
| 240 | + } |
| 241 | + ] |
| 242 | + assert matches_rule(rule, span_attrs) |
0 commit comments