Exemple #1
0
    def store(self, db_helper: DatabaseHelper, project: Project,
              commit: Commit, coverage: List[Tuple[TestMethod,
                                                   List[LineCoverage]]]):
        with db_helper.create_session() as session:
            project, _ = session.add(project)

            commit.project = project
            commit, _ = session.add(commit)

            for test, lines in coverage:
                test.project = project
                test, _ = session.add(test)

                for line in lines:
                    method_version: ProdMethodVersion = session.query(ProdMethodVersion)\
                        .join(ProdMethod,
                            (ProdMethod.id==ProdMethodVersion.method_id)
                            & (ProdMethodVersion.line_start <= line.line_number)
                            & (ProdMethodVersion.line_end >= line.line_number)
                        )\
                        .filter(ProdMethod.file_path.contains(line.full_name))\
                        .filter(ProdMethodVersion.commit_id==commit.id)\
                        .first()

                    line.test_id = test.id
                    line.commit_id = commit.id

                    if method_version is None:
                        continue

                    line.method_version_id = method_version.id
                    session.add(line)
Exemple #2
0
class TestCoverageAndMethodParser(unittest.TestCase):
    def setUp(self):
        self.resource_dir = f'.{os.path.sep}tests{os.path.sep}resources{os.path.sep}'
        self.db_helper = DatabaseHelper(':memory:')

    def tearDown(self):
        pass

    def load_coverage(self, project_name, commit_sha) -> List[Dict]:
        coverage_matrix_file = f'{self.resource_dir}{project_name}{os.path.sep}{commit_sha}-cov-matrix.json'
        with open(coverage_matrix_file) as coverage:
            return json.load(coverage)

    def load_methods(self, project_name, commit_sha) -> List[Dict]:
        methods_file = f'{self.resource_dir}{project_name}{os.path.sep}methods-{commit_sha}.json'
        with open(methods_file) as methods:
            return json.load(methods)

    def test_parsing_and_storing_coverage_data(self):
        # Given: some coverage information
        project_name = 'mid_example'
        commit_sha = 'df1bc2481a05acc3944cc1c3f637856d54cd8ba8'

        project = Project(project_name=project_name)
        commit = Commit(sha=commit_sha)

        # When
        method_parser: MethodParser = MethodParser()
        methods_dict: List[Dict] = self.load_methods(project_name, commit_sha)
        methods = method_parser\
            .set_commit(commit)\
            .parse(methods_dict)

        method_parser.store(self.db_helper, project, commit, methods)

        tacoco_parser: TacocoParser = TacocoParser()
        coverage_dict: Dict = self.load_coverage(project_name, commit_sha)
        coverage = tacoco_parser\
            .parse(coverage_dict)

        tacoco_parser.store(self.db_helper, project, commit, coverage)

        assert len(self.db_helper.query(LineCoverage).all()) != 0
Exemple #3
0
def create_app(data_base_path, echo=False):
    app = Flask(__name__)
    app.config['JSON_SORT_KEYS'] = False
    CORS(app)

    db_helper: DatabaseHelper = DatabaseHelper(data_base_path, echo)

    @app.route('/', methods=['GET'])
    @timer
    def hello_world():
        return "Hello World!", 200

    @app.route('/projects', methods=['GET'])
    @timer
    def list_projects():
        with db_helper.create_session() as session:
            projects = ProjectQuery(session).get_projects()

        if len(projects) == 0:
            return {"Error": "No projects found..."}, 404

        return {"projects": list(map(row2dict, projects))}, 200

    @app.route('/commits/<project_name>', methods=['GET'])
    @timer
    def list_commits_of_project(project_name):

        with db_helper.create_session() as session:
            project: Project = ProjectQuery(session).get_project(project_name)

            if project is None:
                return {"Error": "Project not found..."}, 404

            commits = CommitQuery(session).get_commits(project)

        if len(commits) == 0:
            return {"Error": f"Project '{project_name}' was not found..."}, 404

        return {
            "project": project_name,
            "commits": list(map(row2dict, commits))
        }, 200

    @app.route('/coverage/<project_name>/<commit_sha>', methods=['GET'])
    @timer
    def coverage(project_name, commit_sha):
        # TODO add error handling (commit not found, project not found)
        filters = []

        # TODO Add test/method filter parameter
        with db_helper.create_session() as session:

            project: Project = ProjectQuery(session).get_project(
                project_name=project_name)
            if project is None:
                return {"Error": "Project not found..."}, 404

            commit: Commit = CommitQuery(session).get_commit(
                project, commit_sha)
            logger.debug(f"\n\n{project}/{commit}\n\n")

            if commit is None:
                return {"Error": "Commit not found..."}, 404

            coverage_query = MethodCoverageQuery(session)\
                .set_commit(commit)\
                .set_project(project)

            for filter in filters:
                coverage_query.add_filter(filter)

            edges = coverage_query.get_coverage()
            methods = coverage_query.get_methods()
            tests = coverage_query.get_tests()

        # Format coverage data
        coverage = coverage_format(methods, tests, edges)

        # Filter and sort data using the given parametrs.
        sort_function = list()

        if (f := sort_selector("name")) is not None:
            sort_function.append(f)

        # filter and sort the data
        coverage = ProcessDataBuilder() \
            .add_sorters(sort_function) \
            .add_metrics(cluster) \
            .process_data(coverage)

        return {
            "project": project_name,
            "commit_sha": commit_sha,
            "coverage": coverage
        }, 200
Exemple #4
0
def start(DB_PATH, project_url, output_path, tacoco_path, history_slider_path,
          arguments):
    db_handler = DatabaseHelper(DB_PATH)

    with AnalysisRepo(project_url) as repo:
        # TODO Add in error handling for existing commits/projects
        logger.info("Project: %s", repo.get_project_name())

        # Add project
        project = Project(project_name=repo.get_project_name())

        # Analysis tools
        tacoco_runner = TacocoRunner(repo, output_path, tacoco_path)
        parser_runner = MethodParserRunner(repo, output_path,
                                           history_slider_path)

        # Get all commits we want to run the analysis on.
        commits: List[Commit] = []
        if arguments.current:
            commits = [repo.get_current_commit()]
        elif arguments.tags is not None:
            commits = repo.iterate_tagged_commits(arguments.tags)
        elif arguments.commits is not None:
            commits = repo.iterate_commits(arguments.commits)
        else:
            print("The run was misconfigured...")
            exit(0)

        for commit in commits:
            logger.info("[INFO] Analyze commit: %s", commit.sha)

            # Run analysis and return paths to output files
            success, method_file_path, tacoco_file_path = _analysis(
                repo, tacoco_runner, parser_runner, output_path)

            if not success:
                logger.error('Analysis for %s failed...', commit.sha)
                continue

            with open(method_file_path) as method_file:
                method_parser = MethodParser()\
                    .set_commit(commit)

                methods = method_parser\
                    .parse(json.load(method_file))

                if len(methods) != 0:
                    method_parser.store(db_helper=db_handler,
                                        project=project,
                                        commit=commit,
                                        methods=methods)
                else:
                    logger.error("No methods were parsed...")

            with open(tacoco_file_path) as tacoco_file:
                tacoco_parser = TacocoParser()
                coverage = tacoco_parser\
                    .parse(json.load(tacoco_file))

                if len(coverage) != 0:
                    tacoco_parser.store(db_helper=db_handler,
                                        project=project,
                                        commit=commit,
                                        coverage=coverage)
                else:
                    logger.error("No coverage was collected.")
Exemple #5
0
 def setUp(self):
     self.resource_dir = f'.{os.path.sep}tests{os.path.sep}resources{os.path.sep}'
     self.db_helper = DatabaseHelper(':memory:')
class TestQueryCoverageData(unittest.TestCase):

    def setUp(self):
        self.db_helper = DatabaseHelper(':memory:')
        self.resource_dir = f'.{os.path.sep}tests{os.path.sep}resources{os.path.sep}'

    def tearDown(self):
        pass

    def __init_database(self, project, commit):
        method_parser : MethodParser = MethodParser()
        methods_dict: List[Dict] = self.__load_methods(project.project_name, commit.sha)
        methods = method_parser\
            .set_commit(commit)\
            .parse(methods_dict)
        
        method_parser.store(self.db_helper, project, commit, methods)
        
        tacoco_parser : TacocoParser = TacocoParser()
        coverage_dict: Dict = self.__load_coverage(project.project_name, commit.sha)
        coverage = tacoco_parser\
            .parse(coverage_dict)

        tacoco_parser.store(self.db_helper, project, commit, coverage)

    def __load_coverage(self, project_name, commit_sha) -> List[Dict]:
        coverage_matrix_file = f'{self.resource_dir}{project_name}{os.path.sep}{commit_sha}-cov-matrix.json'
        with open(coverage_matrix_file) as coverage:
            return json.load(coverage)

    def __load_methods(self, project_name, commit_sha) -> List[Dict]:
        methods_file = f'{self.resource_dir}{project_name}{os.path.sep}methods-{commit_sha}.json'
        with open(methods_file) as methods:
            return json.load(methods)

    def test_querying_coverage_primitive_hamcrest(self):
        # Given: an initialized database
        project_name = 'primitive-hamcrest'
        commit_sha = '250f63fe6e70ca6c44ee696c1937b5ccb14f2e6e'

        project = Project(project_name=project_name)
        commit = Commit(sha=commit_sha)

        self.__init_database(project, commit)

        # When: we query a specific method
        with self.db_helper.create_session() as session:
            query = MethodCoverageQuery(session)\
                .set_commit(commit)\
                .set_project(project)

            methods = query.get_methods()
            tests = query.get_tests()
            edges = query.get_coverage()

        coverage = coverage_format(methods, tests, edges)

        coverage = cluster(coverage)

        assert coverage is not None
        assert json.dumps(coverage) is not None
class TestMethodParser(unittest.TestCase):
    def setUp(self):
        self.resource_dir = f'.{os.path.sep}tests{os.path.sep}resources{os.path.sep}'
        self.db_helper = DatabaseHelper(':memory:')

    def tearDown(self):
        pass

    def load_methods(self, project_name, commit_sha) -> List[Dict]:
        methods_file = f'{self.resource_dir}{project_name}{os.path.sep}methods-{commit_sha}.json'
        with open(methods_file) as methods:
            return json.load(methods)

    def test_parsing_methods(self):
        # Given: some coverage information
        project_name = 'mid_example'
        commit_sha = 'df1bc2481a05acc3944cc1c3f637856d54cd8ba8'
        commit = Commit(sha=commit_sha)

        methods: List[Dict] = self.load_methods(project_name, commit_sha)

        # When parsing the coverage file
        parser: MethodParser = MethodParser().set_commit(commit)

        # Then: It contain 1 methods (The test methods are filtered out.)
        results = parser.parse(methods)
        assert len(results) == 1

    def test_adding_single_project_with_two_commits_to_database(self):
        # Given: some coverage information
        # Project 1
        name = 'mid_example'
        url = 'https://github.com/jajones/mid_example'

        commit_sha = 'df1bc2481a05acc3944cc1c3f637856d54cd8ba8'
        methods_dict: List[Dict] = self.load_methods(name, commit_sha)

        # Init project and commits
        project = Project(project_name=name)
        commit1 = Commit(sha='commit-1')
        commit2 = Commit(sha='commit-2')

        # First add project, and then commits
        with self.db_helper.create_session() as session:
            session.add(project)

            project.commits.append(commit1)
            project.commits.append(commit2)
            session.add_all([commit1, commit2])

            parser: MethodParser = MethodParser()
            methods1: List[Tuple[ProdMethod,
                                 ProdMethodVersion]] = parser.set_commit(
                                     commit1).parse(methods_dict)

            for method, version in methods1:
                method.project = project
                method, _ = session.add(method)

                version.method = method
                session.add(version)

            methods2: List[Tuple[ProdMethod,
                                 ProdMethodVersion]] = parser.set_commit(
                                     commit2).parse(methods_dict)

            for method, version in methods2:
                method.project = project
                method, _ = session.add(method)

                version.method = method
                session.add(version)

        assert len(self.db_helper.query(Project).all()) == 1
        assert len(self.db_helper.query(Commit).all()) == 2
        assert len(self.db_helper.query(ProdMethod).all()) == 1
        assert len(self.db_helper.query(ProdMethodVersion).all()) == 2

    def test_adding_two_projects_to_database(self):
        # Given: some coverage information
        # Project 1
        name = 'mid_example'
        commit_sha = 'df1bc2481a05acc3944cc1c3f637856d54cd8ba8'
        methods_dict: List[Dict] = self.load_methods(name, commit_sha)

        parser: MethodParser = MethodParser()

        # Init project and commits
        project1 = Project(project_name='p1')
        commit1 = Commit(sha='commit-1')
        methods1: List[Tuple[ProdMethod, ProdMethodVersion]] = parser\
            .set_commit(commit1)\
            .parse(methods_dict)

        project2 = Project(project_name='p2')
        commit2 = Commit(sha='commit-2')
        methods2: List[Tuple[ProdMethod, ProdMethodVersion]] = parser\
            .set_commit(commit2)\
            .parse(methods_dict)

        # When storing the data in the database
        parser.store(self.db_helper, project1, commit1, methods1)
        parser.store(self.db_helper, project2, commit2, methods2)

        # Then:
        assert len(self.db_helper.query(Project).all()) == 2
        assert len(self.db_helper.query(Commit).all()) == 2
        assert len(self.db_helper.query(ProdMethod).all()) == 2
        assert len(self.db_helper.query(ProdMethodVersion).all()) == 2