diff --git a/requirements.txt b/requirements.txt index 597bab2..53ef946 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -pytest>=2.7,<2.9 +pytest>=2.8,<3.1 coverage>=4 diff --git a/test/test_core.py b/test/test_core.py index 442264a..7d1b1f0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -10,7 +10,6 @@ from _pytest import runner - pytest_plugins = "pytester", Block = namedtuple('Block', 'checksums') @@ -35,13 +34,16 @@ def test_read_nonexistent(testdir): def test_write_read_data2(testdir): - original = ({'a.py': 1.0}, {'n1': {'a.py': [1]}}, ['n1']) + n1_node_data = {'a.py': [1]} + original = ({'a.py': 1.0}, ['n1']) td = CoreTestmonData(testdir.tmpdir.strpath, 'default') - td.mtimes, td.node_data, td.lastfailed = original + td.mtimes, td.lastfailed = original td.write_data() + td.set_dependencies('n1', n1_node_data, ) td2 = CoreTestmonData(testdir.tmpdir.strpath, 'default') td2.read_data() - assert original == (td2.mtimes, td2.node_data, td2.lastfailed) + assert td2.node_data['n1'] == n1_node_data + assert original == (td2.mtimes, td2.lastfailed) class TestDepGraph(): @@ -186,8 +188,10 @@ def test_flip(): files = flip_dictionary(node_data) assert files == {'a': {'X': [1, 2, 3]}, 'b': {'X': [3, 4, 5], 'Y': [3, 6, 7]}} + global_reports = [] + def serialize_report(rep): import py d = rep.__dict__.copy() @@ -203,25 +207,19 @@ def serialize_report(rep): return d - def test_serialize(testdir): - - class PlugWrite: - def pytest_runtest_logreport(self, report): global global_reports global_reports.append(report) class PlugRereport: - def pytest_runtest_protocol(self, item, nextitem): hook = getattr(item.ihook, 'pytest_runtest_logreport') for g in global_reports: hook(report=g) return True - testdir.makepyfile(""" def test_a(): raise Exception('exception from test_a') @@ -229,7 +227,6 @@ def test_a(): testdir.runpytest_inprocess(plugins=[PlugWrite()]) - testdir.makepyfile(""" def test_a(): pass @@ -238,4 +235,3 @@ def test_a(): result = testdir.runpytest_inprocess(plugins=[PlugRereport()]) print(result) - diff --git a/test/test_testmon.py b/test/test_testmon.py index 29175d6..9aee957 100755 --- a/test/test_testmon.py +++ b/test/test_testmon.py @@ -85,7 +85,7 @@ def track_it(testdir, func): testmon.start() func() testmon.stop_and_save(testmon_data, testdir.tmpdir.strpath, 'testnode') - return testmon_data.changed_node_data['testnode'] + return testmon_data._fetch_node_data()['testnode'] def test_subprocesss(testdir, monkeypatch): diff --git a/testmon/testmon_core.py b/testmon/testmon_core.py index 9eff2b8..9340e5c 100644 --- a/testmon/testmon_core.py +++ b/testmon/testmon_core.py @@ -104,7 +104,7 @@ def stop_and_save(self, testmon_data, rootdir, nodeid): if hasattr(self, 'sub_cov_file'): self.cov.combine() - testmon_data.set_dependencies(nodeid, self.cov.get_data(), rootdir) + testmon_data.set_dependencies(nodeid, testmon_data.get_nodedata(nodeid, self.cov.get_data(), rootdir)) def close(self): if hasattr(self, 'sub_cov_file'): @@ -112,18 +112,6 @@ def close(self): os.environ.pop('COVERAGE_PROCESS_START', None) -class ExtTestmon(Testmon): - - def track_dependencies(self, callable_to_track, testmon_data, rootdir, nodeid): - pass - - -class ExtExtTestmon(ExtTestmon): - - def track_dependencies(self, callable_to_track, testmon_data, rootdir, nodeid): - pass - - def eval_variant(run_variant, **kwargs): if not run_variant: return '' @@ -191,6 +179,13 @@ def _fetch_attribute(self, attribute, default=None): else: return default + def _fetch_node_data(self): + result = defaultdict(lambda: {}) + for row in self.connection.execute("SELECT node_name, file_name, checksums FROM node_file WHERE node_variant=?", + (self.variant,)): + result[row[0]][row[1]] = json.loads(row[2]) + return result + def _write_attribute(self, attribute, data): dataid = self.variant + ':' + attribute json_data = json.dumps(data).encode('utf-8') @@ -210,20 +205,13 @@ def init_tables(self): result TEXT, PRIMARY KEY (variant, name)) """) - self.connection.execute(""" - CREATE TABLE file ( - name TEXT PRIMARY KEY, - mtime LONG) - """) - self.connection.execute(""" CREATE TABLE node_file ( node_variant TEXT, node_name TEXT, file_name TEXT, checksums TEXT, - FOREIGN KEY(node_variant, node_name) REFERENCES node(variant, name) ON DELETE CASCADE, - FOREIGN KEY(file_name) REFERENCES file(name) ON DELETE CASCADE) + FOREIGN KEY(node_variant, node_name) REFERENCES node(variant, name) ON DELETE CASCADE) """) def read_data(self): @@ -231,7 +219,7 @@ def read_data(self): self.node_data, \ self.reports, \ self.lastfailed = self._fetch_attribute('mtimes', default={}), \ - self._fetch_attribute('node_data', default={}), \ + self._fetch_node_data(), \ self._fetch_attribute('reports', default={}), \ self._fetch_attribute('lastfailed', default=[]) @@ -241,7 +229,7 @@ def write_data(self): self.node_data.update(self.changed_node_data) self.reports.update(self.changed_reports) self._write_attribute('mtimes', self.mtimes) - self._write_attribute('node_data', self.node_data) + #self._write_attribute('node_data', self.node_data) self._write_attribute('lastfailed', self.lastfailed) self._write_attribute('reports', self.reports) @@ -264,23 +252,28 @@ def file_data(self): # "FROM node_checksum_dep n JOIN file_version f ON n.file_version_id=f.id" # "GROUP BY ") - def set_dependencies(self, nodeid, coverage_data, rootdir): - result = {} - with self.connection as con: - con.execute("INSERT OR REPLACE INTO " - "node " - "VALUES (?, ?, ?)", (self.variant, nodeid, '')) + def get_nodedata(self, nodeid, coverage_data, rootdir): + result = {} for filename in coverage_data.measured_files(): lines = coverage_data.lines(filename) if os.path.exists(filename): result[filename] = checksum_coverage(self.parse_file(filename).blocks, lines) - self.write_db(con, filename, nodeid, result[filename]) - if not result: + if not result: # when testmon kicks-in the test module is already imported. If the test function is skipped + # coverage_data is empty. However, we need to write down, that we depend on the + # file where the test is stored (so that we notice e.g. when the test is no longer skipped.) filename = os.path.join(rootdir, nodeid).split("::", 1)[0] result[filename] = checksum_coverage(self.parse_file(filename).blocks, [1]) - self.write_db(con, filename, nodeid, result[filename]) - self.changed_node_data[nodeid] = result + return result + + def set_dependencies(self, nodeid, nodedata): + with self.connection as con: + con.execute("INSERT OR REPLACE INTO " + "node " + "VALUES (?, ?, ?)", (self.variant, nodeid, '')) + + for filename in nodedata: + self.write_db(con, filename, nodeid, nodedata[filename]) def parse_file(self, file, new_mtime=None): if file not in self.changed_files: @@ -290,14 +283,10 @@ def parse_file(self, file, new_mtime=None): return self.changed_files[file] def write_db(self, con, filename, nodeid, checksums): - fc = con.cursor() - fc.execute("INSERT OR REPLACE INTO file VALUES (?, ?)", (filename, self.mtimes[filename])) dc = con.cursor() dc.execute("INSERT INTO node_file VALUES (?, ?, ?, ?)", (self.variant, nodeid, filename, json.dumps(checksums))) - # import pydevd; pydevd.settrace() - return self.modules_cache[module] def read_fs(self): self.read_data() diff --git a/tox.ini b/tox.ini index cee98e7..2ad0272 100644 --- a/tox.ini +++ b/tox.ini @@ -10,7 +10,6 @@ envlist = py{27,34,35}-pytest{27,28,29,master,features} commands = py.test --tb=native {posargs:test} deps = coverage_pth - pytest27: pytest>=2.7,<2.8 pytest28: pytest>=2.8,<2.9 pytest29: pytest>=2.9,<3.0 # master is current stable version with bugfixes.