diff options
author | mbligh <mbligh@592f7852-d20e-0410-864c-8624ca9c26a4> | 2008-04-16 23:12:12 +0000 |
---|---|---|
committer | mbligh <mbligh@592f7852-d20e-0410-864c-8624ca9c26a4> | 2008-04-16 23:12:12 +0000 |
commit | 244de5669f672711af7023ab6e3967d8652a0661 (patch) | |
tree | 0895acaa4b9f342c028b02b6c2639c1a484c4350 | |
parent | 7344c0955705832c436ac8affce92f8ed59509c5 (diff) |
implementing request: reasons of failure should be displayed in non header cells
- reasons are retrieved from the database and displayed in cells only when
either columns or rows are grouped by status (because of performance reasons)
- reasons are displayed in cell below GOOD / TOTAL ratio and only if GOOD is
less then TOTAL i.e. when some problems occured
From: Vladimir Samarskiy <vsamarsk@google.com>
Signed-off-by: Martin Bligh <mbligh@google.com>
git-svn-id: svn://test.kernel.org/autotest/trunk@1441 592f7852-d20e-0410-864c-8624ca9c26a4
-rwxr-xr-x | tko/compose_query.cgi | 18 | ||||
-rwxr-xr-x | tko/display.py | 22 | ||||
-rwxr-xr-x | tko/frontend.py | 45 |
3 files changed, 66 insertions, 19 deletions
diff --git a/tko/compose_query.cgi b/tko/compose_query.cgi index 8b66145a..d609fa2e 100755 --- a/tko/compose_query.cgi +++ b/tko/compose_query.cgi @@ -238,7 +238,21 @@ def gen_matrix(): return [[display.box(msg)]] try: - test_data = frontend.get_matrix_data(db_obj, column, row, where) + ## Unfortunately, we can not request reasons of failure always + ## because it may result in an inflated size of data transfer + ## (at the moment we fetch 500 bytes of reason descriptions into + ## each cell ) + ## If 'status' in [row,column] then either width or height + ## of the table <=7, hence table is not really 2D, and + ## query_reason is relatively save. + ## At the same time view when either rows or columns grouped + ## by status is when users need reasons of failures the most. + + ## TO DO: implement [Show/Hide reasons] button or link in + ## all views and make thorough performance testing + test_data = frontend.get_matrix_data(db_obj, column, row, where, + query_reasons = ('status' in [row,column]) + ) except db.MySQLTooManyRows, error: return [[display.box(str(error))]] @@ -280,7 +294,7 @@ def gen_matrix(): if x==datetime.datetime(1970,1,1): x = None if y==datetime.datetime(1970,1,1): y = None try: - box_data = test_data.data[x][y].status_count + box_data = test_data.data[x][y] except: cur_row.append(display.box(None, None)) continue diff --git a/tko/display.py b/tko/display.py index 6458e072..78688d69 100755 --- a/tko/display.py +++ b/tko/display.py @@ -147,19 +147,29 @@ def shade_from_status_count(status_count): return shade -def status_html(db, status_count, shade): +def status_html(db, box_data, shade): """ status_count: dict mapping from status (integer key) to count eg. { 'GOOD' : 4, 'FAIL' : 1 } """ + status_count = box_data.status_count if 6 in status_count.keys(): html = "%d / %d " \ %(status_count[6],sum(status_count.values())) else: html = "%d / %d " % \ (0, sum(status_count.values())) - tooltip = "" + if box_data.reasons_list: + box_data.reasons_list.sort() + for reason in box_data.reasons_list: + reason = reason.replace('<br>','\n') + reason = reason.replace('<','[').replace('>',']') + reason = reason.replace('|','\n').replace('&',' AND ') + reason = reason.replace('\n','<br>') + html += '<br>' + reason + + tooltip = "" for status in sorted(status_count.keys(), reverse = True): status_word = db.status_word[status] tooltip += "%d %s " % (status_count[status], status_word) @@ -182,20 +192,22 @@ def status_count_box(db, tests, link = None): return status_precounted_box(db, status_count, link) -def status_precounted_box(db, status_count, link = None): +def status_precounted_box(db, box_data, link = None): """ Display a ratio of total number of GOOD tests to total number of all tests in the group of tests. More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips - """ + """ + status_count = box_data.status_count if not status_count: return box(None, None) shade = shade_from_status_count(status_count) - html,tooltip = status_html(db, status_count, shade) + html,tooltip = status_html(db, box_data, shade) precounted_box = box(html, shade, False, link, tooltip) return precounted_box + def print_table(matrix): """ matrix: list of lists of boxes, giving a matrix of data diff --git a/tko/frontend.py b/tko/frontend.py index 0861bcbd..d496fe9d 100755 --- a/tko/frontend.py +++ b/tko/frontend.py @@ -20,11 +20,12 @@ class status_cell: def __init__(self): # Count is a dictionary: status -> count of tests with status self.status_count = {} + self.reasons_list = [] self.job_tag = None self.job_tag_count = 0 - def add(self, status, count, job_tags): + def add(self, status, count, job_tags, reasons = None): assert count > 0 self.job_tag = job_tags @@ -33,21 +34,31 @@ class status_cell: self.job_tag = None self.status_count[status] = count + ### status == 6 means 'GOOD' + if status != 6: + ## None implies sorting problems and extra CRs in a cell + if reasons: + self.reasons_list.append(reasons) class status_data: - def __init__(self, sql_rows, x_field, y_field): + def __init__(self, sql_rows, x_field, y_field, query_reasons = False): data = {} y_values = set() # Walk through the query, filing all results by x, y info - for (x, y, status, count, job_tags) in sql_rows: + for row in sql_rows: + if query_reasons: + (x,y, status, count, job_tags, reasons) = row + else: + (x,y, status, count, job_tags) = row + reasons = None if not data.has_key(x): data[x] = {} if not data[x].has_key(y): y_values.add(y) data[x][y] = status_cell() - data[x][y].add(status, count, job_tags) + data[x][y].add(status, count, job_tags, reasons) # 2-d hash of data - [x-value][y-value] self.data = data @@ -61,18 +72,24 @@ class status_data: raise db.MySQLTooManyRows(msg) -def get_matrix_data(db_obj, x_axis, y_axis, where = None): +def get_matrix_data(db_obj, x_axis, y_axis, where = None, + query_reasons = False): # Searches on the test_view table - x_axis and y_axis must both be # column names in that table. x_field = test_view_field_dict[x_axis] y_field = test_view_field_dict[y_axis] - fields = ( '%s, %s, status, COUNT(status), ' + - 'LEFT(GROUP_CONCAT(job_tag), 100)' # limit what's returned - ) % (x_field, y_field) + query_fields_list = [x_field, y_field, 'status','COUNT(status)'] + query_fields_list.append("LEFT(GROUP_CONCAT(job_tag),100)") + if query_reasons: + query_fields_list.append( + "LEFT(GROUP_CONCAT(DISTINCT reason SEPARATOR '|'),500)" + ) + fields = ','.join(query_fields_list) + group_by = '%s, %s, status' % (x_field, y_field) rows = db_obj.select(fields, 'test_view', where=where, group_by=group_by, max_rows = MAX_RECORDS) - return status_data(rows, x_field, y_field) + return status_data(rows, x_field, y_field, query_reasons) # Dictionary used simply for fast lookups from short reference names for users @@ -91,6 +108,7 @@ test_view_field_dict = { 'time_daily' : 'DATE(test_finished_time)' } + def smart_sort(list, field): if field == 'kernel_printable': def kernel_encode(kernel): @@ -130,7 +148,8 @@ class group: def tests(self, where = {}): values = [self.name] - sql = 't inner join machines m on m.machine_idx=t.machine_idx where m.machine_group=%s' + sql = 't inner join machines m on m.machine_idx=t.machine_idx' + sql += ' where m.machine_group=%s' for key in where.keys(): sql += ' and %s=%%s' % key values.append(where[key]) @@ -178,7 +197,8 @@ class test: fields = ['test_idx', 'job_idx', 'test', 'subdir', 'kernel_idx', 'status', 'reason', 'machine_idx'] tests = [] - for row in db.select(','.join(fields), 'tests', where, wherein,distinct): + for row in db.select(','.join(fields), 'tests', where, + wherein,distinct): tests.append(klass(db, *row)) return tests @@ -192,7 +212,8 @@ class test: return [klass(db, *row) for row in rows] - def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx, status_num, reason, machine_idx): + def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx, + status_num, reason, machine_idx): self.idx = test_idx self.job = job(db, job_idx) self.testname = testname |