1233 lines
42 KiB
Perl
1233 lines
42 KiB
Perl
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
|
#
|
|
# 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 the Bugzilla Testopia System.
|
|
#
|
|
# The Initial Developer of the Original Code is Greg Hendricks.
|
|
# Portions created by Greg Hendricks are Copyright (C) 2006
|
|
# Novell. All Rights Reserved.
|
|
#
|
|
# Contributor(s): Dallas Harken <dharken@novell.com>
|
|
# Greg Hendricks <ghendricks@novell.com>
|
|
|
|
package Bugzilla::Extension::Testopia::WebService::TestCase;
|
|
|
|
use strict;
|
|
|
|
use base qw(Bugzilla::WebService);
|
|
use lib qw(./extensions/Testopia/lib);
|
|
|
|
use Bugzilla::User;
|
|
use Bugzilla::Constants;
|
|
use Bugzilla::Error;
|
|
|
|
use Bugzilla::Extension::Testopia::TestCase;
|
|
use Bugzilla::Extension::Testopia::Category;
|
|
use Bugzilla::Extension::Testopia::Search;
|
|
use Bugzilla::Extension::Testopia::Table;
|
|
|
|
sub get {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
$case->text();
|
|
$case->author();
|
|
$case->dependson_list();
|
|
$case->blocked_list();
|
|
|
|
#Result is a test case object hash
|
|
return $case;
|
|
}
|
|
|
|
sub list {
|
|
my $self = shift;
|
|
my ($query) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $cgi = Bugzilla->cgi;
|
|
|
|
$cgi->param("current_tab", "case");
|
|
|
|
foreach (keys(%$query)){
|
|
$cgi->param($_, $$query{$_});
|
|
}
|
|
$cgi->param('distinct', 1);
|
|
|
|
my $search = Bugzilla::Extension::Testopia::Search->new($cgi);
|
|
return Bugzilla::Extension::Testopia::Table->new('case','tr_xmlrpc.cgi',$cgi,undef,$search->query())->list();
|
|
}
|
|
|
|
sub list_count {
|
|
my $self = shift;
|
|
my ($query) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $cgi = Bugzilla->cgi;
|
|
|
|
$cgi->param("current_tab", "case");
|
|
|
|
foreach (keys(%$query)){
|
|
$cgi->param($_, $$query{$_});
|
|
}
|
|
$cgi->param('distinct', 1);
|
|
|
|
my $search = Bugzilla::Extension::Testopia::Search->new($cgi);
|
|
return Bugzilla::Extension::Testopia::Table->new('case','tr_xmlrpc.cgi',$cgi,undef,$search->query())->list_count();
|
|
}
|
|
|
|
sub create {
|
|
my $self = shift;
|
|
my ($values) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @new_values;
|
|
if (ref $values eq 'ARRAY'){
|
|
push @new_values, @$values;
|
|
}
|
|
else {
|
|
push @new_values, $values;
|
|
}
|
|
|
|
my @results;
|
|
foreach my $new_values (@new_values){
|
|
my @plan_ids;
|
|
if (ref $new_values->{'plans'} eq 'ARRAY'){
|
|
push @plan_ids, @{$new_values->{'plans'}};
|
|
}
|
|
else{
|
|
push @plan_ids, split(/[\s,]+/, $new_values->{'plans'});
|
|
}
|
|
|
|
if ($new_values->{'plan_id'}){
|
|
push @plan_ids, $new_values->{'plan_id'}
|
|
}
|
|
|
|
my @plans;
|
|
eval{
|
|
foreach my $id (@plan_ids){
|
|
my $plan = Bugzilla::Extension::Testopia::TestPlan->new($id);
|
|
ThrowUserError("invalid-test-id-non-existent", {'id' => $id, 'type' => 'Plan'}) unless $plan->{plan_id};
|
|
ThrowUserError("testopia-create-denied", {'object' => 'Test Case', 'plan' => $plan}) unless $plan->canedit;
|
|
push @plans, $plan;
|
|
}
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
next;
|
|
}
|
|
# Remove plan id from new_values hash
|
|
delete $new_values->{plan_id};
|
|
|
|
my @run_ids;
|
|
if (ref $new_values->{'runs'} eq 'ARRAY'){
|
|
push @run_ids, @{$new_values->{'runs'}};
|
|
}
|
|
my @bug_ids;
|
|
if (ref $new_values->{'bugs'} eq 'ARRAY'){
|
|
push @bug_ids, @{$new_values->{'bugs'}};
|
|
}
|
|
my @dependson;
|
|
if (ref $new_values->{'dependson'} eq 'ARRAY'){
|
|
push @dependson, @{$new_values->{'dependson'}};
|
|
}
|
|
my @blocks;
|
|
if (ref $new_values->{'blocks'} eq 'ARRAY'){
|
|
push @blocks, @{$new_values->{'blocks'}};
|
|
}
|
|
|
|
$new_values->{'case_status_id'} ||= $new_values->{'status'};
|
|
$new_values->{'priority_id'} ||= $new_values->{'priority'};
|
|
$new_values->{'default_tester_id'} ||= $new_values->{'default_tester'};
|
|
$new_values->{'category_id'} ||= $new_values->{'category'};
|
|
$new_values->{'plans'} = \@plans;
|
|
$new_values->{'author_id'} ||= Bugzilla->user->id;
|
|
$new_values->{'runs'} = join(',', @run_ids) if scalar @run_ids;
|
|
$new_values->{'bugs'} = join(',', @bug_ids) if scalar @bug_ids;
|
|
$new_values->{'dependson'} = join(',', @dependson) if scalar @dependson;
|
|
$new_values->{'blocks'} = join(',', @blocks) if scalar @blocks;
|
|
|
|
delete $new_values->{'default_tester'};
|
|
delete $new_values->{'status'};
|
|
delete $new_values->{'priority'};
|
|
delete $new_values->{'category'};
|
|
|
|
my $case;
|
|
eval{
|
|
$case = Bugzilla::Extension::Testopia::TestCase->create($new_values);
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
else {
|
|
return $case if scalar @new_values == 1;
|
|
push @results, $case;
|
|
}
|
|
}
|
|
return \@results;
|
|
}
|
|
|
|
sub update {
|
|
my $self = shift;
|
|
my ($new_values) = @_;
|
|
|
|
if(ref $new_values ne 'HASH'){
|
|
$new_values = $_[1];
|
|
$new_values->{ids} = $_[0];
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($new_values->{ids});
|
|
|
|
my @dependson;
|
|
if (ref $new_values->{'dependson'} eq 'ARRAY'){
|
|
push @dependson, @{$new_values->{'dependson'}};
|
|
}
|
|
my @blocks;
|
|
if (ref $new_values->{'blocks'} eq 'ARRAY'){
|
|
push @blocks, @{$new_values->{'blocks'}};
|
|
}
|
|
$new_values->{'dependson'} = join(',', @dependson) if scalar @dependson;
|
|
$new_values->{'blocks'} = join(',', @blocks) if scalar @blocks;
|
|
|
|
my @cases;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
ThrowUserError("invalid-test-id-non-existent", {'id' => $id, 'type' => 'Case'}) if scalar @ids == 1;
|
|
push @cases, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
ThrowUserError('testopia-read-only', {'object' => $case}) if scalar @ids == 1;
|
|
push @cases, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
|
|
$new_values->{'case_status_id'} ||= $new_values->{'status'};
|
|
$new_values->{'priority_id'} ||= $new_values->{'priority'};
|
|
$new_values->{'default_tester_id'} ||= $new_values->{'default_tester'};
|
|
$new_values->{'category_id'} ||= $new_values->{'category'};
|
|
|
|
eval {
|
|
$case->set_case_status($new_values->{'case_status_id'}) if defined $new_values->{'case_status_id'};
|
|
$case->set_category($new_values->{'category_id'}) if defined $new_values->{'category_id'};
|
|
$case->set_priority($new_values->{'priority_id'}) if defined $new_values->{'priority_id'};
|
|
$case->set_default_tester($new_values->{'default_tester_id'}) if defined $new_values->{'default_tester_id'};
|
|
$case->set_sortkey($new_values->{'sortkey'}) if defined $new_values->{'sortkey'};
|
|
$case->set_requirement($new_values->{'requirement'}) if defined $new_values->{'requirement'};
|
|
$case->set_isautomated($new_values->{'isautomated'}) if defined $new_values->{'isautomated'};
|
|
$case->set_script($new_values->{'script'}) if defined $new_values->{'script'};
|
|
$case->set_arguments($new_values->{'arguments'}) if defined $new_values->{'arguments'};
|
|
$case->set_summary($new_values->{'summary'}) if defined $new_values->{'summary'};
|
|
$case->set_alias($new_values->{'alias'}) if defined $new_values->{'alias'};
|
|
$case->set_estimated_time($new_values->{'estimated_time'}) if defined $new_values->{'estimated_time'};
|
|
$case->set_dependson($new_values->{'dependson'}) if defined $new_values->{'dependson'};
|
|
$case->set_blocks($new_values->{'blocks'}) if defined $new_values->{'blocks'};
|
|
|
|
$case->update;
|
|
$case->dependson_list;
|
|
$case->blocked_list;
|
|
};
|
|
|
|
if ($@){
|
|
return $@ if (scalar @ids == 1);
|
|
push @cases, {ERROR => $@};
|
|
}
|
|
else {
|
|
push @cases, $case;
|
|
}
|
|
|
|
return $case if scalar @ids == 1;
|
|
}
|
|
|
|
return \@cases;
|
|
}
|
|
|
|
sub get_text {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_id} = shift;
|
|
$params->{version} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($params->{case_id});
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $params->{case_id}}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
#Result is the latest test case doc hash map
|
|
return $case->text($params->{version});
|
|
}
|
|
|
|
sub store_text {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_id} = shift;
|
|
$params->{action} = shift;
|
|
$params->{effect} = shift;
|
|
$params->{setup} = shift;
|
|
$params->{breakdown} = shift;
|
|
$params->{author_id} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($params->{case_id});
|
|
|
|
$params->{author_id} ||= Bugzilla->user->id;
|
|
if ($params->{author_id} !~ /^\d+$/){
|
|
$params->{author_id} = Bugzilla::User::login_to_id($params->{author_id}, "THROWERROR");
|
|
}
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $params->{case_id}}) unless $case->{case_id};
|
|
ThrowUserError('testopia-read-only', {'object' => $case}) unless $case->canedit;
|
|
|
|
my $version = $case->store_text($params->{case_id}, $params->{author_id}, $params->{action}, $params->{effect}, $params->{setup}, $params->{breakdown});
|
|
|
|
# Result is new test case doc version on success, otherwise an exception will be thrown
|
|
return $version;
|
|
}
|
|
|
|
sub get_plans {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
return $case->plans();
|
|
}
|
|
|
|
sub attach_bug {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{bug_ids} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->attach_bug($params->{bug_ids});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub detach_bug {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_id} = shift;
|
|
$params->{bug_ids} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($params->{case_id});
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $params->{case_id}}) unless $case->{case_id};
|
|
ThrowUserError('testopia-read-only', {'object' => $case}) unless $case->canedit;
|
|
|
|
$case->detach_bug($params->{bug_ids});
|
|
|
|
# Result 0 on success, otherwise an exception will be thrown
|
|
return 0;
|
|
}
|
|
|
|
sub get_bugs {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
# Result is list of bugs for the given test case
|
|
return $case->bugs;
|
|
}
|
|
|
|
sub add_component {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{components} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->add_component($params->{components});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub remove_component {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{component_id} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->remove_component($params->{component_id});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub get_components {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
# Result list of components otherwise an exception will be thrown
|
|
return $case->components();
|
|
}
|
|
|
|
sub add_tag {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{tags} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->add_tag($params->{tags});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub remove_tag {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{tag} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->remove_tag($params->{tag});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub get_tags {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
my @results;
|
|
foreach my $tag (@{$case->tags}){
|
|
push @results, $tag->name;
|
|
}
|
|
# Result list of tags otherwise an exception will be thrown
|
|
return \@results;
|
|
}
|
|
|
|
sub link_plan {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{plan_ids} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @plans;
|
|
if (ref $params->{plan_ids} eq 'ARRAY'){
|
|
$params->{plan_ids} = join(',', @{$params->{plan_ids}});
|
|
}
|
|
foreach my $id (split(',', $params->{plan_ids})){
|
|
my $plan = Bugzilla::Extension::Testopia::TestPlan->new($id);
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Plan', id => $id}) unless $plan->{plan_id};
|
|
ThrowUserError("testopia-read-only", {'object' => $plan}) unless $plan->canedit;
|
|
push @plans, $plan;
|
|
}
|
|
ThrowUserError('missing-plans-list') unless scalar @plans;
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
foreach my $plan (@plans){
|
|
eval {
|
|
$case->link_plan($plan->id);
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
}
|
|
|
|
# Result is list of plans for test case on success, otherwise an exception will be thrown
|
|
return \@results;
|
|
}
|
|
|
|
sub unlink_plan {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_id} = shift;
|
|
$params->{plan_id} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($params->{case_id});
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $params->{case_id}}) unless $case->{case_id};
|
|
ThrowUserError("testopia-read-only", {'object' => 'case'}) unless ($case->can_unlink_plan($params->{plan_id}));
|
|
|
|
$case->unlink_plan($params->{plan_id});
|
|
|
|
# Result is list of plans for test case on success, otherwise an exception will be thrown
|
|
return $case->plans;
|
|
}
|
|
|
|
sub add_to_run {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{case_ids} = shift;
|
|
$params->{run_ids} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my @ids = Bugzilla::Extension::Testopia::Util::process_list($params->{case_ids});
|
|
my @results;
|
|
foreach my $id (@ids){
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($id);
|
|
unless ($case->{case_id}){
|
|
push @results, {ERROR => "TestCase $id does not exist"};
|
|
next;
|
|
}
|
|
unless ($case->canedit){
|
|
push @results, {ERROR => "You do not have rights to edit this test case"};
|
|
next;
|
|
}
|
|
unless ($case->status eq 'CONFIRMED'){
|
|
push @results, {ERROR => "Only CONFIRMED test cases can be added to runs"};
|
|
next;
|
|
}
|
|
eval {
|
|
$case->add_to_run($params->{run_ids});
|
|
};
|
|
if ($@){
|
|
push @results, {ERROR => $@};
|
|
}
|
|
}
|
|
# @results will be empty if successful
|
|
return \@results;
|
|
}
|
|
|
|
sub get_case_run_history {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
# Result list of caseruns otherwise an exception will be thrown
|
|
return $case->caseruns;
|
|
}
|
|
|
|
sub get_change_history {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
# Result list of changes otherwise an exception will be thrown
|
|
return $case->history;
|
|
}
|
|
|
|
sub calculate_average_time {
|
|
my $self = shift;
|
|
my ($case_id) = @_;
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
my $case = new Bugzilla::Extension::Testopia::TestCase($case_id);
|
|
|
|
ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case', id => $case_id}) unless $case->{case_id};
|
|
ThrowUserError('testopia-permission-denied', {'object' => $case}) unless $case->canview;
|
|
|
|
return $case->calculate_average_time;
|
|
}
|
|
|
|
sub lookup_priority_id_by_name {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{name} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
# Result is test case priority id for the given test case priority name
|
|
return lookup_priority_by_value($params->{name});
|
|
}
|
|
|
|
sub lookup_priority_name_by_id {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{id} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
return lookup_priority($params->{id});
|
|
}
|
|
|
|
sub lookup_status_id_by_name {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{name} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
# Result is test case status id for the given test case status name
|
|
return lookup_status_by_name($params->{name});
|
|
}
|
|
|
|
sub lookup_status_name_by_id {
|
|
my $self = shift;
|
|
my ($params) = @_;
|
|
|
|
if (ref $params ne 'HASH'){
|
|
$params = {};
|
|
$params->{id} = shift;
|
|
}
|
|
|
|
Bugzilla->login(LOGIN_REQUIRED);
|
|
|
|
return lookup_status($params->{id});
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
Testopia::Webservice::TestCase
|
|
|
|
=head1 EXTENDS
|
|
|
|
Bugzilla::Webservice
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Provides methods for automated scripts to manipulate Testopia TestCases
|
|
|
|
=head1 METHODS
|
|
|
|
=over
|
|
|
|
=item C<add_component>
|
|
|
|
Description: Adds one or more components to the selected test cases.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an arry of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$components - Integer/Array/String - The component ID, an array of Component IDs or
|
|
component hashes (components can be an array of IDs, a comma separated string of IDs,
|
|
an array of Hashes, or a single hash where the
|
|
component hash = {component => 'string', product => 'string'},
|
|
or a comma separated list of component IDs
|
|
|
|
Returns: Array: empty on success or an array of hashes with failure
|
|
codes if a failure occured.
|
|
|
|
=item C<add_tag>
|
|
|
|
Description: Add one or more tags to the selected test cases.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an arry of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$tags - String/Array - A single tag, an array of tags,
|
|
or a comma separated list of tags.
|
|
|
|
Returns: Array: empty on success or an array of hashes with failure
|
|
codes if a failure occured.
|
|
|
|
=item C<add_to_run>
|
|
|
|
Description: Add one or more cases to the selected test runs.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an arry of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$run_ids - Integer/Array/String: An integer representing the ID in the database
|
|
an array of IDs, or a comma separated list of IDs.
|
|
|
|
Returns: Array: empty on success or an array of hashes with failure
|
|
codes if a failure occured.
|
|
|
|
=item C<attach_bug>
|
|
|
|
Description: Add one or more bugs to the selected test cases.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$bug_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of bug_ids or aliases, or a string of comma separated bug_ids.
|
|
|
|
Returns: Array: empty on success or an array of hashes with failure
|
|
codes if a failure occured.
|
|
|
|
=item C<calculate_average_time>
|
|
|
|
Description: Returns an average time for completion accross all runs.
|
|
|
|
Params: $id - Integer/String: An integer or alias representing the ID in the database.
|
|
|
|
Returns: String: Time in "HH:MM:SS" format.
|
|
|
|
=item C<create>
|
|
|
|
Description: Creates a new Test Case object and stores it in the database.
|
|
|
|
Params: $values - Array/Hash: A reference to a hash or array of hashes with keys and values
|
|
matching the fields of the test case to be created.
|
|
+-------------------+----------------+-----------+------------------------+
|
|
| Field | Type | Null | Description |
|
|
+-------------------+----------------+-----------+------------------------+
|
|
| status | Integer/String | Required | ID or Name of status |
|
|
| category* | Integer/Hash | Required | ID or hash |
|
|
| priority | Integer/String | Required | ID or Name of Priority |
|
|
| summary | String | Required | |
|
|
| plans | Array/Str/Int | Required | ID or List of plan_ids |
|
|
| default_tester | Integer/String | Optional | ID or Login of tester |
|
|
| estimated_time | String | Optional | HH:MM:SS Format |
|
|
| isautomated | Boolean | Optional | Defaults to False (0) |
|
|
| sortkey | Integer | Optional | |
|
|
| script | String | Optional | |
|
|
| arguments | String | Optional | |
|
|
| requirement | String | Optional | |
|
|
| alias | String | Optional | Must be unique |
|
|
| action | String | Optional | |
|
|
| effect | String | Optional | ExpectedResult |
|
|
| setup | String | Optional | |
|
|
| breakdown | String | Optional | |
|
|
| dependson | Array/String | Optional | String Comma separated |
|
|
| blocks | Array/String | Optional | String Comma separated |
|
|
| tags | Array/String | Optional | String Comma separated |
|
|
| bugs | Array/String | Optional | String Comma separated |
|
|
| components+ | Array/Hash/Str | Optional | String Comma separated |
|
|
+-------------------+----------------+-----------+------------------------+
|
|
* category hash = {category => 'string', product => 'string'}
|
|
+ components can be an array of IDs, a comma separated string of IDs,
|
|
an array of Hashes, or a single hash.
|
|
component hash = {component => 'string', product => 'string'}
|
|
|
|
Returns: Array/Hash: The newly created object hash if a single case was created, or
|
|
an array of objects if more than one was created. If any single case threw an
|
|
error during creation, a hash with an ERROR key will be set in its place.
|
|
|
|
=item C<detach_bug>
|
|
|
|
Description: Remove a bug from a test case.
|
|
|
|
Params: $case_id - Integer/String: An integer or alias representing the ID in the database.
|
|
|
|
$bug_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of bug_ids or aliases, or a string of comma separated bug_ids.
|
|
|
|
Returns: 0 on success.
|
|
|
|
=item C<get>
|
|
|
|
Description: Used to load an existing test case from the database.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: A blessed Bugzilla::Extension::Testopia::TestCase object hash
|
|
|
|
=item C<get_bugs>
|
|
|
|
Description: Get the list of bugs that are associated with this test case.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of bug object hashes.
|
|
|
|
=item C<get_case_run_history>
|
|
|
|
Description: Get the list of case-runs for all runs this case appears in.
|
|
To limit this list by build or other attribute, see TestCaseRun::list.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of case-run object hashes.
|
|
|
|
=item C<get_change_history>
|
|
|
|
Description: Get the list of changes to the fields of this case.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of hashes with changed fields and their details.
|
|
|
|
=item C<get_components>
|
|
|
|
Description: Get the list of components attached to this case.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of component object hashes.
|
|
|
|
=item C<get_plans>
|
|
|
|
Description: Get the list of plans that this case is linked to.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of test plan object hashes.
|
|
|
|
=item C<get_tags>
|
|
|
|
Description: Get the list of tags attached to this case.
|
|
|
|
Params: $id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
Returns: Array: An array of tag object hashes.
|
|
|
|
=item C<get_text>
|
|
|
|
Description: The associated large text fields: Action, Expected Results, Setup, Breakdown
|
|
for a given version.
|
|
|
|
Params: $case_id - Integer/String: An integer representing the ID in the database
|
|
or a string representing the unique alias for this case.
|
|
|
|
$version - Integer: (OPTIONAL) The version of the text you want returned.
|
|
Defaults to the latest.
|
|
|
|
Returns: Hash: Text fields and values.
|
|
|
|
=item C<link_plan>
|
|
|
|
Description: Link test cases to the given plan.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$plan_ids - Integer/Array/String: An integer representing the ID in the database,
|
|
an array of plan_ids, or a string of comma separated plan_ids.
|
|
|
|
Returns: Array: Array of failure codes or an empty array.
|
|
|
|
=item C<list>
|
|
|
|
Description: Performs a search and returns the resulting list of test cases.
|
|
|
|
Params: $query - Hash: keys must match valid search fields.
|
|
|
|
+--------------------------------------------------------+
|
|
| Case Search Parameters |
|
|
+--------------------------------------------------------+
|
|
| Key | Valid Values |
|
|
| andor | 1: Author AND tester, 0: OR |
|
|
| author | A bugzilla login (email address) |
|
|
| author_type | (select from email_variants) |
|
|
| case_id | comma separated integers |
|
|
| case_status | String: Status |
|
|
| case_status_id | Integer: Status |
|
|
| category | String: Category Name |
|
|
| category_id | Integer |
|
|
| component | String: Component Name |
|
|
| default_tester | A bugzilla login (email address) |
|
|
| default_tester_type | (select from email_variants) |
|
|
| isautomated | 1: true 0: false |
|
|
| plan_id | comma separated integers |
|
|
| priority | String: Priority |
|
|
| priority_id | Integer |
|
|
| product | String: Product Name |
|
|
| product_id | Integer |
|
|
| requirement | String: Requirement |
|
|
| requirement_type | (select from query_variants) |
|
|
| run_id | comma separated integers |
|
|
| script | String |
|
|
| script_type | (select from query_variants) |
|
|
| summary | String |
|
|
| summary_type | (select from query_variants) |
|
|
| tags | String |
|
|
| tags_type | (select from tag_variants) |
|
|
| tcaction | String |
|
|
| tcaction_type | (select from query_variants) |
|
|
| tceffect | String |
|
|
| tceffect_type | (select from query_variants) |
|
|
+--------------------------------------------------------+
|
|
|
|
+---------------------------------------------------+
|
|
| Paging and Sorting |
|
|
+---------------------------------------------------+
|
|
| Key | Description |
|
|
| dir | "ASC" or "DESC" |
|
|
| order | field to sort by |
|
|
+---------------------------------------------------+
|
|
| page_size | integer: how many per page |
|
|
| page | integer: page number |
|
|
| +++++++ OR +++++++ |
|
|
| start | integer: Start with which record |
|
|
| limit | integer: limit to how many |
|
|
+---------------------------------------------------+
|
|
| viewall | 1: returns all records |
|
|
+---------------------------------------------------+
|
|
* The default is to only return 25 records at a time
|
|
|
|
+----------------------------------------------------+
|
|
| query_variants |
|
|
+----------------+-----------------------------------+
|
|
| Key | Description |
|
|
| allwordssubstr | contains all of the words/strings |
|
|
| anywordssubstr | contains any of the words/strings |
|
|
| substring | contains the string |
|
|
| casesubstring | contains the string (exact case) |
|
|
| allwords | contains all of the words |
|
|
| anywords | contains any of the words |
|
|
| regexp | matches the regexp |
|
|
| notregexp | doesn't match the regexp |
|
|
+----------------+-----------------------------------+
|
|
|
|
+-------------------------------------+
|
|
| email_variants |
|
|
+--------------+----------------------+
|
|
| Key | Description |
|
|
| substring | contains |
|
|
| exact | is |
|
|
| regexp | matches regexp |
|
|
| notregexp | doesn't match regexp |
|
|
+--------------+----------------------+
|
|
|
|
+----------------------------------------------------+
|
|
| tag_variants |
|
|
+----------------+-----------------------------------+
|
|
| Key | Description |
|
|
| anyexact | is tagged with |
|
|
| allwordssubstr | contains all of the words/strings |
|
|
| anywordssubstr | contains any of the words/strings |
|
|
| substring | contains the string |
|
|
| casesubstring | contains the string (exact case) |
|
|
| regexp | matches the regexp |
|
|
| notregexp | doesn't match the regexp |
|
|
| allwords | contains all of the words |
|
|
| anywords | contains any of the words |
|
|
| nowords | contains none of the words |
|
|
+----------------------------------------------------+
|
|
|
|
Returns: Array: Matching test cases are retuned in a list of hashes.
|
|
|
|
=item C<list_count>
|
|
|
|
Description: Performs a search and returns the resulting count of cases.
|
|
|
|
Params: $query - Hash: keys must match valid search fields (see list).
|
|
|
|
Returns: Integer - total matching cases.
|
|
|
|
=item C<lookup_priority_name_by_id>
|
|
|
|
Params: $id - Integer: ID of the case status to return
|
|
|
|
Returns: String: the status name.
|
|
|
|
=item C<lookup_priority_id_by_name>
|
|
|
|
Params: $name - String: the status name.
|
|
|
|
Returns: Integer: ID of the case status.
|
|
|
|
=item C<lookup_status_name_by_id>
|
|
|
|
Params: $id - Integer: ID of the case status to return
|
|
|
|
Returns: String: the status name.
|
|
|
|
=item C<lookup_status_id_by_name>
|
|
|
|
Params: $name - String: the status name.
|
|
|
|
Returns: Integer: ID of the case status.
|
|
|
|
=item C<remove_component>
|
|
|
|
Description: Removes selected component from the selected test case.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$component_id - Integer: - The component ID to be removed.
|
|
|
|
Returns: Array: Empty on success.
|
|
|
|
=item C<remove_tag>
|
|
|
|
Description: Remove a tag from a case.
|
|
|
|
Params: $case_ids - Integer/Array/String: An integer or alias representing the ID in the database,
|
|
an array of case_ids or aliases, or a string of comma separated case_ids.
|
|
|
|
$tag - String - A single tag to be removed.
|
|
|
|
Returns: Array: Empty on success.
|
|
|
|
=item C<store_text>
|
|
|
|
Description: Update the large text fields of a case.
|
|
|
|
Params: $case_id - Integer: An integer or alias representing the ID in the database.
|
|
$action, $effect, $setup, $breakdown - String: Text for these fields.
|
|
[$author_id] = Integer/String: (OPTIONAL) The numeric ID or the login of the author.
|
|
Defaults to logged in user
|
|
|
|
Returns: Integer: Version of the stored text
|
|
|
|
=item C<unlink_plan>
|
|
|
|
Description: Unlink a test case from the given plan. If only one plan is linked, this will delete
|
|
the test case.
|
|
|
|
Params: $case_id - Integer/String: An integer or alias representing the ID in the database.
|
|
|
|
$plan_id - Integer: An integer representing the ID in the database.
|
|
|
|
Returns: Array: Array of plans still linked if any, empty if not.
|
|
|
|
=item C<update>
|
|
|
|
Description: Updates the fields of the selected case or cases.
|
|
|
|
Params: $ids - Integer/String/Array
|
|
Integer: A single TestCase ID.
|
|
String: A comma separates string of TestCase IDs for batch
|
|
processing.
|
|
Array: An array of case IDs for batch mode processing
|
|
|
|
$values - Hash of keys matching TestCase fields and the new values
|
|
to set each field to.
|
|
|
|
Returns: Hash/Array: In the case of a single case it is returned. If a
|
|
list was passed, it returns an array of case hashes. If the
|
|
update on any particular case failed, the has will contain a
|
|
ERROR key and the message as to why it failed.
|
|
+-------------------+----------------+
|
|
| Field | Type |
|
|
+-------------------+----------------+
|
|
| ids (redonly) | Integer/String |
|
|
| status | Integer/String |
|
|
| category | Integer/String |
|
|
| priority | Integer/String |
|
|
| default_tester | Integer/String |
|
|
| estimated_time | String |
|
|
| isautomated | Boolean |
|
|
| sortkey | Integer |
|
|
| script | String |
|
|
| arguments | String |
|
|
| summary | String |
|
|
| requirement | String |
|
|
| alias | String |
|
|
| dependson | Array/String |
|
|
| blocks | Array/String |
|
|
+-------------------+----------------+
|
|
|
|
=back
|
|
|
|
=head1 SEE ALSO
|
|
|
|
L<Bugzilla::Extension::Testopia::TestCase>
|
|
L<Bugzilla::Webservice>
|
|
|
|
=head1 AUTHOR
|
|
|
|
Greg Hendricks <ghendricks@novell.com> |