Skip to content

Commit 24bb307

Browse files
committed
ci: move DI exploration tests to GitLab
We extract the exploration tests from the rest of the framework tests and move them to GitLab.
1 parent c335af9 commit 24bb307

File tree

7 files changed

+66
-29
lines changed

7 files changed

+66
-29
lines changed

.gitlab-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ include:
3737
- local: ".gitlab/testrunner.yml"
3838
- local: ".gitlab/benchmarks/serverless.yml"
3939
- local: ".gitlab/native.yml"
40+
- local: ".gitlab/debugging/exploration.yml"
4041

4142
tests-gen:
4243
stage: tests

.gitlab/debugging/exploration.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"debugging::exploration-testing::boto3":
2+
stage: tests
3+
extends: .testrunner
4+
variables:
5+
DD_DEBUGGER_EXPL_STATUS_MESSAGES: 1
6+
DD_DEBUGGER_EXPL_INCLUDE: "boto3"
7+
parallel:
8+
matrix:
9+
- PYTHON_VERSION: "3.8"
10+
BOTO3_TAG: 1.37.38
11+
- PYTHON_VERSION: ["3.9", "3.10", "3.11", "3.12", "3.13"]
12+
BOTO3_TAG: 1.38.44
13+
script: |
14+
python${PYTHON_VERSION} -m pip install -e .
15+
git clone --depth 1 --branch ${BOTO3_TAG} https://github.com/boto/boto3.git
16+
cd boto3
17+
python${PYTHON_VERSION} scripts/ci/install
18+
PYTHONPATH=../tests/debugging/exploration/ python${PYTHON_VERSION} scripts/ci/run-tests
19+
needs: []
20+
artifacts:
21+
paths:
22+
- debugger-expl.txt

tests/debugging/exploration/_config.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ExplorationConfig(DDConfig):
2929
encode = DDConfig.v(
3030
bool,
3131
"dd.debugger.expl.encode",
32-
default=True,
32+
default=False,
3333
help="Whether to encode the snapshots",
3434
)
3535

@@ -40,7 +40,7 @@ class ExplorationConfig(DDConfig):
4040
help="Whether to print exploration debugger status messages",
4141
)
4242

43-
include = DDConfig.v(
43+
includes = DDConfig.v(
4444
list,
4545
"dd.debugger.expl.include",
4646
parser=lambda v: [path.split(".") for path in v.split(",")],
@@ -58,7 +58,7 @@ class ExplorationConfig(DDConfig):
5858
conservative = DDConfig.v(
5959
bool,
6060
"dd.debugger.expl.conservative",
61-
default=False,
61+
default=True,
6262
help="Use extremely low capture limits to reduce overhead",
6363
)
6464

tests/debugging/exploration/_coverage.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from collections import defaultdict
22
from pathlib import Path
3-
import sys
43
from types import ModuleType
54
import typing as t
65

@@ -22,27 +21,38 @@
2221

2322

2423
# Track all the covered modules and its lines. Indexed by module origin.
25-
_tracked_modules: t.Dict[str, t.Tuple[ModuleType, t.Set[int]]] = {}
24+
_tracked_modules: t.Dict[Path, t.Tuple[ModuleType, t.Set[int]]] = {}
2625

2726

2827
class LineCollector(ModuleCollector):
2928
def on_collect(self, discovery: FunctionDiscovery) -> None:
3029
o = origin(discovery._module)
30+
if o is None:
31+
status("[coverage] cannot collect lines from %s, no origin found" % discovery._module.__name__)
32+
return
33+
3134
status("[coverage] collecting lines from %s" % o)
3235
_tracked_modules[o] = (discovery._module, {_ for _ in discovery.keys()})
33-
LineCoverage.add_probes(
34-
[
35-
create_snapshot_line_probe(
36-
probe_id="@".join([str(hash(f)), str(line)]),
37-
source_file=origin(sys.modules[f.__module__]),
38-
line=line,
39-
rate=0.0,
40-
limits=expl_config.limits,
36+
probes = []
37+
for line, fcps in discovery.items():
38+
for fcp in fcps:
39+
try:
40+
f = fcp.resolve()
41+
except ValueError:
42+
# This function-code pair is not from a function, e.g. a
43+
# class.
44+
continue
45+
probe_id = "@".join([str(hash(f)), str(line)])
46+
probes.append(
47+
create_snapshot_line_probe(
48+
probe_id=probe_id,
49+
source_file=o,
50+
line=line,
51+
rate=0.0,
52+
limits=expl_config.limits,
53+
)
4154
)
42-
for line, functions in discovery.items()
43-
for f in functions
44-
]
45-
)
55+
LineCoverage.add_probes(probes)
4656

4757

4858
class LineCoverage(ExplorationDebugger):
@@ -72,7 +82,7 @@ def report_coverage(cls) -> None:
7282
total_covered += len(seen_lines)
7383
log(
7484
("{:<%d} {:>5} {: 6.0f}%%" % w).format(
75-
str(o.relative_to(CWD)),
85+
str(o),
7686
len(lines),
7787
len(seen_lines) * 100.0 / len(lines) if lines else 0,
7888
)

tests/debugging/exploration/_profiler.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ class FunctionCollector(ModuleCollector):
2525
def on_collect(self, discovery: FunctionDiscovery) -> None:
2626
module = discovery._module
2727
status("[profiler] Collecting functions from %s" % module.__name__)
28-
for fname, f in discovery._fullname_index.items():
28+
for fname, fcp in discovery._fullname_index.items():
29+
try:
30+
f = fcp.resolve()
31+
except ValueError:
32+
# This function-code pair is not from a function, e.g. a class.
33+
continue
2934
if origin(module) != Path(f.__code__.co_filename).resolve():
3035
# Do not wrap functions that do not belong to the module. We
3136
# will have a chance to wrap them when we discover the module

tests/debugging/exploration/debugger.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def on_collect(self, discovery: FunctionDiscovery) -> None:
4545
def _on_new_module(self, module):
4646
try:
4747
if not is_ddtrace(module):
48-
if config.include:
48+
if config.includes:
4949
if not is_included(module, config):
5050
return
5151
elif not from_editable_install(module, config):
@@ -55,7 +55,7 @@ def _on_new_module(self, module):
5555
return
5656

5757
try:
58-
return self.on_collect(FunctionDiscovery(module))
58+
return self.on_collect(FunctionDiscovery.from_module(module))
5959
except Exception as e:
6060
status("Error collecting functions from %s: %s" % (module.__name__, e))
6161
raise e
@@ -203,6 +203,8 @@ def enable(cls) -> None:
203203
# not being managed by the product manager.
204204
atexit.register(cls.disable)
205205

206+
cls.__watchdog__.install()
207+
206208
@classmethod
207209
def disable(cls, join: bool = True) -> None:
208210
registry = cls._instance._probe_registry
@@ -218,12 +220,7 @@ def disable(cls, join: bool = True) -> None:
218220

219221
cls.on_disable()
220222

221-
snapshots = cls.get_snapshots()
222-
if snapshots and snapshots[-1] is not None:
223-
import json
224-
from pprint import pprint
225-
226-
pprint(json.loads(snapshots[-1].decode()), stream=config.output_stream)
223+
cls.__watchdog__.uninstall()
227224

228225
super(ExplorationDebugger, cls).disable(join=join)
229226

tests/debugging/exploration/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
from types import ModuleType
33

4+
from _config import ExplorationConfig
5+
46
from ddtrace.internal.compat import Path
57
from ddtrace.internal.module import origin
68

@@ -33,9 +35,9 @@ def from_editable_install(module: ModuleType, config) -> bool:
3335
)
3436

3537

36-
def is_included(module: ModuleType, config) -> bool:
38+
def is_included(module: ModuleType, config: ExplorationConfig) -> bool:
3739
segments = module.__name__.split(".")
38-
for i in config.include:
40+
for i in config.includes:
3941
if i == segments[: len(i)]:
4042
return True
4143
return False

0 commit comments

Comments
 (0)