pjs/webtools/litmus/Litmus/DB/Testresult.pm

398 строки
17 KiB
Perl
Executable File

# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License
# at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and
# limitations under the License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testresult;
use strict;
use base 'Litmus::DBI';
use Date::Manip;
use Time::Piece;
use Time::Seconds;
use Memoize;
our $_num_results_default = 15;
Litmus::DB::Testresult->table('test_results');
Litmus::DB::Testresult->columns(All => qw/testresult_id test_id last_updated submission_time user_id platform_id opsys_id branch_id buildid user_agent result_id build_type_id machine_name exit_status_id duration_ms talkback_id valid vetted validated_by_user_id vetted_by_user_id validated_timestamp vetted_timestamp locale_abbrev/);
Litmus::DB::Testresult->column_alias("testresult_id", "testresultid");
Litmus::DB::Testresult->column_alias("test_id", "testid");
Litmus::DB::Testresult->column_alias("test_id", "test");
Litmus::DB::Testresult->column_alias("submission_time", "timestamp");
Litmus::DB::Testresult->column_alias("user_id", "user");
Litmus::DB::Testresult->column_alias("platform_id", "platform");
Litmus::DB::Testresult->column_alias("opsys_id", "opsys");
Litmus::DB::Testresult->column_alias("branch_id", "branch");
Litmus::DB::Testresult->column_alias("user_agent", "useragent");
Litmus::DB::Testresult->column_alias("result_id", "result");
Litmus::DB::Testresult->column_alias("build_type_id", "build_type");
Litmus::DB::Testresult->column_alias("exit_status_id", "exit_status");
Litmus::DB::Testresult->column_alias("validity_id", "validity");
Litmus::DB::Testresult->column_alias("vetting_status_id", "vetting_status");
Litmus::DB::Testresult->column_alias("locale_abbrev", "locale");
Litmus::DB::Testresult->has_a(platform => "Litmus::DB::Platform");
Litmus::DB::Testresult->has_a(opsys => "Litmus::DB::Opsys");
Litmus::DB::Testresult->has_a(branch => "Litmus::DB::Branch");
Litmus::DB::Testresult->has_a(testid => "Litmus::DB::Test");
Litmus::DB::Testresult->has_a(result => "Litmus::DB::Result");
Litmus::DB::Testresult->has_a(user => "Litmus::DB::User");
Litmus::DB::Testresult->has_a(useragent => "Litmus::UserAgentDetect");
Litmus::DB::Testresult->has_a(build_type => "Litmus::DB::BuildType");
Litmus::DB::Testresult->has_a(exit_status => "Litmus::DB::ExitStatus");
Litmus::DB::Testresult->has_a(locale => "Litmus::DB::Locale");
Litmus::DB::Testresult->has_many("logs" => "Litmus::DB::Log", {order_by => 'submission_time'});
Litmus::DB::Testresult->has_many(comments => "Litmus::DB::Comment", {order_by => 'comment_id ASC, submission_time ASC'});
Litmus::DB::Testresult->has_many(bugs => "Litmus::DB::Resultbug", {order_by => 'bug_id ASC, submission_time DESC'});
Litmus::DB::Testresult->autoinflate(dates => 'Time::Piece');
Litmus::DB::Testresult->set_sql(DefaultTestResults => qq{
SELECT tr.testresult_id,tr.test_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email
FROM test_results tr, tests t, platforms p, opsyses o, branches b, products
pr, test_result_status_lookup trsl, test_groups tg, subgroups sg, users u
WHERE tr.test_id=t.test_id AND tr.platform_id=p.platform_id AND tr.opsys_id=o.opsys_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_id=trsl.result_status_id AND t.subgroup_id=sg.subgroup_id AND sg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id
ORDER BY tr.submission_time DESC
LIMIT $_num_results_default
});
Litmus::DB::Testresult->set_sql(CommonResults => qq{
SELECT COUNT(tr.test_id) AS num_results, tr.test_id, t.summary, MAX(tr.submission_time) AS most_recent, MAX(tr.testresult_id) AS max_id
FROM test_results tr, tests t, test_result_status_lookup trsl
WHERE tr.test_id=t.test_id AND tr.result_id=trsl.result_status_id AND trsl.class_name=?
GROUP BY tr.test_id
ORDER BY num_results DESC, tr.testresult_id DESC
LIMIT 15
});
#########################################################################
# for historical reasons, note() is a shorthand way of saying "the text of
# the first comment on this result if that comment was submitted by the
# result submitter"
#########################################################################
sub note {
my $self = shift;
my @comments = $self->comments();
if (@comments && $comments[0] &&
$comments[0]->user() == $self->user()) {
return $comments[0]->comment();
} else {
return undef;
}
}
#########################################################################
# is this test result recent?
memoize('isrecent', NORMALIZER => sub {my $a=shift; return $a->testresultid()});
sub isrecent {
my $self = shift;
my $age = $self->age();
# get the number of days a test result is valid for this group:
my $expdays = $self->testid()->subgroup()->testgroup()->expirationdays();
if ($age->days() < $expdays) {
return 1;
} else {
return 0;
}
}
#########################################################################
# get the age of this result and return it as a Time::Seconds object
memoize('age', NORMALIZER => sub {my $a=shift; return $a->testresultid()});
sub age {
my $self = shift;
my $now = localtime;
my $timediff = $now - $self->timestamp();
return $timediff;
}
#########################################################################
# is this test result from a trusted user?
#########################################################################
sub istrusted {
my $self = shift;
if ($self->user()->istrusted()) {
return 1;
} else {
return 0;
}
}
#########################################################################
# &getDefaultTestResults($)
#
#########################################################################
sub getDefaultTestResults($) {
my $self = shift;
my @rows = $self->search_DefaultTestResults();
my $criteria = "Default<br/>Ordered by Created<br/>Limit to $_num_results_default results";
return $criteria, \@rows;
}
#########################################################################
# &getTestResults($\@\@$)
#
#########################################################################
sub getTestResults($\@\@$) {
my ($self,$where_criteria,$order_by_criteria,$limit_value) = @_;
my $select = 'SELECT tr.testresult_id,tr.test_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name AS result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email';
my $from = 'FROM test_results tr, tests t, platforms p, opsyses o, branches b, products pr, test_result_status_lookup trsl, test_groups tg, subgroups sg, users u';
my $where = 'WHERE tr.test_id=t.test_id AND tr.platform_id=p.platform_id AND tr.opsys_id=o.opsys_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_id=trsl.result_status_id AND t.subgroup_id=sg.subgroup_id AND sg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id';
my $limit = 'LIMIT ';
foreach my $criterion (@$where_criteria) {
$criterion->{'value'} =~ s/'/\'/g;
if ($criterion->{'field'} eq 'branch') {
$where .= " AND b.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'locale') {
$where .= " AND tr.locale_abbrev='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'product') {
$where .= " AND pr.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'platform') {
$where .= " AND p.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'test_group') {
$where .= " AND tg.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'test_id') {
$where .= " AND tr.test_id='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'summary') {
$where .= ' AND t.summary LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'email') {
$where .= ' AND u.email LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'result_status') {
$where .= " AND trsl.class_name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'trusted_only') {
$from .= ", users u";
$where .= " AND u.user_id=tr.user_id AND u.is_trusted=1";
} elsif ($criterion->{'field'} eq 'start_date') {
my $start_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($start_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid start date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time>=$start_timestamp";
}
} elsif ($criterion->{'field'} eq 'end_date') {
my $end_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($end_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid end date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time<=$end_timestamp";
}
} elsif ($criterion->{'field'} eq 'timespan') {
next if ($criterion->{'value'} eq 'all');
my $day_delta = $criterion->{'value'};
my $err;
my $timestamp =
&Date::Manip::UnixDate(&Date::Manip::DateCalc("now",
"$day_delta days",
\$err),
"%q");
$where .= " AND tr.submission_time>=$timestamp";
} elsif ($criterion->{'field'} eq 'search_field') {
($from,$where) = &_processSearchField($criterion,$from,$where);
} else {
# Skip unknown field
}
}
my $order_by = 'ORDER BY ';
foreach my $criterion (@$order_by_criteria) {
# Skip empty fields.
next if (!$criterion or !$criterion->{'field'});
if ($criterion->{'field'} eq 'created') {
$order_by .= "tr.submission_time $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'product') {
$order_by .= "pr.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'platform') {
$order_by .= "p.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'test_group') {
$order_by .= "tg.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'test_id') {
$order_by .= "tr.test_id $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'summary') {
$order_by .= "t.summary $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'result_status') {
$order_by .= "trsl.class_name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'branch') {
$order_by .= "b.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'locale') {
$order_by .= "tr.locale_abbrev $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'email') {
$order_by .= "u.email $criterion->{'direction'},";
} else {
# Skip unknown field
}
}
if ($order_by eq 'ORDER BY ') {
$order_by .= 'tr.submission_time DESC';
} else {
chop($order_by);
}
if ($limit_value and $limit_value ne '') {
$limit .= "$limit_value";
} else {
$limit .= "$_num_results_default";
}
my $sql = "$select $from $where $order_by $limit";
#print $sql,"<br/>\n";
Litmus::DB::Testresult->set_sql(TestResults => qq{
$sql
});
my @rows = $self->search_TestResults();
return \@rows;
}
#########################################################################
# &_processSearchField(\%\$\$)
#
#########################################################################
sub _processSearchField(\%) {
my ($search_field,$from,$where) = @_;
my $table_field = "";
if ($search_field->{'search_field'} eq 'buildid') {
$table_field='tr.build_id';
} elsif ($search_field->{'search_field'} eq 'comments') {
$table_field='c.comment';
} elsif ($search_field->{'search_field'} eq 'locale') {
$table_field='tr.locale_abbrev';
} elsif ($search_field->{'search_field'} eq 'opsys') {
$table_field='o.name';
} elsif ($search_field->{'search_field'} eq 'platform') {
$table_field='p.name';
} elsif ($search_field->{'search_field'} eq 'product') {
$table_field='pr.name';
} elsif ($search_field->{'search_field'} eq 'result_status') {
$table_field='trsl.name';
} elsif ($search_field->{'search_field'} eq 'subgroup') {
$table_field='sg.name';
} elsif ($search_field->{'search_field'} eq 'email') {
if ($from !~ /users u/) {
$from .= ", users u";
$where .= " AND tr.user_id=u.user_id";
}
$table_field='u.email';
} elsif ($search_field->{'search_field'} eq 'summary') {
$table_field='t.name';
} elsif ($search_field->{'search_field'} eq 'test_group') {
$table_field='tg.name';
} elsif ($search_field->{'search_field'} eq 'test_status') {
$table_field='tsl.name';
} elsif ($search_field->{'search_field'} eq 'user_agent') {
$table_field='tr.user_agent';
} else {
return ($from,$where);
}
if ($search_field->{'match_criteria'} eq 'contains_all' or
$search_field->{'match_criteria'} eq 'contains_any' or
$search_field->{'match_criteria'} eq 'not_contain_any') {
my $join = "";
if ($search_field->{'match_criteria'} eq 'contains_all') {
$join = 'AND';
} else {
$join = 'OR';
}
my @words = split(/ /,$search_field->{'value'});
if ($search_field->{'match_criteria'} eq 'not_contain_any') {
$where .= " AND NOT (";
} else {
$where .= " AND (";
}
my $first_pass = 1;
foreach my $word (@words) {
if ( $first_pass ) {
$where .= "UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
$first_pass = 0;
} else {
$where .= " $join UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
}
}
$where .= ")";
} elsif ($search_field->{'match_criteria'} eq 'contains') {
$where .= " AND UPPER($table_field) LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'contains_case') {
$where .= " AND $table_field LIKE '%%" . $search_field->{'value'} . "%%'";
} elsif ($search_field->{'match_criteria'} eq 'not_contain') {
$where .= " AND UPPER($table_field) NOT LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'regexp') {
$where .= " AND $table_field REGEXP '" . $search_field->{'value'} . "'";
} elsif ($search_field->{'match_criteria'} eq 'not_regexp') {
$where .= " AND $table_field NOT REGEXP '" . $search_field->{'value'} . "'";
} else {
# Ignore unknown match criteria.
return ($from,$where);
}
return ($from,$where);
}
#########################################################################
#########################################################################
sub getCommonResults($$) {
my ($self,$status,$limit_value) = @_;
if (!$status) {
return undef;
}
if (!$limit_value) {
$limit_value = $_num_results_default;
}
my @rows = $self->search_CommonResults($status);
return \@rows;
}
1;