pytest-testmon 2.1.4__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_testmon-2.1.4/pytest_testmon.egg-info → pytest_testmon-2.2.0}/PKG-INFO +3 -3
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pyproject.toml +3 -3
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0/pytest_testmon.egg-info}/PKG-INFO +3 -3
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pytest_testmon.egg-info/requires.txt +1 -1
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/__init__.py +1 -1
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/configure.py +2 -1
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/db.py +19 -6
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/process_code.py +2 -1
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/pytest_testmon.py +74 -16
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/testmon_core.py +80 -63
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/LICENSE +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/MANIFEST.in +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/README.md +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pytest_testmon.egg-info/SOURCES.txt +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pytest_testmon.egg-info/dependency_links.txt +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pytest_testmon.egg-info/entry_points.txt +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/pytest_testmon.egg-info/top_level.txt +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/setup.cfg +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/setup.py +0 -0
- {pytest_testmon-2.1.4 → pytest_testmon-2.2.0}/testmon/common.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-testmon
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: selects tests affected by changed files and methods
|
|
5
5
|
Author-email: Tibor Arpas <tibor@testmon.org>
|
|
6
6
|
License: MIT
|
|
@@ -15,10 +15,10 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
15
15
|
Classifier: Topic :: Utilities
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Framework :: Pytest
|
|
18
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: pytest<
|
|
21
|
+
Requires-Dist: pytest<10,>=5
|
|
22
22
|
Requires-Dist: coverage<8,>=6
|
|
23
23
|
Dynamic: license-file
|
|
24
24
|
|
|
@@ -11,7 +11,7 @@ dynamic = ["version"]
|
|
|
11
11
|
|
|
12
12
|
description = "selects tests affected by changed files and methods"
|
|
13
13
|
readme = "README.md"
|
|
14
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
15
|
keywords = ["testing", "pytest", "plugin"]
|
|
16
16
|
license = { text = "MIT" }
|
|
17
17
|
classifiers = [
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
"Framework :: Pytest",
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
|
-
"pytest>=5,<
|
|
30
|
+
"pytest>=5,<10",
|
|
31
31
|
"coverage>=6,<8",
|
|
32
32
|
]
|
|
33
33
|
|
|
@@ -61,4 +61,4 @@ exclude = '''
|
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
[project.entry-points.pytest11]
|
|
64
|
-
pytest-testmon = "testmon.pytest_testmon"
|
|
64
|
+
pytest-testmon = "testmon.pytest_testmon"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-testmon
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: selects tests affected by changed files and methods
|
|
5
5
|
Author-email: Tibor Arpas <tibor@testmon.org>
|
|
6
6
|
License: MIT
|
|
@@ -15,10 +15,10 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
15
15
|
Classifier: Topic :: Utilities
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Framework :: Pytest
|
|
18
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: pytest<
|
|
21
|
+
Requires-Dist: pytest<10,>=5
|
|
22
22
|
Requires-Dist: coverage<8,>=6
|
|
23
23
|
Dynamic: license-file
|
|
24
24
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
pytest<
|
|
1
|
+
pytest<10,>=5
|
|
2
2
|
coverage<8,>=6
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""PYTEST_DONT_REWRITE"""
|
|
2
|
-
TESTMON_VERSION = "2.
|
|
2
|
+
TESTMON_VERSION = "2.2.0"
|
|
@@ -78,7 +78,8 @@ def _get_noselect_reasons(options):
|
|
|
78
78
|
if options["lf"]:
|
|
79
79
|
return ["--lf was used"]
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
file_or_dir = options.get("file_or_dir") or []
|
|
82
|
+
if any(re.match(r"(.*)\.py::(.*)", opt) for opt in file_or_dir):
|
|
82
83
|
return ["you selected tests manually"]
|
|
83
84
|
|
|
84
85
|
return []
|
|
@@ -10,7 +10,7 @@ from testmon.process_code import blob_to_checksums, checksums_to_blob
|
|
|
10
10
|
from testmon.common import TestExecutions
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
DATA_VERSION =
|
|
13
|
+
DATA_VERSION = 14
|
|
14
14
|
|
|
15
15
|
ChangedFileData = namedtuple(
|
|
16
16
|
"ChangedFileData", "filename name method_checksums id failed"
|
|
@@ -359,7 +359,7 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
359
359
|
duration FLOAT,
|
|
360
360
|
failed BIT,
|
|
361
361
|
forced BIT,
|
|
362
|
-
FOREIGN KEY({self._test_execution_fk_column()}) REFERENCES {self._test_execution_fk_table()}(id));
|
|
362
|
+
FOREIGN KEY({self._test_execution_fk_column()}) REFERENCES {self._test_execution_fk_table()}(id) ON DELETE CASCADE);
|
|
363
363
|
CREATE INDEX test_execution_fk_name ON test_execution ({self._test_execution_fk_column()}, test_name);
|
|
364
364
|
"""
|
|
365
365
|
|
|
@@ -394,7 +394,7 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
394
394
|
CREATE TABLE test_execution_file_fp (
|
|
395
395
|
test_execution_id INTEGER,
|
|
396
396
|
fingerprint_id INTEGER,
|
|
397
|
-
FOREIGN KEY(test_execution_id) REFERENCES test_execution(id),
|
|
397
|
+
FOREIGN KEY(test_execution_id) REFERENCES test_execution(id) ON DELETE CASCADE,
|
|
398
398
|
FOREIGN KEY(fingerprint_id) REFERENCES file_fp(id)
|
|
399
399
|
);
|
|
400
400
|
CREATE INDEX test_execution_file_fp_both ON test_execution_file_fp (test_execution_id, fingerprint_id);
|
|
@@ -403,7 +403,7 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
403
403
|
suite_execution_id INTEGER,
|
|
404
404
|
filename TEXT,
|
|
405
405
|
fsha text,
|
|
406
|
-
FOREIGN KEY(suite_execution_id) REFERENCES suite_execution(id)
|
|
406
|
+
FOREIGN KEY(suite_execution_id) REFERENCES suite_execution(id) ON DELETE CASCADE
|
|
407
407
|
);
|
|
408
408
|
CREATE UNIQUE INDEX sefch_suite_id_filename_sha ON suite_execution_file_fsha(suite_execution_id, filename, fsha);
|
|
409
409
|
"""
|
|
@@ -659,7 +659,7 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
659
659
|
ORDER BY id DESC
|
|
660
660
|
""",
|
|
661
661
|
(environment_name,),
|
|
662
|
-
).fetchone()
|
|
662
|
+
).fetchone() # TODO to pick best environment of many with the same name, we would need to fetch all.
|
|
663
663
|
|
|
664
664
|
if environment:
|
|
665
665
|
environment_id = environment["id"]
|
|
@@ -669,7 +669,7 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
669
669
|
)
|
|
670
670
|
else:
|
|
671
671
|
packages_changed = False
|
|
672
|
-
if not environment
|
|
672
|
+
if not environment:
|
|
673
673
|
try:
|
|
674
674
|
cursor.execute(
|
|
675
675
|
"""
|
|
@@ -694,6 +694,19 @@ class DB: # pylint: disable=too-many-public-methods
|
|
|
694
694
|
(environment_name,),
|
|
695
695
|
).fetchone()
|
|
696
696
|
environment_id = environment["id"]
|
|
697
|
+
elif packages_changed:
|
|
698
|
+
cursor.execute(
|
|
699
|
+
"""
|
|
700
|
+
INSERT INTO environment (environment_name, system_packages, python_version)
|
|
701
|
+
VALUES (?, ?, ?)
|
|
702
|
+
""",
|
|
703
|
+
(environment_name, system_packages, python_version),
|
|
704
|
+
)
|
|
705
|
+
new_environment_id = cursor.lastrowid
|
|
706
|
+
cursor.execute(
|
|
707
|
+
"DELETE FROM environment WHERE id = ?", (environment_id,)
|
|
708
|
+
)
|
|
709
|
+
environment_id = new_environment_id
|
|
697
710
|
|
|
698
711
|
return environment_id, packages_changed
|
|
699
712
|
|
|
@@ -238,7 +238,8 @@ def noncached_get_files_shas(directory):
|
|
|
238
238
|
result = run(
|
|
239
239
|
["git", "ls-files", "--stage", "-m", directory],
|
|
240
240
|
capture_output=True,
|
|
241
|
-
|
|
241
|
+
text=True,
|
|
242
|
+
encoding="utf-8",
|
|
242
243
|
check=True,
|
|
243
244
|
)
|
|
244
245
|
except (FileNotFoundError, CalledProcessError):
|
|
@@ -111,7 +111,7 @@ def pytest_addoption(parser):
|
|
|
111
111
|
action="store_true",
|
|
112
112
|
dest="tmnet",
|
|
113
113
|
help=(
|
|
114
|
-
"
|
|
114
|
+
"Use tmnet cloud for storage instead of .testmondata file used by --testmon (see https://www.testmon.net)."
|
|
115
115
|
),
|
|
116
116
|
)
|
|
117
117
|
|
|
@@ -165,24 +165,52 @@ def init_testmon_data(config: Config):
|
|
|
165
165
|
)
|
|
166
166
|
else:
|
|
167
167
|
tmnet_api_key = os.getenv("TMNET_API_KEY")
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
|
|
169
|
+
if not tmnet_api_key.strip():
|
|
170
|
+
raise ValueError(
|
|
171
|
+
"TMNET_API_KEY is required when using --tmnet. "
|
|
172
|
+
"Please set it in pytest.ini, pyproject.toml, or as an environment variable. "
|
|
171
173
|
)
|
|
174
|
+
|
|
172
175
|
rpc_proxy = xmlrpc.client.ServerProxy(
|
|
173
176
|
url,
|
|
174
177
|
allow_none=True,
|
|
175
|
-
headers=[("x-api-key", tmnet_api_key)],
|
|
178
|
+
headers=[("x-api-key", tmnet_api_key.strip())],
|
|
176
179
|
)
|
|
177
180
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
)
|
|
185
|
-
|
|
181
|
+
# Check if we're a worker and have exec_id from controller
|
|
182
|
+
running_as = get_running_as(config)
|
|
183
|
+
exec_id = None
|
|
184
|
+
system_packages_change = None
|
|
185
|
+
files_of_interest = None
|
|
186
|
+
|
|
187
|
+
if running_as == "worker" and hasattr(config, "workerinput"):
|
|
188
|
+
# Use exec_id sent from controller
|
|
189
|
+
exec_id = config.workerinput.get("testmon_exec_id")
|
|
190
|
+
system_packages_change = config.workerinput.get(
|
|
191
|
+
"testmon_system_packages_change"
|
|
192
|
+
)
|
|
193
|
+
files_of_interest = config.workerinput.get("testmon_files_of_interest")
|
|
194
|
+
|
|
195
|
+
if running_as == "worker" and exec_id is not None:
|
|
196
|
+
# Initialize for xdist worker run
|
|
197
|
+
testmon_data: TestmonData = TestmonData.for_worker(
|
|
198
|
+
rootdir=config.rootdir.strpath,
|
|
199
|
+
exec_id=exec_id,
|
|
200
|
+
database=rpc_proxy,
|
|
201
|
+
system_packages_change=system_packages_change,
|
|
202
|
+
files_of_interest=files_of_interest,
|
|
203
|
+
environment=environment,
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
# Initialize for local run (controller or single process)
|
|
207
|
+
testmon_data: TestmonData = TestmonData.for_local_run(
|
|
208
|
+
rootdir=config.rootdir.strpath,
|
|
209
|
+
database=rpc_proxy,
|
|
210
|
+
environment=environment,
|
|
211
|
+
system_packages=system_packages,
|
|
212
|
+
)
|
|
213
|
+
testmon_data.determine_stable()
|
|
186
214
|
config.testmon_data = testmon_data
|
|
187
215
|
|
|
188
216
|
|
|
@@ -321,7 +349,9 @@ def pytest_unconfigure(config):
|
|
|
321
349
|
|
|
322
350
|
|
|
323
351
|
class TestmonCollect:
|
|
324
|
-
def __init__(
|
|
352
|
+
def __init__(
|
|
353
|
+
self, testmon, testmon_data: TestmonData, running_as="single", cov_plugin=None
|
|
354
|
+
):
|
|
325
355
|
self.testmon_data: TestmonData = testmon_data
|
|
326
356
|
self.testmon: TestmonCollector = testmon
|
|
327
357
|
self._running_as = running_as
|
|
@@ -371,7 +401,9 @@ class TestmonCollect:
|
|
|
371
401
|
if call.when == "teardown":
|
|
372
402
|
report = result.get_result()
|
|
373
403
|
report.nodes_files_lines = self.testmon.get_batch_coverage_data()
|
|
374
|
-
result.force_result(
|
|
404
|
+
result.force_result(
|
|
405
|
+
report
|
|
406
|
+
) # under xdist, report is serialized on the worker and sent to the controller
|
|
375
407
|
|
|
376
408
|
@pytest.hookimpl
|
|
377
409
|
def pytest_runtest_logreport(self, report):
|
|
@@ -412,6 +444,32 @@ class TestmonXdistSync:
|
|
|
412
444
|
def __init__(self):
|
|
413
445
|
self.await_nodes = 0
|
|
414
446
|
|
|
447
|
+
def pytest_configure_node(self, node):
|
|
448
|
+
"""
|
|
449
|
+
Send exec_id and related data from controller to worker during xdist initialization.
|
|
450
|
+
This avoids each worker having to independently determine the environment and check
|
|
451
|
+
for package changes.
|
|
452
|
+
|
|
453
|
+
Note: This hook is called on the controller side for each worker node.
|
|
454
|
+
The node.config here is the controller's config, not the worker's config.
|
|
455
|
+
"""
|
|
456
|
+
# Verify we're on the controller (not a worker)
|
|
457
|
+
# node.config in this hook is the controller's config
|
|
458
|
+
running_as = get_running_as(node.config)
|
|
459
|
+
if running_as != "controller":
|
|
460
|
+
return # Safety check: only run on controller
|
|
461
|
+
|
|
462
|
+
# Only proceed if testmon_data has been initialized and workerinput exists
|
|
463
|
+
if hasattr(node.config, "testmon_data") and hasattr(node, "workerinput"):
|
|
464
|
+
testmon_data: TestmonData = node.config.testmon_data
|
|
465
|
+
node.workerinput["testmon_exec_id"] = testmon_data.exec_id
|
|
466
|
+
node.workerinput[
|
|
467
|
+
"testmon_system_packages_change"
|
|
468
|
+
] = testmon_data.system_packages_change
|
|
469
|
+
node.workerinput[
|
|
470
|
+
"testmon_files_of_interest"
|
|
471
|
+
] = testmon_data.files_of_interest
|
|
472
|
+
|
|
415
473
|
def pytest_testnodeready(self, node): # pylint: disable=unused-argument
|
|
416
474
|
self.await_nodes += 1
|
|
417
475
|
|
|
@@ -455,7 +513,7 @@ def format_time_saved(seconds):
|
|
|
455
513
|
|
|
456
514
|
|
|
457
515
|
class TestmonSelect:
|
|
458
|
-
def __init__(self, config, testmon_data):
|
|
516
|
+
def __init__(self, config, testmon_data: TestmonData):
|
|
459
517
|
self.testmon_data: TestmonData = testmon_data
|
|
460
518
|
self.config = config
|
|
461
519
|
|
|
@@ -157,23 +157,14 @@ def collect_mhashes(source_tree, new_changed_file_data):
|
|
|
157
157
|
class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
158
158
|
__test__ = False
|
|
159
159
|
|
|
160
|
-
def __init__(
|
|
160
|
+
def __init__(
|
|
161
161
|
self,
|
|
162
162
|
rootdir,
|
|
163
163
|
database=None,
|
|
164
|
-
environment=None,
|
|
165
|
-
system_packages=None,
|
|
166
|
-
python_version=None,
|
|
167
164
|
readonly=False,
|
|
168
165
|
):
|
|
169
166
|
self.rootdir = rootdir
|
|
170
|
-
self.environment = environment if environment else "default"
|
|
171
167
|
self.source_tree = SourceTree(rootdir=self.rootdir)
|
|
172
|
-
if system_packages is None:
|
|
173
|
-
system_packages = get_system_packages()
|
|
174
|
-
system_packages = drop_patch_version(system_packages)
|
|
175
|
-
if not python_version:
|
|
176
|
-
python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
177
168
|
|
|
178
169
|
if database:
|
|
179
170
|
self.db = database # pylint: disable=invalid-name
|
|
@@ -182,6 +173,48 @@ class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
|
182
173
|
os.path.join(self.rootdir, get_data_file_path()), readonly=readonly
|
|
183
174
|
) # pylint: disable=invalid-name
|
|
184
175
|
|
|
176
|
+
# Initialize instance variables (will be set by init methods)
|
|
177
|
+
self.environment = None
|
|
178
|
+
self.exec_id = None
|
|
179
|
+
self.system_packages_change = None
|
|
180
|
+
self.files_of_interest = None
|
|
181
|
+
self.all_files = {}
|
|
182
|
+
self.unstable_test_names = None
|
|
183
|
+
self.unstable_files = None
|
|
184
|
+
self.stable_test_names = None
|
|
185
|
+
self.stable_files = None
|
|
186
|
+
self.failing_tests = None
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def for_local_run(
|
|
190
|
+
cls,
|
|
191
|
+
rootdir,
|
|
192
|
+
database=None,
|
|
193
|
+
environment=None,
|
|
194
|
+
system_packages=None,
|
|
195
|
+
python_version=None,
|
|
196
|
+
):
|
|
197
|
+
instance = cls(rootdir, database=database, readonly=False)
|
|
198
|
+
instance._init_for_local_run(environment, system_packages, python_version)
|
|
199
|
+
return instance
|
|
200
|
+
|
|
201
|
+
def _init_for_local_run(
|
|
202
|
+
self,
|
|
203
|
+
environment=None,
|
|
204
|
+
system_packages=None,
|
|
205
|
+
python_version=None,
|
|
206
|
+
):
|
|
207
|
+
"""Internal method to initialize for local run."""
|
|
208
|
+
self.environment = environment if environment else "default"
|
|
209
|
+
|
|
210
|
+
if system_packages is None:
|
|
211
|
+
system_packages = get_system_packages()
|
|
212
|
+
system_packages = drop_patch_version(system_packages)
|
|
213
|
+
|
|
214
|
+
if not python_version:
|
|
215
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
216
|
+
|
|
217
|
+
# Initiate execution (controller or single process)
|
|
185
218
|
try:
|
|
186
219
|
result = self.db.initiate_execution(
|
|
187
220
|
self.environment,
|
|
@@ -207,21 +240,49 @@ class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
|
207
240
|
result = self.db.initiate_execution(
|
|
208
241
|
self.environment, system_packages, python_version, {}
|
|
209
242
|
)
|
|
210
|
-
self.exec_id = result["exec_id"]
|
|
211
243
|
|
|
244
|
+
self.exec_id = result["exec_id"]
|
|
212
245
|
self.system_packages_change = result["packages_changed"]
|
|
213
246
|
self.files_of_interest = result["filenames"]
|
|
214
247
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
248
|
+
@classmethod
|
|
249
|
+
def for_worker( # pylint: disable=too-many-arguments
|
|
250
|
+
cls,
|
|
251
|
+
rootdir,
|
|
252
|
+
exec_id,
|
|
253
|
+
database=None,
|
|
254
|
+
system_packages_change=None,
|
|
255
|
+
files_of_interest=None,
|
|
256
|
+
environment=None,
|
|
257
|
+
):
|
|
258
|
+
instance = cls(rootdir, database=database, readonly=True)
|
|
259
|
+
instance._init_for_worker(
|
|
260
|
+
exec_id, system_packages_change, files_of_interest, environment
|
|
261
|
+
)
|
|
262
|
+
return instance
|
|
263
|
+
|
|
264
|
+
def _init_for_worker(
|
|
265
|
+
self,
|
|
266
|
+
exec_id,
|
|
267
|
+
system_packages_change=None,
|
|
268
|
+
files_of_interest=None,
|
|
269
|
+
environment=None,
|
|
270
|
+
):
|
|
271
|
+
"""Internal method to initialize for worker run."""
|
|
272
|
+
self.exec_id = exec_id
|
|
273
|
+
self.system_packages_change = system_packages_change
|
|
274
|
+
self.files_of_interest = files_of_interest
|
|
275
|
+
if environment:
|
|
276
|
+
self.environment = environment
|
|
277
|
+
elif not hasattr(self, "environment") or self.environment is None:
|
|
278
|
+
self.environment = "default"
|
|
221
279
|
|
|
222
280
|
@property
|
|
223
281
|
def new_db(self):
|
|
224
|
-
|
|
282
|
+
# Only local DB instances have file_created attribute
|
|
283
|
+
if isinstance(self.db, db.DB):
|
|
284
|
+
return self.db.file_created
|
|
285
|
+
return False
|
|
225
286
|
|
|
226
287
|
def close_connection(self):
|
|
227
288
|
pass
|
|
@@ -282,7 +343,7 @@ class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
|
282
343
|
with self.db as database:
|
|
283
344
|
database.delete_test_executions(to_delete, self.exec_id)
|
|
284
345
|
|
|
285
|
-
def determine_stable(self
|
|
346
|
+
def determine_stable(self):
|
|
286
347
|
files_fshas = {}
|
|
287
348
|
for filename in self.files_of_interest:
|
|
288
349
|
module = self.source_tree.get_file(filename)
|
|
@@ -299,9 +360,6 @@ class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
|
299
360
|
tests = self.db.determine_tests(self.exec_id, files_mhashes)
|
|
300
361
|
affected_tests, self.failing_tests = tests["affected"], tests["failing"]
|
|
301
362
|
|
|
302
|
-
if assert_old:
|
|
303
|
-
self.assert_old_determin_stable(affected_tests)
|
|
304
|
-
|
|
305
363
|
self.all_files = set(self.db.filenames(self.exec_id))
|
|
306
364
|
self.unstable_test_names = set()
|
|
307
365
|
self.unstable_files = set()
|
|
@@ -313,47 +371,6 @@ class TestmonData: # pylint: disable=too-many-instance-attributes
|
|
|
313
371
|
self.stable_test_names = set(self.all_tests) - self.unstable_test_names
|
|
314
372
|
self.stable_files = set(self.all_files) - self.unstable_files
|
|
315
373
|
|
|
316
|
-
def assert_old_determin_stable(self, new_fingerprint_misses):
|
|
317
|
-
filenames_fingerprints = self.db.filenames_fingerprints(self.exec_id)
|
|
318
|
-
|
|
319
|
-
_, fsha_misses = split_filter(
|
|
320
|
-
self.source_tree, check_fsha, filenames_fingerprints
|
|
321
|
-
) # check 2. fsha vs filesystem
|
|
322
|
-
|
|
323
|
-
# with the list of fingerprint_ids go to the database
|
|
324
|
-
# and fetch all the data needed for next step
|
|
325
|
-
|
|
326
|
-
changed_file_data = self.db.fetch_changed_file_data(
|
|
327
|
-
[fsha_miss["fingerprint_id"] for fsha_miss in (fsha_misses)],
|
|
328
|
-
self.exec_id,
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
# changed_file_data:
|
|
332
|
-
# [(filename, test_name, method_fshas, fingerprint_id, failed )]
|
|
333
|
-
# All the test_names in this list have a dependency on one
|
|
334
|
-
# or more changed files. And we also have the fingerprints
|
|
335
|
-
# of data content which they depend on. So it’s possible to
|
|
336
|
-
# filter out the node_ids where the content of the changed file
|
|
337
|
-
# still matches the fingerprint
|
|
338
|
-
|
|
339
|
-
_, fingerprint_misses = split_filter(
|
|
340
|
-
self.source_tree, check_fingerprint, changed_file_data
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
if {fingerprint_miss[1] for fingerprint_miss in fingerprint_misses} != set(
|
|
344
|
-
new_fingerprint_misses
|
|
345
|
-
):
|
|
346
|
-
print("ERROR: old and new fingerprint misses differ.. printing old algo")
|
|
347
|
-
print(
|
|
348
|
-
"\n".join(
|
|
349
|
-
sorted(
|
|
350
|
-
{fingerprint_miss[1] for fingerprint_miss in fingerprint_misses}
|
|
351
|
-
)
|
|
352
|
-
)
|
|
353
|
-
)
|
|
354
|
-
print("printing new algo")
|
|
355
|
-
print("\n".join(sorted(new_fingerprint_misses)))
|
|
356
|
-
|
|
357
374
|
@property
|
|
358
375
|
def avg_durations(self) -> dict:
|
|
359
376
|
stats = defaultdict(lambda: {"test_execution": 0, "sum_duration": 0})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|