class InitPhasePlugin: """Class to handle mapping database initialization""" def __init__(self): """"Constructor calls database and Coverage.py initialization""" self.test_func_lines = {} self.cov = coverage.Coverage() self.cov._warn_unimported_source = False self.testfiles = set() self.database = DatabaseHelper() self.database.init_conn() self.database.init_mapping_db() self.head_hash = get_current_head_hash() self.database.save_last_update_hash(self.head_hash) def pytest_collection_modifyitems(self, session, config, items): """Calculate function start and end line numbers from testfiles""" del session, config for item in items: testfile = item.nodeid.split("::")[0] self.testfiles.add(testfile) if testfile not in self.test_func_lines: testfile_src_code = coverage.python.get_python_source(testfile) self.test_func_lines[testfile] = calculate_func_lines( testfile_src_code) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_protocol(self, item, nextitem): """Start coverage collection for each test function run and save data""" del nextitem if isinstance(item, Function): start = timer() self.cov.erase() self.cov.start() yield self.cov.stop() self.cov.save() end = timer() elapsed = round(end - start, 4) _, test_function_id = save_testfile_and_func_data( item, elapsed, self.test_func_lines, self.database) save_mapping_data( test_function_id, self.cov.get_data(), self.testfiles, self.database, ) else: yield
def pytest_configure(config): """Register RTS plugins based on state""" logger = logging.getLogger() logging.basicConfig(format="%(message)s", level=logging.INFO) if config.option.rts: if not os.path.isfile(DB_FILE_NAME): logger.info("No mapping database detected, starting initialization...") config.pluginmanager.register(InitPhasePlugin()) return db_helper = DatabaseHelper() db_helper.init_conn() workdir_data = get_tests_and_data_current(db_helper) logger.info("WORKING DIRECTORY CHANGES") logger.info( "Found %s changed test files", workdir_data.changed_testfiles_amount ) logger.info("Found %s changed src files", workdir_data.changed_srcfiles_amount) logger.info("Found %s tests to execute\n", len(workdir_data.test_set)) if workdir_data.test_set: logger.info( "Running WORKING DIRECTORY test set and exiting without updating..." ) config.pluginmanager.register(NormalPhasePlugin(workdir_data.test_set)) return logger.info("No WORKING DIRECTORY tests to run, checking COMMITTED changes...") current_hash = get_current_head_hash() if db_helper.is_last_update_hash(current_hash): pytest.exit("Database is updated to the current commit state", 0) previous_hash = db_helper.get_last_update_hash() logger.info("Comparison: %s\n", " => ".join([current_hash, previous_hash])) committed_data = get_tests_and_data_committed(db_helper) logger.info("COMMITTED CHANGES") logger.info( "Found %s changed test files", committed_data.changed_testfiles_amount ) logger.info( "Found %s changed src files", committed_data.changed_srcfiles_amount ) logger.info( "Found %s newly added tests", committed_data.new_tests_amount, ) logger.info("Found %s tests to execute\n", len(committed_data.test_set)) if committed_data.warning_needed: logger.info( "WARNING: New lines were added to the following files but no new tests discovered:" ) logger.info("\n".join(committed_data.files_to_warn)) logger.info("=> Executing tests (if any) and updating database") db_helper.save_last_update_hash(current_hash) update_mapping_db(committed_data.update_data, db_helper) if committed_data.test_set: config.pluginmanager.register(UpdatePhasePlugin(committed_data.test_set)) return pytest.exit("No tests to run", 0)