Comitting Testopia 1.1 beta
git-svn-id: svn://10.0.0.236/trunk@213182 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -163,7 +163,7 @@ sub store {
|
||||
$self->{'filename'}, $timestamp, $self->{'mime_type'});
|
||||
|
||||
my $key = $dbh->bz_last_key( 'test_attachments', 'attachment_id' );
|
||||
$dbh->do("INSERT INTO test_attachment_data VALUES(?,?)",
|
||||
$dbh->do("INSERT INTO test_attachment_data (attachment_id, contents) VALUES(?,?)",
|
||||
undef, $key, $self->{'contents'});
|
||||
|
||||
return $key;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
|
||||
package Bugzilla::Testopia::Classification;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Config;
|
||||
|
||||
# Extends Bugzilla::Classification;
|
||||
use base "Bugzilla::Classification";
|
||||
|
||||
use Bugzilla;
|
||||
|
||||
sub user_visible_products {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
if (!$self->{'products'}) {
|
||||
my $query = "SELECT id FROM products " .
|
||||
"LEFT JOIN group_control_map " .
|
||||
"ON group_control_map.product_id = products.id ";
|
||||
if (Param('useentrygroupdefault')) {
|
||||
$query .= "AND group_control_map.entry != 0 ";
|
||||
} else {
|
||||
$query .= "AND group_control_map.membercontrol = " .
|
||||
CONTROLMAPMANDATORY . " ";
|
||||
}
|
||||
if (%{Bugzilla->user->groups}) {
|
||||
$query .= "AND group_id NOT IN(" .
|
||||
join(',', values(%{Bugzilla->user->groups})) . ") ";
|
||||
}
|
||||
$query .= "WHERE group_id IS NULL AND products.classification_id= ? ORDER BY products.name";
|
||||
|
||||
my $product_ids = $dbh->selectcol_arrayref($query, undef, $self->id);
|
||||
|
||||
my @products;
|
||||
foreach my $product_id (@$product_ids) {
|
||||
push (@products, new Bugzilla::Testopia::Product($product_id));
|
||||
}
|
||||
$self->{'user_visible_products'} = \@products;
|
||||
}
|
||||
return $self->{'user_visible_products'};
|
||||
}
|
||||
|
||||
sub products_to_json {
|
||||
my $self = shift;
|
||||
my ($disable_move) = @_;
|
||||
|
||||
$disable_move ||= '';
|
||||
$disable_move = ',"addChild","move"' if $disable_move;
|
||||
my $products = $self->user_visible_products;
|
||||
my $json = "[";
|
||||
foreach my $obj (@{$products}){
|
||||
$json .= '{title:"' . $obj->name . '",';
|
||||
$json .= 'isFolder:' . (scalar @{$obj->environment_categories} > 0 ? "true" : "false") . ',';
|
||||
$json .= 'objectId:"' . $obj->id . '",';
|
||||
$json .= 'widgetId:"product' . $obj->id . '",';
|
||||
$json .= 'actionsDisabled:["addElement","addProperty","addValue"'. $disable_move .'],';
|
||||
$json .= 'childIconSrc:"testopia/img/folder_red.gif"},';
|
||||
}
|
||||
chop $json;
|
||||
$json .= "]";
|
||||
return $json;
|
||||
}
|
||||
1;
|
||||
@@ -16,7 +16,9 @@
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
# Michael Hight <mjhight@gmail.com>
|
||||
# Garrett Braden <gbraden@novell.com>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
@@ -26,11 +28,12 @@ Bugzilla::Testopia::Environment - A test environment
|
||||
|
||||
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
|
||||
the information is captured as an XML document. At the very least
|
||||
however, and environment consists of the OS and platform from
|
||||
Bugzilla.
|
||||
Environments can be very simple or very complex.
|
||||
|
||||
Environments are comprised of Elemements, Properties, and Values.
|
||||
Elements can be nested within other elements. Each element can have
|
||||
zero or more properties. Each property can only have one value selected
|
||||
of the possible values.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -54,23 +57,23 @@ use Bugzilla::User;
|
||||
=head1 FIELDS
|
||||
|
||||
environment_id
|
||||
op_sys_id
|
||||
rep_platform_id
|
||||
product_id
|
||||
name
|
||||
xml
|
||||
isactive
|
||||
|
||||
=cut
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
test_environments.environment_id
|
||||
test_environments.op_sys_id
|
||||
test_environments.rep_platform_id
|
||||
test_environments.name
|
||||
test_environments.xml
|
||||
environment_id
|
||||
product_id
|
||||
name
|
||||
isactive
|
||||
);
|
||||
|
||||
our $columns = join(", ", DB_COLUMNS);
|
||||
|
||||
our constant $max_depth = 7;
|
||||
|
||||
###############################
|
||||
#### Methods ####
|
||||
###############################
|
||||
@@ -101,16 +104,18 @@ sub _init {
|
||||
my $self = shift;
|
||||
my ($param) = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $id = $param unless (ref $param eq 'HASH');
|
||||
|
||||
my $id = $param unless (ref $param eq 'HASH' || ref $param eq 'Bugzilla::Testopia::Environment::Xml');
|
||||
my $obj;
|
||||
|
||||
|
||||
if (defined $id && detaint_natural($id)) {
|
||||
|
||||
$obj = $dbh->selectrow_hashref(qq{
|
||||
SELECT $columns FROM test_environments
|
||||
WHERE environment_id = ?}, undef, $id);
|
||||
} elsif (ref $param eq 'HASH'){
|
||||
SELECT $columns
|
||||
FROM test_environments
|
||||
WHERE environment_id = ?}, undef, ($id));
|
||||
|
||||
} elsif (ref $param eq 'HASH' || ref $param eq 'Bugzilla::Testopia::Environment::Xml'){
|
||||
$obj = $param;
|
||||
}
|
||||
|
||||
@@ -119,41 +124,263 @@ sub _init {
|
||||
foreach my $field (keys %$obj) {
|
||||
$self->{$field} = $obj->{$field};
|
||||
}
|
||||
|
||||
if(! ref $obj eq 'Bugzilla::Testopia::Environment::Xml'){
|
||||
|
||||
$self->get_environment_elements();
|
||||
my @elements = $self->{'elements'};
|
||||
|
||||
foreach my $elem (@elements)
|
||||
{
|
||||
foreach my $element (@$elem)
|
||||
{
|
||||
|
||||
my $elem_id = $element->{'element_id'};
|
||||
my @properties = $element->{'properties'};
|
||||
|
||||
foreach my $prop (@properties)
|
||||
{
|
||||
foreach my $property (@$prop)
|
||||
{
|
||||
my $prop_id = $property->{'property_id'};
|
||||
$property->{'value_selected'} = $self->get_value_selected($self->{'environment_id'},$elem_id,$prop_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
=head2 get_op_sys_list
|
||||
|
||||
Returns the list of bugzilla op_sys entries
|
||||
=head2 get element list for environment
|
||||
|
||||
Returns an array of element objects for an environment
|
||||
|
||||
=cut
|
||||
|
||||
sub get_op_sys_list{
|
||||
my $self = shift;
|
||||
sub get_environment_elements{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT id, value AS name
|
||||
FROM op_sys
|
||||
ORDER BY sortkey", {'Slice'=>{}});
|
||||
my $self = shift;
|
||||
|
||||
return $self->{'elements'} if exists $self->{'elements'};
|
||||
|
||||
my $id = $self->{'environment_id'};
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(qq{
|
||||
SELECT DISTINCT tee.element_id
|
||||
FROM test_environment_map as tem
|
||||
JOIN test_environment_element as tee
|
||||
ON tem.element_id = tee.element_id
|
||||
WHERE tem.environment_id = ?},undef,$id);
|
||||
|
||||
my @elements;
|
||||
|
||||
return $ref;
|
||||
foreach my $val (@$ref){
|
||||
push @elements, Bugzilla::Testopia::Environment::Element->new($val);
|
||||
}
|
||||
$self->{'elements'} = \@elements;
|
||||
|
||||
return \@elements;
|
||||
}
|
||||
|
||||
=head2 get_rep_platform_list
|
||||
sub element_count {
|
||||
my $self = shift;
|
||||
|
||||
return scalar(@{$self->get_environment_elements});
|
||||
}
|
||||
|
||||
Returns the list of rep_platforms from bugzilla
|
||||
sub elements_to_json {
|
||||
my $self = shift;
|
||||
|
||||
my $elements = $self->get_environment_elements;
|
||||
my $json = '[';
|
||||
|
||||
foreach my $element (@$elements)
|
||||
{
|
||||
$json .= '{title:"'. $element->{'name'} .'",';
|
||||
$json .= 'objectId:"'. $element->{'element_id'}. '",';
|
||||
$json .= 'widgetId:"element'. $element->{'element_id'} .'",';
|
||||
$json .= 'actionsDisabled:["addCategory","addValue","addChild"],';
|
||||
$json .= 'isFolder:true,' if($element->check_for_children || $element->check_for_properties);
|
||||
$json .= 'childIconSrc:"testopia/img/circle.gif"},';
|
||||
}
|
||||
chop $json;
|
||||
$json .= ']';
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
=head2 get_value_selected
|
||||
|
||||
Returns a selected value for the specified environment element property instance.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_rep_platform_list{
|
||||
sub get_value_selected{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT id, value AS name
|
||||
FROM rep_platform
|
||||
ORDER BY sortkey", {'Slice'=>{}});
|
||||
|
||||
my ($environment,$element,$property) = (@_);
|
||||
|
||||
my ($var) = $dbh->selectrow_array(
|
||||
"SELECT value_selected
|
||||
FROM test_environment_map
|
||||
WHERE environment_id = ?
|
||||
AND element_id = ?
|
||||
AND property_id = ?",
|
||||
undef,($environment,$element,$property));
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
return $ref;
|
||||
=head2 get environment names
|
||||
|
||||
Returns the list of environment names and ids
|
||||
|
||||
=cut
|
||||
|
||||
sub get_environments{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT environment_id, name
|
||||
FROM test_environments");
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub get_all_env_categories {
|
||||
my $self = shift;
|
||||
my ($byid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $idstr = $byid ? 'env_category_id' : 'DISTINCT name';
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT $idstr AS id, name
|
||||
FROM test_environment_category",
|
||||
{'Slice' => {}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub get_all_visible_elements {
|
||||
my $self = shift;
|
||||
my ($byid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $idstr = $byid ? 'element_id' : 'DISTINCT name';
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT $idstr AS id, name
|
||||
FROM test_environment_element",
|
||||
{'Slice' => {}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub get_all_element_properties {
|
||||
my $self = shift;
|
||||
my ($byid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $idstr = $byid ? 'property_id' : 'DISTINCT name';
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT $idstr AS id, name, validexp
|
||||
FROM test_environment_property",
|
||||
{'Slice' => {}});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub get_distinct_property_values {
|
||||
my $self = shift;
|
||||
my @exps;
|
||||
foreach my $prop (@{$self->get_all_element_properties}){
|
||||
push @exps, split(/\|/, $prop->{'validexp'})
|
||||
}
|
||||
my %seen;
|
||||
foreach my $v (@exps){
|
||||
$seen{$v} = $v;
|
||||
}
|
||||
my @values;
|
||||
foreach my $v (keys %seen){
|
||||
my %p;
|
||||
$p{'id'} = $v;
|
||||
$p{'name'} = $v;
|
||||
push @values, \%p;
|
||||
}
|
||||
return \@values;
|
||||
}
|
||||
|
||||
=head2 get all elements
|
||||
|
||||
Returns the list of element names, ids and category names
|
||||
|
||||
=cut
|
||||
|
||||
sub get_all_elements{
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT tee.element_id
|
||||
FROM test_environment_map as tem
|
||||
JOIN test_environment_element as tee
|
||||
ON tem.element_id = tee.element_id",
|
||||
undef);
|
||||
|
||||
my @elements;
|
||||
|
||||
foreach my $val (@$ref){
|
||||
push @elements, Bugzilla::Testopia::Environment::Element->new($val);
|
||||
}
|
||||
|
||||
return \@elements;
|
||||
}
|
||||
|
||||
=head2 check environment name
|
||||
|
||||
Returns environment id if environment exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_environment{
|
||||
my $self = shift;
|
||||
my ($name, $product_id) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT environment_id
|
||||
FROM test_environments
|
||||
WHERE name = ? AND product_id = ?",
|
||||
undef, ($name, $product_id));
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
|
||||
=head2 Check Environment Element Property Value Selected
|
||||
|
||||
Returns environment id if Environment Element Property Value Selected exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_value_selected {
|
||||
my $self = shift;
|
||||
my ($prop_id, $elem_id) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT environment_id
|
||||
FROM test_environment_map
|
||||
WHERE environment_id = ?
|
||||
AND property_id = ?
|
||||
AND element_id = ?",
|
||||
undef, ($self->{'environment_id'}, $prop_id, $elem_id));
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 store
|
||||
@@ -165,17 +392,64 @@ Serializes this environment to the database
|
||||
sub store {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
# Verify name is available
|
||||
return 0 if $self->check_name($self->{'name'});
|
||||
|
||||
|
||||
#Verify Environment isn't already in use.
|
||||
return undef if $self->check_environment($self->{'name'}, $self->{'product_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environments ($columns)
|
||||
VALUES (?,?,?,?,?)",
|
||||
undef, (undef, $self->{'op_sys_id'},
|
||||
$self->{'rep_platform_id'}, $self->{'name'},
|
||||
$self->{'xml'}));
|
||||
my $key = $dbh->bz_last_key( 'test_plans', 'plan_id' );
|
||||
return $key;
|
||||
VALUES (?,?,?,?)",
|
||||
undef, (undef, $self->{'product_id'}, $self->{'name'}, $self->{'isactive'}));
|
||||
my $key = $dbh->bz_last_key( 'test_environments', 'environment_id' );
|
||||
|
||||
my $elements = $self->{'elements'};
|
||||
|
||||
foreach my $element (@$elements)
|
||||
{
|
||||
$self->persist_environment_element_and_children(1, $element, "store");
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
=head2 store property values
|
||||
|
||||
Serializes the property values to the database
|
||||
|
||||
=cut
|
||||
|
||||
sub store_property_value {
|
||||
my $self = shift;
|
||||
|
||||
my ($prop_id,$elem_id,$value_selected) = @_;
|
||||
|
||||
return 0 if ($self->check_value_selected($prop_id, $elem_id, $value_selected));
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environment_map (environment_id,property_id,element_id,value_selected)
|
||||
VALUES (?,?,?,?)",undef, ($self->{'environment_id'}, $prop_id, $elem_id,$value_selected));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 store environment name
|
||||
|
||||
Serializes the environment name to the database
|
||||
|
||||
=cut
|
||||
|
||||
sub store_environment_name {
|
||||
my $self = shift;
|
||||
my ($name, $product_id) = (@_);
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
return undef if $self->check_environment($name, $product_id);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environments ($columns)
|
||||
VALUES (?,?,?,?)", undef,
|
||||
(undef,$product_id,$name,1));
|
||||
return $dbh->bz_last_key( 'test_environments', 'environment_id' );
|
||||
}
|
||||
|
||||
=head2 update
|
||||
@@ -190,12 +464,18 @@ sub update {
|
||||
my $self = shift;
|
||||
my ($newvalues) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $product_id;
|
||||
|
||||
$dbh->bz_lock_tables('test_environments WRITE');
|
||||
foreach my $field (keys %{$newvalues}){
|
||||
if ($self->{$field} ne $newvalues->{$field}){
|
||||
# If the new name is already in use, return.
|
||||
if ($field eq 'name' && $self->check_name($newvalues->{'name'})) {
|
||||
$product_id = $newvalues->{'product_id'} || $self->{'product_id'};
|
||||
if ($product_id eq undef) {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 0;
|
||||
}
|
||||
if ($field eq 'name' && $self->check_environment($newvalues->{'name'}, $product_id)) {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 0;
|
||||
}
|
||||
@@ -203,15 +483,86 @@ sub update {
|
||||
$dbh->do("UPDATE test_environments
|
||||
SET $field = ? WHERE environment_id = ?",
|
||||
undef, $newvalues->{$field}, $self->{'environment_id'});
|
||||
$self->{$field} = $newvalues->{$field};
|
||||
|
||||
$self->{$field} = $newvalues->{$field};
|
||||
}
|
||||
}
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
my $elements = $self->{'elements'};
|
||||
|
||||
foreach my $element (@$elements)
|
||||
{
|
||||
$self->persist_environment_element_and_children(1, $element, "update");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head2 persist_environment_element_and_children
|
||||
|
||||
Persists Environment Element and Children Recursively.
|
||||
|
||||
=cut
|
||||
|
||||
sub persist_environment_element_and_children {
|
||||
my $self = shift;
|
||||
my ($depth, $element, $method) = @_;
|
||||
if ($depth > $max_depth) {
|
||||
return;
|
||||
}
|
||||
$depth++;
|
||||
my $elem_id = $element->{'element_id'};
|
||||
my $properties = $element->{'properties'};
|
||||
foreach my $property (@$properties)
|
||||
{
|
||||
my $prop_id = $property->{'property_id'};
|
||||
my $value_selected = $property->{'value_selected'};
|
||||
my ($value_stored) = $self->get_value_selected($self->{'environment_id'},$prop_id,$elem_id);
|
||||
if ($method eq "store" || $value_stored eq undef) {
|
||||
$self->store_property_value($prop_id,$elem_id,$value_selected);
|
||||
}
|
||||
else {
|
||||
$self->update_property_value($prop_id,$elem_id,$value_selected);
|
||||
}
|
||||
}
|
||||
my $children = $element->{'children'};
|
||||
foreach my $child_element (@$children) {
|
||||
$self->persist_environment_element_and_children($depth, $child_element, $method);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=head2 update property value
|
||||
|
||||
Updates the property of the element in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub update_property_value {
|
||||
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
my $self = shift;
|
||||
my ($propID, $elemID, $valueSelected) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_map
|
||||
SET value_selected = ? WHERE environment_id = ? AND property_id = ? AND element_id = ?"
|
||||
,undef, ($valueSelected,$self->{'environment_id'},$propID,$elemID));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub delete_element {
|
||||
my $self = shift;
|
||||
my ($element_id) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->do("DELETE FROM test_environment_map
|
||||
WHERE environment_id = ? AND element_id = ?",
|
||||
undef,($self->id, $element_id));
|
||||
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
||||
Completely removes this environment from the database.
|
||||
@@ -222,19 +573,23 @@ sub obliterate {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_runs READ', 'test_environments WRITE');
|
||||
$dbh->bz_lock_tables('test_runs READ', 'test_environments WRITE','test_environment_map WRITE');
|
||||
my $used = $dbh->selectrow_array("SELECT 1 FROM test_runs
|
||||
WHERE environment_id = ?",
|
||||
WHERE environment_id = ?",
|
||||
undef, $self->{'environment_id'});
|
||||
if ($used) {
|
||||
$dbh->bz_unlock_tables;
|
||||
ThrowUserError("testopia-non-zero-run-count", {'object' => 'Environment'});
|
||||
}
|
||||
$dbh->do("DELETE FROM test_environments
|
||||
$dbh->do("UPDATE test_environments SET isactive = 0
|
||||
WHERE environment_id = ?", undef, $self->{'environment_id'});
|
||||
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head2 get_run_list
|
||||
|
||||
Returns a list of run ids associated with this environment.
|
||||
@@ -245,7 +600,7 @@ sub get_run_list {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $ref = $dbh->selectcol_arrayref("SELECT run_id FROM test_runs
|
||||
WHERE environment_id = ?",
|
||||
WHERE environment_id = ?",
|
||||
undef, $self->{'environment_id'});
|
||||
return join(",", @{$ref});
|
||||
}
|
||||
@@ -260,29 +615,11 @@ sub get_run_count {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($count) = $dbh->selectrow_array("SELECT COUNT(run_id) FROM test_runs
|
||||
WHERE environment_id = ?",
|
||||
WHERE environment_id = ?",
|
||||
undef, $self->{'environment_id'});
|
||||
return $count;
|
||||
}
|
||||
|
||||
=head2 check_name
|
||||
|
||||
Returns true if an environment of the specified name exists
|
||||
in the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub check_name {
|
||||
my $self = shift;
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($used) = $dbh->selectrow_array("SELECT 1
|
||||
FROM test_environments
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 canedit
|
||||
|
||||
Returns true if the logged in user has rights to edit this environment.
|
||||
@@ -333,57 +670,32 @@ Returns the ID of this object
|
||||
|
||||
Returns the name of this object
|
||||
|
||||
=head2 xml
|
||||
|
||||
Returnst the xml associated with this environment
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'environment_id'}; }
|
||||
sub product_id { return $_[0]->{'product_id'}; }
|
||||
sub isactive { return $_[0]->{'isactive'}; }
|
||||
sub name { return $_[0]->{'name'}; }
|
||||
sub xml { return $_[0]->{'xml'}; }
|
||||
|
||||
=head2 op_sys
|
||||
=head2 product
|
||||
|
||||
Returns the bugzilla op_sys value
|
||||
Returns the bugzilla product
|
||||
|
||||
=cut
|
||||
|
||||
sub op_sys {
|
||||
sub product {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'op_sys'} if exists $self->{'op_sys'};
|
||||
my ($res) = $dbh->selectrow_array("SELECT value
|
||||
FROM op_sys
|
||||
WHERE id = ?",
|
||||
undef, $self->{'op_sys_id'});
|
||||
$self->{'op_sys'} = $res;
|
||||
return $self->{'op_sys'};
|
||||
|
||||
}
|
||||
|
||||
=head2 rep_platform
|
||||
|
||||
Returns the bugzilla rep_platform value
|
||||
|
||||
=cut
|
||||
|
||||
sub rep_platform {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'rep_platform'} if exists $self->{'rep_platform'};
|
||||
my ($res) = $dbh->selectrow_array("SELECT value
|
||||
FROM rep_platform
|
||||
WHERE id = ?",
|
||||
undef, $self->{'rep_platform_id'});
|
||||
$self->{'rep_platform'} = $res;
|
||||
return $self->{'rep_platform'};
|
||||
return $self->{'product'} if exists $self->{'product'};
|
||||
|
||||
$self->{'product'} = Bugzilla::Product->new($self->{'product_id'});
|
||||
return $self->{'product'};
|
||||
|
||||
}
|
||||
|
||||
=head1 TODO
|
||||
|
||||
Use Bugzilla methods for op_sys and rep_platforms in 2.22
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
||||
@@ -0,0 +1,543 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
# Michael Hight <mjhight@gmail.com>
|
||||
# Garrett Braden <gbraden@novell.com>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Testopia::Environment::Category - A test element category
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Categories are used to organize environment elements.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
$prop = Bugzilla::Testopia::Environment::Category->new($env_category_id);
|
||||
$prop = Bugzilla::Testopia::Environment::Category->new(\%cat_hash);
|
||||
|
||||
=cut
|
||||
|
||||
package Bugzilla::Testopia::Environment::Category;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Constants;
|
||||
|
||||
###############################
|
||||
#### Initialization ####
|
||||
###############################
|
||||
|
||||
=head1 FIELDS
|
||||
|
||||
env_category_id
|
||||
product_id
|
||||
name
|
||||
|
||||
=cut
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
env_category_id
|
||||
product_id
|
||||
name
|
||||
);
|
||||
|
||||
our $columns = join(", ", DB_COLUMNS);
|
||||
|
||||
###############################
|
||||
#### Methods ####
|
||||
###############################
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new
|
||||
|
||||
Instantiates a new Category object
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {};
|
||||
bless($self, $class);
|
||||
return $self->_init(@_);
|
||||
}
|
||||
|
||||
=head2 _init
|
||||
|
||||
Private constructor for the category class
|
||||
|
||||
=cut
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
my ($param) = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $id = $param unless (ref $param eq 'HASH');
|
||||
my $obj;
|
||||
|
||||
if (defined $id && detaint_natural($id)) {
|
||||
|
||||
$obj = $dbh->selectrow_hashref(qq{
|
||||
SELECT $columns
|
||||
FROM test_environment_category
|
||||
WHERE env_category_id = ?}, undef, $id);
|
||||
} elsif (ref $param eq 'HASH'){
|
||||
$obj = $param;
|
||||
}
|
||||
|
||||
return undef unless (defined $obj);
|
||||
|
||||
foreach my $field (keys %$obj) {
|
||||
$self->{$field} = $obj->{$field};
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
=head2 get element list by category
|
||||
|
||||
Returns an array of element objects for a category
|
||||
|
||||
=cut
|
||||
|
||||
sub get_elements_by_category{
|
||||
my $self = shift;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(qq{
|
||||
SELECT element_id
|
||||
FROM test_environment_element
|
||||
WHERE env_category_id = ?}, undef, $self->{'env_category_id'});
|
||||
|
||||
my @elements;
|
||||
|
||||
foreach my $val (@$ref){
|
||||
push @elements, Bugzilla::Testopia::Environment::Element->new($val);
|
||||
};
|
||||
|
||||
return \@elements;
|
||||
}
|
||||
|
||||
=head2 get_parent_elements
|
||||
|
||||
Returns an array of parent elements by category
|
||||
|
||||
=cut
|
||||
|
||||
sub get_parent_elements{
|
||||
my $self = shift;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
################## original
|
||||
# Matches null for parent id
|
||||
#
|
||||
# my $ref = $dbh->selectcol_arrayref(qq{
|
||||
# SELECT element_id
|
||||
# FROM test_environment_element
|
||||
# WHERE env_category_id = ? AND parent_id is null }, undef, $self->{'env_category_id'});
|
||||
#
|
||||
############### end original delete when ready
|
||||
|
||||
|
||||
################## edited original
|
||||
# Matches 0 for parent id
|
||||
#
|
||||
# my $ref = $dbh->selectcol_arrayref(qq{
|
||||
# SELECT element_id
|
||||
# FROM test_environment_element
|
||||
# WHERE env_category_id = ? AND parent_id = 0 }, undef, $self->{'env_category_id'});
|
||||
#
|
||||
############### end edited original keep this one when ready
|
||||
|
||||
|
||||
########### temp fix to address issues with 0 or null in test_envrionment_element parent_id column
|
||||
##### matching null OR 0
|
||||
my $ref = $dbh->selectcol_arrayref(qq{
|
||||
SELECT element_id
|
||||
FROM test_environment_element
|
||||
WHERE env_category_id = ? AND (parent_id is null or parent_id = 0) }, undef, $self->{'env_category_id'});
|
||||
########### end temp fix.... delete when ready
|
||||
|
||||
my @elements;
|
||||
|
||||
foreach my $val (@$ref){
|
||||
push @elements, Bugzilla::Testopia::Environment::Element->new($val);
|
||||
};
|
||||
|
||||
return \@elements;
|
||||
}
|
||||
|
||||
=head2 check_for_elements
|
||||
|
||||
Returns 1 if a category has any elements
|
||||
|
||||
=cut
|
||||
|
||||
sub check_for_elements{
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectrow_array(qq{
|
||||
SELECT 1
|
||||
FROM test_environment_element
|
||||
WHERE env_category_id = ?}, undef, $self->{'env_category_id'});
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
=head2 get_product_list
|
||||
|
||||
Returns the product_id, product name, and count of categories
|
||||
|
||||
=cut
|
||||
|
||||
sub get_env_product_list{
|
||||
my $self = shift;
|
||||
my ($class_id) = @_;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $query = "SELECT p.id, p.name, COUNT(tec.env_category_id) AS cat_count
|
||||
FROM products p
|
||||
LEFT JOIN group_control_map
|
||||
ON group_control_map.product_id = p.id ";
|
||||
|
||||
if (Param('useentrygroupdefault')) {
|
||||
$query .= "AND group_control_map.entry != 0 ";
|
||||
} else {
|
||||
$query .= "AND group_control_map.membercontrol = " .
|
||||
CONTROLMAPMANDATORY . " ";
|
||||
}
|
||||
if (%{Bugzilla->user->groups}) {
|
||||
$query .= "AND group_id NOT IN(" .
|
||||
join(',', values(%{Bugzilla->user->groups})) . ") ";
|
||||
}
|
||||
|
||||
$query .= "LEFT OUTER JOIN test_environment_category AS tec
|
||||
ON p.id = tec.product_id ";
|
||||
$query .= "WHERE group_id IS NULL ";
|
||||
$query .= "AND classification_id = ? " if $class_id;
|
||||
$query .= "GROUP BY p.id
|
||||
ORDER BY p.name";
|
||||
|
||||
|
||||
my $ref;
|
||||
if($class_id){
|
||||
$ref = $dbh->selectall_arrayref($query, {'Slice' => {}}, $class_id);
|
||||
}
|
||||
else{
|
||||
$ref = $dbh->selectall_arrayref($query, {'Slice' => {}});
|
||||
}
|
||||
unshift @$ref, {'id' => 0, 'name' => '--ALL--', 'cat_count' => $self->get_all_child_count };
|
||||
return $ref;
|
||||
|
||||
}
|
||||
|
||||
sub get_all_child_count {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($all_count) = $dbh->selectrow_array(
|
||||
"SELECT COUNT(*)
|
||||
FROM test_environment_category
|
||||
WHERE product_id = 0");
|
||||
|
||||
return $all_count;
|
||||
}
|
||||
|
||||
sub product_categories_to_json {
|
||||
my $self = shift;
|
||||
my ($product_id, $disable_move) = @_;
|
||||
detaint_natural($product_id);
|
||||
$disable_move = ',"addChild","move"' if $disable_move;
|
||||
my $json = "[";
|
||||
foreach my $cat (@{$self->get_element_categories_by_product($product_id)}){
|
||||
$json .= '{title:"' . $cat->name . '",';
|
||||
$json .= 'isFolder:' . ($cat->check_for_elements() ? "true" : "false") . ',';
|
||||
$json .= 'objectId:"' . $cat->id . '",';
|
||||
$json .= 'widgetId:"category' . $cat->id . '",';
|
||||
$json .= 'actionsDisabled:["addCategory","addProperty","addValue"';
|
||||
$json .= $disable_move if $disable_move;
|
||||
$json .= ',"remove"' unless $cat->candelete;
|
||||
$json .= '],';
|
||||
$json .= 'childIconSrc:"testopia/img/square.gif"},';
|
||||
}
|
||||
chop $json;
|
||||
$json .= "]";
|
||||
return $json;
|
||||
}
|
||||
|
||||
=head2 get_element_categories_by_product
|
||||
|
||||
Returns the list of element category names and ids by product id
|
||||
|
||||
=cut
|
||||
|
||||
sub get_element_categories_by_product{
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($product_id) = (@_);
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT env_category_id
|
||||
FROM test_environment_category
|
||||
WHERE product_id = ?",
|
||||
undef, $product_id);
|
||||
my @objs;
|
||||
foreach my $id (@{$ref}){
|
||||
push @objs, Bugzilla::Testopia::Environment::Category->new($id);
|
||||
}
|
||||
return \@objs;
|
||||
}
|
||||
|
||||
|
||||
=head2 new_category_count
|
||||
|
||||
Returns 1 if element has children
|
||||
|
||||
=cut
|
||||
|
||||
sub new_category_count{
|
||||
my $self = shift;
|
||||
my ($prod_id) = @_;
|
||||
$prod_id ||= $self->{'product_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT COUNT(*)
|
||||
FROM test_environment_category
|
||||
WHERE name like 'New category%'
|
||||
AND product_id = ?",
|
||||
undef, $prod_id);
|
||||
|
||||
return $used + 1;
|
||||
}
|
||||
|
||||
sub elements_to_json {
|
||||
my $self = shift;
|
||||
my ($disable_add) = @_;
|
||||
$disable_add = ',"addChild"' if $disable_add;
|
||||
|
||||
my $elements = $self->get_parent_elements;
|
||||
my $json = '[';
|
||||
|
||||
foreach my $element (@$elements)
|
||||
{
|
||||
$json .= '{title:"'. $element->{'name'} .'",';
|
||||
$json .= 'objectId:"'. $element->{'element_id'}. '",';
|
||||
$json .= 'widgetId:"element'. $element->{'element_id'} .'",';
|
||||
$json .= 'actionsDisabled:["addCategory","addValue"';
|
||||
$json .= $disable_add if $disable_add;
|
||||
$json .= ',"remove"' unless $element->candelete;
|
||||
$json .= '],';
|
||||
$json .= 'isFolder:true,' if($element->check_for_children || $element->check_for_properties);
|
||||
$json .= 'childIconSrc:"testopia/img/circle.gif"},';
|
||||
}
|
||||
chop $json;
|
||||
$json .= ']';
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
=head2 check_category
|
||||
|
||||
Returns category id if a category exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_category{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
my ($name, $prodID) = (@_);
|
||||
|
||||
$prodID ||= $self->product_id;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT env_category_id
|
||||
FROM test_environment_category
|
||||
WHERE name = ? AND product_id = ?",
|
||||
undef,($name,$prodID));
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 check_category_by_id
|
||||
|
||||
Returns category name if a category id exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_category_by_id{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
my ($id) = (@_);
|
||||
|
||||
my ($used) = $dbh->selectrow_arrayref(qq{
|
||||
SELECT name
|
||||
FROM test_environment_category
|
||||
WHERE env_category_id = ?},undef,$id);
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
|
||||
=head2 store
|
||||
|
||||
Serializes this category to the database and returns the key or 0
|
||||
|
||||
=cut
|
||||
|
||||
sub store {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
return 0 if $self->check_category($self->{'name'},$self->{'product_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environment_category ($columns)
|
||||
VALUES (?,?,?)",undef, (undef, $self->{'product_id'},$self->{'name'}));
|
||||
my $key = $dbh->bz_last_key( 'test_environment_category', 'env_category_id' );
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
=head2 set_name
|
||||
|
||||
Updates the category name in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub set_name {
|
||||
my $self = shift;
|
||||
my ($name) = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
return undef if $self->check_category($name);
|
||||
|
||||
$dbh->do("UPDATE test_environment_category SET name = ?
|
||||
WHERE env_category_id = ? AND product_id = ?",
|
||||
undef, ($name, $self->{'env_category_id'},$self->{'product_id'}));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_product
|
||||
|
||||
Updates the category in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub set_product {
|
||||
my $self = shift;
|
||||
my ($product_id) = (@_);
|
||||
|
||||
return if ($product_id == $self->{'product_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_category SET product_id = ?
|
||||
WHERE env_category_id = ? AND product_id = ?",
|
||||
undef, ($product_id, $self->{'env_category_id'},$self->{'product_id'}));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
||||
Completely removes the element category entry from the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub obliterate {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_environment_element AS tee READ', 'test_environment_map AS tem READ', 'test_environment_category WRITE');
|
||||
|
||||
if (!$self->candelete) {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 0;
|
||||
}
|
||||
$dbh->do("DELETE FROM test_environment_category
|
||||
WHERE env_category_id = ?", undef, $self->id);
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $used = $dbh->selectrow_array(
|
||||
"SELECT 1 FROM test_environment_map AS tem
|
||||
JOIN test_environment_element AS tee ON tee.element_id = tem.element_id
|
||||
WHERE tee.env_category_id = ?",
|
||||
undef, $self->id);
|
||||
return !$used;
|
||||
|
||||
}
|
||||
|
||||
###############################
|
||||
#### Accessors ####
|
||||
###############################
|
||||
=head2 id
|
||||
|
||||
Returns the ID of this category
|
||||
|
||||
=head2 name
|
||||
|
||||
Returns the name of this category
|
||||
|
||||
=head2 product_id
|
||||
|
||||
Returns the product_id of this category
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'env_category_id'}; }
|
||||
sub name { return $_[0]->{'name'}; }
|
||||
sub product_id { return $_[0]->{'product_id'}; }
|
||||
|
||||
|
||||
=head2 product_name
|
||||
|
||||
Returns the name of the product this plan is associated with
|
||||
|
||||
=cut
|
||||
|
||||
sub product_name {
|
||||
my ($self) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'product_name'} if exists $self->{'product_name'};
|
||||
|
||||
my ($name) = $dbh->selectrow_array(
|
||||
"SELECT name FROM products
|
||||
WHERE id = ?",
|
||||
undef, $self->id);
|
||||
$self->{'product_name'} = $name;
|
||||
return $self->{'product_name'};
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,471 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
# Michael Hight <mjhight@gmail.com>
|
||||
# Garrett Braden <gbraden@novell.com>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Testopia::Environment::Element - A test environment element
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Environment elements are a set of environment entities that dictate
|
||||
the conditions a test was conducted in. Each environment must have an
|
||||
element. Elements can be very simple or very complex by adding properties.
|
||||
Elements can have child elements.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
$elem = Bugzilla::Testopia::Environment::Element->new($elem_id);
|
||||
$elem = Bugzilla::Testopia::Environment::Element->new(\%elem_hash);
|
||||
|
||||
=cut
|
||||
|
||||
package Bugzilla::Testopia::Environment::Element;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::User;
|
||||
use JSON;
|
||||
|
||||
###############################
|
||||
#### Initialization ####
|
||||
###############################
|
||||
|
||||
=head1 FIELDS
|
||||
|
||||
element_id
|
||||
env_category_id
|
||||
name
|
||||
parent_id
|
||||
isprivate
|
||||
|
||||
=cut
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
element_id
|
||||
env_category_id
|
||||
name
|
||||
parent_id
|
||||
isprivate
|
||||
);
|
||||
|
||||
our $columns = join(", ", DB_COLUMNS);
|
||||
|
||||
our constant $max_depth = 5;
|
||||
|
||||
###############################
|
||||
#### Methods ####
|
||||
###############################
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new
|
||||
|
||||
Instantiates a new Element object
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {};
|
||||
bless($self, $class);
|
||||
return $self->_init(@_);
|
||||
}
|
||||
|
||||
=head2 _init
|
||||
|
||||
Private constructor for the element class
|
||||
|
||||
=cut
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
my ($param) = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $id = $param unless (ref $param eq 'HASH');
|
||||
my $obj;
|
||||
|
||||
if (defined $id && detaint_natural($id)) {
|
||||
|
||||
$obj = $dbh->selectrow_hashref(
|
||||
"SELECT $columns
|
||||
FROM test_environment_element
|
||||
WHERE element_id = ?", undef, $id);
|
||||
} elsif (ref $param eq 'HASH'){
|
||||
$obj = $param;
|
||||
}
|
||||
|
||||
return undef unless (defined $obj);
|
||||
|
||||
foreach my $field (keys %$obj) {
|
||||
$self->{$field} = $obj->{$field};
|
||||
}
|
||||
|
||||
$self->get_properties();
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
=head2 get_children
|
||||
|
||||
Returns an array of the children objects for an element and recursively
|
||||
gets all of their children until exhausted.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_children{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
return $self->{'children'} if exists $self->{'children'};
|
||||
|
||||
my %newvalues = (@_);
|
||||
my $depth = $max_depth;
|
||||
|
||||
if(%newvalues)
|
||||
{
|
||||
$depth = $newvalues{'depth'};
|
||||
}
|
||||
|
||||
$depth--;
|
||||
|
||||
if($depth == 0)
|
||||
{return;}
|
||||
|
||||
my $id = $self->{'element_id'};
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(qq{
|
||||
SELECT tee.element_id
|
||||
FROM test_environment_element as tee
|
||||
WHERE tee.parent_id = ?},undef,$id);
|
||||
|
||||
my @children;
|
||||
|
||||
foreach my $val (@$ref){
|
||||
my $child = Bugzilla::Testopia::Environment::Element->new($val);
|
||||
$child->get_children('depth'=>$depth);
|
||||
push(@children,$child);
|
||||
}
|
||||
|
||||
$self->{'children'} = \@children;
|
||||
|
||||
}
|
||||
|
||||
=head2 get_properties
|
||||
|
||||
Returns an array of the property objects for an element.
|
||||
|
||||
=cut
|
||||
|
||||
sub get_properties{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(qq{
|
||||
SELECT tep.property_id
|
||||
FROM test_environment_property as tep
|
||||
WHERE tep.element_id = ?},undef,($self->{'element_id'}));
|
||||
|
||||
my @properties;
|
||||
|
||||
foreach my $val (@$ref){
|
||||
my $property = Bugzilla::Testopia::Environment::Property->new($val);
|
||||
push(@properties,$property);
|
||||
}
|
||||
|
||||
$self->{'properties'} = \@properties;
|
||||
return $self->{'properties'};
|
||||
|
||||
}
|
||||
|
||||
=head2 check_element
|
||||
|
||||
Returns element id if element exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_element{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
my ($name, $cat_id) = @_;
|
||||
|
||||
# Since categories are uniquely identified by product_id we don't have to check by join on the product_id.
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT element_id
|
||||
FROM test_environment_element
|
||||
WHERE name = ?
|
||||
AND env_category_id = ?",
|
||||
undef,($name,$cat_id));
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 check_for_children
|
||||
|
||||
Returns 1 if element has children
|
||||
|
||||
=cut
|
||||
|
||||
sub check_for_children{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(qq{
|
||||
SELECT 1
|
||||
FROM test_environment_element
|
||||
WHERE parent_id = ? },undef,$self->{'element_id'});
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
sub children_to_json{
|
||||
my $self = shift;
|
||||
my ($disable_move) = @_;
|
||||
|
||||
$disable_move = ',"addChild","move","remove"' if $disable_move;
|
||||
my $disable_add = ',"addChild"' if $disable_move;
|
||||
my $elements = $self->get_children;
|
||||
my $properties = $self->get_properties;
|
||||
my $json = '[';
|
||||
|
||||
foreach my $elem (@$elements)
|
||||
{
|
||||
$json .= '{title:"' . $elem->{'name'} . '",';
|
||||
$json .= 'objectId:"' . $elem->{'element_id'} . '",';
|
||||
$json .= 'widgetId:"element' . $elem->{'element_id'} . '",';
|
||||
$json .= 'actionsDisabled:["addCategory","addValue"';
|
||||
$json .= $disable_add if $disable_add;
|
||||
$json .=',"remove"' unless $elem->candelete;
|
||||
$json .= '],';
|
||||
$json .= 'isFolder:true,' if $elem->check_for_children();
|
||||
$json .= 'childIconSrc:"testopia/img/circle.gif"},';
|
||||
}
|
||||
foreach my $prop (@$properties)
|
||||
{
|
||||
$json .= '{title: "' . $prop->{'name'} .'",';
|
||||
$json .= 'objectId:"' . $prop->{'property_id'} . '",';
|
||||
$json .= 'widgetId:"property' . $prop->{'property_id'} . '",';
|
||||
$json .= 'actionsDisabled:["addCategory","addElement","addProperty"';
|
||||
$json .= $disable_move if $disable_move;
|
||||
$json .= ',"remove"' unless $prop->candelete;
|
||||
$json .= '],';
|
||||
$json .= 'isFolder:true,' if($prop->check_for_validexp($prop));
|
||||
$json .= 'childIconSrc:"testopia/img/triangle.gif"},';
|
||||
}
|
||||
chop $json if ($json ne '[');
|
||||
$json .= ']';
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
=head2 new_element_count
|
||||
|
||||
Returns 1 if element has children
|
||||
|
||||
=cut
|
||||
|
||||
sub new_element_count{
|
||||
my $self = shift;
|
||||
my ($cat_id) = @_;
|
||||
$cat_id ||= $self->{'env_category_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT COUNT(*)
|
||||
FROM test_environment_element
|
||||
WHERE name like 'New element%'
|
||||
AND env_category_id = ?",
|
||||
undef, $cat_id);
|
||||
|
||||
return $used + 1;
|
||||
}
|
||||
|
||||
=head2 check_for_properties
|
||||
|
||||
Returns 1 if element has properties
|
||||
|
||||
=cut
|
||||
|
||||
sub check_for_properties{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $self = shift;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(qq{
|
||||
SELECT 1
|
||||
FROM test_environment_property
|
||||
WHERE element_id = ? },undef,$self->{'element_id'});
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
|
||||
=head2 store
|
||||
|
||||
Serializes the new element to the database and returns the primary key or 0
|
||||
|
||||
=cut
|
||||
|
||||
sub store {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
# Verify name is available
|
||||
return undef if $self->check_element($self->{'name'},$self->{'env_category_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environment_element ($columns)
|
||||
VALUES (?,?,?,?,?)",
|
||||
undef, (undef, $self->{'env_category_id'}, $self->{'name'},
|
||||
$self->{'parent_id'},$self->{'isprivate'}));
|
||||
my $key = $dbh->bz_last_key('test_environment_element', 'element_id');
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
=head2 update_element_name
|
||||
|
||||
Updates the element in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub update_element_name {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
my ($name) = (@_);
|
||||
|
||||
return 0 if check_element($name, $self->{'env_category_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_element
|
||||
SET name = ? WHERE element_id = ?",undef, ($name,$self->{'element_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 update_element_category
|
||||
|
||||
Updates the category of the element in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub update_element_category {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
my ($catid) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_element
|
||||
SET env_category_id = ? WHERE element_id = ?",undef, ($catid,$self->{'element_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head2 update_element_parent
|
||||
|
||||
Updates the parent_id of the element in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub update_element_parent {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
my ($parent_id) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_element
|
||||
SET parent_id = ? WHERE element_id = ?",undef, ($parent_id,$self->{'element_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
||||
Completely removes the element entry from the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub obliterate {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_environment_map READ', 'test_environment_element WRITE');
|
||||
if (!$self->candelete) {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 0;
|
||||
}
|
||||
$dbh->do("DELETE FROM test_environment_element
|
||||
WHERE element_id = ?", undef, $self->{'element_id'});
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $used = $dbh->selectrow_array("SELECT 1 FROM test_environment_map
|
||||
WHERE element_id = ?",
|
||||
undef, $self->id);
|
||||
return !$used;
|
||||
|
||||
}
|
||||
|
||||
###############################
|
||||
#### Accessors ####
|
||||
###############################
|
||||
=head2 id
|
||||
|
||||
Returns the ID of this object
|
||||
|
||||
=head2 name
|
||||
|
||||
Returns the name of this object
|
||||
|
||||
=head2 product_id
|
||||
|
||||
Returns the product_id of this object
|
||||
|
||||
=head2 env_category_id
|
||||
|
||||
Returns the category_id associated with this element
|
||||
|
||||
=head2 parent_id
|
||||
|
||||
Returns the element's parent_id associated with this element
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'element_id'}; }
|
||||
sub name { return $_[0]->{'name'}; }
|
||||
sub product_id { return $_[0]->{'product_id'}; }
|
||||
sub env_category_id { return $_[0]->{'env_category_id'}; }
|
||||
sub parent_id { return $_[0]->{'parent_id'}; }
|
||||
sub isprivate { return $_[0]->{'isprivate'}; }
|
||||
sub get_parent { return $_[0]->new($_[0]->{'parent_id'}); }
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,372 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
# Michael Hight <mjhight@gmail.com>
|
||||
# Garrett Braden <gbraden@novell.com>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Testopia::Environment::Property - A test environment element property
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Element properties describe the elements in more detail. An
|
||||
element can have an unlimited number of properties to describe it.
|
||||
The valid expression limits the possible descriptions to valid choices
|
||||
for each property.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
$prop = Bugzilla::Testopia::Environment::Property->new($prop_id);
|
||||
$prop = Bugzilla::Testopia::Environment::Property->new(\%prop_hash);
|
||||
|
||||
=cut
|
||||
|
||||
package Bugzilla::Testopia::Environment::Property;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::User;
|
||||
###############################
|
||||
#### Initialization ####
|
||||
###############################
|
||||
|
||||
=head1 FIELDS
|
||||
|
||||
property_id
|
||||
element_id
|
||||
name
|
||||
validexp
|
||||
|
||||
=cut
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
property_id
|
||||
element_id
|
||||
name
|
||||
validexp
|
||||
);
|
||||
|
||||
our $columns = join(", ", DB_COLUMNS);
|
||||
|
||||
###############################
|
||||
#### Methods ####
|
||||
###############################
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new
|
||||
|
||||
Instantiates a new Property object
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {};
|
||||
bless($self, $class);
|
||||
return $self->_init(@_);
|
||||
}
|
||||
|
||||
=head2 _init
|
||||
|
||||
Private constructor for the property class
|
||||
|
||||
=cut
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
my ($param) = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $id = $param unless (ref $param eq 'HASH');
|
||||
my $obj;
|
||||
|
||||
if (defined $id && detaint_natural($id)) {
|
||||
|
||||
$obj = $dbh->selectrow_hashref(qq{
|
||||
SELECT $columns
|
||||
FROM test_environment_property
|
||||
WHERE property_id = ?}, undef, $id);
|
||||
} elsif (ref $param eq 'HASH'){
|
||||
$obj = $param;
|
||||
}
|
||||
|
||||
return undef unless (defined $obj);
|
||||
|
||||
foreach my $field (keys %$obj) {
|
||||
$self->{$field} = $obj->{$field};
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
=head2 check_property
|
||||
|
||||
Returns id if a property exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_property{
|
||||
my $self = shift;
|
||||
my ($name, $element_id) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
if ($name eq undef || $name eq '' || $element_id eq undef) {
|
||||
return "check_product must be passed a valid name and product_id";
|
||||
}
|
||||
|
||||
my ($used) = $dbh->selectrow_array(qq{
|
||||
SELECT property_id
|
||||
FROM test_environment_property
|
||||
WHERE name = ? AND element_id = ?},undef,$name,$element_id);
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 check_for_validexp
|
||||
|
||||
Returns 1 if a validexp exist for the property
|
||||
|
||||
=cut
|
||||
|
||||
sub check_for_validexp{
|
||||
my $self = shift;
|
||||
my $name = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(qq{
|
||||
SELECT 1
|
||||
FROM test_environment_property
|
||||
WHERE property_id = ? AND (validexp IS NOT NULL AND validexp <> '')},undef,$self->{'property_id'});
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
=head2 new_property_count
|
||||
|
||||
Returns the count + 1 of new properties
|
||||
|
||||
=cut
|
||||
|
||||
sub new_property_count{
|
||||
my $self = shift;
|
||||
my ($element_id) = @_;
|
||||
$element_id ||= $self->{'element_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($used) = $dbh->selectrow_array(
|
||||
"SELECT COUNT(*)
|
||||
FROM test_environment_property
|
||||
WHERE name like 'New property%'
|
||||
AND element_id = ?",
|
||||
undef, $element_id);
|
||||
|
||||
return $used + 1;
|
||||
}
|
||||
|
||||
=head2 get_validexp
|
||||
|
||||
Returns the validexp for the property
|
||||
|
||||
=cut
|
||||
|
||||
sub get_validexp{
|
||||
my $self = shift;
|
||||
my $name = (@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $validexp = $dbh->selectrow_arrayref(qq{
|
||||
SELECT validexp
|
||||
FROM test_environment_property
|
||||
WHERE property_id = ? },undef,$self->{'property_id'});
|
||||
|
||||
return $validexp;
|
||||
}
|
||||
|
||||
|
||||
=head2 store
|
||||
|
||||
Serializes the new property to the database
|
||||
|
||||
=cut
|
||||
|
||||
sub store {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
# Verify name is available
|
||||
return undef if $self->check_property($self->{'name'}, $self->{'element_id'});
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_environment_property ($columns)
|
||||
VALUES (?,?,?,?)",undef, (undef, $self->{'element_id'}, $self->{'name'}, $self->{'validexp'}));
|
||||
my $key = $dbh->bz_last_key( 'test_plans', 'plan_id' );
|
||||
return $key;
|
||||
}
|
||||
|
||||
=head2 set_name
|
||||
|
||||
Updates the property name in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub set_name {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
my ($name) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_property
|
||||
SET name = ? WHERE property_id = ?",undef, ($name,$self->{'property_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head2 set_element
|
||||
|
||||
Updates the elmnt_id in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub set_element {
|
||||
my $self = shift;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
|
||||
my ($id) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_property
|
||||
SET element_id = ? WHERE property_id = ?",undef, ($id,$self->{'property_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 update_property_validexp
|
||||
|
||||
Updates the property valid expression in the database
|
||||
|
||||
=cut
|
||||
|
||||
sub update_property_validexp {
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
my $self = shift;
|
||||
my ($validexp) = (@_);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("UPDATE test_environment_property
|
||||
SET validexp = ? WHERE property_id = ?",undef, ($validexp,$self->{'property_id'} ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub valid_exp_to_json {
|
||||
my $self = shift;
|
||||
my ($disable_move, $env_id) = @_;
|
||||
my $env = Bugzilla::Testopia::Environment->new($env_id) if $env_id;
|
||||
|
||||
$disable_move = ',"addChild","move","remove"' if $disable_move;
|
||||
my $validexp = $self->get_validexp;
|
||||
|
||||
my @validexpressions = split(/\|/, @$validexp[0]);
|
||||
|
||||
my $json = '[';
|
||||
|
||||
foreach (@validexpressions)
|
||||
{
|
||||
$json .= '{title: "' . $_ . '",';
|
||||
$json .= 'widgetId:"validexp' . $self->id . '~'. $_ .'",';
|
||||
$json .= 'actionsDisabled:["addCategory","addElement","addProperty","addValue"'. $disable_move .'],';
|
||||
$json .= 'objectId:"' . $self->id . '~' . $_ . '",';
|
||||
if ($env && $env->get_value_selected($env->id, $self->element_id, $self->id) eq $_){
|
||||
$json .= 'childIconSrc:"testopia/img/selected_value.png"},';
|
||||
}
|
||||
else{
|
||||
$json .= 'childIconSrc:""},';
|
||||
}
|
||||
}
|
||||
chop $json;
|
||||
$json .= ']';
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
||||
Completely removes the element property entry from the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub obliterate {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_environment_map READ', 'test_environment_property WRITE');
|
||||
if (!$self->candelete) {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 0;
|
||||
}
|
||||
$dbh->do("DELETE FROM test_environment_property
|
||||
WHERE property_id = ?", undef, $self->id);
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $used = $dbh->selectrow_array("SELECT 1 FROM test_environment_map
|
||||
WHERE property_id = ?",
|
||||
undef, $self->id);
|
||||
return !$used;
|
||||
|
||||
}
|
||||
|
||||
###############################
|
||||
#### Accessors ####
|
||||
###############################
|
||||
=head2 id
|
||||
|
||||
Returns the ID of this object
|
||||
|
||||
=head2 name
|
||||
|
||||
Returns the name of this object
|
||||
|
||||
=head2 validexp
|
||||
|
||||
Returns the valid expression associated with this property
|
||||
|
||||
=head2 element_id
|
||||
|
||||
Returns the element's id associated with this property
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'property_id'}; }
|
||||
sub name { return $_[0]->{'name'}; }
|
||||
sub validexp { return $_[0]->{'validexp'}; }
|
||||
sub element_id { return $_[0]->{'element_id'}; }
|
||||
|
||||
1;
|
||||
585
mozilla/webtools/testopia/Bugzilla/Testopia/Environment/Xml.pm
Normal file
585
mozilla/webtools/testopia/Bugzilla/Testopia/Environment/Xml.pm
Normal file
@@ -0,0 +1,585 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Garrett Braden <gbraden@novell.com>
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Testopia::Environment::Xml - An XML representation of the Environment Object.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module is used to import and export environments via XML. It can parse an XML representation
|
||||
of a Testopia Environment and persist it to the database. An Environment.pm XML object can be
|
||||
initialized using new and passing it an XML scalar. It can also take two other parameters:
|
||||
|
||||
$admin - a boolean that automatically will store the imported environment to the database.
|
||||
$max_depth - the max depth of child elements to import.
|
||||
|
||||
Example:
|
||||
my $env_xml = Bugzilla::Testopia::Environment::Xml->new($xml, 1, 5);
|
||||
|
||||
Other subroutines can be called on the object. For example:
|
||||
parse - takes the same three parameters as new
|
||||
store - stores the imported xml Environment object to the database
|
||||
|
||||
Misc. Other:
|
||||
the module also contains two other valueable fields on it's hash:
|
||||
$self->{'message'} - running list of valueable information upon parsing and storing
|
||||
$self->{'error'} - running list of error messages upon parsing and storing
|
||||
One other method exists(check_new_items) to check if there are new Elements, Properties, Categories,
|
||||
and Selected Values and returns a scalar value report of the new items not present in the database.
|
||||
|
||||
Import XML Environment Implementation Example: see tr_import_environment.cgi
|
||||
|
||||
To export an environment by env_id to XML use export
|
||||
|
||||
Example:
|
||||
my $xml = Bugzilla::Testopia::Environment::Xml->export($env_id);
|
||||
|
||||
Export Environment XML Implementation Example: see tr_export_environment.cgi
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Bugzilla::Testopia::Environment::Xml;
|
||||
|
||||
=cut
|
||||
|
||||
package Bugzilla::Testopia::Environment::Xml;
|
||||
|
||||
#************************************************** Uses ****************************************************#
|
||||
use strict;
|
||||
use warnings;
|
||||
use CGI;
|
||||
use lib ".";
|
||||
use XML::Twig;
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Product;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::Environment;
|
||||
use Bugzilla::Testopia::Product;
|
||||
use Bugzilla::Testopia::Environment::Category;
|
||||
use Bugzilla::Testopia::Environment::Element;
|
||||
use Bugzilla::Testopia::Environment::Property;
|
||||
|
||||
our constant $max_depth = 7;
|
||||
|
||||
|
||||
=head2 new
|
||||
|
||||
Instantiates a new Bugzilla::Testopia::Environment::Xml object
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {};
|
||||
bless($self, $class);
|
||||
return $self->_init(@_);
|
||||
}
|
||||
|
||||
|
||||
=head2 _init
|
||||
|
||||
Private constructor for the Bugzilla::Testopia::Environment::XML class
|
||||
|
||||
=cut
|
||||
|
||||
sub _init {
|
||||
my ($self, $xml, $admin, $depth) = @_;
|
||||
if (ref $xml eq 'HASH') {
|
||||
$self = $xml;
|
||||
}
|
||||
elsif($xml) {
|
||||
parse($self, $xml, $admin, $depth);
|
||||
}
|
||||
return undef unless (defined $xml);
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
=head2 Parse Environment
|
||||
|
||||
=head2 DESCRIPTION
|
||||
|
||||
Parses the Environment XML
|
||||
|
||||
=cut
|
||||
|
||||
sub parse() {
|
||||
my ($self, $xml, $admin, $depth) = @_;
|
||||
|
||||
if($depth eq undef) {
|
||||
$self->{'max_depth'} = $max_depth;
|
||||
}
|
||||
else {
|
||||
$self->{'max_depth'} = $depth
|
||||
}
|
||||
if ($admin) {
|
||||
$self->{'message'} = "Importing XML Environment...<BR />";
|
||||
}
|
||||
else {
|
||||
$self->{'message'} = "Parsing and Validating XML Environment...<BR />";
|
||||
}
|
||||
$self->{'error'} = undef;
|
||||
if ($xml) {
|
||||
trick_taint($xml);
|
||||
}
|
||||
my $twig = XML::Twig->new();
|
||||
$twig->parse($xml);
|
||||
my $root = $twig->root;
|
||||
# Checking if Product and Environment already exist.
|
||||
my $product_name = $root->{'att'}->{'product'};
|
||||
my $product_id;
|
||||
if (lc($product_name) eq "--all--") {
|
||||
$self->{'message'} .= "..Using the <U>--ALL--</U> <STRONG>PRODUCT</STRONG>.<BR />";
|
||||
$product_id = 0;
|
||||
}
|
||||
else {
|
||||
$self->{'message'} .= "..Checking if <U>$product_name</U> <STRONG>PRODUCT</STRONG> already exists...";
|
||||
($product_id) = Bugzilla::Testopia::Product->check_product_by_name($product_name);
|
||||
if ($product_id) {
|
||||
$self->{'message'} .= "EXISTS.<BR />";
|
||||
}
|
||||
else {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U>.<BR />Importing XML Environment Failed!<BR/>";
|
||||
$self->{'error'} .= "<U>$product_name</U> <STRONG>PRODUCT</STRONG> doesn't exist. Please be sure to use an existing product.<BR />";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
($self->{'product_id'}) = $product_id;
|
||||
$self->{'product_name'} = $product_name;
|
||||
my $environment_name = $root->{'att'}->{'name'};
|
||||
$self->{'name'} = $environment_name;
|
||||
$self->{'message'} .= "..Checking if <U>$environment_name</U> <STRONG>ENVIRONMENT NAME</STRONG> already exists for the <U>$product_name</U> <STRONG>PRODUCT</STRONG>...";
|
||||
my $environment = Bugzilla::Testopia::Environment->new({});
|
||||
my ($env_id) = $environment->check_environment($environment_name, $product_id);
|
||||
my $environment_id;
|
||||
if ($env_id < 1) {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U><BR />";
|
||||
# Storing New Environment if Admin
|
||||
if ($admin) {
|
||||
$self->{'message'} .= "....Storing new <U>$environment_name</U> <STRONG>ENVIRONMENT NAME</STRONG> in the <U>$self->{'product_name'}</U> <STRONG>PRODUCT</STRONG>...";
|
||||
$environment->{'name'} = $environment_name;
|
||||
($environment_id) = Bugzilla::Testopia::Environment->store_environment_name($self->{'name'}, $product_id);
|
||||
$self->{'message'} .= "DONE.<BR />";
|
||||
}
|
||||
}
|
||||
else {
|
||||
($environment_id) = $env_id;
|
||||
$self->{'message'} .= "EXISTS<BR />Importing XML Environment Failed!<BR/>";
|
||||
$self->{'error'} .= "<U>$environment_name</U> <STRONG>ENVIRONMENT NAME</STRONG> already exists for the <U>$product_name</U> <STRONG>PRODUCT</STRONG>. Please use another name.";
|
||||
return 0;
|
||||
}
|
||||
($self->{'environment_id'}) = $environment_id;
|
||||
($environment->{'product_id'}) = $self->{'product_id'};
|
||||
# Parse recursively through the nested child elements.
|
||||
foreach my $twig_category ($root->children("category")) {
|
||||
my $category_name = $twig_category->{'att'}->{'name'};
|
||||
# Makes sure to get the category_id by name and product_id
|
||||
my $category = Bugzilla::Testopia::Environment::Category->new({});
|
||||
my ($cat_id) = $category->check_category($category_name, $product_id);
|
||||
my $category_id;
|
||||
# Checking if Categories already exist.
|
||||
$self->{'message'} .= "..Checking if <U>$category_name</U> <STRONG>CATEGORY</STRONG> already exists...";
|
||||
if ($cat_id < 1) {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U>.<BR />";
|
||||
my $new_category_names = $self->{'new_category_names'};
|
||||
push (@$new_category_names, $category_name);
|
||||
$self->{'new_category_names'} = $new_category_names;
|
||||
# Storing New Categories if Admin
|
||||
if ($admin) {
|
||||
$self->{'message'} .= "....Storing new <U>$category_name</U> <STRONG>CATEGORY</STRONG> in the <U>$self->{'product_name'}</U> <STRONG>PRODUCT</STRONG>...";
|
||||
($category->{'product_id'}) = $product_id;
|
||||
$category->{'name'} = $category_name;
|
||||
($category_id) = $category->store();
|
||||
$self->{'message'} .= "DONE.<BR />";
|
||||
}
|
||||
}
|
||||
else {
|
||||
($category_id) = $cat_id;
|
||||
$self->{'message'} .= "EXISTS.<BR />";
|
||||
}
|
||||
foreach my $twig_element ($twig_category->children("element")) {
|
||||
my $element = $self->parse_child_elements(1, $category_id, $category_name, $twig_element, $admin);
|
||||
my $elements = $self->{'elements'};
|
||||
push (@$elements, $element);
|
||||
$self->{'elements'} = $elements;
|
||||
}
|
||||
}
|
||||
if ($admin) {
|
||||
$self->{'message'} .= "Finished Importing XML Environment!<BR/>";
|
||||
}
|
||||
else {
|
||||
$self->{'message'} .= "Finished Parsing and Validating XML Environment!<BR/>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=head2 Parse Children Elements
|
||||
|
||||
=head2 DESCRIPTION
|
||||
|
||||
Parses through elements and their children elements recursively
|
||||
|
||||
=cut
|
||||
|
||||
sub parse_child_elements() {
|
||||
my ($self, $depth, $env_category_id, $category_name, $twig_element, $admin, $parent_element) = @_;
|
||||
if ($depth > $self->{'max_depth'}) {
|
||||
return;
|
||||
}
|
||||
$depth++;
|
||||
my $element_name = $twig_element->{'att'}->{'name'};
|
||||
# Checking if Elements already exist.
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "Checking if <U>$element_name</U> <STRONG>ELEMENT</STRONG> already exists in the <U>$category_name</U> <STRONG>CATEGORY</STRONG>...";
|
||||
my ($product_id) = $self->{'product_id'};
|
||||
my $element = Bugzilla::Testopia::Environment::Element->new({});
|
||||
my ($elem_id) = $element->check_element($element_name, $env_category_id);
|
||||
my $element_id;
|
||||
if ($elem_id < 1) {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U>.<BR />";
|
||||
my $new_category_elements = $self->{'new_category_elements'};
|
||||
my $new_category_element = {'env_category_id' => $env_category_id, 'category_name' => $category_name, 'element_name' => $element_name};
|
||||
push (@$new_category_elements, $new_category_element);
|
||||
$self->{'new_category_elements'} = $new_category_elements;
|
||||
# Storing New Elements if Admin
|
||||
if ($admin) {
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "..Storing new <U>$element_name</U> <STRONG>ELEMENT</STRONG> in the <U>$category_name</U> <STRONG>CATEGORY</STRONG>...";
|
||||
($element->{'env_category_id'}) = $env_category_id;
|
||||
$element->{'name'} = $element_name;
|
||||
($element->{'product_id'}) = $self->{'product_id'};
|
||||
$element->{'isprivate'} = 0;
|
||||
if ($parent_element) {
|
||||
$element->{'parent_id'} = $parent_element->{'element_id'};
|
||||
}
|
||||
($element_id) = $element->store();
|
||||
$self->{'message'} .= "DONE.<BR />";
|
||||
}
|
||||
}
|
||||
else {
|
||||
($element_id) = $elem_id;
|
||||
$self->{'message'} .= "EXISTS.<BR />";
|
||||
}
|
||||
($element->{'element_id'}) = $element_id;
|
||||
($element->{'env_category_id'}) = $env_category_id;
|
||||
$element->{'name'} = $element_name;
|
||||
($element->{'parent_id'}) = $parent_element->{'parent_id'};
|
||||
my @properties;
|
||||
foreach my $twig_property ($twig_element->children("property")) {
|
||||
my $property_name = $twig_property->{'att'}->{'name'};
|
||||
# Checking if Properties already exist.
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "....Checking if <U>$property_name</U> <STRONG>PROPERTY</STRONG> already exists...";
|
||||
my $property = Bugzilla::Testopia::Environment::Property->new({});
|
||||
my ($prop_id) = $property->check_property($property_name, $element_id);
|
||||
my $property_id;
|
||||
if ($prop_id < 1) {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U>.<BR />";
|
||||
my $new_property_names = $self->{'new_property_names'};
|
||||
push (@$new_property_names, $property_name);
|
||||
$self->{'new_property_names'} = $new_property_names;
|
||||
# Storing New Property if Admin
|
||||
if ($admin) {
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "......Storing new <U>$property_name</U> <STRONG>PROPERTY</STRONG>...";
|
||||
$property->{'name'} = $property_name;
|
||||
($property->{'element_id'}) = $element_id;
|
||||
($property_id) = $property->store();
|
||||
$self->{'message'} .= "DONE.<BR />";
|
||||
}
|
||||
}
|
||||
else {
|
||||
($property_id) = $prop_id;
|
||||
$self->{'message'} .= "EXISTS.<BR />";
|
||||
}
|
||||
$property = Bugzilla::Testopia::Environment::Property->new($property_id);
|
||||
# Checking if new Selected Value and Valid Expression exist.
|
||||
my $validexp;
|
||||
if ($property) {
|
||||
$validexp = $property->validexp();
|
||||
}
|
||||
my $value = $twig_property->field('value');
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "........Checking if <U>$value</U> <STRONG>VALUE</STRONG> exists in the list of selectable values...";
|
||||
if ( $validexp !~ m/$value/) {
|
||||
$self->{'message'} .= "<U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U>.<BR/>";
|
||||
if ($admin) {
|
||||
if (!defined($validexp)) {
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "..........Setting <U>$value</U> <STRONG>VALID EXPRESSION</STRONG> equal to the <STRONG>VALUE</STRONG> for the first time...";
|
||||
$validexp = $value;
|
||||
}
|
||||
else {
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "..........Adding <U>$value</U> <STRONG>VALUE</STRONG> to the <STRONG>VALID EXPRESSION</STRONG>...";
|
||||
$validexp = "$validexp | $value";
|
||||
}
|
||||
$property->update_property_validexp($validexp);
|
||||
$self->{'message'} .= "DONE.<BR/>";
|
||||
}
|
||||
else {
|
||||
my $new_validexp_values = $self->{'new_validexp_values'};
|
||||
my $new_validexp_value = {'property_id' => $property_id, 'property_name' => $property_name, 'value' => $value};
|
||||
push (@$new_validexp_values, $new_validexp_value);
|
||||
$self->{'new_validexp_values'} = $new_validexp_values;
|
||||
}
|
||||
}
|
||||
elsif (!defined($validexp)) {
|
||||
$self->{'message'} .= "<STRONG>VALID EXPRESSION</STRONG> <U><FONT COLOR='RED'><STRONG>DOESN'T EXIST</STRONG></FONT></U> YET.<BR/>";
|
||||
}
|
||||
else {
|
||||
$self->{'message'} .= "EXISTS.<BR/>";
|
||||
}
|
||||
if ($property_id && $admin) {
|
||||
for (my $i = 1; $i < $depth; $i++) {
|
||||
$self->{'message'} .= "....";
|
||||
}
|
||||
$self->{'message'} .= "............Storing new <STRONG>VALUE SELECTED</STRONG> <U>$value</U>...";
|
||||
my $environment = Bugzilla::Testopia::Environment->new($self->{'environment_id'});
|
||||
$environment->store_property_value($property_id, $element_id, $value);
|
||||
$self->{'message'} .= "DONE.<BR/>";
|
||||
}
|
||||
$property->{'value_selected'} = $value;
|
||||
push (@properties, $property);
|
||||
}
|
||||
my $elm_properties = $element->{'properties'};
|
||||
push (@$elm_properties, @properties);
|
||||
if ($parent_element) {
|
||||
my $children = $parent_element->{'children'};
|
||||
push (@$children, $element);
|
||||
$parent_element->{'children'} = $children;
|
||||
}
|
||||
foreach my $twig_element_child ($twig_element->children("element")) {
|
||||
$self->parse_child_elements($depth, $env_category_id, $category_name, $twig_element_child, $admin, $element);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
|
||||
=head2 Checking Exists
|
||||
|
||||
=head2 DESCRIPTION
|
||||
|
||||
Checking if the Environment, Elements, Categories, and Properties already exist or not.
|
||||
|
||||
=cut
|
||||
|
||||
sub check_new_items() {
|
||||
my $self = shift;
|
||||
my $report;
|
||||
my $new_category_names = $self->{'new_category_names'};
|
||||
foreach my $new_category_name (@$new_category_names) {
|
||||
$report .= "New <U>$new_category_name</U> <STRONG>CATEGORY</STRONG>.<BR/>";
|
||||
}
|
||||
my $new_category_elements = $self->{'new_category_elements'};
|
||||
foreach my $new_category_element (@$new_category_elements) {
|
||||
$report .= "New <U>$new_category_element->{'element_name'}</U> <STRONG>ELEMENT</STRONG> in the ";
|
||||
if (!$new_category_element->{'env_category_id'}){
|
||||
$report .= "<STRONG>new</STRONG> ";
|
||||
}
|
||||
$report .= "<U>$new_category_element->{'category_name'}</U> <STRONG>CATEGORY</STRONG>.<BR/>";
|
||||
}
|
||||
my $new_property_names = $self->{'new_property_names'};
|
||||
foreach my $new_property_name (@$new_property_names) {
|
||||
$report .= "New <U>$new_property_name</U> <STRONG>PROPERTY</STRONG>.<BR/>";
|
||||
}
|
||||
my $new_validexp_values = $self->{'new_validexp_values'};
|
||||
foreach my $new_validexp_value (@$new_validexp_values) {
|
||||
$report .= "New <U>$new_validexp_value->{'value'}</U> <STRONG>VALUE</STRONG> for the ";
|
||||
if (!$new_validexp_value->{'property_id'}){
|
||||
$report .= "<STRONG>new</STRONG> ";
|
||||
}
|
||||
$report .= "<U>$new_validexp_value->{'property_name'}</U> <STRONG>PROPERTY</STRONG>'s selectable value list.<BR/>";
|
||||
}
|
||||
return $report;
|
||||
}
|
||||
|
||||
|
||||
=head2 Store the Environment
|
||||
|
||||
=head2 Description
|
||||
|
||||
Store the Environment Name, Element-Category relationship, Element-Property relationship,
|
||||
Element-ChildElement relationship, Environment-Element-Property-Value.
|
||||
|
||||
=cut
|
||||
|
||||
sub store() {
|
||||
my $self = shift;
|
||||
$self->{'message'} .= "Storing new XML Environment...";
|
||||
if (!$self->{'environment_id'}) {
|
||||
$self->{'environment_id'} = Bugzilla::Testopia::Environment->store_environment_name($self->{'name'}, $self->{'product_id'});
|
||||
}
|
||||
my $environment = Bugzilla::Testopia::Environment->new($self);
|
||||
my $success = $environment->update();
|
||||
if (!$success) {
|
||||
$self->{'message'} .= "ABORTED!<BR/>";
|
||||
$self->{'error'} .= "Failed to store the Environment!<BR/>";
|
||||
return 0;
|
||||
}
|
||||
$self->{'message'} .= "DONE!<BR/>";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head2 export
|
||||
|
||||
=head2 Description
|
||||
|
||||
Exports and Environment by env_id to a scalar XML value
|
||||
|
||||
=cut
|
||||
|
||||
sub export() {
|
||||
my $self = shift;
|
||||
my ($env_id) = @_;
|
||||
|
||||
my $xml;
|
||||
|
||||
my $environment = Bugzilla::Testopia::Environment->new($env_id);
|
||||
|
||||
$xml =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>" .
|
||||
"<!DOCTYPE environment SYSTEM 'environment.dtd' >" .
|
||||
"<environment name='$environment->{'name'}' product='";
|
||||
|
||||
my $product = Bugzilla::Product->new($environment->{'product_id'});
|
||||
|
||||
$xml .= "$product->{'name'}'>";
|
||||
|
||||
$environment->get_environment_elements();
|
||||
|
||||
my $categories = {};
|
||||
my $category_names = [];
|
||||
my $categorized_elements = [];
|
||||
my $elements = $environment->{'elements'};
|
||||
my $used_elements = {};
|
||||
foreach my $element (@$elements) {
|
||||
my $root_element = $self->get_root_parent($element);
|
||||
my $category_name = $root_element->cat_name();
|
||||
$categorized_elements = $categories->{ $category_name };
|
||||
for my $used_element (@$categorized_elements) {
|
||||
$used_elements->{ $used_element->{'element_id'} } = 1;
|
||||
}
|
||||
if (!$used_elements->{$root_element->{'element_id'}}) {
|
||||
push (@$categorized_elements, $root_element);
|
||||
$categories->{ $category_name } = $categorized_elements;
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $category_name (keys %$categories) {
|
||||
$xml .= "<category name='$category_name'>";
|
||||
|
||||
$elements = $categories->{$category_name};
|
||||
|
||||
|
||||
foreach my $element (@$elements) {
|
||||
$element->get_children();
|
||||
$xml .= $self->export_element_and_children(1, $element, $environment->{'environment_id'});
|
||||
}
|
||||
|
||||
$xml .= "</category>";
|
||||
}
|
||||
|
||||
return "$xml</environment>";
|
||||
}
|
||||
|
||||
|
||||
=head2 get_root_parent
|
||||
|
||||
=head2 Description
|
||||
|
||||
Helper sub that returns the root parent element in the environment of the passed in element
|
||||
|
||||
=cut
|
||||
|
||||
sub get_root_parent {
|
||||
my $self = shift;
|
||||
my ($element) = @_;
|
||||
my $parent = $element->get_parent();
|
||||
if (!$parent) {
|
||||
return $element;
|
||||
}
|
||||
else {
|
||||
$self->get_root_parent($parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=head2 export_element_and_children
|
||||
|
||||
=head2 Description
|
||||
|
||||
Exports Elements and their child elements to XML Recursively.
|
||||
|
||||
=cut
|
||||
|
||||
sub export_element_and_children() {
|
||||
my $self = shift;
|
||||
my ($depth, $element, $env_id) = @_;
|
||||
if ($depth > $max_depth) {
|
||||
return;
|
||||
}
|
||||
$depth++;
|
||||
|
||||
my $xml = "<element name='$element->{'name'}'>";
|
||||
|
||||
my $properties = $element->{'properties'};
|
||||
foreach my $property (@$properties) {
|
||||
my $value_selected = Bugzilla::Testopia::Environment->get_value_selected(
|
||||
$env_id, $element->{'element_id'}, $property->{'property_id'});
|
||||
if (defined($value_selected)) {
|
||||
$xml .=
|
||||
"<property name='$property->{'name'}'>" .
|
||||
"<value>$value_selected</value></property>";
|
||||
}
|
||||
}
|
||||
|
||||
my $children = $element->{'children'};
|
||||
foreach my $child_element (@$children) {
|
||||
$child_element->get_children();
|
||||
$xml .= $self->export_element_and_children($depth, $child_element, $env_id);
|
||||
}
|
||||
$xml .= "</element>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -50,16 +50,60 @@ sub builds {
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT build_id
|
||||
FROM test_builds tb
|
||||
JOIN test_plans tp ON tb.plan_id = tp.plan_id
|
||||
WHERE tp.product_id = ?",
|
||||
FROM test_builds
|
||||
WHERE product_id = ?",
|
||||
undef, $self->{'id'});
|
||||
my @objs;
|
||||
foreach my $id (@{$ref}){
|
||||
push @objs, Bugzilla::Testopia::Build->new($id);
|
||||
}
|
||||
$self->{'build'} = \@objs;
|
||||
return $self->{'build'};
|
||||
$self->{'builds'} = \@objs;
|
||||
return $self->{'builds'};
|
||||
}
|
||||
|
||||
sub categories {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT category_id
|
||||
FROM test_case_categories
|
||||
WHERE product_id = ?",
|
||||
undef, $self->{'id'});
|
||||
my @objs;
|
||||
foreach my $id (@{$ref}){
|
||||
push @objs, Bugzilla::Testopia::Category->new($id);
|
||||
}
|
||||
$self->{'categories'} = \@objs;
|
||||
return $self->{'categories'};
|
||||
}
|
||||
|
||||
sub environment_categories {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT env_category_id
|
||||
FROM test_environment_category
|
||||
WHERE product_id = ?",
|
||||
undef, $self->id);
|
||||
my @objs;
|
||||
foreach my $id (@{$ref}){
|
||||
push @objs, Bugzilla::Testopia::Environment::Category->new($id);
|
||||
}
|
||||
$self->{'environment_categories'} = \@objs;
|
||||
return $self->{'environment_categories'};
|
||||
}
|
||||
|
||||
sub check_product_by_name {
|
||||
my $self = shift;
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($used) = $dbh->selectrow_array(qq{
|
||||
SELECT id
|
||||
FROM products
|
||||
WHERE name = ?},undef,$name);
|
||||
return $used;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -1,489 +0,0 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Justin C. De Vries <judevries@novell.com>
|
||||
|
||||
package Bugzilla::Testopia::Schema;
|
||||
|
||||
use base qw(Bugzilla::DB::Schema);
|
||||
|
||||
use strict;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Util;
|
||||
use Carp;
|
||||
use Safe;
|
||||
|
||||
# Historical, needed for SCHEMA_VERSION = '1.00'
|
||||
use Storable qw(dclone freeze thaw);
|
||||
|
||||
#New SCHEMA_Version (2.00) use this
|
||||
use Data::Dumper;
|
||||
|
||||
use constant SCHEMA_VERSION => '2.00';
|
||||
use constant ABSTRACT_SCHEMA => {
|
||||
#Note: Most of types will need to be defined in a MySQL specific file some where.
|
||||
test_category_templates => {
|
||||
FIELDS => [
|
||||
# Note: UNSMALLSERIAL might need to be added to the MySQL.pm file. Its
|
||||
# definition is UNSIGNED SMALLINT AUTO_INCREMENT.
|
||||
category_template_id => {TYPE => 'UNSMALLSERIAL', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(255)', NOTNULL => 1},
|
||||
description => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
category_template_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_attachments => {
|
||||
FIELDS => [
|
||||
# Note: Serial is a MySQL specific type. This will need to
|
||||
# be written or modified to be database generic.
|
||||
attachment_id => {TYPE => 'SERIAL'},
|
||||
# Note: UNBIGINT need to be added to the MySQL.pm file. Its
|
||||
# definition is UNSIGNED BIGINT.
|
||||
plan_id => {TYPE => 'UNBIGINT'},
|
||||
case_id => {TYPE => 'UNBIGINT'},
|
||||
submitter_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
description => {TYPE => 'MEDIUMTEXT'},
|
||||
filename => {TYPE => 'MEDIUMTEXT'},
|
||||
creation_ts => {TYPE => 'DATETIME'},
|
||||
mime_type => {TYPE => 'varchar(100)', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
attachment_plan_idx => ['plan_id'],
|
||||
attachment_case_idx => ['case_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_categories => {
|
||||
FIELDS => [
|
||||
category_id => {TYPE => 'UNSMALLSERIAL', NOTNULL => 1},
|
||||
product_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(240)', NOTNULL => 1},
|
||||
description => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
category_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_cases => {
|
||||
FIELDS => [
|
||||
case_id => {TYPE => 'SERIAL'},
|
||||
case_status_id => {TYPE => 'INT1', NOTNULL => 1},
|
||||
# Note: UNINT2 need to be added to the MySQL.pm file. Its
|
||||
# definition is UNSIGNED SMALLINT.
|
||||
category_id => {TYPE => 'UNINT2', NOTNULL => 1},
|
||||
priority_id => {TYPE => 'INT2'},
|
||||
author_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
creation_date => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
isautomated => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => '0'},
|
||||
sortkey => {TYPE => 'INT4'},
|
||||
script => {TYPE => 'MEDIUMTEXT'},
|
||||
arguments => {TYPE => 'MEDIUMTEXT'},
|
||||
summary => {TYPE => 'varchar(255)'},
|
||||
requirement => {TYPE => 'varchar(255)'},
|
||||
alias => {TYPE => 'varchar(255)'},
|
||||
],
|
||||
INDEXES => [
|
||||
test_case_category_idx => ['category_id'],
|
||||
test_case_author_idx => ['author_id'],
|
||||
test_case_creation_date_idx => ['creation_date'],
|
||||
test_case_sortkey_idx => ['sortkey'],
|
||||
test_case_requirement_idx => ['requirement'],
|
||||
test_case_shortname_idx => ['alias'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_bugs => {
|
||||
FIELDS => [
|
||||
bug_id => {TYPE => 'INT3', NOTNUTLL => 1},
|
||||
case_run_id => {TYPE => 'UNBIGINT'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_run_id_idx => [qw(case_run_id bug_id)],
|
||||
case_run_bug_id_idx => ['bug_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_runs => {
|
||||
FIELDS => [
|
||||
case_run_id => {TYPE => 'SERIAL'},
|
||||
run_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
assignee => {TYPE => 'INT3'},
|
||||
testedby => {TYPE => 'INT3'},
|
||||
case_run_status_id => {TYPE => 'UNINT1', NOTNULL => 1},
|
||||
case_text_version => {TYPE => 'UNINT3', NOTNULL => 1},
|
||||
build_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
close_date => {TYPE => 'DATETIME'},
|
||||
notes => {TYPE => 'TEXT'},
|
||||
iscurrent => {TYPE => 'BOOLEAN', DEFAULT => '0'},
|
||||
sortkey => {TYPE => 'INT4'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_run_run_id_idx => ['run_id'],
|
||||
case_run_case_id_idx => ['case_id'],
|
||||
case_run_assignee_idx => ['assignee'],
|
||||
case_run_testedby_idx => ['testedby'],
|
||||
case_run_close_date_idx => ['close_date'],
|
||||
case_run_shortkey_idx => ['sortkey'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_texts => {
|
||||
FIELDS => [
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL =>1},
|
||||
case_text_version => {TYPE => 'INT3', NOTNULL =>1},
|
||||
who => {TYPE => 'INT3', NOTNULL =>1},
|
||||
creation_ts => {TYPE => 'DATETIME', NOTNULL =>1},
|
||||
action => {TYPE => 'MEDIUMTEXT'},
|
||||
effect => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_versions_idx => {FIELDS => [qw(case_id case_text_version)],
|
||||
TYPE => 'UNIQUE'},
|
||||
case_versions_who_idx => ['who'],
|
||||
case_versions_creation_ts_idx => ['creation_ts'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_tags => {
|
||||
FIELDS => [
|
||||
tag_id => {TYPE => 'UNINT4', NOTNULL => 1},
|
||||
case_id => {TYPE => 'UNBIGINT'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_tags_case_id_idx => [qw(case_id tag_id)],
|
||||
case_tags_tag_id_idx => [qw(tag_id case_id)],
|
||||
test_tag_name_indx => ['tag_name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_plan_testers => {
|
||||
FIELDS => [
|
||||
tester_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
product_id => {TYPE => 'INT2'},
|
||||
read_only => {TYPE => 'BOOLEAN', DEFAULT => '1'},
|
||||
],
|
||||
},
|
||||
|
||||
test_tags => {
|
||||
FIELDS => [
|
||||
# Note: UNINT4SERIAL need to be added to the MySQL.pm file. Its
|
||||
# definition is UNSIGNED INTEGER AUTO_INCREMENT.
|
||||
tag_id => {TYPE => 'UNINT4SERIAL', NOTNULL => 1},
|
||||
tag_name => {TYPE => 'varchar(255)', NOTNULL => 1},
|
||||
],
|
||||
},
|
||||
|
||||
test_plans => {
|
||||
FIELDS => [
|
||||
plan_id => {TYPE => 'SERIAL'},
|
||||
product_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
author_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
editor_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
type_id => {TYPE => 'UNINT1', NOTNULL => 1},
|
||||
default_product_version => {TYPE => 'MEDIUMTEXT', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(255)', NOTNULL => 1},
|
||||
creation_date => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL =>, DEFAULT => '1'},
|
||||
],
|
||||
INDEXES => [
|
||||
plan_product_plan_id_idx => [qw(product_id plan_id)],
|
||||
plan_author_idx => ['author_id'],
|
||||
plan_type_idx => ['type_id'],
|
||||
plan_editor_idx => ['editor_id'],
|
||||
plan_isactive_idx => ['isactive'],
|
||||
],
|
||||
},
|
||||
|
||||
text_plan_text => {
|
||||
FIELDS => [
|
||||
plan_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
plan_text_version => {TYPE => 'INT4', NOTNULL => 1},
|
||||
who => {TYPE => 'INT3', NOTNULL => 1},
|
||||
creation_ts => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
# Note: LONGTEXT needs to be added to the MySQL.pm file. Its
|
||||
# definition is LONGTEXT.
|
||||
plan_text => {TYPE => 'LONGTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
test_plan_text_version_idx => [qw(plan_id plan_text_version)],
|
||||
test_plan_text_who_idx => ['who'],
|
||||
],
|
||||
},
|
||||
|
||||
test_plan_types => {
|
||||
FIELDS => [
|
||||
# Note: UNTINYINTSERIAL needs to be added to the MySQL.pm file. Its
|
||||
# definition is UNSIGNED TINYINT AUTO_INCREMENT.
|
||||
type_id => {TYPE => 'UNTINYSERIAL', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
plan_type_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_runs => {
|
||||
FIELDS => [
|
||||
run_id => {TYPE => 'SERIAL'},
|
||||
plan_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
environment_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
product_version => {TYPE => 'MEDIUMTEXT'},
|
||||
build_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
plan_text_version => {TYPE => 'INT4', NOTNULL => 1},
|
||||
manager_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
default_tester_id => {TYPE => 'INT3'},
|
||||
start_date => {TYPE => 'DATETIME'},
|
||||
stop_date => {TYPE => 'DATETIME'},
|
||||
summary => {TYPE => 'TINYTEXT', NOTNULL => 1},
|
||||
notes => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
test_run_plan_id_run_id_idx => [qw(plan_id run_id)],
|
||||
test_run_manager_idx => ['manager_id'],
|
||||
test_run_start_date_idx => ['start_date'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_plans => {
|
||||
FIELDS => [
|
||||
plan_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
case_plans_plan_id_idx => ['plan_id'],
|
||||
case_plans_case_id_idx => ['plan_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_activity => {
|
||||
FIELDS => [
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
fieldid => {TYPE => 'UNINT2', NOTNULL => 1},
|
||||
who => {TYPE => 'INT3', NOTNULL => 1},
|
||||
changed => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
oldvalue => {TYPE => 'MEDUIMTEXT'},
|
||||
newvalue => {TYPE => 'MEDUIMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_activity_case_id_idx => ['case_id'],
|
||||
case_activity_who_idx => ['who'],
|
||||
case_activity_when_idx => ['changed'],
|
||||
case_activity_field_idx => ['fieldid'],
|
||||
],
|
||||
},
|
||||
|
||||
test_fielddefs => {
|
||||
FIELDS => [
|
||||
fieldid => {TYPE => 'UNSMALLSERIAL', NOTNULL => 1},
|
||||
name => {TPYE => 'varchar(100)', NOTNULL => 1},
|
||||
description => {TYPE => 'MEDIUMTEXT'},
|
||||
table_name => {TYPE => 'varchar(100)', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
fielddefs_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_plan_activity => {
|
||||
FIELDS => [
|
||||
plan_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
fieldid => {TYPE => 'UNINT2', NOTNULL => 1},
|
||||
who => {TYPE => 'INT3', NOTNULL => 1},
|
||||
changed => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
oldvalue => {TYPE => 'MEDIUMTEXT'},
|
||||
newvalue => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
plan_activity_who_idx => ['who'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_components => {
|
||||
FIELDS => [
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
component_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
case_components_case_id_idx => ['case_id'],
|
||||
case_commponents_component_id_idx => ['case_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_run_activity => {
|
||||
FIELDS => [
|
||||
run_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
fieldid => {TYPE => 'UNINT2', NOTNULL => 1},
|
||||
who => {TYPE => 'INT3', NOTNULL => 1},
|
||||
changed => {TYPE => 'DATETIME', NOTNULL => 1},
|
||||
oldvalue => {TYPE => 'MEDIUMTEXT'},
|
||||
newvalue => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
run_activity_run_id_idx => ['run_id'],
|
||||
run_activity_who_idx => ['who'],
|
||||
run_activity_when_idx => ['changed'],
|
||||
],
|
||||
},
|
||||
|
||||
test_run_cc => {
|
||||
FIELDS => [
|
||||
run_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
who => {TYPE => 'INT3', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
run_cc_run_id_who_idx => [qw(run_id who)],
|
||||
],
|
||||
},
|
||||
|
||||
test_email_settings => {
|
||||
FIELDS => [
|
||||
userid => {TYPE => 'INT3', NOTNULL => 1},
|
||||
eventid => {TYPE => 'UNINT1', NOTNULL => 1},
|
||||
relationship_id => {TYPE => 'UNINT1', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
test_event_user_event_idx => [qw(userid eventid)],
|
||||
test_event_user_relationship_idx => [qw(userid relationship_id)],
|
||||
],
|
||||
},
|
||||
|
||||
test_events => {
|
||||
FIELDS => [
|
||||
eventid => {TYPE => 'UNIN1', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(50)'},
|
||||
],
|
||||
INDEXES => [
|
||||
test_event_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_relationships => {
|
||||
FIELDS => [
|
||||
relationship_id => {TYPE => 'UNINT1', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(50)'},
|
||||
],
|
||||
},
|
||||
|
||||
test_case_run_status => {
|
||||
FIELDS => [
|
||||
case_run_status_id => {TYPE => 'UNTINYSERIAL', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(20)'},
|
||||
sortkey => {TYPE => 'INT4'},
|
||||
],
|
||||
INDEXES => [
|
||||
case_run_status_name_idx => ['name'],
|
||||
case_run_status_sortkey_idx => ['sortkey'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_status => {
|
||||
FIELDS => [
|
||||
case_status_id => {TYPE => 'UNTINYSERIAL', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(255)'},
|
||||
],
|
||||
INDEXES => [
|
||||
test_case_status_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_case_dependencies => {
|
||||
FIELDS => [
|
||||
dependson => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
blocks => {TYPE => 'UNBIGINT'},
|
||||
],
|
||||
},
|
||||
|
||||
test_case_group_map => {
|
||||
FIELDS => [
|
||||
case_id => {TYPE => 'UNBIGINT', NOTNULL =>1},
|
||||
group_id => {TYPE => 'INT3'},
|
||||
],
|
||||
},
|
||||
|
||||
test_environments => {
|
||||
FIELDS => [
|
||||
environment_id => {TYPE => 'SERIAL', NOTNULL => 1},
|
||||
op_sys_id => {TYPE => 'INT4'},
|
||||
rep_platform_id => {TYPE => 'INT4'},
|
||||
name => {TYPE => 'varchar(255)'},
|
||||
xml => {TYPE => 'MEDIUMTEXT'},
|
||||
],
|
||||
INDEXES => [
|
||||
environment_op_sys_idx => ['op_sys_id'],
|
||||
environment_platform_idx => ['rep_platform_id'],
|
||||
environment_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
test_run_tags => {
|
||||
FIELDS => [
|
||||
tag_id => {TYPE => 'UNINT4', NOTNULL => 1},
|
||||
run_id => {TYPE => 'UNBIGINT'},
|
||||
],
|
||||
INDEXES => [
|
||||
run_tags_idx => ['qw(tag_id, run_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_plan_tags => {
|
||||
FIELDS => [
|
||||
tag_id => {TYPE => 'UNINT4', NOTNULL => 1},
|
||||
plan_id => {TYPE => 'UNBIGINT'},
|
||||
],
|
||||
INDEXES => [
|
||||
plan_tags_idx => ['qw(tag_id, plan_id'],
|
||||
],
|
||||
},
|
||||
|
||||
test_build => {
|
||||
FIELDS => [
|
||||
build_id => {TYPE => 'SERIAL', NOTNULL => 1},
|
||||
product_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(255)'},
|
||||
description => {TYPE => 'TEXT'},
|
||||
],
|
||||
},
|
||||
|
||||
test_attachment_data => {
|
||||
FIELDS => [
|
||||
attachment_id => {TYPE => 'UNBIGINT', NOTNULL => 1},
|
||||
contents => {TYPE => 'LONGBLOB'},
|
||||
],
|
||||
},
|
||||
|
||||
test_named_queries => {
|
||||
FIELDS => [
|
||||
userid => {TYPE => 'INT3', NOTNULL => 1},
|
||||
name => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
isvisible => {TYEP => 'BOOLEAN', NOTNULL => 1, DEFAULT => 1},
|
||||
query => {TYPE => 'MEDIUMTEXT', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
test_namedquery_name_idx => ['name'],
|
||||
],
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
1;
|
||||
@@ -133,9 +133,10 @@ sub init {
|
||||
my $type;
|
||||
|
||||
my $obj = trim($cgi->param('current_tab')) || ThrowUserError('testopia-missing-parameter', {'param' => 'current_tab'});
|
||||
ThrowUserError('unknown-tab') if $obj !~ '^(case|plan|run|case_run)$';
|
||||
ThrowUserError('unknown-tab') if $obj !~ '^(case|plan|run|case_run|environment)$';
|
||||
trick_taint($obj);
|
||||
|
||||
# Set up tables for field sort order
|
||||
my $order = $cgi->param('order') || '';
|
||||
if ($order eq 'author') {
|
||||
push @supptables, "INNER JOIN profiles as map_author ON map_author.userid = test_". $obj ."s.author_id";
|
||||
@@ -158,7 +159,7 @@ sub init {
|
||||
push @orderby, 'map_tester.login_name';
|
||||
}
|
||||
elsif ($order eq 'product') {
|
||||
push @supptables, "INNER JOIN products ON products.id = test_". $obj ."s.product_id";
|
||||
push @supptables, "LEFT JOIN products ON products.id = test_". $obj ."s.product_id";
|
||||
push @orderby, 'products.name';
|
||||
}
|
||||
elsif ($order eq 'build') {
|
||||
@@ -178,6 +179,9 @@ sub init {
|
||||
push @orderby, 'versions.value';
|
||||
}
|
||||
elsif ($order eq 'priority') {
|
||||
if ($obj eq 'case_run'){
|
||||
push @supptables, "INNER JOIN test_cases ON test_cases.case_id = test_case_runs.case_id";
|
||||
}
|
||||
push @supptables, "INNER JOIN priority ON priority.id = test_cases.priority_id";
|
||||
push @orderby, 'test_cases.priority_id';
|
||||
}
|
||||
@@ -201,7 +205,13 @@ sub init {
|
||||
push @orderby, 'case_status.name';
|
||||
}
|
||||
elsif ($order eq 'summary') {
|
||||
push @orderby, 'test_'. $obj .'s.summary';
|
||||
if ($obj eq 'case_run'){
|
||||
push @supptables, "INNER JOIN test_cases AS cases ON cases.case_id = test_case_runs.case_id";
|
||||
push @orderby, 'cases.summary';
|
||||
}
|
||||
else{
|
||||
push @orderby, 'test_'. $obj .'s.summary';
|
||||
}
|
||||
}
|
||||
elsif ($order eq 'created') {
|
||||
push @orderby, 'test_'. $obj .'s.creation_date';
|
||||
@@ -215,6 +225,7 @@ sub init {
|
||||
push @orderby, 'test_'. $obj .'s.' . $order;
|
||||
}
|
||||
}
|
||||
|
||||
my @funcdefs =
|
||||
(
|
||||
"^category," => sub {
|
||||
@@ -250,12 +261,71 @@ sub init {
|
||||
$f = "plan_texts.plan_text";
|
||||
},
|
||||
"^environment," => sub {
|
||||
if ($obj eq 'case_run'){
|
||||
$f = "environment_id";
|
||||
}
|
||||
else{
|
||||
push(@supptables,
|
||||
"LEFT JOIN test_environments AS env " .
|
||||
"ON test_runs.environment_id = env.environment_id");
|
||||
$f = "env.xml";
|
||||
}
|
||||
},
|
||||
"^env_products," => sub {
|
||||
print STDERR "THIS IS HERE";
|
||||
push(@supptables,
|
||||
"LEFT JOIN test_environments AS env " .
|
||||
"ON test_runs.environment_id = env.environment_id");
|
||||
$f = "env.xml";
|
||||
"INNER JOIN products as env_products
|
||||
ON test_environments.product_id = env_products.id");
|
||||
$f = 'env_products.id'
|
||||
},
|
||||
"^env_categories," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_map as env_map_categories
|
||||
ON test_environments.environment_id = env_map_categories.environment_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_element as env_element
|
||||
ON env_map_categories.element_id = env_element.element_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_category as env_categories
|
||||
ON env_element.env_category_id = env_categories.env_category_id");
|
||||
$f = 'env_categories.env_category_id'
|
||||
},
|
||||
"^env_elements," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_map as env_map_elements
|
||||
ON test_environments.environment_id = env_map_elements.environment_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_element as env_element
|
||||
ON env_map_elements.element_id = env_element.element_id");
|
||||
$f = 'env_element.element_id'
|
||||
},
|
||||
"^env_properties," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_map as env_map_properties
|
||||
ON test_environments.environment_id = env_map_properties.environment_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_property as env_property
|
||||
ON env_map_properties.property_id = env_property.property_id");
|
||||
$f = 'env_property.property_id'
|
||||
},
|
||||
"^env_expressions," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_map as env_map_value
|
||||
ON test_environments.environment_id = env_map_value.environment_id");
|
||||
$f = 'env_map_value.value_selected'
|
||||
},
|
||||
"^env_value_selected," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_environment_map as env_map_value_selected
|
||||
ON test_environments.environment_id = env_map_value_selected.environment_id");
|
||||
$f = 'env_map_value_selected.value_selected'
|
||||
},
|
||||
"^component," => sub {
|
||||
if ($obj eq 'case_run'){
|
||||
push(@supptables,
|
||||
"INNER JOIN test_cases
|
||||
ON test_cases.case_id = test_case_runs.case_id");
|
||||
}
|
||||
push(@supptables,
|
||||
"INNER JOIN test_case_components AS tc_components " .
|
||||
"ON test_cases.case_id = tc_components.case_id");
|
||||
@@ -264,6 +334,22 @@ sub init {
|
||||
"ON components.id = tc_components.component_id");
|
||||
$f = "components.name";
|
||||
},
|
||||
"^priority_id," => sub {
|
||||
if ($obj eq 'case_run'){
|
||||
push(@supptables,
|
||||
"INNER JOIN test_cases
|
||||
ON test_cases.case_id = test_case_runs.case_id");
|
||||
}
|
||||
$f = "test_cases.priority_id";
|
||||
},
|
||||
"^isautomated," => sub {
|
||||
if ($obj eq 'case_run'){
|
||||
push(@supptables,
|
||||
"INNER JOIN test_cases
|
||||
ON test_cases.case_id = test_case_runs.case_id");
|
||||
}
|
||||
$f = "test_cases.isautomated";
|
||||
},
|
||||
"^milestone," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_builds AS builds " .
|
||||
@@ -282,13 +368,33 @@ sub init {
|
||||
"ON case_bugs.bug_id = bugs.bug_id");
|
||||
$f = "bugs.bug_id";
|
||||
},
|
||||
"^case_summary," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_cases AS cases " .
|
||||
"ON cases.case_id = test_case_runs.case_id");
|
||||
$f = "cases.summary";
|
||||
},
|
||||
|
||||
"^tags," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN test_". $obj ."_tags AS ". $obj ."_tags " .
|
||||
"ON test_". $obj ."s.". $obj ."_id = ". $obj ."_tags.". $obj ."_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_tags " .
|
||||
"ON ". $obj ."_tags.tag_id = test_tags.tag_id");
|
||||
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_tags AS case_tags " .
|
||||
"ON test_cases.case_id = case_tags.case_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_tags " .
|
||||
"ON case_tags.tag_id = test_tags.tag_id");
|
||||
}
|
||||
else{
|
||||
push(@supptables,
|
||||
"INNER JOIN test_". $obj ."_tags AS ". $obj ."_tags " .
|
||||
"ON test_". $obj ."s.". $obj ."_id = ". $obj ."_tags.". $obj ."_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN test_tags " .
|
||||
"ON ". $obj ."_tags.tag_id = test_tags.tag_id");
|
||||
}
|
||||
$f = "test_tags.tag_name";
|
||||
},
|
||||
"^case_plan_id," => sub {
|
||||
@@ -324,17 +430,28 @@ sub init {
|
||||
"ON test_plans.product_id = products.id");
|
||||
$f = "test_plans.product_id";
|
||||
},
|
||||
"^(author|editor|manager|default_tester)," => sub {
|
||||
"^(author|manager|default_tester)," => sub {
|
||||
push(@supptables,
|
||||
"INNER JOIN profiles AS map_$1 " .
|
||||
"ON test_". $obj ."s.". $1 ."_id = map_$1.userid");
|
||||
$f = "map_$1.login_name";
|
||||
$f = "map_$1.login_name";
|
||||
},
|
||||
"^(assignee|testedby)," => sub {
|
||||
push(@supptables,
|
||||
if ($obj eq 'run'){
|
||||
push(@supptables,
|
||||
"LEFT JOIN test_case_runs AS case_run " .
|
||||
"ON case_run.run_id = test_runs.run_id");
|
||||
push(@supptables,
|
||||
"INNER JOIN profiles AS map_$1 " .
|
||||
"ON case_run.". $1 ." = map_$1.userid");
|
||||
}
|
||||
else {
|
||||
push(@supptables,
|
||||
"INNER JOIN profiles AS map_$1 " .
|
||||
"ON test_". $obj ."s.". $1 ." = map_$1.userid");
|
||||
}
|
||||
$f = "map_$1.login_name";
|
||||
|
||||
},
|
||||
",isnotnull" => sub {
|
||||
$term = "$ff is not null";
|
||||
@@ -409,22 +526,46 @@ sub init {
|
||||
|
||||
if ($cgi->param('case_id')) {
|
||||
my $type = "anyexact";
|
||||
if ($cgi->param('caseidtype') && $cgi->param('caseidtype') eq 'exclude') {
|
||||
$type = "nowords";
|
||||
if ($cgi->param('caseidtype'))
|
||||
{
|
||||
if ($cgi->param('caseidtype') eq 'exclude')
|
||||
{
|
||||
$type = "nowords";
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = $cgi->param('caseidtype')
|
||||
}
|
||||
}
|
||||
push(@specialchart, ["case_id", $type, join(',', $cgi->param('case_id'))]);
|
||||
}
|
||||
if ($cgi->param('run_id')) {
|
||||
my $type = "anyexact";
|
||||
if ($cgi->param('runidtype') && $cgi->param('runidtype') eq 'exclude') {
|
||||
$type = "nowords";
|
||||
if ($cgi->param('runidtype'))
|
||||
{
|
||||
if ($cgi->param('runidtype') eq 'exclude')
|
||||
{
|
||||
$type = "nowords";
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = $cgi->param('runidtype')
|
||||
}
|
||||
}
|
||||
push(@specialchart, ["run_id", $type, join(',', $cgi->param('run_id'))]);
|
||||
}
|
||||
if ($cgi->param('plan_id')) {
|
||||
my $type = "anyexact";
|
||||
if ($cgi->param('planidtype') && $cgi->param('planidtype') eq 'exclude') {
|
||||
$type = "nowords";
|
||||
if ($cgi->param('planidtype'))
|
||||
{
|
||||
if ($cgi->param('planidtype') eq 'exclude')
|
||||
{
|
||||
$type = "nowords";
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = $cgi->param('planidtype')
|
||||
}
|
||||
}
|
||||
if ($obj eq 'case'){
|
||||
push(@specialchart, ["case_plan_id", $type, join(',', $cgi->param('plan_id'))]);
|
||||
@@ -469,7 +610,8 @@ sub init {
|
||||
my @legal_fields = ("case_status_id", "category", "priority_id",
|
||||
"component", "isautomated", "case_run_status_id",
|
||||
"default_product_version", "type_id",
|
||||
"build", "environment_id", "milestone");
|
||||
"build", "environment_id", "milestone", "env_products",
|
||||
"env_categories", "env_elements", "env_properties", "env_expressions");
|
||||
|
||||
foreach my $field ($cgi->param()) {
|
||||
if (lsearch(\@legal_fields, $field) != -1) {
|
||||
@@ -509,7 +651,7 @@ sub init {
|
||||
}
|
||||
# Check for author
|
||||
my @clist;
|
||||
foreach my $profile ("author", "editor", "manager", "default_tester",
|
||||
foreach my $profile ("author", "manager", "default_tester",
|
||||
"assignee", "testedby"){
|
||||
$t = $cgi->param($profile . "_type") || '';
|
||||
if ($t eq "exact") {
|
||||
@@ -535,9 +677,9 @@ sub init {
|
||||
}
|
||||
|
||||
# check static text fields
|
||||
foreach my $f ("summary", "tcaction", "tceffect", "script",
|
||||
foreach my $f ("case_summary", "summary", "tcaction", "tceffect", "script",
|
||||
"requirement", "name", "plan_text", "environment",
|
||||
"notes") {
|
||||
"notes", "env_value_selected") {
|
||||
if (defined $cgi->param($f)) {
|
||||
my $s = trim($cgi->param($f));
|
||||
if ($s ne "") {
|
||||
@@ -557,6 +699,7 @@ sub init {
|
||||
push @wherepart, 'test_case_runs.iscurrent = 1';
|
||||
}
|
||||
}
|
||||
|
||||
my @funcnames;
|
||||
while (@funcdefs) {
|
||||
my $key = shift(@funcdefs);
|
||||
|
||||
@@ -31,7 +31,7 @@ arguments:
|
||||
|
||||
=over
|
||||
|
||||
=item type - one of 'case', 'plan', 'run', or 'caserun'
|
||||
=item type - one of 'case', 'plan', 'run', 'caserun', or 'environment'
|
||||
|
||||
=item url - the cgi file that is calling this
|
||||
|
||||
@@ -135,6 +135,9 @@ sub init {
|
||||
elsif ($type eq 'case_run'){
|
||||
$o = Bugzilla::Testopia::TestCaseRun->new($id);
|
||||
}
|
||||
elsif ($type eq 'environment'){
|
||||
$o = Bugzilla::Testopia::Environment->new($id);
|
||||
}
|
||||
push (@ids, $id);
|
||||
push (@list, $o);
|
||||
}
|
||||
@@ -248,7 +251,7 @@ sub save_list {
|
||||
(join(",", $self->{'id_list'}), $self->{'user'}->id, "__". $self->{'type'} ."__"));
|
||||
}
|
||||
else {
|
||||
$dbh->do("INSERT INTO test_named_queries VALUES(?,?,?,?)", undef,
|
||||
$dbh->do("INSERT INTO test_named_queries (userid, name, isvisible, query) VALUES(?,?,?,?)", undef,
|
||||
($self->{'user'}->id, "__". $self->{'type'} ."__", 0, join(",", $self->{'id_list'})));
|
||||
}
|
||||
$dbh->bz_unlock_tables();
|
||||
@@ -344,8 +347,10 @@ sub get_next{
|
||||
###############################
|
||||
|
||||
sub list { return $_[0]->{'list'}; }
|
||||
sub id_list { return $_[0]->{'id_list'}; }
|
||||
sub list_count { return $_[0]->{'list_count'}; }
|
||||
sub page { return $_[0]->{'page'}; }
|
||||
sub url_loc { return $_[0]->{'url_loc'}; }
|
||||
|
||||
=head2 page_size
|
||||
|
||||
@@ -405,6 +410,21 @@ sub get_url {
|
||||
return $self->{'url'};
|
||||
}
|
||||
|
||||
sub get_query_part {
|
||||
my $self = shift;
|
||||
my $cgi = $self->{'cgi'};
|
||||
my @keys = $cgi->param;
|
||||
my $qstring;
|
||||
foreach my $key (@keys){
|
||||
my @vals = $cgi->param($key);
|
||||
foreach my $val (@vals){
|
||||
$qstring .= $key ."=". $val ."&";
|
||||
}
|
||||
}
|
||||
chop $qstring;
|
||||
return $qstring
|
||||
}
|
||||
|
||||
=head2 page_count
|
||||
|
||||
Returns a total count of the number of pages returned by a query.
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
# Christopher Aillon <christopher@aillon.com>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
# Jeff Hedlund <jeff.hedlund@matrixsi.com>
|
||||
# Fr<EFBFBD><EFBFBD>ic Buclin <LpSolit@gmail.com>
|
||||
# Frederic Buclin <LpSolit@gmail.com>
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
|
||||
@@ -193,41 +193,26 @@ sub get_selectable_components {
|
||||
my $self = shift;
|
||||
my ($byid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my @compids;
|
||||
my @exclusions;
|
||||
unless ($byid) {
|
||||
foreach my $e (@{$self->components}){
|
||||
push @exclusions, $e->{'id'};
|
||||
}
|
||||
}
|
||||
my $query = "SELECT id FROM components
|
||||
WHERE product_id = ?";
|
||||
my $query = "SELECT DISTINCT id FROM components
|
||||
WHERE product_id IN (" . join(",", @{$self->get_product_ids}) . ") ";
|
||||
if (@exclusions){
|
||||
$query .= " AND id NOT IN(". join(",", @exclusions) .")";
|
||||
$query .= "AND id NOT IN(". join(",", @exclusions) .") ";
|
||||
}
|
||||
foreach my $p (@{$self->plans}){
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
$query, undef, $p->{'product_id'});
|
||||
push @compids, @{$ref};
|
||||
}
|
||||
my %compseen;
|
||||
foreach (@compids){
|
||||
$compseen{$_} = 1;
|
||||
}
|
||||
@compids = keys %compseen;
|
||||
#TODO: 2.22 use Bugzilla::Component
|
||||
$query .= "ORDER BY name";
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref($query);
|
||||
my @comps;
|
||||
push @comps, {'id' => '0', 'name' => '--Please Select--'} unless $byid;
|
||||
foreach my $id (@compids){
|
||||
my $ref = $dbh->selectrow_hashref(
|
||||
"SELECT id, name FROM components
|
||||
WHERE id = ?", undef, $id);
|
||||
|
||||
push @comps, $ref;
|
||||
#push @comps, Bugzilla::Component->new($id);
|
||||
foreach my $id (@$ref){
|
||||
push @comps, Bugzilla::Component->new($id);
|
||||
}
|
||||
return \@comps;
|
||||
|
||||
}
|
||||
|
||||
=head2 get_available_components
|
||||
@@ -275,35 +260,25 @@ plans referenced by this case.
|
||||
#TODO: Move to Testopia::Product.pm in 2.22
|
||||
sub get_category_list{
|
||||
my $self = shift;
|
||||
my ($by_name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my @categories;
|
||||
|
||||
my @product_ids;
|
||||
foreach my $p (@{$self->plans}){
|
||||
if (Bugzilla::Testopia::Util::can_view_product($p->product_id)){
|
||||
push @categories, @{$p->categories};
|
||||
}
|
||||
push @product_ids, $p->product_id;
|
||||
}
|
||||
my %seen;
|
||||
foreach my $c (@categories){
|
||||
$seen{$c->id} = $c;
|
||||
my $id_part;
|
||||
my $name_part;
|
||||
if ($by_name){
|
||||
$id_part = "cat.name AS id";
|
||||
$name_part = ", cat.name as name";
|
||||
}
|
||||
@categories = values %seen;
|
||||
@categories = sort @categories;
|
||||
return \@categories;
|
||||
}
|
||||
|
||||
=head2 get_distinct_categories
|
||||
|
||||
Returns a list of all user viewable categories for use in searches
|
||||
|
||||
=cut
|
||||
|
||||
#TODO: Move to Testopia::Product.pm in 2.22
|
||||
sub get_distinct_categories{
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $query = "SELECT DISTINCT cat.name AS id, cat.name " .
|
||||
"FROM test_case_categories AS cat " .
|
||||
"JOIN products ON cat.product_id = products.id " .
|
||||
else {
|
||||
$id_part = "category_id";
|
||||
}
|
||||
my $query = "SELECT DISTINCT $id_part $name_part ";
|
||||
$query .= "FROM test_case_categories AS cat " .
|
||||
"JOIN products ON cat.product_id = products.id " .
|
||||
"LEFT JOIN group_control_map " .
|
||||
"ON group_control_map.product_id = products.id ";
|
||||
if (Param('useentrygroupdefault')) {
|
||||
@@ -316,11 +291,50 @@ sub get_distinct_categories{
|
||||
$query .= "AND group_id NOT IN(" .
|
||||
join(',', values(%{Bugzilla->user->groups})) . ") ";
|
||||
}
|
||||
$query .= "WHERE group_id IS NULL ORDER BY cat.name";
|
||||
|
||||
my $ref = $dbh->selectall_arrayref($query, {'Slice'=>{}});
|
||||
$query .= "WHERE group_id IS NULL ";
|
||||
$query .= "AND cat.product_id IN (". join(",", @product_ids) . ") " unless ($by_name || !@product_ids);
|
||||
$query .= "ORDER BY cat.name";
|
||||
|
||||
return $ref;
|
||||
if ($by_name){
|
||||
my $ref = $dbh->selectall_arrayref($query, {'Slice'=>{}});
|
||||
return $ref;
|
||||
}
|
||||
my $ids = $dbh->selectcol_arrayref($query);
|
||||
|
||||
my @categories;
|
||||
foreach my $c (@$ids){
|
||||
push @categories, Bugzilla::Testopia::Category->new($c);
|
||||
}
|
||||
return \@categories;
|
||||
}
|
||||
|
||||
=head2 get_product_ids
|
||||
|
||||
Returns the list of product ids that this case is associated with
|
||||
|
||||
=cut
|
||||
|
||||
sub get_product_ids {
|
||||
my $self = shift;
|
||||
|
||||
if ($self->id == 0){
|
||||
my @ids;
|
||||
foreach my $plan (@{$self->plans}){
|
||||
push @ids, $plan->product_id if Bugzilla->user->can_see_product($plan->product_name);
|
||||
}
|
||||
return \@ids;
|
||||
}
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectcol_arrayref(
|
||||
"SELECT DISTINCT products.id FROM products
|
||||
JOIN test_plans AS plans ON plans.product_id = products.id
|
||||
JOIN test_case_plans ON plans.plan_id = test_case_plans.plan_id
|
||||
JOIN test_cases AS cases ON cases.case_id = test_case_plans.case_id
|
||||
WHERE cases.case_id = ?
|
||||
ORDER BY products.id", undef, $self->{'case_id'});
|
||||
return $ref;
|
||||
}
|
||||
|
||||
=head2 get_status_list
|
||||
@@ -373,8 +387,8 @@ sub add_tag {
|
||||
$dbh->bz_unlock_tables();
|
||||
return 1;
|
||||
}
|
||||
$dbh->do("INSERT INTO test_case_tags(tag_id, case_id) VALUES(?,?)",
|
||||
undef, $tag_id, $self->{'case_id'});
|
||||
$dbh->do("INSERT INTO test_case_tags(tag_id, case_id, userid) VALUES(?,?,?)",
|
||||
undef, $tag_id, $self->{'case_id'}, Bugzilla->user->id);
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
return 0;
|
||||
@@ -396,6 +410,51 @@ sub remove_tag {
|
||||
return;
|
||||
}
|
||||
|
||||
=head2 attach_bug
|
||||
|
||||
Attaches the specified bug to this test case
|
||||
|
||||
=cut
|
||||
|
||||
sub attach_bug {
|
||||
my $self = shift;
|
||||
my ($bug, $case_id) = @_;
|
||||
$case_id ||= $self->{'case_id'};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_case_bugs WRITE');
|
||||
my ($exists) = $dbh->selectrow_array(
|
||||
"SELECT bug_id
|
||||
FROM test_case_bugs
|
||||
WHERE case_id=?
|
||||
AND bug_id=?",
|
||||
undef, ($case_id, $bug));
|
||||
if ($exists) {
|
||||
$dbh->bz_unlock_tables();
|
||||
return;
|
||||
}
|
||||
$dbh->do("INSERT INTO test_case_bugs (bug_id, case_run_id, case_id)
|
||||
VALUES(?,?,?)", undef, ($bug, undef, $self->{'case_id'}));
|
||||
$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_id = ?",
|
||||
undef, ($bug, $self->{'case_id'}));
|
||||
}
|
||||
|
||||
=head2 add_component
|
||||
|
||||
Associates a component with this test case
|
||||
@@ -465,14 +524,17 @@ text has changed and thus requiring a new version be created.
|
||||
|
||||
sub diff_case_doc {
|
||||
my $self = shift;
|
||||
my ($newaction, $neweffect) = @_;
|
||||
my ($newaction, $neweffect, $newsetup, $newbreakdown) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($oldaction, $oldeffect) = $dbh->selectrow_array(
|
||||
"SELECT action, effect FROM test_case_texts
|
||||
WHERE case_id = ? AND case_text_version = ?",
|
||||
undef, $self->{'case_id'}, $self->version);
|
||||
my ($oldaction, $oldeffect, $oldsetup, $oldbreakdown) = $dbh->selectrow_array(
|
||||
"SELECT action, effect, setup, breakdown
|
||||
FROM test_case_texts
|
||||
WHERE case_id = ? AND case_text_version = ?",
|
||||
undef, ($self->{'case_id'}, $self->version));
|
||||
my $diff = diff(\$newaction, \$oldaction);
|
||||
$diff .= diff(\$neweffect, \$oldeffect);
|
||||
$diff .= diff(\$newsetup, \$oldsetup);
|
||||
$diff .= diff(\$newbreakdown, \$oldbreakdown);
|
||||
return $diff
|
||||
}
|
||||
|
||||
@@ -516,7 +578,8 @@ sub store {
|
||||
|
||||
my $key = $dbh->bz_last_key( 'test_cases', 'case_id' );
|
||||
|
||||
$self->store_text($key, $self->{'author_id'}, $self->{'action'}, $self->{'effect'}, $timestamp);
|
||||
$self->store_text($key, $self->{'author_id'}, $self->{'action'}, $self->{'effect'},
|
||||
$self->{'setup'}, $self->{'breakdown'}, $timestamp);
|
||||
$self->update_deps($self->{'dependson'}, $self->{'blocks'}, $key);
|
||||
foreach my $p (@{$self->{'plans'}}){
|
||||
$self->link_plan($p->id, $key);
|
||||
@@ -535,16 +598,16 @@ author id, action text, effect text, and an optional timestamp.
|
||||
sub store_text {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($key, $author, $action, $effect, $timestamp) = @_;
|
||||
my ($key, $author, $action, $effect, $setup, $breakdown, $timestamp) = @_;
|
||||
if (!defined $timestamp){
|
||||
($timestamp) = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
}
|
||||
trick_taint($action);
|
||||
trick_taint($effect);
|
||||
my $version = $self->version || 0;
|
||||
$dbh->do("INSERT INTO test_case_texts VALUES(?,?,?,?,?,?)",
|
||||
$dbh->do("INSERT INTO test_case_texts
|
||||
(case_id, case_text_version, who, creation_ts, action, effect, setup, breakdown)
|
||||
VALUES(?,?,?,?,?,?,?,?)",
|
||||
undef, $key, ++$version, $author,
|
||||
$timestamp, $action, $effect);
|
||||
$timestamp, $action, $effect, $setup, $breakdown);
|
||||
$self->{'version'} = $version;
|
||||
return $self->{'version'};
|
||||
|
||||
@@ -579,6 +642,43 @@ sub link_plan {
|
||||
$dbh->do("INSERT INTO test_case_plans (plan_id, case_id)
|
||||
VALUES (?,?)", undef, $plan_id, $case_id);
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
# Update the plans array to include new plan added.
|
||||
|
||||
push @{$self->{'plans'}}, Bugzilla::Testopia::TestPlan->new($plan_id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
=head2 unlink_plan
|
||||
|
||||
Removes the link to the specified plan id.
|
||||
|
||||
=cut
|
||||
|
||||
sub unlink_plan {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($plan_id) = @_;
|
||||
|
||||
$dbh->bz_lock_tables('test_case_plans WRITE', 'test_case_runs WRITE',
|
||||
'test_runs READ', 'test_plans READ');
|
||||
|
||||
if (!$self->can_unlink_plan($plan_id)){
|
||||
$dbh->bz_unlock_tables();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$dbh->do("DELETE FROM test_case_plans
|
||||
WHERE plan_id = ?
|
||||
AND case_id = ?", undef, $plan_id, $self->{'case_id'});
|
||||
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
# Update the plans array.
|
||||
delete $self->{'plans'};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 copy
|
||||
@@ -604,7 +704,9 @@ sub copy {
|
||||
my $key = $dbh->bz_last_key( 'test_cases', 'case_id' );
|
||||
|
||||
if ($copydoc){
|
||||
$self->store_text($key, Bugzilla->user->id, $self->text->{'action'}, $self->text->{'effect'}, $timestamp);
|
||||
$self->store_text($key, Bugzilla->user->id, $self->text->{'action'},
|
||||
$self->text->{'effect'}, $self->text->{'setup'},
|
||||
$self->text->{'breakdown'}, $timestamp);
|
||||
}
|
||||
return $key;
|
||||
|
||||
@@ -621,15 +723,37 @@ sub check_alias {
|
||||
my $self = shift;
|
||||
my ($alias) = @_;
|
||||
|
||||
return unless $alias;
|
||||
my $id = $self->{'case_id'} || '';
|
||||
my $dbh = Bugzilla->dbh;
|
||||
($id) = $dbh->selectrow_array(
|
||||
"SELECT case_id
|
||||
FROM test_cases
|
||||
WHERE alias = ?
|
||||
AND case_id != ?",
|
||||
undef, ($alias, $id));
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
=head2 class_check_alias
|
||||
|
||||
Checks if the given alias exists already. Returns the case_id of
|
||||
the matching test case if it does.
|
||||
|
||||
=cut
|
||||
|
||||
sub class_check_alias {
|
||||
my ($alias) = @_;
|
||||
|
||||
return unless $alias;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($id) = $dbh->selectrow_array(
|
||||
"SELECT case_id
|
||||
FROM test_cases
|
||||
WHERE alias = ?
|
||||
AND case_id != ?",
|
||||
undef, ($alias, $self->{'case_id'}));
|
||||
WHERE alias = ?",
|
||||
undef, ($alias));
|
||||
|
||||
return $id;
|
||||
}
|
||||
@@ -662,6 +786,7 @@ sub update {
|
||||
# Update the history
|
||||
my $field_id = Bugzilla::Testopia::Util::get_field_id($field, "test_cases");
|
||||
$dbh->do("INSERT INTO test_case_activity
|
||||
(case_id, fieldid, who, changed, oldvalue, newvalue)
|
||||
VALUES(?,?,?,?,?,?)",
|
||||
undef, $self->{'case_id'}, $field_id, Bugzilla->user->id,
|
||||
$timestamp, $self->{$field}, $newvalues->{$field});
|
||||
@@ -711,6 +836,21 @@ sub history {
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub last_changed {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($date) = $dbh->selectrow_array(
|
||||
"SELECT MAX(changed)
|
||||
FROM test_case_activity
|
||||
WHERE case_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
return $self->{'creation_date'} unless $date;
|
||||
return $date;
|
||||
|
||||
}
|
||||
|
||||
=head2 lookup_status
|
||||
|
||||
Takes an ID of the status field and returns the value
|
||||
@@ -764,6 +904,23 @@ sub lookup_category {
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_category_by_name
|
||||
|
||||
Returns the id of the category name passed.
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_category_by_name {
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($value) = $dbh->selectrow_array(
|
||||
"SELECT category_id
|
||||
FROM test_case_categories
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_priority
|
||||
|
||||
Takes an ID of the priority field and returns the value
|
||||
@@ -782,6 +939,24 @@ sub lookup_priority {
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_priority_by_name
|
||||
|
||||
Returns the id of the priority name passed.
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_priority_by_value {
|
||||
my ($value) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($id) = $dbh->selectrow_array(
|
||||
"SELECT id
|
||||
FROM priority
|
||||
WHERE value = ?",
|
||||
undef, $value);
|
||||
return $id;
|
||||
}
|
||||
|
||||
|
||||
=head2 lookup_default_tester
|
||||
|
||||
Takes an ID of the default_tester field and returns the value
|
||||
@@ -991,11 +1166,37 @@ sub _generate_dep_tree {
|
||||
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 can_unlink_plan
|
||||
|
||||
Returns true if this test case can be unlinked from the given plan
|
||||
|
||||
=cut
|
||||
|
||||
sub can_unlink_plan {
|
||||
my $self = shift;
|
||||
my ($plan_id) = @_;
|
||||
|
||||
return 0 if (!UserInGroup('managetestplans'));
|
||||
|
||||
return 0 if scalar @{$self->plans} < 2;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($res) = $dbh->selectrow_array(
|
||||
"SELECT 1
|
||||
FROM test_case_runs
|
||||
INNER JOIN test_runs ON test_case_runs.run_id = test_runs.run_id
|
||||
WHERE test_runs.plan_id = ?
|
||||
AND test_case_runs.case_id = ?",
|
||||
undef, ($plan_id, $self->{'case_id'}));
|
||||
|
||||
return !$res;
|
||||
}
|
||||
|
||||
=head2 canedit
|
||||
|
||||
Returns true if the logged in user has rights to edit this test case.
|
||||
@@ -1221,16 +1422,19 @@ sub components {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'components'} if exists $self->{'components'};
|
||||
#TODO: 2.22 use Bugzilla::Component
|
||||
my $comps = $dbh->selectall_arrayref(
|
||||
"SELECT comp.id, comp.name
|
||||
my $comps = $dbh->selectcol_arrayref(
|
||||
"SELECT comp.id
|
||||
FROM components AS comp
|
||||
JOIN test_case_components AS tcc ON tcc.component_id = comp.id
|
||||
JOIN test_cases ON tcc.case_id = test_cases.case_id
|
||||
WHERE test_cases.case_id = ?",
|
||||
{'Slice' => {}}, $self->{'case_id'});
|
||||
|
||||
|
||||
$self->{'components'} = $comps;
|
||||
my @comps;
|
||||
foreach my $id (@$comps){
|
||||
push @comps, Bugzilla::Component->new($id);
|
||||
}
|
||||
$self->{'components'} = \@comps;
|
||||
return $self->{'components'};
|
||||
}
|
||||
|
||||
@@ -1293,8 +1497,7 @@ sub bugs {
|
||||
return $self->{'bugs'} if exists $self->{'bugs'};
|
||||
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
|
||||
FROM test_case_bugs
|
||||
WHERE case_id = ?",
|
||||
undef, $self->{'case_id'});
|
||||
my @bugs;
|
||||
@@ -1317,11 +1520,12 @@ sub text {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return $self->{'text'} if exists $self->{'text'};
|
||||
my $text = $dbh->selectrow_hashref("SELECT action, effect
|
||||
FROM test_case_texts
|
||||
WHERE case_id=? AND case_text_version=?",
|
||||
undef, $self->{'case_id'},
|
||||
$self->version);
|
||||
my $text = $dbh->selectrow_hashref(
|
||||
"SELECT action, effect, setup, breakdown, who author_id, case_text_version AS version
|
||||
FROM test_case_texts
|
||||
WHERE case_id=? AND case_text_version=?",
|
||||
undef, $self->{'case_id'},
|
||||
$self->version);
|
||||
$self->{'text'} = $text;
|
||||
return $self->{'text'};
|
||||
}
|
||||
@@ -1409,7 +1613,21 @@ sub blocked_list {
|
||||
my $ref = _get_dep_lists("dependson", "blocked", $self->{'case_id'});
|
||||
$self->{'blocked_list'} = join(",", @$ref);
|
||||
return $self->{'blocked_list'};
|
||||
}
|
||||
}
|
||||
|
||||
=head2 blocked_list_uncached
|
||||
|
||||
Returns a space separated list of test cases that are blocked by this test case.
|
||||
This method does not cache the blocked test cases so each call will result
|
||||
in a database read.
|
||||
|
||||
=cut
|
||||
|
||||
sub blocked_list_uncached {
|
||||
my ($self) = @_;
|
||||
my $ref = _get_dep_lists("dependson", "blocked", $self->{'case_id'});
|
||||
return join(" ", @$ref)
|
||||
}
|
||||
|
||||
=head2 dependson
|
||||
|
||||
@@ -1439,6 +1657,20 @@ sub dependson_list {
|
||||
return $self->{'dependson_list'};
|
||||
}
|
||||
|
||||
=head2 dependson_list_uncached
|
||||
|
||||
Returns a space separated list of test cases that depend on this test case.
|
||||
This method does not cache the dependent test cases so each call will result
|
||||
in a database read.
|
||||
|
||||
=cut
|
||||
|
||||
sub dependson_list_uncached {
|
||||
my ($self) = @_;
|
||||
my $ref = _get_dep_lists("blocked", "dependson", $self->{'case_id'});
|
||||
return join(" ", @$ref)
|
||||
}
|
||||
|
||||
|
||||
=head1 TODO
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ use Bugzilla::User;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::Constants;
|
||||
use Date::Format;
|
||||
|
||||
###############################
|
||||
#### Initialization ####
|
||||
@@ -81,6 +82,7 @@ use constant DB_COLUMNS => qw(
|
||||
test_case_runs.case_run_status_id
|
||||
test_case_runs.case_text_version
|
||||
test_case_runs.build_id
|
||||
test_case_runs.environment_id
|
||||
test_case_runs.notes
|
||||
test_case_runs.close_date
|
||||
test_case_runs.iscurrent
|
||||
@@ -161,10 +163,11 @@ sub store {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO test_case_runs ($columns)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", undef,
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", undef,
|
||||
(undef, $self->{'run_id'}, $self->{'case_id'}, $self->{'assignee'},
|
||||
undef, IDLE, $self->{'case_text_version'},
|
||||
$self->{'build_id'}, $self->{'notes'}, undef, 1, 0));
|
||||
$self->{'build_id'}, $self->{'environment_id'},
|
||||
undef, undef, 1, 0));
|
||||
|
||||
my $key = $dbh->bz_last_key( 'test_case_runs', 'case_run_id' );
|
||||
return $key;
|
||||
@@ -180,7 +183,10 @@ sub clone {
|
||||
my $self = shift;
|
||||
my ($fields) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$self->{'build_id'} = $fields->{'build_id'};
|
||||
my $note = "Build or Environment changed. Resetting to IDLE.";
|
||||
$self->append_note($note);
|
||||
$self->{'build_id'} = $fields->{'build_id'} if $fields->{'build_id'};
|
||||
$self->{'environment_id'} = $fields->{'environment_id'} if $fields->{'environment_id'};
|
||||
my $entry = $self->store;
|
||||
$self->set_as_current($entry);
|
||||
return $entry;
|
||||
@@ -188,28 +194,54 @@ sub clone {
|
||||
|
||||
=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
|
||||
Checks for an existing entry with the same build and environment 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) = @_;
|
||||
my ($run_id, $case_id, $build_id, $env_id) = @_;
|
||||
|
||||
$run_id ||= $self->{'run_id'};
|
||||
$case_id ||= $self->{'case_id'};
|
||||
$build_id ||= $self->{'build_id'};
|
||||
|
||||
$env_id ||= $self->{'environment_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 = ?
|
||||
AND environment_id = ?",
|
||||
undef, ($run_id, $case_id, $build_id, $env_id));
|
||||
|
||||
return $is;
|
||||
|
||||
}
|
||||
|
||||
=head2 lookup_case_run_id
|
||||
|
||||
Checks for an existing entry based on run, case, and build,
|
||||
and returns the id if it is found
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_case_run_id
|
||||
{
|
||||
my ($run_id, $case_id, $build_id) = @_;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($case_run_id) = $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;
|
||||
|
||||
return $case_run_id;
|
||||
}
|
||||
|
||||
=head2 update
|
||||
@@ -227,9 +259,9 @@ sub update {
|
||||
if ($self->is_closed_status($fields->{'case_run_status_id'})){
|
||||
$fields->{'close_date'} = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
}
|
||||
my ($is) = $self->check_exists($self->run_id, $self->case_id, $fields->{'build_id'});
|
||||
my ($is) = $self->check_exists($self->run_id, $self->case_id, $fields->{'build_id'}, $fields->{'environment_id'});
|
||||
|
||||
if ($fields->{'build_id'} != $self->{'build_id'}){
|
||||
if ($fields->{'build_id'} != $self->{'build_id'} || $fields->{'environment_id'} != $self->{'environment_id'}){
|
||||
if ($is){
|
||||
return $is;
|
||||
}
|
||||
@@ -311,6 +343,19 @@ sub set_build {
|
||||
$self->{'build_id'} = $build_id;
|
||||
}
|
||||
|
||||
=head2 set_environment
|
||||
|
||||
Sets the environment on a case-run
|
||||
|
||||
=cut
|
||||
|
||||
sub set_environment {
|
||||
my $self = shift;
|
||||
my ($env_id) = @_;
|
||||
$self->_update_fields({'environment_id' => $env_id});
|
||||
$self->{'environment_id'} = $env_id;
|
||||
}
|
||||
|
||||
=head2 set_status
|
||||
|
||||
Sets the status on a case-run and updates the close_date and testedby
|
||||
@@ -356,17 +401,56 @@ sub set_assignee {
|
||||
$self->_update_fields({'assignee' => $user_id});
|
||||
}
|
||||
|
||||
=head2 set_note
|
||||
=head2 lookup_status
|
||||
|
||||
Returns the status name of the given case_run_status_id
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_status {
|
||||
my $self = shift;
|
||||
my ($status_id) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($status) = $dbh->selectrow_array(
|
||||
"SELECT name
|
||||
FROM test_case_run_status
|
||||
WHERE case_run_status_id = ?",
|
||||
undef, $status_id);
|
||||
return $status;
|
||||
}
|
||||
|
||||
=head2 lookup_status_by_name
|
||||
|
||||
Returns the id of the status name passed.
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_status_by_name {
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($value) = $dbh->selectrow_array(
|
||||
"SELECT case_run_status_id
|
||||
FROM test_case_run_status
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 append_note
|
||||
|
||||
Updates the notes field for the case-run
|
||||
|
||||
=cut
|
||||
|
||||
sub set_note {
|
||||
sub append_note {
|
||||
my $self = shift;
|
||||
my ($note, $append) = @_;
|
||||
if ($append){
|
||||
my $note = $self->notes . "\n" . $note;
|
||||
my ($note) = @_;
|
||||
return unless $note;
|
||||
my $timestamp = time2str("%c", time());
|
||||
$note = "$timestamp: $note";
|
||||
if ($self->{'notes'}){
|
||||
$note = $self->{'notes'} . "\n" . $note;
|
||||
}
|
||||
$self->_update_fields({'notes' => $note});
|
||||
$self->{'notes'} = $note;
|
||||
@@ -456,18 +540,35 @@ sub attach_bug {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->bz_lock_tables('test_case_bugs WRITE');
|
||||
my ($is) = $dbh->selectrow_array(
|
||||
my ($exists) = $dbh->selectrow_array(
|
||||
"SELECT bug_id
|
||||
FROM test_case_bugs
|
||||
WHERE case_run_id=?
|
||||
AND bug_id=?",
|
||||
undef, ($caserun_id, $bug));
|
||||
if ($is) {
|
||||
if ($exists) {
|
||||
$dbh->bz_unlock_tables();
|
||||
return;
|
||||
}
|
||||
$dbh->do("INSERT INTO test_case_bugs (bug_id, case_run_id)
|
||||
VALUES(?,?)", undef, ($bug, $self->{'case_run_id'}));
|
||||
my ($check) = $dbh->selectrow_array(
|
||||
"SELECT bug_id
|
||||
FROM test_case_bugs
|
||||
WHERE case_id=?
|
||||
AND bug_id=?
|
||||
AND case_run_id=?",
|
||||
undef, ($caserun_id, $bug, undef));
|
||||
|
||||
if ($check){
|
||||
$dbh->do("UPDATE test_case_bugs
|
||||
SET test_case_run_id = ?
|
||||
WHERE case_id = ?
|
||||
AND bug_id = ?",
|
||||
undef, ($bug, $self->{'case_run_id'}));
|
||||
}
|
||||
else{
|
||||
$dbh->do("INSERT INTO test_case_bugs (bug_id, case_run_id, case_id)
|
||||
VALUES(?,?,?)", undef, ($bug, $self->{'case_run_id'}, $self->{'case_id'}));
|
||||
}
|
||||
$dbh->bz_unlock_tables();
|
||||
}
|
||||
|
||||
@@ -569,7 +670,6 @@ sub run_id { return $_[0]->{'run_id'}; }
|
||||
sub testedby { return Bugzilla::User->new($_[0]->{'testedby'}); }
|
||||
sub assignee { return Bugzilla::User->new($_[0]->{'assignee'}); }
|
||||
sub case_text_version { return $_[0]->{'case_text_version'}; }
|
||||
sub notes { return $_[0]->{'notes'}; }
|
||||
sub close_date { return $_[0]->{'close_date'}; }
|
||||
sub iscurrent { return $_[0]->{'iscurrent'}; }
|
||||
sub status_id { return $_[0]->{'case_run_status_id'}; }
|
||||
@@ -577,6 +677,25 @@ sub sortkey { return $_[0]->{'sortkey'}; }
|
||||
sub isprivate { return $_[0]->{'isprivate'}; }
|
||||
sub updated_deps { return $_[0]->{'updated_deps'}; }
|
||||
|
||||
=head2 notes
|
||||
|
||||
Returns the cumulative notes of all caserun records of this case and run.
|
||||
|
||||
=cut
|
||||
|
||||
sub notes {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $notes = $dbh->selectcol_arrayref(
|
||||
"SELECT notes
|
||||
FROM test_case_runs
|
||||
WHERE case_id = ? AND run_id = ?
|
||||
ORDER BY case_run_id",
|
||||
undef,($self->case_id, $self->run_id));
|
||||
|
||||
return join("\n", @$notes);
|
||||
}
|
||||
|
||||
=head2 run
|
||||
|
||||
Returns the TestRun object that this case-run is associated with
|
||||
@@ -618,6 +737,19 @@ sub build {
|
||||
return $self->{'build'};
|
||||
}
|
||||
|
||||
=head2 environment
|
||||
|
||||
Returns the Build object that this case-run is associated with
|
||||
|
||||
=cut
|
||||
|
||||
sub environment {
|
||||
my $self = shift;
|
||||
return $self->{'environment'} if exists $self->{'environment'};
|
||||
$self->{'environment'} = Bugzilla::Testopia::Environment->new($self->{'environment_id'});
|
||||
return $self->{'environment'};
|
||||
}
|
||||
|
||||
=head2 status
|
||||
|
||||
Looks up the status name of the associated status_id for this object
|
||||
@@ -817,7 +949,17 @@ Returns true if the logged in user has rights to delete this case-run.
|
||||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
return $self->canedit && Param('allow-test-deletion');
|
||||
|
||||
return ($self->canedit
|
||||
&& Param('allow-test-deletion')
|
||||
&& scalar @{$self->get_case_run_list} == 1
|
||||
&& $self->status eq 'IDLE');
|
||||
}
|
||||
|
||||
sub do_delete {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("DELETE FROM test_case_runs WHERE case_run_id = ?", undef, $self->id);
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
@@ -66,7 +66,6 @@ use base qw(Exporter);
|
||||
plan_id
|
||||
product_id
|
||||
author_id
|
||||
editor_id
|
||||
type_id
|
||||
default_product_version
|
||||
name
|
||||
@@ -79,7 +78,6 @@ use constant DB_COLUMNS => qw(
|
||||
test_plans.plan_id
|
||||
test_plans.product_id
|
||||
test_plans.author_id
|
||||
test_plans.editor_id
|
||||
test_plans.type_id
|
||||
test_plans.default_product_version
|
||||
test_plans.name
|
||||
@@ -158,13 +156,13 @@ sub store {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
$dbh->do("INSERT INTO test_plans ($columns)
|
||||
VALUES (?,?,?,?,?,?,?,?,?)",
|
||||
VALUES (?,?,?,?,?,?,?,?)",
|
||||
undef, (undef, $self->{'product_id'}, $self->{'author_id'},
|
||||
$self->{'editor_id'}, $self->{'type_id'},
|
||||
$self->{'default_product_version'}, $self->{'name'},
|
||||
$self->{'type_id'}, $self->{'default_product_version'}, $self->{'name'},
|
||||
$timestamp, 1));
|
||||
my $key = $dbh->bz_last_key( 'test_plans', 'plan_id' );
|
||||
$self->store_text($key, $self->{'author_id'}, $self->text, $timestamp);
|
||||
$self->{'plan_id'} = $key;
|
||||
return $key;
|
||||
}
|
||||
|
||||
@@ -186,7 +184,9 @@ sub store_text {
|
||||
$text ||= '';
|
||||
trick_taint($text);
|
||||
my $version = $self->version || 0;
|
||||
$dbh->do("INSERT INTO test_plan_texts VALUES(?,?,?,?,?)",
|
||||
$dbh->do("INSERT INTO test_plan_texts
|
||||
(plan_id, plan_text_version, who, creation_ts, plan_text)
|
||||
VALUES(?,?,?,?,?)",
|
||||
undef, $key, ++$version, $author,
|
||||
$timestamp, $text);
|
||||
$self->{'version'} = $version;
|
||||
@@ -208,10 +208,9 @@ sub clone {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($timestamp) = Bugzilla::Testopia::Util::get_time_stamp();
|
||||
$dbh->do("INSERT INTO test_plans ($columns)
|
||||
VALUES (?,?,?,?,?,?,?,?,?)",
|
||||
VALUES (?,?,?,?,?,?,?,?)",
|
||||
undef, (undef, $self->{'product_id'}, $self->{'author_id'},
|
||||
$self->{'editor_id'}, $self->{'type_id'},
|
||||
$self->{'default_product_version'}, $name,
|
||||
$self->{'type_id'}, $self->{'default_product_version'}, $name,
|
||||
$timestamp, 1));
|
||||
my $key = $dbh->bz_last_key( 'test_plans', 'plan_id' );
|
||||
if ($store_doc){
|
||||
@@ -241,6 +240,7 @@ sub toggle_archive {
|
||||
WHERE plan_id = ?", undef, $newvalue, $self->{'plan_id'});
|
||||
my $field_id = Bugzilla::Testopia::Util::get_field_id("isactive", "test_plans");
|
||||
$dbh->do("INSERT INTO test_plan_activity
|
||||
(plan_id, fieldid, who, changed, oldvalue, newvalue)
|
||||
VALUES(?,?,?,?,?,?)",
|
||||
undef, ($self->{'plan_id'}, $field_id, Bugzilla->user->id,
|
||||
$timestamp, $oldvalue, $newvalue));
|
||||
@@ -270,8 +270,8 @@ sub add_tag {
|
||||
$dbh->bz_unlock_tables();
|
||||
return 1;
|
||||
}
|
||||
$dbh->do("INSERT INTO test_plan_tags VALUES(?,?)",
|
||||
undef, ($tag_id, $self->{'plan_id'}));
|
||||
$dbh->do("INSERT INTO test_plan_tags(tag_id, plan_id, userid) VALUES(?,?,?)",
|
||||
undef, ($tag_id, $self->{'plan_id'}), Bugzilla->user->id);
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
}
|
||||
@@ -450,6 +450,103 @@ sub get_plan_types {
|
||||
ORDER BY name",
|
||||
{"Slice"=>{}});
|
||||
return $types;
|
||||
|
||||
}
|
||||
|
||||
=head2 last_changed
|
||||
|
||||
Returns the date of the last change in the history table
|
||||
|
||||
=cut
|
||||
|
||||
sub last_changed {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($date) = $dbh->selectrow_array(
|
||||
"SELECT MAX(changed)
|
||||
FROM test_plan_activity
|
||||
WHERE plan_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
return $self->{'creation_date'} unless $date;
|
||||
return $date;
|
||||
}
|
||||
|
||||
=head2 lookup_plan_type
|
||||
|
||||
Returns a type name matching the given type id
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_plan_type {
|
||||
my $self = shift;
|
||||
my $type_id = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $type = $dbh->selectrow_hashref(
|
||||
"SELECT type_id AS id, name
|
||||
FROM test_plan_types
|
||||
WHERE type_id = ?",
|
||||
undef, $type_id);
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
=head2 check_plan_type
|
||||
|
||||
Returns true if a type with the given name exists
|
||||
|
||||
=cut
|
||||
|
||||
sub check_plan_type {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $type = $dbh->selectrow_hashref(
|
||||
"SELECT 1
|
||||
FROM test_plan_types
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
=head2 update_plan_type
|
||||
|
||||
Update the given type
|
||||
|
||||
=cut
|
||||
|
||||
sub update_plan_type {
|
||||
my $self = shift;
|
||||
my ($type_id, $name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $type = $dbh->do(
|
||||
"UPDATE test_plan_types
|
||||
SET name = ?
|
||||
WHERE type_id = ?",
|
||||
undef, ($name,$type_id));
|
||||
|
||||
}
|
||||
|
||||
=head2 add_plan_type
|
||||
|
||||
Add the given type
|
||||
|
||||
=cut
|
||||
|
||||
sub add_plan_type {
|
||||
my $self = shift;
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $type = $dbh->do(
|
||||
"INSERT INTO test_plan_types (type_id, name)
|
||||
VALUES(?,?)",
|
||||
undef, (undef, $name));
|
||||
}
|
||||
|
||||
=head2 get_fields
|
||||
@@ -551,6 +648,7 @@ sub update {
|
||||
# Update the history
|
||||
my $field_id = Bugzilla::Testopia::Util::get_field_id($field, "test_plans");
|
||||
$dbh->do("INSERT INTO test_plan_activity
|
||||
(plan_id, fieldid, who, changed, oldvalue, newvalue)
|
||||
VALUES(?,?,?,?,?,?)",
|
||||
undef, ($self->{'plan_id'}, $field_id, Bugzilla->user->id,
|
||||
$timestamp, $self->{$field}, $newvalues->{$field}));
|
||||
@@ -609,6 +707,25 @@ sub lookup_type {
|
||||
undef, $id);
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_type_by_name
|
||||
|
||||
Returns the id of the type name passed.
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_type_by_name {
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($value) = $dbh->selectrow_array(
|
||||
"SELECT type_id
|
||||
FROM test_plan_types
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_status
|
||||
|
||||
Takes an ID of the status field and returns the value
|
||||
@@ -665,9 +782,8 @@ Returns true if the logged in user has rights to view this plan
|
||||
|
||||
sub canview {
|
||||
my $self = shift;
|
||||
return $self->{'canview'} if exists $self->{'canview'};
|
||||
$self->{'canview'} = Bugzilla::Testopia::Util::can_view_product($self->product_id);
|
||||
return $self->{'canview'};
|
||||
return 1 if (Bugzilla->user->id == $self->author->id);
|
||||
return Bugzilla::Testopia::Util::can_view_product($self->product_id);
|
||||
}
|
||||
|
||||
=head2 delete
|
||||
@@ -703,10 +819,6 @@ Returns the product version for this object
|
||||
|
||||
Returns the product id for this object
|
||||
|
||||
=head2 editor
|
||||
|
||||
Returns a Bugzilla::User object representing the plan's last editor
|
||||
|
||||
=head2 author
|
||||
|
||||
Returns a Bugzilla::User object representing the plan author
|
||||
@@ -729,7 +841,6 @@ sub id { return $_[0]->{'plan_id'}; }
|
||||
sub creation_date { return $_[0]->{'creation_date'}; }
|
||||
sub product_version { return $_[0]->{'default_product_version'}; }
|
||||
sub product_id { return $_[0]->{'product_id'}; }
|
||||
sub editor { return Bugzilla::User->new($_[0]->{'editor_id'}); }
|
||||
sub author { return Bugzilla::User->new($_[0]->{'author_id'}); }
|
||||
sub name { return $_[0]->{'name'}; }
|
||||
sub type_id { return $_[0]->{'type_id'}; }
|
||||
|
||||
@@ -161,7 +161,7 @@ sub calculate_percent_completed {
|
||||
my $total = $idle + $run;
|
||||
my $percent;
|
||||
if ($total == 0) {
|
||||
$percent = 100;
|
||||
$percent = 0;
|
||||
} else {
|
||||
$percent = $run*100/$total;
|
||||
$percent = int($percent + 0.5);
|
||||
@@ -226,8 +226,8 @@ sub add_tag {
|
||||
$dbh->bz_unlock_tables;
|
||||
return 1;
|
||||
}
|
||||
$dbh->do("INSERT INTO test_run_tags VALUES(?,?)",
|
||||
undef, $tag_id, $self->{'run_id'});
|
||||
$dbh->do("INSERT INTO test_run_tags(tag_id, run_id, userid) VALUES(?,?,?)",
|
||||
undef, $tag_id, $self->{'run_id'}, Bugzilla->user->id);
|
||||
$dbh->bz_unlock_tables;
|
||||
|
||||
return 0;
|
||||
@@ -259,6 +259,7 @@ the test_case_runs table
|
||||
sub add_case_run {
|
||||
my $self = shift;
|
||||
my ($case_id) = @_;
|
||||
return 0 if $self->check_case($case_id);
|
||||
my $case = Bugzilla::Testopia::TestCase->new($case_id);
|
||||
my $caserun = Bugzilla::Testopia::TestCaseRun->new({
|
||||
'run_id' => $self->{'run_id'},
|
||||
@@ -266,6 +267,7 @@ sub add_case_run {
|
||||
'assignee' => $case->default_tester->id,
|
||||
'case_text_version' => $case->version,
|
||||
'build_id' => $self->build->id,
|
||||
'environment_id' => $self->environment_id,
|
||||
});
|
||||
$caserun->store;
|
||||
}
|
||||
@@ -318,6 +320,7 @@ sub update {
|
||||
# Update the history
|
||||
my $field_id = Bugzilla::Testopia::Util::get_field_id($field, "test_runs");
|
||||
$dbh->do("INSERT INTO test_run_activity
|
||||
(run_id, fieldid, who, changed, oldvalue, newvalue)
|
||||
VALUES(?,?,?,?,?,?)",
|
||||
undef, ($self->{'run_id'}, $field_id, Bugzilla->user->id,
|
||||
$timestamp, $self->{$field}, $newvalues->{$field}));
|
||||
@@ -400,6 +403,25 @@ sub history {
|
||||
return $ref;
|
||||
}
|
||||
|
||||
|
||||
=head2 Check_case
|
||||
|
||||
Checks if the given test case is already associated with this run
|
||||
|
||||
=cut
|
||||
|
||||
sub check_case {
|
||||
my $self = shift;
|
||||
my ($case_id) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($value) = $dbh->selectrow_array(
|
||||
"SELECT case_run_id
|
||||
FROM test_case_runs
|
||||
WHERE case_id = ? AND run_id = ?",
|
||||
undef, ($case_id, $self->{'run_id'}));
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_environment
|
||||
|
||||
Takes an ID of the envionment field and returns the value
|
||||
@@ -418,6 +440,23 @@ sub lookup_environment {
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_environment_by_name
|
||||
|
||||
Takes the name of an envionment and returns its id
|
||||
|
||||
=cut
|
||||
|
||||
sub lookup_environment_by_name {
|
||||
my ($name) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($value) = $dbh->selectrow_array(
|
||||
"SELECT environment_id
|
||||
FROM test_environments
|
||||
WHERE name = ?",
|
||||
undef, $name);
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 lookup_build
|
||||
|
||||
Takes an ID of the build field and returns the value
|
||||
@@ -454,6 +493,84 @@ sub lookup_manager {
|
||||
return $value;
|
||||
}
|
||||
|
||||
=head2 last_changed
|
||||
|
||||
Returns the date of the last change in the history table
|
||||
|
||||
=cut
|
||||
|
||||
sub last_changed {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($date) = $dbh->selectrow_array(
|
||||
"SELECT MAX(changed)
|
||||
FROM test_run_activity
|
||||
WHERE run_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
return $self->{'creation_date'} unless $date;
|
||||
return $date;
|
||||
}
|
||||
|
||||
sub filter_case_categories {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ids = $dbh->selectcol_arrayref(
|
||||
"SELECT DISTINCT tcc.category_id
|
||||
FROM test_case_categories AS tcc
|
||||
JOIN test_cases ON test_cases.category_id = tcc.category_id
|
||||
JOIN test_case_runs AS tcr ON test_cases.case_id = tcr.case_id
|
||||
WHERE run_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
my @categories;
|
||||
foreach my $id (@$ids){
|
||||
push @categories, Bugzilla::Testopia::Category->new($id);
|
||||
}
|
||||
|
||||
return \@categories;
|
||||
}
|
||||
|
||||
sub filter_builds {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ids = $dbh->selectcol_arrayref(
|
||||
"SELECT DISTINCT build_id
|
||||
FROM test_case_runs
|
||||
WHERE run_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
my @builds;
|
||||
foreach my $id (@$ids){
|
||||
push @builds, Bugzilla::Testopia::Build->new($id);
|
||||
}
|
||||
return \@builds;
|
||||
}
|
||||
|
||||
sub filter_components {
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ids = $dbh->selectcol_arrayref(
|
||||
"SELECT DISTINCT components.id
|
||||
FROM components
|
||||
JOIN test_case_components AS tcc ON tcc.component_id = components.id
|
||||
JOIN test_cases ON test_cases.case_id = tcc.case_id
|
||||
JOIN test_case_runs AS tcr ON test_cases.case_id = tcr.case_id
|
||||
WHERE run_id = ?",
|
||||
undef, $self->id);
|
||||
|
||||
my @components;
|
||||
foreach my $id (@$ids){
|
||||
push @components, Bugzilla::Component->new($id);
|
||||
}
|
||||
|
||||
return \@components;
|
||||
}
|
||||
|
||||
=head2 environments
|
||||
|
||||
Returns a reference to a list of Testopia::Environment objects.
|
||||
@@ -960,6 +1077,39 @@ sub percent_complete {
|
||||
return $self->{'percent_complete'};
|
||||
}
|
||||
|
||||
sub percent_passed {
|
||||
my $self = shift;
|
||||
my $notrun = $self->idle_count + $self->running_count + $self->paused_count + $self->failed_count + $self->blocked_count;
|
||||
my $run = $self->passed_count;
|
||||
$self->{'percent_passed'} = calculate_percent_completed($notrun, $run);
|
||||
return $self->{'percent_passed'};
|
||||
}
|
||||
|
||||
sub percent_failed {
|
||||
my $self = shift;
|
||||
my $notrun = $self->idle_count + $self->running_count + $self->paused_count + $self->passed_count + $self->blocked_count;
|
||||
my $run = $self->failed_count;
|
||||
$self->{'percent_failed'} = calculate_percent_completed($notrun, $run);
|
||||
return $self->{'percent_failed'};
|
||||
}
|
||||
|
||||
sub percent_blocked {
|
||||
my $self = shift;
|
||||
my $notrun = $self->idle_count + $self->running_count + $self->paused_count + $self->passed_count + $self->failed_count;
|
||||
my $run = $self->blocked_count;
|
||||
$self->{'percent_blocked'} = calculate_percent_completed($notrun, $run);
|
||||
return $self->{'percent_blocked'};
|
||||
}
|
||||
|
||||
sub percent_not_run {
|
||||
my $self = shift;
|
||||
my $notrun = $self->failed_count + $self->running_count + $self->paused_count + $self->passed_count;
|
||||
my $run = $self->idle_count + $self->blocked_count;
|
||||
$self->{'percent_not_run'} = calculate_percent_completed($notrun, $run);
|
||||
return $self->{'percent_not_run'};
|
||||
}
|
||||
|
||||
|
||||
=head2 current_caseruns
|
||||
|
||||
Returns a reference to a list of TestCaseRun objects that are the
|
||||
|
||||
@@ -173,7 +173,8 @@ sub store {
|
||||
undef, (undef, $self->{'tag_name'}));
|
||||
$key = $dbh->bz_last_key( 'test_tags', 'tag_id' );
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
|
||||
$self->{'tag_id'} = $key;
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ package Bugzilla::Testopia::Xml;
|
||||
#use fields qw(testplans testcases tags categories builds);
|
||||
|
||||
use strict;
|
||||
#use base qw(Exporter);
|
||||
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Product;
|
||||
use Bugzilla::Testopia::Attachment;
|
||||
use Bugzilla::Testopia::Build;
|
||||
@@ -54,6 +54,27 @@ use Bugzilla::Testopia::XmlTestCase;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util;
|
||||
|
||||
use constant AUTOMATIC => "AUTOMATIC";
|
||||
use constant BLOCKS => "blocks";
|
||||
our $DATABASE_DESCRIPTION = "Database_descripiton";
|
||||
our $DATABASE_ID = "Database_id";
|
||||
use constant IGNORECASE => 1;
|
||||
use constant DEPENDSON => "dependson";
|
||||
use constant PCDATA => "#PCDATA";
|
||||
our $TESTOPIA_GT = "&testopia_gt;";
|
||||
our $TESTOPIA_LT = "&testopia_lt;";
|
||||
use constant TESTPLAN_REFERENCE => "testplan_reference";
|
||||
our $XML_DESCRIPTION = "Xml_description";
|
||||
our $XML_AMP = "&[Aa][Mm][Pp];";
|
||||
our $XML_APOS = "&[Aa][Pp][Oo][Ss];";
|
||||
our $XML_GT = "&[Gg][Tt];";
|
||||
our $XML_LT = "&[Ll][Tt];";
|
||||
our $XML_QUOT = "&[Qq][Uu][Oo][Tt];";
|
||||
|
||||
use constant XMLREFERENCES_FIELDS => "Database_descripiton Database_id Xml_description";
|
||||
@Bugzilla::Testopia::Xml::EXPORT = qw($DATABASE_DESCRIPTION $DATABASE_ID $XML_DESCRIPTION);
|
||||
|
||||
|
||||
use Class::Struct;
|
||||
#
|
||||
# The Xml structure is used to keep track of all new Testopia objects being created.
|
||||
@@ -62,13 +83,22 @@ struct
|
||||
(
|
||||
'Bugzilla::Testopia::Xml',
|
||||
{
|
||||
# Array of attachments read for xml source.
|
||||
attachments => '@',
|
||||
builds => '@',
|
||||
#TODO builds => '@',
|
||||
# Array of categories read from xml source. Categories
|
||||
categories => '@',
|
||||
tags => '@',
|
||||
testenvironments => '@',
|
||||
#TODO testenvironments => '@',
|
||||
# Array of testcases read from xml source.
|
||||
testcases => '@',
|
||||
# Hash of testcase aliases indexed by testcase id. Used during verfication to
|
||||
# insure that alias does not exist and that new aliases are used in only one testcase.
|
||||
testcase_aliases => '%',
|
||||
# Array of testplans read from xml source.
|
||||
testplans => '@',
|
||||
# If true indicates some type of error has occurred processing the XML. Used to prevent
|
||||
# updating Testopia with contents of current XML.
|
||||
parse_error => '$',
|
||||
}
|
||||
);
|
||||
@@ -76,7 +106,6 @@ struct
|
||||
#TODO: Add this to checksetup
|
||||
use Text::Diff;
|
||||
|
||||
#use base qw(Exporter);
|
||||
|
||||
|
||||
###############################
|
||||
@@ -91,35 +120,11 @@ use Text::Diff;
|
||||
#### Methods ####
|
||||
###############################
|
||||
|
||||
=head2 new
|
||||
|
||||
Instantiate a new xml object. This takes a single argument
|
||||
|
||||
Instantiate a new test plan. This takes a single argument
|
||||
either a test plan ID or a reference to a hash containing keys
|
||||
identical to a test plan's fields and desired values.
|
||||
|
||||
=cut
|
||||
|
||||
#sub new {
|
||||
# my Bugzilla::Testopia::Xml $self = fields::new(ref($invocant) || $invocant);
|
||||
# $self->{testplans} = [];
|
||||
# $self->{testcases} = [];
|
||||
# $self->{tags} = [];
|
||||
# $self->{categories} = [];
|
||||
# $self->{builds} = [];
|
||||
# return $self;
|
||||
#}
|
||||
|
||||
sub debug_display()
|
||||
{
|
||||
my ($self) = @_;
|
||||
my $attachments_array_ref = $self->attachments;
|
||||
my $categories_array_ref = $self->categories;
|
||||
my $testcases_array_ref = $self->testcases;
|
||||
my $testplans_array_ref = $self->testplans;
|
||||
|
||||
foreach my $category ( @$categories_array_ref )
|
||||
foreach my $category ( @{$self->categories})
|
||||
{
|
||||
bless($category,"Bugzilla::Testopia::Category");
|
||||
|
||||
@@ -131,7 +136,7 @@ sub debug_display()
|
||||
print STDERR " Description " . $category->description() . "\n";
|
||||
}
|
||||
|
||||
foreach my $testplan ( @$testplans_array_ref )
|
||||
foreach my $testplan ( @{$self->testplans} )
|
||||
{
|
||||
bless($testplan,"Bugzilla::Testopia::TestPlan");
|
||||
|
||||
@@ -147,10 +152,6 @@ sub debug_display()
|
||||
print STDERR " Description " . $testplan->text() . "\n";
|
||||
print STDERR " Default Product Version " . $testplan->product_version() . "\n";
|
||||
print STDERR " Document " . $testplan->text() . "\n";
|
||||
my %editor = %{$testplan->editor()};
|
||||
my $editor_id = $editor{"id"};
|
||||
my $editor_login = $editor{"login"};
|
||||
print STDERR " Editor " . $editor_login . " (id=" . $editor_id . ", hash=" . $testplan->editor() . ")\n";
|
||||
print STDERR " Is Active " . $testplan->isactive() . "\n";
|
||||
print STDERR " Product " . $testplan->product_id() . "\n";
|
||||
print STDERR " Type " . $testplan->type_id() . "\n";
|
||||
@@ -173,13 +174,68 @@ sub debug_display()
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $testcase ( @$testcases_array_ref )
|
||||
foreach my $testcase ( @{$self->testplans} )
|
||||
{
|
||||
bless($testcase,"Bugzilla::Testopia::XmlTestCase");
|
||||
$testcase->debug_display();
|
||||
}
|
||||
}
|
||||
|
||||
=head2 entity_replace_testopia
|
||||
|
||||
Replace testopia entities in the string supplied.
|
||||
|
||||
This method is called for any field that is stored in HTML format. The Testopia entities are
|
||||
provided to allow users to pass HTML tags.
|
||||
|
||||
For example, if you want to store a < in Bold font, the following XML
|
||||
|
||||
&testopia_lt;B&testopia_gt;<&testopia_lt;/B&testopia_gt;
|
||||
|
||||
is passed to the HTML field as
|
||||
|
||||
<B><</B>
|
||||
|
||||
=cut
|
||||
|
||||
sub entity_replace_testopia
|
||||
{
|
||||
my ($string) = @_;
|
||||
|
||||
return undef if ( ! defined $string );
|
||||
|
||||
$string =~ s/$TESTOPIA_GT/>/g;
|
||||
$string =~ s/$TESTOPIA_LT/</g;
|
||||
$string =~ s/\n/<br>/g;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
=head2 entity_replace_xml
|
||||
|
||||
Replace xml entities in the string supplied.
|
||||
|
||||
This method is called for any field that is not stored in HTML format. The source is XML so any
|
||||
XML entity will be in the &<name>; format. These entities need to be converted back to their
|
||||
character representation.
|
||||
|
||||
=cut
|
||||
|
||||
sub entity_replace_xml
|
||||
{
|
||||
my ($string) = @_;
|
||||
|
||||
return undef if ( ! defined $string );
|
||||
|
||||
$string =~ s/$XML_GT/>/g;
|
||||
$string =~ s/$XML_LT/</g;
|
||||
$string =~ s/$XML_AMP/&/g;
|
||||
$string =~ s/$XML_APOS/'/g;
|
||||
$string =~ s/$XML_QUOT/"/g;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub error()
|
||||
{
|
||||
my ($self, $message) = @_;
|
||||
@@ -192,15 +248,12 @@ sub error()
|
||||
sub parse()
|
||||
{
|
||||
my ($self, $xml) = @_;
|
||||
my $twig = XML::Twig->new();
|
||||
|
||||
my $twig = XML::Twig->new( load_DTD => 1, keep_encoding => 1 );
|
||||
|
||||
$twig->parse($xml);
|
||||
my $root = $twig->root;
|
||||
|
||||
my $attachments_array_ref = $self->attachments;
|
||||
my $categories_array_ref = $self->categories;
|
||||
my $testplans_array_ref = $self->testplans;
|
||||
my $testcases_array_ref = $self->testcases;
|
||||
|
||||
foreach my $twig_category ($root->children('category'))
|
||||
{
|
||||
my $product = new Bugzilla::Product({name => $twig_category->field('product')});
|
||||
@@ -216,7 +269,7 @@ sub parse()
|
||||
product_id => $product->id(),
|
||||
description => $twig_category->field('description'),
|
||||
});
|
||||
push @$categories_array_ref, $category;
|
||||
push @{$self->categories}, $category;
|
||||
}
|
||||
|
||||
my $testplan = Bugzilla::Testopia::TestPlan->new({ 'name' => 'dummy' });
|
||||
@@ -230,7 +283,7 @@ sub parse()
|
||||
|
||||
foreach my $twig_testplan ($root->children('testplan'))
|
||||
{
|
||||
my $author = $twig_testplan->field('author');
|
||||
my $author = $twig_testplan->att('author');
|
||||
# Bugzilla::User::match returns a array with a user hash. Fields of the hash needed
|
||||
# are 'id' and 'login'.
|
||||
my $author_ref = Bugzilla::User::match($author, 1, 0);
|
||||
@@ -245,50 +298,43 @@ sub parse()
|
||||
bless($author_user,"Bugzilla::User");
|
||||
$author_id = $author_user->id();
|
||||
}
|
||||
my $editor = $twig_testplan->field('editor');
|
||||
my $editor_ref = Bugzilla::User::match($editor, 1, 0);
|
||||
my $editor_id = -1;
|
||||
if ( ! $editor_ref->[0] )
|
||||
|
||||
my $product_id = Bugzilla::Testopia::TestPlan::lookup_product_by_name($twig_testplan->field('product'));
|
||||
if ( ! defined($product_id) )
|
||||
{
|
||||
$self->error("Cannot find editor '" . $editor . "' in test plan '" . $twig_testplan->field('name') . "'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
my $editor_user = $editor_ref->[0];
|
||||
bless($editor_user,"Bugzilla::User");
|
||||
$editor_id = $editor_user->id();
|
||||
$self->error("Cannot find product '" . $twig_testplan->field('product') . "' in test plan '" . $twig_testplan->field('name') . "'.");
|
||||
}
|
||||
|
||||
$testplan = Bugzilla::Testopia::TestPlan->new({
|
||||
'name' => $twig_testplan->field('name'),
|
||||
'product_id' => Bugzilla::Testopia::TestPlan::lookup_product_by_name($twig_testplan->field('product')),
|
||||
'default_product_version' => $twig_testplan->field('productversion'),
|
||||
'type_id' => $plantype_ids{$twig_testplan->field('type')},
|
||||
'text' => $twig_testplan->field('document'),
|
||||
'author_id' => $author_id,
|
||||
'editor_id' => $editor_id,
|
||||
'isactive' => $twig_testplan->field('archive'),
|
||||
'creation_date' => $twig_testplan->field('created')
|
||||
'name' => entity_replace_xml($twig_testplan->field('name')),
|
||||
'product_id' => $product_id,
|
||||
'default_product_version' => entity_replace_xml($twig_testplan->field('productversion')),
|
||||
'type_id' => $plantype_ids{$twig_testplan->att('type')},
|
||||
'text' => entity_replace_testopia($twig_testplan->field('document')),
|
||||
'author_id' => $author_id,
|
||||
'isactive' => entity_replace_xml($twig_testplan->field('archive')),
|
||||
'creation_date' => entity_replace_xml($twig_testplan->field('created'))
|
||||
});
|
||||
push @$testplans_array_ref, $testplan;
|
||||
push @{$self->testplans}, $testplan;
|
||||
|
||||
my @tags = $twig_testplan->children('tag');
|
||||
foreach my $twig_tag (@tags)
|
||||
{
|
||||
push @{$self->tags}, $twig_tag->text();
|
||||
push @{$self->tags}, entity_replace_xml($twig_tag->text());
|
||||
}
|
||||
|
||||
my @attachments = $twig_testplan->children('attachment');
|
||||
foreach my $twig_attachments (@attachments)
|
||||
{
|
||||
my $attachment = Bugzilla::Testopia::Attachment->new({
|
||||
'description' => $twig_attachments->field('description'),
|
||||
'filename' => $twig_attachments->field('filename'),
|
||||
'submitter_id' => $twig_attachments->field('submitter'),
|
||||
'mime_type' => $twig_attachments->field('mimetype'),
|
||||
'creation_ts' => $twig_attachments->field('created'),
|
||||
'data' => $twig_attachments->field('data')
|
||||
'description' => entity_replace_xml($twig_attachments->field('description')),
|
||||
'filename' => entity_replace_xml($twig_attachments->field('filename')),
|
||||
'submitter_id' => entity_replace_xml($twig_attachments->field('submitter')),
|
||||
'mime_type' => entity_replace_xml($twig_attachments->field('mimetype')),
|
||||
'creation_ts' => entity_replace_xml($twig_attachments->field('created')),
|
||||
'data' => entity_replace_xml($twig_attachments->field('data'))
|
||||
});
|
||||
push @$attachments_array_ref, $attachment;
|
||||
push @{$self->attachments}, $attachment;
|
||||
#$testplan->add_tag($tag->id());
|
||||
}
|
||||
}
|
||||
@@ -309,14 +355,15 @@ sub parse()
|
||||
}
|
||||
foreach my $twig_testcase ($root->children('testcase'))
|
||||
{
|
||||
my $author = $twig_testcase->field('author');
|
||||
my $summary = entity_replace_xml($twig_testcase->field('summary')) || undef;
|
||||
my $author = $twig_testcase->att('author');
|
||||
# Bugzilla::User::match returns a array with a user hash. Fields of the hash needed
|
||||
# are 'id' and 'login'.
|
||||
my $author_ref = Bugzilla::User::match($author, 1, 0);
|
||||
my $author_id = -1;
|
||||
if ( ! $author_ref->[0] )
|
||||
{
|
||||
$self->error("Cannot find author '" . $author . "' in test case '" . $twig_testcase->field('summary') . "'.");
|
||||
$self->error("Cannot find author '" . $author . "' in test case '" . $summary . "'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -324,14 +371,14 @@ sub parse()
|
||||
bless($author_user,"Bugzilla::User");
|
||||
$author_id = $author_user->id();
|
||||
}
|
||||
my $tester = $twig_testcase->field('defaulttester');
|
||||
my $tester = entity_replace_xml($twig_testcase->field('defaulttester'));
|
||||
# Bugzilla::User::match returns a array with a user hash. Fields of the hash needed
|
||||
# are 'id' and 'login'.
|
||||
my $tester_ref = Bugzilla::User::match($tester, 1, 0);
|
||||
my $tester_id = -1;
|
||||
if ( ! $tester_ref->[0] )
|
||||
{
|
||||
$self->error("Cannot find default tester '" . $tester . "' in test case '" . $twig_testcase->field('summary') . "'.");
|
||||
$self->error("Cannot find default tester '" . $tester . "' in test case '" . $summary . "'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -339,74 +386,158 @@ sub parse()
|
||||
bless($tester_user,"Bugzilla::User");
|
||||
$tester_id = $tester_user->id();
|
||||
}
|
||||
my $status_id = Bugzilla::Testopia::TestCase::lookup_status_by_name($twig_testcase->field('status'));
|
||||
$self->error("Cannot find status '" . $twig_testcase->field('status') . "' in test case '" . $twig_testcase->field('summary') . "'.") if ( ! defined($status_id) );
|
||||
my $status_id = Bugzilla::Testopia::TestCase::lookup_status_by_name($twig_testcase->att('status'));
|
||||
$self->error("Cannot find status '" . $twig_testcase->att('status') . "' in test case '" . $summary . "'.") if ( ! defined($status_id) );
|
||||
|
||||
my $xml_testcase = new Bugzilla::Testopia::XmlTestCase;
|
||||
$xml_testcase->blocks(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
|
||||
$xml_testcase->dependson(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
|
||||
$xml_testcase->testplan(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
|
||||
push @{$self->testcases}, $xml_testcase;
|
||||
my $alias = entity_replace_xml($twig_testcase->field('alias')) || undef;
|
||||
|
||||
$xml_testcase->testcase(Bugzilla::Testopia::TestCase->new({
|
||||
'action' => $twig_testcase->field('action'),
|
||||
'alias' => $twig_testcase->field('alias') || undef,
|
||||
'arguments' => $twig_testcase->field('arguments'),
|
||||
'action' => entity_replace_testopia($twig_testcase->field('action')),
|
||||
'alias' => $alias,
|
||||
'arguments' => entity_replace_xml($twig_testcase->field('arguments')),
|
||||
'author_id' => $author_id,
|
||||
#TODO: Blocks
|
||||
'blocks' => undef,
|
||||
|
||||
'breakdown' => entity_replace_testopia($twig_testcase->field('breakdown')),
|
||||
'case_status_id' => $status_id,
|
||||
'category_id' => undef,
|
||||
'creation_date' => $twig_testcase->field('created'),
|
||||
'creation_date' => $twig_testcase->att('created'),
|
||||
'default_tester_id' => $tester_id,
|
||||
#TODO: Depends On
|
||||
'dependson' => undef,
|
||||
'effect' => $twig_testcase->field('effect'),
|
||||
'expectedresults' => $twig_testcase->field('expectedresults'),
|
||||
'isautomated' => $twig_testcase->field('isautomated'),
|
||||
'effect' => entity_replace_testopia($twig_testcase->field('expectedresults')),
|
||||
'isautomated' => ( uc $twig_testcase->att('automated') ) eq AUTOMATIC,
|
||||
'plans' => undef,
|
||||
'priority_id' => $priority_ids{$twig_testcase->field('priority')},
|
||||
'requirement' => $twig_testcase->field('requirement'),
|
||||
'script' => $twig_testcase->field('script'),
|
||||
'summary' => $twig_testcase->field('summary'),
|
||||
'priority_id' => $priority_ids{$twig_testcase->att('priority')},
|
||||
'requirement' => entity_replace_xml($twig_testcase->field('requirement')),
|
||||
'setup' => entity_replace_testopia($twig_testcase->field('setup')),
|
||||
'script' => entity_replace_xml($twig_testcase->field('script')),
|
||||
'summary' => $summary,
|
||||
}));
|
||||
# Action field is html format.
|
||||
my $action = $twig_testcase->field('action');
|
||||
$action =~ s/\n/<br>/g;
|
||||
$xml_testcase->action($action);
|
||||
$xml_testcase->category($twig_testcase->field('category'));
|
||||
# Expectedresults field is html format.
|
||||
my $expectedresults = $twig_testcase->field('expectedresults');
|
||||
$expectedresults =~ s/\n/<br>/g;
|
||||
$xml_testcase->expectedresults($expectedresults);
|
||||
push @$testcases_array_ref, $xml_testcase;
|
||||
|
||||
foreach my $twig_testplan_reference ( $twig_testcase->children(TESTPLAN_REFERENCE) )
|
||||
{
|
||||
my $testplan_reference = $twig_testplan_reference->children_text(PCDATA);
|
||||
if ( $testplan_reference eq "" )
|
||||
{
|
||||
$self->error("No test plan included for type '"
|
||||
. $twig_testplan_reference->att('type')
|
||||
. "' in test case '" . $twig_testcase->field('summary') . "'." );
|
||||
}
|
||||
elsif ( ! $xml_testcase->testplan->add($twig_testplan_reference->att('type'),entity_replace_xml($testplan_reference)) )
|
||||
{
|
||||
$self->error("Do not know how to handle test plan of type '"
|
||||
. $twig_testplan_reference->att('type')
|
||||
. "' in test case '" . $twig_testcase->field('summary') . "'."
|
||||
. "\nKnow types are: (" . uc XMLREFERENCES_FIELDS . ").");
|
||||
}
|
||||
}
|
||||
# Keep track of this testcase's alias. Used during verification to insure aliases are unique.
|
||||
$self->testcase_aliases(entity_replace_xml($twig_testcase->field('summary')),$alias) if ( defined $alias );
|
||||
# Keep track of this testcase's category. To create a category at this time would require
|
||||
# getting the product from the Test Plan that this Test Case is associated with. The category
|
||||
# will created when each Test Case is stored.
|
||||
$xml_testcase->category(entity_replace_xml($twig_testcase->field('categoryname')));
|
||||
|
||||
my @tags = $twig_testcase->children('tag');
|
||||
foreach my $twig_tag (@tags)
|
||||
foreach my $twig_tag ( @tags )
|
||||
{
|
||||
$xml_testcase->add_tag($twig_tag->text());
|
||||
$xml_testcase->add_tag(entity_replace_xml($twig_tag->text()));
|
||||
}
|
||||
|
||||
#my @components;
|
||||
#foreach my $id (@comps){
|
||||
# detaint_natural($id);
|
||||
# validate_selection($id, 'id', 'components');
|
||||
# push @components, $id;
|
||||
#}
|
||||
|
||||
#$case->add_component($_) foreach (@components);
|
||||
my @components = $twig_testcase->children('component');
|
||||
foreach my $twig_component ( @components )
|
||||
{
|
||||
$xml_testcase->add_component(entity_replace_xml($twig_component->text()));
|
||||
}
|
||||
|
||||
foreach my $twig_blocks ( $twig_testcase->children(BLOCKS) )
|
||||
{
|
||||
if ( ! $xml_testcase->blocks->add($twig_blocks->att('type'),entity_replace_xml($twig_blocks->children_text(PCDATA))) )
|
||||
{
|
||||
$self->error("Do not know how to handle a blocking test case of type '" . $twig_blocks->att('type') . "' in test case '" . $xml_testcase->testcase->summary() . "'.")
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $twig_dependson ( $twig_testcase->children(DEPENDSON) )
|
||||
{
|
||||
if ( ! $xml_testcase->dependson->add($twig_dependson->att('type'),entity_replace_xml($twig_dependson->children_text(PCDATA))) )
|
||||
{
|
||||
$self->error("Do not know how to handle dependency of type '" . $twig_dependson->att('type') . "' in test case '" . entity_replace_xml($xml_testcase->testcase->summary()) . "'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Start of data integrity check.
|
||||
#
|
||||
# Run through the Test Plans and Test Cases looking for integrity errors.
|
||||
#
|
||||
|
||||
# Check for duplicate aliases. Loop though all testcases that have a alias.
|
||||
my %used_alias;
|
||||
my %duplicate_alias;
|
||||
foreach my $summary ( keys %{$self->testcase_aliases} )
|
||||
{
|
||||
# Get the alias.
|
||||
my $alias = $self->testcase_aliases($summary);
|
||||
# Is the alias used by a testcase in the database already? If so add it to the duplicate list
|
||||
# and move onto next testcase.
|
||||
my $alias_testcase_id = Bugzilla::Testopia::TestCase::class_check_alias($alias);
|
||||
if ( $alias_testcase_id )
|
||||
{
|
||||
$duplicate_alias{$alias} = $alias_testcase_id;
|
||||
next;
|
||||
}
|
||||
# Is the alias in the used_alias array?
|
||||
if ( defined( $used_alias{$alias} ) )
|
||||
{
|
||||
# If so then another testcase being created also used the alias. Add the alias to the
|
||||
# duplicate list.
|
||||
$duplicate_alias{$alias} = "import";
|
||||
}
|
||||
else
|
||||
{
|
||||
# Alias has not been seen yet. Add it to the used_alias list to keep track of it.
|
||||
$used_alias{$alias} = "";
|
||||
}
|
||||
}
|
||||
# The @duplicate_alias list contains aliases used by more that one test case. Display them and set
|
||||
# error condition
|
||||
foreach my $summary ( keys %{$self->testcase_aliases} )
|
||||
{
|
||||
my $alias = $self->testcase_aliases($summary);
|
||||
if ( exists $duplicate_alias{$alias} )
|
||||
{
|
||||
my $error_message = "Test Case '" . $summary . "' has a non-unique alias '" . $alias . "'.";
|
||||
if ( $duplicate_alias{$alias} ne "import" )
|
||||
{
|
||||
$error_message .= " Test Case " . $duplicate_alias{$alias} . " already uses the alias '" . $alias . "'.";
|
||||
}
|
||||
else
|
||||
{
|
||||
$error_message .= " Additional test cases being imported are using the alias '" . $alias . "'.";
|
||||
}
|
||||
$self->error($error_message);
|
||||
}
|
||||
}
|
||||
|
||||
#TODO Verfication of data.
|
||||
#Test cases require a category or store will fail.
|
||||
|
||||
# Don't really care about the value of parse_error. If it has been defined then a error occurred
|
||||
# parsing the XML.
|
||||
#
|
||||
# Start of data store.
|
||||
#
|
||||
# No data has been written prior to this point. If parse_error has not been set the XML is valid
|
||||
# and no integrity errors were found. It's time to start storing the Test Plans and Test Cases.
|
||||
#
|
||||
|
||||
if ( ! defined $self->parse_error )
|
||||
{
|
||||
# $self->debug_display();
|
||||
my @testplanarray;
|
||||
|
||||
foreach my $testplan ( @{$self->testplans} )
|
||||
{
|
||||
my $plan_id = $testplan->store();
|
||||
$testplan->{'plan_id'} = $plan_id;
|
||||
print "Created Test Plan $plan_id: " . $testplan->name() . "\n";
|
||||
foreach my $asciitag ( @{$self->tags} )
|
||||
{
|
||||
my $classtag = Bugzilla::Testopia::TestTag->new({'tag_name' => $asciitag});
|
||||
@@ -414,20 +545,30 @@ sub parse()
|
||||
$testplan->{'tag_id'} = $tagid;
|
||||
$testplan->add_tag($tagid);
|
||||
}
|
||||
|
||||
push @testplanarray, $testplan;
|
||||
}
|
||||
|
||||
# Store the testcases.
|
||||
foreach my $testcase ( @{$self->testcases} )
|
||||
{
|
||||
bless($testcase,"Bugzilla::Testopia::XmlTestCase");
|
||||
my $result = $testcase->store($testplan->{'author_id'},@testplanarray);
|
||||
my $result = $testcase->store(@{$self->testplans});
|
||||
if ( $result ne "" )
|
||||
{
|
||||
$self->error($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
print "Created Test Case " . $testcase->testcase->id() . ": " . $testcase->testcase->summary() . "\n";
|
||||
}
|
||||
}
|
||||
# Now that each testcase has been stored we loop though them again and create
|
||||
# relationships like blocks or dependson.
|
||||
foreach my $testcase ( @{$self->testcases} )
|
||||
{
|
||||
$testcase->store_relationships(@{$self->testcases});
|
||||
}
|
||||
}
|
||||
|
||||
$twig->purge;
|
||||
}
|
||||
|
||||
|
||||
101
mozilla/webtools/testopia/Bugzilla/Testopia/XmlReferences.pm
Normal file
101
mozilla/webtools/testopia/Bugzilla/Testopia/XmlReferences.pm
Normal file
@@ -0,0 +1,101 @@
|
||||
# -*- 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 Test Runner System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Maciej Maczynski.
|
||||
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
||||
# Maciej Maczynski. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): David Koenig <dkoenig@novell.com>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Testopia::XmlReferences - Testopia XmlReferences object
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module maintains references to objects while the XML data is
|
||||
being imported. Test plans and Test cases can be referenced by
|
||||
database id, database description or XML description. The references
|
||||
are stored here and processed as needed.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Bugzilla::Testopia::XmlReferences;
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
package Bugzilla::Testopia::XmlReferences;
|
||||
|
||||
use constant IGNORECASE => "ignorecase";
|
||||
|
||||
#use strict;
|
||||
|
||||
sub new
|
||||
{
|
||||
my ($invocant,$ignorecase,$fields) = @_;
|
||||
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {};
|
||||
bless($self, $class);
|
||||
$self{IGNORECASE} = $ignorecase;
|
||||
for my $field ( split(/ /, $fields) )
|
||||
{
|
||||
$field = uc $field if ( $self{IGNORECASE} );
|
||||
$self->{$field} = [];
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub add
|
||||
{
|
||||
my ($self, $type, $object) = @_;
|
||||
|
||||
$type = uc $type if ( $self{IGNORECASE} );
|
||||
|
||||
return 0 if ( ! exists $self->{$type} );
|
||||
|
||||
push @{$self->{$type}}, $object;
|
||||
}
|
||||
|
||||
sub display
|
||||
{
|
||||
my ($self) = @_;
|
||||
|
||||
print "display() self=" . $self . "\n";
|
||||
foreach $key (keys %$self)
|
||||
{
|
||||
if ( defined $self->{$key} )
|
||||
{
|
||||
print "display() key=$key value=" . $self->{$key} . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print "display() key=$key value=undefined\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my ($self, $type) = @_;
|
||||
|
||||
$type = uc $type if ( $self{IGNORECASE} );
|
||||
|
||||
return 0 if ( ! exists $self->{$type} );
|
||||
|
||||
return $self->{$type};
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -48,6 +48,7 @@ use Bugzilla::Testopia::TestPlan;
|
||||
use Bugzilla::Testopia::TestRun;
|
||||
use Bugzilla::Testopia::TestTag;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::XmlReferences;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util;
|
||||
|
||||
@@ -62,129 +63,224 @@ struct
|
||||
(
|
||||
'Bugzilla::Testopia::XmlTestCase',
|
||||
{
|
||||
action => '$',
|
||||
blocks => '@',
|
||||
category => '$',
|
||||
dependson => '@',
|
||||
expectedresults => '$',
|
||||
tags => '@',
|
||||
testcase => 'Bugzilla::Testopia::TestCase',
|
||||
# action => '$',
|
||||
blocks => 'Bugzilla::Testopia::XmlReferences',
|
||||
category => '$',
|
||||
components => '@',
|
||||
dependson => 'Bugzilla::Testopia::XmlReferences',
|
||||
# expectedresults => '$',
|
||||
tags => '@',
|
||||
testcase => 'Bugzilla::Testopia::TestCase',
|
||||
testplan => 'Bugzilla::Testopia::XmlReferences',
|
||||
}
|
||||
);
|
||||
|
||||
sub add_tag()
|
||||
{
|
||||
my ($self,$tag) = @_;
|
||||
|
||||
push @{$self->tags}, $tag;
|
||||
}
|
||||
|
||||
sub add_component()
|
||||
{
|
||||
my ($self,$component) = @_;
|
||||
|
||||
push @{$self->components}, $component;
|
||||
}
|
||||
|
||||
sub debug_display()
|
||||
{
|
||||
my ($self) = @_;
|
||||
my $display_variable = "";
|
||||
|
||||
my %text = %{$self->testcase->text()} if ( defined $self->testcase->text() );
|
||||
print STDERR "Testcase: " . $self->testcase->summary() . "\n";
|
||||
my $testcase_id = "null";
|
||||
$testcase_id = $self->testcase->id() if ( $self->testcase->id() );
|
||||
print STDERR " ID " . $testcase_id . "\n";
|
||||
print STDERR " Action\n";
|
||||
my @results = split(/\n/,$self->action);
|
||||
my $testcase_id = "null";
|
||||
$testcase_id = $self->testcase->id() if ( $self->testcase->id() );
|
||||
print STDERR " ID " . $testcase_id . "\n";
|
||||
print STDERR " Action\n";
|
||||
if ( defined $text{'action'} )
|
||||
{
|
||||
my @results = split(/\n/,$text{'action'});
|
||||
foreach my $result (@results)
|
||||
{
|
||||
print STDERR " $result\n";
|
||||
}
|
||||
my $alias = "null";
|
||||
$alias = $self->testcase-alias() if ( $self->testcase->alias() );
|
||||
print STDERR " Alias " . $alias . "\n";
|
||||
my %author = %{$self->testcase->author()};
|
||||
my $author_id = $author{"id"};
|
||||
my $author_login = $author{"login"};
|
||||
print STDERR " Author " . $author_login . " (id=" . $author_id . ", hash=" . $self->testcase->author() . ")\n";
|
||||
foreach my $loop ( @{$self->blocks} )
|
||||
{
|
||||
$display_variable .= $loop . ",";
|
||||
}
|
||||
chop $display_variable;
|
||||
print STDERR " Blocks " . $display_variable . "\n";
|
||||
$display_variable = "";
|
||||
print STDERR " Category " . $self->category . "\n";
|
||||
print STDERR " Creation Date " . $self->testcase->creation_date() . "\n";
|
||||
foreach my $loop ( @{$self->blocks} )
|
||||
{
|
||||
$display_variable .= $loop . ",";
|
||||
}
|
||||
chop $display_variable;
|
||||
print STDERR " Dependson " . $display_variable . "\n";
|
||||
$display_variable = "";
|
||||
print STDERR " Expected Results\n";
|
||||
@results = split(/\n/,$self->expectedresults);
|
||||
}
|
||||
my $alias = "null";
|
||||
$alias = $self->testcase-alias() if ( $self->testcase->alias() );
|
||||
print STDERR " Alias " . $alias . "\n";
|
||||
my %author = %{$self->testcase->author()};
|
||||
my $author_id = $author{"id"};
|
||||
my $author_login = $author{"login"};
|
||||
print STDERR " Author " . $author_login . " (id=" . $author_id . ", hash=" . $self->testcase->author() . ")\n";
|
||||
print STDERR " Blocks " . $self->blocks->display() . "\n";
|
||||
print STDERR " Category " . $self->category . "\n";
|
||||
$display_variable = $self->testcase->creation_date();
|
||||
if ( defined $display_variable )
|
||||
{
|
||||
print STDERR " Creation Date " . $display_variable . "\n";
|
||||
}
|
||||
print STDERR " Depends On " . $self->dependson->display() . "\n";
|
||||
print STDERR " Expected Results\n";
|
||||
if ( defined $text{'effect'} )
|
||||
{
|
||||
my @results = split(/\n/,$text{'effect'});
|
||||
foreach my $result (@results)
|
||||
{
|
||||
print STDERR " $result\n";
|
||||
}
|
||||
print STDERR " Summary " . $self->testcase->summary() . "\n";
|
||||
#TODO:print STDERR " Default Product Version " . $self->testcase->product_version() . "\n";
|
||||
#TODO:print STDERR " Document " . $self->testcase->text() . "\n";
|
||||
my %tester = %{$self->testcase->default_tester()};
|
||||
my $tester_id = $tester{"id"};
|
||||
my $tester_login = $tester{"login"};
|
||||
print STDERR " Tester " . $tester_login . " (id=" . $tester_id . ", hash=" . $self->testcase->default_tester() . ")\n";
|
||||
print STDERR " Is Automated " . $self->testcase->isautomated() . "\n";
|
||||
#TODO:print STDERR " Plans " . $self->testcase->plans() . "\n";
|
||||
#TODO:print STDERR " Priority " . $self->testcase->priority_id() . "\n";
|
||||
#TODO:print STDERR " Product " . $self->testcase->product_id() . "\n";
|
||||
print STDERR " Requirement " . $self->testcase->requirement() . "\n";
|
||||
}
|
||||
print STDERR " Summary " . $self->testcase->summary() . "\n";
|
||||
#TODO:print STDERR " Default Product Version " . $self->testcase->product_version() . "\n";
|
||||
#TODO:print STDERR " Document " . $self->testcase->text() . "\n";
|
||||
my %tester = %{$self->testcase->default_tester()};
|
||||
my $tester_id = $tester{"id"};
|
||||
my $tester_login = $tester{"login"};
|
||||
print STDERR " Tester " . $tester_login . " (id=" . $tester_id . ", hash=" . $self->testcase->default_tester() . ")\n";
|
||||
print STDERR " Is Automated " . $self->testcase->isautomated() . "\n";
|
||||
#TODO:print STDERR " Plans " . $self->testcase->plans() . "\n";
|
||||
#TODO:print STDERR " Priority " . $self->testcase->priority_id() . "\n";
|
||||
#TODO:print STDERR " Product " . $self->testcase->product_id() . "\n";
|
||||
print STDERR " Requirement " . $self->testcase->requirement() . "\n";
|
||||
|
||||
print STDERR " Script " . $self->testcase->script() . "\n";
|
||||
print STDERR " Script Arguments " . $self->testcase->arguments() . "\n";
|
||||
print STDERR " Status " . $self->testcase->status() . "\n";
|
||||
print STDERR " Script " . $self->testcase->script() . "\n";
|
||||
print STDERR " Script Arguments " . $self->testcase->arguments() . "\n";
|
||||
print STDERR " Status " . $self->testcase->status() . "\n";
|
||||
|
||||
foreach my $tag (@{$self->tags})
|
||||
{
|
||||
print STDERR " Tag " . $tag . "\n";
|
||||
}
|
||||
foreach my $tag (@{$self->tags})
|
||||
{
|
||||
print STDERR " Tag " . $tag . "\n";
|
||||
}
|
||||
|
||||
my @attachments = @{$self->testcase->attachments()};
|
||||
foreach my $attachment (@attachments)
|
||||
{
|
||||
my %submitter = %{$self->testcase->submitter()};
|
||||
my $author_login = $author{"login"};
|
||||
print STDERR " Attachment " . $attachment->description() . "\n";
|
||||
print STDERR " Creation Date " . $attachment->creation_ts(). "\n";
|
||||
print STDERR " Filename " . $attachment->filename() . "\n";
|
||||
print STDERR " Mime Type " . $attachment->mime_type(). "\n";
|
||||
print STDERR " Submitter " . $author_login . "\n";
|
||||
}
|
||||
my @attachments = @{$self->testcase->attachments()};
|
||||
foreach my $attachment (@attachments)
|
||||
{
|
||||
my %submitter = %{$self->testcase->submitter()};
|
||||
$author_login = $author{"login"};
|
||||
print STDERR " Attachment " . $attachment->description() . "\n";
|
||||
print STDERR " Creation Date " . $attachment->creation_ts(). "\n";
|
||||
print STDERR " Filename " . $attachment->filename() . "\n";
|
||||
print STDERR " Mime Type " . $attachment->mime_type(). "\n";
|
||||
print STDERR " Submitter " . $author_login . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub add_tag()
|
||||
sub get_testcase_ids()
|
||||
{
|
||||
my ($self,$tag) = @_;
|
||||
|
||||
push @{$self->tags}, $tag;
|
||||
my ($self, $field, @new_testcases) = @_;
|
||||
my $error_message = "";
|
||||
|
||||
my @testcase_id = @{$self->$field->get(uc $Bugzilla::Testopia::Xml::DATABASE_ID)};
|
||||
|
||||
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} )
|
||||
{
|
||||
foreach my $testcase (@new_testcases)
|
||||
{
|
||||
push @testcase_id, $testcase->testcase->id() if ( $testcase->testcase->summary() eq $testcase_summary );
|
||||
}
|
||||
}
|
||||
|
||||
#TODO Testplans using Database_Description
|
||||
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} )
|
||||
{
|
||||
$error_message .= "\n" if ( $error_message ne "" );
|
||||
$error_message .= "Have not implemented code for $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION lookup for blocking test case " . $testcase_summary . "' for Test Case '". $self->testcase->summary . "'.";
|
||||
}
|
||||
return $error_message if ( $error_message ne "" );
|
||||
|
||||
my @return_testcase_id;
|
||||
foreach my $testcase_id (@testcase_id)
|
||||
{
|
||||
my $testcase = Bugzilla::Testopia::TestCase->new($testcase_id);
|
||||
if ( ! defined($testcase) )
|
||||
{
|
||||
$error_message .= "\n" if ( $error_message ne "" );
|
||||
$error_message .= "Could not find blocking Test Case '" . $testcase_id . "' for Test Case '". $self->testcase->summary . "'.";
|
||||
}
|
||||
else
|
||||
{
|
||||
push @return_testcase_id, $testcase->id();
|
||||
}
|
||||
}
|
||||
return $error_message if ( $error_message ne "" );
|
||||
|
||||
return @return_testcase_id;
|
||||
}
|
||||
|
||||
sub store()
|
||||
{
|
||||
my ($self, $userid, @testplans) = @_;
|
||||
my ($self, @new_testplans) = @_;
|
||||
my $error_message = "";
|
||||
my @testplan_id = @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::DATABASE_ID)};
|
||||
|
||||
#
|
||||
# Following code pulled from Bugzilla::Testopia::TestCase->get_category_list().
|
||||
# Cannot call Bugzilla::Testopia::TestCase->get_category_list() until we create a
|
||||
# TestCase but cannot create a TestCase without a category.
|
||||
#
|
||||
my @categories;
|
||||
foreach my $testplan (@testplans)
|
||||
# If we have any references to test plans from the XML data we need to search the @new_testplans
|
||||
# array to find the actual test plan id. The new_testplans array contains all test plans created
|
||||
# from the XML.
|
||||
# Order of looping does not matter, number of test plans associated to each test case should be small.
|
||||
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} )
|
||||
{
|
||||
push @categories, @{$testplan->categories};
|
||||
}
|
||||
my $categoryid = -1;
|
||||
foreach my $category (@categories)
|
||||
{
|
||||
my %temphash = %{$category};
|
||||
if ( $self->category eq $temphash{"name"} )
|
||||
foreach my $testplan (@new_testplans)
|
||||
{
|
||||
$categoryid = $temphash{"category_id"};
|
||||
last;
|
||||
push @testplan_id, $testplan->id() if ( $testplan->name() eq $testplan_name );
|
||||
}
|
||||
}
|
||||
return "Cannot save test case '" . $self->testcase->summary . "', Category '" . $self->category . "' is not valid." if ( $categoryid == -1 );
|
||||
$self->testcase->{'category_id'} = $categoryid;
|
||||
}
|
||||
|
||||
#TODO Testplans using Database_Description
|
||||
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} )
|
||||
{
|
||||
$error_message .= "\n" if ( $error_message ne "" );
|
||||
$error_message .= "Have not implemented code for $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION lookup of test plan " . $testplan_name . "' for Test Case '". $self->testcase->summary . "'.";
|
||||
}
|
||||
return $error_message if ( $error_message ne "" );
|
||||
|
||||
# Have to have a testplan to determine valid categories for testcase.
|
||||
return "Test Case '" . $self->testcase->summary . "' needs a Test Plan." if ( $#testplan_id == -1 );
|
||||
|
||||
# Verify that each testplan exists.
|
||||
my @testplan;
|
||||
foreach my $testplan_id (@testplan_id)
|
||||
{
|
||||
my $testplan = Bugzilla::Testopia::TestPlan->new($testplan_id);
|
||||
if ( ! defined($testplan) )
|
||||
{
|
||||
$error_message .= "\n" if ( $error_message ne "" );
|
||||
$error_message .= "Could not find Test Plan '" . $testplan_id . "' for Test Case '". $self->testcase->summary . "'.";
|
||||
}
|
||||
else
|
||||
{
|
||||
push @testplan, $testplan;
|
||||
}
|
||||
}
|
||||
return $error_message if ( $error_message ne "" );
|
||||
|
||||
# Verify that each testplan has the testcase's category associated to it. If the category does not
|
||||
# exist it will be created.
|
||||
foreach my $testplan (@testplan)
|
||||
{
|
||||
my $categoryid = -1;
|
||||
|
||||
push my @categories, @{$testplan->categories};
|
||||
foreach my $category (@categories)
|
||||
{
|
||||
if ( $category->name eq $self->category )
|
||||
{
|
||||
$categoryid = $category->id;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ( $categoryid == -1 )
|
||||
{
|
||||
my $new_category = Bugzilla::Testopia::Category->new({
|
||||
product_id => $testplan->product_id,
|
||||
name => $self->category,
|
||||
description => "FIX ME. Created during Test Plan import."
|
||||
});
|
||||
$categoryid = $new_category->store();
|
||||
}
|
||||
$self->testcase->{'category_id'} = $categoryid if ( ! defined($self->testcase->{'category_id'}) );
|
||||
}
|
||||
my $case_id = $self->testcase->store();
|
||||
$self->testcase->{'case_id'} = $case_id;
|
||||
foreach my $asciitag ( @{$self->tags} )
|
||||
@@ -193,13 +289,33 @@ sub store()
|
||||
my $tagid = $classtag->store;
|
||||
$self->testcase->add_tag($tagid);
|
||||
}
|
||||
foreach my $testplan ( @testplans )
|
||||
|
||||
# Link the testcase to each of it's testplans.
|
||||
foreach my $testplan ( @testplan )
|
||||
{
|
||||
$self->testcase->link_plan($testplan->id(),$case_id)
|
||||
}
|
||||
$self->testcase->store_text($case_id,$userid,$self->action,$self->expectedresults);
|
||||
|
||||
return "";
|
||||
# Code below requires the testplans to be linked into testcases before being run.
|
||||
foreach my $component ( @{$self->components} )
|
||||
{
|
||||
foreach my $available_component ( @{$self->testcase->get_selectable_components()} )
|
||||
{
|
||||
$self->testcase->add_component($available_component->{'id'}) if ( $component eq $available_component->{'name'} );
|
||||
}
|
||||
}
|
||||
|
||||
return $error_message;
|
||||
}
|
||||
|
||||
sub store_relationships()
|
||||
{
|
||||
my ($self, @new_testcases) = @_;
|
||||
|
||||
my $blocks = $self->testcase->blocked_list_uncached() . " " . join(' ',$self->get_testcase_ids("blocks",@new_testcases));
|
||||
my $dependson = $self->testcase->dependson_list_uncached() . " " . join(' ',$self->get_testcase_ids("dependson",@new_testcases));
|
||||
|
||||
$self->testcase->update_deps($dependson,$blocks);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
36
mozilla/webtools/testopia/Bugzilla/WebService/Constants.pm
Normal file
36
mozilla/webtools/testopia/Bugzilla/WebService/Constants.pm
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
|
||||
|
||||
package Bugzilla::WebService::Constants;
|
||||
|
||||
use strict;
|
||||
use base qw(Exporter);
|
||||
|
||||
@Bugzilla::WebService::Constants::EXPORT = qw(
|
||||
ERROR_AUTH_NODATA
|
||||
ERROR_UNIMPLEMENTED
|
||||
ERROR_GENERAL
|
||||
ERROR_FAULT_SERVER
|
||||
);
|
||||
|
||||
use constant ERROR_AUTH_NODATA => 410;
|
||||
use constant ERROR_UNIMPLEMENTED => 910;
|
||||
use constant ERROR_GENERAL => 999;
|
||||
|
||||
# RPC Fault Code must be an integer
|
||||
use constant ERROR_FAULT_SERVER => 998;
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,257 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
|
||||
# Dallas Harken <dharken@novell.com>
|
||||
|
||||
package Bugzilla::WebService::Testopia::TestCase;
|
||||
|
||||
use strict;
|
||||
use base qw(Bugzilla::WebService);
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util qw(detaint_natural);
|
||||
use Bugzilla::Testopia::TestCase;
|
||||
use Bugzilla::Testopia::Search;
|
||||
use Bugzilla::Testopia::Table;
|
||||
|
||||
|
||||
# Convert string field values to their respective integer id's
|
||||
sub _convert_to_ids
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if (defined($$hash{"author"}))
|
||||
{
|
||||
$$hash{"author_id"} = login_to_id($$hash{"author"});
|
||||
}
|
||||
delete $$hash{"author"};
|
||||
|
||||
if (defined($$hash{"case_status"}))
|
||||
{
|
||||
$$hash{"case_status_id"} = Bugzilla::Testopia::TestCase::lookup_status_by_name($$hash{"case_status"});
|
||||
}
|
||||
delete $$hash{"case_status"};
|
||||
|
||||
if (defined($$hash{"category"}))
|
||||
{
|
||||
$$hash{"category_id"} = Bugzilla::Testopia::TestCase::lookup_category_by_name($$hash{"category"});
|
||||
}
|
||||
delete $$hash{"category"};
|
||||
|
||||
if (defined($$hash{"default_tester"}))
|
||||
{
|
||||
$$hash{"default_tester_id"} = login_to_id($$hash{"default_tester"});
|
||||
}
|
||||
delete $$hash{"default_tester"};
|
||||
|
||||
if (defined($$hash{"priority"}))
|
||||
{
|
||||
$$hash{"priority_id"} = Bugzilla::Testopia::TestCase::lookup_priority_by_value($$hash{"priority"});
|
||||
}
|
||||
delete $$hash{"priority"};
|
||||
}
|
||||
|
||||
# Convert fields with integer id's to their respective string values
|
||||
sub _convert_to_strings
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$$hash{"author"} = "";
|
||||
if (defined($$hash{"author_id"}))
|
||||
{
|
||||
$$hash{"author"} = new Bugzilla::User($$hash{"author_id"})->login;
|
||||
}
|
||||
delete $$hash{"author_id"};
|
||||
|
||||
$$hash{"case_status"} = "";
|
||||
if (defined($$hash{"case_status_id"}))
|
||||
{
|
||||
$$hash{"case_status"} = Bugzilla::Testopia::TestCase->lookup_status($$hash{"case_status_id"});
|
||||
}
|
||||
delete $$hash{"case_status_id"};
|
||||
|
||||
$$hash{"category"} = "";
|
||||
if (defined($$hash{"category_id"}))
|
||||
{
|
||||
$$hash{"category"} = Bugzilla::Testopia::TestCase->lookup_category($$hash{"category_id"});
|
||||
}
|
||||
delete $$hash{"category_id"};
|
||||
|
||||
$$hash{"default_tester"} = "";
|
||||
if (defined($$hash{"default_tester_id"}))
|
||||
{
|
||||
$$hash{"default_tester"} = new Bugzilla::User($$hash{"default_tester_id"})->login;
|
||||
}
|
||||
delete $$hash{"default_tester_id"};
|
||||
|
||||
$$hash{"priority"} = "";
|
||||
if (defined($$hash{"priority_id"}))
|
||||
{
|
||||
$$hash{"priority"} = Bugzilla::Testopia::TestCase->lookup_priority($$hash{"priority_id"});
|
||||
}
|
||||
delete $$hash{"priority_id"};
|
||||
}
|
||||
|
||||
# Utility method called by the list method
|
||||
sub _list
|
||||
{
|
||||
my ($query) = @_;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
$cgi->param("viewall", 1);
|
||||
|
||||
$cgi->param("current_tab", "case");
|
||||
|
||||
foreach (keys(%$query))
|
||||
{
|
||||
$cgi->param($_, $$query{$_});
|
||||
}
|
||||
|
||||
my $search = Bugzilla::Testopia::Search->new($cgi);
|
||||
|
||||
# Result is an array of test plan hash maps
|
||||
return Bugzilla::Testopia::Table->new('case',
|
||||
'tr_xmlrpc.cgi',
|
||||
$cgi,
|
||||
undef,
|
||||
$search->query()
|
||||
)->list();
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
my ($test_case_id) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
# We can detaint immediately if what we get passed is fully numeric.
|
||||
# We leave bug alias checks to Bugzilla::Testopia::TestCase::new.
|
||||
|
||||
if ($test_case_id =~ /^[0-9]+$/) {
|
||||
detaint_natural($test_case_id);
|
||||
}
|
||||
|
||||
#Result is a test case hash map
|
||||
my $testcase = new Bugzilla::Testopia::TestCase($test_case_id);
|
||||
|
||||
_convert_to_strings($testcase);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $testcase;
|
||||
}
|
||||
|
||||
sub list
|
||||
{
|
||||
Bugzilla->login;
|
||||
|
||||
my $self = shift;
|
||||
my ($query) = @_;
|
||||
|
||||
_convert_to_ids($query);
|
||||
|
||||
my $list = _list($query);
|
||||
|
||||
foreach (@$list)
|
||||
{
|
||||
_convert_to_strings($_);
|
||||
}
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
sub create
|
||||
{
|
||||
my $self =shift;
|
||||
my ($new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
my $test_case = new Bugzilla::Testopia::TestCase($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is new test plan id
|
||||
return $test_case->store();
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self =shift;
|
||||
my ($test_case_id, $new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $test_case = new Bugzilla::Testopia::TestCase($test_case_id);
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
$test_case->update($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is zero on success, otherwise an exception will be thrown
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub get_text
|
||||
{
|
||||
my $self =shift;
|
||||
my ($test_case_id) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $test_case = new Bugzilla::Testopia::TestCase($test_case_id);
|
||||
|
||||
my $doc = $test_case->text();
|
||||
|
||||
$$doc{"author"} = "";
|
||||
if (defined($$doc{"author_id"}))
|
||||
{
|
||||
$$doc{"author"} = new Bugzilla::User($$doc{"author_id"})->login;
|
||||
}
|
||||
delete $$doc{"author_id"};
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
#Result is the latest test case doc hash map
|
||||
return $doc;
|
||||
}
|
||||
|
||||
sub store_text
|
||||
{
|
||||
my $self =shift;
|
||||
my ($test_case_id, $author, $action, $effect) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $author_id = login_to_id($author);
|
||||
|
||||
my $test_case = new Bugzilla::Testopia::TestCase($test_case_id);
|
||||
|
||||
my $version = $test_case->store_text($test_case_id, $author_id, $action, $effect);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is new test case doc version on success, otherwise an exception will be thrown
|
||||
return $version;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,186 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
|
||||
# Dallas Harken <dharken@novell.com>
|
||||
|
||||
package Bugzilla::WebService::Testopia::TestCaseRun;
|
||||
|
||||
use strict;
|
||||
use base qw(Bugzilla::WebService);
|
||||
use Bugzilla::Util qw(detaint_natural);
|
||||
use Bugzilla::Testopia::TestCaseRun;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Testopia::Search;
|
||||
use Bugzilla::Testopia::Table;
|
||||
|
||||
# Convert string field values to their respective integer id's
|
||||
sub _convert_to_ids
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if (defined($$hash{"assignee"}))
|
||||
{
|
||||
$$hash{"assignee"} = login_to_id($$hash{"assignee"});
|
||||
}
|
||||
|
||||
if (defined($$hash{"testedby"}))
|
||||
{
|
||||
$$hash{"testedby"} = login_to_id($$hash{"testedby"});
|
||||
}
|
||||
|
||||
if (defined($$hash{"case_run_status"}))
|
||||
{
|
||||
$$hash{"case_run_status_id"} = Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($$hash{"case_run_status"});
|
||||
}
|
||||
delete $$hash{"case_run_status"};
|
||||
}
|
||||
|
||||
# Convert fields with integer id's to their respective string values
|
||||
sub _convert_to_strings
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if (defined($$hash{"assignee"}))
|
||||
{
|
||||
$$hash{"assignee"} = new Bugzilla::User($$hash{"assignee"})->login;
|
||||
}
|
||||
|
||||
if (defined($$hash{"testedby"}))
|
||||
{
|
||||
$$hash{"testedby"} = new Bugzilla::User($$hash{"testedby"})->login;
|
||||
}
|
||||
|
||||
$$hash{"case_run_status"} = "";
|
||||
if (defined($$hash{"case_run_status_id"}))
|
||||
{
|
||||
$$hash{"case_run_status"} = Bugzilla::Testopia::TestCaseRun->lookup_status($$hash{"case_run_status_id"});
|
||||
}
|
||||
delete $$hash{"case_run_status_id"};
|
||||
}
|
||||
|
||||
# Utility method called by the list method
|
||||
sub _list
|
||||
{
|
||||
my ($query) = @_;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
$cgi->param("viewall", 1);
|
||||
|
||||
$cgi->param("current_tab", "case_run");
|
||||
|
||||
foreach (keys(%$query))
|
||||
{
|
||||
$cgi->param($_, $$query{$_});
|
||||
}
|
||||
|
||||
my $search = Bugzilla::Testopia::Search->new($cgi);
|
||||
|
||||
# Result is an array of test case run hash maps
|
||||
return Bugzilla::Testopia::Table->new('case_run',
|
||||
'tr_xmlrpc.cgi',
|
||||
$cgi,
|
||||
undef,
|
||||
$search->query()
|
||||
)->list();
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
my ($test_case_run_id) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
# We can detaint immediately if what we get passed is fully numeric.
|
||||
# We leave bug alias checks to Bugzilla::Testopia::TestCaseRun::new.
|
||||
|
||||
if ($test_case_run_id =~ /^[0-9]+$/) {
|
||||
detaint_natural($test_case_run_id);
|
||||
}
|
||||
|
||||
#Result is a test case run hash map
|
||||
my $test_case_run = new Bugzilla::Testopia::TestCaseRun($test_case_run_id);
|
||||
|
||||
_convert_to_strings($test_case_run);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $test_case_run;
|
||||
|
||||
}
|
||||
|
||||
sub list
|
||||
{
|
||||
Bugzilla->login;
|
||||
|
||||
my $self = shift;
|
||||
my ($query) = @_;
|
||||
|
||||
_convert_to_ids($query);
|
||||
|
||||
my $list = _list($query);
|
||||
|
||||
foreach (@$list)
|
||||
{
|
||||
_convert_to_strings($_);
|
||||
}
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
sub create
|
||||
{
|
||||
my $self =shift;
|
||||
my ($new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
my $test_case_run = new Bugzilla::Testopia::TestCaseRun($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is new test case run id
|
||||
return $test_case_run->store();
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self =shift;
|
||||
my ($run_id, $case_id, $build_id, $new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $test_case_run_id = Bugzilla::Testopia::TestCaseRun::lookup_case_run_id($run_id, $case_id, $build_id);
|
||||
|
||||
my $test_case_run = new Bugzilla::Testopia::TestCaseRun($test_case_run_id);
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
$$new_values{build_id} = $build_id; # Needed by TestCaseRun's update member function
|
||||
|
||||
$test_case_run->update($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is zero on success, otherwise an exception will be thrown
|
||||
return 0;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,190 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
|
||||
# Dallas Harken <dharken@novell.com>
|
||||
|
||||
package Bugzilla::WebService::Testopia::TestPlan;
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Bugzilla::WebService);
|
||||
|
||||
use Bugzilla::Util qw(detaint_natural);
|
||||
use Bugzilla::Product;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Testopia::TestPlan;
|
||||
use Bugzilla::Testopia::Search;
|
||||
use Bugzilla::Testopia::Table;
|
||||
|
||||
# Convert string field values to their respective integer id's
|
||||
sub _convert_to_ids
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if (defined($$hash{"author"}))
|
||||
{
|
||||
$$hash{"author_id"} = login_to_id($$hash{"author"});
|
||||
}
|
||||
delete $$hash{"author"};
|
||||
if (defined($$hash{"product"}))
|
||||
{
|
||||
my $product = Bugzilla::Product::check_product($$hash{"product"});
|
||||
$$hash{"product_id"} = $product->id;
|
||||
}
|
||||
delete $$hash{"product"};
|
||||
|
||||
if (defined($$hash{"type"}))
|
||||
{
|
||||
$$hash{"type_id"} = Bugzilla::Testopia::TestPlan::lookup_type_by_name($$hash{"type"});
|
||||
}
|
||||
delete $$hash{"type"};
|
||||
}
|
||||
|
||||
# Convert fields with integer id's to their respective string values
|
||||
sub _convert_to_strings
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$$hash{"author"} = "";
|
||||
if (defined($$hash{"author_id"}))
|
||||
{
|
||||
$$hash{"author"} = new Bugzilla::User($$hash{"author_id"})->login;
|
||||
}
|
||||
delete $$hash{"author_id"};
|
||||
|
||||
$$hash{"product"} = "";
|
||||
if (defined($$hash{"product_id"}))
|
||||
{
|
||||
$$hash{"product"} = new Bugzilla::Product($$hash{"product_id"})->name;
|
||||
}
|
||||
delete $$hash{"product_id"};
|
||||
|
||||
$$hash{"type"} = "";
|
||||
if (defined($$hash{"type_id"}))
|
||||
{
|
||||
$$hash{"type"} = Bugzilla::Testopia::TestPlan->lookup_type($$hash{"type_id"});
|
||||
}
|
||||
delete $$hash{"type_id"};
|
||||
}
|
||||
|
||||
# Utility method called by the list method
|
||||
sub _list
|
||||
{
|
||||
my ($query) = @_;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
$cgi->param("viewall", 1);
|
||||
|
||||
$cgi->param("current_tab", "plan");
|
||||
|
||||
foreach (keys(%$query))
|
||||
{
|
||||
$cgi->param($_, $$query{$_});
|
||||
}
|
||||
|
||||
my $search = Bugzilla::Testopia::Search->new($cgi);
|
||||
|
||||
# Result is an array of test plan hash maps
|
||||
return Bugzilla::Testopia::Table->new('plan',
|
||||
'tr_xmlrpc.cgi',
|
||||
$cgi,
|
||||
undef,
|
||||
$search->query()
|
||||
)->list();
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
my ($test_plan_id) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
# We can detaint immediately if what we get passed is fully numeric.
|
||||
# We leave bug alias checks to Bugzilla::Testopia::TestPlan::new.
|
||||
|
||||
if ($test_plan_id =~ /^[0-9]+$/) {
|
||||
detaint_natural($test_plan_id);
|
||||
}
|
||||
|
||||
#Result is a test plan hash map
|
||||
my $testplan = new Bugzilla::Testopia::TestPlan($test_plan_id);
|
||||
|
||||
_convert_to_strings($testplan);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $testplan;
|
||||
}
|
||||
|
||||
sub list
|
||||
{
|
||||
Bugzilla->login;
|
||||
|
||||
my $self = shift;
|
||||
my ($query) = @_;
|
||||
|
||||
_convert_to_ids($query);
|
||||
|
||||
my $list = _list($query);
|
||||
|
||||
foreach (@$list)
|
||||
{
|
||||
_convert_to_strings($_);
|
||||
}
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
sub create
|
||||
{
|
||||
my $self =shift;
|
||||
my ($new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
my $test_plan = new Bugzilla::Testopia::TestPlan($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is new test plan id
|
||||
return $test_plan->store();
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self =shift;
|
||||
my ($test_plan_id, $new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $test_plan = new Bugzilla::Testopia::TestPlan($test_plan_id);
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
$test_plan->update($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is zero on success, otherwise an exception will be thrown
|
||||
return 0;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,177 @@
|
||||
# -*- 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 Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
|
||||
# Dallas Harken <dharken@novell.com>
|
||||
|
||||
package Bugzilla::WebService::Testopia::TestRun;
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Bugzilla::WebService);
|
||||
|
||||
use Bugzilla::Util qw(detaint_natural);
|
||||
use Bugzilla::Product;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Testopia::TestRun;
|
||||
use Bugzilla::Testopia::Search;
|
||||
use Bugzilla::Testopia::Table;
|
||||
|
||||
# Convert string field values to their respective integer id's
|
||||
sub _convert_to_ids
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if (defined($$hash{"manager"}))
|
||||
{
|
||||
$$hash{"manager_id"} = login_to_id($$hash{"manager"});
|
||||
}
|
||||
delete $$hash{"manager"};
|
||||
|
||||
if (defined($$hash{"environment"}))
|
||||
{
|
||||
$$hash{"environment_id"} = Bugzilla::Testopia::TestRun::lookup_environment_by_name($$hash{"environment"});
|
||||
}
|
||||
delete $$hash{"environment"};
|
||||
}
|
||||
|
||||
# Convert fields with integer id's to their respective string values
|
||||
sub _convert_to_strings
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$$hash{"manager"} = "";
|
||||
if (defined($$hash{"manager_id"}))
|
||||
{
|
||||
$$hash{"manager"} = new Bugzilla::User($$hash{"manager_id"})->login;
|
||||
}
|
||||
delete $$hash{"manager_id"};
|
||||
|
||||
$$hash{"environment"} = "";
|
||||
if (defined($$hash{"environment_id"}))
|
||||
{
|
||||
$$hash{"environment"} = Bugzilla::Testopia::TestRun->lookup_environment($$hash{"environment_id"});
|
||||
}
|
||||
delete $$hash{"environment_id"};
|
||||
}
|
||||
|
||||
# Utility method called by the list method
|
||||
sub _list
|
||||
{
|
||||
my ($query) = @_;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
$cgi->param("viewall", 1);
|
||||
|
||||
$cgi->param("current_tab", "run");
|
||||
|
||||
foreach (keys(%$query))
|
||||
{
|
||||
$cgi->param($_, $$query{$_});
|
||||
}
|
||||
|
||||
my $search = Bugzilla::Testopia::Search->new($cgi);
|
||||
|
||||
# Result is an array of test run hash maps
|
||||
return Bugzilla::Testopia::Table->new('run',
|
||||
'tr_xmlrpc.cgi',
|
||||
$cgi,
|
||||
undef,
|
||||
$search->query()
|
||||
)->list();
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
my ($test_run_id) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
# We can detaint immediately if what we get passed is fully numeric.
|
||||
# We leave bug alias checks to Bugzilla::Testopia::TestRun::new.
|
||||
|
||||
if ($test_run_id =~ /^[0-9]+$/) {
|
||||
detaint_natural($test_run_id);
|
||||
}
|
||||
|
||||
#Result is a test run hash map
|
||||
my $testrun = new Bugzilla::Testopia::TestRun($test_run_id);
|
||||
|
||||
_convert_to_strings($testrun);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $testrun;
|
||||
}
|
||||
|
||||
sub list
|
||||
{
|
||||
Bugzilla->login;
|
||||
|
||||
my $self = shift;
|
||||
my ($query) = @_;
|
||||
|
||||
_convert_to_ids($query);
|
||||
|
||||
my $list = _list($query);
|
||||
|
||||
foreach (@$list)
|
||||
{
|
||||
_convert_to_strings($_);
|
||||
}
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
sub create
|
||||
{
|
||||
my $self =shift;
|
||||
my ($new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
my $test_run = new Bugzilla::Testopia::TestRun($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is new test run id
|
||||
return $test_run->store();
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self =shift;
|
||||
my ($test_run_id, $new_values) = @_;
|
||||
|
||||
Bugzilla->login;
|
||||
|
||||
my $test_run = new Bugzilla::Testopia::TestRun($test_run_id);
|
||||
|
||||
_convert_to_ids($new_values);
|
||||
|
||||
$test_run->update($new_values);
|
||||
|
||||
Bugzilla->logout;
|
||||
|
||||
# Result is zero on success, otherwise an exception will be thrown
|
||||
return 0;
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user