Added a number of features and fixed several bugs. RC1.
git-svn-id: svn://10.0.0.236/trunk@202845 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -335,7 +335,7 @@ Returns true if the logged in user has rights to edit this attachment
|
||||
sub canedit {
|
||||
}
|
||||
|
||||
=head2 canview
|
||||
=head2 candelete
|
||||
|
||||
Returns true if the logged in user has rights to delete this attachment
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Bugzilla::Testopia::Environment - A test environment
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Environments are a set of paramaters dictating what conditions
|
||||
Environments are a set of parameters dictating what conditions
|
||||
a test was conducted in. Each test run must have an environment.
|
||||
Environments can be very simple or very complex. Since there is
|
||||
no easy way of defining a limit for an environment, the bulk of
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
package Bugzilla::Testopia::Product;
|
||||
|
||||
use strict;
|
||||
|
||||
# Extends Bugzilla::Product;
|
||||
use base "Bugzilla::Product";
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ Bugzilla::Testopia::Search - A module to support searches in Testopis
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Testopia::Search is based heavilly on Bugzilla::Search. It takes a
|
||||
CGI instance and parses its paramaters to generate an SQL query that
|
||||
CGI instance and parses its parameters to generate an SQL query that
|
||||
can be used to get a result set from the database. The query is
|
||||
usually passed to Table.pm to execute and display the results.
|
||||
Search.pm supports searching for all major objects in the Testopia
|
||||
@@ -218,15 +218,22 @@ sub init {
|
||||
my @funcdefs =
|
||||
(
|
||||
"^category," => sub {
|
||||
if ($obj eq 'case_run'){
|
||||
push(@supptables,
|
||||
"INNER JOIN test_cases " .
|
||||
"ON test_case_runs.case_id = test_cases.case_id");
|
||||
}
|
||||
push(@supptables,
|
||||
"INNER JOIN test_case_categories AS categories " .
|
||||
"ON test_cases.category_id = categories.category_id");
|
||||
$f = "categories.name";
|
||||
},
|
||||
"^build," => sub {
|
||||
my $str = '';
|
||||
$str = 'case_' if ($obj eq 'case_run');
|
||||
push(@supptables,
|
||||
"INNER JOIN test_builds AS builds " .
|
||||
"ON test_runs.build_id = builds.build_id");
|
||||
"ON test_". $str ."runs.build_id = builds.build_id");
|
||||
$f = "builds.name";
|
||||
},
|
||||
"^(tcaction|tceffect)," => sub {
|
||||
@@ -296,6 +303,27 @@ sub init {
|
||||
"^run_plan_id," => sub {
|
||||
$f = "test_runs.plan_id";
|
||||
},
|
||||
"^case_prod," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_case_plans AS case_plans " .
|
||||
"ON test_cases.case_id = case_plans.case_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_plans " .
|
||||
"ON case_plans.plan_id = test_plans.plan_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN products " .
|
||||
"ON test_plans.product_id = products.id");
|
||||
$f = "test_plans.product_id";
|
||||
},
|
||||
"^run_prod," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_plans " .
|
||||
"ON test_runs.plan_id = test_plans.plan_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN products " .
|
||||
"ON test_plans.product_id = products.id");
|
||||
$f = "test_plans.product_id";
|
||||
},
|
||||
"^(author|editor|manager|default_tester)," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN profiles AS map_$1 " .
|
||||
@@ -422,9 +450,24 @@ sub init {
|
||||
}
|
||||
push(@specialchart, ["bug", $type, join(',', $cgi->param('bug_id'))]);
|
||||
}
|
||||
if ($cgi->param("product_id")){
|
||||
my $type = "anyexact";
|
||||
if ($cgi->param('prodidtype') && $cgi->param('prodidtype') eq 'exclude') {
|
||||
$type = "nowords";
|
||||
}
|
||||
if ($obj eq 'run'){
|
||||
push(@specialchart, ["run_prod", $type, join(',', $cgi->param('product_id'))]);
|
||||
}
|
||||
elsif ($obj eq 'case'){
|
||||
push(@specialchart, ["case_prod", $type, join(',', $cgi->param('product_id'))]);
|
||||
}
|
||||
else{
|
||||
push(@specialchart, ["product_id", $type, join(',', $cgi->param('product_id'))]);
|
||||
}
|
||||
}
|
||||
# Check the Multi select fields and add them to the chart
|
||||
my @legal_fields = ("case_status_id", "category", "priority_id",
|
||||
"component", "isautomated", "product_id",
|
||||
"component", "isautomated", "case_run_status_id",
|
||||
"default_product_version", "type_id",
|
||||
"build", "environment_id", "milestone");
|
||||
|
||||
@@ -465,7 +508,7 @@ sub init {
|
||||
push(@specialchart, ["tags", $t, $cgi->param('tags')]);
|
||||
}
|
||||
# Check for author
|
||||
|
||||
my @clist;
|
||||
foreach my $profile ("author", "editor", "manager", "default_tester",
|
||||
"assignee", "testedby"){
|
||||
$t = $cgi->param($profile . "_type") || '';
|
||||
@@ -479,9 +522,18 @@ sub init {
|
||||
}
|
||||
}
|
||||
if ($cgi->param($profile)){
|
||||
push(@specialchart, [$profile, $t, $cgi->param($profile)]);
|
||||
if ($cgi->param('andor')){
|
||||
push(@specialchart, [$profile, $t, trim($cgi->param($profile))]);
|
||||
}
|
||||
else{
|
||||
push(@clist, $profile, $t, trim($cgi->param($profile)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@clist) {
|
||||
push(@specialchart, \@clist);
|
||||
}
|
||||
|
||||
# check static text fields
|
||||
foreach my $f ("summary", "tcaction", "tceffect", "script",
|
||||
"requirement", "name", "plan_text", "environment",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/perl -wT
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
@@ -105,13 +104,9 @@ sub init {
|
||||
$self->{'type'} = $type || ThrowCodeError('bad_arg',
|
||||
{argument => 'type',
|
||||
function => 'Testopia::Table::_init'});
|
||||
$self->{'url_loc'} = $url || ThrowCodeError('bad_arg',
|
||||
{argument => 'url',
|
||||
function => 'Testopia::Table::_init'});
|
||||
$self->{'cgi'} = $cgi || ThrowCodeError('bad_arg',
|
||||
{argument => 'cgi',
|
||||
function => 'Testopia::Table::_init'});
|
||||
my $debug = $cgi->param('debug');
|
||||
$self->{'url_loc'} = $url;
|
||||
$self->{'cgi'} = $cgi;
|
||||
my $debug = $cgi->param('debug') if $cgi;
|
||||
my @list;
|
||||
if ($query){
|
||||
print "$query" if $debug;
|
||||
@@ -120,11 +115,11 @@ sub init {
|
||||
my $countquery = $query;
|
||||
$countquery =~ s/ LIMIT.*$//;
|
||||
print "<br> $countquery" if $debug;
|
||||
my $count = $dbh->selectcol_arrayref($countquery);
|
||||
$count = scalar @$count;
|
||||
my $count_res = $dbh->selectcol_arrayref($countquery);
|
||||
my $count = scalar @$count_res;
|
||||
print "<br> total rows: $count" if $debug;
|
||||
$self->{'list_count'} = $count;
|
||||
|
||||
my @ids;
|
||||
my $list = $dbh->selectcol_arrayref($query);
|
||||
foreach my $id (@$list){
|
||||
my $o;
|
||||
@@ -140,12 +135,16 @@ sub init {
|
||||
elsif ($type eq 'case_run'){
|
||||
$o = Bugzilla::Testopia::TestCaseRun->new($id);
|
||||
}
|
||||
push (@ids, $id);
|
||||
push (@list, $o);
|
||||
}
|
||||
$self->{'list'} = \@list;
|
||||
$self->{'id_list'} = join(",", @$count_res);
|
||||
}
|
||||
if ($cgi){
|
||||
$self->{'viewall'} = $cgi->param('viewall');
|
||||
$self->{'page'} = $cgi->param('page') || 0;
|
||||
}
|
||||
$self->{'viewall'} = $cgi->param('viewall');
|
||||
$self->{'page'} = $cgi->param('page') || 0;
|
||||
|
||||
# elsif (!$query && !$list){
|
||||
# my @list;
|
||||
@@ -206,9 +205,9 @@ sub init {
|
||||
# $self->{'reverse_sort'} = ($self->{'reverse_sort'} ? 1 : 0);
|
||||
# }
|
||||
#
|
||||
# #### SAVE ####
|
||||
# # Save the list of testcases for use in paginating and sorting
|
||||
# $self->save_list;
|
||||
#### SAVE ####
|
||||
# Save the list of testcases for use in paginating and sorting
|
||||
$self->save_list;
|
||||
#
|
||||
# #### SPLICE ####
|
||||
# # If we are using a paged view of the data we split it up here
|
||||
@@ -228,31 +227,32 @@ Used only in list context
|
||||
=cut
|
||||
|
||||
sub save_list {
|
||||
my $self = shift;
|
||||
my @ids;
|
||||
foreach my $i (@{$self->{'list'}}){
|
||||
push @ids, $i->id;
|
||||
}
|
||||
my $list = join(",", @ids);
|
||||
my $self = shift;
|
||||
return if ($self->{'user'}->id == 0);
|
||||
# my @ids;
|
||||
# foreach my $i (@{$self->{'list'}}){
|
||||
# push @ids, $i->id;
|
||||
# }
|
||||
# my $list = join(",", @ids);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_named_queries WRITE');
|
||||
my ($is) = $dbh->selectrow_array(
|
||||
"SELECT 1 FROM test_named_queries
|
||||
WHERE userid = ? AND name = ?", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
|
||||
if ($is) {
|
||||
$dbh->do("UPDATE test_named_queries SET query = ?
|
||||
WHERE userid = ? AND name = ?", undef,
|
||||
($list, $self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
if ($self->{'id_list'}){
|
||||
$dbh->bz_lock_tables('test_named_queries WRITE');
|
||||
my ($is) = $dbh->selectrow_array(
|
||||
"SELECT 1 FROM test_named_queries
|
||||
WHERE userid = ? AND name = ?", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
|
||||
if ($is) {
|
||||
$dbh->do("UPDATE test_named_queries SET query = ?
|
||||
WHERE userid = ? AND name = ?", undef,
|
||||
(join(",", $self->{'id_list'}), $self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
}
|
||||
else {
|
||||
$dbh->do("INSERT INTO test_named_queries VALUES(?,?,?,?)", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__", 0, join(",", $self->{'id_list'})));
|
||||
}
|
||||
$dbh->bz_unlock_tables();
|
||||
}
|
||||
else {
|
||||
$dbh->do("INSERT INTO test_named_queries VALUES(?,?,?,?)", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__", 0, $list));
|
||||
}
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
# $self->{'list_count'} = scalar @ids unless $self->{'query'};
|
||||
}
|
||||
|
||||
@@ -264,13 +264,16 @@ Used only in list context
|
||||
=cut
|
||||
|
||||
sub get_saved_list {
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
return undef if ($self->{'user'}->id == 0);
|
||||
my $type = shift || $self->{'type'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($list) = $dbh->selectrow_array(
|
||||
"SELECT query FROM test_named_queries
|
||||
WHERE userid = ? AND name = ?", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
return $list;
|
||||
($self->{'user'}->id, "__". $type ."__"));
|
||||
my @list = split(',', $list);
|
||||
return \@list;
|
||||
}
|
||||
|
||||
# used by the sort function to check which field to sort on
|
||||
@@ -305,28 +308,37 @@ sub sort_fields {
|
||||
}
|
||||
|
||||
sub sort_list {
|
||||
my $self = shift;
|
||||
$field = shift;
|
||||
$reverse = $self->{'reverse_sort'};
|
||||
my @list = sort sort_fields @{$self->{'list'}};
|
||||
$self->{'list'} = \@list;
|
||||
return $self->{'list'};
|
||||
my $self = shift;
|
||||
$field = shift;
|
||||
$reverse = $self->{'reverse_sort'};
|
||||
my @list = sort sort_fields @{$self->{'list'}};
|
||||
$self->{'list'} = \@list;
|
||||
return $self->{'list'};
|
||||
}
|
||||
|
||||
sub get_page {
|
||||
my $self = shift;
|
||||
if ($self->{'viewall'}){
|
||||
return $self->{'list'};
|
||||
}
|
||||
my $pagenum = shift || $self->{'page'};
|
||||
$self->{'page'} = $pagenum;
|
||||
my $offset = $pagenum * $self->page_size;
|
||||
my @list = @{$self->{'list'}};
|
||||
my $self = shift;
|
||||
if ($self->{'viewall'}){
|
||||
return $self->{'list'};
|
||||
}
|
||||
my $pagenum = shift || $self->{'page'};
|
||||
$self->{'page'} = $pagenum;
|
||||
my $offset = $pagenum * $self->page_size;
|
||||
my @list = @{$self->{'list'}};
|
||||
@list = splice(@list, $offset, $self->page_size);
|
||||
$self->{'list'} = \@list;
|
||||
return $self->{'list'};
|
||||
}
|
||||
|
||||
sub get_next{
|
||||
my $self = shift;
|
||||
my ($curr) = @_;
|
||||
|
||||
my $list = $self->get_list;
|
||||
my $ref = lsearch($curr, $list);
|
||||
return undef if $ref == -1;
|
||||
return $list->[$ref];
|
||||
}
|
||||
###############################
|
||||
#### Accessors ####
|
||||
###############################
|
||||
@@ -341,11 +353,11 @@ Returns an ineger representing how many items should appear on a page
|
||||
|
||||
=cut
|
||||
|
||||
sub page_size {
|
||||
sub page_size {
|
||||
my $self = shift;
|
||||
my $cgi = $self->{'cgi'};
|
||||
return $cgi->param('pagesize') if $cgi->param('pagesize');
|
||||
return 25; #TODO: make this a user setting
|
||||
return 25; #TODO: make this a user setting
|
||||
}
|
||||
|
||||
=head2 get_order_url
|
||||
@@ -376,19 +388,19 @@ sub get_url {
|
||||
my $self = shift;
|
||||
my $regxp = shift;
|
||||
my $cgi = $self->{'cgi'};
|
||||
my @keys = $cgi->param;
|
||||
my $qstring;
|
||||
foreach my $key (@keys){
|
||||
if ($key =~ /$regxp/){
|
||||
my @keys = $cgi->param;
|
||||
my $qstring;
|
||||
foreach my $key (@keys){
|
||||
if ($key =~ /$regxp/){
|
||||
next;
|
||||
}
|
||||
my @vals = $cgi->param($key);
|
||||
}
|
||||
my @vals = $cgi->param($key);
|
||||
foreach my $val (@vals){
|
||||
$qstring .= $key ."=". $val ."&";
|
||||
}
|
||||
}
|
||||
chop $qstring;
|
||||
$qstring = $self->{'url_loc'} ."?". $qstring;
|
||||
}
|
||||
chop $qstring;
|
||||
$qstring = $self->{'url_loc'} ."?". $qstring;
|
||||
$self->{'url'} = $qstring;
|
||||
return $self->{'url'};
|
||||
}
|
||||
@@ -406,7 +418,7 @@ sub page_count {
|
||||
use integer;
|
||||
return ($self->list_count / $self->page_size) + 1;
|
||||
}
|
||||
return $self->list_count/$self->page_size;
|
||||
return $self->list_count/$self->page_size;
|
||||
}
|
||||
|
||||
sub reverse_sort {
|
||||
|
||||
@@ -191,11 +191,14 @@ associated with this case.
|
||||
#TODO: This can be done with a single query
|
||||
sub get_selectable_components {
|
||||
my $self = shift;
|
||||
my ($byid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my @compids;
|
||||
my @exclusions;
|
||||
foreach my $e (@{$self->components}){
|
||||
push @exclusions, $e->{'id'};
|
||||
unless ($byid) {
|
||||
foreach my $e (@{$self->components}){
|
||||
push @exclusions, $e->{'id'};
|
||||
}
|
||||
}
|
||||
my $query = "SELECT id FROM components
|
||||
WHERE product_id = ?";
|
||||
@@ -214,7 +217,7 @@ sub get_selectable_components {
|
||||
@compids = keys %compseen;
|
||||
#TODO: 2.22 use Bugzilla::Component
|
||||
my @comps;
|
||||
push @comps, {'id' => '0', 'name' => '--Please Select--'};
|
||||
push @comps, {'id' => '0', 'name' => '--Please Select--'} unless $byid;
|
||||
foreach my $id (@compids){
|
||||
my $ref = $dbh->selectrow_hashref(
|
||||
"SELECT id, name FROM components
|
||||
@@ -946,6 +949,36 @@ sub update_deps {
|
||||
}
|
||||
}
|
||||
|
||||
=head2 get_dep_tree
|
||||
|
||||
Returns a list of test case dependencies
|
||||
|
||||
=cut
|
||||
|
||||
sub get_dep_tree {
|
||||
my $self = shift;
|
||||
$self->{'dep_list'} = ();
|
||||
$self->_generate_dep_tree($self->{'case_id'});
|
||||
return $self->{'dep_list'};
|
||||
}
|
||||
|
||||
=head2 _generate_dep_tree
|
||||
|
||||
Private method that recursivly gets a list of the test cases this blocks
|
||||
|
||||
=cut
|
||||
|
||||
sub _generate_dep_tree {
|
||||
my $self = shift;
|
||||
my ($case_id) = @_;
|
||||
my $deps = _get_dep_lists("dependson", "blocked", $case_id);
|
||||
return unless scalar @$deps;
|
||||
foreach my $id (@$deps){
|
||||
#print "ID $id";
|
||||
$self->_generate_dep_tree($id);
|
||||
push @{$self->{'dep_list'}}, $id
|
||||
}
|
||||
}
|
||||
=head2 canedit
|
||||
|
||||
Returns true if the logged in user has rights to edit this test case.
|
||||
@@ -1230,7 +1263,7 @@ sub plans {
|
||||
return $self->{'plans'};
|
||||
}
|
||||
|
||||
=head2 plans
|
||||
=head2 bugs
|
||||
|
||||
Returns a reference to a list of Bugzilla::Bug objects
|
||||
associated with this case.
|
||||
@@ -1241,12 +1274,12 @@ sub bugs {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'bugs'} if exists $self->{'bugs'};
|
||||
my $ref = $dbh->selectcol_arrayref("SELECT bug_id
|
||||
FROM test_case_bugs b
|
||||
JOIN test_case_runs r
|
||||
ON r.case_run_id = b.case_run_id
|
||||
WHERE case_id = ?",
|
||||
undef, $self->{'case_id'});
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT DISTINCT bug_id
|
||||
FROM test_case_bugs b
|
||||
JOIN test_case_runs r ON r.case_run_id = b.case_run_id
|
||||
WHERE case_id = ?",
|
||||
undef, $self->{'case_id'});
|
||||
my @bugs;
|
||||
foreach my $id (@{$ref}){
|
||||
push @bugs, Bugzilla::Bug->new($id, Bugzilla->user->id);
|
||||
|
||||
@@ -163,7 +163,7 @@ sub store {
|
||||
$dbh->do("INSERT INTO test_case_runs ($columns)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", undef,
|
||||
(undef, $self->{'run_id'}, $self->{'case_id'}, $self->{'assignee'},
|
||||
$self->{'testedby'}, IDLE, $self->{'case_text_version'},
|
||||
undef, IDLE, $self->{'case_text_version'},
|
||||
$self->{'build_id'}, $self->{'notes'}, undef, 1, 0));
|
||||
|
||||
my $key = $dbh->bz_last_key( 'test_case_runs', 'case_run_id' );
|
||||
@@ -181,13 +181,37 @@ sub clone {
|
||||
my ($fields) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$self->{'build_id'} = $fields->{'build_id'};
|
||||
$self->{'case_run_status_id'} = IDLE;
|
||||
$self->{'notes'} = '';
|
||||
my $entry = $self->store;
|
||||
$self->set_as_current($entry);
|
||||
return $entry;
|
||||
}
|
||||
|
||||
=head2 check_exists
|
||||
|
||||
Checks for an existing entry with the same build for this case and run
|
||||
and returns the id if it is found
|
||||
|
||||
=cut
|
||||
|
||||
sub check_exists {
|
||||
my $self = shift;
|
||||
my ($run_id, $case_id, $build_id) = @_;
|
||||
|
||||
$run_id ||= $self->{'run_id'};
|
||||
$case_id ||= $self->{'case_id'};
|
||||
$build_id ||= $self->{'build_id'};
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($is) = $dbh->selectrow_array(
|
||||
"SELECT case_run_id
|
||||
FROM test_case_runs
|
||||
WHERE run_id = ? AND case_id = ? AND build_id = ?",
|
||||
undef, ($run_id, $case_id, $build_id));
|
||||
|
||||
return $is;
|
||||
|
||||
}
|
||||
|
||||
=head2 update
|
||||
|
||||
Update this case-run in the database. This method checks which
|
||||
@@ -203,13 +227,17 @@ sub update {
|
||||
if ($self->is_closed_status($fields->{'case_run_status_id'})){
|
||||
$fields->{'close_date'} = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
}
|
||||
if ($fields->{'build_id'} != $self->{'build_id'} && $self->{'case_run_status_id'} != IDLE){
|
||||
return $self->clone($fields);
|
||||
my ($is) = $self->check_exists($self->run_id, $self->case_id, $fields->{'build_id'});
|
||||
|
||||
if ($fields->{'build_id'} != $self->{'build_id'}){
|
||||
if ($is){
|
||||
return $is;
|
||||
}
|
||||
if ($self->{'case_run_status_id'} != IDLE){
|
||||
return $self->clone($fields);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $self->_update_fields($fields);
|
||||
}
|
||||
|
||||
return $self->_update_fields($fields);
|
||||
}
|
||||
|
||||
=head2 _update_fields
|
||||
@@ -224,6 +252,13 @@ sub _update_fields{
|
||||
my ($newvalues) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
if ($newvalues->{'case_run_status_id'} && $newvalues->{'case_run_status_id'} == FAILED){
|
||||
$self->_update_deps(BLOCKED);
|
||||
}
|
||||
elsif ($newvalues->{'case_run_status_id'} && $newvalues->{'case_run_status_id'} == PASSED){
|
||||
$self->_update_deps(IDLE);
|
||||
}
|
||||
|
||||
$dbh->bz_lock_tables('test_case_runs WRITE');
|
||||
foreach my $field (keys %{$newvalues}){
|
||||
$dbh->do("UPDATE test_case_runs
|
||||
@@ -302,9 +337,9 @@ sub set_status {
|
||||
$self->_update_fields({'close_date' => $timestamp});
|
||||
$self->_update_fields({'testedby' => Bugzilla->user->id});
|
||||
$self->{'close_date'} = $timestamp;
|
||||
$self->{'tested_by'} = Bugzilla->user;
|
||||
$self->{'testedby'} = Bugzilla->user->id;
|
||||
}
|
||||
|
||||
|
||||
$self->{'case_run_status_id'} = $status_id;
|
||||
$self->{'status'} = undef;
|
||||
}
|
||||
@@ -337,6 +372,43 @@ sub set_note {
|
||||
$self->{'notes'} = $note;
|
||||
}
|
||||
|
||||
=head2 _update_deps
|
||||
|
||||
Private method for updating blocked test cases. If the pre-requisite
|
||||
case fails, the blocked test cases in a run get a status of BLOCKED
|
||||
if it passes they are set back to IDLE. This only happens to the
|
||||
current case run and only if it doesn't already have a closed status.
|
||||
=cut
|
||||
|
||||
sub _update_deps {
|
||||
my $self = shift;
|
||||
my ($status) = @_;
|
||||
my $deplist = $self->case->get_dep_tree;
|
||||
return unless $deplist;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->bz_lock_tables("test_case_runs WRITE");
|
||||
my $caseruns = $dbh->selectcol_arrayref(
|
||||
"SELECT case_run_id
|
||||
FROM test_case_runs
|
||||
WHERE iscurrent = 1
|
||||
AND run_id = ?
|
||||
AND case_run_status_id IN(". join(',', (IDLE,RUNNING,PAUSED,BLOCKED)) .")
|
||||
AND case_id IN (". join(',', @$deplist) .")",
|
||||
undef, $self->{'run_id'});
|
||||
my $sth = $dbh->prepare_cached(
|
||||
"UPDATE test_case_runs
|
||||
SET case_run_status_id = ?
|
||||
WHERE case_run_id = ?");
|
||||
|
||||
foreach my $id (@$caseruns){
|
||||
$sth->execute($status, $id);
|
||||
}
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
$self->{'updated_deps'} = $caseruns;
|
||||
}
|
||||
|
||||
=head2 get_case_run_list
|
||||
|
||||
Returns a reference to a list of case-runs for the given case and run
|
||||
@@ -379,7 +451,8 @@ Attaches the specified bug to this test case-run
|
||||
|
||||
sub attach_bug {
|
||||
my $self = shift;
|
||||
my ($bug) = @_;
|
||||
my ($bug, $caserun_id) = @_;
|
||||
$caserun_id ||= $self->{'case_run_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_case_bugs WRITE');
|
||||
@@ -388,7 +461,7 @@ sub attach_bug {
|
||||
FROM test_case_bugs
|
||||
WHERE case_run_id=?
|
||||
AND bug_id=?",
|
||||
undef, ($self->{'case_run_id'}, $bug));
|
||||
undef, ($caserun_id, $bug));
|
||||
if ($is) {
|
||||
$dbh->bz_unlock_tables();
|
||||
return;
|
||||
@@ -398,6 +471,24 @@ sub attach_bug {
|
||||
$dbh->bz_unlock_tables();
|
||||
}
|
||||
|
||||
=head2 detach_bug
|
||||
|
||||
Removes the association of the specified bug from this test case-run
|
||||
|
||||
=cut
|
||||
|
||||
sub detach_bug {
|
||||
my $self = shift;
|
||||
my ($bug) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->do("DELETE FROM test_case_bugs
|
||||
WHERE bug_id = ?
|
||||
AND case_run_id = ?",
|
||||
undef, ($bug, $self->{'case_run_id'}));
|
||||
|
||||
}
|
||||
|
||||
=head2 get_buglist
|
||||
|
||||
Returns a comma separated string off bug ids associated with
|
||||
@@ -466,6 +557,12 @@ Returns the true if this case-run is private.
|
||||
|
||||
=cut
|
||||
|
||||
=head2 updated_deps
|
||||
|
||||
Returns a reference to a list of dependent caseruns that were updated
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'case_run_id'}; }
|
||||
sub case_id { return $_[0]->{'case_id'}; }
|
||||
sub run_id { return $_[0]->{'run_id'}; }
|
||||
@@ -478,6 +575,7 @@ sub iscurrent { return $_[0]->{'iscurrent'}; }
|
||||
sub status_id { return $_[0]->{'case_run_status_id'}; }
|
||||
sub sortkey { return $_[0]->{'sortkey'}; }
|
||||
sub isprivate { return $_[0]->{'isprivate'}; }
|
||||
sub updated_deps { return $_[0]->{'updated_deps'}; }
|
||||
|
||||
=head2 run
|
||||
|
||||
@@ -520,7 +618,7 @@ sub build {
|
||||
return $self->{'build'};
|
||||
}
|
||||
|
||||
=head2 run
|
||||
=head2 status
|
||||
|
||||
Looks up the status name of the associated status_id for this object
|
||||
|
||||
@@ -612,10 +710,10 @@ sub is_open_status {
|
||||
my $self = shift;
|
||||
my $status = shift;
|
||||
my @open_status_list = (IDLE, RUNNING, PAUSED);
|
||||
return 1 if lsearch(\@open_status_list, $status) > 0;
|
||||
return 1 if lsearch(\@open_status_list, $status) > -1;
|
||||
}
|
||||
|
||||
=head2 is_open_status
|
||||
=head2 is_closed_status
|
||||
|
||||
Returns true if the status of this case-run is a closed status
|
||||
|
||||
@@ -625,7 +723,7 @@ sub is_closed_status {
|
||||
my $self = shift;
|
||||
my $status = shift;
|
||||
my @closed_status_list = (PASSED, FAILED, BLOCKED);
|
||||
return 1 if lsearch(\@closed_status_list, $status) > 0;
|
||||
return 1 if lsearch(\@closed_status_list, $status) > -1;
|
||||
}
|
||||
|
||||
=head2 canview
|
||||
@@ -705,13 +803,13 @@ Returns true if the logged in user has rights to edit this case-run.
|
||||
|
||||
sub canedit {
|
||||
my $self = shift;
|
||||
return $self->canview
|
||||
return !$self->run->stop_date && $self->canview
|
||||
&& (UserInGroup('managetestplans')
|
||||
|| UserInGroup('edittestcases')
|
||||
|| UserInGroup('runtests'));
|
||||
}
|
||||
|
||||
=head2 canedit
|
||||
=head2 candelete
|
||||
|
||||
Returns true if the logged in user has rights to delete this case-run.
|
||||
|
||||
|
||||
@@ -326,17 +326,19 @@ specified, use the plan product
|
||||
sub get_product_versions {
|
||||
my $self = shift;
|
||||
my ($product) = @_;
|
||||
detaint_natural($product);
|
||||
$product = $self->{'product_id'} unless ($product);
|
||||
|
||||
$product = $self->{'product_id'} unless $product;
|
||||
$product ||= 0;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
#TODO: 2.22 use product->versions
|
||||
# Can't use placeholders as this could be a single id (integer)
|
||||
# or a comma separated list (string)
|
||||
my $versions = $dbh->selectall_arrayref(
|
||||
"SELECT value AS id, value AS name
|
||||
"SELECT DISTINCT value AS id, value AS name
|
||||
FROM versions
|
||||
WHERE product_id = ?
|
||||
WHERE product_id IN($product)
|
||||
ORDER BY name",
|
||||
{'Slice'=>{}}, $product);
|
||||
{'Slice'=>{}});
|
||||
|
||||
return $versions;
|
||||
}
|
||||
|
||||
@@ -354,11 +356,80 @@ sub get_product_milestones {
|
||||
$product_id ||= $self->{'product_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT value AS id, value AS name
|
||||
"SELECT DISTINCT value AS id, value AS name
|
||||
FROM milestones
|
||||
WHERE product_id = ?
|
||||
WHERE product_id IN($product_id)
|
||||
ORDER BY sortkey",
|
||||
{'Slice'=>{}}, $product_id);
|
||||
{'Slice'=>{}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
=head2 get_product_builds
|
||||
|
||||
Returns al list of builds for the given product. If one
|
||||
is not specified, use the plan product.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_product_builds {
|
||||
#TODO: 2.22 use product.pm
|
||||
my $self = shift;
|
||||
my ($product_id) = @_;
|
||||
$product_id ||= $self->{'product_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT DISTINCT name AS id, name
|
||||
FROM test_builds
|
||||
WHERE product_id IN($product_id)
|
||||
ORDER BY name",
|
||||
{'Slice'=>{}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
=head2 get_product_categories
|
||||
|
||||
Returns a list of product categories for the given product. If one
|
||||
is not specified, use the plan product.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_product_categories {
|
||||
#TODO: 2.22 use product.pm
|
||||
my $self = shift;
|
||||
my ($product_id) = @_;
|
||||
$product_id ||= $self->{'product_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT DISTINCT name AS id, name
|
||||
FROM test_case_categories
|
||||
WHERE product_id IN($product_id)
|
||||
ORDER BY name",
|
||||
{'Slice'=>{}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
=head2 get_product_components
|
||||
|
||||
Returns a list of product components for the given product. If one
|
||||
is not specified, use the plan product.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_product_components {
|
||||
#TODO: 2.22 use product.pm
|
||||
my $self = shift;
|
||||
my ($product_id) = @_;
|
||||
$product_id ||= $self->{'product_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT DISTINCT name AS id, name
|
||||
FROM components
|
||||
WHERE product_id IN($product_id)
|
||||
ORDER BY name",
|
||||
{'Slice'=>{}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ sub validate_test_id {
|
||||
|
||||
$res
|
||||
|| ThrowUserError("invalid-test-id-non-existent",
|
||||
{'id' => $id, 'type' => $type});
|
||||
{'id' => $alias, 'type' => $type});
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user