зеркало из https://github.com/mozilla/pjs.git
261 строка
8.8 KiB
Perl
Executable File
261 строка
8.8 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::Test;
|
|
|
|
use strict;
|
|
use base 'Litmus::DBI';
|
|
|
|
use Litmus::DB::Testresult;
|
|
use Memoize;
|
|
use Litmus::Error;
|
|
|
|
Litmus::DB::Test->table('tests');
|
|
|
|
Litmus::DB::Test->columns(Primary => qw/test_id/);
|
|
Litmus::DB::Test->columns(Essential => qw/subgroup_id summary details status_id community_enabled format_id regression_bug_id/);
|
|
Litmus::DB::Test->columns(All => qw/steps expected_results sort_order author_id creation_date last_updated version testrunner_case_id testrunner_case_version/);
|
|
|
|
Litmus::DB::Test->column_alias("test_id", "testid");
|
|
Litmus::DB::Test->column_alias("subgroup_id", "subgroup");
|
|
Litmus::DB::Test->column_alias("status_id", "status");
|
|
Litmus::DB::Test->column_alias("community_enabled", "communityenabled");
|
|
Litmus::DB::Test->column_alias("format_id", "format");
|
|
Litmus::DB::Test->column_alias("author_id", "author");
|
|
|
|
Litmus::DB::Test->has_a(subgroup => "Litmus::DB::Subgroup");
|
|
Litmus::DB::Test->has_a(status => "Litmus::DB::Status");
|
|
Litmus::DB::Test->has_a("format" => "Litmus::DB::Format");
|
|
Litmus::DB::Test->has_a(author => "Litmus::DB::User");
|
|
|
|
Litmus::DB::Test->has_many(testresults => "Litmus::DB::Testresult", {order_by => 'submission_time DESC'});
|
|
|
|
#########################################################################
|
|
# does the test have at least one recent result?
|
|
# optionally, just check for a particular platform.
|
|
#########################################################################
|
|
memoize('isrecent');
|
|
sub isrecent {
|
|
my $self = shift;
|
|
my $platform = shift;
|
|
|
|
my %restrictor;
|
|
if ($platform) { $restrictor{platform} = $platform }
|
|
|
|
my @results = $self->testresults(%restrictor);
|
|
foreach my $curresult (@results) {
|
|
if ($curresult->isrecent()) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#########################################################################
|
|
# is_completed($$$$$)
|
|
#
|
|
# Check whether we have test results for the current test that correspond
|
|
# to the provided platform, build_id, and user(optional).
|
|
#########################################################################
|
|
memoize('is_completed');
|
|
sub is_completed {
|
|
my $self = shift;
|
|
my $platform = shift;
|
|
my $build_id = shift;
|
|
my $locale = shift;
|
|
my $user = shift; # optional
|
|
|
|
my @results;
|
|
if ($user) {
|
|
@results = $self->testresults(
|
|
platform => $platform,
|
|
buildid => $build_id,
|
|
locale => $locale,
|
|
user => $user,
|
|
);
|
|
} else {
|
|
@results = Litmus::DB::Testresult->retrieve_from_sql(
|
|
"platform_id = " . $platform->{'platform_id'} . " AND " .
|
|
"buildid LIKE \'\%" . $build_id . "\%\' AND " .
|
|
"locale_abbrev = \'" . $locale->{'abbrev'} . "\' AND " .
|
|
"test_id = " . $self->{'test_id'}
|
|
);
|
|
|
|
# @results = $self->testresults(
|
|
# platform => $platform,
|
|
# buildid => $build_id,
|
|
# locale => $locale,
|
|
# );
|
|
}
|
|
|
|
return @results;
|
|
}
|
|
|
|
#########################################################################
|
|
# You might think that getting the state of a test for a particular platform
|
|
# would be pretty easy. In reality, it's more of an art then a science, since
|
|
# we get to consider all the test results submitted for a particular test,
|
|
# their age, whether the result is from a trusted user, and other fun things.
|
|
#
|
|
# Or in other words: "Heuristics are bug ridden by definition. If they didn't
|
|
# have bugs, then they'd be algorithms."
|
|
#
|
|
# XXX: Rewrite all this as an SQL query so it doesn't take so long.
|
|
#
|
|
# YYY: 'state' is even less simple than you might think, and should be
|
|
# based per-branch and make note of the most recent build ID per
|
|
# platform.
|
|
#########################################################################
|
|
memoize('state');
|
|
sub state {
|
|
my $self = shift;
|
|
my $platform = shift;
|
|
|
|
# XXX: if the test is automated, just return the most recent state
|
|
|
|
my %statecounts;
|
|
|
|
# first get all results for this test for this platform:
|
|
my @results = $self->testresults(platform => $platform);
|
|
foreach my $curresult (@results) {
|
|
if (! $curresult->isrecent($platform)) {
|
|
# only consider recent results
|
|
next;
|
|
}
|
|
# we weight the result based on its age and if it is confirmed:
|
|
# first figure out how old the result is as a proportion of the
|
|
# expiration time for the group using a grannuler definition of a day:
|
|
my $adjustedage;
|
|
if ($curresult->age()->days() < 1.5) {
|
|
$adjustedage = 1;
|
|
} elsif ($curresult->age()->days() < 2.5) {
|
|
$adjustedage = 1.8;
|
|
} else {
|
|
$adjustedage = $curresult->age()->days();
|
|
}
|
|
|
|
my $ageproportion = $self->subgroup()->testgroup()->expirationdays()/$adjustedage;
|
|
my $weight = $ageproportion;
|
|
|
|
# give an additional weighting of 2 points to confirmed results:
|
|
if ($curresult->istrusted()) {
|
|
$weight += 2;
|
|
}
|
|
|
|
$statecounts{$curresult->result()} += $weight;
|
|
}
|
|
|
|
# now that we have the weighted counts for each possible state, we
|
|
# calculate the magic number for this test. In other words, the
|
|
# result spread that we require in order to have confidence in our
|
|
# result. If the spread between two states is within the magic
|
|
# number, we just return 0 and the test should be considered unrun
|
|
# since we have no confidence in our result.
|
|
my $magicnumber = 2; # ok we don't really calculate it. We should though...
|
|
|
|
foreach my $outer (keys(%statecounts)) {
|
|
foreach my $inner (keys(%statecounts)) {
|
|
if ($outer eq $inner) {
|
|
next;
|
|
}
|
|
if (abs($statecounts{$inner} - $statecounts{$outer}) < $magicnumber) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
# now we just find the state with the greatest value and return it:
|
|
my $maxkey;
|
|
foreach my $cur (keys(%statecounts)) {
|
|
unless ($maxkey) {$maxkey = $cur}
|
|
if ($statecounts{$cur} > $statecounts{$maxkey}) {
|
|
$maxkey = $cur;
|
|
}
|
|
}
|
|
|
|
return Litmus::DB::Result->retrieve($maxkey);
|
|
}
|
|
|
|
#########################################################################
|
|
# calculate the percent of the time this test has been in existance that it
|
|
# has had a particular state (default state is the current one)
|
|
#########################################################################
|
|
sub percentinstate {
|
|
my $self = shift;
|
|
my $state = shift || $self->state();
|
|
|
|
|
|
}
|
|
|
|
#########################################################################
|
|
# find the number of recent results for this test
|
|
#########################################################################
|
|
memoize('num_recent_results');
|
|
sub num_recent_results {
|
|
my $self = shift;
|
|
|
|
my $count;
|
|
foreach my $curresult ($self->testresults()) {
|
|
if ($curresult->isrecent()) {
|
|
$count++;
|
|
}
|
|
}
|
|
return $count;
|
|
}
|
|
|
|
#########################################################################
|
|
# these are just convenience functions since they are pretty common needs
|
|
# and templates would be pretty verbose without them:
|
|
#########################################################################
|
|
sub product {
|
|
my $self = shift;
|
|
return $self->testgroup()->product();
|
|
}
|
|
|
|
#########################################################################
|
|
#########################################################################
|
|
sub testgroup {
|
|
my $self = shift;
|
|
return $self->subgroup()->testgroup();
|
|
}
|
|
|
|
1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|