# -*- Mode: perl; indent-tabs-mode: nil -*- # # The contents of this file are subject to the Mozilla Public # License Version 1.1 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or # implied. See the License for the specific language governing # rights and limitations under the License. # # The Original Code is the Bugzilla Testopia System. # # The Initial Developer of the Original Code is Greg Hendricks. # Portions created by Greg Hendricks are Copyright (C) 2006 # Novell. All Rights Reserved. # # Contributor(s): Dallas Harken # Greg Hendricks package Bugzilla::WebService::Testopia::TestCaseRun; use strict; use base qw(Bugzilla::WebService); use Bugzilla::User; use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Util; use Bugzilla::Testopia::Constants; use Bugzilla::Testopia::Search; use Bugzilla::Testopia::Table; use Bugzilla::Testopia::TestCaseRun; use Bugzilla::Testopia::Util; sub get { my $self = shift; my ($run_id, $case_id, $build_id, $env_id) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-permission-denied', {'object' => $caserun}) unless $caserun->canview; return $caserun; } sub list { my $self = shift; my ($query) = @_; Bugzilla->login(LOGIN_REQUIRED); my $cgi = Bugzilla->cgi; $cgi->param("current_tab", "case_run"); foreach (keys(%$query)){ $cgi->param($_, $$query{$_}); } my $search = Bugzilla::Testopia::Search->new($cgi); return Bugzilla::Testopia::Table->new('case_run','tr_xmlrpc.cgi',$cgi,undef,$search->query())->list(); } sub create { my $self = shift; my ($new_values) = @_; Bugzilla->login(LOGIN_REQUIRED); my $run = Bugzilla::Testopia::TestRun->new($new_values->{'run_id'}); ThrowUserError('invalid-test-id-non-existent', {type => 'Test Run', id => $new_values->{'run_id'}}) unless $run; ThrowUserError('testopia-read-only', {'object' => $run}) unless $run->canedit; $new_values->{'build_id'} ||= $new_values->{'build'}; $new_values->{'environment_id'} ||= $new_values->{'environment'}; delete $new_values->{'build'}; delete $new_values->{'environment'}; if (trim($new_values->{'build_id'}) !~ /^\d+$/ ){ my $build = Bugzilla::Testopia::Build::check_build($new_values->{'build_id'}, $run->plan->product, "THROWERROR"); $new_values->{'build_id'} = $build->id; } if (trim($new_values->{'environment_id'}) !~ /^\d+$/ ){ my $environment = Bugzilla::Testopia::Environment::check_environment($new_values->{'environment_id'}, $run->plan->product, "THROWERROR"); $new_values->{'environment_id'} = $environment->id; } if ($new_values->{'status'}){ $new_values->{'case_run_status_id'} = Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($new_values->{'status'}); delete $new_values->{'status'}; } $new_values->{'case_run_status_id'} = IDLE unless $new_values->{'case_run_status_id'}; my $caserun = Bugzilla::Testopia::TestCaseRun->create($new_values); # Result is new test case run object hash return $caserun; } sub update { my $self = shift; my ($run_id, $case_id, $build_id, $env_id, $new_values) = @_; Bugzilla->login(LOGIN_REQUIRED); my @caseruns; my @ids = Bugzilla::Testopia::Util::process_list($run_id); if (ref $case_id eq 'HASH' && !$build_id){ $new_values = $case_id; foreach my $id (@ids){ my $caserun = new Bugzilla::Testopia::TestCaseRun($id); if ($caserun){ push @caseruns, $caserun; } else { push @caseruns, {ERROR => 'Case-run does not exist'}; } } } else { foreach my $id (@ids){ my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id,$case_id,$build_id,$env_id); if ($caserun){ push @caseruns, $caserun; } else { push @caseruns, {ERROR => 'Case-run does not exist'}; } } } if ($new_values->{'status'}){ $new_values->{'case_run_status_id'} = Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($new_values->{'status'}); delete $new_values->{'status'}; } $new_values->{'build_id'} ||= $new_values->{'build'}; $new_values->{'environment_id'} ||= $new_values->{'environment'}; my @results; foreach my $caserun (@caseruns){ if ($caserun->{'ERROR'}){ push @results, $caserun; next; } unless ($caserun->canedit){ push @results, {ERROR => "You do not have rights to edit this test case"}; next; } $run_id = $caserun->run_id; $case_id = $caserun->case_id; $build_id ||= $caserun->build->id; $env_id ||= $caserun->environment->id; # Check to see what has changed then use set methods # The order is important. We need to check if the build or environment has # Changed so that we can switch to the right record first. if ($new_values->{'build_id'} && $new_values->{'environment_id'}){ $caserun = $caserun->switch($new_values->{'build_id'}, $new_values->{'environment_id'}, $run_id, $case_id); } elsif ($new_values->{'build_id'}){ $caserun = $caserun->switch($new_values->{'build_id'}, $env_id, $run_id, $case_id); } elsif ($new_values->{'environment_id'}){ $caserun = $caserun->switch($build_id, $new_values->{'environment_id'}, $run_id, $case_id); } # Now that we know we are working with the right record, update it. if ($new_values->{'assignee'}){ $caserun->set_assignee($new_values->{'assignee'}); } if ($new_values->{'case_run_status_id'}){ $caserun->set_status($new_values->{'case_run_status_id'}, $new_values->{'update_bugs'}); } if ($new_values->{'sortkey'}){ $caserun->set_sortkey($new_values->{'sortkey'}); } if ($new_values->{'notes'}){ $caserun->append_note($new_values->{'notes'}); } # Remove assignee user object and replace with just assignee id if (ref $caserun->{'assignee'} eq 'Bugzilla::User'){ $caserun->{assignee} = $caserun->{assignee}->id(); } # Result is modified test case run on success, otherwise an exception will be thrown push @results, $caserun; } return \@results; } sub lookup_status_id_by_name { my $self = shift; my ($name) = @_; Bugzilla->login(LOGIN_REQUIRED); # Result is test case run status id for the given test case run status name return Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($name); } sub lookup_status_name_by_id { my $self = shift; my ($id) = @_; Bugzilla->login(LOGIN_REQUIRED); my $test_case_run = new Bugzilla::Testopia::TestCaseRun({}); # Result is test case run status name for the given test case run status id return $test_case_run->lookup_status($id); } sub get_history { my $self = shift; my ($run_id, $case_id, $build_id, $env_id) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-permission-denied', {'object' => $caserun}) unless $caserun->canview; return $caserun->get_case_run_list; } sub attach_bug { my $self = shift; my ($run_id, $case_id, $build_id, $env_id, $bug_ids) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); # If we have just the id, the third arg will not be set. $bug_ids = $case_id unless $build_id; ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-read-only', {'object' => $caserun}) unless $caserun->canedit; $caserun->attach_bug($bug_ids); return undef; } sub detach_bug { my $self = shift; my ($run_id, $case_id, $build_id, $env_id, $bug_id) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); # If we have just the id, the third arg will not be set. $bug_id = $case_id unless $build_id; ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-read-only', {'object' => $caserun}) unless $caserun->canedit; $caserun->detach_bug($bug_id); # Result 0 on success, otherwise an exception will be thrown return 0; } sub get_bugs { my $self = shift; my ($run_id, $case_id, $build_id, $env_id) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-permission-denied', {'object' => $caserun}) unless $caserun->canview; return $caserun->bugs; } sub get_completion_time { my $self = shift; my ($run_id, $case_id, $build_id, $env_id) = @_; Bugzilla->login(LOGIN_REQUIRED); #Result is a test case run hash map my $caserun = new Bugzilla::Testopia::TestCaseRun($run_id, $case_id, $build_id, $env_id); ThrowUserError('invalid-test-id-non-existent', {type => 'Test Case Run', id => $run_id}) unless $caserun; ThrowUserError('testopia-permission-denied', {'object' => $caserun}) unless $caserun->canview; return $caserun->completion_time; } 1; __END__ =head1 NAME Bugzilla::Testopia::Webservice::TestCaseRun =head1 EXTENDS Bugzilla::Webservice =head1 DESCRIPTION Provides methods for automated scripts to manipulate Testopia TestCaseRuns. =head1 SYNOPSIS Test case-runs are the mapping of a test case in a given run for a particular build and environment. There are therefore two ways to refer to a given case-run: By ID: The unique case_run_id By Combination: $run_id, $case_id, $build_id, $environment_id TestCaseRun methods are therefore overloaded to support either of these two methods of looking up the case-run you are interested in. B TestCaseRun->get($caserun_id) TestCaseRun->get($run_id, $case_id, $build_id, $environment_id) =head1 METHODS =over =item C Description: Add one or more bugs to the selected test case-runs. Params: $case_run_id - Integer: An integer representing the ID in the database. $bug_ids - Integer/Array/String: An integer or alias representing the ID in the database, an array of bug_ids or aliases, or a string of comma separated bug_ids. Returns: undef. =item C Description: Add one or more bugs to the selected test case-runs. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. $bug_ids - Integer/Array/String: An integer or alias representing the ID in the database, an array of bug_ids or aliases, or a string of comma separated bug_ids. Returns: undef. =item C Description: Creates a new Test Case Run object and stores it in the database. Params: $values - Hash: A reference to a hash with keys and values matching the fields of the test case to be created. +--------------------+----------------+-----------+------------------------------------------------+ | Field | Type | Null | Description | +--------------------+----------------+-----------+------------------------------------------------+ | run_id | Integer | Required | Test Run Number | | case_id | Integer/String | Required | ID or alias of test case | | build | Integer/String | Required | ID or name of a Build in plan's product | | environment | Integer/String | Required | ID or name of an Environment in plan's product | | assignee | Integer/String | Optional | Defaults to test case default tester | | status | String | Optional | Defaults to "IDLE" | | case_text_version | Integer | Optional | | | notes | String | Optional | | | sortkey | Integer | Optional | a.k.a. Index | +--------------------+----------------+-----------+------------------------------------------------+ Valid statuses include: IDLE, PASSED, FAILED, RUNNING, PAUSED, BLOCKED Returns: The newly created object hash. =item C Description: Remove a bug from a test case-run. Params: $caserun_id - Integer: An integer representing the ID in the database. $bug_ids - Integer/Array/String: An integer or alias representing the ID in the database, an array of bug_ids or aliases, or a string of comma separated bug_ids. Returns: undef. =item C Description: Remove a bug from a test case-run. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. $bug_id - Integer: An integer or alias representing the ID of the bug in the database, Returns: undef. =item C Description: Used to load an existing test case-run from the database. Params: $caserun_id - Integer: An integer representing the ID in the database for this case-run. Returns: A blessed Bugzilla::Testopia::TestCase object hash =item C Description: Used to load an existing test case from the database. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. Returns: A blessed Bugzilla::Testopia::TestCase object hash =item C Description: Get the list of bugs that are associated with this test case. Params: $caserun_id - Integer: An integer representing the ID in the database for this case-run. Returns: Array: An array of bug object hashes. =item C Description: Get the list of bugs that are associated with this test case. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. Returns: Array: An array of bug object hashes. =item C Description: Get the list of components attached to this case. Params: $caserun_id - Integer: An integer representing the ID in the database for this case-run. Returns: Array: An array of component object hashes. =item C Description: Get the list of components attached to this case. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. Returns: Array: An array of component object hashes. =item C Description: Get the list of case-runs for all runs this case appears in. To limit this list by build or other attribute, see TestCaseRun::list. Params: $caserun_id - Integer: An integer representing the ID in the database for this case-run. Returns: Array: An array of case-run object hashes. =item C Description: Get the list of case-runs for all runs this case appears in. To limit this list by build or other attribute, see TestCaseRun::list. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. Returns: Array: An array of case-run object hashes. =item C Description: Performs a search and returns the resulting list of test cases. Params: $query - Hash: keys must match valid search fields. +--------------------------------------------------------+ | Case-Run Search Parameters | +--------------------------------------------------------+ | Key | Valid Values | | andor | 1: Author AND tester, 0: OR | | assignee | A bugzilla login (email address) | | assignee_type | (select from email_variants) | | build | String | | build_id | Integer | | case_id | comma separated integers | | case_run_status | String: Status | | case_run_status_id | Integer: Status | | case_summary | String: Requirement | | case_summary_type | (select from query_variants) | | category | String: Category Name | | category_id | Integer | | component | String: Component Name | | environment | String | | environment_id | Integer | | isactive | 0: Only show current 1: show all | | isautomated | 1: true 0: false | | milestone | String | | notes | String | | notes_type | (select from query_variants) | | plan_id | comma separated integers | | priority | String: Priority | | priority_id | Integer | | product | String | | product_id | Integer | | requirement | String: Requirement | | requirement_type | (select from query_variants) | | run_id | comma separated integers | | run_product_version | String | | run_status | 1: RUNNING 0: STOPPED | | tags | String | | tags_type | (select from tag_variants) | | testedby | A bugzilla login (email address) | | testedby_type | (select from email_variants) | +--------------------------------------------------------+ +---------------------------------------------------+ | Paging and Sorting | +---------------------------------------------------+ | Key | Description | | dir | "ASC" or "DESC" | | order | field to sort by | +---------------------------------------------------+ | page_size | integer: how many per page | | page | integer: page number | | +++++++ OR +++++++ | | start | integer: Start with which record | | limit | integer: limit to how many | +---------------------------------------------------+ | viewall | 1: returns all records | +---------------------------------------------------+ +----------------------------------------------------+ | query_variants | +----------------+-----------------------------------+ | Key | Description | | allwordssubstr | contains all of the words/strings | | anywordssubstr | contains any of the words/strings | | substring | contains the string | | casesubstring | contains the string (exact case) | | allwords | contains all of the words | | anywords | contains any of the words | | regexp | matches the regexp | | notregexp | doesn't match the regexp | +----------------+-----------------------------------+ +-------------------------------------+ | email_variants | +--------------+----------------------+ | Key | Description | | substring | contains | | exact | is | | regexp | matches regexp | | notregexp | doesn't match regexp | +--------------+----------------------+ +----------------------------------------------------+ | tag_variants | +----------------+-----------------------------------+ | Key | Description | | anyexact | is tagged with | | allwordssubstr | contains all of the words/strings | | anywordssubstr | contains any of the words/strings | | substring | contains the string | | casesubstring | contains the string (exact case) | | regexp | matches the regexp | | notregexp | doesn't match the regexp | | allwords | contains all of the words | | anywords | contains any of the words | | nowords | contains none of the words | +----------------------------------------------------+ Returns: Array: Matching test cases are retuned in a list of hashes. =item C Params: $id - Integer: ID of the case status to return Returns: String: the status name. =item C Params: $name - String: the status name. Returns: Integer: ID of the case status. =item C Description: Updates the fields of the selected case-runs. Params: $caserun_ids - Integer/String/Array Integer: A single TestCaseRun ID. String: A comma separates string of TestCaseRun IDs for batch processing. Array: An array of TestCaseRun IDs for batch mode processing $values - Hash of keys matching TestCaseRun fields and the new values to set each field to. +--------------------+----------------+ | Field | Type | +--------------------+----------------+ | build | Integer/String | | environment | Integer/String | | assignee | Integer/String | | status | String | | notes | String | | sortkey | Integer | | update_bugs | Boolean | 1: Reopen bugs on FAILED 0: Don't change bug status +--------------------+----------------+ Returns: Hash/Array: In the case of a single object, it is returned. If a list was passed, it returns an array of object hashes. If the update on any particular object failed, the hash will contain a ERROR key and the message as to why it failed. =item C Description: Updates the fields of the selected case-run. Params: $case_id - Integer: An integer representing the ID of the test case in the database. $run_id - Integer: An integer representing the ID of the test run in the database. $build_id - Integer: An integer representing the ID of the test build in the database. $environment_id - Integer: An integer representing the ID of the environment in the database. $values - Hash of keys matching TestCaseRun fields and the new values to set each field to. See above. Returns: Hash/Array: In the case of a single object, it is returned. If a list was passed, it returns an array of object hashes. If the update on any particular object failed, the hash will contain a ERROR key and the message as to why it failed. =back =head1 SEE ALSO L L =head1 AUTHOR Greg Hendricks