Exemple #1
0
def get_tests_summary_with_wildcards(job_names):
    """
    Like get_tests_summary(job_names) but allowing wildcards.
    @param job_names: Names of the suite jobs to get the summary from.
    @returns: A summary of all the passed and failed tests per suite job.
    """
    query = '''SELECT IF (status = 'GOOD', status, 'FAIL')
                   AS test_status, COUNT(*) num
                 FROM tko_test_view_2
                 WHERE job_name LIKE %s
                   AND test_name <> 'SERVER_JOB'
                   AND test_name NOT LIKE 'CLIENT_JOB%%'
                   AND status <> 'TEST_NA'
                 GROUP BY IF (status = 'GOOD', status, 'FAIL')'''

    summaries = {}
    cursor = readonly_connection.cursor()
    for job_name in job_names:
        cursor.execute(query, job_name)
        results = rpc_utils.fetchall_as_list_of_dicts(cursor)
        summary = summaries.setdefault(job_name, {})
        for result in results:
            status = 'passed' if result['test_status'] == 'GOOD' else 'failed'
            summary[status] = result['num']

    return summaries
Exemple #2
0
def get_tests_summary(job_names):
    """
    Gets the count summary of all passed and failed tests per suite.
    @param job_names: Names of the suite jobs to get the summary from.
    @returns: A summary of all the passed and failed tests per suite job.
    """
    # Take advantage of Django's literal escaping to prevent SQL injection
    sql_list = ','.join(['%s'] * len(job_names))
    query = ('''SELECT job_name, IF (status = 'GOOD', status, 'FAIL')
                   AS test_status, COUNT(*) num
                 FROM tko_test_view_2
                 WHERE job_name IN (%s)
                   AND test_name <> 'SERVER_JOB'
                   AND test_name NOT LIKE 'CLIENT_JOB%%%%'
                   AND status <> 'TEST_NA'
                 GROUP BY job_name, IF (status = 'GOOD', status, 'FAIL')''' %
             sql_list)

    cursor = readonly_connection.cursor()
    cursor.execute(query, job_names)
    results = rpc_utils.fetchall_as_list_of_dicts(cursor)

    summaries = {}
    for result in results:
        status = 'passed' if result['test_status'] == 'GOOD' else 'failed'
        summary = summaries.setdefault(result['job_name'], {})
        summary[status] = result['num']

    return summaries
Exemple #3
0
    def get_num_groups(self, query, group_by):
        """Gets the number of distinct groups for a query.

        @param query: The query to use.
        @param group_by: The fields by which to group.

        @return The number of distinct groups for the given query grouped by
            the fields in group_by.

        """
        sql, params = self._get_num_groups_sql(query, group_by)
        cursor = readonly_connection.cursor()
        cursor.execute(sql, params)
        return self._cursor_rowcount(cursor)
Exemple #4
0
    def execute_group_query(self, query, group_by):
        """Performs the given query grouped by the specified fields.

        The given query's extra select fields are added.

        @param query: The query to perform.
        @param group_by: The fields by which to group.

        @return A list of dicts, where each dict corresponds to single row and
            contains a key for each grouped field as well as all of the extra
            select fields.

        """
        sql, params = self._get_group_query_sql(query, group_by)
        cursor = readonly_connection.cursor()
        cursor.execute(sql, params)
        field_names = self._get_column_names(cursor)
        row_dicts = [dict(zip(field_names, row)) for row in cursor.fetchall()]
        return row_dicts
Exemple #5
0
def _create_qual_histogram_helper(plot_info, extra_text=None):
    """\
    Create a machine qualification histogram of the given data.

    plot_info: a QualificationHistogram
    extra_text: text to show at the upper-left of the graph

    TODO(showard): move much or all of this into methods on
    QualificationHistogram
    """
    cursor = readonly_connection.cursor()
    cursor.execute(plot_info.query)

    if not cursor.rowcount:
        raise NoDataError('query did not return any data')

    # Lists to store the plot data.
    # hist_data store tuples of (hostname, pass_rate) for machines that have
    #     pass rates between 0 and 100%, exclusive.
    # no_tests is a list of machines that have run none of the selected tests
    # no_pass is a list of machines with 0% pass rate
    # perfect is a list of machines with a 100% pass rate
    hist_data = []
    no_tests = []
    no_pass = []
    perfect = []

    # Construct the lists of data to plot
    for hostname, total, good in cursor.fetchall():
        if total == 0:
            no_tests.append(hostname)
            continue

        if good == 0:
            no_pass.append(hostname)
        elif good == total:
            perfect.append(hostname)
        else:
            percentage = 100.0 * good / total
            hist_data.append((hostname, percentage))

    interval = plot_info.interval
    bins = range(0, 100, interval)
    if bins[-1] != 100:
        bins.append(bins[-1] + interval)

    figure, height = _create_figure(_SINGLE_PLOT_HEIGHT)
    subplot = figure.add_subplot(1, 1, 1)

    # Plot the data and get all the bars plotted
    _, _, bars = subplot.hist([data[1] for data in hist_data],
                              bins=bins,
                              align='left')
    bars += subplot.bar([-interval],
                        len(no_pass),
                        width=interval,
                        align='center')
    bars += subplot.bar([bins[-1]],
                        len(perfect),
                        width=interval,
                        align='center')
    bars += subplot.bar([-3 * interval],
                        len(no_tests),
                        width=interval,
                        align='center')

    buckets = [(bin, min(bin + interval, 100)) for bin in bins[:-1]]
    # set the x-axis range to cover all the normal bins plus the three "special"
    # ones - N/A (3 intervals left), 0% (1 interval left) ,and 100% (far right)
    subplot.set_xlim(-4 * interval, bins[-1] + interval)
    subplot.set_xticks([-3 * interval, -interval] + bins + [100 + interval])
    subplot.set_xticklabels(['N/A', '0%'] +
                            ['%d%% - <%d%%' % bucket
                             for bucket in buckets] + ['100%'],
                            rotation=90,
                            size='small')

    # Find the coordinates on the image for each bar
    x = []
    y = []
    for bar in bars:
        x.append(bar.get_x())
        y.append(bar.get_height())
    f = subplot.plot(x, y, linestyle='None')[0]
    upper_left_coords = f.get_transform().transform(zip(x, y))
    bottom_right_coords = f.get_transform().transform([(x_val + interval, 0)
                                                       for x_val in x])

    # Set the title attributes
    titles = [
        '%d%% - <%d%%: %d machines' % (bucket[0], bucket[1], y_val)
        for bucket, y_val in zip(buckets, y)
    ]
    titles.append('0%%: %d machines' % len(no_pass))
    titles.append('100%%: %d machines' % len(perfect))
    titles.append('N/A: %d machines' % len(no_tests))

    # Get the hostnames for each bucket in the histogram
    names_list = [
        _get_hostnames_in_bucket(hist_data, bucket) for bucket in buckets
    ]
    names_list += [no_pass, perfect]

    if plot_info.filter_string:
        plot_info.filter_string += ' AND '

    # Construct the list of drilldown parameters to be passed when the user
    # clicks on the bar.
    params = []
    for names in names_list:
        if names:
            hostnames = ','.join(_quote(hostname) for hostname in names)
            hostname_filter = 'hostname IN (%s)' % hostnames
            full_filter = plot_info.filter_string + hostname_filter
            params.append({'type': 'normal', 'filterString': full_filter})
        else:
            params.append({'type': 'empty'})

    params.append({'type': 'not_applicable', 'hosts': '<br />'.join(no_tests)})

    area_data = [
        dict(left=ulx,
             top=height - uly,
             right=brx,
             bottom=height - bry,
             title=title,
             callback=plot_info.drilldown_callback,
             callback_arguments=param_dict)
        for (ulx, uly), (brx, bry), title, param_dict in zip(
            upper_left_coords, bottom_right_coords, titles, params)
    ]

    # TODO(showard): extract these magic numbers to named constants
    if extra_text:
        figure.text(.1, .95, extra_text, size='xx-small')

    return (figure, area_data)
Exemple #6
0
def _create_metrics_plot_helper(plot_info, extra_text=None):
    """
    Create a metrics plot of the given plot data.
    plot_info: a MetricsPlot object.
    extra_text: text to show at the uppper-left of the graph

    TODO(showard): move some/all of this logic into methods on MetricsPlot
    """
    query = plot_info.query_dict['__main__']
    cursor = readonly_connection.cursor()
    cursor.execute(query)

    if not cursor.rowcount:
        raise NoDataError('query did not return any data')
    rows = cursor.fetchall()
    # "transpose" rows, so columns[0] is all the values from the first column,
    # etc.
    columns = zip(*rows)

    plots = []
    labels = [str(label) for label in columns[0]]
    needs_resort = (cursor.description[0][0] == 'kernel')

    # Collect all the data for the plot
    col = 1
    while col < len(cursor.description):
        y = columns[col]
        label = cursor.description[col][0]
        col += 1
        if (col < len(cursor.description)
                and 'errors-' + label == cursor.description[col][0]):
            errors = columns[col]
            col += 1
        else:
            errors = None
        if needs_resort:
            y = _resort(labels, y)
            if errors:
                errors = _resort(labels, errors)

        x = [index for index, value in enumerate(y) if value is not None]
        if not x:
            raise NoDataError('No data for series ' + label)
        y = [y[i] for i in x]
        if errors:
            errors = [errors[i] for i in x]
        plots.append({'label': label, 'x': x, 'y': y, 'errors': errors})

    if needs_resort:
        labels = _resort(labels, labels)

    # Normalize the data if necessary
    normalize_to = plot_info.normalize_to
    if normalize_to == 'first' or normalize_to.startswith('x__'):
        if normalize_to != 'first':
            baseline = normalize_to[3:]
            try:
                baseline_index = labels.index(baseline)
            except ValueError:
                raise ValidationError(
                    {'Normalize': 'Invalid baseline %s' % baseline})
        for plot in plots:
            if normalize_to == 'first':
                plot_index = 0
            else:
                try:
                    plot_index = plot['x'].index(baseline_index)
                # if the value is not found, then we cannot normalize
                except ValueError:
                    raise ValidationError({
                        'Normalize': ('%s does not have a value for %s' %
                                      (plot['label'], normalize_to[3:]))
                    })
            base_values = [plot['y'][plot_index]] * len(plot['y'])
            if plot['errors']:
                base_errors = [plot['errors'][plot_index]] * len(
                    plot['errors'])
            plot['y'], plot['errors'] = _normalize(plot['y'], plot['errors'],
                                                   base_values, None
                                                   or base_errors)

    elif normalize_to.startswith('series__'):
        base_series = normalize_to[8:]
        _normalize_to_series(plots, base_series)

    # Call the appropriate function to draw the line or bar plot
    if plot_info.is_line:
        figure, area_data = _create_line(plots, labels, plot_info)
    else:
        figure, area_data = _create_bar(plots, labels, plot_info)

    # TODO(showard): extract these magic numbers to named constants
    if extra_text:
        text_y = .95 - .0075 * len(plots)
        figure.text(.1, text_y, extra_text, size='xx-small')

    return (figure, area_data)
Exemple #7
0
def execute_query_with_param(query, param):
    cursor = readonly_connection.cursor()
    cursor.execute(query, param)
    return cursor.fetchall()