refactor Builda and Category to extend Object

git-svn-id: svn://10.0.0.236/trunk@233156 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ghendricks%novell.com
2007-08-27 18:49:09 +00:00
parent f096ffb852
commit 8439655cbd
11 changed files with 338 additions and 206 deletions

View File

@@ -39,9 +39,13 @@ package Bugzilla::Testopia::Build;
use strict;
use Bugzilla::Util;
use Bugzilla::Error;
use Bugzilla::Testopia::TestPlan;
use Bugzilla::Testopia::TestCase;
use base qw(Exporter Bugzilla::Object);
@Bugzilla::Bug::EXPORT = qw(check_build);
###############################
#### Initialization ####
###############################
@@ -56,7 +60,9 @@ use Bugzilla::Testopia::TestCase;
isactive
=cut
use constant DB_TABLE => "test_builds";
use constant NAME_FIELD => "name";
use constant ID_FIELD => "build_id";
use constant DB_COLUMNS => qw(
build_id
product_id
@@ -66,6 +72,152 @@ use constant DB_COLUMNS => qw(
isactive
);
use constant REQUIRED_CREATE_FIELDS => qw(product_id name milestone isactive);
use constant UPDATE_COLUMNS => qw(name description milestone isactive);
use constant VALIDATORS => {
product_id => \&_check_product,
isactive => \&_check_isactive,
};
###############################
#### Validators ####
###############################
sub _check_product {
my ($invocant, $product_id) = @_;
$product_id = trim($product_id);
ThrowUserError("testopia-create-denied", {'object' => 'build'}) unless Bugzilla->user->in_group('Testers');
my $product = Bugzilla::Testopia::Product->new($product_id);
if (ref $invocant){
$invocant->{'product'} = $product;
return $product->id;
}
return $product;
}
sub _check_name {
my ($invocant, $name, $product_id) = @_;
$name = clean_text($name) if $name;
trick_taint($name);
if (!defined $name || $name eq '') {
ThrowUserError('testopia-missing-required-field', {'field' => 'name'});
}
# Check that we don't already have a build with that name in this product.
my $orig_id = check_build($name, $product_id);
my $notunique;
if (ref $invocant){
# If updating, we have matched ourself at least
$notunique = 1 if (($orig_id && $orig_id != $invocant->id))
}
else {
# In new build any match is one too many
$notunique = 1 if $orig_id;
}
ThrowUserError('testopia-name-not-unique',
{'object' => 'Build',
'name' => $name}) if $notunique;
return $name;
}
sub _check_milestone {
my ($invocant, $milestone, $product) = @_;
if (ref $invocant){
$product = $invocant->product;
}
$milestone = trim($milestone);
$milestone = Bugzilla::Milestone::check_milestone($product, $milestone);
return $milestone->name;
}
sub _check_isactive {
my ($invocant, $isactive) = @_;
ThrowCodeError('bad_arg', {argument => 'isactive', function => 'set_isactive'}) unless ($isactive =~ /(1|0)/);
return $isactive;
}
##############################
#### Mutators ####
###############################
sub set_description { $_[0]->set('description', $_[1]); }
sub set_isactive { $_[0]->set('isactive', $_[1]); }
sub set_milestone {
my ($self, $value) = @_;
$value = $self->_check_milestone($value);
$self->set('milestone', $value);
}
sub set_name {
my ($self, $value) = @_;
$value = $self->_check_name($value, $self->product_id);
$self->set('name', $value);
}
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $param = shift;
# We want to be able to supply an empty object to the templates for numerous
# lists etc. This is much cleaner than exporting a bunch of subroutines and
# adding them to $vars one by one. Probably just Laziness shining through.
if (ref $param eq 'HASH'){
if (keys %$param){
bless($param, $class);
return $param;
}
bless($param, $class);
return $param;
}
unshift @_, $param;
my $self = $class->SUPER::new(@_);
return $self;
}
sub run_create_validators {
my $class = shift;
my $params = $class->SUPER::run_create_validators(@_);
my $product = $params->{product_id};
$params->{milestone} = $class->_check_milestone($params->{milestone}, $product);
$params->{name} = $class->_check_name($params->{name}, $product);
return $params;
}
sub create {
my ($class, $params) = @_;
$class->SUPER::check_required_create_fields($params);
my $field_values = $class->run_create_validators($params);
$field_values->{isactive} = 1;
$field_values->{product_id} = $field_values->{product_id}->id;
my $self = $class->SUPER::insert_create_data($field_values);
return $self;
}
###############################
#### Functions ####
###############################
sub check_build {
my ($name, $product_id) = @_;
my $dbh = Bugzilla->dbh;
my $is = $dbh->selectrow_array(
"SELECT build_id FROM test_builds
WHERE name = ? AND product_id = ?",
undef, $name, $product_id);
return $is;
}
###############################
#### Methods ####
###############################
@@ -77,46 +229,6 @@ use constant DB_COLUMNS => qw(
Instantiates a new Build 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 build class
=cut
sub _init {
my $self = shift;
my ($param) = (@_);
my $dbh = Bugzilla->dbh;
my $columns = join(", ", DB_COLUMNS);
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_builds
WHERE build_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 store
Serializes this build to the database
@@ -143,17 +255,6 @@ for a product.
=cut
sub check_name {
my $self = shift;
my ($name) = @_;
my $dbh = Bugzilla->dbh;
my $is = $dbh->selectrow_array(
"SELECT build_id FROM test_builds
WHERE name = ? AND product_id = ?",
undef, $name, $self->{'product_id'});
return $is;
}
=head2 check_build_by_name
@@ -172,23 +273,6 @@ sub check_build_by_name {
return $id;
}
=head2 update
Updates an existing build object in the database.
Takes the new name, description, and milestone.
=cut
sub update {
my $self = shift;
my ($name, $desc, $milestone, $isactive) = @_;
my $dbh = Bugzilla->dbh;
$dbh->do("UPDATE test_builds
SET name = ?, description = ?, milestone = ?, isactive= ?
WHERE build_id = ?", undef,
($name, $desc, $milestone, $isactive, $self->{'build_id'}));
}
=head2 toggle_hidden
Toggles the archive bit on the build.
@@ -236,6 +320,15 @@ sub description { return $_[0]->{'description'};}
sub milestone { return $_[0]->{'milestone'};}
sub isactive { return $_[0]->{'isactive'};}
sub product {
my ($self) = @_;
return $self->{'product'} if exists $self->{'product'};
$self->{'product'} = Bugzilla::Testopia::Product->new($self->product_id);
return $self->{'product'};
}
=head2 run_count
Returns the number of test runs using this build

View File

@@ -43,6 +43,9 @@ use Bugzilla::Error;
use Bugzilla::Testopia::TestPlan;
use Bugzilla::Testopia::TestCase;
use base qw(Exporter Bugzilla::Object);
@Bugzilla::Bug::EXPORT = qw(check_case_category);
###############################
#### Initialization ####
###############################
@@ -55,7 +58,9 @@ use Bugzilla::Testopia::TestCase;
description
=cut
use constant DB_TABLE => "test_case_categories";
use constant NAME_FIELD => "name";
use constant ID_FIELD => "category_id";
use constant DB_COLUMNS => qw(
category_id
product_id
@@ -63,6 +68,127 @@ use constant DB_COLUMNS => qw(
description
);
use constant REQUIRED_CREATE_FIELDS => qw(product_id name);
use constant UPDATE_COLUMNS => qw(name description);
use constant VALIDATORS => {
product_id => \&_check_product,
};
###############################
#### Validators ####
###############################
sub _check_product {
my ($invocant, $product_id) = @_;
$product_id = trim($product_id);
ThrowUserError("testopia-create-denied", {'object' => 'build'}) unless Bugzilla->user->in_group('Testers');
my $product = Bugzilla::Testopia::Product->new($product_id);
if (ref $invocant){
$invocant->{'product'} = $product;
return $product->id;
}
return $product;
}
sub _check_name {
my ($invocant, $name, $product_id) = @_;
$name = clean_text($name) if $name;
trick_taint($name);
if (!defined $name || $name eq '') {
ThrowUserError('testopia-missing-required-field', {'field' => 'name'});
}
# Check that we don't already have a build with that name in this product.
my $orig_id = check_case_category($name, $product_id);
my $notunique;
if (ref $invocant){
# If updating, we have matched ourself at least
$notunique = 1 if (($orig_id && $orig_id != $invocant->id))
}
else {
# In new build any match is one too many
$notunique = 1 if $orig_id;
}
ThrowUserError('testopia-name-not-unique',
{'object' => 'Case Category',
'name' => $name}) if $notunique;
return $name;
}
##############################
#### Mutators ####
###############################
sub set_description { $_[0]->set('description', $_[1]); }
sub set_name {
my ($self, $value) = @_;
$value = $self->_check_name($value, $self->product_id);
$self->set('name', $value);
}
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $param = shift;
# We want to be able to supply an empty object to the templates for numerous
# lists etc. This is much cleaner than exporting a bunch of subroutines and
# adding them to $vars one by one. Probably just Laziness shining through.
if (ref $param eq 'HASH'){
if (keys %$param){
bless($param, $class);
return $param;
}
bless($param, $class);
return $param;
}
unshift @_, $param;
my $self = $class->SUPER::new(@_);
return $self;
}
sub run_create_validators {
my $class = shift;
my $params = $class->SUPER::run_create_validators(@_);
my $product = $params->{product_id};
$params->{name} = $class->_check_name($params->{name}, $product);
return $params;
}
sub create {
my ($class, $params) = @_;
$class->SUPER::check_required_create_fields($params);
my $field_values = $class->run_create_validators($params);
$field_values->{product_id} = $field_values->{product_id}->id;
my $self = $class->SUPER::insert_create_data($field_values);
return $self;
}
###############################
#### Functions ####
###############################
sub check_case_category {
my ($name, $product_id) = @_;
my $dbh = Bugzilla->dbh;
my $is = $dbh->selectrow_array(
"SELECT category_id FROM test_case_categories
WHERE name = ? AND product_id = ?",
undef, $name, $product_id);
return $is;
}
###############################
#### Methods ####
###############################
@@ -159,17 +285,7 @@ database for the product.
=cut
sub check_name {
my $self = shift;
my ($name) = @_;
my $dbh = Bugzilla->dbh;
my $is = $dbh->selectrow_array(
"SELECT category_id FROM test_case_categories
WHERE name = ? AND product_id = ?",
undef, $name, $self->{'product_id'});
return $is;
}
=head2 update
@@ -178,16 +294,6 @@ Takes the new name, and description.
=cut
sub update {
my $self = shift;
my ($name, $desc) = @_;
my $dbh = Bugzilla->dbh;
$dbh->do("UPDATE test_case_categories
SET name = ?, description = ?
WHERE category_id = ?", undef,
($name, $desc, $self->{'category_id'}));
}
sub candelete {
my $self = shift;
return 0 unless Bugzilla->user->in_group('Testers');

View File

@@ -78,9 +78,9 @@ use constant UPDATE_COLUMNS => qw(product_id type_id default_product_ver
use constant VALIDATORS => {
product_id => \&_check_product,
author_id => \&_check_author,
type_id => \&_check_type,
isactive => \&_check_isactive,
author_id => \&_check_author,
type_id => \&_check_type,
isactive => \&_check_isactive,
};
use constant NAME_MAX_LENGTH => 255;

View File

@@ -276,10 +276,10 @@ sub parse()
});
# Only create the category if it does not exist.
push @{$self->categories}, $category if ( ! $category->check_name($category_name) );
push @{$self->categories}, $category if ( ! check_case_category($category_name, $product->id) );
}
my $testplan = Bugzilla::Testopia::TestPlan->new({ 'name' => 'dummy' });
my $testplan = Bugzilla::Testopia::TestPlan->new({});
my %plantype_ids;
my @temparray = @{$testplan->get_plan_types()};
foreach my $arrayelement (@temparray)
@@ -316,7 +316,7 @@ sub parse()
$self->error("Found empty Test Plan name.") if ( ! defined($name) );
$self->error("Length of Test Plan name '" . $name . "' must be " . Bugzilla::Testopia::TestPlan->NAME_MAX_LENGTH . " characters or less.") if ( defined($name) && ( length($name) > Bugzilla::Testopia::TestPlan->NAME_MAX_LENGTH ) );
$testplan = Bugzilla::Testopia::TestPlan->new({
$testplan = Bugzilla::Testopia::TestPlan->create({
'name' => $name,
'product_id' => $product_id,
'default_product_version' => entity_replace_xml($twig_testplan->field('productversion'),STRIP_BOTH),
@@ -609,7 +609,7 @@ sub parse()
{
# Make sure category still does not exist. We don't check for uniqueness above so
# the same category could be defined multiple times.
if ( ! $category->check_name($category->name()) )
if ( ! check_case_category($category->name(), $category->product_id) )
{
$category->store();
my $product_name = Bugzilla::Testopia::Product->new($category->product_id())->name();
@@ -620,8 +620,6 @@ sub parse()
# Store new testplans.
foreach my $testplan ( @{$self->testplans} )
{
my $plan_id = $testplan->store();
$testplan->{'plan_id'} = $plan_id;
foreach my $asciitag ( @{$self->tags} )
{
my $classtag = Bugzilla::Testopia::TestTag->new({'tag_name' => $asciitag});
@@ -631,10 +629,10 @@ sub parse()
}
foreach my $attachment ( @{$self->attachments} )
{
$attachment->{'plan_id'} = $plan_id;
$attachment->{'plan_id'} = $testplan->id;
$attachment->store();
}
print "Created Test Plan $plan_id: " . $testplan->name() . "\n";
print "Created Test Plan ". $testplan->id . ": " . $testplan->name() . "\n";
}
# Store new testcases.

View File

@@ -319,7 +319,7 @@ sub store()
foreach my $testplan (@testplan)
{
my $category = $testplan->product->categories->[0];
my $categoryid = $category->check_name($self->category) if ( defined($category) );
my $categoryid = check_case_category($self->category) if ( defined($category) );
if ( ! defined($categoryid) )
{
my $new_category = Bugzilla::Testopia::Category->new({

View File

@@ -51,21 +51,12 @@ sub create
$self->login;
my $build = new Bugzilla::Testopia::Build($new_values);
my $name = $$new_values{name};
if (defined($name) && $build->check_name($name))
{
die "Build name, " . $name . ", already exists";
}
my $result = $build->store();
my $build = Bugzilla::Testopia::Build->create($new_values);
$self->logout;
# Result is new build id
return $result;
return $build->id;
}
sub update
@@ -85,7 +76,7 @@ sub update
my $name = $$new_values{name};
if (defined($name) && $build->check_name($name))
if (defined($name) && check_build($name, $build->product_id))
{
die "Build name, " . $name . ", already exists";
}
@@ -97,14 +88,14 @@ sub update
my $description = (defined($$new_values{description}) ? $$new_values{description} : $build->description());
my $milestone = (defined($$new_values{milestone}) ? $$new_values{milestone} : $build->milestone());
my $milestone = (defined($$new_values{milestone}) ? $$new_values{milestone} : $build->milestone());
my $result = $build->update($name,
$description,
$milestone);
$build->set_name($name);
$build->set_description($description);
$build->set_milestone($milestone);
$build->update;
$build = new Bugzilla::Testopia::Build($build_id);
$self->logout;
# Result is modified build, otherwise an exception will be thrown

View File

@@ -18,7 +18,6 @@
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
#%]
<link href="testopia/css/default.css" rel="stylesheet" type="text/css" />
[% PROCESS global/header.html.tmpl
style_urls = ['testopia.css'] %]

View File

@@ -41,8 +41,6 @@ my $cgi = Bugzilla->cgi;
print $cgi->header;
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
my $action = $cgi->param('action') || '';
my $product_id = $cgi->param('product_id');
@@ -63,27 +61,13 @@ if ($action eq 'add'){
}
elsif ($action eq 'do_add'){
my $cname = $cgi->param('name');
my $desc = $cgi->param('desc');
my $tm = $cgi->param('milestone');
ThrowUserError('testopia-missing-required-field', {'field' => 'build name'}) unless $cname;
trick_taint($cname);
trick_taint($desc);
trick_taint($tm);
my $build = Bugzilla::Testopia::Build->new({
my $build = Bugzilla::Testopia::Build->create({
product_id => $product->id,
name => $cname,
description => $desc,
milestone => $tm,
name => $cgi->param('name'),
description => $cgi->param('desc'),
milestone => $cgi->param('milestone'),
isactive => $cgi->param('isactive') ? 1 : 0,
});
ThrowUserError('testopia-name-not-unique',
{'object' => 'Build',
'name' => $cname}) if $build->check_name($cname);
$build->store;
$vars->{'tr_message'} = "Build successfully added";
display();
@@ -102,27 +86,15 @@ elsif ($action eq 'edit'){
}
elsif ($action eq 'do_edit'){
my $cname = $cgi->param('name');
my $desc = $cgi->param('desc');
my $milestone = $cgi->param('milestone');
my $bid = $cgi->param('build_id');
my $build = Bugzilla::Testopia::Build->new($cgi->param('build_id'));
ThrowUserError('testopia-missing-required-field', {'field' => 'build name'}) unless $cname;
$build->set_name($cgi->param('name'));
$build->set_description($cgi->param('desc'));
$build->set_milestone($cgi->param('milestone'));
$build->set_isactive($cgi->param('isactive') ? 1 : 0);
my $build = Bugzilla::Testopia::Build->new($bid);
$build->update();
trick_taint($cname);
trick_taint($desc);
trick_taint($milestone);
validate_selection($milestone, 'value', 'milestones');
my $orig_id = $build->check_name($cname);
ThrowUserError('testopia-name-not-unique',
{'object' => 'Build',
'name' => $cname}) if ($orig_id && $orig_id != $bid);
$build->update($cname, $desc, $milestone, $cgi->param('isactive') ? 1 : 0);
$vars->{'tr_message'} = "Build successfully updated";
display();
}

View File

@@ -41,8 +41,6 @@ my $cgi = Bugzilla->cgi;
print $cgi->header;
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
my $action = $cgi->param('action') || '';
my $product_id = $cgi->param('product_id');
@@ -63,23 +61,11 @@ if ($action eq 'add'){
}
elsif ($action eq 'do_add'){
my $cname = $cgi->param('name');
my $desc = $cgi->param('desc');
ThrowUserError('testopia-missing-required-field', {'field' => 'category name'}) unless $cname;
trick_taint($cname);
trick_taint($desc);
my $category = Bugzilla::Testopia::Category->new({
product_id => $product->id,
name => $cname,
description => $desc
my $category = Bugzilla::Testopia::Category->create({
product_id => $product->id,
name => $cgi->param('name'),
description => $cgi->param('desc'),
});
ThrowUserError('testopia-name-not-unique',
{'object' => 'Category',
'name' => $cname}) if $category->check_name($cname);
$category->store;
$vars->{'tr_message'} = "Category successfully added";
display();
@@ -89,31 +75,19 @@ elsif ($action eq 'do_add'){
### Edit a Category ###
#######################
elsif ($action eq 'edit'){
my $category = Bugzilla::Testopia::Category->new($cgi->param('category_id'));
$vars->{'category'} = $category;
$vars->{'category'} = Bugzilla::Testopia::Category->new($cgi->param('category_id'));
$vars->{'action'} = 'do_edit';
$template->process("testopia/category/form.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'do_edit'){
my $cname = $cgi->param('name');
my $desc = $cgi->param('desc');
my $cid = $cgi->param('category_id');
my $category = Bugzilla::Testopia::Category->new($cid);
my $category = Bugzilla::Testopia::Category->new($cgi->param('category_id'));
ThrowUserError('testopia-missing-required-field', {'field' => 'category name'}) unless $cname;
trick_taint($cname);
trick_taint($desc);
my $orig_id = $category->check_name($cname);
ThrowUserError('testopia-name-not-unique',
{'object' => 'Category',
'name' => $cname}) if ($orig_id && $cid != $orig_id);
$category->set_name($cgi->param('name'));
$category->set_description($cgi->param('desc'));
$category->update($cname, $desc);
$category->update;
$vars->{'tr_message'} = "Category successfully updated";
display();

View File

@@ -109,19 +109,19 @@ if ($action eq 'Add'){
if ($cgi->param('new_build')){
my $new_build = $cgi->param('new_build');
trick_taint($new_build);
my $b = Bugzilla::Testopia::Build->new({
'name' => $new_build,
'milestone' => '---',
'product_id' => $plan->product_id,
'description' => '',
'isactive' => 1,
});
my $bid = $b->check_name($new_build);
my $bid = check_build($new_build);
if($bid){
$build = $bid;
}
else{
$build = $b->store;
my $b = Bugzilla::Testopia::Build->create({
'name' => $cgi->param('new_build'),
'milestone' => '---',
'product_id' => $plan->product_id,
'description' => '',
'isactive' => 1,
});
$build = $b->id;
}
}
@@ -220,6 +220,7 @@ else {
my $run = Bugzilla::Testopia::TestRun->new(
{'run_id' => 0,
'plan' => $plan,
'build' => {},
'plan_text_version' => $plan->version } );
print $cgi->header;
ThrowUserError('testopia-create-environment') unless (scalar @{$run->environments} > 0);

View File

@@ -43,8 +43,6 @@ my $dbh = Bugzilla->dbh;
local our $cgi = Bugzilla->cgi;
local our $template = Bugzilla->template;
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
Bugzilla->login(LOGIN_REQUIRED);
sub get_searchable_objects{