Skip to content

Commit

Permalink
Checker summary view
Browse files Browse the repository at this point in the history
  • Loading branch information
csordasmarton committed Sep 4, 2017
1 parent 147a366 commit d287779
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 42 deletions.
15 changes: 11 additions & 4 deletions api/report_server.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ struct RunReportCount{
}
typedef list<RunReportCount> RunReportCounts

struct CheckerDataCount {
1: string name, // Checker name
2: shared.Severity severity, // Severity level of the checker
3: i64 count // Checker count
}
typedef list<CheckerDataCount> CheckerDataCounts

struct ReviewData{
1: shared.ReviewStatus status,
2: string comment,
Expand Down Expand Up @@ -412,10 +419,10 @@ service codeCheckerDBAccess {
// If the run id list is empty the metrics will be counted
// for all of the runs and in compare mode all of the runs
// will be used as a baseline excluding the runs in compare data.
map<string, i64> getCheckerCounts(1: list<i64> runIds,
2: ReportFilter_v2 reportFilter,
3: CompareData cmpData)
throws (1: shared.RequestFailed requestError),
CheckerDataCounts getCheckerCounts(1: list<i64> runIds,
2: ReportFilter_v2 reportFilter,
3: CompareData cmpData)
throws (1: shared.RequestFailed requestError),


//============================================
Expand Down
76 changes: 76 additions & 0 deletions libcodechecker/cmd/cmd_line_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,82 @@ def handle_list_results(args):
print(twodim_to_str(args.output_format, header, rows))


def handle_statistic_results(args):
def getStatistics(client, run_ids, field, values):
report_filter = codeCheckerDBAccess.ttypes.ReportFilter_v2()
setattr(report_filter, field, values)
checkers = client.getCheckerCounts(run_ids,
report_filter,
None)

return dict((res.name, res.count) for res in checkers)

def checkerCount(dict, key):
return dict[key] if key in dict else 0

client = setup_client(args.product_url)

run_info = check_run_names(client, [args.name])

run_id, _ = run_info.get(args.name)
run_ids = None if run_id is None else [run_id]

all_checkers_report_filter = codeCheckerDBAccess.ttypes.ReportFilter_v2()
all_checkers = client.getCheckerCounts(run_ids, all_checkers_report_filter,
None)
all_checkers_dict = dict((res.name, res) for res in all_checkers)

unreviewed_checkers = getStatistics(client, run_ids, 'reviewStatus',
[shared.ttypes.ReviewStatus.UNREVIEWED])

confirmed_checkers = getStatistics(client, run_ids, 'reviewStatus',
[shared.ttypes.ReviewStatus.CONFIRMED])

false_checkers = getStatistics(client, run_ids, 'reviewStatus',
[shared.ttypes.ReviewStatus.FALSE_POSITIVE])

wontfix_checkers = getStatistics(client, run_ids, 'reviewStatus',
[shared.ttypes.ReviewStatus.WONT_FIX])

resolved_checkers = getStatistics(client, run_ids, 'detectionStatus',
[shared.ttypes.DetectionStatus.RESOLVED])

all_results = []
for key, checker_data in sorted(all_checkers_dict.items(),
key=lambda x: x[1].severity,
reverse=True):
all_results.append(dict(
checker=key,
severity = \
shared.ttypes.Severity._VALUES_TO_NAMES[checker_data.severity],
reports=checker_data.count,
unreviewed=checkerCount(unreviewed_checkers, key),
confirmed=checkerCount(confirmed_checkers, key),
false_positive=checkerCount(false_checkers, key),
wont_fix=checkerCount(wontfix_checkers, key),
resolved=checkerCount(resolved_checkers, key),
))

if args.output_format == 'json':
print(CmdLineOutputEncoder().encode(all_results))
else:
header = ['Checker', 'Severity', 'Reports', 'Unreviewed', 'Confirmed',
'False positive', "Won't fix", 'Resolved']

rows = []
for stat in all_results:
rows.append((stat['checker'],
stat['severity'],
str(stat['reports']),
str(stat['unreviewed']),
str(stat['confirmed']),
str(stat['false_positive']),
str(stat['wont_fix']),
str(stat['resolved'])))

print(twodim_to_str(args.output_format, header, rows))


def handle_diff_results(args):
def getDiffResults(getterFn, baseid, newid):
report_filter = [
Expand Down
9 changes: 9 additions & 0 deletions libcodechecker/libhandlers/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,15 @@ def add_arguments_to_parser(parser):
results.set_defaults(func=cmd_line_client.handle_list_results)
__add_common_arguments(results, has_matrix_output=True)

results = subcommands.add_parser(
'statistics',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description="Show checker statistics.",
help="Show statistics for individual checkers.")
__register_results(results)
results.set_defaults(func=cmd_line_client.handle_statistic_results)
__add_common_arguments(results, has_matrix_output=True)

diff = subcommands.add_parser(
'diff',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
Expand Down
12 changes: 8 additions & 4 deletions libcodechecker/server/client_db_access_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,7 @@ def getCheckerCounts(self, run_ids, report_filter, cmp_data):
for all of the runs and in compare mode all of the runs
will be used as a baseline excluding the runs in compare data.
"""
results = {}
results = []
session = self.__Session()
try:

Expand All @@ -1341,7 +1341,7 @@ def getCheckerCounts(self, run_ids, report_filter, cmp_data):

count_expr = func.count(literal_column('*'))

q = session.query(Report.checker_id, count_expr) \
q = session.query(Report.checker_id, Report.severity, count_expr) \
.filter(Report.run_id.in_(run_ids)) \
.outerjoin(File,
Report.file_id == File.id) \
Expand All @@ -1352,9 +1352,13 @@ def getCheckerCounts(self, run_ids, report_filter, cmp_data):
if cmp_data:
q = q.filter(Report.bug_id.in_(diff_hashes))

checker_ids = q.group_by(Report.checker_id).all()
q = q.group_by(Report.checker_id).all()

results = dict(checker_ids)
for name, severity, count in q:
checker_count = CheckerDataCount(name=name,
severity=severity,
count=count)
results.append(checker_count)

except Exception as ex:
LOG.error(ex)
Expand Down
29 changes: 21 additions & 8 deletions tests/functional/diff/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,11 @@ def test_get_diff_checker_counts(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
None,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# core.CallAndMessage is the new checker.
test_res = {"core.CallAndMessage": 5}
self.assertDictEqual(diff_res, test_res)
self.assertDictEqual(diff_dict, test_res)

def test_get_diff_checker_counts_core_new(self):
"""
Expand All @@ -265,9 +266,11 @@ def test_get_diff_checker_counts_core_new(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
report_filter,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# core.CallAndMessage is the new checker.
test_res = {"core.CallAndMessage": 5}
self.assertDictEqual(diff_res, test_res)
self.assertDictEqual(diff_dict, test_res)

def test_get_diff_checker_counts_unix_resolved(self):
"""
Expand All @@ -282,9 +285,11 @@ def test_get_diff_checker_counts_unix_resolved(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
report_filter,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# Resolved core checkers.
test_res = {'core.StackAddressEscape': 3}
self.assertDictEqual(diff_res, test_res)
self.assertDictEqual(diff_dict, test_res)

def test_get_diff_checker_counts_core_unresolved(self):
"""
Expand All @@ -299,9 +304,11 @@ def test_get_diff_checker_counts_core_unresolved(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
report_filter,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# Unresolved core checkers.
test_res = {'core.NullDereference': 4, 'core.DivideZero': 5}
self.assertDictContainsSubset(test_res, diff_res)
self.assertDictContainsSubset(test_res, diff_dict)

def test_get_diff_checker_counts_all_unresolved(self):
"""
Expand All @@ -316,14 +323,16 @@ def test_get_diff_checker_counts_all_unresolved(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
None,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# All unresolved checkers.
test_res = {'core.DivideZero': 5,
'core.NullDereference': 4,
'cplusplus.NewDelete': 5,
'deadcode.DeadStores': 5,
'unix.Malloc': 1}

self.assertDictContainsSubset(diff_res, test_res)
self.assertDictContainsSubset(diff_dict, test_res)

def test_get_diff_severity_counts_all_unresolved(self):
"""
Expand Down Expand Up @@ -423,8 +432,10 @@ def test_get_diff_res_types_resolved(self):
diff_res = self._cc_client.getCheckerCounts([base_run_id],
None,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

test_res = {'core.StackAddressEscape': 3}
self.assertDictEqual(diff_res, test_res)
self.assertDictEqual(diff_dict, test_res)

def test_get_diff_res_types_unresolved(self):
"""
Expand All @@ -444,13 +455,14 @@ def test_get_diff_res_types_unresolved(self):
self._cc_client.getCheckerCounts([base_run_id],
None,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

test_res = {'cplusplus.NewDelete': 5,
'deadcode.DeadStores': 5,
'unix.Malloc': 1,
'core.NullDereference': 4,
'core.DivideZero': 5}
self.assertDictEqual(diff_res, test_res)
self.assertDictEqual(diff_dict, test_res)

def test_get_diff_res_types_unresolved_filter(self):
"""
Expand All @@ -472,9 +484,10 @@ def test_get_diff_res_types_unresolved_filter(self):
self._cc_client.getCheckerCounts([base_run_id],
checker_filter,
cmp_data)
diff_dict = dict((res.name, res.count) for res in diff_res)

# There should be only one result for each checker name.
self.assertEqual(test_result_count, diff_res[checker_name])
self.assertEqual(test_result_count, diff_dict[checker_name])

def test_local_compare_res_count_new(self):
"""
Expand Down
32 changes: 23 additions & 9 deletions tests/functional/report_viewer_api/test_report_counting.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ def test_run1_all_checkers(self):
checker_counts = self._cc_client.getCheckerCounts([runid],
None,
None)
checkers_dict = dict((res.name, res.count) for res in checker_counts)

self.assertGreaterEqual(len(checker_counts), len(self.run1_checkers))
self.assertDictContainsSubset(self.run1_checkers, checker_counts)
self.assertDictContainsSubset(self.run1_checkers, checkers_dict)

def test_run1_core_checkers(self):
"""
Expand All @@ -131,11 +132,13 @@ def test_run1_core_checkers(self):
checker_counts = self._cc_client.getCheckerCounts([runid],
core_filter,
None)
checkers_dict = dict((res.name, res.count) for res in checker_counts)

core_checkers = {k: v for k, v in self.run1_checkers.items()
if "core." in k}

self.assertGreaterEqual(len(checker_counts), len(core_checkers))
self.assertDictContainsSubset(core_checkers, checker_counts)
self.assertDictContainsSubset(core_checkers, checkers_dict)

def test_run2_all_checkers(self):
"""
Expand All @@ -145,9 +148,10 @@ def test_run2_all_checkers(self):
checker_counts = self._cc_client.getCheckerCounts([runid],
None,
None)
checkers_dict = dict((res.name, res.count) for res in checker_counts)

self.assertGreaterEqual(len(checker_counts), len(self.run2_checkers))
self.assertDictContainsSubset(self.run2_checkers, checker_counts)
self.assertDictContainsSubset(self.run2_checkers, checkers_dict)

def test_run1_run2_all_checkers(self):
"""
Expand All @@ -156,13 +160,14 @@ def test_run1_run2_all_checkers(self):
checker_counts = self._cc_client.getCheckerCounts(self._runids,
None,
None)
checkers_dict = dict((res.name, res.count) for res in checker_counts)

r1_checkers = Counter(self.run1_checkers)
r2_checkers = Counter(self.run2_checkers)
all_checkers = dict(r1_checkers + r2_checkers)

self.assertEqual(len(checker_counts), len(all_checkers))
self.assertDictEqual(checker_counts, all_checkers)
self.assertDictEqual(checkers_dict, all_checkers)

def test_run1_run2_core_checkers(self):
"""
Expand All @@ -172,6 +177,7 @@ def test_run1_run2_core_checkers(self):
checker_counts = self._cc_client.getCheckerCounts(self._runids,
core_filter,
None)
checkers_dict = dict((res.name, res.count) for res in checker_counts)

core_checkers_r1 = {k: v for k, v in self.run1_checkers.items()
if "core." in k}
Expand All @@ -184,7 +190,7 @@ def test_run1_run2_core_checkers(self):
all_core = dict(r1_core + r2_core)

self.assertGreaterEqual(len(checker_counts), len(all_core))
self.assertDictContainsSubset(all_core, checker_counts)
self.assertDictContainsSubset(all_core, checkers_dict)

def test_run1_all_severity(self):
"""
Expand Down Expand Up @@ -457,14 +463,16 @@ def test_run1_detection_status_new(self):
new_reports = self._cc_client.getCheckerCounts([runid],
new_filter,
None)
checkers_dict = dict((res.name, res.count) for res in new_reports)

new = {'core.CallAndMessage': 5,
'core.StackAddressEscape': 3,
'cplusplus.NewDelete': 5,
'core.NullDereference': 4,
'core.DivideZero': 5,
'deadcode.DeadStores': 5,
'unix.Malloc': 1}
self.assertDictEqual(new, new_reports)
self.assertDictEqual(new, checkers_dict)

def test_run1_detection_status_resolved(self):
"""
Expand All @@ -477,7 +485,9 @@ def test_run1_detection_status_resolved(self):
resolved_reports = self._cc_client.getCheckerCounts([runid],
resolved_filter,
None)
self.assertDictEqual({}, resolved_reports)
checkers_dict = dict((res.name, res.count) for res in resolved_reports)

self.assertDictEqual({}, checkers_dict)

def test_run1_detection_status_unresolved(self):
"""
Expand All @@ -491,7 +501,10 @@ def test_run1_detection_status_unresolved(self):
self._cc_client.getCheckerCounts([runid],
unresolved_filter,
None)
self.assertDictEqual({}, unresolved_reports)
checkers_dict = dict((res.name, res.count)
for res in unresolved_reports)

self.assertDictEqual({}, checkers_dict)

def test_run1_detection_status_repoened(self):
"""
Expand All @@ -504,7 +517,8 @@ def test_run1_detection_status_repoened(self):
reopened_reports = self._cc_client.getCheckerCounts([runid],
reopen_filter,
None)
self.assertDictEqual({}, reopened_reports)
checkers_dict = dict((res.name, res.count) for res in reopened_reports)
self.assertDictEqual({}, checkers_dict)

def test_all_run_report_counts(self):
"""
Expand Down
Loading

0 comments on commit d287779

Please sign in to comment.