diff options
87 files changed, 13515 insertions, 11 deletions
diff --git a/docker/runtests.sh b/docker/runtests.sh index 3142056ff..b74359b04 100755 --- a/docker/runtests.sh +++ b/docker/runtests.sh @@ -39,11 +39,6 @@ if [ "$TEST_SUITE" = "docs" ]; then exit $? fi -echo -e "\n== Cloning QA test suite" -cd $BUGZILLA_ROOT -echo "Cloning git repo $GITHUB_QA_GIT branch $GITHUB_BASE_BRANCH ..." -git clone $GITHUB_QA_GIT -b $GITHUB_BASE_BRANCH qa - echo -e "\n== Starting database" /usr/bin/mysqld_safe & sleep 3 @@ -54,10 +49,10 @@ sleep 3 echo -e "\n== Updating configuration" mysql -u root mysql -e "CREATE DATABASE bugs_test CHARACTER SET = 'utf8';" -sed -e "s?%DB%?$BUGS_DB_DRIVER?g" --in-place qa/config/checksetup_answers.txt -sed -e "s?%DB_NAME%?bugs_test?g" --in-place qa/config/checksetup_answers.txt -sed -e "s?%USER%?$BUGZILLA_USER?g" --in-place qa/config/checksetup_answers.txt -echo "\$answer{'memcached_servers'} = 'localhost:11211';" >> qa/config/checksetup_answers.txt +sed -e "s?%DB%?$BUGS_DB_DRIVER?g" --in-place $BUGZILLA_ROOT/qa/config/checksetup_answers.txt +sed -e "s?%DB_NAME%?bugs_test?g" --in-place $BUGZILLA_ROOT/qa/config/checksetup_answers.txt +sed -e "s?%USER%?$BUGZILLA_USER?g" --in-place $BUGZILLA_ROOT/qa/config/checksetup_answers.txt +echo "\$answer{'memcached_servers'} = 'localhost:11211';" >> $BUGZILLA_ROOT/qa/config/checksetup_answers.txt if [ "$TEST_SUITE" == "checksetup" ]; then cd $BUGZILLA_ROOT/qa diff --git a/qa/config/checksetup_answers.txt b/qa/config/checksetup_answers.txt new file mode 100644 index 000000000..adafe8c43 --- /dev/null +++ b/qa/config/checksetup_answers.txt @@ -0,0 +1,26 @@ +$answer{'ADMIN_EMAIL'} = 'admin@mozilla.bugs'; +$answer{'ADMIN_OK'} = 'Y'; +$answer{'ADMIN_PASSWORD'} = 'password'; +$answer{'ADMIN_REALNAME'} = 'QA Admin'; +$answer{'NO_PAUSE'} = 1; +$answer{'bugzilla_version'} = '1'; +$answer{'create_htaccess'} = ''; +$answer{'cvsbin'} = '/usr/bin/cvs'; +$answer{'db_check'} = 1; +$answer{'db_driver'} = '%DB%'; +$answer{'db_host'} = 'localhost'; +$answer{'db_mysql_ssl_ca_file'} = ''; +$answer{'db_mysql_ssl_ca_path'} = ''; +$answer{'db_mysql_ssl_client_cert'} = ''; +$answer{'db_mysql_ssl_client_key'} = ''; +$answer{'db_name'} = '%DB_NAME%', +$answer{'db_pass'} = 'bugs'; +$answer{'db_port'} = 0; +$answer{'db_sock'} = ''; +$answer{'db_user'} = 'bugs'; +$answer{'diffpath'} = '/usr/bin'; +$answer{'index_html'} = 0; +$answer{'interdiffbin'} = '/usr/bin/interdiff'; +$answer{'urlbase'} = 'http://localhost/bmo/'; +$answer{'use_suexec'} = ''; +$answer{'webservergroup'} = '%USER%'; diff --git a/qa/config/generate_test_data.pl b/qa/config/generate_test_data.pl new file mode 100644 index 000000000..2c6afe03a --- /dev/null +++ b/qa/config/generate_test_data.pl @@ -0,0 +1,822 @@ +#!/usr/bin/perl -w + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +use strict; +use warnings; + +use Cwd; +use File::Copy::Recursive qw(dircopy); + +my $conf_path; +my $config; + +BEGIN { + print "reading the config file...\n"; + my $conf_file = "selenium_test.conf"; + if (@ARGV) { + $conf_file = shift @ARGV; + } + $config = do "$conf_file" + or die "can't read configuration '$conf_file': $!$@"; + + $conf_path = $config->{bugzilla_path}; +} + +use lib $conf_path; + +use Bugzilla; +use Bugzilla::Attachment; +use Bugzilla::Bug; +use Bugzilla::User; +use Bugzilla::Install; +use Bugzilla::Milestone; +use Bugzilla::Product; +use Bugzilla::Component; +use Bugzilla::Group; +use Bugzilla::Version; +use Bugzilla::Constants; +use Bugzilla::Keyword; +use Bugzilla::Config qw(:admin); +use Bugzilla::User::Setting; +use Bugzilla::Util qw(generate_random_password); + +my $dbh = Bugzilla->dbh; + +# set Bugzilla usage mode to USAGE_MODE_CMDLINE +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +########################################################################## +# Set Parameters +########################################################################## + +# Some parameters must be turned on to create bugs requiring them. +# They are also expected to be turned on by some webservice_*.t scripts. +my ($urlbase, $sslbase); +$urlbase = $config->{browser_url} . '/' . $config->{bugzilla_installation}; +$urlbase .= '/' unless $urlbase =~ /\/$/; + +if ($urlbase =~ /^https/) { + $sslbase = $urlbase; + $urlbase =~ s/^https(.+)$/http$1/; +} + +# Create missing priorities +# BMO uses P1-P5 which is different from upstream +my $field = Bugzilla::Field->new({ name => 'priority' }); +foreach my $value (qw(Highest High Normal Low Lowest)) { +# Bugzilla::Field::Choice->type($field)->create({ +# value => $value, +# sortkey => 0 +# }); +} + +# Add missing platforms +$field = Bugzilla::Field->new({ name => 'rep_platform' }); +foreach my $value (qw(PC)) { +# Bugzilla::Field::Choice->type($field)->create({ +# value => $value, +# sortkey => 0 +# }); +} + +my %set_params = ( + urlbase => $urlbase, + sslbase => $sslbase, + usebugaliases => 1, + useqacontact => 1, + mail_delivery_method => 'Test', + maxattachmentsize => 256, + defaultpriority => 'Highest', # BMO CHANGE + timetrackinggroup => 'editbugs', # BMO CHANGE + letsubmitterchoosepriority => 1, # BMO CHANGE + createemailregexp => '.*', # BMO CHANGE +); + +my $params_modified; +foreach my $param (keys %set_params) { + my $value = $set_params{$param}; + next unless defined $value && Bugzilla->params->{$param} ne $value; + SetParam($param, $value); + $params_modified = 1; +} + +write_params() if $params_modified; + +########################################################################## +# Set Default User Preferences +########################################################################## + +# When editing a bug, the page being displayed depends on the +# post_bug_submit_action user pref. We set it globally so that we know +# the exact behavior of process_bug.cgi. +my %user_prefs = (post_bug_submit_action => 'nothing'); + +foreach my $pref (keys %user_prefs) { + my $value = $user_prefs{$pref}; + Bugzilla::User::Setting::set_default($pref, $value, 0); +} + +########################################################################## +# Create Users +########################################################################## +# First of all, remove the default .* regexp for the editbugs group. +my $group = new Bugzilla::Group({ name => 'editbugs' }); +$group->set_user_regexp(''); +$group->update(); + +my @usernames = ( + 'admin', 'no-privs', + 'QA-Selenium-TEST', 'canconfirm', + 'tweakparams', 'permanent_user', + 'editbugs', 'disabled', +); + +print "creating user accounts...\n"; +foreach my $username (@usernames) { + + my $password; + my $login; + my $realname = exists $config->{"$username" . "_user_username"} + ? $config->{"$username" . "_user_username"} + : $username; + + if ($username eq 'permanent_user') { + $password = $config->{admin_user_passwd}; + $login = $config->{$username}; + } + elsif ($username eq 'no-privs') { + $password = $config->{unprivileged_user_passwd}; + $login = $config->{unprivileged_user_login}; + } + elsif ($username eq 'QA-Selenium-TEST') { + $password = $config->{QA_Selenium_TEST_user_passwd}; + $login = $config->{QA_Selenium_TEST_user_login}; + } + else { + $password = $config->{"$username" . "_user_passwd"}; + $login = $config->{"$username" . "_user_login"}; + } + + if ( is_available_username($login) ) { + my %extra_args; + if ($username eq 'disabled') { + $extra_args{disabledtext} = '!!This is the text!!'; + } + + Bugzilla::User->create( + { login_name => $login, + realname => $realname, + cryptpassword => $password, + %extra_args, + } + ); + + if ( $username eq 'admin' or $username eq 'permanent_user' ) { + + Bugzilla::Install::make_admin($login); + } + } +} + +########################################################################## +# Bug statuses +########################################################################## + +# We need to add in the upstream statuses in addition to the BMO ones. + +my @statuses = ( + { + value => undef, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['NEW', 0], + ['ASSIGNED', 0], ['IN_PROGRESS', 0]], + }, + { + value => 'UNCONFIRMED', + sortkey => 100, + isactive => 1, + isopen => 1, + transitions => [['CONFIRMED', 0], ['NEW', 0], ['ASSIGNED', 0], + ['IN_PROGRESS', 0], ['RESOLVED', 0]], + }, + { + value => 'CONFIRMED', + sortkey => 200, + isactive => 1, + isopen => 1, + transitions => [['UNCONFIRMED', 0], ['NEW', 0], ['ASSIGNED', 0], + ['IN_PROGRESS', 0], ['RESOLVED', 0]], + }, + { + value => 'NEW', + sortkey => 300, + isactive => 1, + isopen => 1, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['ASSIGNED', 0], + ['IN_PROGRESS', 0], ['RESOLVED', 0]], + }, + { + value => 'ASSIGNED', + sortkey => 400, + isactive => 1, + isopen => 1, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['NEW', 0], + ['IN_PROGRESS', 0], ['RESOLVED', 0]], + }, + { + value => 'IN_PROGRESS', + sortkey => 500, + isactive => 1, + isopen => 1, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['NEW', 0], + ['ASSIGNED', 0], ['RESOLVED', 0]], + }, + { + value => 'REOPENED', + sortkey => 600, + isactive => 1, + isopen => 1, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['NEW', 0], + ['ASSIGNED', 0], ['IN_PROGRESS', 0], ['RESOLVED', 0]], + }, + { + value => 'RESOLVED', + sortkey => 700, + isactive => 1, + isopen => 0, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['REOPENED', 0], + ['VERIFIED', 0]], + }, + { + value => 'VERIFIED', + sortkey => 800, + isactive => 1, + isopen => 0, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['REOPENED', 0], + ['RESOLVED', 0]], + }, + { + value => 'CLOSED', + sortkey => 900, + isactive => 1, + isopen => 0, + transitions => [['UNCONFIRMED', 0], ['CONFIRMED', 0], ['REOPENED', 0], + ['RESOLVED', 0]], + }, +); + +if ($dbh->selectrow_array("SELECT 1 FROM bug_status WHERE value = 'ASSIGNED'")) { + $dbh->do('DELETE FROM bug_status'); + $dbh->do('DELETE FROM status_workflow'); + + print "creating status workflow...\n"; + + # One pass to add the status entries. + foreach my $status (@statuses) { + next if !$status->{value}; + $dbh->do('INSERT INTO bug_status (value, sortkey, isactive, is_open) VALUES (?, ?, ?, ?)', + undef, ( $status->{value}, $status->{sortkey}, $status->{isactive}, $status->{isopen} )); + } + + # Another pass to add the transitions. + foreach my $status (@statuses) { + my $old_id; + if ($status->{value}) { + my $from_status = new Bugzilla::Status({ name => $status->{value} }); + $old_id = $from_status->{id}; + } else { + $old_id = undef; + } + + foreach my $transition (@{$status->{transitions}}) { + my $to_status = new Bugzilla::Status({ name => $transition->[0] }); + + $dbh->do('INSERT INTO status_workflow (old_status, new_status, require_comment) VALUES (?, ?, ?)', + undef, ( $old_id, $to_status->{id}, $transition->[1] )); + } + } +} + +########################################################################## +# Create Bugs +########################################################################## + +# login to bugzilla +my $admin_user = Bugzilla::User->check($config->{admin_user_login}); +Bugzilla->set_user($admin_user); + +my %field_values = ( + 'priority' => 'Highest', + 'bug_status' => 'CONFIRMED', + 'version' => 'unspecified', + 'bug_file_loc' => '', + 'comment' => 'please ignore this bug', + 'component' => 'TestComponent', + 'rep_platform' => 'All', + 'short_desc' => 'This is a testing bug only', + 'product' => 'TestProduct', + 'op_sys' => 'Linux', + 'bug_severity' => 'normal', + 'groups' => [], +); + +print "creating bugs...\n"; +Bugzilla::Bug->create( \%field_values ); +if (Bugzilla::Bug->new('public_bug')->{error}) { + # The deadline must be set so that this bug can be used to test + # timetracking fields using WebServices. + Bugzilla::Bug->create({ %field_values, alias => 'public_bug', deadline => '2010-01-01' }); +} + +########################################################################## +# Create Classifications +########################################################################## +my @classifications = ({ name => "Class2_QA", + description => "required by Selenium... DON'T DELETE" }, +); + +print "creating classifications...\n"; +foreach my $class (@classifications) { + my $new_class = Bugzilla::Classification->new({ name => $class->{name} }); + if (!$new_class) { + $dbh->do('INSERT INTO classifications (name, description) VALUES (?, ?)', + undef, ( $class->{name}, $class->{description} )); + } +} +########################################################################## +# Create Products +########################################################################## +my $default_platform_id = $dbh->selectcol_arrayref("SELECT id FROM rep_platform WHERE value = 'Unspecified'"); +my $default_op_sys_id = $dbh->selectcol_arrayref("SELECT id FROM op_sys WHERE value = 'Unspecified'"); + +my @products = ( + { product_name => 'QA-Selenium-TEST', + description => "used by Selenium test.. DON'T DELETE", + versions => ['unspecified', 'QAVersion'], + milestones => ['QAMilestone'], + defaultmilestone => '---', + components => [ + { name => "QA-Selenium-TEST", + description => "used by Selenium test.. DON'T DELETE", + initialowner => $config->{QA_Selenium_TEST_user_login}, + initialqacontact => $config->{QA_Selenium_TEST_user_login}, + initial_cc => [$config->{QA_Selenium_TEST_user_login}], + + } + ], + default_platform_id => $default_platform_id, + default_op_sys_id => $default_op_sys_id, + }, + + { product_name => 'Another Product', + description => + "Alternate product used by Selenium. <b>Do not edit!</b>", + versions => ['unspecified', 'Another1', 'Another2'], + milestones => ['AnotherMS1', 'AnotherMS2', 'Milestone'], + defaultmilestone => '---', + + components => [ + { name => "c1", + description => "c1", + initialowner => $config->{permanent_user}, + initialqacontact => '', + initial_cc => [], + + }, + { name => "c2", + description => "c2", + initialowner => $config->{permanent_user}, + initialqacontact => '', + initial_cc => [], + + }, + ], + default_platform_id => $default_platform_id, + default_op_sys_id => $default_op_sys_id, + }, + + { product_name => 'C2 Forever', + description => 'I must remain in the Class2_QA classification ' . + 'in all cases! Do not edit!', + classification => 'Class2_QA', + versions => ['unspecified', 'C2Ver'], + milestones => ['C2Mil'], + defaultmilestone => '---', + components => [ + { name => "Helium", + description => "Feel free to add bugs to me", + initialowner => $config->{permanent_user}, + initialqacontact => '', + initial_cc => [], + + } + ], + default_platform_id => $default_platform_id, + default_op_sys_id => $default_op_sys_id, + }, + + { product_name => 'QA Entry Only', + description => 'Only the QA group may enter bugs here.', + versions => ['unspecified'], + milestones => [], + defaultmilestone => '---', + components => [ + { name => "c1", + description => "Same name as Another Product's component", + initialowner => $config->{QA_Selenium_TEST_user_login}, + initialqacontact => '', + initial_cc => [], + } + ], + default_platform_id => $default_platform_id, + default_op_sys_id => $default_op_sys_id, + }, + + { product_name => 'QA Search Only', + description => 'Only the QA group may search for bugs here.', + versions => ['unspecified'], + milestones => [], + defaultmilestone => '---', + components => [ + { name => "c1", + description => "Still same name as the Another component", + initialowner => $config->{QA_Selenium_TEST_user_login}, + initialqacontact => '', + initial_cc => [], + } + ], + default_platform_id => $default_platform_id, + default_op_sys_id => $default_op_sys_id, + }, +); + +print "creating products...\n"; +foreach my $product (@products) { + my $new_product = + Bugzilla::Product->new({ name => $product->{product_name} }); + if (!$new_product) { + my $class_id = 1; + if ($product->{classification}) { + $class_id = Bugzilla::Classification->new({ name => $product->{classification} })->id; + } + $dbh->do('INSERT INTO products (name, description, classification_id, default_platform_id, default_op_sys_id) + VALUES (?, ?, ?, ?, ?)', + undef, ( $product->{product_name}, $product->{description}, $class_id, + $new_product->{default_platform_id}, $new_product->{default_op_sys_id} )); + + $new_product + = new Bugzilla::Product( { name => $product->{product_name} } ); + + $dbh->do( 'INSERT INTO milestones (product_id, value) VALUES (?, ?)', + undef, ( $new_product->id, $product->{defaultmilestone} ) ); + + # Now clear the internal list of accessible products. + delete Bugzilla->user->{selectable_products}; + + foreach my $component ( @{ $product->{components} } ) { + # BMO Change for ComponentWatching extension + my $watch_user = lc($component->{name}) . '@' . lc($new_product->name) . '.bugs'; + $watch_user =~ s/\s+/\-/g; + + Bugzilla::User->create({ + login_name => $watch_user, + cryptpassword => generate_random_password(), + disable_mail => 1, + }); + + my %params = %{ Bugzilla->input_params }; + $params{watch_user} = $watch_user; + Bugzilla->input_params(\%params); + + Bugzilla::Component->create( + { name => $component->{name}, + product => $new_product, + description => $component->{description}, + initialowner => $component->{initialowner}, + initialqacontact => $component->{initialqacontact}, + initial_cc => $component->{initial_cc}, + } + ); + } + } + + foreach my $version (@{ $product->{versions} }) { + if (!new Bugzilla::Version({ name => $version, + product => $new_product })) + { + Bugzilla::Version->create({value => $version, product => $new_product}); + } + } + + foreach my $milestone (@{ $product->{milestones} }) { + if (!new Bugzilla::Milestone({ name => $milestone, + product => $new_product })) + { + # We don't use Bugzilla::Milestone->create because we want to + # bypass security checks. + $dbh->do('INSERT INTO milestones (product_id, value) VALUES (?,?)', + undef, $new_product->id, $milestone); + } + } +} + +########################################################################## +# Create Groups +########################################################################## +# create Master group +my ( $group_name, $group_desc ) + = ( "Master", "Master Selenium Group <b>DO NOT EDIT!</b>" ); + +print "creating groups...\n"; +if ( !Bugzilla::Group->new( { name => $group_name } ) ) { + my $group = Bugzilla::Group->create({ name => $group_name, + description => $group_desc, + isbuggroup => 1}); + + $dbh->do('INSERT INTO group_control_map + (group_id, product_id, entry, membercontrol, othercontrol, canedit) + SELECT ?, products.id, 0, ?, ?, 0 FROM products', + undef, ( $group->id, CONTROLMAPSHOWN, CONTROLMAPSHOWN ) ); +} + +# create QA-Selenium-TEST group. Do not use Group->create() so that +# the admin group doesn't inherit membership (yes, that's what we want!). +( $group_name, $group_desc ) + = ( "QA-Selenium-TEST", "used by Selenium test.. DON'T DELETE" ); + +if ( !Bugzilla::Group->new( { name => $group_name } ) ) { + $dbh->do('INSERT INTO groups (name, description, isbuggroup, isactive) + VALUES (?, ?, 1, 1)', undef, ( $group_name, $group_desc ) ); +} + +# BMO 'editbugs' is also a member of 'canconfirm' +my $editbugs = Bugzilla::Group->new({ name => 'editbugs' }); +my $canconfirm = Bugzilla::Group->new({ name => 'canconfirm' }); +$dbh->do('INSERT INTO group_group_map VALUES (?, ?, 0)', + undef, $editbugs->id, $canconfirm->id); + +########################################################################## +# Add Users to Groups +########################################################################## +my @users_groups = ( + { user => $config->{QA_Selenium_TEST_user_login}, group => 'QA-Selenium-TEST' }, + { user => $config->{tweakparams_user_login}, group => 'tweakparams' }, + { user => $config->{canconfirm_user_login}, group => 'canconfirm' }, + { user => $config->{editbugs_user_login}, group => 'editbugs' }, +); + +print "adding users to groups...\n"; +foreach my $user_group (@users_groups) { + + my $group = new Bugzilla::Group( { name => $user_group->{group} } ); + my $user = new Bugzilla::User( { name => $user_group->{user} } ); + + my $sth_add_mapping = $dbh->prepare( + qq{INSERT INTO user_group_map (user_id, group_id, isbless, grant_type) + VALUES (?, ?, ?, ?)}); + # Don't crash if the entry already exists. + eval { + $sth_add_mapping->execute( $user->id, $group->id, 0, GRANT_DIRECT ); + }; +} + +########################################################################## +# Associate Products with groups +########################################################################## +# Associate the QA-Selenium-TEST group with the QA-Selenium-TEST. +my $created_group = new Bugzilla::Group( { name => 'QA-Selenium-TEST' } ); +my $secret_product = new Bugzilla::Product( { name => 'QA-Selenium-TEST' } ); +my $no_entry = new Bugzilla::Product({ name => 'QA Entry Only' }); +my $no_search = new Bugzilla::Product({ name => 'QA Search Only' }); + +print "restricting products to groups...\n"; +# Don't crash if the entries already exist. +my $sth = $dbh->prepare('INSERT INTO group_control_map + (group_id, product_id, entry, membercontrol, othercontrol, canedit) + VALUES (?, ?, ?, ?, ?, ?)'); +eval { + $sth->execute($created_group->id, $secret_product->id, 1, CONTROLMAPMANDATORY, + CONTROLMAPMANDATORY, 0); +}; +eval { + $sth->execute($created_group->id, $no_entry->id, 1, CONTROLMAPNA, CONTROLMAPNA, 0); +}; +eval { + $sth->execute($created_group->id, $no_search->id, 0, CONTROLMAPMANDATORY, + CONTROLMAPMANDATORY, 0); +}; + +########################################################################## +# Create flag types +########################################################################## +my @flagtypes = ( + {name => 'spec_multi_flag', desc => 'Specifically requestable and multiplicable bug flag', + is_requestable => 1, is_requesteeble => 1, is_multiplicable => 1, grant_group => 'editbugs', + target_type => 'b', cc_list => '', inclusions => ['Another Product:c1']}, +); + +print "creating flag types...\n"; +foreach my $flag (@flagtypes) { + # The name is not unique, even within a single product/component, so there is NO WAY + # to know if the existing flag type is the one we want or not. + # As our Selenium scripts would be confused anyway if there is already such a flag name, + # we simply skip it and assume the existing flag type is the one we want. + next if new Bugzilla::FlagType({ name => $flag->{name} }); + + my $grant_group_id = $flag->{grant_group} ? Bugzilla::Group->new({ name => $flag->{grant_group} })->id : undef; + my $request_group_id = $flag->{request_group} ? Bugzilla::Group->new({ name => $flag->{request_group} })->id : undef; + + $dbh->do('INSERT INTO flagtypes (name, description, cc_list, target_type, is_requestable, + is_requesteeble, is_multiplicable, grant_group_id, request_group_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', + undef, ($flag->{name}, $flag->{desc}, $flag->{cc_list}, $flag->{target_type}, + $flag->{is_requestable}, $flag->{is_requesteeble}, $flag->{is_multiplicable}, + $grant_group_id, $request_group_id)); + + my $type_id = $dbh->bz_last_key('flagtypes', 'id'); + + foreach my $inclusion (@{$flag->{inclusions}}) { + my ($product, $component) = split(':', $inclusion); + my ($prod_id, $comp_id); + if ($product) { + my $prod_obj = Bugzilla::Product->new({ name => $product }); + $prod_id = $prod_obj->id; + if ($component) { + $comp_id = Bugzilla::Component->new({ name => $component, product => $prod_obj})->id; + } + } + $dbh->do('INSERT INTO flaginclusions (type_id, product_id, component_id) + VALUES (?, ?, ?)', + undef, ($type_id, $prod_id, $comp_id)); + } +} + +########################################################################## +# Create custom fields +########################################################################## +my @fields = ( + { name => 'cf_QA_status', + description => 'QA Status', + type => FIELD_TYPE_MULTI_SELECT, + sortkey => 100, + mailhead => 0, + enter_bug => 1, + obsolete => 0, + custom => 1, + values => ['verified', 'in progress', 'untested'] + }, + { name => 'cf_single_select', + description => 'SingSel', + type => FIELD_TYPE_SINGLE_SELECT, + sortkey => 200, + mailhead => 0, + enter_bug => 1, + custom => 1, + obsolete => 0, + values => [qw(one two three)], + }, +); + +print "creating custom fields...\n"; +foreach my $f (@fields) { + # Skip existing custom fields. + next if Bugzilla::Field->new({ name => $f->{name} }); + + my @values; + if (exists $f->{values}) { + @values = @{$f->{values}}; + # We have to delete this key, else create() will complain + # that 'values' is not an existing column name. + delete $f->{values}; + } + Bugzilla::Field->create($f); + my $field = Bugzilla::Field->new({ name => $f->{name} }); + + # Now populate the table with valid values, if necessary. + next unless scalar @values; + + my $sth = $dbh->prepare('INSERT INTO ' . $field->name . ' (value) VALUES (?)'); + foreach my $value (@values) { + $sth->execute($value); + } +} + +#################################################################### +# Set Parameters That Require Other Things To Have Been Done First # +#################################################################### + +if (Bugzilla->params->{insidergroup} ne 'QA-Selenium-TEST') { + SetParam('insidergroup', 'QA-Selenium-TEST'); + $params_modified = 1; +} + +if ($params_modified) { + write_params(); + print <<EOT +** Parameters have been modified by this script. Please re-run +** checksetup.pl to set file permissions on data/params correctly. + +EOT +} + +######################## +# Create a Private Bug # +######################## + +my $test_user = Bugzilla::User->check($config->{QA_Selenium_TEST_user_login}); +Bugzilla->set_user($test_user); + +print "Creating private bug(s)...\n"; +if (Bugzilla::Bug->new('private_bug')->{error}) { + my %priv_values = %field_values; + $priv_values{alias} = 'private_bug'; + $priv_values{product} = 'QA-Selenium-TEST'; + $priv_values{component} = 'QA-Selenium-TEST'; + my $bug = Bugzilla::Bug->create(\%priv_values); +} + +###################### +# Create Attachments # +###################### + +# BMO FIXME: Users must be in 'editbugs' to set their own +# content type other than text/plain or application/octet-stream +$group = new Bugzilla::Group( { name => 'editbugs' } ); +my $sth_add_mapping = $dbh->prepare( + qq{INSERT INTO user_group_map (user_id, group_id, isbless, grant_type) + VALUES (?, ?, ?, ?)}); +# Don't crash if the entry already exists. +eval { + $sth_add_mapping->execute( Bugzilla->user->id, $group->id, 0, GRANT_DIRECT ); +}; + +print "creating attachments...\n"; + +# We use the contents of this script as the attachment. +open(my $attachment_fh, '<', __FILE__) or die __FILE__ . ": $!"; + +my $attachment_contents; +{ local $/; $attachment_contents = <$attachment_fh>; } + +close($attachment_fh); + +foreach my $alias (qw(public_bug private_bug)) { + my $bug = Bugzilla::Bug->new($alias); + foreach my $is_private (0, 1) { + Bugzilla::Attachment->create({ + bug => $bug, + data => $attachment_contents, + description => "${alias}_${is_private}", + filename => "${alias}_${is_private}.pl", + mimetype => 'application/x-perl', + isprivate => $is_private, + }); + } +} + +# BMO FIXME: Remove test user from 'editbugs' group +my $sth_remove_mapping = $dbh->prepare( + qq{DELETE FROM user_group_map WHERE user_id = ? + AND group_id = ? AND isbless = 0 AND grant_type = ?}); +# Don't crash if the entry already exists. +eval { + $sth_remove_mapping->execute( Bugzilla->user->id, $group->id, GRANT_DIRECT ); +}; + +################### +# Create Keywords # +################### + +my @keywords = ( + { name => 'test-keyword-1', + description => 'Created for Bugzilla QA Tests, Keyword 1' }, + { name => 'test-keyword-2', + description => 'Created for Bugzilla QA Tests, Keyword 2' }, +); + +print "creating keywords...\n"; +foreach my $kw (@keywords) { + next if new Bugzilla::Keyword({ name => $kw->{name} }); + Bugzilla::Keyword->create($kw); +} + +############################ +# Install the QA extension # +############################ + +print "copying the QA extension...\n"; +dircopy("$conf_path/qa/extensions/QA", "$conf_path/extensions/QA"); + +my $cwd = cwd(); +chdir($conf_path); +system("perl", "contrib/fixperms.pl"); +chdir($cwd); + +print "installation and configuration complete!\n"; diff --git a/qa/config/patch.diff b/qa/config/patch.diff new file mode 100644 index 000000000..d85ecbdfe --- /dev/null +++ b/qa/config/patch.diff @@ -0,0 +1,18 @@ +Index: Bugzilla/Config/MTA.pm +=================================================================== +RCS file: /cvsroot/mozilla/webtools/bugzilla/Bugzilla/Config/MTA.pm,v +retrieving revision 1.13 +diff -3 -p -u -r1.13 MTA.pm +--- Bugzilla/Config/MTA.pm 13 Nov 2006 23:32:28 -0000 1.13 ++++ Bugzilla/Config/MTA.pm 9 Dec 2006 12:19:44 -0000 +@@ -44,7 +44,9 @@ sub get_param_list { + { + name => 'mail_delivery_method', + type => 's', +- choices => [Email::Send->new()->all_mailers(), 'None'], ++ # Bugzilla is not ready yet to send mails to newsgroups, and 'IO' ++ # is of no use for now as we already have our own 'Test' mode. ++ choices => [grep {$_ ne 'NNTP' && $_ ne 'IO'} Email::Send->new()->all_mailers(), 'None'], + default => 'Sendmail', + checker => \&check_mail_delivery_method + }, diff --git a/qa/config/selenium_test.conf b/qa/config/selenium_test.conf new file mode 100644 index 000000000..896d332e9 --- /dev/null +++ b/qa/config/selenium_test.conf @@ -0,0 +1,49 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# To make this configuration file useful to you, you have to: +# - set the path and URL to your Bugzilla installation. +# - replace @mozilla.test by something more relevant to you, +# also what comes before @mozilla.test if you want/need to. +# - set passwords for each user accounts. + +{ 'browser' => '*firefox', + 'experimental_browser_launcher' => '*chrome', + 'host' => 'localhost', + 'port' => 4444, + 'browser_url' => 'http://localhost', + 'attachment_file' => '/home/bugzilla/devel/htdocs/1144485/qa/config/patch.diff', + 'bugzilla_installation' => '1144485', + 'bugzilla_path' => '/home/bugzilla/devel/htdocs/1144485', + 'test_bug_1' => 1, + 'test_bug_2' => 2, + 'admin_user_login' => 'admin@mozilla.test', + 'admin_user_passwd' => 'password', + 'admin_user_username' => 'QA Admin', + 'admin_user_nick' => 'admin', + 'permanent_user' => 'permanent_user@mozilla.test', + 'permanent_user_login' => 'permanent_user@mozilla.test', + 'permanent_user_passwd' => 'password', + 'unprivileged_user_login' => 'no-privs@mozilla.test', + 'unprivileged_user_passwd' => 'password', + 'unprivileged_user_username' => 'no-privs', + 'unprivileged_user_nick' => 'no-privs', + 'unprivileged_user_login_truncated' => 'no-privs@mo', + 'QA_Selenium_TEST_user_login' => 'QA-Selenium-TEST@mozilla.test', + 'QA_Selenium_TEST_user_passwd' => 'password', + 'editbugs_user_login' => 'editbugs@mozilla.test', + 'editbugs_user_passwd' => 'password', + 'canconfirm_user_login' => 'canconfirm@mozilla.test', + 'canconfirm_user_passwd' => 'password', + 'tweakparams_user_login' => 'tweakparams@mozilla.test', + 'tweakparams_user_login_truncated' => 'tweakparams@mo', + 'tweakparams_user_passwd' => 'password', + 'disabled_user_login' => 'disabled@mozilla.test', + 'disabled_user_passwd' => 'password', + 'common_email' => '@mozilla.test', + 'test_extensions' => 1, +}; diff --git a/qa/extensions/QA/Config.pm b/qa/extensions/QA/Config.pm new file mode 100644 index 000000000..59799ec6b --- /dev/null +++ b/qa/extensions/QA/Config.pm @@ -0,0 +1,20 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::QA; + +use strict; + +use constant NAME => 'QA'; + +use constant REQUIRED_MODULES => [ +]; + +use constant OPTIONAL_MODULES => [ +]; + +__PACKAGE__->NAME; diff --git a/qa/extensions/QA/Extension.pm b/qa/extensions/QA/Extension.pm new file mode 100644 index 000000000..b5f404d74 --- /dev/null +++ b/qa/extensions/QA/Extension.pm @@ -0,0 +1,71 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::QA; + +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::Extension::QA::Util; +use Bugzilla::Constants; +use Bugzilla::Error; +use Bugzilla::Util; +use Bugzilla::Bug; +use Bugzilla::User; + +our $VERSION = '1.0'; + +sub page_before_template { + my ($self, $args) = @_; + return if $args->{page_id} ne 'qa/email_in.html'; + + my $template = Bugzilla->template; + my $cgi = Bugzilla->cgi; + print $cgi->header; + + # Needed to make sure he can access and edit bugs. + my $user = Bugzilla::User->check($cgi->param('sender')); + Bugzilla->set_user($user); + + my ($output, $tmpl_file); + my $action = $cgi->param('action') || ''; + my $vars = { sender => $user, action => $action, pid => $$ }; + + if ($action eq 'create') { + $tmpl_file = 'qa/create_bug.txt.tmpl'; + } + elsif ($action eq 'create_with_headers') { + $tmpl_file = 'qa/create_bug_with_headers.txt.tmpl'; + } + elsif ($action =~ /^update(_with_headers)?$/) { + my $f = $1 || ''; + $tmpl_file = "qa/update_bug$f.txt.tmpl"; + my $bug = Bugzilla::Bug->check($cgi->param('bug_id')); + $vars->{bug_id} = $bug->id; + } + else { + ThrowUserError('unknown_action', { action => $action }); + } + + $template->process($tmpl_file, $vars, \$output) + or ThrowTemplateError($template->error()); + + my $file = "/tmp/email_in_$$.txt"; + open(FH, '>', $file); + print FH $output; + close FH; + + $output = `email_in.pl -v < $file 2>&1`; + unlink $file; + + parse_output($output, $vars); + + $template->process('qa/results.html.tmpl', $vars) + or ThrowTemplateError($template->error()); +} + +__PACKAGE__->NAME; diff --git a/qa/extensions/QA/lib/Util.pm b/qa/extensions/QA/lib/Util.pm new file mode 100644 index 000000000..9bc2d8dbb --- /dev/null +++ b/qa/extensions/QA/lib/Util.pm @@ -0,0 +1,25 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::QA::Util; + +use strict; +use base qw(Exporter); + +our @EXPORT = qw( + parse_output +); + +sub parse_output { + my ($output, $vars) = @_; + + $vars->{error} = ($output =~ /software error/i) ? 1 : 0; + $vars->{output} = $output; + $vars->{bug_id} ||= ($output =~ /Created bug (\d+)/i) ? $1 : undef; +} + +1; diff --git a/qa/extensions/QA/template/en/default/pages/qa/email_in.html.tmpl b/qa/extensions/QA/template/en/default/pages/qa/email_in.html.tmpl new file mode 100644 index 000000000..bcb75107d --- /dev/null +++ b/qa/extensions/QA/template/en/default/pages/qa/email_in.html.tmpl @@ -0,0 +1,7 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] diff --git a/qa/extensions/QA/template/en/default/qa/create_bug.txt.tmpl b/qa/extensions/QA/template/en/default/qa/create_bug.txt.tmpl new file mode 100644 index 000000000..5a83a6c5b --- /dev/null +++ b/qa/extensions/QA/template/en/default/qa/create_bug.txt.tmpl @@ -0,0 +1,17 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +From: [% sender.email %] +Subject: [% terms.Bug %] created using email_in.pl +Content-Type: text/plain; charset="UTF-8" + +@product = TestProduct +@component = TestComponent +@version = unspecified + +This [% terms.bug %] has been created using email_in.pl (PID: [% pid %]). diff --git a/qa/extensions/QA/template/en/default/qa/create_bug_with_headers.txt.tmpl b/qa/extensions/QA/template/en/default/qa/create_bug_with_headers.txt.tmpl new file mode 100644 index 000000000..997378343 --- /dev/null +++ b/qa/extensions/QA/template/en/default/qa/create_bug_with_headers.txt.tmpl @@ -0,0 +1,33 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +From - Sat Jan 1 18:38:17 2011 +X-Account-Key: account2 +X-UIDL: GmailId12d42784d83cb4a4 +X-Mozilla-Status: 0011 +X-Mozilla-Status2: 00000000 +X-Mozilla-Keys: +Return-Path: <foo@bar.com> +Received: from [192.168.0.2] (provider.com [51.162.153.14]) + by mx.google.com with ESMTPS id m10sm12712256wbc.4.2011.01.01.09.38.01 + (version=TLSv1/SSLv3 cipher=RC4-MD5); + Sat, 01 Jan 2011 09:38:01 -0800 (PST) +Message-ID: <4D1F6580.9060076@gmail.com> +Date: Sat, 01 Jan 2011 18:38:08 +0100 +User-Agent: Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.13) Gecko/20101207 Lightning/1.0b2 Thunderbird/3.1.7 +MIME-Version: 1.0 +From: [% sender.email %] +Subject: [% terms.Bug %] created using email_in.pl (with email headers) +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: 8bit + +@product = TestProduct +@component = TestComponent +@version = unspecified + +This [% terms.bug %] has been created using email_in.pl (PID: [% pid %]) with email headers. diff --git a/qa/extensions/QA/template/en/default/qa/results.html.tmpl b/qa/extensions/QA/template/en/default/qa/results.html.tmpl new file mode 100644 index 000000000..a2f812697 --- /dev/null +++ b/qa/extensions/QA/template/en/default/qa/results.html.tmpl @@ -0,0 +1,28 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% title = BLOCK %] + [% IF error %] + Unexpected error + [% ELSE %] + email_in.pl output + [% END %] +[% END %] + +[% PROCESS global/header.html.tmpl %] + +<h1>Action '[% action FILTER html %]' successful</h1> + +<div> +<p>PID: <span id="pid">[% pid FILTER html %]</span></p> +<p>[%+ terms.Bug %] ID: <span id="bug_id">[% bug_id FILTER html %]</span></p> + +<p>Full output:</p> +<pre id="output">[% output FILTER html_light %]</pre> + +[% PROCESS global/footer.html.tmpl %] diff --git a/qa/extensions/QA/template/en/default/qa/update_bug.txt.tmpl b/qa/extensions/QA/template/en/default/qa/update_bug.txt.tmpl new file mode 100644 index 000000000..f37c00262 --- /dev/null +++ b/qa/extensions/QA/template/en/default/qa/update_bug.txt.tmpl @@ -0,0 +1,13 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +From: [% sender.email %] +Subject: [[% terms.Bug %] [%+ bug_id %]] This subject is ignored, only the [% terms.bug %] ID matters +Content-Type: text/plain; charset="UTF-8" + +Comment added by email_in.pl (PID: [% pid %]). No other changes. diff --git a/qa/extensions/QA/template/en/default/qa/update_bug_with_headers.txt.tmpl b/qa/extensions/QA/template/en/default/qa/update_bug_with_headers.txt.tmpl new file mode 100644 index 000000000..fd093d3b0 --- /dev/null +++ b/qa/extensions/QA/template/en/default/qa/update_bug_with_headers.txt.tmpl @@ -0,0 +1,29 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +From - Sat Jan 1 18:38:17 2011 +X-Account-Key: account2 +X-UIDL: GmailId12d42784d83cb4a4 +X-Mozilla-Status: 0011 +X-Mozilla-Status2: 00000000 +X-Mozilla-Keys: +Return-Path: <foo@bar.com> +Received: from [192.168.0.2] (provider.com [51.162.153.14]) + by mx.google.com with ESMTPS id m10sm12712256wbc.4.2011.01.01.09.38.01 + (version=TLSv1/SSLv3 cipher=RC4-MD5); + Sat, 01 Jan 2011 09:38:01 -0800 (PST) +Message-ID: <4D1F6580.9060076@gmail.com> +Date: Sat, 01 Jan 2011 18:38:08 +0100 +User-Agent: Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.13) Gecko/20101207 Lightning/1.0b2 Thunderbird/3.1.7 +MIME-Version: 1.0 +From: [% sender.email %] +Subject: [[% terms.Bug %] [%+ bug_id %]] This subject is ignored, only the [% terms.bug %] ID matters +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: 8bit + +Comment added by email_in.pl (PID: [% pid %]) with email headers. No other changes. diff --git a/qa/t/lib/QA/RPC.pm b/qa/t/lib/QA/RPC.pm new file mode 100644 index 000000000..4053c4dfe --- /dev/null +++ b/qa/t/lib/QA/RPC.pm @@ -0,0 +1,284 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +package QA::RPC; +use strict; +use Data::Dumper; +use QA::Util; +use QA::Tests qw(PRIVATE_BUG_USER create_bug_fields); +use Storable qw(dclone); +use Test::More; + +sub bz_config { + my $self = shift; + $self->{bz_config} ||= QA::Util::get_config(); + return $self->{bz_config}; +} + +# True if we're doing calls over GET instead of POST. +sub bz_get_mode { return 0 } + +# When doing bz_log_in over GET, we can't actually call User.login, +# we just store credentials here and then pass them as Bugzilla_login +# and Bugzilla_password with every future call until User.logout is called +# (which actually just calls _bz_clear_credentials, under GET). +sub _bz_credentials { + my ($self, $user, $pass) = @_; + if (@_ == 3) { + $self->{_bz_credentials}->{user} = $user; + $self->{_bz_credentials}->{pass} = $pass; + } + return $self->{_bz_credentials}; +} +sub _bz_clear_credentials { delete $_[0]->{_bz_credentials} } + +################################ +# Helpers for RPC test scripts # +################################ + +sub bz_log_in { + my ($self, $user) = @_; + my $username = $self->bz_config->{"${user}_user_login"}; + my $password = $self->bz_config->{"${user}_user_passwd"}; + + if ($self->bz_get_mode) { + $self->_bz_credentials($username, $password); + return; + } + + my $call = $self->bz_call_success( + 'User.login', { login => $username, password => $password }); + cmp_ok($call->result->{id}, 'gt', 0, $self->TYPE . ": Logged in as $user"); + $self->{_bz_credentials}->{token} = $call->result->{token}; +} + +sub bz_call_success { + my ($self, $method, $orig_args, $test_name) = @_; + my $args = $orig_args ? dclone($orig_args) : {}; + + if ($self->bz_get_mode and $method eq 'User.logout') { + $self->_bz_clear_credentials(); + return; + } + + my $call; + # Under XMLRPC::Lite, if we pass undef as the second argument, + # it sends a single param <value />, which shows up as an + # empty string on the Bugzilla side. + if ($self->{_bz_credentials}->{token}) { + $args->{Bugzilla_token} = $self->{_bz_credentials}->{token}; + } + + if (scalar keys %$args) { + $call = $self->call($method, $args); + } + else { + $call = $self->call($method); + } + $test_name ||= "$method returned successfully"; + $self->_handle_undef_response($test_name) if !$call; + ok(!$call->fault, $self->TYPE . ": $test_name") + or diag($call->faultstring); + + if ($method eq 'User.logout') { + delete $self->{_bz_credentials}->{token}; + } + return $call; +} + +sub bz_call_fail { + my ($self, $method, $orig_args, $faultstring, $test_name) = @_; + my $args = $orig_args ? dclone($orig_args) : {}; + + if ($self->{_bz_credentials}->{token}) { + $args->{Bugzilla_token} = $self->{_bz_credentials}->{token}; + } + + $test_name ||= "$method failed (as intended)"; + my $call = $self->call($method, $args); + $self->_handle_undef_response($test_name) if !$call; + ok($call->fault, $self->TYPE . ": $test_name") + or diag("Returned: " . Dumper($call->result)); + if (defined $faultstring) { + cmp_ok(trim($call->faultstring), '=~', $faultstring, + $self->TYPE . ": Got correct fault for $method"); + } + ok($call->faultcode + && (($call->faultcode < 32000 && $call->faultcode > -32000) + # Fault codes 32610 and above are OK because they are errors + # that we expect and test for sometimes. + || $call->faultcode >= 32610), + $self->TYPE . ': Fault code is set properly') + or diag("Code: " . $call->faultcode + . " Message: " . $call->faultstring); + + return $call; +} + +sub _handle_undef_response { + my ($self, $test_name) = @_; + my $response = $self->transport->http_response; + die "$test_name:\n", $response->as_string; +} + +sub bz_get_products { + my ($self) = @_; + $self->bz_log_in('QA_Selenium_TEST'); + + my $accessible = $self->bz_call_success('Product.get_accessible_products'); + my $prod_call = $self->bz_call_success('Product.get', $accessible->result); + my %products; + foreach my $prod (@{ $prod_call->result->{products} }) { + $products{$prod->{name}} = $prod->{id}; + } + + $self->bz_call_success('User.logout'); + return \%products; +} + +sub _string_array { map { random_string() } (1..$_[0]) } + +sub bz_create_test_bugs { + my ($self, $second_private) = @_; + my $config = $self->bz_config; + + my @whiteboard_strings = _string_array(3); + my @summary_strings = _string_array(3); + + my $public_bug = create_bug_fields($config); + $public_bug->{alias} = random_string(40); + $public_bug->{whiteboard} = join(' ', @whiteboard_strings); + $public_bug->{summary} = join(' ', @summary_strings); + + my $private_bug = dclone($public_bug); + $private_bug->{alias} = random_string(40); + if ($second_private) { + $private_bug->{product} = 'QA-Selenium-TEST'; + $private_bug->{component} = 'QA-Selenium-TEST'; + $private_bug->{target_milestone} = 'QAMilestone'; + $private_bug->{version} = 'QAVersion'; + # Although we don't directly use this, this helps some tests that + # depend on the values in $private_bug. + $private_bug->{creator} = $config->{PRIVATE_BUG_USER . '_user_login'}; + } + + my @create_bugs = ( + { user => 'editbugs', + args => $public_bug, + test => 'Create a public bug' }, + { user => $second_private ? PRIVATE_BUG_USER : 'editbugs', + args => $private_bug, + test => $second_private ? 'Create a private bug' + : 'Create a second public bug' }, + ); + + my $post_success = sub { + my ($call, $t) = @_; + my $id = $call->result->{id}; + $t->{args}->{id} = $id; + }; + + # Creating the bugs isn't really a test, it's just preliminary work + # for the tests. So we just run it with one of the RPC clients. + $self->bz_run_tests(tests => \@create_bugs, method => 'Bug.create', + post_success => $post_success); + + return ($public_bug, $private_bug); +} + +sub bz_run_tests { + my ($self, %params) = @_; + # Required params + my $config = $self->bz_config; + my $tests = $params{tests}; + my $method = $params{method}; + + # Optional params + my $post_success = $params{post_success}; + my $pre_call = $params{pre_call}; + + my $former_user = ''; + foreach my $t (@$tests) { + # Only logout/login if the user has changed since the last test + # (this saves us LOTS of needless logins). + my $user = $t->{user} || ''; + if ($former_user ne $user) { + $self->bz_call_success('User.logout') if $former_user; + $self->bz_log_in($user) if $user; + $former_user = $user; + } + + $pre_call->($t, $self) if $pre_call; + + if ($t->{error}) { + $self->bz_call_fail($method, $t->{args}, $t->{error}, $t->{test}); + } + else { + my $call = $self->bz_call_success($method, $t->{args}, $t->{test}); + if ($call->result && $post_success) { + $post_success->($call, $t, $self); + } + } + } + + $self->bz_call_success('User.logout') if $former_user; +} + +sub bz_test_bug { + my ($self, $fields, $bug, $expect, $t, $creation_time) = @_; + + foreach my $field (sort @$fields) { + # "description" is used by Bug.create but comments are not returned + # by Bug.get or Bug.search. + next if $field eq 'description'; + + my @include = @{ $t->{args}->{include_fields} || [] }; + my @exclude = @{ $t->{args}->{exclude_fields} || [] }; + if ( (@include and !grep($_ eq $field, @include)) + or (@exclude and grep($_ eq $field, @exclude)) ) + { + ok(!exists $bug->{$field}, "$field is not included") + or diag Dumper($bug); + next; + } + + if ($field =~ /^is_/) { + ok(defined $bug->{$field}, $self->TYPE . ": $field is not null"); + is($bug->{$field} ? 1 : 0, $expect->{$field} ? 1 : 0, + $self->TYPE . ": $field has the right boolean value"); + } + elsif ($field eq 'cc') { + foreach my $cc_item (@{ $expect->{cc} || [] }) { + ok(grep($_ eq $cc_item, @{ $bug->{cc} }), + $self->TYPE . ": $field contains $cc_item"); + } + } + elsif ($field eq 'creation_time' or $field eq 'last_change_time') { + my $creation_day; + # XML-RPC and JSON-RPC have different date formats. + if ($self->isa('QA::RPC::XMLRPC')) { + $creation_day = $creation_time->ymd(''); + } + else { + $creation_day = $creation_time->ymd; + } + + like($bug->{$field}, qr/^\Q${creation_day}\ET\d\d:\d\d:\d\d/, + $self->TYPE . ": $field has the right format"); + } + else { + is_deeply($bug->{$field}, $expect->{$field}, + $self->TYPE . ": $field value is correct"); + } + } +} + +1; + +__END__ diff --git a/qa/t/lib/QA/RPC/JSONRPC.pm b/qa/t/lib/QA/RPC/JSONRPC.pm new file mode 100644 index 000000000..4175b10fc --- /dev/null +++ b/qa/t/lib/QA/RPC/JSONRPC.pm @@ -0,0 +1,168 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +package QA::RPC::JSONRPC; +use strict; + +use QA::RPC; +BEGIN { + our @ISA = qw(QA::RPC); + + if (eval { require JSON::RPC::Client }) { + push(@ISA, 'JSON::RPC::Client'); + } + else { + require JSON::RPC::Legacy::Client; + push(@ISA, 'JSON::RPC::Legacy::Client'); + } +} + +use URI::Escape; + +use constant DATETIME_REGEX => qr/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ$/; +sub TYPE { + my ($self) = @_; + return $self->bz_get_mode ? 'JSON-RPC GET' : 'JSON-RPC'; +} + +################################# +# Consistency with XMLRPC::Lite # +################################# + +sub ua { + my $self = shift; + if ($self->{ua} and not $self->{ua}->isa('QA::RPC::UserAgent')) { + bless $self->{ua}, 'QA::RPC::UserAgent'; + } + return $self->SUPER::ua(@_); +} +sub transport { $_[0]->ua } + +sub bz_get_mode { + my ($self, $value) = @_; + $self->{bz_get_mode} = $value if @_ > 1; + return $self->{bz_get_mode}; +} + +sub _bz_callback { + my ($self, $value) = @_; + $self->{bz_callback} = $value if @_ > 1; + return $self->{bz_callback}; +} + +sub call { + my $self = shift; + my ($method, $args) = @_; + my %params = ( method => $method ); + $params{params} = $args ? [$args] : []; + + my $config = $self->bz_config; + my $url = $config->{browser_url} . "/" + . $config->{bugzilla_installation} . "/jsonrpc.cgi"; + my $result; + if ($self->bz_get_mode) { + my $method_escaped = uri_escape($method); + $url .= "?method=$method_escaped"; + if (my $cred = $self->_bz_credentials) { + $args->{Bugzilla_login} = $cred->{user} + if !exists $args->{Bugzilla_login}; + $args->{Bugzilla_password} = $cred->{pass} + if !exists $args->{Bugzilla_password}; + } + if ($args) { + my $params_json = $self->json->encode($args); + my $params_escaped = uri_escape($params_json); + $url .= "¶ms=$params_escaped"; + } + if ($self->version eq '1.1') { + $url .= "&version=1.1"; + } + my $callback = delete $args->{callback}; + if (defined $callback) { + $self->_bz_callback($callback); + $url .= "&callback=" . uri_escape($callback); + } + $result = $self->SUPER::call($url); + } + else { + $result = $self->SUPER::call($url, \%params); + } + + if ($result) { + bless $result, 'QA::RPC::JSONRPC::ReturnObject'; + } + return $result; +} + +sub _get { + my $self = shift; + my $result = $self->SUPER::_get(@_); + # Simple JSONP support for tests. We just remove the callback from + # the return value. + my $callback = $self->_bz_callback; + if (defined $callback and $result->is_success) { + my $content = $result->content; + $content =~ s/^(?:\/\*\*\/)?\Q$callback(\E(.*)\)$/$1/s; + $result->content($content); + # We don't need this anymore, and we don't want it to affect + # future calls. + delete $self->{bz_callback}; + } + return $result; +} + +1; + +package QA::RPC::JSONRPC::ReturnObject; +use strict; + +BEGIN { + if (eval { require JSON::RPC::Client }) { + our @ISA = qw(JSON::RPC::ReturnObject); + } + else { + require JSON::RPC::Legacy::Client; + our @ISA = qw(JSON::RPC::Legacy::ReturnObject); + } +} + +################################# +# Consistency with XMLRPC::Lite # +################################# + +sub faultstring { $_[0]->{content}->{error}->{message} } +sub faultcode { $_[0]->{content}->{error}->{code} } +sub fault { $_[0]->is_error } + +1; + +package QA::RPC::UserAgent; +use strict; +use base qw(LWP::UserAgent); + +######################################## +# Consistency with XMLRPC::Lite's ->ua # +######################################## + +sub send_request { + my $self = shift; + my $response = $self->SUPER::send_request(@_); + $self->http_response($response); + # JSON::RPC::Client can't handle 500 responses, even though + # they're required by the JSON-RPC spec. + $response->code(200); + return $response; +} + +# Copied directly from SOAP::Lite::Transport::HTTP. +sub http_response { + my $self = shift; + if (@_) { $self->{'_http_response'} = shift; return $self } + return $self->{'_http_response'}; +} diff --git a/qa/t/lib/QA/RPC/XMLRPC.pm b/qa/t/lib/QA/RPC/XMLRPC.pm new file mode 100644 index 000000000..d88d4092e --- /dev/null +++ b/qa/t/lib/QA/RPC/XMLRPC.pm @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +package QA::RPC::XMLRPC; +use strict; +use base qw(QA::RPC XMLRPC::Lite); + +use constant TYPE => 'XML-RPC'; +use constant DATETIME_REGEX => qr/^\d{8}T\d\d:\d\d:\d\d$/; + +1; + +__END__ diff --git a/qa/t/lib/QA/Tests.pm b/qa/t/lib/QA/Tests.pm new file mode 100644 index 000000000..0bd0942fa --- /dev/null +++ b/qa/t/lib/QA/Tests.pm @@ -0,0 +1,108 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +package QA::Tests; +use strict; +use base qw(Exporter); +our @EXPORT_OK = qw( + PRIVATE_BUG_USER + STANDARD_BUG_TESTS + bug_tests + create_bug_fields +); + +use constant INVALID_BUG_ID => -1; +use constant INVALID_BUG_ALIAS => 'aaaaaaa12345'; +use constant PRIVATE_BUG_USER => 'QA_Selenium_TEST'; + +use constant CREATE_BUG => { + 'priority' => 'Highest', + 'status' => 'CONFIRMED', + 'version' => 'unspecified', + 'creator' => 'editbugs', + 'description' => '-- Comment Created By Bugzilla XML-RPC Tests --', + 'cc' => ['unprivileged'], + 'component' => 'c1', + 'platform' => 'PC', + # It's necessary to assign the bug to somebody who isn't in the + # timetracking group, for the Bug.update tests. + 'assigned_to' => PRIVATE_BUG_USER, + 'summary' => 'WebService Test Bug', + 'product' => 'Another Product', + 'op_sys' => 'Linux', + 'severity' => 'normal', + 'qa_contact' => 'canconfirm', + version => 'Another1', + url => 'http://www.bugzilla.org/', + target_milestone => 'AnotherMS1', +}; + +sub create_bug_fields { + my ($config) = @_; + my %bug = %{ CREATE_BUG() }; + foreach my $field (qw(creator assigned_to qa_contact)) { + my $value = $bug{$field}; + $bug{$field} = $config->{"${value}_user_login"}; + } + $bug{cc} = [map { $config->{$_ . "_user_login"} } @{ $bug{cc} }]; + return \%bug; +} + +sub bug_tests { + my ($public_id, $private_id) = @_; + return [ + { args => { ids => [$private_id] }, + error => "You are not authorized to access", + test => 'Logged-out user cannot access a private bug', + }, + { args => { ids => [$public_id] }, + test => 'Logged-out user can access a public bug.', + }, + { args => { ids => [INVALID_BUG_ID] }, + error => "not a valid bug number", + test => 'Passing invalid bug id returns error "Invalid Bug ID"', + }, + { args => { ids => [undef] }, + error => "You must enter a valid bug number", + test => 'Passing undef as bug id param returns error "Invalid Bug ID"', + }, + { args => { ids => [INVALID_BUG_ALIAS] }, + error => "nor an alias to a bug", + test => 'Passing invalid bug alias returns error "Invalid Bug Alias"', + }, + + { user => 'editbugs', + args => { ids => [$private_id] }, + error => "You are not authorized to access", + test => 'Access to a private bug is denied to a user without privs', + }, + { user => 'unprivileged', + args => { ids => [$public_id] }, + test => 'User without privs can access a public bug', + }, + { user => 'admin', + args => { ids => [$public_id] }, + test => 'Admin can access a public bug.', + }, + { user => PRIVATE_BUG_USER, + args => { ids => [$private_id] }, + test => 'User with privs can successfully access a private bug', + }, + # This helps webservice_bug_attachment get private attachment ids + # from the public bug, and doesn't hurt for the other tests. + { user => PRIVATE_BUG_USER, + args => { ids => [$public_id] }, + test => 'User with privs can also access the public bug', + }, + ]; +} + +use constant STANDARD_BUG_TESTS => bug_tests('public_bug', 'private_bug'); + +1; diff --git a/qa/t/lib/QA/Util.pm b/qa/t/lib/QA/Util.pm new file mode 100644 index 000000000..d8d8ae52f --- /dev/null +++ b/qa/t/lib/QA/Util.pm @@ -0,0 +1,375 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# -*- Mode: perl; indent-tabs-mode: nil -*- + +package QA::Util; + +use strict; +use Data::Dumper; +use Test::More; +use Test::WWW::Selenium; +use WWW::Selenium::Util qw(server_is_running); + +# Fixes wide character warnings +BEGIN { + my $builder = Test::More->builder; + binmode $builder->output, ":encoding(utf8)"; + binmode $builder->failure_output, ":encoding(utf8)"; + binmode $builder->todo_output, ":encoding(utf8)"; +} + +use base qw(Exporter); +@QA::Util::EXPORT = qw( + trim + url_quote + random_string + + log_in + logout + file_bug_in_product + create_bug + edit_bug + edit_bug_and_return + go_to_bug + go_to_home + go_to_admin + edit_product + add_product + open_advanced_search_page + set_parameters + + get_selenium + get_rpc_clients + + WAIT_TIME + CHROME_MODE +); + +# How long we wait for pages to load. +use constant WAIT_TIME => 60000; +use constant CONF_FILE => "../config/selenium_test.conf"; +use constant CHROME_MODE => 1; +use constant NDASH => chr(0x2013); + +##################### +# Utility Functions # +##################### + +sub random_string { + my $size = shift || 30; # default to 30 chars if nothing specified + return join("", map{ ('0'..'9','a'..'z','A'..'Z')[rand 62] } (1..$size)); +} + +# Remove consecutive as well as leading and trailing whitespaces. +sub trim { + my ($str) = @_; + if ($str) { + $str =~ s/[\r\n\t\s]+/ /g; + $str =~ s/^\s+//g; + $str =~ s/\s+$//g; + } + return $str; +} + +# This originally came from CGI.pm, by Lincoln D. Stein +sub url_quote { + my ($toencode) = (@_); + $toencode =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg; + return $toencode; +} + +################### +# Setup Functions # +################### + +sub get_config { + # read the test configuration file + my $conf_file = CONF_FILE; + my $config = do($conf_file) + or die "can't read configuration '$conf_file': $!$@"; +} + +sub get_selenium { + my $chrome_mode = shift; + my $config = get_config(); + + if (!server_is_running) { + die "Selenium Server isn't running!"; + } + + my $sel = Test::WWW::Selenium->new( + host => $config->{host}, + port => $config->{port}, + browser => $chrome_mode ? $config->{experimental_browser_launcher} : $config->{browser}, + browser_url => $config->{browser_url} + ); + + return ($sel, $config); +} + +sub get_xmlrpc_client { + my $config = get_config(); + my $xmlrpc_url = $config->{browser_url} . "/" . + $config->{bugzilla_installation} . "/xmlrpc.cgi"; + + require QA::RPC::XMLRPC; + my $rpc = new QA::RPC::XMLRPC(proxy => $xmlrpc_url); + return ($rpc, $config); +} + +sub get_jsonrpc_client { + my ($get_mode) = @_; + require QA::RPC::JSONRPC; + my $rpc = new QA::RPC::JSONRPC(); + # If we don't set a long timeout, then the Bug.add_comment test + # where we add a too-large comment fails. + $rpc->transport->timeout(180); + $rpc->version($get_mode ? '1.1' : '1.0'); + $rpc->bz_get_mode($get_mode); + return $rpc; +} + +sub get_rpc_clients { + my ($xmlrpc, $config) = get_xmlrpc_client(); + my $jsonrpc = get_jsonrpc_client(); + my $jsonrpc_get = get_jsonrpc_client('GET'); + return ($config, $xmlrpc, $jsonrpc, $jsonrpc_get); +} + +################################ +# Helpers for Selenium Scripts # +################################ + +sub go_to_home { + my ($sel, $config) = @_; + $sel->open_ok("/$config->{bugzilla_installation}/", undef, "Go to the home page"); + $sel->title_is("Bugzilla Main Page"); +} + +# Go to the home/login page and log in. +sub log_in { + my ($sel, $config, $user) = @_; + + go_to_home($sel, $config); + $sel->type_ok("Bugzilla_login_top", $config->{"${user}_user_login"}, "Enter $user login name"); + $sel->type_ok("Bugzilla_password_top", $config->{"${user}_user_passwd"}, "Enter $user password"); + $sel->click_ok("log_in_top", undef, "Submit credentials"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Bugzilla Main Page", "User is logged in"); +} + +# Log out. Will fail if you are not logged in. +sub logout { + my $sel = shift; + + $sel->click_ok("link=Log out", undef, "Logout"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Logged Out"); +} + +# Display the bug form to enter a bug in the given product. +sub file_bug_in_product { + my ($sel, $product, $classification) = @_; + + $classification ||= "Unclassified"; + $sel->click_ok("link=New", undef, "Go create a new bug"); + $sel->wait_for_page_to_load(WAIT_TIME); + my $title = $sel->get_title(); + if ($sel->is_text_present("Select Classification")) { + ok(1, "More than one enterable classification available. Display them in a list"); + $sel->click_ok("link=$classification", undef, "Choose $classification"); + $sel->wait_for_page_to_load(WAIT_TIME); + $title = $sel->get_title(); + } + if ($sel->is_text_present("Which product is affected by the problem")) { + ok(1, "Which product is affected by the problem"); + $sel->click_ok("link=Other Products", undef, "Choose full product list"); + $sel->wait_for_page_to_load(WAIT_TIME); + $title = $sel->get_title(); + } + if ($sel->is_text_present($product)) { + ok(1, "Display the list of enterable products"); + $sel->open_ok("/bmo/enter_bug.cgi?product=$product&format=__default__", undef, "Choose product $product"); + $sel->wait_for_page_to_load(WAIT_TIME); + } + else { + ok(1, "Only one product available in $classification. Skipping the 'Choose product' page.") + } + $sel->title_is("Enter Bug: $product", "Display form to enter bug data"); + # Always make sure all fields are visible + if ($sel->is_element_present('//input[@value="Show Advanced Fields"]')) { + $sel->click_ok('//input[@value="Show Advanced Fields"]'); + } +} + +sub create_bug { + my ($sel, $bug_summary) = @_; + my $ndash = NDASH; + + $sel->click_ok('commit'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + my $bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + $sel->title_like(qr/$bug_id $ndash( \(.*\))? $bug_summary/, "Bug $bug_id created with summary '$bug_summary'"); + return $bug_id; +} + +sub edit_bug { + my ($sel, $bug_id, $bug_summary, $options) = @_; + my $btn_id = $options ? $options->{id} : 'commit'; + $sel->click_ok($btn_id); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->is_text_present_ok("Changes submitted for bug $bug_id"); +} + +sub edit_bug_and_return { + my ($sel, $bug_id, $bug_summary, $options) = @_; + my $ndash = NDASH; + edit_bug($sel, $bug_id, $bug_summary, $options); + $sel->click_ok("//a[contains(\@href, 'show_bug.cgi?id=$bug_id')]"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("$bug_id $ndash $bug_summary", "Returning back to bug $bug_id"); +} + +# Go to show_bug.cgi. +sub go_to_bug { + my ($sel, $bug_id) = @_; + + $sel->type_ok("quicksearch_top", $bug_id); + $sel->click_ok("find_top", undef, "Go to bug $bug_id"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + my $bug_title = $sel->get_title(); + utf8::encode($bug_title) if utf8::is_utf8($bug_title); + $sel->title_like(qr/^$bug_id /, $bug_title); +} + +# Go to admin.cgi. +sub go_to_admin { + my $sel = shift; + + $sel->click_ok("link=Administration", undef, "Go to the Admin page"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_like(qr/^Administer your installation/, "Display admin.cgi"); +} + +# Go to editproducts.cgi and display the given product. +sub edit_product { + my ($sel, $product, $classification) = @_; + + $classification ||= "Unclassified"; + go_to_admin($sel); + $sel->click_ok("link=Products", undef, "Go to the Products page"); + $sel->wait_for_page_to_load(WAIT_TIME); + my $title = $sel->get_title(); + if ($title eq "Select Classification") { + ok(1, "More than one enterable classification available. Display them in a list"); + $sel->click_ok("link=$classification", undef, "Choose $classification"); + $sel->wait_for_page_to_load(WAIT_TIME); + } + else { + $sel->title_is("Select product", "Display the list of enterable products"); + } + $sel->click_ok("link=$product", undef, "Choose $product"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Edit Product '$product'", "Display properties of $product"); +} + +sub add_product { + my ($sel, $classification) = @_; + + $classification ||= "Unclassified"; + go_to_admin($sel); + $sel->click_ok("link=Products", undef, "Go to the Products page"); + $sel->wait_for_page_to_load(WAIT_TIME); + my $title = $sel->get_title(); + if ($title eq "Select Classification") { + ok(1, "More than one enterable classification available. Display them in a list"); + $sel->click_ok("//a[contains(\@href, 'editproducts.cgi?action=add&classification=$classification')]", + undef, "Add product to $classification"); + } + else { + $sel->title_is("Select product", "Display the list of enterable products"); + $sel->click_ok("link=Add", undef, "Add a new product"); + } + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Add Product", "Display the new product form"); +} + +sub open_advanced_search_page { + my $sel = shift; + + $sel->click_ok("link=Search"); + $sel->wait_for_page_to_load(WAIT_TIME); + my $title = $sel->get_title(); + if ($title eq "Simple Search") { + ok(1, "Display the simple search form"); + $sel->click_ok("link=Advanced Search"); + $sel->wait_for_page_to_load(WAIT_TIME); + } + $sel->title_is("Search for bugs", "Display the Advanced search form"); +} + +# $params is a hashref of the form: +# {section1 => { param1 => {type => '(text|select)', value => 'foo'}, +# param2 => {type => '(text|select)', value => 'bar'}, +# param3 => undef }, +# section2 => { param4 => ...}, +# } +# section1, section2, ... is the name of the section +# param1, param2, ... is the name of the parameter (which must belong to the given section) +# type => 'text' is for text fields +# type => 'select' is for drop-down select fields +# undef is for radio buttons (in which case the parameter must be the ID of the radio button) +# value => 'foo' is the value of the parameter (either text or label) +sub set_parameters { + my ($sel, $params) = @_; + + go_to_admin($sel); + $sel->click_ok("link=Parameters", undef, "Go to the Config Parameters page"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Configuration: Required Settings"); + my $last_section = "Required Settings"; + + foreach my $section (keys %$params) { + if ($section ne $last_section) { + $sel->click_ok("link=$section"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Configuration: $section"); + $last_section = $section; + } + my $param_list = $params->{$section}; + foreach my $param (keys %$param_list) { + my $data = $param_list->{$param}; + if (defined $data) { + my $type = $data->{type}; + my $value = $data->{value}; + + if ($type eq 'text') { + $sel->type_ok($param, $value); + } + elsif ($type eq 'select') { + $sel->select_ok($param, "label=$value"); + } + else { + ok(0, "Unknown parameter type: $type"); + } + } + else { + # If the value is undefined, then the param name is + # the ID of the radio button. + $sel->click_ok($param); + } + } + $sel->click_ok('//input[@type="submit" and @value="Save Changes"]', undef, "Save Changes"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Parameters Updated"); + } +} + +1; + +__END__ diff --git a/qa/t/selenium_server_start.t b/qa/t/selenium_server_start.t new file mode 100644 index 000000000..c08db293c --- /dev/null +++ b/qa/t/selenium_server_start.t @@ -0,0 +1,83 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; + +use constant DISPLAY => 99; +#use constant DISPLAY => 0; + +use Test::More tests => 12; +#use Test::More tests => 4; + +my $pid; + +# Start the Xvfb server first +$pid = xserver_start(); +ok($pid, "X Server started with PID $pid on display " . DISPLAY); +ok(open(XPID, ">testing.x.pid"), "Opening testing.x.pid"); +ok((print XPID $pid), "Writing testing.x.pid"); +ok(close(XPID), "Closing testing.x.pid"); + +# Start the VNC service second +ok($pid = vnc_start(), "VNC desktop started with PID $pid"); +ok(open(VNCPID, ">testing.vnc.pid"), "Opening testing.vnc.pid"); +ok((print VNCPID $pid), "Writing testing.vnc.pid"); +ok(close(VNCPID), "Closing testing.vnc.pid"); + +# Start the selenium server third +ok($pid = selenium_start(), "Selenium RC server started with PID $pid"); +ok(open(SPID, ">testing.selenium.pid"), "Opening testing.selenium.pid"); +ok((print SPID $pid), "Writing testing.selenium.pid"); +ok(close(SPID), "Closing testing.selenium.pid"); + +sleep(10); + +# Subroutines + +sub xserver_start { + my $pid; + my @x_cmd = qw(Xvfb -ac -screen 0 1600x1200x24 -fbdir /tmp); + push(@x_cmd, ":" . DISPLAY); + $pid = fork(); + if (!$pid) { + open(STDOUT, ">/dev/null"); + open(STDERR, ">/dev/null"); + exec(@x_cmd) || die "unable to execute: $!"; + } + else { + return $pid; + } + return 0; +} + +sub vnc_start { + my @vnc_cmd = qw(x11vnc -viewonly -forever -nopw -quiet -display); + push(@vnc_cmd, ":" . DISPLAY); + my $pid = fork(); + if (!$pid) { + open(STDOUT, ">/dev/null"); + open(STDERR, ">/dev/null"); + exec(@vnc_cmd) || die "unabled to execute: $!"; + } + return $pid; +} + +sub selenium_start { + my @selenium_cmd = qw(java -jar ../config/selenium-server-standalone.jar + -firefoxProfileTemplate ../config/firefox + -log ../config/selenium.log + -singlewindow); + unshift(@selenium_cmd, "env", "DISPLAY=:" . DISPLAY); + my $pid = fork(); + if (!$pid) { + open(STDOUT, ">/dev/null"); + open(STDERR, ">/dev/null"); + exec(@selenium_cmd) || die "unable to execute: $!"; + } + return $pid; +} diff --git a/qa/t/selenium_server_stop.t b/qa/t/selenium_server_stop.t new file mode 100644 index 000000000..62a29f38c --- /dev/null +++ b/qa/t/selenium_server_stop.t @@ -0,0 +1,34 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; + +use Test::More tests => 15; + +my $pid; + +# Stop the selenium server first +ok(open(SPID, "<testing.selenium.pid"), "Opening testing.selenium.pid"); +ok(($pid = <SPID>), "Reading testing.selenium.pid"); +ok(close(SPID), "Closing testing.selenium.pid"); +ok(kill(9, $pid), "Killing process $pid"); +ok(unlink("testing.selenium.pid"), "Removing testing.selenium.pid"); + +# Stop the VNC service second +ok(open(VNCPID, "<testing.vnc.pid"), "Opening testing.vnc.pid"); +ok(($pid = <VNCPID>), "Reading testing.vnc.pid"); +ok(close(VNCPID), "Closing testing.vnc.pid"); +ok(kill(9, $pid), "Killing process $pid"); +ok(unlink("testing.vnc.pid"), "Removing testing.vnc.pid"); + +# Stop the Xvfb server third +ok(open(XPID, "<testing.x.pid"), "Opening testing.x.pid"); +ok(($pid = <XPID>), "Reading testing.x.pid"); +ok(close(XPID), "Closing testing.x.pid"); +ok(kill(9, $pid), "Killing process $pid"); +ok(unlink("testing.x.pid"), "Removing testing.x.pid"); diff --git a/qa/t/test_bmo_autolinkification.t b/qa/t/test_bmo_autolinkification.t new file mode 100644 index 000000000..520301165 --- /dev/null +++ b/qa/t/test_bmo_autolinkification.t @@ -0,0 +1,53 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'unprivileged'); +file_bug_in_product($sel, 'TestProduct'); +my $bug_summary = "linkification test bug"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "linkification test"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/\d+ \S $bug_summary/, "Bug created"); +my $bug_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); + +$sel->type_ok("comment", "bp-63f096f7-253b-4ee2-ae3d-8bb782090824"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/\d+ \S $bug_summary/, "crash report added"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->attribute_is('link=bp-63f096f7-253b-4ee2-ae3d-8bb782090824@href', 'https://crash-stats.mozilla.com/report/index/63f096f7-253b-4ee2-ae3d-8bb782090824'); + +$sel->type_ok("comment", "CVE-2010-2884"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/\d+ \S $bug_summary/, "cve added"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->attribute_is('link=CVE-2010-2884@href', 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2884'); + +$sel->type_ok("comment", "r12345"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/\d+ \S $bug_summary/, "svn revision added"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->attribute_is('link=r12345@href', 'https://viewvc.svn.mozilla.org/vc?view=rev&revision=12345'); + +logout($sel); + diff --git a/qa/t/test_bmo_enter_new_bug.t b/qa/t/test_bmo_enter_new_bug.t new file mode 100644 index 000000000..ac4a9ca8b --- /dev/null +++ b/qa/t/test_bmo_enter_new_bug.t @@ -0,0 +1,421 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +# Comments: +# 1. Some of the forms have been commented as they have been removed since +# this script was originally created. I left them in insteading of deleting +# so they could be used for reference for adding new form tests. +# 2. The _check_* utility functions for creating objects should be moved to +# generate_test_data.pl at some point. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-off" => undef} }); + +# mktgevent and swag are dependent so we create the mktgevent bug first so +# we can provide the bug id to swag + +## mktgevent +# +#_check_product('Marketing'); +#_check_component('Marketing', 'Event Requests'); +#_check_component('Marketing', 'Swag Requests'); +#_check_group('mozilla-corporation-confidential'); +# +## FIXME figure out how to use format= with file_bug_in_product +# +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Marketing&format=mktgevent"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Event Request Form", "Open custom bug entry form - mktgevent"); +#$sel->type_ok("firstname", "Bugzilla", "Enter first name"); +#$sel->type_ok("lastname", "Administrator", "Enter last name"); +#$sel->type_ok("email", $config->{'admin_user_login'}, "Enter email address"); +#$sel->type_ok("eventname", "Event Name", "Enter event name"); +#$sel->type_ok("website", $config->{'browser_url'}, "Enter web site"); +#$sel->type_ok("goals", "Goals for the event", "Enter goals"); +#$sel->type_ok("date", "2032/01/01", "Enter date"); +#$sel->type_ok("successmeasure", "Success Measure", "Enter measure of success"); +#$sel->click_ok("doing", "value=Other", "Select what doing"); +#$sel->type_ok("doing-other-what", "What will you be doing at the event", "Enter other what doing"); +#$sel->select_ok("attendees", "value=1-99", "Select number of attendees"); +#$sel->select_ok("audience", "value=Contributors", "Select targeted audience"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $mktgevent_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +# +## swag +# +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Marketing&format=swag"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Swag Request Form", "Open custom bug entry form - swag"); +#$sel->type_ok("firstname", "Bugzilla", "Enter first name"); +#$sel->type_ok("lastname", "Administrator", "Enter last name"); +#$sel->type_ok("dependson", $mktgevent_bug_id, "Enter event request bug id"); +#$sel->type_ok("email", $config->{'admin_user_login'}, "Enter email address"); +#$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +#$sel->type_ok("additional", "Specific swag needed", "Enter specific swag needed"); +#$sel->type_ok("shiptofirstname", "Bugzilla", "Enter ship to first name"); +#$sel->type_ok("shiptolastname", "Administrator", "Enter ship to last name"); +#$sel->type_ok("shiptoaddress", "100 Some Street", "Enter ship to address"); +#$sel->type_ok("shiptoaddress2", "Suite 200", "Enter ship to address 2"); +#$sel->type_ok("shiptocity", "Mountain View", "Enter ship to city"); +#$sel->type_ok("shiptostate", "California", "Enter ship to state"); +#$sel->type_ok("shiptocountry", "USA", "Enter ship to country"); +#$sel->type_ok("shiptopcode", "94041", "Enter ship to postal code"); +#$sel->type_ok("shiptophone", "1-800-555-1212", "Enter ship to phone"); +#$sel->type_ok("shiptoidrut", "What is this?", "Enter ship to personal id/rut"); +#$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter bug description"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $swag_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# trademark + +_check_product('Marketing'); +_check_component('Marketing', 'Trademark Permissions'); +_check_group('marketing-private'); + +$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Marketing&format=trademark"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Trademark Usage Requests", "Open custom bug entry form - trademark"); +$sel->type_ok("short_desc", "Bug created by Selenium", "Enter bug summary"); +$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter bug description"); +$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $trademark_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# itrequest + +_check_product('mozilla.org'); +_check_product('Infrastructure & Operations'); +_check_component('Infrastructure & Operations', 'WebOps: Other'); +_check_version('Infrastructure & Operations', 'other'); +_check_group('infra'); + +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=mozilla.org&format=itrequest"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Mozilla Corporation/Foundation IT Requests", "Open custom bug entry form - itrequest"); +#$sel->click_ok("component_webops_other", "Select request type"); +#$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +#$sel->type_ok("short_desc", "Bug created by Selenium", "Enter request summary"); +#$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter request description"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $itrequest_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# brownbag + +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=mozilla.org&format=brownbag"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Mozilla Corporation Brownbag Requests", "Open custom bug entry form - brownbag"); +#$sel->type_ok("presenter", "Bugzilla Administrator", "Enter presenter"); +#$sel->type_ok("topic", "Automated testing of Bugzilla", "Enter topic"); +#$sel->type_ok("date", "01/01/2012", "Enter date"); +#$sel->select_ok("time_hour", "value=1", "Select hour"); +#$sel->select_ok("time_minute", "value=30", "Select minute"); +#$sel->select_ok("ampm", "value=PM", "Select am/pm"); +#$sel->select_ok("audience", "value=Employees Only", "Select audience"); +#$sel->check_ok("airmozilla", "Select need airmozilla"); +#$sel->check_ok("dialin", "Select need dial in"); +#$sel->check_ok("archive", "Select need to be archived"); +#$sel->check_ok("ithelp", "Select need it help"); +#$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +#$sel->type_ok("description", "--- Bug created by Selenium ---", "Enter request description"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $brownbag_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# presentation + +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=mozilla.org&format=presentation"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Mozilla Corporation Mountain View Presentation Request", "Open custom bug entry form - presentation"); +#$sel->type_ok("presenter", "Bugzilla Administrator", "Enter presenter"); +#$sel->type_ok("topic", "Automated testing of Bugzilla", "Enter topic"); +#$sel->type_ok("date", "01/01/2012", "Enter date"); +#$sel->select_ok("time_hour", "value=1", "Select hour"); +#$sel->select_ok("time_minute", "value=30", "Select minute"); +#$sel->select_ok("ampm", "value=PM", "Select am/pm"); +#$sel->select_ok("audience", "value=Employees Only", "Select audience"); +#$sel->check_ok("airmozilla", "Select need airmozilla"); +#$sel->check_ok("dialin", "Select need dial in"); +#$sel->check_ok("archive", "Select need to be archived"); +#$sel->check_ok("ithelp", "Select need it help"); +#$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +#$sel->type_ok("description", "--- Bug created by Selenium ---", "Enter request description"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $presentation_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +_check_component('mozilla.org', 'Discussion Forums'); + +#mozlist + +_check_version('mozilla.org', 'other'); +_check_component('mozilla.org', 'Discussion Forums'); + +$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=mozilla.org&format=mozlist"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Mozilla Discussion Forum", "Open custom bug entry form - mozlist"); +$sel->type_ok("listName", "test-list", "Enter name for mailing list"); +$sel->type_ok("listAdmin", $config->{'admin_user_login'}, "Enter list administator"); +$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +$sel->check_ok("name=groups", "value=infra", "Select private group"); +$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter bug description"); +$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $mozlist_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +_check_product('Mozilla PR'); +_check_component('Mozilla PR', 'China - AMO'); +_check_group('mozilla-confidential'); + +#mozpr + +_check_group('pr-private'); + +#$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Mozilla PR&format=mozpr"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->title_is("Create a PR Request", "Open custom bug entry form - mozpr"); +#$sel->select_ok("location", "value=China", "Select location"); +#$sel->select_ok("component", "value=China - AMO", "Select component"); +#$sel->select_ok("fakecomp", "value=AMO", "Select fake component"); +#$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +#$sel->type_ok("short_desc", "Bug created by Selenium", "Enter bug summary"); +#$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter bug description"); +#$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +#$sel->wait_for_page_to_load_ok(WAIT_TIME); +#$sel->is_text_present_ok('has been added to the database', 'Bug created'); +#my $mozpr_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# legal + +_check_product('Legal'); +_check_component('Legal', 'Canonical'); +_check_component('Legal', 'Copyright'); +_check_group('mozilla-employee-confidential'); + +$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Legal&format=legal"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Mozilla Corporation Legal Requests", "Open custom bug entry form - legal"); +$sel->select_ok("component", "value=Canonical", "Select request type"); +$sel->type_ok("short_desc", "Bug created by Selenium", "Enter request summary"); +$sel->type_ok("cc", $config->{'unprivileged_user_login'}, "Enter cc address"); +$sel->type_ok("otherparty", "Other party", "Enter other party"); +$sel->type_ok("busobj", "Business objective", "Enter business objective"); +$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter request description"); +$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $legal_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# poweredby + +_check_product('Websites', 'other'); +_check_component('Websites', 'www.mozilla.org'); +_check_user('liz@mozilla.com'); + +$sel->open_ok("/$config->{bugzilla_installation}/enter_bug.cgi?product=Websites&format=poweredby"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Powered by Mozilla Logo Requests", "Open custom bug entry form - poweredby"); +$sel->type_ok("short_desc", "Bug created by Selenium", "Enter bug summary"); +$sel->type_ok("comment", "--- Bug created by Selenium ---", "Enter bug description"); +$sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $poweredby_bug_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +set_parameters($sel, { "Bug Fields" => {"useclassification-on" => undef} }); +logout($sel); + +sub _check_product { + my ($product, $version) = @_; + + go_to_admin($sel); + $sel->click_ok("link=Products"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Select product"); + + my $product_description = "$product Description"; + + my $text = trim($sel->get_text("bugzilla-body")); + if ($text =~ /$product_description/) { + # Product exists already + return 1; + } + + $sel->click_ok("link=Add"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Add Product"); + $sel->type_ok("product", $product); + $sel->type_ok("description", $product_description); + $sel->type_ok("version", $version) if $version; + $sel->select_ok("default_op_sys_id", "Unspecified"); + $sel->select_ok("default_platform_id", "Unspecified"); + $sel->click_ok('//input[@type="submit" and @value="Add"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $text = trim($sel->get_text("message")); + ok($text =~ /You will need to add at least one component before anyone can enter bugs against this product/, + "Display a reminder about missing components"); + + return 1; +} + +sub _check_component { + my ($product, $component) = @_; + + go_to_admin($sel); + $sel->click_ok("link=components"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Edit components for which product?"); + + $sel->click_ok("link=$product"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Select component of product '$product'"); + + my $component_description = "$component Description"; + + my $text = trim($sel->get_text("bugzilla-body")); + if ($text =~ /$component_description/) { + # Component exists already + return 1; + } + + # Add the watch user for component watching + my $watch_user = lc $component . "@" . lc $product . ".bugs"; + $watch_user =~ s/ & /-/; + $watch_user =~ s/\s+/\-/g; + $watch_user =~ s/://g; + + go_to_admin($sel); + $sel->click_ok("link=components"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Edit components for which product?"); + $sel->click_ok("link=$product"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Select component of product '$product'"); + $sel->click_ok("link=Add"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Add component to the $product product"); + $sel->type_ok("component", $component); + $sel->type_ok("description", $component_description); + $sel->type_ok("initialowner", $config->{'admin_user_login'}); + $sel->uncheck_ok("watch_user_auto"); + $sel->type_ok("watch_user", $watch_user); + $sel->check_ok("watch_user_auto"); + $sel->click_ok('//input[@type="submit" and @value="Add"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Component Created"); + $text = trim($sel->get_text("message")); + ok($text eq "The component $component has been created.", "Component successfully created"); + + return 1; +} + +sub _check_group { + my ($group) = @_; + + go_to_admin($sel); + $sel->click_ok("link=Groups"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Edit Groups"); + + my $group_description = "$group Description"; + + my $text = trim($sel->get_text("bugzilla-body")); + if ($text =~ /$group_description/) { + # Group exists already + return 1; + } + + $sel->title_is("Edit Groups"); + $sel->click_ok("link=Add Group"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Add group"); + $sel->type_ok("name", $group); + $sel->type_ok("desc", $group_description); + $sel->check_ok("isactive"); + $sel->check_ok("insertnew"); + $sel->click_ok("create"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("New Group Created"); + my $group_id = $sel->get_value("group_id"); + + return 1; +} + +sub _check_version { + my ($product, $version) = @_; + + go_to_admin($sel); + $sel->click_ok("link=versions"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Edit versions for which product?"); + $sel->click_ok("link=$product"); + $sel->wait_for_page_to_load(WAIT_TIME); + + my $text = trim($sel->get_text("bugzilla-body")); + if ($text =~ /$version/) { + # Version exists already + return 1; + } + + $sel->click_ok("link=Add"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_like(qr/^Add Version to Product/); + $sel->type_ok("version", $version); + $sel->click_ok("create"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Version Created"); + + return 1; +} + +sub _check_user { + my ($user) = @_; + + go_to_admin($sel); + $sel->click_ok("link=Users"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Search users"); + $sel->type_ok("matchstr", $user); + $sel->click_ok("search"); + $sel->wait_for_page_to_load(WAIT_TIME); + + my $text = trim($sel->get_text("bugzilla-body")); + if ($text =~ /$user/) { + # User exists already + return 1; + } + + $sel->click_ok("link=add a new user"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is('Add user'); + $sel->type_ok('login', $user); + $sel->type_ok('password', 'password'); + $sel->click_ok("add"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->is_text_present('regexp:The user account .* has been created successfully'); + + return 1; +} diff --git a/qa/t/test_bmo_retire_values.t b/qa/t/test_bmo_retire_values.t new file mode 100644 index 000000000..f6086e0f9 --- /dev/null +++ b/qa/t/test_bmo_retire_values.t @@ -0,0 +1,388 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); +my ($text, $bug_id); + +my $admin_user_login = $config->{admin_user_login}; + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-off" => undef, + "usetargetmilestone-on" => undef}, + "Administrative Policies" => {"allowbugdeletion-on" => undef}, + }); + +# create a clean bug + +file_bug_in_product($sel, "TestProduct"); +$sel->select_ok("component", "label=TestComponent"); +$sel->type_ok("short_desc", "testing testComponent"); +$sel->type_ok("comment", "testing"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $clean_bug_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $clean_bug_id created"); + +# +# component +# +# add a new component to TestProduct + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit components:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select component of product 'TestProduct'"); +$text = trim($sel->get_text("bugzilla-body")); +if ($text =~ /TempComponent/) { + $sel->click_ok("//a[contains(\@href, 'editcomponents.cgi?action=del&product=TestProduct&component=TempComponent')]"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Delete component 'TempComponent' from 'TestProduct' product"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Component Deleted"); +} +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add component to the TestProduct product"); +$sel->type_ok("component", "TempComponent"); +$sel->type_ok("description", "Temp component"); +$sel->type_ok("initialowner", $admin_user_login); +$sel->uncheck_ok("watch_user_auto"); +$sel->type_ok("watch_user", 'tempcomponent@testproduct.bugs'); +$sel->check_ok("watch_user_auto"); +$sel->click_ok('//input[@type="submit" and @value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Created"); + +# create bug into TempComponent + +file_bug_in_product($sel, "TestProduct"); +$sel->select_ok("component", "label=TempComponent"); +$sel->type_ok("short_desc", "testing tempComponent"); +$sel->type_ok("comment", "testing"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$bug_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug_id created"); + +# disable TestProduct:TestComponent for bug entry + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit components:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select component of product 'TestProduct'"); +$sel->click_ok("link=TempComponent"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit component 'TempComponent' of product 'TestProduct'"); +$sel->click_ok("isactive"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Updated"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /Disabled for bugs/, "Component deactivation confirmed"); + +# update bug TempComponent bug + +go_to_bug($sel, $bug_id); +# make sure the component is still tempcomponent +$sel->selected_label_is("component", 'TempComponent'); +# update +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug_id"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +# make sure the component is still tempcomponent +ok($sel->get_selected_labels("component"), 'TempComponent'); + +# try creating new bug with TempComponent + +file_bug_in_product($sel, "TestProduct"); +ok(!$sel->is_element_present( + q#//select[@id='component']/option[@value='TempComponent']#), + 'TempComponent is missing from create'); + +# try changing compoent of existing bug to TempComponent + +go_to_bug($sel, $clean_bug_id); +ok(!$sel->is_element_present( + q#//select[@id='component']/option[@value='TempComponent']#), + 'TempComponent is missing from update'); + +# delete TempComponent + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit components:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok("//a[contains(\@href, 'editcomponents.cgi?action=del&product=TestProduct&component=TempComponent')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete component 'TempComponent' from 'TestProduct' product"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Deleted"); + +# +# version +# + +# add a new version to TestProduct + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit versions:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select version of product 'TestProduct'"); +$text = trim($sel->get_text("bugzilla-body")); +if ($text =~ /TempVersion/) { + $sel->click_ok("//a[contains(\@href, 'editversions.cgi?action=del&product=TestProduct&version=TempVersion')]"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Delete Version of Product 'TestProduct'"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Version Deleted"); +} +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Version to Product 'TestProduct'"); +$sel->type_ok("version", "TempVersion"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Version Created"); + +# create bug with new version + +file_bug_in_product($sel, "TestProduct"); +$sel->select_ok("version", "label=TempVersion"); +$sel->type_ok("short_desc", "testing tempVersion"); +$sel->type_ok("comment", "testing"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$bug_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug_id created"); + +# disable new version for bug entry + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit versions:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select version of product 'TestProduct'"); +$sel->click_ok("link=TempVersion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Version 'TempVersion' of product 'TestProduct'"); +$sel->click_ok("isactive"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Version Updated"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /Disabled for bugs/, "Version deactivation confirmed"); + +# update new version bug + +go_to_bug($sel, $bug_id); +# make sure the version is still tempversion +$sel->selected_label_is("version", 'TempVersion'); +# update +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug_id"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +# make sure the version is still tempversion +$sel->selected_label_is("version", 'TempVersion'); +# change the version so it can be deleted +$sel->select_ok("version", "label=unspecified"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug_id"); + +# try creating new bug with new version + +file_bug_in_product($sel, "TestProduct"); +ok(!$sel->is_element_present( + q#//select[@id='version']/option[@value='TempVersion']#), + 'TempVersion is missing from create'); + +# try changing existing bug to new version + +go_to_bug($sel, $clean_bug_id); +ok(!$sel->is_element_present( + q#//select[@id='version']/option[@value='TempVersion']#), + 'TempVersion is missing from update'); + +# delete new version + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit versions:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select version of product 'TestProduct'"); +$text = trim($sel->get_text("bugzilla-body")); +$sel->click_ok("//a[contains(\@href, 'editversions.cgi?action=del&product=TestProduct&version=TempVersion')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Version of Product 'TestProduct'"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Version Deleted"); + +# +# milestone +# + +# add a milestone to TestProduct + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$text = trim($sel->get_text("bugzilla-body")); +if ($text =~ /TempMilestone/) { + $sel->click_ok("//a[contains(\@href, 'editmilestones.cgi?action=del&product=TestProduct&milestone=TempMilestone')]"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Delete Milestone of Product 'TestProduct'"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Milestone Deleted"); +} +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'TestProduct'"); +$sel->type_ok("milestone", "TempMilestone"); +$sel->type_ok("sortkey", "999"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Created"); + +# create bug with milestone + +file_bug_in_product($sel, "TestProduct"); +$sel->select_ok("target_milestone", "label=TempMilestone"); +$sel->type_ok("short_desc", "testing tempMilestone"); +$sel->type_ok("comment", "testing"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$bug_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug_id created"); + +# disable milestone for bug entry + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$sel->click_ok("link=TempMilestone"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Milestone 'TempMilestone' of product 'TestProduct'"); +$sel->click_ok("isactive"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Updated"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /Disabled for bugs/, "Milestone deactivation confirmed"); + +# update milestone bug + +go_to_bug($sel, $bug_id); +# make sure the milestone is still tempmilestone +$sel->selected_label_is("target_milestone", 'TempMilestone'); +# update +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug_id"); +$sel->click_ok("link=bug $bug_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +# make sure the milestone is still tempmilestone +$sel->selected_label_is("target_milestone", 'TempMilestone'); + +# try creating new bug with milestone + +file_bug_in_product($sel, "TestProduct"); +ok(!$sel->is_element_present( + q#//select[@id='target_milestone']/option[@value='TempMilestone']#), + 'TempMilestone is missing from create'); + +# try changing existing bug to milestone + +go_to_bug($sel, $clean_bug_id); +ok(!$sel->is_element_present( + q#//select[@id='target_milestone']/option[@value='TempMilestone']#), + 'TempMilestone is missing from update'); + +# delete milestone + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'TestProduct'"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$text = trim($sel->get_text("bugzilla-body")); +$sel->click_ok("//a[contains(\@href, 'editmilestones.cgi?action=del&product=TestProduct&milestone=TempMilestone')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Milestone of Product 'TestProduct'"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Deleted"); + +logout($sel); diff --git a/qa/t/test_bug_edit.t b/qa/t/test_bug_edit.t new file mode 100644 index 000000000..64deafcf6 --- /dev/null +++ b/qa/t/test_bug_edit.t @@ -0,0 +1,504 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"usestatuswhiteboard-on" => undef} }); + +# Clear the saved search, in case this test didn't complete previously. +if ($sel->is_text_present("My bugs from QA_Selenium")) { + $sel->click_ok("link=My bugs from QA_Selenium"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Bug List: My bugs from QA_Selenium"); + $sel->click_ok("link=Forget Search 'My bugs from QA_Selenium'"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Search is gone"); + $sel->is_text_present_ok("OK, the My bugs from QA_Selenium search is gone"); +} + +# Just in case the test failed before completion previously, reset the CANEDIT bit. +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Master"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: Master"); +my $group_url = $sel->get_location(); +$group_url =~ /group=(\d+)$/; +my $master_gid = $1; + +clear_canedit_on_testproduct($sel, $master_gid); +logout($sel); + +# First create a bug. + +log_in($sel, $config, 'QA_Selenium_TEST'); +file_bug_in_product($sel, 'TestProduct'); +$sel->select_ok("bug_severity", "label=critical"); +$sel->type_ok("short_desc", "Test bug editing"); +$sel->type_ok("comment", "ploc"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); + +# Now edit field values of the bug you just filed. + +$sel->select_ok("rep_platform", "label=Other"); +$sel->select_ok("op_sys", "label=Other"); +$sel->select_ok("priority", "label=Highest"); +$sel->select_ok("bug_severity", "label=blocker"); +$sel->type_ok("bug_file_loc", "foo.cgi?action=bar"); +$sel->type_ok("status_whiteboard", "[Selenium was here]"); +$sel->type_ok("comment", "new comment from me :)"); +$sel->select_ok("bug_status", "label=RESOLVED"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +# Now move the bug into another product, which has a mandatory group. + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->select_ok("product", "label=QA-Selenium-TEST"); +$sel->type_ok("comment", "moving to QA-Selenium-TEST"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Verify New Product Details..."); +$sel->select_ok("component", "label=QA-Selenium-TEST"); +$sel->is_element_present_ok('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'); +ok(!$sel->is_editable('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'), "QA-Selenium-TEST group not editable"); +$sel->is_checked_ok('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]', "QA-Selenium-TEST group is selected"); +$sel->click_ok("change_product"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->select_ok("bug_severity", "label=normal"); +$sel->select_ok("priority", "label=High"); +$sel->select_ok("rep_platform", "label=All"); +$sel->select_ok("op_sys", "label=All"); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $config->{admin_user_login}); +$sel->type_ok("comment", "Unchecking the reporter_accessible checkbox"); +# This checkbox is checked by default. +$sel->click_ok("reporter_accessible"); +$sel->select_ok("bug_status", "label=VERIFIED"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->type_ok("comment", "I am the reporter, but I can see the bug anyway as I belong to the mandatory group"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# The admin is not in the mandatory group, but he has been CC'ed, +# so he can view and edit the bug (as he has editbugs privs by inheritance). + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->select_ok("bug_severity", "label=blocker"); +$sel->select_ok("priority", "label=Highest"); +$sel->type_ok("status_whiteboard", "[Selenium was here][admin too]"); +$sel->select_ok("bug_status", "label=CONFIRMED"); +$sel->click_ok("bz_assignee_edit_action"); +$sel->type_ok("assigned_to", $config->{admin_user_login}); +$sel->type_ok("comment", "I have editbugs privs. Taking!"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $config->{unprivileged_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# The powerless user can see the restricted bug, as he has been CC'ed. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug1_id); +$sel->is_text_present_ok("I have editbugs privs. Taking!"); +logout($sel); + +# Now turn off cclist_accessible, which will prevent +# the powerless user to see the bug again. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->click_ok("cclist_accessible"); +$sel->type_ok("comment", "I am allowed to turn off cclist_accessible despite not being in the mandatory group"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# The powerless user cannot see the restricted bug anymore. + +log_in($sel, $config, 'unprivileged'); +$sel->type_ok("quicksearch_top", $bug1_id); +$sel->click_ok("find_top"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Access Denied"); +$sel->is_text_present_ok("You are not authorized to access bug #$bug1_id"); +logout($sel); + +# Move the bug back to TestProduct, which has no group restrictions. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->select_ok("product", "label=TestProduct"); +# When selecting a new product, Bugzilla tries to reassign the bug by default, +# so we have to uncheck it. +$sel->click_ok("set_default_assignee"); +$sel->uncheck_ok("set_default_assignee"); +$sel->type_ok("comment", "-> Moving back to Testproduct."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Verify New Product Details..."); +$sel->select_ok("component", "label=TestComponent"); +$sel->is_text_present_ok("These groups are not legal for the 'TestProduct' product or you are not allowed to restrict bugs to these groups"); +$sel->is_element_present_ok('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'); +ok(!$sel->is_editable('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'), "QA-Selenium-TEST group not editable"); +ok(!$sel->is_checked('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'), "QA-Selenium-TEST group not selected"); +$sel->is_element_present_ok('//input[@type="checkbox" and @name="groups" and @value="Master"]'); +$sel->is_editable_ok('//input[@type="checkbox" and @name="groups" and @value="Master"]', "Master group is editable"); +ok(!$sel->is_checked('//input[@type="checkbox" and @name="groups" and @value="Master"]'), "Master group not selected by default"); +$sel->click_ok("change_product"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->click_ok("cclist_accessible"); +$sel->type_ok("comment", "I am allowed to turn off cclist_accessible despite not being in the mandatory group"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# The unprivileged user can view the bug again, but cannot +# edit it, except adding comments. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug1_id); +$sel->type_ok("comment", "I have no privs, I can only comment (and remove people from the CC list)"); +ok(!$sel->is_element_present('//select[@name="product"]'), "Product field not editable"); +ok(!$sel->is_element_present('//select[@name="bug_severity"]'), "Severity field not editable"); +ok(!$sel->is_element_present('//select[@name="priority"]'), "Priority field not editable"); +ok(!$sel->is_element_present('//select[@name="op_sys"]'), "OS field not editable"); +ok(!$sel->is_element_present('//select[@name="rep_platform"]'), "Hardware field not editable"); +$sel->click_ok("cc_edit_area_showhide"); +$sel->add_selection_ok("cc", "label=" . $config->{admin_user_login}); +$sel->click_ok("removecc"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# Now let's test the CANEDIT bit. + +log_in($sel, $config, 'admin'); +edit_product($sel, "TestProduct"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for TestProduct"); +$sel->check_ok("canedit_$master_gid"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Update group access controls for TestProduct"); + +# The user is in the master group, so he can comment. + +go_to_bug($sel, $bug1_id); +$sel->type_ok("comment", "Do nothing except adding a comment..."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# This user is not in the master group, so he cannot comment. + +log_in($sel, $config, 'QA_Selenium_TEST'); +go_to_bug($sel, $bug1_id); +$sel->type_ok("comment", "Just a comment too..."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Edit Access Denied"); +$sel->is_text_present_ok("You are not permitted to edit bugs in product TestProduct."); +logout($sel); + +# Test searches and "format for printing". + +log_in($sel, $config, 'admin'); +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections_ok("bug_status"); +$sel->remove_all_selections_ok("resolution"); +$sel->is_checked_ok("emailassigned_to1"); +$sel->select_ok("emailtype1", "label=is"); +$sel->type_ok("email1", $config->{admin_user_login}); +$sel->check_ok("emailassigned_to2"); +$sel->check_ok("emailqa_contact2"); +$sel->check_ok("emailcc2"); +$sel->select_ok("emailtype2", "label=is"); +$sel->type_ok("email2", $config->{QA_Selenium_TEST_user_login}); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); + +$sel->is_text_present_ok("One bug found."); +$sel->type_ok("save_newqueryname", "My bugs from QA_Selenium"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +$sel->is_text_present_ok("OK, you have a new search named My bugs from QA_Selenium."); +$sel->click_ok("link=My bugs from QA_Selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My bugs from QA_Selenium"); +$sel->click_ok("long_format"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Full Text Bug Listing"); +$sel->is_text_present_ok("Bug $bug1_id"); +$sel->is_text_present_ok("Status: CONFIRMED"); +$sel->is_text_present_ok("Reporter: QA-Selenium-TEST <$config->{QA_Selenium_TEST_user_login}>"); +$sel->is_text_present_ok("Assignee: QA Admin <$config->{admin_user_login}>"); +$sel->is_text_present_ok("Severity: blocker"); +$sel->is_text_present_ok("Priority: Highest"); +$sel->is_text_present_ok("I have no privs, I can only comment"); +logout($sel); + +# Let's create a 2nd bug by this user so that we can test mass-change +# using the saved search the admin just created. + +log_in($sel, $config, 'QA_Selenium_TEST'); +file_bug_in_product($sel, 'TestProduct'); +$sel->select_ok("bug_severity", "label=blocker"); +$sel->type_ok("short_desc", "New bug from me"); +# We turned on the CANEDIT bit for TestProduct. +$sel->type_ok("comment", "I can enter a new bug, but not edit it, right?"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug2_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug2_id created"); + +# Clicking the "Back" button and resubmitting the form again should trigger a suspicous action error. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Enter Bug: TestProduct"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Suspicious Action"); +$sel->is_text_present_ok("you have no valid token for the create_bug action"); +$sel->click_ok('//input[@value="Confirm Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +$sel->type_ok("comment", "New comment not allowed"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Edit Access Denied"); +$sel->is_text_present_ok("You are not permitted to edit bugs in product TestProduct."); +logout($sel); + +# Reassign the newly created bug to the admin. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug2_id); +$sel->click_ok("bz_assignee_edit_action"); +$sel->type_ok("assigned_to", $config->{admin_user_login}); +$sel->type_ok("comment", "Taking!"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug2_id"); + +# Test mass-change. + +$sel->click_ok("link=My bugs from QA_Selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My bugs from QA_Selenium"); +$sel->is_text_present_ok("2 bugs found"); +$sel->click_ok("link=Change Several Bugs at Once"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->click_ok("check_all"); +$sel->type_ok("comment", 'Mass change"'); +$sel->select_ok("bug_status", "label=RESOLVED"); +$sel->select_ok("resolution", "label=WORKSFORME"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugs processed"); + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug1_id /); +$sel->selected_label_is("resolution", "WORKSFORME"); +$sel->select_ok("resolution", "label=INVALID"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug1_id /); +$sel->selected_label_is("resolution", "INVALID"); + +$sel->click_ok("link=History"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Changes made to bug $bug1_id"); +$sel->is_text_present_ok("URL foo.cgi?action=bar"); +$sel->is_text_present_ok("Severity critical blocker"); +$sel->is_text_present_ok("Whiteboard [Selenium was here] [Selenium was here][admin too]"); +$sel->is_text_present_ok("Product QA-Selenium-TEST TestProduct"); +$sel->is_text_present_ok("Status CONFIRMED RESOLVED"); + +# Last step: move bugs to another DB, if the extension is enabled. + +# if ($config->{test_extensions}) { +# set_parameters($sel, { "Bug Moving" => {"move-to-url" => {type => "text", value => 'http://www.foo.com/'}, +# "move-to-address" => {type => "text", value => 'import@foo.com'}, +# "movers" => {type => "text", value => $config->{admin_user_login}} +# } +# }); +# +# # Mass-move has been removed, see 581690. +# # Restore these tests once this bug is fixed. +# # $sel->click_ok("link=My bugs from QA_Selenium"); +# # $sel->wait_for_page_to_load_ok(WAIT_TIME); +# # $sel->title_is("Bug List: My bugs from QA_Selenium"); +# # $sel->is_text_present_ok("2 bugs found"); +# # $sel->click_ok("link=Change Several Bugs at Once"); +# # $sel->wait_for_page_to_load_ok(WAIT_TIME); +# # $sel->title_is("Bug List"); +# # $sel->click_ok("check_all"); +# # $sel->type_ok("comment", "-> moved"); +# # $sel->click_ok('oldbugmove'); +# # $sel->wait_for_page_to_load_ok(WAIT_TIME); +# # $sel->title_is("Bugs processed"); +# # $sel->is_text_present_ok("Bug $bug1_id has been moved to another database"); +# # $sel->is_text_present_ok("Bug $bug2_id has been moved to another database"); +# # $sel->click_ok("link=Bug $bug2_id"); +# # $sel->wait_for_page_to_load_ok(WAIT_TIME); +# # $sel->title_like(qr/^$bug2_id/); +# # $sel->selected_label_is("resolution", "MOVED"); +# +# go_to_bug($sel, $bug2_id); +# $sel->click_ok('oldbugmove'); +# $sel->wait_for_page_to_load_ok(WAIT_TIME); +# $sel->is_text_present_ok("Changes submitted for bug $bug2_id"); +# $sel->click_ok("link=bug $bug2_id"); +# $sel->wait_for_page_to_load_ok(WAIT_TIME); +# $sel->title_like(qr/$bug2_id /); +# $sel->selected_label_is("resolution", "MOVED"); +# $sel->is_text_present_ok("Bug moved to http://www.foo.com/."); +# +# # Disable bug moving again. +# set_parameters($sel, { "Bug Moving" => {"movers" => {type => "text", value => ""}} }); +# } + +# Make sure token checks are working correctly for single bug editing and mass change, +# first with no token, then with an invalid token. + +foreach my $params (["no_token_single_bug", ""], ["invalid_token_single_bug", "&token=1"]) { + my ($comment, $token) = @$params; + $sel->open_ok("/$config->{bugzilla_installation}/process_bug.cgi?id=$bug1_id&comment=$comment$token", + undef, "Edit a single bug with " . ($token ? "an invalid" : "no") . " token"); + $sel->title_is("Suspicious Action"); + $sel->is_text_present_ok($token ? "an invalid token" : "web browser directly"); + $sel->click_ok("confirm"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + $sel->click_ok("link=bug $bug1_id"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_like(qr/^$bug1_id /); + $sel->is_text_present_ok($comment); +} + +foreach my $params (["no_token_mass_change", ""], ["invalid_token_mass_change", "&token=1"]) { + my ($comment, $token) = @$params; + $sel->open_ok("/$config->{bugzilla_installation}/process_bug.cgi?id_$bug1_id=1&id_$bug2_id=1&comment=$comment$token", + undef, "Mass change with " . ($token ? "an invalid" : "no") . " token"); + $sel->title_is("Suspicious Action"); + $sel->is_text_present_ok("no valid token for the buglist_mass_change action"); + $sel->click_ok("confirm"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Bugs processed"); + foreach my $bug_id ($bug1_id, $bug2_id) { + $sel->click_ok("link=bug $bug_id"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_like(qr/^$bug_id /); + $sel->is_text_present_ok($comment); + next if $bug_id == $bug2_id; + $sel->go_back_ok(); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Bugs processed"); + } +} + +# Now move these bugs out of our radar. + +$sel->click_ok("link=My bugs from QA_Selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My bugs from QA_Selenium"); +$sel->is_text_present_ok("2 bugs found"); +$sel->click_ok("link=Change Several Bugs at Once"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->click_ok("check_all"); +$sel->type_ok("comment", "Reassigning to the reporter"); +$sel->type_ok("assigned_to", $config->{QA_Selenium_TEST_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugs processed"); + +# Now delete the saved search. + +$sel->click_ok("link=My bugs from QA_Selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My bugs from QA_Selenium"); +$sel->click_ok("link=Forget Search 'My bugs from QA_Selenium'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$sel->is_text_present_ok("OK, the My bugs from QA_Selenium search is gone"); + +# Reset the CANEDIT bit. We want it to be turned off by default. +clear_canedit_on_testproduct($sel, $master_gid); +logout($sel); + +sub clear_canedit_on_testproduct { + my ($sel, $master_gid) = @_; + + edit_product($sel, "TestProduct"); + $sel->click_ok("link=Edit Group Access Controls:"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Edit Group Controls for TestProduct"); + $sel->uncheck_ok("canedit_$master_gid"); + $sel->click_ok("submit"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Update group access controls for TestProduct"); +} diff --git a/qa/t/test_choose_priority.t b/qa/t/test_choose_priority.t new file mode 100644 index 000000000..a35823327 --- /dev/null +++ b/qa/t/test_choose_priority.t @@ -0,0 +1,27 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Change Policies" => {"letsubmitterchoosepriority-off" => undef} }); +file_bug_in_product($sel, "TestProduct"); +ok(!$sel->is_text_present("Priority"), "The Priority label is not present"); +ok(!$sel->is_element_present("//select[\@name='priority']"), "The Priority drop-down menu is not present"); +set_parameters($sel, { "Bug Change Policies" => {"letsubmitterchoosepriority-on" => undef} }); +file_bug_in_product($sel, "TestProduct"); +$sel->is_text_present_ok("Priority"); +$sel->is_element_present_ok("//select[\@name='priority']"); +logout($sel); diff --git a/qa/t/test_classifications.t b/qa/t/test_classifications.t new file mode 100644 index 000000000..ec5597d9e --- /dev/null +++ b/qa/t/test_classifications.t @@ -0,0 +1,146 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Enable classifications + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-on" => undef} }); + +# Create a new classification. + +go_to_admin($sel); +$sel->click_ok("link=Classifications"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select classification"); + +# Delete old classifications if this script failed. +# Accessing action=delete directly must 1) trigger the security check page, +# and 2) automatically reclassify products in this classification. +if ($sel->is_text_present("cone")) { + $sel->open_ok("/$config->{bugzilla_installation}/editclassifications.cgi?action=delete&classification=cone"); + $sel->title_is("Suspicious Action"); + $sel->click_ok("confirm"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Classification Deleted"); +} +if ($sel->is_text_present("ctwo")) { + $sel->open_ok("/$config->{bugzilla_installation}/editclassifications.cgi?action=delete&classification=ctwo"); + $sel->title_is("Suspicious Action"); + $sel->click_ok("confirm"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Classification Deleted"); +} + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add new classification"); +$sel->type_ok("classification", "cone"); +$sel->type_ok("description", "Classification number 1"); +$sel->click_ok('//input[@type="submit" and @value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Classification Created"); + +# Add TestProduct to the new classification. There should be no other +# products in this classification. + +$sel->select_ok("prodlist", "value=TestProduct"); +$sel->click_ok("add_products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Reclassify products"); +my @products = $sel->get_select_options("myprodlist"); +ok(scalar @products == 1 && $products[0] eq 'TestProduct', "TestProduct successfully added to 'cone'"); + +# Create a new bug in this product/classification. + +file_bug_in_product($sel, 'TestProduct', 'cone'); +$sel->type_ok("short_desc", "Bug in classification cone"); +$sel->type_ok("comment", "Created by Selenium with classifications turned on"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); + +# Rename 'cone' to 'Unclassified', which must be rejected as it already exists, +# then to 'ctwo', which is not yet in use. Should work fine, even with products +# already in it. + +go_to_admin($sel); +$sel->click_ok("link=Classifications"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select classification"); +$sel->click_ok("link=cone"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit classification"); +$sel->type_ok("classification", "Unclassified"); +$sel->click_ok("//input[\@value='Update']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Classification Already Exists"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit classification"); +$sel->type_ok("classification", "ctwo"); +$sel->click_ok("//input[\@value='Update']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Classification Updated"); + +# The classification the bug belongs to is no longer displayed since bug 452733. +# Keeping the code here in case it comes back in a future release. :) +# go_to_bug($sel, $bug1_id); +# $sel->is_text_present_ok('[ctwo]'); + +# Now try to delete the 'ctwo' classification. It should fail as there are +# products in it. + +go_to_admin($sel); +$sel->click_ok("link=Classifications"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select classification"); +$sel->click_ok('//a[@href="editclassifications.cgi?action=del&classification=ctwo"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Error"); +my $error = trim($sel->get_text("error_msg")); +ok($error =~ /there are products for this classification/, "Reject classification deletion"); + +# Reclassify the product before deleting the classification. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select classification"); +$sel->click_ok('//a[@href="editclassifications.cgi?action=reclassify&classification=ctwo"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Reclassify products"); +$sel->add_selection_ok("myprodlist", "label=TestProduct"); +$sel->click_ok("remove_products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Reclassify products"); +$sel->click_ok("link=edit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select classification"); +$sel->click_ok('//a[@href="editclassifications.cgi?action=del&classification=ctwo"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete classification"); +$sel->is_text_present_ok("Do you really want to delete this classification?"); +$sel->click_ok("//input[\@value='Yes, delete']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Classification Deleted"); + +# Disable classifications and make sure you cannot edit them anymore. + +set_parameters($sel, { "Bug Fields" => {"useclassification-off" => undef} }); +$sel->open_ok("/$config->{bugzilla_installation}/editclassifications.cgi"); +$sel->title_is("Classification Not Enabled"); +logout($sel); diff --git a/qa/t/test_config.t b/qa/t/test_config.t new file mode 100644 index 000000000..e2f82fc21 --- /dev/null +++ b/qa/t/test_config.t @@ -0,0 +1,45 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Turn on 'requirelogin' and log out. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"requirelogin-on" => undef} }); +logout($sel); + +# Accessing config.cgi should display no sensitive data. + +$sel->open_ok("/$config->{bugzilla_installation}/config.cgi", undef, "Go to config.cgi (JS format)"); +$sel->is_text_present_ok("var status = [ ];"); +$sel->is_text_present_ok("var status_open = [ ];"); +$sel->is_text_present_ok("var status_closed = [ ];"); +$sel->is_text_present_ok("var resolution = [ ];"); +$sel->is_text_present_ok("var keyword = [ ];"); +$sel->is_text_present_ok("var platform = [ ];"); +$sel->is_text_present_ok("var severity = [ ];"); +$sel->is_text_present_ok("var field = [\n];"); + +ok(!$sel->is_text_present("cf_"), "No custom field displayed"); +ok(!$sel->is_text_present("component["), "No component displayed"); +ok(!$sel->is_text_present("version["), "No version displayed"); +ok(!$sel->is_text_present("target_milestone["), "No target milestone displayed"); + +# Turn on 'requirelogin' and log out. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"requirelogin-off" => undef} }); +logout($sel); diff --git a/qa/t/test_create_user_accounts.t b/qa/t/test_create_user_accounts.t new file mode 100644 index 000000000..18b555aaf --- /dev/null +++ b/qa/t/test_create_user_accounts.t @@ -0,0 +1,129 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Set the email regexp for new bugzilla accounts to end with @bugzilla.test. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"createemailregexp" => {type => "text", value => '[^@]+@bugzilla\.test'}} }); +logout($sel); + +# Create a valid account. We need to randomize the login address, because a request +# expires after 3 days only and this test can be executed several times per day. +my $valid_account = 'selenium-' . random_string(10) . '@bugzilla.test'; + +$sel->is_text_present_ok("Open a New Account"); +$sel->click_ok("link=Open a New Account"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create a new Bugzilla account"); +$sel->type_ok("login", $valid_account); +$sel->click_ok('//input[@value="Create Account"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Request for new user account '$valid_account' submitted"); +$sel->is_text_present_ok("A confirmation email has been sent"); + +# Try creating the same account again. It's too soon. +$sel->click_ok("link=Home"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugzilla Main Page"); +$sel->is_text_present_ok("Open a New Account"); +$sel->click_ok("link=Open a New Account"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create a new Bugzilla account"); +$sel->type_ok("login", $valid_account); +$sel->click_ok('//input[@value="Create Account"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Too Soon For New Token"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /Please wait a while and try again/, "Too soon for this account"); + +# These accounts do not pass the regexp. +my @accounts = ('test@yahoo.com', 'test@bugzilla.net', 'test@bugzilla..test'); +foreach my $account (@accounts) { + $sel->click_ok("link=New Account"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Create a new Bugzilla account"); + $sel->type_ok("login", $account); + $sel->click_ok('//input[@value="Create Account"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Account Creation Restricted"); + $sel->is_text_present_ok("User account creation has been restricted."); +} + +# These accounts are illegal and should cause a javascript alert. +@accounts = qw( + test\bugzilla@bugzilla.test + testbugzilla.test + test@bugzilla + test@bugzilla. + 'test'@bugzilla.test + test&test@bugzilla.test + [test]@bugzilla.test +); +foreach my $account (@accounts) { + $sel->click_ok("link=New Account"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Create a new Bugzilla account"); + $sel->type_ok("login", $account); + $sel->click_ok('//input[@value="Create Account"]'); + ok($sel->get_alert() =~ /The e-mail address doesn't pass our syntax checking for a legal email address/, + 'Invalid email address detected'); +} + +# This account already exists. +$sel->click_ok("link=New Account"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create a new Bugzilla account"); +$sel->type_ok("login", $config->{admin_user_login}); +$sel->click_ok('//input[@value="Create Account"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Account Already Exists"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg eq "There is already an account with the login name $config->{admin_user_login}.", "Account already exists"); + +# Turn off user account creation. +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"createemailregexp" => {type => "text", value => ''}} }); +logout($sel); + +# Make sure that links pointing to createaccount.cgi are all deactivated. +ok(!$sel->is_text_present("New Account"), "No link named 'New Account'"); +$sel->click_ok("link=Home"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugzilla Main Page"); +ok(!$sel->is_text_present("Open a New Account"), "No link named 'Open a New Account'"); +$sel->open_ok("/$config->{bugzilla_installation}/createaccount.cgi"); +$sel->title_is("Account Creation Disabled"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^User account creation has been disabled. New accounts must be created by an administrator/, + "User account creation disabled"); + +# Re-enable user account creation. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"createemailregexp" => {type => "text", value => '.*'}} }); + +# Make sure selenium-<random_string>@bugzilla.test has not be added to the DB yet. +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search users"); +$sel->type_ok("matchstr", $valid_account); +$sel->click_ok("search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select user"); +$sel->is_text_present_ok("0 users found"); +logout($sel); diff --git a/qa/t/test_custom_fields.t b/qa/t/test_custom_fields.t new file mode 100644 index 000000000..7c69e4bbf --- /dev/null +++ b/qa/t/test_custom_fields.t @@ -0,0 +1,459 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); +log_in($sel, $config, 'admin'); + +# Create new bug to test custom fields + +file_bug_in_product($sel, 'TestProduct'); +my $bug_summary = "What's your ID?"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "Use the ID of this bug to generate a unique custom field name."); +$sel->type_ok("bug_severity", "label=normal"); +my $bug1_id = create_bug($sel, $bug_summary); + +# Create custom fields + +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); +$sel->click_ok("link=Add a new custom field"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add a new Custom Field"); +$sel->type_ok("name", "cf_qa_freetext_$bug1_id"); +$sel->type_ok("desc", "Freetext$bug1_id"); +$sel->select_ok("type", "label=Free Text"); +$sel->type_ok("sortkey", $bug1_id); +# These values are off by default. +$sel->value_is("enter_bug", "off"); +$sel->value_is("obsolete", "off"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Created"); +$sel->is_text_present_ok("The new custom field 'cf_qa_freetext_$bug1_id' has been successfully created."); + +$sel->click_ok("link=Add a new custom field"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add a new Custom Field"); +$sel->type_ok("name", "cf_qa_list_$bug1_id"); +$sel->type_ok("desc", "List$bug1_id"); +$sel->select_ok("type", "label=Drop Down"); +$sel->type_ok("sortkey", $bug1_id); +$sel->click_ok("enter_bug"); +$sel->value_is("enter_bug", "on"); +$sel->click_ok("new_bugmail"); +$sel->value_is("new_bugmail", "on"); +$sel->value_is("obsolete", "off"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Created"); +$sel->is_text_present_ok("The new custom field 'cf_qa_list_$bug1_id' has been successfully created."); + +$sel->click_ok("link=Add a new custom field"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add a new Custom Field"); +$sel->type_ok("name", "cf_qa_bugid_$bug1_id"); +$sel->type_ok("desc", "Reference$bug1_id"); +$sel->select_ok("type", "label=Bug ID"); +$sel->type_ok("sortkey", $bug1_id); +$sel->type_ok("reverse_desc", "IsRef$bug1_id"); +$sel->click_ok("enter_bug"); +$sel->value_is("enter_bug", "on"); +$sel->value_is("obsolete", "off"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Created"); +$sel->is_text_present_ok("The new custom field 'cf_qa_bugid_$bug1_id' has been successfully created."); + +# Add values to the custom fields. + +$sel->click_ok("link=cf_qa_list_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_list_$bug1_id' (List$bug1_id)"); +$sel->click_ok("link=Edit legal values for this field"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->type_ok("value", "have fun?"); +$sel->type_ok("sortkey", "805"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); +$sel->is_text_present_ok("The value have fun? has been added as a valid choice for the List$bug1_id (cf_qa_list_$bug1_id) field."); + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->type_ok("value", "storage"); +$sel->type_ok("sortkey", "49"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); +$sel->is_text_present_ok("The value storage has been added as a valid choice for the List$bug1_id (cf_qa_list_$bug1_id) field."); + +# Also create a new bug status and a new resolution. + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=Resolution"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'Resolution' (resolution) field"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'Resolution' (resolution) field"); +$sel->type_ok("value", "UPSTREAM"); +$sel->type_ok("sortkey", 450); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=Status"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'Status' (bug_status) field"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'Status' (bug_status) field"); +$sel->type_ok("value", "SUSPENDED"); +$sel->type_ok("sortkey", 250); +$sel->click_ok("open_status"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'Status' (bug_status) field"); +$sel->type_ok("value", "IN_QA"); +$sel->type_ok("sortkey", 550); +$sel->click_ok("closed_status"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); + +$sel->click_ok("link=status workflow page"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Workflow"); +$sel->click_ok('//td[@title="From UNCONFIRMED to SUSPENDED"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From CONFIRMED to SUSPENDED"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From SUSPENDED to CONFIRMED"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From SUSPENDED to IN_PROGRESS"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From RESOLVED to IN_QA"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From IN_QA to VERIFIED"]//input[@type="checkbox"]'); +$sel->click_ok('//td[@title="From IN_QA to CONFIRMED"]//input[@type="checkbox"]'); +$sel->click_ok('//input[@value="Commit Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Workflow"); + +# Create new bug to test custom fields in bug creation page + +file_bug_in_product($sel, 'TestProduct'); +$sel->is_text_present_ok("List$bug1_id:"); +$sel->is_element_present_ok("cf_qa_list_$bug1_id"); +$sel->is_text_present_ok("Reference$bug1_id:"); +$sel->is_element_present_ok("cf_qa_bugid_$bug1_id"); +ok(!$sel->is_text_present("Freetext$bug1_id:"), "Freetext$bug1_id is not displayed"); +ok(!$sel->is_element_present("cf_qa_freetext_$bug1_id"), "cf_qa_freetext_$bug1_id is not available"); +my $bug_summary2 = "Et de un"; +$sel->type_ok("short_desc", $bug_summary2); +$sel->select_ok("bug_severity", "critical"); +$sel->type_ok("cf_qa_bugid_$bug1_id", $bug1_id); +$sel->type_ok("comment", "hops!"); +my $bug2_id = create_bug($sel, $bug_summary2); + +# Both fields are editable. + +$sel->type_ok("cf_qa_freetext_$bug1_id", "bonsai"); +$sel->selected_label_is("cf_qa_list_$bug1_id", "---"); +$sel->select_ok("bug_status", "label=SUSPENDED"); +edit_bug($sel, $bug2_id); + +go_to_bug($sel, $bug1_id); +$sel->type_ok("cf_qa_freetext_$bug1_id", "dumbo"); +$sel->select_ok("cf_qa_list_$bug1_id", "label=storage"); +$sel->is_text_present_ok("IsRef$bug1_id: $bug2_id"); +$sel->select_ok("bug_status", "RESOLVED"); +$sel->select_ok("resolution", "UPSTREAM"); +edit_bug_and_return($sel, $bug1_id, $bug_summary); +$sel->select_ok("bug_status", "IN_QA"); +edit_bug_and_return($sel, $bug1_id, $bug_summary); + +$sel->click_ok("link=Format For Printing"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Full Text Bug Listing"); +$sel->is_text_present_ok("Freetext$bug1_id: dumbo"); +$sel->is_text_present_ok("List$bug1_id: storage"); +$sel->is_text_present_ok("Status: IN_QA UPSTREAM"); +go_to_bug($sel, $bug2_id); +$sel->select_ok("cf_qa_list_$bug1_id", "label=storage"); +edit_bug($sel, $bug2_id); + +# Test searching for bugs using the custom fields + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections("bug_status"); +$sel->remove_all_selections("resolution"); +$sel->select_ok("f1", "label=List$bug1_id"); +$sel->select_ok("o1", "label=is equal to"); +$sel->type_ok("v1", "storage"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("2 bugs found"); +$sel->is_text_present_ok("What's your ID?"); +$sel->is_text_present_ok("Et de un"); + +# Now edit custom fields in mass changes. + +$sel->click_ok("link=Change Several Bugs at Once"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->click_ok("check_all"); +$sel->select_ok("cf_qa_list_$bug1_id", "label=---"); +$sel->type_ok("cf_qa_freetext_$bug1_id", "thanks"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugs processed"); +$sel->click_ok("link=bug $bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug2_id/); +$sel->value_is("cf_qa_freetext_$bug1_id", "thanks"); +$sel->selected_label_is("cf_qa_list_$bug1_id", "---"); +$sel->select_ok("cf_qa_list_$bug1_id", "label=storage"); +edit_bug($sel, $bug2_id); + +# Let's now test custom field visibility. + +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); +$sel->click_ok("link=cf_qa_list_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_list_$bug1_id' (List$bug1_id)"); +$sel->select_ok("visibility_field_id", "label=Severity (bug_severity)"); +$sel->select_ok("visibility_values", "label=critical"); +$sel->click_ok("edit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Updated"); + +go_to_bug($sel, $bug1_id); +$sel->is_element_present_ok("cf_qa_list_$bug1_id", "List$bug1_id is in the DOM of the page..."); +ok(!$sel->is_visible("cf_qa_list_$bug1_id"), "... but is not displayed with severity = 'normal'"); +$sel->select_ok("bug_severity", "major"); +ok(!$sel->is_visible("cf_qa_list_$bug1_id"), "... nor with severity = 'major'"); +$sel->select_ok("bug_severity", "critical"); +$sel->is_visible_ok("cf_qa_list_$bug1_id", "... but is visible with severity = 'critical'"); +edit_bug_and_return($sel, $bug1_id, $bug_summary); +$sel->is_visible_ok("cf_qa_list_$bug1_id"); + +go_to_bug($sel, $bug2_id); +$sel->is_visible_ok("cf_qa_list_$bug1_id"); +$sel->select_ok("bug_severity", "minor"); +ok(!$sel->is_visible("cf_qa_list_$bug1_id"), "List$bug1_id is not displayed with severity = 'minor'"); +edit_bug_and_return($sel, $bug2_id, $bug_summary2); +ok(!$sel->is_visible("cf_qa_list_$bug1_id"), "List$bug1_id is not displayed with severity = 'minor'"); + +# Add a new value which is only listed under some condition. + +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); +$sel->click_ok("link=cf_qa_list_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_list_$bug1_id' (List$bug1_id)"); +$sel->select_ok("value_field_id", "label=Resolution (resolution)"); +$sel->click_ok("edit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Updated"); +$sel->click_ok("link=cf_qa_list_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_list_$bug1_id' (List$bug1_id)"); +$sel->click_ok("link=Edit legal values for this field"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->type_ok("value", "ghost"); +$sel->type_ok("sortkey", "500"); +$sel->select_ok("visibility_value_id", "label=FIXED"); +$sel->click_ok("id=create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Field Value Created"); + +go_to_bug($sel, $bug1_id); +my @labels = $sel->get_select_options("cf_qa_list_$bug1_id"); +ok(grep(/^ghost$/, @labels), "ghost is in the DOM of the page..."); +my $disabled = $sel->get_attribute("v4_cf_qa_list_$bug1_id\@disabled"); +ok($disabled, "... but is not available for selection by default"); +$sel->select_ok("bug_status", "label=RESOLVED"); +$sel->select_ok("resolution", "label=FIXED"); +$sel->select_ok("cf_qa_list_$bug1_id", "label=ghost"); +edit_bug_and_return($sel, $bug1_id, $bug_summary); +$sel->selected_label_is("cf_qa_list_$bug1_id", "ghost"); + +# Delete an unused field value. + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=List$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->click_ok("//a[contains(\@href, 'editvalues.cgi?action=del&field=cf_qa_list_$bug1_id&value=have%20fun%3F')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'have fun?' from the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->is_text_present_ok("Do you really want to delete this value?"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Field Value Deleted"); + +# This value cannot be deleted as it's in use. + +$sel->click_ok("//a[contains(\@href, 'editvalues.cgi?action=del&field=cf_qa_list_$bug1_id&value=storage')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'storage' from the 'List$bug1_id' (cf_qa_list_$bug1_id) field"); +$sel->is_text_present_ok("There is 1 bug with this field value"); + +# Mark the <select> field as obsolete, making it unavailable in bug reports. + +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); +$sel->click_ok("link=cf_qa_list_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_list_$bug1_id' (List$bug1_id)"); +$sel->click_ok("obsolete"); +$sel->value_is("obsolete", "on"); +$sel->click_ok("edit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Updated"); +go_to_bug($sel, $bug1_id); +$sel->value_is("cf_qa_freetext_$bug1_id", "thanks"); +ok(!$sel->is_element_present("cf_qa_list_$bug1_id"), "The custom list is not visible"); + +# Custom fields are also viewable by logged out users. + +logout($sel); +go_to_bug($sel, $bug1_id); +$sel->is_text_present_ok("Freetext$bug1_id: thanks"); + +# Powerless users should still be able to CC themselves when +# custom fields are in use. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug1_id); +$sel->is_text_present_ok("Freetext$bug1_id: thanks"); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $config->{unprivileged_user_login}); +edit_bug($sel, $bug1_id); +logout($sel); + +# Disable the remaining free text field. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); +$sel->click_ok("link=cf_qa_freetext_$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit the Custom Field 'cf_qa_freetext_$bug1_id' (Freetext$bug1_id)"); +$sel->click_ok("obsolete"); +$sel->value_is("obsolete", "on"); +$sel->click_ok("edit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Field Updated"); + +# Trying to delete a bug status which is in use is forbidden. + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=Status"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'Status' (bug_status) field"); +$sel->click_ok('//a[@href="editvalues.cgi?action=del&field=bug_status&value=SUSPENDED"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'SUSPENDED' from the 'Status' (bug_status) field"); +$sel->is_text_present_ok("Sorry, but the 'SUSPENDED' value cannot be deleted"); + +go_to_bug($sel, $bug2_id); +$sel->select_ok("bug_status", "CONFIRMED"); +edit_bug($sel, $bug2_id); + +go_to_bug($sel, $bug1_id); +$sel->select_ok("bug_status", "VERIFIED"); +$sel->select_ok("resolution", "INVALID"); +edit_bug($sel, $bug1_id); + +# Unused values can be deleted. + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=Status"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'Status' (bug_status) field"); +$sel->click_ok('//a[@href="editvalues.cgi?action=del&field=bug_status&value=SUSPENDED"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'SUSPENDED' from the 'Status' (bug_status) field"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Field Value Deleted"); +$sel->is_text_present_ok("The value SUSPENDED of the Status (bug_status) field has been deleted"); + +$sel->click_ok('//a[@href="editvalues.cgi?action=del&field=bug_status&value=IN_QA"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'IN_QA' from the 'Status' (bug_status) field"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Field Value Deleted"); +$sel->is_text_present_ok("The value IN_QA of the Status (bug_status) field has been deleted"); + +go_to_admin($sel); +$sel->click_ok("link=Field Values"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit values for which field?"); +$sel->click_ok("link=Resolution"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select value for the 'Resolution' (resolution) field"); +$sel->click_ok('//a[@href="editvalues.cgi?action=del&field=resolution&value=UPSTREAM"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Value 'UPSTREAM' from the 'Resolution' (resolution) field"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Field Value Deleted"); +$sel->is_text_present_ok("The value UPSTREAM of the Resolution (resolution) field has been deleted"); + +logout($sel); diff --git a/qa/t/test_custom_fields_admin.t b/qa/t/test_custom_fields_admin.t new file mode 100644 index 000000000..cadb6c157 --- /dev/null +++ b/qa/t/test_custom_fields_admin.t @@ -0,0 +1,53 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); +log_in($sel, $config, 'admin'); + +# Create a custom field, going through each type available, +# mark it as obsolete and delete it immediately. + +go_to_admin($sel); +$sel->click_ok("link=Custom Fields"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Custom Fields"); + +my @types = ("Bug ID", "Large Text Box", "Free Text", "Multiple-Selection Box", + "Drop Down", "Date/Time"); +my $counter = int(rand(10000)); + +foreach my $type (@types) { + my $fname = "cf_field" . ++$counter; + my $fdesc = "Field" . $counter; + + $sel->click_ok("link=Add a new custom field"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Add a new Custom Field"); + $sel->type_ok("name", $fname); + $sel->type_ok("desc", $fdesc); + $sel->select_ok("type", "label=$type"); + $sel->click_ok("obsolete"); + $sel->click_ok("create"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Custom Field Created"); + $sel->click_ok("//a[\@href='editfields.cgi?action=del&name=$fname']"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Delete the Custom Field '$fname' ($fdesc)"); + $sel->click_ok("link=Delete field '$fdesc'"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Custom Field Deleted"); +} + +logout($sel); diff --git a/qa/t/test_default_groups.t b/qa/t/test_default_groups.t new file mode 100644 index 000000000..9875bc847 --- /dev/null +++ b/qa/t/test_default_groups.t @@ -0,0 +1,210 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Turn on the makeproductgroups parameter. Create a new product and check that +# it has automatically a group created for it with the same name. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"makeproductgroups-on" => undef} }); +add_product($sel); +$sel->type_ok("product", "ready_to_die"); +$sel->type_ok("description", "will die"); +$sel->select_ok("default_op_sys_id", "Unspecified"); +$sel->select_ok("default_platform_id", "Unspecified"); +$sel->click_ok('//input[@value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Created"); +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=ready_to_die"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: ready_to_die"); +my $group_url = $sel->get_location(); +$group_url =~ /group=(\d+)/; +my $group1_id = $1; +$sel->value_is("desc", "Access to bugs in the ready_to_die product"); +my @groups = $sel->get_select_options("members_remove"); +ok((grep { $_ eq 'admin' } @groups), "'admin' inherits group membership"); +@groups = $sel->get_select_options("bless_from_remove"); +ok((grep { $_ eq 'admin' } @groups), "'admin' inherits can bless group membership"); +$sel->is_checked_ok("isactive"); + +# Check that the automatically created product group has the membercontrol +# for it set to Default and othercontrol set to NA. + +edit_product($sel, "ready_to_die"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for ready_to_die"); +$sel->value_is("entry_$group1_id", "off"); +$sel->value_is("canedit_$group1_id", "off"); +$sel->selected_label_is("membercontrol_$group1_id", "Default"); +$sel->selected_label_is("othercontrol_$group1_id", "NA"); + +edit_product($sel, "ready_to_die"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok('//a[@href="editproducts.cgi?action=del&product=ready_to_die"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Product 'ready_to_die'"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Deleted"); + +# The product has been deleted, but the group must survive. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->is_text_present_ok("Access to bugs in the ready_to_die product"); + +# Create a new product. As the "ready_to_die" group already exists, +# a new "ready_to_die_" one must be created. + +add_product($sel); +$sel->type_ok("product", "ready_to_die"); +$sel->type_ok("description", "will die"); +$sel->select_ok("default_op_sys_id", "Unspecified"); +$sel->select_ok("default_platform_id", "Unspecified"); +$sel->click_ok('//input[@value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Created"); + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=ready_to_die_"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: ready_to_die_"); +$group_url = $sel->get_location(); +$group_url =~ /group=(\d+)/; +my $group2_id = $1; +$sel->value_is("desc", "Access to bugs in the ready_to_die product"); +@groups = $sel->get_select_options("members_remove"); +ok((grep { $_ eq 'admin' } @groups), "'admin' inherits group membership"); +@groups = $sel->get_select_options("bless_from_remove"); +ok((grep { $_ eq 'admin' } @groups), "'admin' inherits can bless group membership"); +$sel->value_is("isactive", "on"); + +# Check group settings. The old 'ready_to_die' group has no relationship +# with this new product, despite its identical name. + +edit_product($sel, "ready_to_die"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for ready_to_die"); +$sel->value_is("entry_$group1_id", "off"); +$sel->value_is("entry_$group2_id", "off"); +$sel->value_is("canedit_$group1_id", "off"); +$sel->value_is("canedit_$group2_id", "off"); +$sel->selected_label_is("membercontrol_$group1_id", "NA"); +$sel->selected_label_is("othercontrol_$group1_id", "NA"); +$sel->selected_label_is("membercontrol_$group2_id", "Default"); +$sel->selected_label_is("othercontrol_$group2_id", "NA"); + +# Delete the ready_to_die_ group. It's bound to the ready_to_die product, +# so the deletion requires explicit agreement from the admin. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("//a[contains(\@href, 'editgroups.cgi?action=del&group=$group2_id')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete group"); +$sel->is_text_present_ok("This group is tied to the following products"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Cannot Delete Group"); +my $text = trim($sel->get_text("error_msg")); +ok($text =~ qr/All references to this group must be removed/, + "Group ready_to_die_ cannot be deleted as it is bound to a product"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete group"); +$sel->click_ok("unbind"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Group Deleted"); +$text = trim($sel->get_text("message")); +ok($text =~ qr/The group ready_to_die_ has been deleted/, "Group ready_to_die_ has been deleted"); + +edit_product($sel, "ready_to_die"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok('//a[@href="editproducts.cgi?action=del&product=ready_to_die"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Product 'ready_to_die'"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Deleted"); + +# Reset the makeproductgroups parameter. Now creating a new product must +# not create a new group, nor bind any group with it. + +set_parameters($sel, { "Group Security" => {"makeproductgroups-off" => undef} }); +add_product($sel); +$sel->type_ok("product", "ready_to_die"); +$sel->type_ok("description", "will die"); +$sel->select_ok("default_op_sys_id", "Unspecified"); +$sel->select_ok("default_platform_id", "Unspecified"); +$sel->click_ok('//input[@value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Created"); + +# Make sure that all group controls are set to NA for this product. + +edit_product($sel, "ready_to_die"); +$sel->title_is("Edit Product 'ready_to_die'"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for ready_to_die"); +$sel->value_is("entry_$group1_id", "off"); +$sel->value_is("canedit_$group1_id", "off"); +$sel->selected_label_is("membercontrol_$group1_id", "NA"); +$sel->selected_label_is("othercontrol_$group1_id", "NA"); + +# Delete remaining groups and products. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +ok(!$sel->is_text_present('ready_to_die__'), 'No ready_to_die__ group created'); +$sel->click_ok("//a[contains(\@href, 'editgroups.cgi?action=del&group=$group1_id')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete group"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Group Deleted"); +$text = trim($sel->get_text("message")); +ok($text =~ /The group ready_to_die has been deleted/, "Group ready_to_die has been deleted"); + +edit_product($sel, "ready_to_die"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok('//a[@href="editproducts.cgi?action=del&product=ready_to_die"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Product 'ready_to_die'"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Deleted"); +logout($sel); diff --git a/qa/t/test_dependencies.t b/qa/t/test_dependencies.t new file mode 100644 index 000000000..f842b5fcd --- /dev/null +++ b/qa/t/test_dependencies.t @@ -0,0 +1,53 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Let's create a public and a private bug. + +log_in($sel, $config, 'admin'); +file_bug_in_product($sel, "TestProduct"); +my $bug_summary = "Dependency Checks"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "This bug is public"); +my $bug1_id = create_bug($sel, $bug_summary); + +file_bug_in_product($sel, "TestProduct"); +$sel->type_ok("alias", "secret_qa_bug_$bug1_id+1"); +my $bug_summary2 = "Big Ben"; +$sel->type_ok("short_desc", $bug_summary2); +$sel->type_ok("comment", "This bug is private"); +$sel->type_ok("dependson", $bug1_id); +$sel->check_ok('//input[@name="groups" and @value="Master"]'); +my $bug2_id = create_bug($sel, $bug_summary2); + +go_to_bug($sel, $bug1_id); +$sel->click_ok("link=Mark as Duplicate"); +$sel->type_ok("dup_id", $bug2_id); +edit_bug_and_return($sel, $bug1_id, $bug_summary); +$sel->is_text_present_ok("secret_qa_bug_$bug1_id+1"); +logout($sel); + +# A user with editbugs privs who cannot see some bugs in the dependency list +# or the bug this duplicate points to should still be able to edit this bug. + +log_in($sel, $config, 'editbugs'); +go_to_bug($sel, $bug1_id); +ok(!$sel->is_text_present("secret_qa_bug_$bug1_id+1"), "The alias of the private bug is not visible"); +$sel->select_ok("priority", "label=High"); +$sel->select_ok("bug_status", "VERIFIED"); +$sel->type_ok("comment", "Can I still edit this bug?"); +edit_bug($sel, $bug1_id); +logout($sel); diff --git a/qa/t/test_edit_products_properties.t b/qa/t/test_edit_products_properties.t new file mode 100644 index 000000000..7b3eabc19 --- /dev/null +++ b/qa/t/test_edit_products_properties.t @@ -0,0 +1,361 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +my $admin_user_login = $config->{admin_user_login}; +my $unprivileged_user_login = $config->{unprivileged_user_login}; +my $permanent_user = $config->{permanent_user}; + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-off" => undef, + "usetargetmilestone-on" => undef}, + "Administrative Policies" => {"allowbugdeletion-on" => undef} + }); + +# Create a product and add components to it. Do some cleanup first +# if the script failed during a previous run. + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +# No risk to get the "Select classification" page. We turned off useclassification. +$sel->title_is("Select product"); + +my $text = trim($sel->get_text("bugzilla-body")); +if ($text =~ /(Kill me!|Kill me nicely)/) { + my $product = $1; + my $escaped_product = url_quote($product); + $sel->click_ok("//a[\@href='editproducts.cgi?action=del&product=$escaped_product']"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Delete Product '$product'"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Product Deleted"); +} + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Product"); +$sel->type_ok("product", "Kill me!"); +$sel->type_ok("description", "I will disappear very soon. Do not add bugs to it."); +$sel->type_ok("defaultmilestone", "0.1a"); +# Since Bugzilla 4.0, the voting system is in an extension. +if ($config->{test_extensions}) { + $sel->type_ok("votesperuser", "1"); + $sel->type_ok("maxvotesperbug", "1"); + $sel->type_ok("votestoconfirm", "10"); +} +$sel->type_ok("version", "0.1a"); +$sel->select_ok("default_op_sys_id", "Unspecified"); +$sel->select_ok("default_platform_id", "Unspecified"); +$sel->click_ok('//input[@type="submit" and @value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$text = trim($sel->get_text("message")); +ok($text =~ /You will need to add at least one component before anyone can enter bugs against this product/, + "Display a reminder about missing components"); +$sel->click_ok("link=add at least one component"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add component to the Kill me! product"); +$sel->type_ok("component", "first comp"); +$sel->type_ok("description", "comp 1"); +$sel->type_ok("initialowner", $admin_user_login); +$sel->uncheck_ok("watch_user_auto"); +$sel->type_ok("watch_user", "first-comp\@kill-me.bugs"); +$sel->check_ok("watch_user_auto"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Created"); +$text = trim($sel->get_text("message")); +ok($text eq 'The component first comp has been created.', "Component successfully created"); + +# Try creating a second component with the same name. + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add component to the Kill me! product"); +$sel->type_ok("component", "first comp"); +$sel->type_ok("description", "comp 2"); +$sel->type_ok("initialowner", $admin_user_login); +$sel->uncheck_ok("watch_user_auto"); +$sel->type_ok("watch_user", "first-comp\@kill-me.bugs"); +$sel->check_ok("watch_user_auto"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Already Exists"); + +# Now really create a second component, with a distinct name. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->type_ok("component", "second comp"); +# FIXME - Re-enter the default assignee (regression due to bug 577574) +$sel->type_ok("initialowner", $admin_user_login); +$sel->type_ok("initialcc", $permanent_user); +$sel->uncheck_ok("watch_user_auto"); +$sel->type_ok("watch_user", "second-comp\@kill-me.bugs"); +$sel->check_ok("watch_user_auto"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Created"); + +# Add a new version. + +edit_product($sel, "Kill me!"); +$sel->click_ok("//a[contains(text(),'Edit\nversions:')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select version of product 'Kill me!'"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->type_ok("version", "0.1"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Version Created"); + +# Add a new milestone. + +$sel->click_ok("link='Kill me!'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'Kill me!'"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select milestone of product 'Kill me!'"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'Kill me!'"); +$sel->type_ok("milestone", "0.2"); +$sel->type_ok("sortkey", "2"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Created"); + +# Add another milestone. + +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'Kill me!'"); +$sel->type_ok("milestone", "0.1a"); +# Negative sortkeys are valid for milestones. +$sel->type_ok("sortkey", "-2"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Already Exists"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->type_ok("milestone", "pre-0.1"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Created"); + +# Now create an UNCONFIRMED bug and add it to the newly created product. + +file_bug_in_product($sel, "Kill me!"); +$sel->select_ok("version", "label=0.1a"); +$sel->select_ok("component", "label=first comp"); +# UNCONFIRMED must be present. +$sel->select_ok("bug_status", "label=UNCONFIRMED"); +$sel->type_ok("cc", $unprivileged_user_login); +$sel->type_ok("bug_file_loc", "http://www.test.com"); +$sel->type_ok("short_desc", "test create/edit product properties"); +$sel->type_ok("comment", "this bug will soon be dead"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $bug1_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +my @cc_list = $sel->get_select_options("cc"); +ok(grep($_ eq $unprivileged_user_login, @cc_list), "$unprivileged_user_login correctly added to the CC list"); +ok(!grep($_ eq $permanent_user, @cc_list), "$permanent_user not in the CC list for 'first comp' by default"); + +# File a second bug, and make sure users in the default CC list are added. +file_bug_in_product($sel, "Kill me!"); +$sel->select_ok("version", "label=0.1a"); +$sel->select_ok("component", "label=second comp"); +$sel->type_ok("short_desc", "check default CC list"); +$sel->type_ok("comment", "is the CC list populated correctly?"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +@cc_list = $sel->get_select_options("cc"); +ok(grep($_ eq $permanent_user, @cc_list), "$permanent_user in the CC list for 'second comp' by default"); + +# Edit product properties and set votes_to_confirm to 0, which has +# the side-effect to disable auto-confirmation (new behavior compared +# to Bugzilla 3.4 and older). + +edit_product($sel, "Kill me!"); +$sel->type_ok("product", "Kill me nicely"); +$sel->type_ok("description", "I will disappear very soon. Do not add bugs to it (except for testing)."); +$sel->select_ok("defaultmilestone", "label=0.2"); +if ($config->{test_extensions}) { + $sel->type_ok("votesperuser", "2"); + $sel->type_ok("maxvotesperbug", 5); + $sel->type_ok("votestoconfirm", "0"); +} +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Updating Product 'Kill me nicely'"); +$sel->is_text_present_ok("Updated product name from 'Kill me!' to 'Kill me nicely'"); +$sel->is_text_present_ok("Updated description"); +$sel->is_text_present_ok("Updated default milestone"); +if ($config->{test_extensions}) { + $sel->is_text_present_ok("Updated votes per user"); + $sel->is_text_present_ok("Updated maximum votes per bug"); + $sel->is_text_present_ok("Updated number of votes needed to confirm a bug"); + $text = trim($sel->get_text("bugzilla-body")); + # We use .{1} in place of the right arrow character, which fails otherwise. + ok($text =~ /Checking unconfirmed bugs in this product for any which now have sufficient votes\.{3} .{1}there were none/, + "No bugs confirmed by popular votes (votestoconfirm = 0 disables auto-confirmation)"); + + # Now set votestoconfirm to 2, vote for a bug, and then set + # this attribute back to 1, to trigger auto-confirmation. + + $sel->click_ok("link=Kill me nicely"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Edit Product 'Kill me nicely'", "Display properties of Kill me nicely"); + $sel->type_ok("votestoconfirm", 2); + $sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Updating Product 'Kill me nicely'"); + $sel->is_text_present_ok("Updated number of votes needed to confirm a bug"); + + go_to_bug($sel, $bug1_id); + $sel->click_ok("link=vote"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Change Votes"); + $sel->type_ok("bug_$bug1_id", 1); + $sel->click_ok("change"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Change Votes"); + $sel->is_text_present_ok("The changes to your votes have been saved"); + + edit_product($sel, "Kill me nicely"); + $sel->type_ok("votestoconfirm", 1); + $sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Updating Product 'Kill me nicely'"); + $sel->is_text_present_ok("Updated number of votes needed to confirm a bug"); + $text = trim($sel->get_text("bugzilla-body")); + ok($text =~ /Bug $bug1_id confirmed by number of votes/, "Bug $bug1_id is confirmed by popular votes"); +} + +# Edit the bug. + +go_to_bug($sel, $bug1_id); +$sel->selected_label_is("product", "Kill me nicely"); +$sel->selected_label_is("bug_status", "CONFIRMED") if $config->{test_extensions}; +$sel->select_ok("target_milestone", "label=pre-0.1"); +$sel->select_ok("component", "label=second comp"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug1_id /); +@cc_list = $sel->get_select_options("cc"); +ok(grep($_ eq $permanent_user, @cc_list), "User $permanent_user automatically added to the CC list"); + +# Delete the milestone the bug belongs to. This should retarget the bug +# to the default milestone. + +edit_product($sel, "Kill me nicely"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select milestone of product 'Kill me nicely'"); +$sel->click_ok('//a[@href="editmilestones.cgi?action=del&product=Kill%20me%20nicely&milestone=pre-0.1"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Milestone of Product 'Kill me nicely'"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /There is 1 bug entered for this milestone/, "Warning displayed"); +ok($text =~ /Do you really want to delete this milestone\?/, "Requesting confirmation"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Deleted"); +$text = trim($sel->get_text("message")); +ok($text =~ /Bugs targetted to this milestone have been retargetted to the default milestone/, "Bug retargetted"); + +# Try deleting the version used by the bug. This action must be rejected. + +$sel->click_ok("link='Kill me nicely'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'Kill me nicely'"); +$sel->click_ok("//a[contains(text(),'Edit\nversions:')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select version of product 'Kill me nicely'"); +$sel->click_ok("//a[contains(\@href, 'editversions.cgi?action=del&product=Kill%20me%20nicely&version=0.1a')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Version of Product 'Kill me nicely'"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /Sorry, there are 2 bugs outstanding for this version/, "Rejecting version deletion"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); + +# Delete an unused version. The action must succeed. + +$sel->click_ok('//a[@href="editversions.cgi?action=del&product=Kill%20me%20nicely&version=0.1"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Version of Product 'Kill me nicely'"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /Do you really want to delete this version\?/, "Requesting confirmation"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Version Deleted"); + +# Delete the component the bug belongs to. The action must succeed. + +$sel->click_ok("link='Kill me nicely'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'Kill me nicely'"); +$sel->click_ok("link=Edit components:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select component of product 'Kill me nicely'"); +$sel->click_ok("//a[contains(\@href, 'editcomponents.cgi?action=del&product=Kill%20me%20nicely&component=second%20comp')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete component 'second comp' from 'Kill me nicely' product"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /There are 2 bugs entered for this component/, "Warning displayed"); +ok($text =~ /Do you really want to delete this component\?/, "Requesting confirmation"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Deleted"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /The component second comp has been deleted/, "Component deletion confirmed"); +ok($text =~ /All bugs being in this component and all references to them have also been deleted/, + "Bug deletion confirmed"); + +# Only one value for component, version and milestone available. They should +# be selected by default. + +file_bug_in_product($sel, "Kill me nicely"); +$sel->type_ok("short_desc", "bye bye everybody!"); +$sel->type_ok("comment", "I'm dead :("); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); + +# Now delete the product. + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok("//a[\@href='editproducts.cgi?action=del&product=Kill%20me%20nicely']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Product 'Kill me nicely'"); +$text = trim($sel->get_text("bugzilla-body")); +ok($text =~ /There is 1 bug entered for this product/, "Warning displayed"); +ok($text =~ /Do you really want to delete this product\?/, "Confirmation request displayed"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Deleted"); +logout($sel); diff --git a/qa/t/test_email_preferences.t b/qa/t/test_email_preferences.t new file mode 100644 index 000000000..cc314ea2c --- /dev/null +++ b/qa/t/test_email_preferences.t @@ -0,0 +1,400 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Used to test sent bugmails +my @email_both = ($config->{admin_user_login}, $config->{editbugs_user_login}); +my @email_admin = ($config->{admin_user_login}); +my @email_normal = ($config->{editbugs_user_login}); + +# Test script to test email preferences. +# For reference, following bugmail and request mails should be generated. +# +# Admin should get following bugmails (in order): +# 1) A bug is created +# 2) Normal user adds a CC for itself +# 3) Admin removes CC of normal user +# 4) Admin assigns the bug to itself +# 5) Admin requests a flag from normal user +# 6) Admin grants a flag requested from itself +# 7) Normal user set severity to normal +# 8) Normal user adds a comment #3 +# 9) Normal user assigns the bug to itself +# Normal User should get following bugmail (in order): +# 1) A bug is created +# 2) Normal user sets severity to blocker +# 3) Admin sets severity to trivial +# 4) Admin adds a comment #2 +# 5) Admin removes CC of normal user +# 6) Admin assigns the bug to itself +# 7) Normal user sets severity to normal +# +# Admin should get following request mails (in order): +# 1) Normal user denies a flag requested by the admin +# Normal user should get following request mails (in order): +# 1) Admin requests a flag from normal user +# +# NOTE that only correct bugmail is verified by the test script because +# sending request mail is not indicated on the UI. + +# Set admin Email Prefs (via link in footer) +log_in($sel, $config, 'admin'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Email Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Email Preferences"); +$sel->click_ok("//input[\@value='Disable All Bugmail']"); +$sel->click_ok("email-0-1", undef, 'Set "I\'m added to or removed from this capacity" for Assignee role'); +$sel->click_ok("email-0-5", undef, 'Set "The priority, status, severity, or milestone changes" for Assignee role'); +$sel->click_ok("email-0-2", undef, 'Set "New comments are added" for Assignee role'); +$sel->click_ok("email-0-0", undef, 'Set "Any field not mentioned above changes" for Assignee role'); +$sel->click_ok("email-3-8", undef, 'Set "The CC field changes" for CCed role'); +$sel->click_ok("email-1-10", undef, 'Set "A new bug is created" for QA Contact role'); +$sel->click_ok("email-100-101", undef, 'Set "Email me when someone sets a flag I asked for" global option'); +# Restore the old 4.2 behavior for 'Disable All Mail'. +foreach my $col (0..3) { + foreach my $row (50..51) { + $sel->click_ok("neg-email-$col-$row"); + } +} +$sel->value_is("email-0-1", "on"); +$sel->value_is("email-0-10", "off"); +$sel->value_is("email-0-6", "off"); +$sel->value_is("email-0-5", "on"); +$sel->value_is("email-0-2", "on"); +$sel->value_is("email-0-3", "off"); +$sel->value_is("email-0-4", "off"); +$sel->value_is("email-0-7", "off"); +$sel->value_is("email-0-8", "off"); +$sel->value_is("email-0-9", "off"); +$sel->value_is("email-0-0", "on"); +$sel->value_is("neg-email-0-50", "off"); +$sel->value_is("neg-email-0-51", "off"); +$sel->value_is("email-1-1", "off"); +$sel->value_is("email-1-10", "on"); +$sel->value_is("email-1-6", "off"); +$sel->value_is("email-1-5", "off"); +$sel->value_is("email-1-2", "off"); +$sel->value_is("email-1-3", "off"); +$sel->value_is("email-1-4", "off"); +$sel->value_is("email-1-7", "off"); +$sel->value_is("email-1-8", "off"); +$sel->value_is("email-1-9", "off"); +$sel->value_is("email-1-0", "off"); +$sel->value_is("neg-email-1-50", "off"); +$sel->value_is("neg-email-1-51", "off"); +ok(!$sel->is_editable("email-2-1"), 'The "I\'m added to or removed from this capacity" for Reporter role is disabled'); +$sel->value_is("email-2-10", "off"); +$sel->value_is("email-2-6", "off"); +$sel->value_is("email-2-5", "off"); +$sel->value_is("email-2-2", "off"); +$sel->value_is("email-2-3", "off"); +$sel->value_is("email-2-4", "off"); +$sel->value_is("email-2-7", "off"); +$sel->value_is("email-2-8", "off"); +$sel->value_is("email-2-9", "off"); +$sel->value_is("email-2-0", "off"); +$sel->value_is("neg-email-2-50", "off"); +$sel->value_is("neg-email-2-51", "off"); +$sel->value_is("email-3-1", "off"); +$sel->value_is("email-3-10", "off"); +$sel->value_is("email-3-6", "off"); +$sel->value_is("email-3-5", "off"); +$sel->value_is("email-3-2", "off"); +$sel->value_is("email-3-3", "off"); +$sel->value_is("email-3-4", "off"); +$sel->value_is("email-3-7", "off"); +$sel->value_is("email-3-8", "on"); +$sel->value_is("email-3-9", "off"); +$sel->value_is("email-3-0", "off"); +$sel->value_is("neg-email-3-50", "off"); +$sel->value_is("neg-email-3-51", "off"); +$sel->value_is("email-100-100", "off"); +$sel->value_is("email-100-101", "on"); +$sel->click_ok("update", undef, "Submit modified admin email preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("The changes to your email preferences have been saved."); + +# Set "After changing a bug" default preference to "Show the updated bug" +# This simplifies bug changes below +go_to_admin($sel); +$sel->click_ok("link=Default Preferences"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Default Preferences"); +$sel->check_ok("post_bug_submit_action-enabled"); +$sel->select_ok("post_bug_submit_action", "label=Show the updated bug"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Default Preferences"); + +# Set normal user Email Prefs (by directly going to Email Prefs pane) +logout($sel); +log_in($sel, $config, 'editbugs'); +$sel->open_ok("$config->{bugzilla_installation}/userprefs.cgi?tab=email"); +$sel->is_text_present_ok("Email Preferences"); +$sel->click_ok("//input[\@value='Enable All Bugmail']"); +$sel->click_ok("email-3-1", undef, 'Clear "I\'m added to or removed from this capacity" for CCed role'); +$sel->click_ok("email-3-5", undef, 'Clear "The priority, status, severity, or milestone changes" for CCed role'); +$sel->click_ok("email-2-2", undef, 'Clear "New comments are added" for Reporter role'); +$sel->click_ok("email-3-2", undef, 'Clear "New comments are added" for CCed role'); +$sel->click_ok("email-2-8", undef, 'Clear "The CC field changes" for Reporter role'); +$sel->click_ok("email-3-8", undef, 'Clear "The CC field changes" for CCed role'); +$sel->click_ok("email-2-0", undef, 'Clear "Any field not mentioned above changes" for Reporter role'); +$sel->click_ok("email-3-0", undef, 'Clear "Any field not mentioned above changes" for CCed role'); +$sel->click_ok("neg-email-0-51", undef, 'Set "Change was made by me" override for Assignee role'); +$sel->click_ok("email-100-101", undef, 'Clear "Email me when someone sets a flag I asked for" global option'); +$sel->value_is("email-0-1", "on"); +$sel->value_is("email-0-10", "on"); +$sel->value_is("email-0-6", "on"); +$sel->value_is("email-0-5", "on"); +$sel->value_is("email-0-2", "on"); +$sel->value_is("email-0-3", "on"); +$sel->value_is("email-0-4", "on"); +$sel->value_is("email-0-7", "on"); +$sel->value_is("email-0-8", "on"); +$sel->value_is("email-0-9", "on"); +$sel->value_is("email-0-0", "on"); +$sel->value_is("neg-email-0-50", "off"); +$sel->value_is("neg-email-0-51", "on"); +$sel->value_is("email-1-1", "on"); +$sel->value_is("email-1-10", "on"); +$sel->value_is("email-1-6", "on"); +$sel->value_is("email-1-5", "on"); +$sel->value_is("email-1-2", "on"); +$sel->value_is("email-1-3", "on"); +$sel->value_is("email-1-4", "on"); +$sel->value_is("email-1-7", "on"); +$sel->value_is("email-1-8", "on"); +$sel->value_is("email-1-9", "on"); +$sel->value_is("email-1-0", "on"); +$sel->value_is("neg-email-1-50", "off"); +$sel->value_is("neg-email-1-51", "off"); +ok(!$sel->is_editable("email-2-1"), 'The "I\'m added to or removed from this capacity" for Reporter role is disabled'); +$sel->value_is("email-2-10", "on"); +$sel->value_is("email-2-6", "on"); +$sel->value_is("email-2-5", "on"); +$sel->value_is("email-2-2", "off"); +$sel->value_is("email-2-3", "on"); +$sel->value_is("email-2-4", "on"); +$sel->value_is("email-2-7", "on"); +$sel->value_is("email-2-8", "off"); +$sel->value_is("email-2-9", "on"); +$sel->value_is("email-2-0", "off"); +$sel->value_is("neg-email-2-50", "off"); +$sel->value_is("neg-email-2-51", "off"); +$sel->value_is("email-3-1", "off"); +$sel->value_is("email-3-10", "on"); +$sel->value_is("email-3-6", "on"); +$sel->value_is("email-3-5", "off"); +$sel->value_is("email-3-2", "off"); +$sel->value_is("email-3-3", "on"); +$sel->value_is("email-3-4", "on"); +$sel->value_is("email-3-7", "on"); +$sel->value_is("email-3-8", "off"); +$sel->value_is("email-3-9", "on"); +$sel->value_is("email-3-0", "off"); +$sel->value_is("neg-email-3-50", "off"); +$sel->value_is("neg-email-3-51", "off"); +$sel->value_is("email-100-100", "on"); +$sel->value_is("email-100-101", "off"); +$sel->click_ok("update", undef, "Submit modified normal user email preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("The changes to your email preferences have been saved."); + +# Always show email recipients +ok($sel->create_cookie('show_bugmail_recipients=1'), 'Always show recipient list'); + +# Create a test bug (bugmail to both normal user and admin) +file_bug_in_product($sel, "Another Product"); +$sel->select_ok("component", "label=c1"); +$sel->type_ok("short_desc", "Selenium Email Preference test bug", "Enter bug summary"); +$sel->type_ok("comment", "Created by Selenium to test Email Preferences", "Enter bug description"); +$sel->type_ok("assigned_to", $config->{editbugs_user_login}); +$sel->type_ok("qa_contact", $config->{admin_user_login}); +$sel->type_ok("cc", $config->{admin_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug1_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); +my @email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_both, "Admin and normal user got bugmail"); + +# Make normal user changes (first pass) +# +go_to_bug($sel, $bug1_id); +# Severity change (bugmail to normal user but not admin) +$sel->select_ok("bug_severity", "label=blocker"); +$sel->selected_label_is("bug_severity", "blocker"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_normal, "Normal user got bugmail"); +# Add a comment (bugmail to no one) +$sel->type_ok("comment", "This is a Selenium generated normal user test comment 1 of 2. (No bugmail should be generated for this.)"); +$sel->value_is("comment", "This is a Selenium generated normal user test comment 1 of 2. (No bugmail should be generated for this.)"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +ok($email_sentto[0] eq "no one", "No bugmail sent"); +# Add normal user to CC list (bugmail to admin but not normal user) +$sel->type_ok("newcc", $config->{editbugs_user_login}); +$sel->value_is("newcc", $config->{editbugs_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_admin, "Admin got bugmail"); +# Request a flag from admin (bugmail to no one, request mail to no one) +$sel->select_ok("flag_type-4", "label=?"); +$sel->type_ok("requestee_type-4", $config->{admin_user_login}); +$sel->value_is("requestee_type-4", $config->{admin_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +ok($email_sentto[0] eq "no one", "No bugmail sent"); + +# Make admin changes +# +logout($sel); +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +# Severity change (bugmail to normal user but not admin) +$sel->select_ok("bug_severity", "label=trivial"); +$sel->selected_label_is("bug_severity", "trivial"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_normal, "Normal user got bugmail"); +# Add a comment (bugmail to normal user but not admin) +$sel->type_ok("comment", "This is a Selenium generated admin user test comment. (Only normal user should get bugmail for this.)"); +$sel->value_is("comment", "This is a Selenium generated admin user test comment. (Only normal user should get bugmail for this.)"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_normal, "Normal user got bugmail"); +# Remove normal user from CC list (bugmail to both normal user and admin) +$sel->click_ok("removecc"); +$sel->add_selection_ok("cc", "label=$config->{editbugs_user_login}"); +$sel->value_is("removecc", "on"); +$sel->selected_label_is("cc", $config->{editbugs_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_both, "Admin and normal user got bugmail"); +# Reassign bug to admin user (bugmail to both normal user and admin) +$sel->type_ok("assigned_to", $config->{admin_user_login}); +$sel->value_is("assigned_to", $config->{admin_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_both, "Admin and normal user got bugmail"); +# Request a flag from normal user (bugmail to admin but not normal user and request mail to admin) +$sel->select_ok("flag_type-4", "label=?"); +$sel->type_ok("requestee_type-4", $config->{editbugs_user_login}); +$sel->value_is("requestee_type-4", $config->{editbugs_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_admin, "Admin got bugmail"); +# Grant a normal user flag request (bugmail to admin but not normal user and request mail to no one) +my $flag1_id = set_flag($sel, $config->{admin_user_login}, "?", "+"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_admin, "Admin got bugmail"); + +# Make normal user changes (second pass) +# +logout($sel); +log_in($sel, $config, 'editbugs'); +go_to_bug($sel, $bug1_id); +# Severity change (bugmail to both admin and normal user) +$sel->select_ok("bug_severity", "label=normal"); +$sel->selected_label_is("bug_severity", "normal"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_both, "Admin and normal user got bugmail"); +# Add a comment (bugmail to admin but not normal user) +$sel->type_ok("comment", "This is a Selenium generated normal user test comment 2 of 2. (Only admin should get bugmail for this.)"); +$sel->value_is("comment", "This is a Selenium generated normal user test comment 2 of 2. (Only admin should get bugmail for this.)"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_admin, "Admin got bugmail"); +# Reassign to normal user (bugmail to admin but not normal user) +$sel->type_ok("assigned_to", $config->{editbugs_user_login}); +$sel->value_is("assigned_to", $config->{editbugs_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +@email_sentto = get_email_sentto($sel); +is_deeply(\@email_sentto, \@email_admin, "Admin got bugmail"); +# Deny a flag requested by admin (bugmail to no one and request mail to admin) +my $flag2_id = set_flag($sel, $config->{editbugs_user_login}, "?", "-"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +@email_sentto = get_email_sentto($sel); +ok($email_sentto[0] eq "no one", "No bugmail sent"); +# Cancel both flags (bugmail and request mail to no one) +set_flag($sel, undef, "+", "X", $flag1_id); +set_flag($sel, undef, "-", "X", $flag2_id); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +@email_sentto = get_email_sentto($sel); +ok($email_sentto[0] eq "no one", "No bugmail sent"); +logout($sel); + +# Help functions +sub get_email_sentto { + my ($sel) = @_; + my @email_sentto; + my $index = 1; + while ($sel->is_element_present("//dt[text()='Email sent to:']/following-sibling::dd/code[$index]")) { + push(@email_sentto, + $sel->get_text("//dt[text()='Email sent to:']/following-sibling::dd/code[$index]")); + $index++; + } + return ("no one") if !@email_sentto; + return sort @email_sentto; +} + +sub set_flag { + my ($sel, $login, $curval, $newval, $prev_id) = @_; + + # Retrieve flag id for the flag to be set + my $flag_id = $prev_id; + if (defined $login) { + my $flag_name = $sel->get_attribute("//table[\@id='flags']//input[\@value='$login']\@name"); + $flag_name =~ /^requestee-(\d+)$/; + $flag_id = $1; + } + + # Set new value for the flag (verifies current value) + $sel->select_ok("//select[\@id=\"flag-$flag_id\"]/option[\@value=\"$curval\" and \@selected]/..", "value=$newval", "Set flag ID $flag_id to $newval from $curval"); + + return $flag_id; +} diff --git a/qa/t/test_enter_new_bug.t b/qa/t/test_enter_new_bug.t new file mode 100644 index 000000000..b7ac92461 --- /dev/null +++ b/qa/t/test_enter_new_bug.t @@ -0,0 +1,35 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Very simple test script to test if bug creation with minimal data +# passes successfully for different user privileges. +# +# More elaborate tests exist in other scripts. This doesn't mean this +# one could not be improved a bit. + +foreach my $user (qw(admin unprivileged canconfirm)) { + log_in($sel, $config, $user); + file_bug_in_product($sel, "TestProduct"); + $sel->type_ok("short_desc", "Bug created by Selenium", + "Enter bug summary"); + $sel->type_ok("comment", "--- Bug created by Selenium ---", + "Enter bug description"); + $sel->click_ok("commit", undef, "Submit bug data to post_bug.cgi"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->is_text_present_ok('has been added to the database', 'Bug created'); + logout($sel); +} diff --git a/qa/t/test_flags.t b/qa/t/test_flags.t new file mode 100644 index 000000000..0f7c950f7 --- /dev/null +++ b/qa/t/test_flags.t @@ -0,0 +1,482 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +# We have to upload files from the local computer. This requires +# chrome privileges. +my ($sel, $config) = get_selenium(CHROME_MODE); + +# First create a flag type for bugs. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Flags"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Administer Flag Types"); +$sel->click_ok("link=Create Flag Type for Bugs"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->type_ok("name", "SeleniumBugFlag1Test"); +$sel->type_ok("description", "bugflag1"); +$sel->select_ok("product", "label=TestProduct"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->remove_all_selections_ok("inclusion_to_remove"); +$sel->add_selection_ok("inclusion_to_remove", "label=__Any__:__Any__"); +$sel->click_ok("categoryAction-removeInclusion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->select_ok("product", "label=QA-Selenium-TEST"); +$sel->click_ok("categoryAction-exclude"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->select_ok("product", "label=QA-Selenium-TEST"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +my @inclusion = $sel->get_select_options("inclusion_to_remove"); +ok(scalar @inclusion == 2, "The inclusion list contains 2 elements"); +ok(grep($_ eq "QA-Selenium-TEST:__Any__", @inclusion), "QA-Selenium-TEST:__Any__ is in the inclusion list"); +ok(grep($_ eq "TestProduct:__Any__", @inclusion), "TestProduct:__Any__ is in the inclusion list"); +my @exclusion = $sel->get_select_options("exclusion_to_remove"); +ok(scalar @exclusion == 1, "The exclusion list contains 1 element"); +ok($exclusion[0] eq "QA-Selenium-TEST:__Any__", "QA-Selenium-TEST:__Any__ is in the exclusion list"); +$sel->type_ok("sortkey", "900"); +$sel->value_is("cc_list", ""); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->value_is("is_requesteeble", "on"); +$sel->value_is("is_multiplicable", "on"); +$sel->select_ok("grant_group", "label=admin"); +$sel->select_ok("request_group", "label=(no group)"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumBugFlag1Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumBugFlag1Test has been created."); +my $flagtype_url = $sel->get_attribute('link=SeleniumBugFlag1Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $flagtype1_id = $1; + +# Clone the flag type, but set the request group to 'editbugs' and the sortkey to 950. + +$sel->click_ok("//a[\@href='editflagtypes.cgi?action=copy&id=$flagtype1_id']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs Based on SeleniumBugFlag1Test"); +$sel->type_ok("name", "SeleniumBugFlag2Test"); +$sel->type_ok("description", "bugflag2"); +@inclusion = $sel->get_select_options("inclusion_to_remove"); +ok(scalar @inclusion == 2, "The inclusion list contains 2 elements"); +ok(grep($_ eq "QA-Selenium-TEST:__Any__", @inclusion), "QA-Selenium-TEST:__Any__ is in the inclusion list"); +ok(grep($_ eq "TestProduct:__Any__", @inclusion), "TestProduct:__Any__ is in the inclusion list"); +@exclusion = $sel->get_select_options("exclusion_to_remove"); +ok(scalar @exclusion == 1, "The exclusion list contains 1 element"); +ok($exclusion[0] eq "QA-Selenium-TEST:__Any__", "QA-Selenium-TEST:__Any__ is in the exclusion list"); +$sel->type_ok("sortkey", "950"); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->value_is("is_requesteeble", "on"); +$sel->value_is("is_multiplicable", "on"); +$sel->type_ok("cc_list", $config->{canconfirm_user_login}); +$sel->selected_label_is("grant_group", "admin"); +$sel->select_ok("request_group", "label=editbugs"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumBugFlag2Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumBugFlag2Test has been created."); +$flagtype_url = $sel->get_attribute('link=SeleniumBugFlag2Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $flagtype2_id = $1; + +# Clone the first flag type again, but with different attributes. + +$sel->click_ok("//a[\@href='editflagtypes.cgi?action=copy&id=$flagtype1_id']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs Based on SeleniumBugFlag1Test"); +$sel->type_ok("name", "SeleniumBugFlag3Test"); +$sel->type_ok("description", "bugflag3"); +$sel->type_ok("sortkey", "980"); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->uncheck_ok("is_requesteeble"); +$sel->uncheck_ok("is_multiplicable"); +$sel->value_is("cc_list", ""); +$sel->select_ok("grant_group", "label=(no group)"); +$sel->selected_label_is("request_group", "(no group)"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumBugFlag3Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumBugFlag3Test has been created."); +$flagtype_url = $sel->get_attribute('link=SeleniumBugFlag3Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $flagtype3_id = $1; + +# We now create a flag type for attachments. + +$sel->click_ok("link=Create Flag Type For Attachments"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->type_ok("name", "SeleniumAttachmentFlag1Test"); +$sel->type_ok("description", "attachmentflag1"); +$sel->select_ok("product", "label=TestProduct"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->remove_all_selections_ok("inclusion_to_remove"); +$sel->add_selection_ok("inclusion_to_remove", "label=__Any__:__Any__"); +$sel->click_ok("categoryAction-removeInclusion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +@inclusion = $sel->get_select_options("inclusion_to_remove"); +ok(scalar @inclusion == 1, "The inclusion list contains 1 element"); +ok($inclusion[0] eq "TestProduct:__Any__", "TestProduct:__Any__ is in the exclusion list"); +$sel->type_ok("sortkey", "700"); +$sel->value_is("cc_list", ""); +$sel->select_ok("grant_group", "label=editbugs"); +$sel->select_ok("request_group", "label=canconfirm"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumAttachmentFlag1Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumAttachmentFlag1Test has been created."); +$flagtype_url = $sel->get_attribute('link=SeleniumAttachmentFlag1Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $aflagtype1_id = $1; + +# Clone the flag type. + +$sel->click_ok("//a[\@href='editflagtypes.cgi?action=copy&id=$aflagtype1_id']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments Based on SeleniumAttachmentFlag1Test"); +$sel->type_ok("name", "SeleniumAttachmentFlag2Test"); +$sel->type_ok("description", "attachmentflag2"); +@inclusion = $sel->get_select_options("inclusion_to_remove"); +ok(scalar @inclusion == 1, "The inclusion list contains 1 element"); +ok($inclusion[0] eq "TestProduct:__Any__", "TestProduct:__Any__ is in the exclusion list"); +$sel->type_ok("sortkey", "750"); +$sel->type_ok("cc_list", $config->{admin_user_login}); +$sel->uncheck_ok("is_multiplicable"); +$sel->select_ok("grant_group", "label=(no group)"); +$sel->select_ok("request_group", "label=(no group)"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumAttachmentFlag2Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumAttachmentFlag2Test has been created."); +$flagtype_url = $sel->get_attribute('link=SeleniumAttachmentFlag2Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $aflagtype2_id = $1; + +# Clone the flag type again, and set it as inactive. + +$sel->click_ok("//a[\@href='editflagtypes.cgi?action=copy&id=$aflagtype1_id']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments Based on SeleniumAttachmentFlag1Test"); +$sel->type_ok("name", "SeleniumAttachmentFlag3Test"); +$sel->type_ok("description", "attachmentflag3"); +$sel->type_ok("sortkey", "800"); +$sel->uncheck_ok("is_active"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'SeleniumAttachmentFlag3Test' Created"); +$sel->is_text_present_ok("The flag type SeleniumAttachmentFlag3Test has been created."); +$flagtype_url = $sel->get_attribute('link=SeleniumAttachmentFlag3Test@href'); +$flagtype_url =~ /id=(\d+)$/; +my $aflagtype3_id = $1; + +# All flag types have been created. Now "real" tests can start. + +file_bug_in_product($sel, 'TestProduct'); +$sel->type_ok("short_desc", "test flags"); +$sel->type_ok("comment", "this bug is used by Selenium to test flags"); +# Restrict the bug to the Master group. That's important for subsequent tests! +$sel->check_ok('//input[@name="groups" and @value="Master"]'); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); + +# All 3 bug flag types must be available; we are in the TestProduct product. + +$sel->click_ok("link=Bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id .* test flags/); +$sel->is_text_present_ok("SeleniumBugFlag1Test"); +# We specify //select or //input, just to be sure. This is not required, though. +$sel->is_element_present_ok("//select[\@id='flag_type-$flagtype1_id']"); +$sel->is_element_present_ok("//input[\@id='requestee_type-$flagtype1_id']"); +# If fields are of the correct type above, we assume this is still true below. +$sel->is_text_present_ok("SeleniumBugFlag2Test"); +$sel->is_element_present_ok("flag_type-$flagtype2_id"); +$sel->is_element_present_ok("requestee_type-$flagtype2_id"); +$sel->is_text_present_ok("SeleniumBugFlag3Test"); +$sel->is_element_present_ok("flag_type-$flagtype3_id"); +ok(!$sel->is_element_present("requestee_type-$flagtype3_id"), "SeleniumBugFlag3Test is not specifically requestable"); + +# This is intentional to generate "flagmail". Some flags have a CC list +# associated with them, some others don't. This is to catch crashes due to +# the MTA. + +$sel->select_ok("flag_type-$flagtype1_id", "label=?"); +$sel->select_ok("flag_type-$flagtype2_id", "label=?"); +$sel->select_ok("flag_type-$flagtype3_id", "label=?"); +$sel->type_ok("comment", "Setting all 3 flags to ?"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# We need to store the new flag IDs. + +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumBugFlag1Test"); +my $flag1_1_id = $sel->get_attribute('//select[@title="bugflag1"]@id'); +$flag1_1_id =~ s/flag-//; +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumBugFlag2Test"); +my $flag2_1_id = $sel->get_attribute('//select[@title="bugflag2"]@id'); +$flag2_1_id =~ s/flag-//; +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumBugFlag3Test"); +my $flag3_1_id = $sel->get_attribute('//select[@title="bugflag3"]@id'); +$flag3_1_id =~ s/flag-//; + +$sel->is_text_present_ok("addl. SeleniumBugFlag1Test"); +$sel->is_text_present_ok("addl. SeleniumBugFlag2Test"); +ok(!$sel->is_text_present("addl. SeleniumBugFlag3Test"), "SeleniumBugFlag3Test is not multiplicable"); +$sel->select_ok("flag_type-$flagtype1_id", "label=+"); +$sel->select_ok("flag_type-$flagtype2_id", "label=-"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# Now let's test requestees. SeleniumBugFlag2Test requires the requestee +# to be in the editbugs group. + +$sel->select_ok("flag_type-$flagtype1_id", "label=?"); +$sel->type_ok("requestee_type-$flagtype1_id", $config->{admin_user_login}); +$sel->select_ok("flag_type-$flagtype2_id", "label=?"); +$sel->type_ok("requestee_type-$flagtype2_id", $config->{unprivileged_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Requestee Not Authorized"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->type_ok("requestee_type-$flagtype2_id", $config->{admin_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# Final tests for bug flags. + +$sel->select_ok("flag-$flag1_1_id", "value=X"); +$sel->select_ok("flag-$flag2_1_id", "label=+"); +$sel->select_ok("flag-$flag3_1_id", "label=-"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# Now we test attachment flags. + +$sel->click_ok("link=Add an attachment"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "patch, v1"); +$sel->check_ok("ispatch"); +$sel->is_text_present_ok("SeleniumAttachmentFlag1Test"); +$sel->is_text_present_ok("SeleniumAttachmentFlag2Test"); +ok(!$sel->is_text_present("SeleniumAttachmentFlag3Test"), "Inactive SeleniumAttachmentFlag3Test flag type not displayed"); + +# Let's generate some "flagmail", first with no requestee. + +$sel->select_ok("flag_type-$aflagtype1_id", "label=?"); +$sel->select_ok("flag_type-$aflagtype2_id", "label=?"); +$sel->type_ok("comment", "patch for testing purposes only"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); + +# Store the flag ID. + +my $alink = $sel->get_attribute('//a[@title="patch, v1"]@href'); +$alink =~ /id=(\d+)/; +my $attachment1_id = $1; + +# Now create another attachment, and set requestees. + +$sel->click_ok("//a[contains(text(),'Create\n Another Attachment to Bug $bug1_id')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "patch, v2"); +$sel->check_ok("ispatch"); +# Mark the previous attachment as obsolete. +$sel->check_ok($attachment1_id); +$sel->select_ok("flag_type-$aflagtype1_id", "label=?"); +$sel->type_ok("requestee_type-$aflagtype1_id", $config->{admin_user_login}); +$sel->select_ok("flag_type-$aflagtype2_id", "label=?"); +# The requestee is not in the Master group, and so he cannot view the bug. +# He must be silently skipped from the requestee field. +$sel->type_ok("requestee_type-$aflagtype2_id", $config->{unprivileged_user_login}); +$sel->type_ok("comment", "second patch, with requestee"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); +$alink = $sel->get_attribute('//a[@title="patch, v2"]@href'); +$alink =~ /id=(\d+)/; +my $attachment2_id = $1; + +# Create a third attachment, but we now set the MIME type manually. + +$sel->click_ok("//a[contains(text(),'Create\n Another Attachment to Bug $bug1_id')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "patch, v3"); +$sel->click_ok("list"); +$sel->select_ok("contenttypeselection", "label=plain text (text/plain)"); +$sel->select_ok("flag_type-$aflagtype1_id", "label=+"); +$sel->type_ok("comment", "one +, the other one blank"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); +$alink = $sel->get_attribute('//a[@title="patch, v3"]@href'); +$alink =~ /id=(\d+)/; +my $attachment3_id = $1; + +# Display the bug and check flags are correctly set. + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumAttachmentFlag1Test? ($config->{admin_user_nick})"); +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumAttachmentFlag2Test?"); +$sel->is_text_present_ok("$config->{admin_user_nick}: SeleniumAttachmentFlag1Test+"); +# We marked the first attachment as obsolete, so it should have no flag on it. +$sel->is_text_present_ok("no flags"); + +# Make the bug public and log out. + +$sel->uncheck_ok('//input[@name="groups" and @value="Master"]'); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +logout($sel); + +# As an unprivileged user, try to edit flags. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug1_id); +# No privs are required to clear this flag. +$sel->select_ok("flag-$flag3_1_id", "value=X"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# editbugs privs are required to clear this flag, so no other option +# should be displayed besides the currently set "+". + +my @flag_states = $sel->get_select_options("flag-$flag2_1_id"); +ok(scalar(@flag_states) == 1 && $flag_states[0] eq '+', "Single flag state '+' available"); + +# Powerless users cannot set the flag to +, but setting it to ? is allowed. + +@flag_states = $sel->get_select_options("flag_type-$flagtype1_id"); +ok(scalar @flag_states == 2, "Two flag states available"); +ok(grep($_ eq '?', @flag_states), "Flag state '?' available"); + +# A powerless user cannot edit someone else's attachment flags. + +$sel->click_ok("//a[\@href='attachment.cgi?id=$attachment2_id&action=edit']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Attachment $attachment2_id Details for Bug $bug1_id/); +$sel->is_element_present_ok('//select[@title="attachmentflag2"][@disabled]', + "Attachment flags are not editable by a powerless user"); + +# Add an attachment and set flags on it. + +$sel->click_ok("link=Bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->click_ok("link=Add an attachment"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "patch, v4"); +$sel->value_is("ispatch", "on"); + +# canconfirm/editbugs privs are required to edit this flag. + +ok(!$sel->is_editable("flag_type-$aflagtype1_id"), "Flag type non editable by powerless users"); + +# No privs are required to edit this flag. + +$sel->select_ok("flag_type-$aflagtype2_id", "label=+"); +$sel->type_ok("comment", "granting again"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("$config->{unprivileged_user_nick}: SeleniumAttachmentFlag2Test+"); +logout($sel); + +# Final tests as an admin. He has editbugs privs, so he can edit +# someone else's patch. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->click_ok("//a[\@href='attachment.cgi?id=${attachment3_id}&action=edit']"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Attachment $attachment3_id Details for Bug $bug1_id/); +$sel->select_ok('//select[@title="attachmentflag1"]', "label=+"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes to attachment $attachment3_id of bug $bug1_id submitted"); + +# It's time to delete all created flag types. + +go_to_admin($sel); +$sel->click_ok("link=Flags"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Administer Flag Types"); + +foreach my $flagtype ([$flagtype1_id, "SeleniumBugFlag1Test"], [$flagtype2_id, "SeleniumBugFlag2Test"], + [$flagtype3_id, "SeleniumBugFlag3Test"], [$aflagtype1_id, "SeleniumAttachmentFlag1Test"], + [$aflagtype2_id, "SeleniumAttachmentFlag2Test"], [$aflagtype3_id, "SeleniumAttachmentFlag3Test"]) +{ + my $flag_id = $flagtype->[0]; + my $flag_name = $flagtype->[1]; + $sel->click_ok("//a[\@href='editflagtypes.cgi?action=confirmdelete&id=$flag_id']"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Confirm Deletion of Flag Type '$flag_name'"); + $sel->click_ok("link=Yes, delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Flag Type '$flag_name' Deleted"); + my $msg = trim($sel->get_text("message")); + ok($msg eq "The flag type $flag_name has been deleted.", "Flag type $flag_name deleted"); +} +logout($sel); diff --git a/qa/t/test_flags2.t b/qa/t/test_flags2.t new file mode 100644 index 000000000..9706af639 --- /dev/null +++ b/qa/t/test_flags2.t @@ -0,0 +1,344 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +################################################################ +# 2nd script about flags. This one is focused on flag behavior # +# when moving a bug from one product/component to another one. # +################################################################ + +# We have to upload files from the local computer. This requires +# chrome privileges. +my ($sel, $config) = get_selenium(CHROME_MODE); + +# Start by creating a flag type for bugs. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Flags"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Administer Flag Types"); +$sel->click_ok("link=Create Flag Type for Bugs"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->type_ok("name", "selenium"); +$sel->type_ok("description", "Available in TestProduct and Another Product/c1"); +$sel->add_selection_ok("inclusion_to_remove", "label=__Any__:__Any__"); +$sel->click_ok("categoryAction-removeInclusion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->select_ok("product", "label=TestProduct"); +$sel->selected_label_is("component", "__Any__"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->select_ok("product", "label=Another Product"); +$sel->select_ok("component", "label=c1"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); + +# This flag type must have a higher sortkey than the one we will create later. +# The reason is that link=selenium will catch the first link with this name in +# the UI, so when the second flag type with this name is created, we have to +# catch it, not this one (which will be unique for now, so no worry to find it). + +$sel->type_ok("sortkey", 100); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->click_ok("is_multiplicable"); +$sel->value_is("is_multiplicable", "off"); +$sel->select_ok("grant_group", "label=editbugs"); +$sel->select_ok("request_group", "label=canconfirm"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'selenium' Created"); +$sel->is_text_present_ok("The flag type selenium has been created."); + +# Store the flag type ID. + +$sel->click_ok("link=selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $flag_url = $sel->get_location(); +$flag_url =~ /id=(\d+)/; +my $flagtype1_id = $1; + +# Now create a flag type for attachments in 'Another Product'. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok("link=Create Flag Type For Attachments"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->type_ok("name", "selenium_review"); +$sel->type_ok("description", "Review flag used by Selenium"); +$sel->add_selection_ok("inclusion_to_remove", "label=__Any__:__Any__"); +$sel->click_ok("categoryAction-removeInclusion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->select_ok("product", "label=Another Product"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->type_ok("sortkey", 100); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->click_ok("is_multiplicable"); +$sel->value_is("is_multiplicable", "off"); +$sel->selected_label_is("grant_group", "(no group)"); +$sel->selected_label_is("request_group", "(no group)"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'selenium_review' Created"); +$sel->is_text_present_ok("The flag type selenium_review has been created."); + +# Store the flag type ID. + +$sel->click_ok("link=selenium_review"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$flag_url = $sel->get_location(); +$flag_url =~ /id=(\d+)/; +my $aflagtype1_id = $1; + +# Create a 2nd flag type for attachments, with the same name +# as the 1st one, but now *excluded* from 'Another Product'. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok("link=Create Flag Type For Attachments"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->type_ok("name", "selenium_review"); +$sel->type_ok("description", "Another review flag used by Selenium"); +$sel->select_ok("product", "label=Another Product"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Attachments"); +$sel->type_ok("sortkey", 50); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->value_is("is_multiplicable", "on"); +$sel->select_ok("grant_group", "label=editbugs"); +$sel->select_ok("request_group", "label=canconfirm"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'selenium_review' Created"); + +# Store the flag type ID. + +$sel->click_ok("link=selenium_review"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$flag_url = $sel->get_location(); +$flag_url =~ /id=(\d+)/; +my $aflagtype2_id = $1; + +# We are done with the admin tasks. Now play with flags in bugs. + +file_bug_in_product($sel, 'TestProduct'); +$sel->click_ok('//input[@value="Set bug flags"]'); +$sel->select_ok("flag_type-$flagtype1_id", "label=+"); +$sel->type_ok("short_desc", "The selenium flag should be kept on product change"); +$sel->type_ok("comment", "pom"); +$sel->click_ok('//input[@value="Add an attachment"]'); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "small patch"); +$sel->value_is("ispatch", "on"); +ok(!$sel->is_element_present("flag_type-$aflagtype1_id"), "Flag type $aflagtype1_id not available in TestProduct"); +$sel->select_ok("flag_type-$aflagtype2_id", "label=-"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); + +# Store the bug and flag IDs. + +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->click_ok("link=Bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->is_text_present_ok("$config->{admin_user_nick}: selenium"); +my $flag1_id = $sel->get_attribute('//select[@title="Available in TestProduct and Another Product/c1"]@id'); +$flag1_id =~ s/flag-//; +$sel->selected_label_is("flag-$flag1_id", "+"); +$sel->is_text_present_ok("$config->{admin_user_nick}: selenium_review-"); + +# Now move the bug into the 'Another Product' product. +# Both the bug and attachment flags should survive. + +$sel->select_ok("product", "label=Another Product"); +$sel->type_ok("comment", "Moving to Another Product / c1. The flag should be preserved."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Verify New Product Details..."); +$sel->select_ok("component", "label=c1"); +$sel->click_ok("change_product"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->selected_label_is("flag-$flag1_id", "+"); +$sel->is_text_present_ok("$config->{admin_user_nick}: selenium_review-"); + +# Now moving the bug into the c2 component. The bug flag +# won't survive, but the attachment flag should. + +$sel->type_ok("comment", "Moving to c2. The selenium flag will be deleted."); +$sel->select_ok("component", "label=c2"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +ok(!$sel->is_element_present("flag-$flag1_id"), "The selenium bug flag didn't survive"); +ok(!$sel->is_element_present("flag_type-$flagtype1_id"), "The selenium flag type doesn't exist"); +$sel->is_text_present_ok("$config->{admin_user_nick}: selenium_review-"); + +# File a bug in 'Another Product / c2' and assign it +# to a powerless user, so that he can move it later. + +file_bug_in_product($sel, 'Another Product'); +$sel->click_ok('//input[@value="Set bug flags"]'); +$sel->select_ok("component", "label=c2"); +$sel->type_ok("assigned_to", $config->{unprivileged_user_login}); +ok(!$sel->is_editable("flag_type-$flagtype1_id"), "The selenium bug flag type is displayed but not selectable"); +$sel->select_ok("component", "label=c1"); +$sel->is_editable_ok("flag_type-$flagtype1_id", "The selenium bug flag type is not selectable"); +$sel->select_ok("flag_type-$flagtype1_id", "label=?"); +$sel->type_ok("short_desc", "Create a new selenium flag for c2"); +$sel->type_ok("comment", "."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); + +# Store the bug and flag IDs. + +my $bug2_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->click_ok("link=Bug $bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug2_id /); +$sel->is_text_present_ok("$config->{admin_user_nick}: selenium"); +my $flag2_id = $sel->get_attribute('//select[@title="Available in TestProduct and Another Product/c1"]@id'); +$flag2_id =~ s/flag-//; +$sel->selected_label_is("flag-$flag2_id", '?'); + +# Create a 2nd bug flag type, again named 'selenium', but now +# for the 'Another Product / c2' component only. + +go_to_admin($sel); +$sel->click_ok("link=Flags"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Administer Flag Types"); +$sel->click_ok("link=Create Flag Type for Bugs"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->type_ok("name", "selenium"); +$sel->type_ok("description", "Another flag with the selenium name"); +$sel->add_selection_ok("inclusion_to_remove", "label=__Any__:__Any__"); +$sel->click_ok("categoryAction-removeInclusion"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->select_ok("product", "label=Another Product"); +$sel->select_ok("component", "label=c2"); +$sel->click_ok("categoryAction-include"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create Flag Type for Bugs"); +$sel->type_ok("sortkey", 50); +$sel->value_is("is_active", "on"); +$sel->value_is("is_requestable", "on"); +$sel->value_is("is_multiplicable", "on"); +$sel->selected_label_is("grant_group", "(no group)"); +$sel->selected_label_is("request_group", "(no group)"); +$sel->click_ok("save"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Flag Type 'selenium' Created"); + +# Store the flag type ID. + +$sel->click_ok("link=selenium"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$flag_url = $sel->get_location(); +$flag_url =~ /id=(\d+)/; +my $flagtype2_id = $1; + +# Now move the bug from c1 into c2. The bug flag should survive. + +go_to_bug($sel, $bug2_id); +$sel->select_ok("component", "label=c2"); +$sel->type_ok("comment", "The selenium flag should be preserved."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug2_id"); +$sel->click_ok("link=bug $bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug2_id /); +$sel->selected_label_is("flag-$flag2_id", '?'); +ok(!$sel->is_element_present("flag_type-$flagtype1_id"), "Flag type not available in c2"); +$sel->is_element_present_ok("flag_type-$flagtype2_id"); +logout($sel); + +# Powerless users can edit the 'selenium' flag being in c2. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug2_id); +$sel->select_ok("flag-$flag2_id", "label=+"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug2_id"); +$sel->click_ok("link=bug $bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug2_id /); +$sel->selected_label_is("flag-$flag2_id", "+"); + +# But moving the bug into TestProduct will delete the flag +# as the flag setter is not in the editbugs group. + +$sel->select_ok("product", "label=TestProduct"); +$sel->type_ok("comment", "selenium flag will be lost. I don't have editbugs privs."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Verify New Product Details..."); +$sel->click_ok("change_product"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug2_id"); +$sel->click_ok("link=bug $bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug2_id /); +ok(!$sel->is_element_present("flag-$flag2_id"), "Flag $flag2_id deleted"); +ok(!$sel->is_editable("flag_type-$flagtype1_id"), "Flag type 'selenium' not editable by powerless users"); +ok(!$sel->is_element_present("flag_type-$flagtype2_id"), "Flag type not available in c1"); +logout($sel); + +# Time to delete created flag types. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Flags"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Administer Flag Types"); + +foreach my $flagtype ([$flagtype1_id, "selenium"], [$flagtype2_id, "selenium"], + [$aflagtype1_id, "selenium_review"], [$aflagtype2_id, "selenium_review"]) +{ + my $flag_id = $flagtype->[0]; + my $flag_name = $flagtype->[1]; + $sel->click_ok("//a[\@href='editflagtypes.cgi?action=confirmdelete&id=$flag_id']"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Confirm Deletion of Flag Type '$flag_name'"); + $sel->click_ok("link=Yes, delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Flag Type '$flag_name' Deleted"); + my $msg = trim($sel->get_text("message")); + ok($msg eq "The flag type $flag_name has been deleted.", "Flag type $flag_name deleted"); +} +logout($sel); diff --git a/qa/t/test_groups.t b/qa/t/test_groups.t new file mode 100644 index 000000000..1974091ea --- /dev/null +++ b/qa/t/test_groups.t @@ -0,0 +1,323 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Add the new Selenium-test group. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Add Group"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add group"); +$sel->type_ok("name", "Selenium-test"); +$sel->type_ok("desc", "Test group for Selenium"); +$sel->check_ok("isactive"); +$sel->uncheck_ok("insertnew"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("New Group Created"); +my $group_id = $sel->get_value("group_id"); + +# Mark the Selenium-test group as Shown/Mandatory for TestProduct. + +edit_product($sel, "TestProduct"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Group Controls for TestProduct"); +$sel->is_text_present_ok("Selenium-test"); +$sel->select_ok("membercontrol_${group_id}", "label=Shown"); +$sel->select_ok("othercontrol_${group_id}", "label=Mandatory"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Update group access controls for TestProduct"); + +# File a new bug in the TestProduct product, and restrict it to the bug group. + +file_bug_in_product($sel, "TestProduct"); +$sel->is_text_present_ok("Test group for Selenium"); +$sel->value_is("group_${group_id}", "off"); # Must be OFF (else that's a bug) +$sel->check_ok("group_${group_id}"); +$sel->type_ok("short_desc", "bug restricted to the Selenium group"); +$sel->type_ok("comment", "should be invisible"); +$sel->selected_label_is("component", "TestComponent"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); +$sel->is_text_present_ok("Test group for Selenium"); +$sel->value_is("group_${group_id}", "on"); # Must be ON + +# Look for this new bug and add it to the new "Selenium bugs" saved search. + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections("bug_status"); +$sel->add_selection_ok("bug_status", "UNCONFIRMED"); +$sel->add_selection_ok("bug_status", "CONFIRMED"); +$sel->select_ok("f1", "Group"); +$sel->select_ok("o1", "is equal to"); +$sel->type_ok("v1", "Selenium-test"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("One bug found"); +$sel->is_text_present_ok("bug restricted to the Selenium group"); +$sel->type_ok("save_newqueryname", "Selenium bugs"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("OK, you have a new search named Selenium bugs"); +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_text_present_ok("One bug found"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); + +# No longer use Selenium-test as a bug group. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Selenium-test"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->value_is("isactive", "on"); +$sel->click_ok("isactive"); +$sel->click_ok('//input[@value="Update Group"]'); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->is_text_present_ok("The group will no longer be used for bugs"); + +# File another new bug, now visible as the bug group is disabled. + +file_bug_in_product($sel, "TestProduct"); +$sel->selected_label_is("component", "TestComponent"); +$sel->type_ok("short_desc", "bug restricted to the Selenium group"); +$sel->type_ok("comment", "should be *visible* when created (the group is disabled)"); +ok(!$sel->is_text_present("Test group for Selenium"), "Selenium-test group unavailable"); +ok(!$sel->is_element_present("group_${group_id}"), "Selenium-test checkbox not present"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug2_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug2_id created"); + +# Make sure the new bug doesn't appear in the "Selenium bugs" saved search. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_text_present_ok("One bug found"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +ok(!$sel->is_element_present("b$bug2_id"), "Bug $bug2_id NOT restricted to the bug group"); + +# Re-enable the Selenium-test group as bug group. This doesn't affect +# already filed bugs as this group is not mandatory. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Selenium-test"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->value_is("isactive", "off"); +$sel->click_ok("isactive"); +$sel->title_is("Change Group: Selenium-test"); +$sel->click_ok('//input[@value="Update Group"]'); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->is_text_present_ok("The group will now be used for bugs"); + +# Make sure the second filed bug has not been added to the bug group. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_text_present_ok("One bug found"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +ok(!$sel->is_element_present("b$bug2_id"), "Bug $bug2_id NOT restricted to the bug group"); + +# Make the Selenium-test group mandatory for TestProduct. + +edit_product($sel, "TestProduct"); +$sel->is_text_present_ok("Selenium-test: Shown/Mandatory"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->select_ok("membercontrol_${group_id}", "Mandatory"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Confirm Group Control Change for product 'TestProduct'"); +$sel->is_text_present_ok("the group is newly mandatory and will be added"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Update group access controls for TestProduct"); +$sel->is_text_present_ok('regexp:Adding bugs to group \'Selenium-test\' which is\W+mandatory for this product'); + +# All bugs being in TestProduct must now be restricted to the bug group. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug2_id", undef, "Bug $bug2_id restricted to the bug group"); + +# File a new bug, which must automatically be restricted to the bug group. + +file_bug_in_product($sel, "TestProduct"); +$sel->selected_label_is("component", "TestComponent"); +$sel->type_ok("short_desc", "Selenium-test group mandatory"); +$sel->type_ok("comment", "group enabled"); +ok(!$sel->is_text_present("Test group for Selenium"), "Selenium-test group not available"); +ok(!$sel->is_element_present("group_${group_id}"), "Selenium-test checkbox not present (mandatory group)"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug3_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug3_id created"); + +# Make sure all three bugs are listed as being restricted to the bug group. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug2_id", undef, "Bug $bug2_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug3_id", undef, "Bug $bug3_id restricted to the bug group"); + +# Turn off the Selenium-test group again. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Selenium-test"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->value_is("isactive", "on"); +$sel->click_ok("isactive"); +$sel->click_ok("//input[\@value='Update Group']"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->is_text_present_ok("The group will no longer be used for bugs"); + +# File a bug again. It should not be added to the bug group as this one is disabled. + +file_bug_in_product($sel, "TestProduct"); +$sel->selected_label_is("component", "TestComponent"); +$sel->type_ok("short_desc", "bug restricted to the Selenium-test group"); +$sel->type_ok("comment", "group disabled"); +ok(!$sel->is_text_present("Test group for Selenium"), "Selenium-test group not available"); +ok(!$sel->is_element_present("group_${group_id}"), "Selenium-test checkbox not present"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug4_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug4_id created"); + +# The last bug must not be in the list. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug2_id", undef, "Bug $bug2_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug3_id", undef, "Bug $bug3_id restricted to the bug group"); +ok(!$sel->is_element_present("b$bug4_id"), "Bug $bug4_id NOT restricted to the bug group"); + +# Re-enable the mandatory group. All bugs should be restricted to this bug group automatically. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Selenium-test"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->value_is("isactive", "off"); +$sel->click_ok("isactive"); +$sel->click_ok("//input[\@value='Update Group']"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: Selenium-test"); +$sel->is_text_present_ok("The group will now be used for bugs"); + +# Make sure all bugs are restricted to the bug group. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug2_id", undef, "Bug $bug2_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug3_id", undef, "Bug $bug3_id restricted to the bug group"); +$sel->is_element_present_ok("b$bug4_id", undef, "Bug $bug4_id restricted to the bug group"); + +# Try to remove the Selenium-test group from TestProduct, but DON'T do it! +# We just want to make sure a warning is displayed about this removal. + +edit_product($sel, "TestProduct"); +$sel->is_text_present_ok("Selenium-test: Mandatory/Mandatory"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Group Controls for TestProduct"); +$sel->is_text_present_ok("Selenium-test"); +$sel->select_ok("membercontrol_${group_id}", "NA"); +$sel->select_ok("othercontrol_${group_id}", "NA"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Confirm Group Control Change for product 'TestProduct'"); +$sel->is_text_present_ok("the group is no longer applicable and will be removed"); + +# Delete the Selenium-test group. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("//a[\@href='editgroups.cgi?action=del&group=${group_id}']"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Delete group"); +$sel->is_text_present_ok("Do you really want to delete this group?"); +$sel->is_element_present_ok("removebugs"); +$sel->value_is("removebugs", "off"); +$sel->is_text_present_ok("Remove all bugs from this group restriction for me"); +$sel->is_element_present_ok("unbind"); +$sel->value_is("unbind", "off"); +$sel->is_text_present_ok("remove these controls"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Cannot Delete Group"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^The Selenium-test group cannot be deleted/, "Group is in use - not deletable"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->check("removebugs"); +$sel->check("unbind"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Group Deleted"); +$sel->is_text_present_ok("The group Selenium-test has been deleted."); + +# No more bugs listed in the saved search as the bug group is gone. + +$sel->click_ok("link=Selenium bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: Selenium bugs"); +$sel->is_text_present_ok("Zarro Boogs found"); +$sel->click_ok("link=Forget Search 'Selenium bugs'"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Search is gone"); +$sel->is_text_present_ok("OK, the Selenium bugs search is gone."); +logout($sel); diff --git a/qa/t/test_keywords.t b/qa/t/test_keywords.t new file mode 100644 index 000000000..5789676b4 --- /dev/null +++ b/qa/t/test_keywords.t @@ -0,0 +1,176 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + + +my $test_bug_1 = $config->{test_bug_1}; +my $test_bug_2 = $config->{test_bug_2}; + +# Create keywords. Do some cleanup first if necessary. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Keywords"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select keyword"); + +# If keywords already exist, delete them to not disturb the test. + +my $page = $sel->get_body_text(); +my @keywords = $page =~ m/(key-selenium-\w+)/gi; + +foreach my $keyword (@keywords) { + my $url = $sel->get_attribute("link=$keyword\@href"); + $url =~ s/action=edit/action=del/; + $sel->click_ok("//a[\@href='$url']"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Delete Keyword"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Keyword Deleted"); +} + +# Now let's create our first keyword. + +go_to_admin($sel); +$sel->click_ok("link=Keywords"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select keyword"); +$sel->click_ok("link=Add a new keyword"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add keyword"); +$sel->type_ok("name", "key-selenium-kone"); +$sel->type_ok("description", "Hopefully an ice cream"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("New Keyword Created"); + +# Try create the same keyword, to check validators. + +$sel->click_ok("link=Add a new keyword"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add keyword"); +$sel->type_ok("name", "key-selenium-kone"); +$sel->type_ok("description", "FIX ME!"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Keyword Already Exists"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg eq 'A keyword with the name key-selenium-kone already exists.', 'Already created keyword'); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); + +# Create a second keyword. + +$sel->type_ok("name", "key-selenium-ktwo"); +$sel->type_ok("description", "FIX ME!"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("New Keyword Created"); + +# Again test validators. + +$sel->click_ok("link=key-selenium-ktwo"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit keyword"); +$sel->type_ok("name", "key-selenium-kone"); +$sel->type_ok("description", "the second keyword"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Keyword Already Exists"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg eq 'A keyword with the name key-selenium-kone already exists.', 'Already created keyword'); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit keyword"); +$sel->type_ok("name", "key-selenium-ktwo"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Keyword Updated"); + +# Add keywords to bugs + +go_to_bug($sel, $test_bug_1); +# If another script is playing with keywords too, don't mess with it. +my $kw1 = $sel->get_text("keywords"); +$sel->type_ok("keywords", "$kw1, key-selenium-kone"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); +go_to_bug($sel, $test_bug_2); +my $kw2 = $sel->get_text("keywords"); +$sel->type_ok("keywords", "$kw2, key-selenium-kone, key-selenium-ktwo"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_2"); + +# Now make sure these bugs correctly appear in buglists. + +open_advanced_search_page($sel); +$sel->remove_all_selections("product"); +$sel->remove_all_selections("bug_status"); +$sel->type_ok("keywords", "key-selenium-kone"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("2 bugs found"); + +$sel->click_ok("link=Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Search for bugs"); +$sel->remove_all_selections("product"); +$sel->remove_all_selections("bug_status"); +# Try with a different case than the one in the DB. +$sel->type_ok("keywords", "key-selenium-ktWO"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("One bug found"); + +$sel->click_ok("link=Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Search for bugs"); +$sel->remove_all_selections("product"); +$sel->remove_all_selections("bug_status"); +# Bugzilla doesn't allow substrings for keywords. +$sel->type_ok("keywords", "selen"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Zarro Boogs found"); + +# Make sure describekeywords.cgi works as expected. + +$sel->open_ok("/$config->{bugzilla_installation}/describekeywords.cgi"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bugzilla Keyword Descriptions"); +$sel->is_text_present_ok("key-selenium-kone"); +$sel->is_text_present_ok("Hopefully an ice cream"); +$sel->is_text_present_ok("key-selenium-ktwo"); +$sel->is_text_present_ok("the second keyword"); +$sel->click_ok('//a[@href="buglist.cgi?keywords=key-selenium-kone"]'); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_element_present_ok("link=$test_bug_1"); +$sel->is_element_present_ok("link=$test_bug_2"); +$sel->is_text_present_ok("2 bugs found"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->click_ok('//a[@href="buglist.cgi?keywords=key-selenium-ktwo"]'); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_element_present_ok("link=$test_bug_2"); +$sel->is_text_present_ok("One bug found"); +logout($sel); diff --git a/qa/t/test_login.t b/qa/t/test_login.t new file mode 100644 index 000000000..2b66d6e3c --- /dev/null +++ b/qa/t/test_login.t @@ -0,0 +1,32 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# FIXME: At some point, this trivial script should be merged with test_create_user_accounts.t. +# Either that or we should improve this script a lot. + +# Try to log in to Bugzilla using an invalid account. To be sure that the login form +# is triggered, we try to access an admin page. + +$sel->open_ok("/$config->{bugzilla_installation}/editparams.cgi"); +$sel->title_is("Log in to Bugzilla"); +# The login and password are hardcoded here, because this account doesn't exist. +$sel->type_ok("Bugzilla_login", 'guest@foo.com'); +$sel->type_ok("Bugzilla_password", 'foo-bar-baz'); +$sel->click_ok("log_in"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Invalid Username Or Password"); +$sel->is_text_present_ok("The username or password you entered is not valid."); diff --git a/qa/t/test_long_list_redirection.t b/qa/t/test_long_list_redirection.t new file mode 100644 index 000000000..4e3a8ba97 --- /dev/null +++ b/qa/t/test_long_list_redirection.t @@ -0,0 +1,20 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use Test::More "no_plan"; +use QA::Util; + +my ($sel, $config) = get_selenium(); + +$sel->open_ok("/$config->{bugzilla_installation}/long_list.cgi?id=1"); +$sel->title_is("Full Text Bug Listing", "Display bug as format for printing"); +my $text = $sel->get_text("//h1"); +$text =~ s/[\r\n\t\s]+/ /g; +is($text, 'Bug 1', 'Display bug 1 specifically'); diff --git a/qa/t/test_milestones.t b/qa/t/test_milestones.t new file mode 100644 index 000000000..baf04d402 --- /dev/null +++ b/qa/t/test_milestones.t @@ -0,0 +1,170 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# 1st step: turn on usetargetmilestone, musthavemilestoneonaccept and letsubmitterchoosemilestone. + +log_in($sel, $config, 'admin'); +set_parameters($sel, {'Bug Fields' => {'usetargetmilestone-on' => undef}, + 'Bug Change Policies' => {'musthavemilestoneonaccept-on' => undef, + 'letsubmitterchoosemilestone-on' => undef}, + } + ); + +# 2nd step: Add the milestone "2.0" (with sortkey = 10) to the TestProduct product. + +edit_product($sel, "TestProduct"); +$sel->click_ok("link=Edit milestones:", undef, "Go to the Edit milestones page"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'", "Display milestones"); +$sel->click_ok("link=Add", undef, "Go add a new milestone"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'TestProduct'", "Enter new milestone"); +$sel->type_ok("milestone", "2.0", "Set its name to 2.0"); +$sel->type_ok("sortkey", "10", "Set its sortkey to 10"); +$sel->click_ok("create", undef, "Submit data"); +$sel->wait_for_page_to_load(WAIT_TIME); +# If the milestone already exists, that's not a big deal. So no special action +# is required in this case. +$sel->title_is("Milestone Created", "Milestone Created"); + +# 3rd step: file a new bug, leaving the milestone alone (should fall back to the default one). + +file_bug_in_product($sel, "TestProduct"); +$sel->selected_label_is("component", "TestComponent", "Component already selected (no other component defined)"); +$sel->selected_label_is("target_milestone", "---", "Default milestone selected"); +$sel->selected_label_is("version", "unspecified", "Version already selected (no other version defined)"); +$sel->type_ok("short_desc", "Target Milestone left to default", "Enter bug summary"); +$sel->type_ok("comment", "Created by Selenium to test 'musthavemilestoneonaccept'", "Enter bug description"); +$sel->click_ok("commit", undef, "Commit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug1_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); + +# 4th step: edit the bug (test musthavemilestoneonaccept ON). + +$sel->select_ok("bug_status", "label=IN_PROGRESS", "Change bug status to IN_PROGRESS"); +$sel->click_ok("commit", undef, "Save changes"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Milestone Required", "Change rejected: musthavemilestoneonaccept is on but the milestone selected is the default one"); +$sel->is_text_present_ok("You must select a target milestone", undef, "Display error message"); +# We cannot use go_back_ok() because we just left post_bug.cgi where data has been submitted using POST. +go_to_bug($sel, $bug1_id); +$sel->select_ok("target_milestone", "label=2.0", "Select a non-default milestone"); +$sel->click_ok("commit", undef, "Save changes (2nd attempt)"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +# 5th step: create another bug. + +file_bug_in_product($sel, "TestProduct"); +$sel->select_ok("target_milestone", "label=2.0", "Set the milestone to 2.0"); +$sel->selected_label_is("component", "TestComponent", "Component already selected (no other component defined)"); +$sel->selected_label_is("version", "unspecified", "Version already selected (no other version defined)"); +$sel->type_ok("short_desc", "Target Milestone set to non-default", "Enter bug summary"); +$sel->type_ok("comment", "Created by Selenium to test 'musthavemilestoneonaccept'", "Enter bug description"); +$sel->click_ok("commit", undef, "Commit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug2_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug2_id created"); + +# 6th step: edit the bug (test musthavemilestoneonaccept ON). + +$sel->select_ok("bug_status", "label=IN_PROGRESS"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug2_id"); + + +# 7th step: test validation methods for milestones. + +$sel->open_ok("/$config->{bugzilla_installation}/editmilestones.cgi"); +$sel->title_is("Edit milestones for which product?"); +$sel->click_ok("link=TestProduct"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$sel->click_ok("link=2.0"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Milestone '2.0' of product 'TestProduct'"); +$sel->type_ok("milestone", "1.0"); +$sel->value_is("milestone", "1.0"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Milestone Updated"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'TestProduct'"); +$sel->type_ok("milestone", "1.5"); +$sel->value_is("milestone", "1.5"); +$sel->type_ok("sortkey", "99999999999999999"); +$sel->value_is("sortkey", "99999999999999999"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Invalid Milestone Sortkey"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^The sortkey '99999999999999999' is not in the range/, "Invalid sortkey"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->type_ok("sortkey", "-polu7A"); +$sel->value_is("sortkey", "-polu7A"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Invalid Milestone Sortkey"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^The sortkey '-polu7A' is not in the range/, "Invalid sortkey"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->click_ok("link='TestProduct'"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$sel->click_ok("link=Delete"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Delete Milestone of Product 'TestProduct'"); +$sel->is_text_present_ok("When you delete this milestone", undef, "Warn the user about bugs being affected"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Milestone Deleted"); + +# 8th step: make sure the (now deleted) milestone of the bug has fallen back to the default milestone. + +$sel->open_ok("/$config->{bugzilla_installation}/show_bug.cgi?id=$bug1_id"); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok('regexp:Target Milestone:\W+---', undef, "Milestone has fallen back to the default milestone"); + +# 9th step: file another bug. + +file_bug_in_product($sel, "TestProduct"); +$sel->selected_label_is("target_milestone", "---", "Default milestone selected"); +$sel->selected_label_is("component", "TestComponent"); +$sel->type_ok("short_desc", "Only one Target Milestone available", "Enter bug summary"); +$sel->type_ok("comment", "Created by Selenium to test 'musthavemilestoneonaccept'", "Enter bug description"); +$sel->click_ok("commit", undef, "Commit bug data to post_bug.cgi"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug3_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug3_id created"); + +# 10th step: musthavemilestoneonaccept must have no effect as there is +# no other milestone available besides the default one. + +$sel->select_ok("bug_status", "label=IN_PROGRESS"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug3_id"); + +# 11th step: turn musthavemilestoneonaccept back to OFF. + +set_parameters($sel, {'Bug Change Policies' => {'musthavemilestoneonaccept-off' => undef}}); +logout($sel); diff --git a/qa/t/test_private_attachments.t b/qa/t/test_private_attachments.t new file mode 100644 index 000000000..74b5adac9 --- /dev/null +++ b/qa/t/test_private_attachments.t @@ -0,0 +1,200 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +# We have to upload files from the local computer. This requires +# chrome privileges. +my ($sel, $config) = get_selenium(CHROME_MODE); + +# set the insidergroup parameter to the admin group, and make sure +# we can view and delete attachments. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"insidergroup" => {type => "select", value => "admin"}}, + "Attachments" => {"allow_attachment_display-on" => undef, + "allow_attachment_deletion-on" => undef} + }); + +# First create a new bug with a private attachment. + +file_bug_in_product($sel, "TestProduct"); +$sel->type_ok("short_desc", "Some comments are private"); +$sel->type_ok("comment", "and some attachments too, like this one."); +$sel->check_ok("comment_is_private"); +$sel->click_ok('//input[@value="Add an attachment"]'); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "private attachment, v1"); +$sel->check_ok("ispatch"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok("private attachment, v1 ("); +$sel->is_text_present_ok("and some attachments too, like this one."); +$sel->is_checked_ok('//a[@id="comment_link_0"]/../..//div//input[@type="checkbox"]'); + +# Now attach a public patch to the existing bug. + +$sel->click_ok("link=Add an attachment"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "public attachment, v2"); +$sel->check_ok("ispatch"); +# The existing attachment name must be displayed, to mark it as obsolete. +$sel->is_text_present_ok("private attachment, v1"); +$sel->type_ok("comment", "this patch is public. Everyone can see it."); +$sel->value_is("isprivate", "off"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); + +# We need to store the attachment ID. + +my $alink = $sel->get_attribute('//a[@title="public attachment, v2"]@href'); +$alink =~ /id=(\d+)/; +my $attachment1_id = $1; + +# Be sure to redisplay the same bug, and make sure the new attachment is visible. + +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("public attachment, v2"); +$sel->is_text_present_ok("this patch is public. Everyone can see it."); +ok(!$sel->is_checked('//a[@id="comment_link_1"]/../..//div//input[@type="checkbox"]'), "Public attachment is visible"); +logout($sel); + +# A logged out user cannot see the private attachment, only the public one. +# Same for a user with no privs. + +foreach my $user ('', 'unprivileged') { + log_in($sel, $config, $user) if $user; + go_to_bug($sel, $bug1_id); + ok(!$sel->is_text_present("private attachment, v1"), "Private attachment not visible"); + $sel->is_text_present_ok("public attachment, v2"); + ok(!$sel->is_text_present("and some attachments too, like this one"), "Private comment not visible"); + $sel->is_text_present_ok("this patch is public. Everyone can see it."); +} + +# A powerless user can comment on attachments he doesn't own. + +$sel->click_ok('//a[@href="attachment.cgi?id=' . $attachment1_id . '&action=edit"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Attachment $attachment1_id Details for Bug $bug1_id/); +$sel->is_text_present_ok("created by QA Admin"); +$sel->type_ok("comment", "This attachment is not mine."); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes to attachment $attachment1_id of bug $bug1_id submitted"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("This attachment is not mine"); + +# Powerless users will always be able to view their own attachments, even +# when those are marked private by a member of the insider group. + +$sel->click_ok("link=Add an attachment"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Create New Attachment for Bug #$bug1_id"); +$sel->type_ok("data", $config->{attachment_file}); +$sel->check_ok("ispatch"); +# The user doesn't have editbugs privs. +$sel->is_text_present_ok("[no attachments can be made obsolete]"); +$sel->type_ok("description", "My patch, which I should see, always"); +$sel->type_ok("comment", "This is my patch!"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('regexp:Attachment #\d+ to bug \d+ created'); +$alink = $sel->get_attribute('//a[@title="My patch, which I should see, always"]@href'); +$alink =~ /id=(\d+)/; +my $attachment2_id = $1; +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("My patch, which I should see, always ("); +$sel->is_text_present_ok("This is my patch!"); +logout($sel); + +# Let the admin mark the powerless user's attachment as private. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->click_ok('//a[@href="attachment.cgi?id=' . $attachment2_id . '&action=edit"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Attachment $attachment2_id Details for Bug $bug1_id/); +$sel->check_ok("isprivate"); +$sel->type_ok("comment", "Making the powerless user's patch private."); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes to attachment $attachment2_id of bug $bug1_id submitted"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("My patch, which I should see, always ("); +$sel->is_checked_ok('//a[@id="comment_link_4"]/../..//div//input[@type="checkbox"]'); +$sel->is_text_present_ok("Making the powerless user's patch private."); +logout($sel); + +# A logged out user cannot see private attachments. + +go_to_bug($sel, $bug1_id); +ok(!$sel->is_text_present("private attachment, v1"), "Private attachment not visible to logged out users"); +ok(!$sel->is_text_present("My patch, which I should see, always ("), "Private attachment not visible to logged out users"); +$sel->is_text_present_ok("This is my patch!"); +ok(!$sel->is_text_present("Making the powerless user's patch private"), "Private comment not visible to logged out users"); + +# A powerless user can only see private attachments he owns. + +log_in($sel, $config, 'unprivileged'); +go_to_bug($sel, $bug1_id); +$sel->is_text_present_ok("My patch, which I should see, always ("); +$sel->click_ok("link=My patch, which I should see, always"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +# No title displayed while viewing an attachment. +$sel->title_is(""); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +logout($sel); + +# Admins can delete attachments. + +log_in($sel, $config, 'admin'); +go_to_bug($sel, $bug1_id); +$sel->click_ok('//a[@href="attachment.cgi?id=' . $attachment2_id . '&action=edit"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Attachment $attachment2_id Details for Bug $bug1_id/); +$sel->click_ok("link=Delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Attachment $attachment2_id of Bug $bug1_id"); +$sel->is_text_present_ok("Do you really want to delete this attachment?"); +$sel->type_ok("reason", "deleted by Selenium"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes to attachment $attachment2_id of bug $bug1_id submitted"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/); +$sel->is_text_present_ok("deleted by Selenium"); +$sel->click_ok("link=attachment $attachment2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Attachment Removed"); +$sel->is_text_present_ok("The attachment you are attempting to access has been removed"); + +set_parameters($sel, { + "Group Security" => {"insidergroup" => { type => "select", + value => "QA-Selenium-TEST" }}, +}); +logout($sel); diff --git a/qa/t/test_qa_contact.t b/qa/t/test_qa_contact.t new file mode 100644 index 000000000..1de131861 --- /dev/null +++ b/qa/t/test_qa_contact.t @@ -0,0 +1,167 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# First make sure the 'My QA query' saved search is gone. + +log_in($sel, $config, 'admin'); +if($sel->is_text_present("My QA query")) { + $sel->open_ok("/$config->{bugzilla_installation}/buglist.cgi?cmdtype=dorem&remaction=forget&namedcmd=My%20QA%20query", + undef, "Make sure the 'My QA query' saved search isn't present"); + # We bypass the UI to delete the saved search, and so Bugzilla should complain about the missing token. + $sel->title_is("Suspicious Action"); + $sel->is_text_present_ok("It looks like you didn't come from the right page"); + $sel->click_ok("confirm"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Search is gone"); + my $text = trim($sel->get_text("message")); + ok($text =~ /OK, the My QA query search is gone/, "Removed the 'My QA query' saved search"); +} + +# Enable the QA contact field and file a new bug restricted to the 'Master' group +# with a powerless user as the QA contact. He should only be able to access the +# bug if the QA contact field is enabled, else he looses this privilege. + +set_parameters($sel, { "Bug Fields" => {"useqacontact-on" => undef} }); +file_bug_in_product($sel, 'TestProduct'); +$sel->type_ok("qa_contact", $config->{unprivileged_user_login}, "Set the powerless user as QA contact"); +$sel->type_ok("short_desc", "Test for QA contact"); +$sel->type_ok("comment", "This is a test to check QA contact privs."); +$sel->check_ok('//input[@name="groups" and @value="Master"]'); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database', 'Bug created'); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# Create a saved search querying for all bugs with the powerless user +# as QA contact. + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections("bug_status"); +$sel->select_ok("f1", "label=QA Contact"); +$sel->select_ok("o1", "label=is equal to"); +$sel->type_ok("v1", $config->{unprivileged_user_login}, "Look for the powerless user as QA contact"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id is on the list"); +$sel->is_text_present_ok("Test for QA contact"); +$sel->type_ok("save_newqueryname", "My QA query"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +my $text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named My QA query/, "New saved search 'My QA query'"); +$sel->click_ok("link=My QA query"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My QA query"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id is on the list"); +$sel->is_text_present_ok("Test for QA contact"); + +# The saved search should still work, even with the QA contact field disabled. +# ("work" doesn't mean you should still see all bugs, depending on your role +# and privs!) + +set_parameters($sel, { "Bug Fields" => {"useqacontact-off" => undef} }); +$sel->click_ok("link=My QA query"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: My QA query"); +$sel->is_text_present_ok("One bug found"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id is on the list"); +$sel->click_ok("link=$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +# The 'QA Contact' label must not be displayed. +ok(!$sel->is_element_present('//label[@for="qa_contact"]')); +logout($sel); + +# You cannot access the bug when being logged out, as it's restricted +# to the Master group. + +$sel->type_ok("quicksearch_top", $bug1_id); +$sel->click_ok("find_top"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Access Denied"); +$sel->is_text_present_ok("You are not authorized to access bug"); + +# You are still not allowed to access the bug when logged in as the +# powerless user, as the QA contact field is disabled. +# Don't use it log_in() as we want to follow this specific link. + +$sel->click_ok("//a[contains(text(),'log\n in to an account')]", undef, "Log in"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Log in to Bugzilla"); +$sel->is_text_present_ok("I need an email address and password to continue."); +$sel->type_ok("Bugzilla_login", $config->{unprivileged_user_login}, "Enter login name"); +$sel->type_ok("Bugzilla_password", $config->{unprivileged_user_passwd}, "Enter password"); +$sel->click_ok("log_in", undef, "Submit credentials"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Access Denied"); +$sel->is_text_present_ok("You are not authorized to access bug"); +logout($sel); + +# Re-enable the QA contact field. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useqacontact-on" => undef} }); +logout($sel); + +# Log in as the powerless user. As the QA contact field is enabled again, +# you can now access the restricted bug. Before doing that, we need to set +# some user prefs correctly to not interfere with our test. + +log_in($sel, $config, 'unprivileged'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->select_ok("state_addselfcc", "value=never"); +$sel->select_ok("post_bug_submit_action", "value=same_bug"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections_ok("bug_status"); +$sel->select_ok("f1", "label=QA Contact"); +$sel->select_ok("o1", "label=is equal to"); +$sel->type_ok("v1", $config->{unprivileged_user_login}, "Look for the powerless user as QA contact"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("One bug found"); +$sel->is_element_present_ok("b$bug1_id", undef, "Bug $bug1_id is on the list"); +$sel->is_text_present_ok("Test for QA contact"); +$sel->click_ok("link=$bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug1_id /); +$sel->click_ok("bz_qa_contact_edit_action"); +$sel->value_is("qa_contact", $config->{unprivileged_user_login}, "The powerless user is the current QA contact"); +$sel->check_ok("set_default_qa_contact"); +$sel->click_ok("commit"); + +# The user is no longer the QA contact, and he has no other role +# with the bug. He can no longer see it. + +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("(list of e-mails not available)"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Access Denied"); +logout($sel); diff --git a/qa/t/test_require_login.t b/qa/t/test_require_login.t new file mode 100644 index 000000000..e4fd81891 --- /dev/null +++ b/qa/t/test_require_login.t @@ -0,0 +1,81 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Turn on 'requirelogin'. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"requirelogin-on" => undef} }); +logout($sel); + +# We try to access each page. None of the ones listed below should +# let you view it without being logged in. + +my @pages = qw(admin attachment buglist chart colchange describecomponents + describekeywords duplicates editclassifications editcomponents + editfields editflagtypes editgroups editkeywords editmilestones + editparams editproducts editsettings editusers editvalues + editversions editwhines editworkflow enter_bug long_list page + post_bug process_bug query quips report reports request + sanitycheck search_plugin show_activity show_bug showattachment + showdependencygraph showdependencytree summarize_time + userprefs votes xml); + +foreach my $page (@pages) { + $sel->open_ok("/$config->{bugzilla_installation}/${page}.cgi"); + if ($page ne 'votes' || $config->{test_extensions}) { + $sel->title_is("Log in to Bugzilla"); + } + else { + $sel->title_is("Extension Disabled"); + } +} + +# Those have parameters passed to the page, so we put them here separately. + +@pages = ("query.cgi?format=report-table", "query.cgi?format=report-graph", + "votes.cgi?action=show_user", "votes.cgi?action=show_bug"); + +foreach my $page (@pages) { + $sel->open_ok("/$config->{bugzilla_installation}/$page"); + if ($page !~ /^votes/ || $config->{test_extensions}) { + $sel->title_is("Log in to Bugzilla"); + } + else { + $sel->title_is("Extension Disabled"); + } +} + +# These pages should still be accessible. + +@pages = ("config.cgi", "createaccount.cgi", "index.cgi", "relogin.cgi", + "token.cgi?a=reqpw&loginname=" . $config->{unprivileged_user_login}); + +foreach my $page (@pages) { + $sel->open_ok("/$config->{bugzilla_installation}/$page"); + $sel->title_isnt("Log in to Bugzilla"); +} + +# Turn off 'requirelogin'. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "User Authentication" => {"requirelogin-off" => undef} }); +logout($sel); + +# Make sure we can access random pages again. +$sel->click_ok("link=Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_isnt("Log in to Bugzilla"); diff --git a/qa/t/test_sanity_check.t b/qa/t/test_sanity_check.t new file mode 100644 index 000000000..84fc4d8c4 --- /dev/null +++ b/qa/t/test_sanity_check.t @@ -0,0 +1,46 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Sanity Check", undef, "Go to Sanity Check (no parameter)"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Sanity Check", "Display sanitycheck.cgi"); +$sel->is_text_present_ok("Sanity check completed.", undef, "Page displayed correctly"); + +my @args = qw(rebuildvotecache createmissinggroupcontrolmapentries repair_creation_date + repair_bugs_fulltext remove_invalid_bug_references repair_bugs_fulltext + remove_invalid_attach_references remove_old_whine_targets rescanallBugMail); + +foreach my $arg (@args) { + $sel->open_ok("/$config->{bugzilla_installation}/sanitycheck.cgi?$arg=1"); + $sel->title_is("Suspicious Action", "Calling sanitycheck.cgi with no token triggers a confirmation page"); + $sel->click_ok("confirm", "Confirm the action"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Sanity Check", "Calling sanitycheck.cgi with $arg=1"); + if ($arg eq 'rescanallBugMail') { + # sanitycheck.cgi always stops after looking for unsent bugmail. So we cannot rely on + # "Sanity check completed." to determine if an error has been thrown or not. + $sel->is_text_present_ok("found with possibly unsent mail", undef, "Look for unsent bugmail"); + ok(!$sel->is_text_present("Software error"), "No error thrown"); + } + else { + $sel->is_text_present_ok("Sanity check completed.", undef, "Page displayed correctly"); + } +} + +logout($sel); diff --git a/qa/t/test_saved_searches.t b/qa/t/test_saved_searches.t new file mode 100644 index 000000000..b92307e60 --- /dev/null +++ b/qa/t/test_saved_searches.t @@ -0,0 +1,114 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# If a saved search named 'SavedSearchTEST1' exists, remove it. + +log_in($sel, $config, 'QA_Selenium_TEST'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); + +if($sel->is_text_present("SavedSearchTEST1")) { + # There is no other way to identify this link (as they are all named "Forget"). + $sel->click_ok('//a[contains(@href,"buglist.cgi?cmdtype=dorem&remaction=forget&namedcmd=SavedSearchTEST1")]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Search is gone"); + $sel->is_text_present_ok("OK, the SavedSearchTEST1 search is gone."); +} + +# Create a new saved search. + +open_advanced_search_page($sel); +$sel->type_ok("short_desc", "test search"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->type_ok("save_newqueryname", "SavedSearchTEST1"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +my $text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named SavedSearchTEST1./, "New search named SavedSearchTEST1 has been created"); +$sel->click_ok("link=SavedSearchTEST1"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: SavedSearchTEST1"); + +# Remove the saved search from the page footer. It should no longer be displayed there. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); + +$sel->is_text_present_ok("SavedSearchTEST1"); +$sel->uncheck_ok('//input[@type="checkbox" and @alt="SavedSearchTEST1"]'); +# $sel->value_is("//input[\@type='checkbox' and \@alt='SavedSearchTEST1']", "off"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$text = trim($sel->get_text("message")); +ok($text =~ /The changes to your saved searches have been saved./, "Saved searches changes have been saved"); + +# Modify the saved search. Said otherwise, we should still be able to save +# a new search with exactly the same name. + +open_advanced_search_page($sel); +$sel->type_ok("short_desc", "bilboa"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +# As we said, this saved search should no longer be displayed in the page footer. +ok(!$sel->is_text_present("SavedSearchTEST1"), "SavedSearchTEST1 is not present in the page footer"); +$sel->type_ok("save_newqueryname", "SavedSearchTEST1"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search updated"); +$text = trim($sel->get_text("message")); +ok($text =~ /Your search named SavedSearchTEST1 has been updated./, "Saved searche SavedSearchTEST1 has been updated."); + +# Make sure our new criteria has been saved (let's edit the saved search). +# As the saved search is no longer displayed in the footer, we have to go +# to the "Preferences" page to edit it. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); + +$sel->is_text_present_ok("SavedSearchTEST1"); +$sel->click_ok('//a[@href="buglist.cgi?cmdtype=dorem&remaction=run&namedcmd=SavedSearchTEST1"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: SavedSearchTEST1"); +$sel->click_ok("link=Edit Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search for bugs"); +$sel->value_is("short_desc", "bilboa"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->click_ok("link=Forget Search 'SavedSearchTEST1'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, the SavedSearchTEST1 search is gone./, "The SavedSearchTEST1 search is gone."); +logout($sel); diff --git a/qa/t/test_search.t b/qa/t/test_search.t new file mode 100644 index 000000000..b1f77aebf --- /dev/null +++ b/qa/t/test_search.t @@ -0,0 +1,71 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use Test::More "no_plan"; + +my ($sel, $config) = get_selenium(); + +# TODO: This test really needs improvement. There is by far much more stuff +# to test in this area. + +# First, a very trivial search, which returns no result. + +go_to_home($sel, $config); +open_advanced_search_page($sel); +$sel->type_ok("short_desc", "ois£jdfm#sd%fasd!fm", "Type a non-existent string in the bug summary field"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Zarro Boogs found"); + +# Display all available columns. Look for all bugs assigned to a user who doesn't exist. + +$sel->open_ok("/$config->{bugzilla_installation}/buglist.cgi?quicksearch=%40xx45ft&columnlist=all"); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Zarro Boogs found"); + +# Now some real tests. + +log_in($sel, $config, 'canconfirm'); +file_bug_in_product($sel, "TestProduct"); +my $bug_summary = "Update this summary with this bug ID"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "I'm supposed to appear in the coming buglist."); +my $bug1_id = create_bug($sel, $bug_summary); +$sel->click_ok("editme_action"); +$bug_summary .= ": my ID is $bug1_id"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "Updating bug summary...."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +# Test pronoun substitution. + +open_advanced_search_page($sel); +$sel->remove_all_selections("bug_status"); +$sel->remove_all_selections("resolution"); +$sel->type_ok("short_desc", "my ID is $bug1_id"); +$sel->select_ok("f1", "label=Commenter"); +$sel->select_ok("o1", "label=is equal to"); +$sel->type_ok("v1", "%user%"); +$sel->click_ok("add_button"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search for bugs"); +$sel->select_ok("f2", "label=Comment"); +$sel->select_ok("o2", "label=contains the string"); +$sel->type_ok("v2", "coming buglist"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("One bug found"); +$sel->is_text_present_ok("Update this summary with this bug ID: my ID is $bug1_id"); +logout($sel); diff --git a/qa/t/test_security.t b/qa/t/test_security.t new file mode 100644 index 000000000..42ec304e0 --- /dev/null +++ b/qa/t/test_security.t @@ -0,0 +1,177 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(CHROME_MODE); +my $urlbase = $config->{bugzilla_installation}; +my $admin_user = $config->{admin_user_login}; + +# Let's create a bug and attachment to play with. + +log_in($sel, $config, 'admin'); +file_bug_in_product($sel, "TestProduct"); +my $bug_summary = "Security checks"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "This bug will be used to test security fixes."); +$sel->type_ok("data", $config->{attachment_file}); +$sel->type_ok("description", "simple patch, v1"); +my $bug1_id = create_bug($sel, $bug_summary); + + +####################################################################### +# Security bug 38862. +####################################################################### + +# No alternate host for attachments; cookies will be accessible. + +set_parameters($sel, { "Attachments" => {"allow_attachment_display-on" => undef, + "reset-attachment_base" => undef} }); + +go_to_bug($sel, $bug1_id); +$sel->click_ok("link=simple patch, v1"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is(""); +my @cookies = split(/[\s;]+/, $sel->get_cookie()); +my $nb_cookies = scalar @cookies; +ok($nb_cookies, "Found $nb_cookies cookies:\n" . join("\n", @cookies)); +ok(!$sel->is_cookie_present("Bugzilla_login"), "Bugzilla_login not accessible"); +ok(!$sel->is_cookie_present("Bugzilla_logincookie"), "Bugzilla_logincookie not accessible"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +# Alternate host for attachments; no cookie should be accessible. + +set_parameters($sel, { "Attachments" => {"attachment_base" => {type => "text", + value => "http://127.0.0.1/$urlbase/"}} }); +go_to_bug($sel, $bug1_id); +$sel->click_ok("link=simple patch, v1"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is(""); +@cookies = split(/[\s;]+/, $sel->get_cookie()); +$nb_cookies = scalar @cookies; +ok(!$nb_cookies, "No cookies found"); +ok(!$sel->is_cookie_present("Bugzilla_login"), "Bugzilla_login not accessible"); +ok(!$sel->is_cookie_present("Bugzilla_logincookie"), "Bugzilla_logincookie not accessible"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); + +set_parameters($sel, { "Attachments" => {"reset-attachment_base" => undef} }); + +####################################################################### +# Security bug 472362. +####################################################################### + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +my $admin_cookie = $sel->get_value("token"); +logout($sel); + +log_in($sel, $config, 'editbugs'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +my $editbugs_cookie = $sel->get_value("token"); + +# Using our own unused token is fine. + +$sel->open_ok("/$urlbase/userprefs.cgi?dosave=1&display_quips=off&token=$editbugs_cookie"); +$sel->title_is("User Preferences"); +$sel->is_text_present_ok("The changes to your general preferences have been saved"); + +# Reusing a token must fail. They must all trigger the Suspicious Action warning. + +my @args = ("", "token=", "token=i123x", "token=$admin_cookie", "token=$editbugs_cookie"); + +foreach my $arg (@args) { + $sel->open_ok("/$urlbase/userprefs.cgi?dosave=1&display_quips=off&$arg"); + $sel->title_is("Suspicious Action"); + + if ($arg eq "token=$admin_cookie") { + $sel->is_text_present_ok("Generated by: QA Admin <$admin_user>"); + $sel->is_text_present_ok("This token has not been generated by you"); + } + else { + $sel->is_text_present_ok("It looks like you didn't come from the right page"); + } +} +logout($sel); + +####################################################################### +# Security bug 529416. +####################################################################### + +log_in($sel, $config, 'admin'); +file_bug_in_product($sel, "TestProduct"); +$sel->type_ok("alias", "secret_qa_bug_" . ($bug1_id + 1)); +my $bug_summary2 = "Private QA Bug"; +$sel->type_ok("short_desc", $bug_summary2); +$sel->type_ok("comment", "This private bug is used to test security fixes."); +$sel->type_ok("dependson", $bug1_id); +$sel->check_ok('//input[@name="groups" and @value="Master"]'); +my $bug2_id = create_bug($sel, $bug_summary2); + +go_to_bug($sel, $bug1_id); +$sel->is_text_present_ok("secret_qa_bug_$bug2_id"); +logout($sel); + +log_in($sel, $config, 'editbugs'); +go_to_bug($sel, $bug1_id); +ok(!$sel->is_text_present("secret_qa_bug_$bug2_id"), "The alias 'secret_qa_bug_$bug2_id' is not visible for unauthorized users"); +$sel->is_text_present_ok($bug2_id); +logout($sel); + +go_to_bug($sel, $bug1_id); +ok(!$sel->is_text_present("secret_qa_bug_$bug2_id"), "The alias 'secret_qa_bug_$bug2_id' is not visible for logged out users"); +$sel->is_text_present_ok($bug2_id); + +####################################################################### +# Security bug 472206. +# Keep this test as the very last one as the File Saver will remain +# open till the end of the script. Selenium is currently* unable +# to interact with it and close it (* = 2.6.0). +####################################################################### + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Attachments" => {"allow_attachment_display-off" => undef} }); + +# Attachments are not viewable. + +go_to_bug($sel, $bug1_id); +$sel->click_ok("link=Details"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/Attachment \d+ Details for Bug $bug1_id/); +$sel->is_text_present_ok("The attachment is not viewable in your browser due to security restrictions"); +$sel->click_ok("link=View"); +# Wait 1 second to give the browser a chance to display the attachment. +# Do not use wait_for_page_to_load_ok() as the File Saver will never go away. +sleep(1); +$sel->title_like(qr/Attachment \d+ Details for Bug $bug1_id/); +ok(!$sel->is_text_present('@@'), "Patch not displayed"); + +# Enable viewing attachments. + +set_parameters($sel, { "Attachments" => {"allow_attachment_display-on" => undef} }); + +go_to_bug($sel, $bug1_id); +$sel->click_ok('link=simple patch, v1'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is(""); +$sel->is_text_present_ok('@@'); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug1_id /); +logout($sel); diff --git a/qa/t/test_shared_searches.t b/qa/t/test_shared_searches.t new file mode 100644 index 000000000..6b38a271b --- /dev/null +++ b/qa/t/test_shared_searches.t @@ -0,0 +1,196 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Set the querysharegroup param to be the canconfirm group. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"querysharegroup" => {type => "select", value => "canconfirm"}} }); + +# Create new saved search and call it 'Shared Selenium buglist'. + +$sel->type_ok("quicksearch_top", ":TestProduct Selenium"); +$sel->click_ok("find_top"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->type_ok("save_newqueryname", "Shared Selenium buglist"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +my $text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named Shared Selenium buglist./, "New search named 'Shared Selenium buglist' has been created"); + +# Retrieve the newly created saved search's internal ID and make sure it's displayed +# in the footer by default. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +my $ssname = $sel->get_attribute('//input[@type="checkbox" and @alt="Shared Selenium buglist"]@name'); +$ssname =~ /(?:link_in_footer_(\d+))/; +my $saved_search1_id = $1; +$sel->is_checked_ok("link_in_footer_$saved_search1_id"); + +# As an admin, the "Add to footer" checkbox must be displayed, but unchecked by default. + +$sel->select_ok("share_$saved_search1_id", "label=canconfirm"); +ok(!$sel->is_checked("force_$saved_search1_id"), "Shared search not displayed in other users' footer by default"); +$sel->click_ok("force_$saved_search1_id"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +logout($sel); + +# Log in as the "canconfirm" user. The search shared by the admin must appear +# in the footer. + +log_in($sel, $config, 'canconfirm'); +$sel->is_text_present_ok("Shared Selenium buglist"); +$sel->click_ok("link=Shared Selenium buglist"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: Shared Selenium buglist"); +# You cannot delete other users' saved searches. +ok(!$sel->is_text_present("Forget Search 'Shared Selenium buglist'"), "'Forget...' link not available"); + +# The name of the sharer must appear in the "Saved Searches" section. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->is_text_present_ok($config->{admin_user_login}); + +# Remove the shared search from your footer. + +$sel->is_checked_ok("link_in_footer_$saved_search1_id"); +$sel->click_ok("link_in_footer_$saved_search1_id"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +# Go to a page where the query name is unlikely to appear in the main page. +$sel->click_ok("link=Permissions"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +ok(!$sel->is_text_present("Shared Selenium buglist"), "Shared query no longer displayed in the footer"); + +# Create your own saved search, and share it with the canconfirm group. + +$sel->type_ok("quicksearch_top", ":TestProduct sw:helpwanted"); +$sel->click_ok("find_top"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->type_ok("save_newqueryname", "helpwanted"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named helpwanted./, "New search named helpwanted has been created"); + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$ssname = $sel->get_attribute('//input[@type="checkbox" and @alt="helpwanted"]@name'); +$ssname =~ /(?:link_in_footer_(\d+))/; +my $saved_search2_id = $1; +# Our own saved searches are displayed in the footer by default. +$sel->is_checked_ok("link_in_footer_$saved_search2_id"); +$sel->select_ok("share_$saved_search2_id", "label=canconfirm"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +logout($sel); + +# Log in as admin again. The other user is not a blesser for the 'canconfirm' +# group, and so his shared search must not be displayed by default. But it +# must still be available and can be added to the footer, if desired. + +log_in($sel, $config, 'admin'); +ok(!$sel->is_text_present("helpwanted"), "No 'helpwanted' shared search displayed"); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->is_text_present_ok("helpwanted"); +$sel->is_text_present_ok($config->{canconfirm_user_login}); + +ok(!$sel->is_checked("link_in_footer_$saved_search2_id"), "Shared query available but not displayed"); +$sel->click_ok("link_in_footer_$saved_search2_id"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +# This query is now available from the footer. +$sel->click_ok("link=helpwanted"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: helpwanted"); + +# Remove the 'Shared Selenium buglist' query. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +# There is no better way to identify the link +$sel->click_ok('//a[contains(@href,"buglist.cgi?cmdtype=dorem&remaction=forget&namedcmd=Shared%20Selenium%20buglist")]', + undef, "Deleting the 'Shared Selenium buglist' search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, the Shared Selenium buglist search is gone./, "The 'Shared Selenium buglist' search is gone"); +logout($sel); + +# Make sure that the 'helpwanted' query is not shared with the QA_Selenium_TEST +# user as he doesn't belong to the 'canconfirm' group. + +log_in($sel, $config, 'QA_Selenium_TEST'); +ok(!$sel->is_text_present("helpwanted"), "The 'helpwanted' query is not displayed in the footer"); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +ok(!$sel->is_text_present("helpwanted"), "The 'helpwanted' query is not shared with this user"); +logout($sel); + +# Now remove the 'helpwanted' saved search. + +log_in($sel, $config, 'canconfirm'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Saved Searches"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +ok(!$sel->is_text_present("Shared Selenium buglist"), "The 'Shared Selenium buglist' is no longer available"); +$sel->click_ok('//a[contains(@href,"buglist.cgi?cmdtype=dorem&remaction=forget&namedcmd=helpwanted")]', + undef, "Deleting the 'helpwanted' search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, the helpwanted search is gone./, "The 'helpwanted' search is gone"); +logout($sel); diff --git a/qa/t/test_show_all_products.t b/qa/t/test_show_all_products.t new file mode 100644 index 000000000..97d915174 --- /dev/null +++ b/qa/t/test_show_all_products.t @@ -0,0 +1,57 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-on" => undef} }); + +# Do not use file_bug_in_product() because our goal here is not to file +# a bug but to check what is present in the UI, and also to make sure +# that we get exactly the right page with the right information. +# +# The admin is not a member of the "QA‑Selenium‑TEST" group, and so +# cannot see the "QA‑Selenium‑TEST" product. + +$sel->click_ok("link=New"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Enter Bug"); +$sel->click_ok("link=Other Products", undef, "Choose full product list"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Enter Bug"); +ok(!$sel->is_text_present("QA-Selenium-TEST"), "The QA-Selenium-TEST product is not displayed"); +logout($sel); + +# Same steps, but for a member of the "QA‑Selenium‑TEST" group. +# The "QA‑Selenium‑TEST" product must be visible to him. + +log_in($sel, $config, 'QA_Selenium_TEST'); +$sel->click_ok("link=New"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Enter A Bug"); +if ($sel->is_text_present('None of the above; my bug is in')) { + $sel->click_ok('advanced_link'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Enter Bug"); +} +$sel->click_ok('link=Other Products'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("QA-Selenium-TEST"); +# For some unknown reason, Selenium doesn't like hyphens in links. +# $sel->click_ok("link=QA-Selenium-TEST"); +$sel->click_ok('//div[@id="choose_product"]//a[contains(@href, "QA-Selenium-TEST")]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Product: QA-Selenium-TEST"); +logout($sel); diff --git a/qa/t/test_shutdown.t b/qa/t/test_shutdown.t new file mode 100644 index 000000000..be562ad24 --- /dev/null +++ b/qa/t/test_shutdown.t @@ -0,0 +1,75 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "General" => {shutdownhtml => {type => "text", + value => "I'm down (set by test_shutdown.t)" } + } }); + +# None of the following pages should be accessible when Bugzilla is down. + +my @pages = qw(admin attachment buglist chart colchange config createaccount + describecomponents describekeywords duplicates + editclassifications editcomponents editfields editflagtypes + editgroups editkeywords editmilestones editproducts editsettings + editusers editvalues editversions editwhines editworkflow + enter_bug index long_list page post_bug process_bug query quips + relogin report reports request sanitycheck search_plugin + show_activity show_bug showattachment showdependencygraph + showdependencytree sidebar summarize_time token userprefs votes + xml xmlrpc); + +foreach my $page (@pages) { + $sel->open_ok("/$config->{bugzilla_installation}/${page}.cgi"); + $sel->title_is("Bugzilla is Down"); +} + +# Those have parameters passed to the page, so we put them here separately. + +@pages = ("query.cgi?format=report-table", "query.cgi?format=report-graph", + "votes.cgi?action=show_user", "votes.cgi?action=show_bug"); + +foreach my $page (@pages) { + $sel->open_ok("/$config->{bugzilla_installation}/$page"); + $sel->title_is("Bugzilla is Down"); +} + +# Clear 'shutdownhtml', to re-enable Bugzilla. +# At this point, the admin has been logged out. We cannot use log_in(), +# nor set_parameters(), due to shutdownhtml being active. + +$sel->open_ok("/$config->{bugzilla_installation}/editparams.cgi"); +$sel->title_is("Log in to Bugzilla"); +$sel->type_ok("Bugzilla_login", $config->{admin_user_login}, "Enter admin login name"); +$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password"); +$sel->click_ok("log_in"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Configuration: Required Settings"); +$sel->click_ok("link=General"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Configuration: General"); +$sel->type_ok("shutdownhtml", ""); +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]', undef, "Save Changes"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Parameters Updated"); + +# Accessing index.cgi should work again now. + +$sel->click_ok("link=Home"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bugzilla Main Page"); +logout($sel); diff --git a/qa/t/test_status_whiteboard.t b/qa/t/test_status_whiteboard.t new file mode 100644 index 000000000..6c7f7b085 --- /dev/null +++ b/qa/t/test_status_whiteboard.t @@ -0,0 +1,98 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +my $test_bug_1 = $config->{test_bug_1}; +my $test_bug_2 = $config->{test_bug_2}; + +# Turn on usestatuswhiteboard + +log_in($sel, $config, 'admin'); +set_parameters($sel, {'Bug Fields' => {'usestatuswhiteboard-on' => undef}}); + +# Make sure the status whiteboard is displayed and add stuff to it. + +$sel->open_ok("/$config->{bugzilla_installation}/show_bug.cgi?id=$test_bug_1"); +$sel->title_like(qr/^$test_bug_1\b/); +$sel->is_text_present_ok("Whiteboard:"); +$sel->type_ok("status_whiteboard", "[msg from test_status_whiteboard.t: x77v]"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); +$sel->open_ok("/$config->{bugzilla_installation}/show_bug.cgi?id=$test_bug_2"); +$sel->title_like(qr/^$test_bug_2\b/); +$sel->type_ok("status_whiteboard", "[msg from test_status_whiteboard.t: x77v]"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_2"); + +# Now search these bugs above using data being in the status whiteboard, +# and save the query. + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->remove_all_selections_ok("bug_status"); +$sel->type_ok("status_whiteboard", "x77v"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("2 bugs found"); +$sel->type_ok("save_newqueryname", "sw-x77v"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +my $text = trim($sel->get_text("message")); +ok($text =~ /you have a new search named sw-x77v/, 'Saved search correctly saved'); + +# Make sure the saved query works. + +$sel->click_ok("link=sw-x77v"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: sw-x77v"); +$sel->is_text_present_ok("2 bugs found"); + +# The status whiteboard should no longer be displayed in both the query +# and bug view pages (query.cgi and show_bug.cgi) when usestatuswhiteboard +# is off. + +set_parameters($sel, {'Bug Fields' => {'usestatuswhiteboard-off' => undef}}); +# Show detailed bug information panel on advanced search +ok($sel->create_cookie('TUI=information_query=1'), 'Show detailed bug information'); +$sel->click_ok("link=Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search for bugs"); +ok(!$sel->is_text_present("Whiteboard:"), "Whiteboard label no longer displayed"); +$sel->open_ok("/$config->{bugzilla_installation}/show_bug.cgi?id=$test_bug_1"); +$sel->title_like(qr/^$test_bug_1\b/); +ok(!$sel->is_element_present('//label[@for="status_whiteboard"]')); + +# Queries based on the status whiteboard should still work when +# the parameter is off. + +$sel->click_ok("link=sw-x77v"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: sw-x77v"); +$sel->is_text_present_ok("2 bugs found"); +$sel->click_ok("link=Forget Search 'sw-x77v'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$sel->is_text_present_ok("OK, the sw-x77v search is gone."); + +# Turn on usestatuswhiteboard again as some other scripts may expect the status +# whiteboard to be available by default. + +set_parameters($sel, {'Bug Fields' => {'usestatuswhiteboard-on' => undef}}); +logout($sel); diff --git a/qa/t/test_strict_isolation.t b/qa/t/test_strict_isolation.t new file mode 100644 index 000000000..48ef222b3 --- /dev/null +++ b/qa/t/test_strict_isolation.t @@ -0,0 +1,155 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); +my $qa_user = $config->{QA_Selenium_TEST_user_login}; +my $no_privs_user = $config->{unprivileged_user_login}; + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"strict_isolation-on" => undef} }); + +# Restrict the bug to the "Master" group, so that we can check that only +# allowed people can be CC'ed to the bug. + +file_bug_in_product($sel, 'Another Product'); +$sel->select_ok("component", "label=c2"); +$sel->select_ok("version", "label=Another2"); +my $bug_summary = "Test isolation"; +$sel->type_ok("short_desc", $bug_summary); +$sel->type_ok("comment", "Unallowed users refused"); +my $master_gid = $sel->get_attribute('//input[@type="checkbox" and @name="groups" and @value="Master"]@id'); +$sel->check_ok($master_gid); +$master_gid =~ s/group_//; +$sel->click_ok('commit'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); + +# At that point, CANEDIT is off and so everybody can be CC'ed to the bug. + +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", "$qa_user, $no_privs_user"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +go_to_bug($sel, $bug1_id); +$sel->click_ok("cc_edit_area_showhide"); +$sel->add_selection_ok("cc", "label=$no_privs_user"); +$sel->add_selection_ok("cc", "label=$qa_user"); +$sel->check_ok("removecc"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +# Now enable CANEDIT for the "Master" group. This will enable strict isolation +# for the product. + +edit_product($sel, "Another Product"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for Another Product"); +$sel->check_ok("canedit_$master_gid"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Update group access controls for Another Product"); + +# Non-members can no longer be CC'ed to the bug. + +go_to_bug($sel, $bug1_id); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $no_privs_user); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Invalid User Group"); +$sel->is_text_present_ok("User '$no_privs_user' is not able to edit the 'Another Product' Product"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $qa_user); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Invalid User Group"); +$sel->is_text_present_ok("User '$qa_user' is not able to edit the 'Another Product' Product"); + +# Now set QA_Selenium_TEST user as a member of the Master group. + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search users"); +$sel->type_ok("matchstr", $qa_user); +$sel->select_ok("matchtype", "label=exact (find this user)"); +$sel->click_ok("search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit user QA-Selenium-TEST <$qa_user>"); +$sel->check_ok("group_$master_gid"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User $qa_user updated"); + +# The QA_Selenium_TEST user can now be CC'ed to the bug. + +go_to_bug($sel, $bug1_id); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", $qa_user); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +go_to_bug($sel, $bug1_id); +$sel->click_ok("cc_edit_area_showhide"); +$sel->add_selection_ok("cc", "label=$qa_user"); +$sel->check_ok("removecc"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +# The powerless user still cannot be CC'ed. + +go_to_bug($sel, $bug1_id); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", "$qa_user, $no_privs_user"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Invalid User Group"); +$sel->is_text_present_ok("User '$no_privs_user' is not able to edit the 'Another Product' Product"); + +# Reset parameters back to defaults. + +set_parameters($sel, { "Group Security" => {"strict_isolation-off" => undef} }); + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search users"); +$sel->type_ok("matchstr", $qa_user); +$sel->select_ok("matchtype", "label=exact (find this user)"); +$sel->click_ok("search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit user QA-Selenium-TEST <$qa_user>"); +$sel->uncheck_ok("group_$master_gid"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User $qa_user updated"); + +edit_product($sel, "Another Product"); +$sel->click_ok("link=Edit Group Access Controls:"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Group Controls for Another Product"); +$sel->uncheck_ok("canedit_$master_gid"); +$sel->click_ok("submit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Update group access controls for Another Product"); +logout($sel); diff --git a/qa/t/test_sudo_sessions.t b/qa/t/test_sudo_sessions.t new file mode 100644 index 000000000..828f41330 --- /dev/null +++ b/qa/t/test_sudo_sessions.t @@ -0,0 +1,143 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Turn on the usevisibilitygroups param so that some users are invisible. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"usevisibilitygroups-on" => undef} }); + +# You can see all users from editusers.cgi, but once you leave this page, +# usual group visibility restrictions apply and the "powerless" user cannot +# be sudo'ed as he is in no group. + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search users"); +$sel->type_ok("matchstr", $config->{unprivileged_user_login}); +$sel->select_ok("matchtype", "label=exact (find this user)"); +$sel->click_ok("search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit user no-privs <$config->{unprivileged_user_login}>"); +$sel->value_is("login", $config->{unprivileged_user_login}); +$sel->click_ok("link=Impersonate this user"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Begin sudo session"); +$sel->value_is("target_login", $config->{unprivileged_user_login}); +$sel->type_ok("reason", "Selenium test about sudo sessions"); +$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password"); +$sel->click_ok('//input[@value="Begin Session"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Match Failed"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg eq "$config->{unprivileged_user_login} does not exist or you are not allowed to see that user.", + "Cannot impersonate users you cannot see"); + +# Turn off the usevisibilitygroups param so that all users are visible again. + +set_parameters($sel, { "Group Security" => {"usevisibilitygroups-off" => undef} }); + +# The "powerless" user can now be sudo'ed. + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search users"); +$sel->type_ok("matchstr", $config->{unprivileged_user_login}); +$sel->select_ok("matchtype", "label=exact (find this user)"); +$sel->click_ok("search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit user no-privs <$config->{unprivileged_user_login}>"); +$sel->value_is("login", $config->{unprivileged_user_login}); +$sel->click_ok("link=Impersonate this user"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Begin sudo session"); +$sel->value_is("target_login", $config->{unprivileged_user_login}); +$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password"); +$sel->click_ok('//input[@value="Begin Session"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Sudo session started"); +my $text = trim($sel->get_text("message")); +ok($text =~ /The sudo session has been started/, "The sudo session has been started"); + +# Make sure this user is not an admin and has no privs at all, and that +# he cannot access editusers.cgi (despite the sudoer can). + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->click_ok("link=Permissions"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Preferences"); +$sel->is_text_present_ok("There are no permission bits set on your account"); +# We access the page directly as there is no link pointing to it. +$sel->open_ok("/$config->{bugzilla_installation}/editusers.cgi"); +$sel->title_is("Authorization Required"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^Sorry, you aren't a member of the 'editusers' group/, "Not a member of the editusers group"); +$sel->click_ok("link=End sudo session impersonating " . $config->{unprivileged_user_login}); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Sudo session complete"); +$sel->is_text_present_ok("The sudo session has been ended"); + +# Try to access the sudo page directly, with no credentials. + +$sel->open_ok("/$config->{bugzilla_installation}/relogin.cgi?action=begin-sudo"); +$sel->title_is("Password Required"); + +# Now try to start a sudo session directly, with all required credentials. + +$sel->open_ok("/$config->{bugzilla_installation}/relogin.cgi?action=begin-sudo&Bugzilla_login=$config->{admin_user_login}&Bugzilla_password=$config->{admin_user_passwd}&target_login=$config->{admin_user_login}", undef, "Impersonate a user directly by providing all required data"); +$sel->title_is("Preparation Required"); + +# The link should populate the target_login field correctly. +# Note that we are trying to sudo an admin, which is not allowed. + +$sel->click_ok("link=start your session normally"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Begin sudo session"); +$sel->value_is("target_login", $config->{admin_user_login}); +$sel->type_ok("reason", "Selenium hack"); +$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password"); +$sel->click_ok('//input[@value="Begin Session"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("User Protected"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /^The user $config->{admin_user_login} may not be impersonated by sudoers/, "Cannot impersonate administrators"); + +# Now try to sudo a non-existing user account, with no password. + +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Begin sudo session"); +$sel->type_ok("target_login", 'foo@bar.com'); +$sel->click_ok('//input[@value="Begin Session"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Invalid Username Or Password"); + +# Same as above, but with your password. + +$sel->open_ok("/$config->{bugzilla_installation}/relogin.cgi?action=prepare-sudo&target_login=foo\@bar.com"); +$sel->title_is("Begin sudo session"); +$sel->value_is("target_login", 'foo@bar.com'); +$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password"); +$sel->click_ok('//input[@value="Begin Session"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Match Failed"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg eq 'foo@bar.com does not exist or you are not allowed to see that user.', "Cannot impersonate non-existing accounts"); +logout($sel); diff --git a/qa/t/test_target_milestones.t b/qa/t/test_target_milestones.t new file mode 100644 index 000000000..f02eb42d7 --- /dev/null +++ b/qa/t/test_target_milestones.t @@ -0,0 +1,109 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +my $test_bug_1 = $config->{test_bug_1}; + +# Enable target milestones. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"usetargetmilestone-on" => undef} }); + +# Create a new milestone to the 'TestProduct' product. + +edit_product($sel, "TestProduct"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$sel->click_ok("link=Add"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Add Milestone to Product 'TestProduct'"); +$sel->type_ok("milestone", "TM1"); +$sel->type_ok("sortkey", "10"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Milestone Created"); + +# Edit the milestone of test_bug_1. + +go_to_bug($sel, $test_bug_1); +$sel->is_text_present_ok("Target Milestone:"); +$sel->select_ok("target_milestone", "label=TM1"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); + +# Query for bugs with the TM1 milestone. + +open_advanced_search_page($sel); +$sel->is_text_present_ok("Target Milestone:"); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "label=TestProduct"); +$sel->add_selection_ok("target_milestone", "label=TM1"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("One bug found"); +$sel->type_ok("save_newqueryname", "selenium_m0"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search created"); +my $text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named selenium_m0./, "New search named selenium_m0 has been created"); + +# Turn off milestones and check that the milestone field no longer appears in bugs. + +set_parameters($sel, { "Bug Fields" => {"usetargetmilestone-off" => undef} }); + +$sel->click_ok("link=Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search for bugs"); +ok(!$sel->is_text_present("Target Milestone:"), "The target milestone field is no longer displayed"); + +go_to_bug($sel, $test_bug_1); +ok(!$sel->is_element_present('//label[@for="target_milestone"]')); + +# The existing query must still work despite milestones are off now. + +$sel->click_ok("link=selenium_m0"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List: selenium_m0"); +$sel->is_text_present_ok("One bug found"); +$sel->click_ok("link=Forget Search 'selenium_m0'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Search is gone"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, the selenium_m0 search is gone./, "The selenium_m0 search is gone"); + +# Re-enable the usetargetmilestone parameter and delete the created +# milestone from the Testproduct product. + +set_parameters($sel, { "Bug Fields" => {"usetargetmilestone-on" => undef} }); + +edit_product($sel, "TestProduct"); +$sel->click_ok("link=Edit milestones:"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Select milestone of product 'TestProduct'"); +$sel->click_ok('//a[@href="editmilestones.cgi?action=del&product=TestProduct&milestone=TM1"]', + undef, "Deleting the TM1 milestone"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Milestone of Product 'TestProduct'"); +$text = trim($sel->get_body_text()); +ok($text =~ /There is 1 bug entered for this milestone/, "Warning displayed about 1 bug targetted to TM1"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Milestone Deleted"); +logout($sel); diff --git a/qa/t/test_time_summary.t b/qa/t/test_time_summary.t new file mode 100644 index 000000000..0ae2ea5da --- /dev/null +++ b/qa/t/test_time_summary.t @@ -0,0 +1,100 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +my $test_bug_1 = $config->{test_bug_1}; + +# Set the timetracking group to "editbugs", which is the default value for this parameter. + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Group Security" => {"timetrackinggroup" => {type => "select", value => "editbugs"}} }); + +# Add some Hours Worked to a bug so that we are sure at least one bug +# will be present in our buglist below. + +go_to_bug($sel, $test_bug_1); +$sel->type_ok("work_time", 2.6); +$sel->type_ok("comment", "I did some work"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); +# Make sure the correct bug is redisplayed. +$sel->click_ok("link=bug $test_bug_1"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/, "Display bug $test_bug_1"); +$sel->is_text_present_ok("I did some work"); +$sel->is_text_present_ok("Hours Worked: 2.6"); + +# Let's call summarize_time.cgi directly, with no parameters. + +$sel->open_ok("/$config->{bugzilla_installation}/summarize_time.cgi"); +$sel->title_is("No Bugs Selected"); +my $error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /You apparently didn't choose any bugs to view/, "No data displayed"); + +# Search for bugs which have some value in the Hours Worked field. + +open_advanced_search_page($sel); +$sel->remove_all_selections("bug_status"); +$sel->select_ok("f1", "label=Hours Worked"); +$sel->select_ok("o1", "label=is greater than"); +$sel->type_ok("v1", "0"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("found"); + +# Test dates passed to summarize_time.cgi. + +$sel->click_ok("timesummary"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Time Summary \(\d+ bugs selected\)/); +$sel->check_ok("monthly"); +$sel->check_ok("detailed"); +$sel->type_ok("start_date", "2009-01-01"); +$sel->type_ok("end_date", "2009-04-30"); +$sel->click_ok("summarize"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^Time Summary \(\d+ bugs selected\)/); +$sel->is_text_present_ok('regexp:Total of \d+\.\d+ hours worked'); +$sel->is_text_present_ok("2009-01-01 to 2009-01-31"); +$sel->is_text_present_ok("2009-02-01 to 2009-02-28"); +$sel->is_text_present_ok("2009-04-01 to 2009-04-30"); + +$sel->type_ok("end_date", "2009-04-as"); +$sel->click_ok("summarize"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Illegal Date"); +$error_msg = trim($sel->get_text("error_msg")); +ok($error_msg =~ /'2009-04-as' is not a legal date/, "Illegal end date"); + +# Now display one bug only. We cannot do careful checks, because +# the page sums up contributions made by the same user during the same +# month, and so running this script several times per month would +# break checks we may want to do (e.g. by making sure that the contribution +# above has been taken into account). So we are just making sure that +# the page is displayed and throws no error. + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("//a[contains(text(),'Summarize time')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Time Summary for Bug $test_bug_1"); +$sel->check_ok("inactive"); +$sel->check_ok("owner"); +$sel->click_ok("summarize"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Time Summary for Bug $test_bug_1"); +logout($sel); diff --git a/qa/t/test_user_groups.t b/qa/t/test_user_groups.t new file mode 100644 index 000000000..e4dd5dc30 --- /dev/null +++ b/qa/t/test_user_groups.t @@ -0,0 +1,229 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Administrative Policies" => {"allowuserdeletion-on" => undef} }); + +# First delete test users, if not deleted correctly during a previous run. + +cleanup_users($sel); + +# The Master group inherits privs of the Slave group. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Master"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: Master"); +my $group_url = $sel->get_location(); +$group_url =~ /group=(\d+)$/; +my $master_gid = $1; + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=Add Group"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add group"); +$sel->type_ok("name", "Slave"); +$sel->type_ok("desc", "Members of the Master group are also members of this group"); +$sel->uncheck_ok("isactive"); +ok(!$sel->is_checked("insertnew"), "Group not added to products by default"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("New Group Created"); +my $slave_gid = $sel->get_value("group_id"); +$sel->add_selection_ok("members_add", "label=Master"); +$sel->click_ok('//input[@value="Update Group"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: Slave"); + +# Create users. + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Search users'); +$sel->click_ok('link=add a new user'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Add user'); +$sel->type_ok('login', 'master@selenium.bugzilla.org'); +$sel->type_ok('name', 'master-user'); +$sel->type_ok('password', 'selenium', 'Enter password'); +$sel->type_ok('disabledtext', 'Not for common usage'); +$sel->click_ok('add'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Edit user master-user <master@selenium.bugzilla.org>'); +$sel->check_ok("//input[\@name='group_$master_gid']"); +$sel->click_ok('update'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('User master@selenium.bugzilla.org updated'); +$sel->is_text_present_ok('The account has been added to the Master group'); + +$sel->click_ok("//a[contains(text(),'add\n a new user')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Add user'); +$sel->type_ok('login', 'slave@selenium.bugzilla.org'); +$sel->type_ok('name', 'slave-user'); +$sel->type_ok('password', 'selenium', 'Enter password'); +$sel->type_ok('disabledtext', 'Not for common usage'); +$sel->click_ok('add'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Edit user slave-user <slave@selenium.bugzilla.org>'); +$sel->check_ok("//input[\@name='group_$slave_gid']"); +$sel->click_ok('update'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('User slave@selenium.bugzilla.org updated'); +$sel->is_text_present_ok('The account has been added to the Slave group'); + +$sel->click_ok("//a[contains(text(),'add\n a new user')]"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Add user'); +$sel->type_ok('login', 'reg@selenium.bugzilla.org'); +$sel->type_ok('name', 'reg-user'); +$sel->type_ok('password', 'selenium', 'Enter password'); +$sel->type_ok('disabledtext', 'Not for common usage'); +$sel->click_ok('add'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Edit user reg-user <reg@selenium.bugzilla.org>'); + +# Now make sure group inheritance works correctly. + +$sel->click_ok('link=find other users'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Search users'); +$sel->check_ok('grouprestrict'); +$sel->select_ok('groupid', 'label=Master'); +$sel->select_ok('matchtype', 'value=substr'); +$sel->click_ok('search'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('master@selenium.bugzilla.org', 'master-user in Master group'); +ok(!$sel->is_text_present('slave@selenium.bugzilla.org'), 'slave-user not in Master group'); +ok(!$sel->is_text_present('reg@selenium.bugzilla.org'), 'reg-user not in Master group'); + +$sel->click_ok('link=find other users'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Search users'); +$sel->check_ok('grouprestrict'); +$sel->select_ok('groupid', 'label=Slave'); +$sel->select_ok('matchtype', 'value=substr'); +$sel->click_ok('search'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('master@selenium.bugzilla.org', 'master-user in Slave group'); +$sel->is_text_present_ok('slave@selenium.bugzilla.org', 'slave-user in Slave group'); +ok(!$sel->is_text_present('reg@selenium.bugzilla.org'), 'reg-user not in Slave group'); + +# Add a regular expression to the Slave group. + +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok('link=Slave'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Change Group: Slave'); +$sel->type_ok('regexp', '^reg\@.*$'); +$sel->click_ok('//input[@value="Update Group"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Group: Slave"); + +# Test group inheritance again. + +go_to_admin($sel); +$sel->click_ok("link=Users"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Search users'); +$sel->check_ok('grouprestrict'); +$sel->select_ok('groupid', 'label=Master'); +$sel->select_ok('matchtype', 'value=substr'); +$sel->click_ok('search'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('master@selenium.bugzilla.org', 'master-user in Master group'); +ok(!$sel->is_text_present('slave@selenium.bugzilla.org'), 'slave-user not in Master group'); +ok(!$sel->is_text_present('reg@selenium.bugzilla.org'), 'reg-user not in Master group'); + +$sel->click_ok('link=find other users'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is('Search users'); +$sel->check_ok('grouprestrict'); +$sel->select_ok('groupid', 'label=Slave'); +$sel->select_ok('matchtype', 'value=substr'); +$sel->click_ok('search'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('master@selenium.bugzilla.org', 'master-user in Slave group'); +$sel->is_text_present_ok('slave@selenium.bugzilla.org', 'slave-user in Slave group'); +$sel->is_text_present_ok('reg@selenium.bugzilla.org', 'reg-user in Slave group'); + +# Remove created users and groups. + +cleanup_users($sel); +cleanup_groups($sel, $slave_gid); +logout($sel); + +sub cleanup_users { + my $sel = shift; + + go_to_admin($sel); + $sel->click_ok("link=Users"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Search users"); + $sel->type_ok('matchstr', '(master|slave|reg)@selenium.bugzilla.org'); + $sel->select_ok('matchtype', 'value=regexp'); + $sel->click_ok("search"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Select user"); + + foreach my $user ('master', 'slave', 'reg') { + my $login = $user . '@selenium.bugzilla.org'; + next unless $sel->is_text_present($login); + + $sel->click_ok("link=$login"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Edit user ${user}-user <$login>"); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Confirm deletion of user $login"); + ok(!$sel->is_text_present('You cannot delete this user account'), 'The user can be safely deleted'); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("User $login deleted"); + $sel->click_ok('link=show the user list again'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is('Select user'); + } +} + +sub cleanup_groups { + my ($sel, $slave_gid) = @_; + + go_to_admin($sel); + $sel->click_ok("link=Groups"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Edit Groups"); + $sel->click_ok("//a[\@href='editgroups.cgi?action=del&group=$slave_gid']"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Delete group"); + $sel->is_text_present_ok("Do you really want to delete this group?"); + ok(!$sel->is_element_present("removeusers"), 'No direct members in this group'); + $sel->click_ok("delete"); + $sel->wait_for_page_to_load(WAIT_TIME); + $sel->title_is("Group Deleted"); + $sel->is_text_present_ok("The group Slave has been deleted."); +} diff --git a/qa/t/test_user_matching.t b/qa/t/test_user_matching.t new file mode 100644 index 000000000..0326b8770 --- /dev/null +++ b/qa/t/test_user_matching.t @@ -0,0 +1,188 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +my $test_bug_1 = $config->{test_bug_1}; + + +log_in($sel, $config, 'tweakparams'); +set_parameters($sel, { "User Matching" => {"usemenuforusers-off" => undef, + "maxusermatches" => {type => 'text', value => '0'}, + "confirmuniqueusermatch-on" => undef}, + "Group Security" => {"usevisibilitygroups-off" => undef} + }); + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("cc_edit_area_showhide"); + +# We enter an incomplete email address. process_bug.cgi must ask +# for confirmation as confirmuniqueusermatch is turned on. + +$sel->type_ok("newcc", $config->{unprivileged_user_login_truncated}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Confirm Match"); +$sel->is_text_present_ok("$config->{unprivileged_user_login_truncated} matched"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/); +$sel->click_ok("cc_edit_area_showhide"); + +# We now enter a complete and valid email address, so it must be accepted. +# confirmuniqueusermatch = 1 must not trigger the confirmation page as we +# type the complete email address. + +$sel->type_ok("newcc", $config->{unprivileged_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); + +# Now test wildcards ("*"). Due to confirmuniqueusermatch being turned on, +# a confirmation page must be displayed. + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("cc_edit_area_showhide"); +$sel->type_ok("newcc", "$config->{unprivileged_user_login_truncated}*"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Confirm Match"); +$sel->is_text_present_ok("<$config->{unprivileged_user_login}>"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/); +$sel->click_ok("cc_edit_area_showhide"); + +# This will return more than one account. + +$sel->type_ok("newcc", "*$config->{common_email}"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Confirm Match"); +$sel->is_text_present_ok("*$config->{common_email} matched:"); + +# Now restrict 'maxusermatches'. + +set_parameters($sel, { "User Matching" => {"maxusermatches" => {type => 'text', value => '1'}} }); + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("cc_edit_area_showhide"); + +# Several user accounts match this partial email address. Due to +# maxusermatches = 1, no email address is suggested. + +$sel->type_ok("newcc", "*$config->{common_email}"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Match Failed"); +$sel->is_text_present_ok("matches multiple users"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/); +$sel->click_ok("cc_edit_area_showhide"); + +# We now type a complete and valid email address, so no confirmation +# page should be displayed. + +$sel->type_ok("newcc", $config->{unprivileged_user_login}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $test_bug_1"); + +# Now turn on group visibility. It involves important security checks. + +set_parameters($sel, { "User Matching" => {"maxusermatches" => {type => 'text', value => '2'}}, + "Group Security" => {"usevisibilitygroups-on" => undef} + }); + +# By default, groups are not visible to themselves, so we have to enable this. +# The tweakparams user has not enough privs to do it himself. + +logout($sel); +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Groups"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Edit Groups"); +$sel->click_ok("link=tweakparams"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Change Group: tweakparams"); + +my @groups = $sel->get_select_options("visible_from_add"); +if (grep {$_ eq 'tweakparams'} @groups) { + $sel->add_selection_ok("visible_from_add", "label=tweakparams"); + $sel->click_ok('//input[@value="Update Group"]'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Change Group: tweakparams"); +} +logout($sel); +log_in($sel, $config, 'tweakparams'); + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("cc_edit_area_showhide"); + +# We are not in the same groups as the unprivileged user, so we cannot see him. + +$sel->type_ok("newcc", $config->{unprivileged_user_login_truncated}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Match Failed"); +$sel->is_text_present_ok("$config->{unprivileged_user_login_truncated} did not match anything"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/); +$sel->click_ok("cc_edit_area_showhide"); + +# This will return too many users (there are at least always three: +# you, the admin and the permanent user (who has admin privs too)). + +$sel->type_ok("newcc", $config->{common_email}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Confirm Match"); +$sel->is_text_present_ok("$config->{common_email} matched more than the maximum of 2 users"); +$sel->go_back_ok(); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$test_bug_1/); +$sel->click_ok("cc_edit_area_showhide"); + +# We can always see ourselves. + +$sel->type_ok("newcc", $config->{tweakparams_user_login_truncated}); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Confirm Match"); +$sel->is_text_present_ok("<$config->{tweakparams_user_login}>"); + +# Now test user menus. It must NOT display users we are not allowed to see. + +set_parameters($sel, { "User Matching" => {"usemenuforusers-on" => undef} }); + +go_to_bug($sel, $test_bug_1); +$sel->click_ok("cc_edit_area_showhide"); +my @cc = $sel->get_select_options("newcc"); +ok(!grep($_ =~ /$config->{unprivileged_user_login}/, @cc), "$config->{unprivileged_user_login} is not visible"); +ok(!grep($_ =~ /$config->{canconfirm_user_login}/, @cc), "$config->{canconfirm_user_login} is not visible"); +ok(grep($_ =~ /$config->{admin_user_login}/, @cc), "$config->{admin_user_login} is visible"); +ok(grep($_ =~ /$config->{tweakparams_user_login}/, @cc), "$config->{tweakparams_user_login} is visible"); + +# Reset paramters. + +set_parameters($sel, { "User Matching" => {"usemenuforusers-off" => undef, + "maxusermatches" => {type => 'text', value => '0'}, + "confirmuniqueusermatch-off" => undef}, + "Group Security" => {"usevisibilitygroups-off" => undef} + }); +logout($sel); diff --git a/qa/t/test_user_preferences.t b/qa/t/test_user_preferences.t new file mode 100644 index 000000000..d4161a6f6 --- /dev/null +++ b/qa/t/test_user_preferences.t @@ -0,0 +1,237 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +# Update default user preferences. + +log_in($sel, $config, 'admin'); +go_to_admin($sel); +$sel->click_ok("link=Default Preferences"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Default Preferences"); +$sel->uncheck_ok("skin-enabled"); +$sel->value_is("skin-enabled", "off"); +$sel->check_ok("state_addselfcc-enabled"); +$sel->select_ok("state_addselfcc", "label=Never"); +$sel->check_ok("post_bug_submit_action-enabled"); +$sel->select_ok("post_bug_submit_action", "label=Show the updated bug"); +$sel->check_ok("per_bug_queries-enabled"); +$sel->select_ok("per_bug_queries", "label=On"); +$sel->uncheck_ok("zoom_textareas-enabled"); +$sel->select_ok("zoom_textareas", "label=Off"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Default Preferences"); + +# Update own user preferences. Some of them are not editable. + +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("User Preferences"); +ok(!$sel->is_editable("skin"), "The 'skin' user preference is not editable"); +$sel->select_ok("state_addselfcc", "label=Site Default (Never)"); +$sel->select_ok("post_bug_submit_action", "label=Site Default (Show the updated bug)"); +$sel->select_ok("per_bug_queries", "label=Site Default (On)"); +ok(!$sel->is_editable("zoom_textareas"), "The 'zoom_textareas' user preference is not editable"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("User Preferences"); + +# File a bug in the 'TestProduct' product. The form fields must follow user prefs. + +file_bug_in_product($sel, 'TestProduct'); +$sel->value_is("cc", ""); +$sel->type_ok("short_desc", "First bug created"); +$sel->type_ok("comment", "I'm not in the CC list."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); +$sel->value_is("addselfcc", "off"); +$sel->select_ok("bug_status", "label=IN_PROGRESS"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->click_ok("editme_action"); +$sel->value_is("short_desc", "First bug created"); +$sel->value_is("addselfcc", "off"); + +# Tag the bug. + +$sel->select_ok("lob_action", "label=Add"); +$sel->type_ok("lob_newqueryname", "sel-tmp"); +$sel->type_ok("bug_ids", $bug1_id); +$sel->click_ok("commit_list_of_bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Tag Updated"); +my $text = trim($sel->get_text("message")); +ok($text =~ /The 'sel-tmp' tag has been added to bug $bug1_id/, "Bug added to 'sel-tmp' tag"); +$sel->click_ok("link=sel-tmp"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Tags: sel-tmp"); +$sel->is_text_present_ok("One bug found"); + +# File another bug in the 'TestProduct' product. + +file_bug_in_product($sel, 'TestProduct'); +$sel->value_is("cc", ""); +$sel->type_ok("short_desc", "My second bug"); +$sel->type_ok("comment", "Still not in the CC list"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +my $bug2_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); +$sel->is_text_present_ok('has been added to the database', "Bug $bug2_id created"); +$sel->value_is("addselfcc", "off"); + +# Add another bug to the tag. + +$sel->select_ok("lob_action", "label=Add"); +$sel->select_ok("lob_oldqueryname", "label=sel-tmp"); +$sel->type_ok("bug_ids", $bug2_id); +$sel->click_ok("commit_list_of_bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Tag Updated"); +$text = trim($sel->get_text("message")); +ok($text =~ /The 'sel-tmp' tag has been added to bug $bug2_id/, "Bug added to 'sel-tmp' tag"); +$sel->click_ok("link=sel-tmp"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Tags: sel-tmp"); +$sel->is_text_present_ok("2 bugs found"); +$sel->click_ok("link=$bug1_id"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->type_ok("comment", "The next bug I should see is this one."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); + +$sel->click_ok("editme_action"); +$sel->value_is("short_desc", "First bug created"); +$sel->is_text_present_ok("The next bug I should see is this one."); + +# Remove the tag from all bugs. + +$sel->open_ok("/$config->{bugzilla_installation}/buglist.cgi?tag=sel-tmp", undef, "List 'sel-tmp' bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Tags: sel-tmp"); +$sel->click_ok("link=$bug1_id"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_like(qr/^$bug1_id /); +$sel->select_ok("lob_action", "label=Remove"); +$sel->select_ok("lob_oldqueryname", "label=sel-tmp"); +$sel->type_ok("bug_ids", $bug1_id); +$sel->click_ok("commit_list_of_bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Tag Updated"); +$text = trim($sel->get_text("message")); +ok($text =~ /The 'sel-tmp' tag has been removed from bug $bug1_id/, "Bug removed from 'sel-tmp' tag"); +$sel->click_ok("link=sel-tmp"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Tags: sel-tmp"); +$sel->click_ok("link=$bug2_id"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_like(qr/^$bug2_id /); +$sel->select_ok("lob_action", "label=Remove"); +$sel->select_ok("lob_oldqueryname", "label=sel-tmp"); +$sel->type_ok("bug_ids", $bug2_id); +$sel->click_ok("commit_list_of_bugs"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Tag Updated"); +$text = trim($sel->get_text("message")); +ok($text =~ /The 'sel-tmp' tag has been removed from bug $bug2_id/, "Bug removed from 'sel-tmp' tag"); +$sel->click_ok("link=sel-tmp"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("Tags: sel-tmp"); +$sel->is_text_present_ok("Zarro Boogs found"); +logout($sel); + +# Edit own user preferences, now as an unprivileged user. + +log_in($sel, $config, 'unprivileged'); +$sel->click_ok("link=Preferences"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("User Preferences"); +ok(!$sel->is_editable("skin"), "The 'skin' user preference is not editable"); +$sel->select_ok("state_addselfcc", "label=Always"); +$sel->select_ok("post_bug_submit_action", "label=Show next bug in my list"); +$sel->select_ok("per_bug_queries", "label=Off"); +ok(!$sel->is_editable("zoom_textareas"), "The 'zoom_textareas' user preference is not editable"); +$sel->click_ok("update"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("User Preferences"); + +ok(!$sel->is_element_present("lob_action"), "Element 1/3 for tags is not displayed"); +ok(!$sel->is_element_present("lob_newqueryname"), "Element 2/3 for tags is not displayed"); +ok(!$sel->is_element_present("commit_list_of_bugs"), "Element 3/3 for tags is not displayed"); + +# Create a new search named 'my_list'. + +open_advanced_search_page($sel); +$sel->remove_all_selections_ok("product"); +$sel->add_selection_ok("product", "TestProduct"); +$sel->remove_all_selections_ok("bug_status"); +$sel->select_ok("bug_id_type", "label=only included in"); +$sel->type_ok("bug_id", "$bug1_id , $bug2_id"); +$sel->select_ok("order", "label=Bug Number"); +$sel->click_ok("Search"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Bug List"); +$sel->is_text_present_ok("2 bugs found"); +$sel->type_ok("save_newqueryname", "my_list"); +$sel->click_ok("remember"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Search created"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, you have a new search named my_list./, "New saved search 'my_list' has been created"); + +# Editing bugs should follow user preferences. + +$sel->click_ok("link=my_list"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: my_list"); +$sel->click_ok("link=$bug1_id"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_like(qr/^$bug1_id .* First bug created/); +$sel->value_is("addselfcc", "on"); +$sel->type_ok("comment", "I should be CC'ed and then I should see the next bug."); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->is_text_present_ok("Changes submitted for bug $bug1_id"); +$sel->is_text_present_ok("The next bug in your list is bug $bug2_id"); +ok(!$sel->is_text_present("I should see the next bug"), "The updated bug is no longer displayed"); +# The user has no privs, so the short_desc field is not present. +$sel->is_text_present_ok("My second bug"); +$sel->value_is("addselfcc", "on"); +$sel->click_ok("link=bug $bug1_id"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_like(qr/^$bug1_id .* First bug created/); +$sel->is_text_present_ok("1 user including you"); + +# Delete the saved search and log out. + +$sel->click_ok("link=my_list"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Bug List: my_list"); +$sel->click_ok("link=Forget Search 'my_list'"); +$sel->wait_for_page_to_load(WAIT_TIME); +$sel->title_is("Search is gone"); +$text = trim($sel->get_text("message")); +ok($text =~ /OK, the my_list search is gone/, "The saved search 'my_list' has been deleted"); +logout($sel); diff --git a/qa/t/test_user_privs.t b/qa/t/test_user_privs.t new file mode 100644 index 000000000..367049bc7 --- /dev/null +++ b/qa/t/test_user_privs.t @@ -0,0 +1,68 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); +my $test_bug_1 = $config->{test_bug_1}; + +# When being logged out, the 'Commit' button should not be displayed. + +$sel->open_ok("/$config->{bugzilla_installation}/index.cgi?logout=1", undef, "Log out (if required)"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Logged Out"); +go_to_bug($sel, $test_bug_1); +ok(!$sel->is_element_present('commit'), "Button 'Commit' not available"); + +# Now create a new bug. As the reporter, some forms are editable to you. +# But as you don't have editbugs privs, you cannot edit everything. + +log_in($sel, $config, 'unprivileged'); +file_bug_in_product($sel, 'TestProduct'); +ok(!$sel->is_editable("assigned_to"), "The assignee field is not editable"); +$sel->type_ok("short_desc", "Greetings from a powerless user"); +$sel->type_ok("comment", "File a bug with an empty CC list"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +my $bug1_id = $sel->get_value("//input[\@name='id' and \@type='hidden']"); +$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created"); +logout($sel); + +# Some checks while being logged out. + +go_to_bug($sel, $bug1_id); +ok(!$sel->is_element_present("commit"), "Button 'Commit' not available"); +my $text = trim($sel->get_text("//fieldset")); +ok($text =~ /You need to log in before you can comment on or make changes to this bug./, + "Addl. comment box not displayed"); + +# Don't call log_in() here. We explicitly want to use the "log in" link +# in the addl. comment box. + +$sel->click_ok("link=log in"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Log in to Bugzilla"); +$sel->is_text_present_ok("I need an email address and password to continue."); +$sel->type_ok("Bugzilla_login", $config->{unprivileged_user_login}, "Enter login name"); +$sel->type_ok("Bugzilla_password", $config->{unprivileged_user_passwd}, "Enter password"); +$sel->click_ok("log_in", undef, "Submit credentials"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/^$bug1_id/, "Display bug $bug1_id"); + +# Neither the (edit) link nor the hidden form must exist, at all. +# But the 'Commit' button does exist. + +ok(!$sel->is_element_present("bz_assignee_edit_action"), "No (edit) link displayed for the assignee"); +ok(!$sel->is_element_present("assigned_to"), "No hidden assignee field available"); +$sel->is_element_present_ok("commit"); +logout($sel); diff --git a/qa/t/test_votes.t b/qa/t/test_votes.t new file mode 100644 index 000000000..99b191c80 --- /dev/null +++ b/qa/t/test_votes.t @@ -0,0 +1,251 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); + +use Test::More "no_plan"; + +use QA::Util; + +my ($sel, $config) = get_selenium(); + +unless ($config->{test_extensions}) { + ok(1, "this installation doesn't test extensions. Skipping test_votes.t completely."); + exit; +} + +log_in($sel, $config, 'admin'); +set_parameters($sel, { "Bug Fields" => {"useclassification-off" => undef}, + "Administrative Policies" => {"allowbugdeletion-on" => undef} + }); + +# Create a new product, so that we can safely play with vote settings. + +add_product($sel); +$sel->type_ok("product", "Eureka"); +$sel->type_ok("description", "A great new product"); +$sel->type_ok("votesperuser", 10); +$sel->type_ok("maxvotesperbug", 5); +$sel->type_ok("votestoconfirm", 3); +$sel->select_ok("default_op_sys_id", "Unspecified"); +$sel->select_ok("default_platform_id", "Unspecified"); +$sel->click_ok('//input[@type="submit" and @value="Add"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Created"); +$sel->click_ok("link=add at least one component"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Add component to the Eureka product"); +$sel->type_ok("component", "Pegasus"); +$sel->type_ok("description", "A constellation in the north hemisphere."); +$sel->type_ok("initialowner", $config->{permanent_user}, "Setting the default owner"); +$sel->uncheck_ok("watch_user_auto"); +$sel->type_ok("watch_user", "pegasus\@eureka.bugs"); +$sel->check_ok("watch_user_auto"); +$sel->click_ok("create"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Component Created"); +my $text = trim($sel->get_text("message")); +ok($text =~ qr/The component Pegasus has been created/, "Component 'Pegasus' created"); + +# Create a new bug with the CONFIRMED status. + +file_bug_in_product($sel, 'Eureka'); +# CONFIRMED must be the default bug status for users with editbugs privs. +$sel->selected_label_is("bug_status", "CONFIRMED"); +$sel->type_ok("short_desc", "Aries"); +$sel->type_ok("comment", "1st constellation"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database'); +my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# Now vote for this bug. + +$sel->click_ok("link=vote"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +# No comment :-/ +my $full_text = trim($sel->get_body_text()); +# OK, this is not the most robust regexp, but that's better than nothing. +ok($full_text =~ /only 5 votes allowed per bug in this product/, + "Notice about the number of votes allowed per bug displayed"); +$sel->type_ok("bug_$bug1_id", 4); +$sel->click_ok("change"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +$full_text = trim($sel->get_body_text()); +# OK, we may get a false positive if another product has the exact same numbers, +# but I have no better idea to check this information. +ok($full_text =~ /4 votes used out of 10 allowed/, "Display the number of votes used"); + +# File a new bug, now as UNCONFIRMED. We will confirm it by popular votes. + +file_bug_in_product($sel, 'Eureka'); +$sel->select_ok("bug_status", "UNCONFIRMED"); +$sel->type_ok("short_desc", "Taurus"); +$sel->type_ok("comment", "2nd constellation"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database'); +my $bug2_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# Put enough votes on this bug to confirm it by popular votes. + +$sel->click_ok("link=vote"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +$sel->type_ok("bug_$bug2_id", 5); +$sel->click_ok("change"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +$sel->is_text_present_ok("Bug $bug2_id confirmed by number of votes"); + +# File a third bug, again as UNCONFIRMED. We will confirm it +# by decreasing the number required to confirm bugs by popular votes. + +file_bug_in_product($sel, 'Eureka'); +$sel->select_ok("bug_status", "UNCONFIRMED"); +$sel->type_ok("short_desc", "Gemini"); +$sel->type_ok("comment", "3rd constellation"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database'); +my $bug3_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# Vote for this bug, but remain below the threshold required +# to confirm the bug by popular votes. +# We also change votes set on other bugs for testing purposes. + +$sel->click_ok("link=vote"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +$sel->type_ok("bug_$bug1_id", 2); +$sel->type_ok("bug_$bug3_id", 2); +$sel->click_ok("change"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); +# Illegal change: max is 5 votes per bug! +$sel->type_ok("bug_$bug2_id", 15); +$sel->click_ok("change"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Illegal Vote"); +$text = trim($sel->get_text("error_msg")); +ok($text =~ /You may only use at most 5 votes for a single bug in the Eureka product, but you are trying to use 15/, + "Too many votes per bug"); + +# FIXME: We cannot use go_back_ok() here, because Firefox complains about +# POST data not being stored in its cache. As a workaround, we go to +# the bug we just visited and click the 'vote' link again. + +go_to_bug($sel, $bug3_id); +$sel->click_ok("link=vote"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Change Votes"); + +# Illegal change: max is 10 votes for this product! +$sel->type_ok("bug_$bug2_id", 5); +$sel->type_ok("bug_$bug1_id", 5); +$sel->click_ok("change"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Illegal Vote"); +$text = trim($sel->get_text("error_msg")); +ok($text =~ /You tried to use 12 votes in the Eureka product, which exceeds the maximum of 10 votes for this product/, + "Too many votes for this product"); + +# Decrease the confirmation threshold so that $bug3 becomes confirmed. + +edit_product($sel, 'Eureka'); +$sel->type_ok("votestoconfirm", 2); +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Updating Product 'Eureka'"); +$full_text = trim($sel->get_body_text()); +ok($full_text =~ /Updated number of votes needed to confirm a bug from 3 to 2/, + "Confirming the new number of votes to confirm"); +$sel->is_text_present_ok("Bug $bug3_id confirmed by number of votes"); + +# Decrease the number of votes per bug so that $bug2 is updated. + +$sel->click_ok("link='Eureka'"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Edit Product 'Eureka'"); +$sel->type_ok("maxvotesperbug", 4); +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Updating Product 'Eureka'"); +$full_text = trim($sel->get_body_text()); +ok($full_text =~ /Updated maximum votes per bug from 5 to 4/, "Confirming the new number of votes per bug"); +$sel->is_text_present_ok("removed votes for bug $bug2_id from " . $config->{admin_user_login}, undef, + "Removed votes from the admin"); + +# Go check that $bug2 has been correctly updated. + +$sel->click_ok("link=$bug2_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug2_id /); +$text = trim($sel->get_text("votes_container")); +ok($text =~ /4 votes/, "4 votes remaining"); + +# Decrease the number per user. Bugs should keep at least one vote, +# i.e. not all votes are removed (which was the old behavior). + +edit_product($sel, "Eureka"); +$sel->type_ok("votesperuser", 5); +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Updating Product 'Eureka'"); +$full_text = trim($sel->get_body_text()); +ok($full_text =~ /Updated votes per user from 10 to 5/, "Confirming the new number of votes per user"); +$sel->is_text_present_ok("removed votes for bug"); + +# Go check that $bug3 has been correctly updated. + +$sel->click_ok("link=$bug3_id"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_like(qr/$bug3_id /); +$text = trim($sel->get_text("votes_container")); +ok($text =~ /2 votes/, "2 votes remaining"); + +# Now disable UNCONFIRMED. + +edit_product($sel, "Eureka"); +$sel->click_ok("allows_unconfirmed"); +$sel->click_ok('//input[@type="submit" and @value="Save Changes"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Updating Product 'Eureka'"); +$full_text = trim($sel->get_body_text()); +ok($full_text =~ /The product no longer allows the UNCONFIRMED status/, "Disable UNCONFIRMED"); + +# File a new bug. UNCONFIRMED must not be listed as a valid bug status. + +file_bug_in_product($sel, "Eureka"); +ok(!scalar(grep {$_ eq "UNCONFIRMED"} $sel->get_select_options("bug_status")), "UNCONFIRMED not listed"); +$sel->type_ok("short_desc", "Cancer"); +$sel->type_ok("comment", "4th constellation"); +$sel->click_ok("commit"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->is_text_present_ok('has been added to the database'); +my $bug4_id = $sel->get_value('//input[@name="id" and @type="hidden"]'); + +# Now delete the 'Eureka' product. + +go_to_admin($sel); +$sel->click_ok("link=Products"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Select product"); +$sel->click_ok('//a[@href="editproducts.cgi?action=del&product=Eureka"]'); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Delete Product 'Eureka'"); +$full_text = trim($sel->get_body_text()); +ok($full_text =~ /There are 4 bugs entered for this product/, "Display warning about existing bugs"); +ok($full_text =~ /Pegasus: A constellation in the north hemisphere/, "Display product description"); +$sel->click_ok("delete"); +$sel->wait_for_page_to_load_ok(WAIT_TIME); +$sel->title_is("Product Deleted"); +logout($sel); diff --git a/qa/t/webservice_bug_add_attachment.t b/qa/t/webservice_bug_add_attachment.t new file mode 100644 index 000000000..1ea0ca76a --- /dev/null +++ b/qa/t/webservice_bug_add_attachment.t @@ -0,0 +1,227 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use MIME::Base64 qw(encode_base64 decode_base64); +use Test::More tests => 187; +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +use constant INVALID_BUG_ID => -1; +use constant INVALID_BUG_ALIAS => random_string(20); +use constant PRIVS_USER => 'QA_Selenium_TEST'; + +sub attach { + my ($id, $override) = @_; + my %fields = ( + ids => [$id], + data => 'data-' . random_string(100), + file_name => 'file_name-' . random_string(60), + summary => 'summary-' . random_string(100), + content_type => 'text/plain', + comment => 'comment-' . random_string(100), + ); + + foreach my $key (keys %{ $override || {} }) { + my $value = $override->{$key}; + if (defined $value) { + $fields{$key} = $value; + } + else { + delete $fields{$key}; + } + } + return \%fields; +} + +my ($public_bug, $private_bug) = + $xmlrpc->bz_create_test_bugs('private'); +my $public_id = $public_bug->{id}; +my $private_id = $private_bug->{id}; + +my @tests = ( + # Permissions + { args => attach($public_id), + error => 'You must log in', + test => 'Logged-out user cannot add an attachment to a public bug', + }, + { args => attach($private_id), + error => "You must log in", + test => 'Logged-out user cannot add an attachment to a private bug', + }, + { user => 'editbugs', + args => attach($private_id), + error => "not authorized to access", + test => "Editbugs user can't add an attachment to a private bug", + }, + + # Test ID parameter + { user => 'unprivileged', + args => attach(undef, { ids => undef }), + error => 'a ids argument', + test => 'Failing to pass the "ids" param fails', + }, + { user => 'unprivileged', + args => attach(INVALID_BUG_ID), + error => "not a valid bug number", + test => 'Passing invalid bug id returns error "Invalid Bug ID"', + }, + { user => 'unprivileged', + args => attach(''), + error => "You must enter a valid bug number", + test => 'Passing empty bug id returns error "Invalid Bug ID"', + }, + { user => 'unprivileged', + args => attach(INVALID_BUG_ALIAS), + error => "nor an alias to a bug", + test => 'Passing invalid bug alias returns error "Invalid Bug Alias"', + }, + + # Test Comment parameter + { user => 'unprivileged', + args => attach($public_id, { data => undef }), + error => 'a data argument', + test => 'Failing to pass the "data" parameter fails', + }, + { user => 'unprivileged', + args => attach($public_id, { data => '' }), + error => "The file you are trying to attach is empty", + test => 'Passing empty data fails', + }, + { user => 'unprivileged', + args => attach($public_id, { data => random_string(300_000) }), + error => "Attachments cannot be more than", + test => "Passing an attachment that's too large fails", + }, + + # Test the private parameter + { user => 'unprivileged', + args => attach($public_id, { is_private => 1 }), + error => 'attachments as private', + test => 'Unprivileged user cannot add a private attachment' + }, + + # Content-type + { user => 'unprivileged', + args => attach($public_id, { content_type => 'foo/bar' }), + error => "Valid types must be of the form", + test => "Well-formed but invalid content type fails", + }, + { user => 'unprivileged', + args => attach($public_id, { content_type => undef }), + error => 'Valid types must be of the form', + test => "Failing to pass content_type fails", + }, + { user => 'unprivileged', + args => attach($public_id, { content_type => '' }), + error => 'Valid types must be of the form', + test => "Empty content type fails", + }, + + # Summary + { user => 'unprivileged', + args => attach($public_id, { summary => undef }), + error => 'You must enter a description for the attachment', + test => "Failing to pass summary fails", + }, + { user => 'unprivileged', + args => attach($public_id, { summary => '' }), + error => 'You must enter a description for the attachment', + test => "Empty summary fails", + }, + + # Filename + { user => 'unprivileged', + args => attach($public_id, { file_name => undef }), + error => 'You did not specify a file to attach', + test => "Failing to pass file_name fails", + }, + { user => 'unprivileged', + args => attach($public_id, { file_name => '' }), + error => 'You did not specify a file to attach', + test => "Empty file_name fails", + }, + + # Success tests + { user => 'unprivileged', + args => attach($public_id), + test => 'Unprivileged user can add an attachment to a public bug', + }, + { user => 'unprivileged', + args => attach($public_id, { is_patch => 1, content_type => undef }), + test => 'Attaching a patch with no content type works', + }, + { user => 'unprivileged', + args => attach($public_id, { is_patch => 1, + content_type => 'application/octet-stream' }), + test => 'Attaching a patch with a bad content_type works', + }, + { user => PRIVS_USER, + args => attach($private_id), + test => 'Privileged user can add an attachment to a private bug', + }, + { user => PRIVS_USER, + args => attach($public_id, { is_private => 1 }), + test => 'Insidergroup user can add a private attachment', + }, +); + +$jsonrpc_get->bz_call_fail('Bug.add_attachment', attach($public_id), + 'must use HTTP POST', 'add_attachment fails over GET'); + +foreach my $rpc ($jsonrpc, $xmlrpc) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.add_attachment', + post_success => \&post_success, pre_call => \&pre_call); +} + +# We have to encode data manually when using JSON-RPC, else it fails. +sub pre_call { + my ($t, $rpc) = @_; + return if !$rpc->isa('QA::RPC::JSONRPC'); + return if !defined $t->{args}->{data}; + + $t->{args}->{data} = encode_base64($t->{args}->{data}, ''); +} + +sub post_success { + my ($call, $t, $rpc) = @_; + + my $ids = [ keys %{ $call->result->{attachments} } ]; + $call = $rpc->bz_call_success("Bug.attachments", {attachment_ids => $ids}); + my $attachments = $call->result->{attachments}; + + foreach my $id (keys %$attachments) { + my $attachment = $attachments->{$id}; + if ($t->{args}->{is_private}) { + ok($attachment->{is_private}, + $rpc->TYPE . ": Attachment $id is private"); + } + else { + ok(!$attachment->{is_private}, + $rpc->TYPE . ": Attachment $id is NOT private"); + } + + if ($t->{args}->{is_patch}) { + is($attachment->{content_type}, 'text/plain', + $rpc->TYPE . ": Patch $id content type is text/plain"); + } + else { + is($attachment->{content_type}, $t->{args}->{content_type}, + $rpc->TYPE . ": Attachment $id content type is correct"); + } + + if ($rpc->isa('QA::RPC::JSONRPC')) { + # We encoded data in pre_call(), so we have to restore it to its original content. + $t->{args}->{data} = decode_base64($t->{args}->{data}); + $attachment->{data} = decode_base64($attachment->{data}); + } + is($attachment->{data}, $t->{args}->{data}, + $rpc->TYPE . ": Attachment $id data is correct"); + } +} diff --git a/qa/t/webservice_bug_add_comment.t b/qa/t/webservice_bug_add_comment.t new file mode 100644 index 000000000..64c410f3f --- /dev/null +++ b/qa/t/webservice_bug_add_comment.t @@ -0,0 +1,168 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +############################################# +# Test for xmlrpc call to Bug.add_comment() # +############################################# + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use Test::More tests => 141; +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +use constant INVALID_BUG_ID => -1; +use constant INVALID_BUG_ALIAS => 'aaaaaaa12345'; +use constant PRIVS_USER => 'QA_Selenium_TEST'; +use constant TIMETRACKING_USER => 'admin'; + +use constant TEST_COMMENT => '--- Test Comment From QA Tests ---'; +use constant TOO_LONG_COMMENT => 'a' x 100000; + +my @tests = ( + # Permissions + { args => { id => 'public_bug', comment => TEST_COMMENT }, + error => 'You must log in', + test => 'Logged-out user cannot comment on a public bug', + }, + { args => { id => 'private_bug', comment => TEST_COMMENT }, + error => "You must log in", + test => 'Logged-out user cannot comment on a private bug', + }, + { user => 'unprivileged', + args => { id => 'private_bug', comment => TEST_COMMENT }, + error => "not authorized to access", + test => "Unprivileged user can't comment on a private bug", + }, + + # Test ID parameter + { user => 'unprivileged', + args => { comment => TEST_COMMENT }, + error => 'a id argument', + test => 'Failing to pass the "id" param fails', + }, + { user => 'unprivileged', + args => { id => INVALID_BUG_ID, comment => TEST_COMMENT }, + error => "not a valid bug number", + test => 'Passing invalid bug id returns error "Invalid Bug ID"', + }, + { user => 'unprivileged', + args => { id => '', comment => TEST_COMMENT }, + error => "You must enter a valid bug number", + test => 'Passing empty bug id param returns error "Invalid Bug ID"', + }, + { user => 'unprivileged', + args => { id => INVALID_BUG_ALIAS, comment => TEST_COMMENT }, + error => "nor an alias to a bug", + test => 'Passing invalid bug alias returns error "Invalid Bug Alias"', + }, + + # Test Comment parameter + { user => 'unprivileged', + args => { id => 'public_bug' }, + error => 'a comment argument', + test => 'Failing to pass the "comment" parameter fails', + }, + { user => 'unprivileged', + args => { id => 'public_bug', comment => '' }, + error => "a comment argument", + test => 'Passing an empty comment fails', + }, + { user => 'unprivileged', + args => { id => 'public_bug', comment => ' ' }, + error => 'a comment argument', + test => 'Passing only a space for comment fails', + }, + { user => 'unprivileged', + args => { id => 'public_bug', comment => " \t\n\n\r\n\r\n\r " }, + error => 'a comment argument', + test => 'Passing only whitespace (including newlines) fails', + }, + { user => 'unprivileged', + args => { id => 'public_bug', comment => TOO_LONG_COMMENT }, + error => "cannot be longer than", + test => "Passing a comment that's too long fails", + }, + + # Testing the "private" parameter happens in the tests for Bug.comments + + # Test work_time parameter + # FIXME: Should be testing permissions on the work_time parameter, + # but we currently have no way to verify whether or not time was + # added to the bug, and there's no error thrown if you lack perms. + { user => 'admin', + args => { id => 'public_bug', comment => TEST_COMMENT, + work_time => 'aaa' }, + error => "is not a numeric value", + test => "Passing a non-numeric work_time fails", + }, + { user => 'admin', + args => { id => 'public_bug', comment => TEST_COMMENT, + work_time => '1234567890' }, + error => 'more than the maximum', + test => 'Passing too large of a work_time fails', + }, + { user => 'admin', + args => { id => 'public_bug', comment => '', + work_time => '1.0' }, + error => 'a comment argument', + test => 'Passing a work_time with an empty comment fails', + }, + + # Success tests + { user => 'unprivileged', + args => { id => 'public_bug', comment => TEST_COMMENT }, + test => 'Unprivileged user can add a comment to a public bug', + }, + { user => 'unprivileged', + args => { id => 'public_bug', comment => " \n" . TEST_COMMENT }, + test => 'Can add a comment to a bug where the first line is whitespace', + }, + { user => 'QA_Selenium_TEST', + args => { id => 'private_bug', comment => TEST_COMMENT }, + test => 'Privileged user can add a comment to a private bug', + check_privacy => 1, + }, + { user => 'QA_Selenium_TEST', + args => { id => 'public_bug', comment => TEST_COMMENT, + is_private => 1 }, + test => 'Insidergroup user can add a private comment', + check_privacy => 1, + }, + { user => 'admin', + args => { id => 'public_bug', comment => TEST_COMMENT, + work_time => '1.5' }, + test => 'Timetracking user can add work_time to a bug', + }, + # FIXME: Need to verify that the comment added actually has work_time. +); + +$jsonrpc_get->bz_call_fail('Bug.add_comment', + { id => 'public_bug', comment => TEST_COMMENT }, + 'must use HTTP POST', 'add_comment fails over GET'); + +foreach my $rpc ($jsonrpc, $xmlrpc) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.add_comment', + post_success => \&post_success); +} + +sub post_success { + my ($call, $t, $rpc) = @_; + return unless $t->{check_privacy}; + + my $comment_id = $call->result->{id}; + my $result = $rpc->bz_call_success('Bug.comments', {comment_ids => [$comment_id]}); + if ($t->{args}->{is_private}) { + ok($result->result->{comments}->{$comment_id}->{is_private}, + $rpc->TYPE . ": Comment $comment_id is private"); + } + else { + ok(!$result->result->{comments}->{$comment_id}->{is_private}, + $rpc->TYPE . ": Comment $comment_id is NOT private"); + } +} diff --git a/qa/t/webservice_bug_attachments.t b/qa/t/webservice_bug_attachments.t new file mode 100644 index 000000000..da63ddd27 --- /dev/null +++ b/qa/t/webservice_bug_attachments.t @@ -0,0 +1,151 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use QA::Tests qw(STANDARD_BUG_TESTS PRIVATE_BUG_USER); +use Data::Dumper; +use List::Util qw(first); +use MIME::Base64; +use Test::More tests => 313; +my ($config, @clients) = get_rpc_clients(); + +################ +# Bug ID Tests # +################ + +our %attachments; + +sub post_bug_success { + my ($call, $t) = @_; + + my $bugs = $call->result->{bugs}; + is(scalar keys %$bugs, 1, "Got exactly one bug") + or diag(Dumper($call->result)); + + my $bug_attachments = (values %$bugs)[0]; + # Collect attachment ids + foreach my $alias (qw(public_bug private_bug)) { + foreach my $is_private (0, 1) { + my $find_desc = "${alias}_${is_private}"; + my $attachment = first { $_->{summary} eq $find_desc } + reverse @$bug_attachments; + if ($attachment) { + $attachments{$find_desc} = $attachment->{id}; + } + } + } +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => STANDARD_BUG_TESTS, method => 'Bug.attachments', + post_success => \&post_bug_success); +} + +foreach my $alias (qw(public_bug private_bug)) { + foreach my $is_private (0, 1) { + ok($attachments{"${alias}_${is_private}"}, + "Found attachment id for ${alias}_${is_private}"); + } +} + +#################### +# Attachment Tests # +#################### + +my $content_file = '../config/generate_test_data.pl'; +open(my $fh, '<', $content_file) or die "$content_file: $!"; +my $content; +{ local $/; $content = <$fh>; } +close($fh); + +# Access tests for public/private stuff, and also validate that the +# format of each return value is correct. + +my @tests = ( + # Logged-out user + { args => { attachment_ids => [$attachments{'public_bug_0'}] }, + test => 'Logged-out user can access public attachment on public' + . ' bug by id', + }, + { args => { attachment_ids => [$attachments{'public_bug_1'}] }, + test => 'Logged-out user cannot access private attachment on public bug', + error => 'Sorry, you are not authorized', + }, + { args => { attachment_ids => [$attachments{'private_bug_0'}] }, + test => 'Logged-out user cannot access attachments by id on private bug', + error => 'You are not authorized to access', + }, + { args => { attachment_ids => [$attachments{'private_bug_1'}] }, + test => 'Logged-out user cannot access private attachment on ' + . ' private bug', + error => 'You are not authorized to access', + }, + + # Logged-in, unprivileged user. + { user => 'unprivileged', + args => { attachment_ids => [$attachments{'public_bug_0'}] }, + test => 'Logged-in user can see a public attachment on a public bug by id', + }, + { user => 'unprivileged', + args => { attachment_ids => [$attachments{'public_bug_1'}] }, + test => 'Logged-in user cannot access private attachment on public bug', + error => 'Sorry, you are not authorized', + }, + { user => 'unprivileged', + args => { attachment_ids => [$attachments{'private_bug_0'}] }, + test => 'Logged-in user cannot access attachments by id on private bug', + error => "You are not authorized to access", + }, + { user => 'unprivileged', + args => { attachment_ids => [$attachments{'private_bug_1'}] }, + test => 'Logged-in user cannot access private attachment on private bug', + error => "You are not authorized to access", + }, + + # User who can see private bugs and private attachments + { user => PRIVATE_BUG_USER, + args => { attachment_ids => [$attachments{'public_bug_1'}] }, + test => PRIVATE_BUG_USER . ' can see private attachment on public bug', + }, + { user => PRIVATE_BUG_USER, + args => { attachment_ids => [$attachments{'private_bug_1'}] }, + test => PRIVATE_BUG_USER . ' can see private attachment on private bug', + }, +); + +sub post_success { + my ($call, $t, $rpc) = @_; + is(scalar keys %{ $call->result->{attachments} }, 1, + "Got exactly one attachment"); + my $attachment = (values %{ $call->result->{attachments} })[0]; + + cmp_ok($attachment->{last_change_time}, '=~', $rpc->DATETIME_REGEX, + "last_change_time is in the right format"); + cmp_ok($attachment->{creation_time}, '=~', $rpc->DATETIME_REGEX, + "creation_time is in the right format"); + is($attachment->{is_obsolete}, 0, 'is_obsolete is 0'); + cmp_ok($attachment->{bug_id}, '=~', qr/^\d+$/, "bug_id is an integer"); + cmp_ok($attachment->{id}, '=~', qr/^\d+$/, "id is an integer"); + is($attachment->{content_type}, 'application/x-perl', + "content_type is correct"); + cmp_ok($attachment->{file_name}, '=~', qr/^\w+\.pl$/, + "filename is in the expected format"); + is($attachment->{creator}, $config->{QA_Selenium_TEST_user_login}, + "creator is the correct user"); + my $data = $attachment->{data}; + $data = decode_base64($data) if $rpc->isa('QA::RPC::JSONRPC'); + is($data, $content, 'data is correct'); + is($attachment->{size}, length($data), "size matches data's size"); +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(method => 'Bug.attachments', tests => \@tests, + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_comments.t b/qa/t/webservice_bug_comments.t new file mode 100644 index 000000000..df583c8ce --- /dev/null +++ b/qa/t/webservice_bug_comments.t @@ -0,0 +1,175 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +########################################## +# Test for xmlrpc call to Bug.comments() # +########################################## + +use strict; +use warnings; +use lib qw(lib); +use DateTime; +use QA::Util; +use QA::Tests qw(STANDARD_BUG_TESTS PRIVATE_BUG_USER); +use Test::More tests => 331; +my ($config, @clients) = get_rpc_clients(); + +# These gets populated when we call Bug.add_comment. +our $creation_time; +our %comments = ( + public_comment_public_bug => 0, + public_comment_private_bug => 0, + private_comment_public_bug => 0, + private_comment_private_bug => 0, +); + +sub test_comments { + my ($comments_returned, $call, $t, $rpc) = @_; + + my $comment = $comments_returned->[0]; + ok($comment->{bug_id}, "bug_id exists"); + # FIXME: At some point we should test attachment_id here. + + if ($t->{args}->{comment_ids}) { + my $expected_id = $t->{args}->{comment_ids}->[0]; + is($comment->{id}, $expected_id, "comment id is correct"); + + my %reverse_map = reverse %comments; + my $expected_text = $reverse_map{$expected_id}; + is($comment->{text}, $expected_text, "comment has the correct text"); + + my $priv_login = $rpc->bz_config->{PRIVATE_BUG_USER . '_user_login'}; + is($comment->{creator}, $priv_login, "comment creator is correct"); + + + my $creation_day; + if ($rpc->isa('QA::RPC::XMLRPC')) { + $creation_day = $creation_time->ymd(''); + } + else { + $creation_day = $creation_time->ymd; + } + like($comment->{time}, qr/^\Q${creation_day}\ET\d\d:\d\d:\d\d/, + "comment time has the right format"); + } + else { + foreach my $field (qw(id text creator time)) { + ok(defined $comment->{$field}, "$field is defined"); + } + } +} + +################ +# Bug ID Tests # +################ + +sub post_bug_success { + my ($call, $t) = @_; + my @bugs = values %{ $call->result->{bugs} }; + is(scalar @bugs, 1, "Got exactly one bug"); + my @comments = map { @{ $_->{comments} } } @bugs; + test_comments(\@comments, @_); +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => STANDARD_BUG_TESTS, method => 'Bug.comments', + post_success => \&post_bug_success); +} + +#################### +# Comment ID Tests # +#################### + +# First, create comments using add_comment. +my @add_comment_tests; +foreach my $key (keys %comments) { + $key =~ /^([a-z]+)_comment_(\w+)$/; + my $is_private = ($1 eq 'private' ? 1 : 0); + my $bug_alias = $2; + push(@add_comment_tests, { args => { id => $bug_alias, comment => $key, + private => $is_private }, + test => "Add comment: $key", + user => PRIVATE_BUG_USER }); +} + +# Set the comment id for each comment that we add, so we can test getting +# them back, later. +sub post_add { + my ($call, $t) = @_; + my $key = $t->{args}->{comment}; + $comments{$key} = $call->result->{id}; +} + +$creation_time = DateTime->now(); +# We only need to create these comments once, with one of the interfaces. +$clients[0]->bz_run_tests( + tests => \@add_comment_tests, method => 'Bug.add_comment', + post_success => \&post_add); + +# Now check access on each private and public comment + +my @comment_tests = ( + # Logged-out user + { args => { comment_ids => [$comments{'public_comment_public_bug'}] }, + test => 'Logged-out user can access public comment on public bug by id', + }, + { args => { comment_ids => [$comments{'private_comment_public_bug'}] }, + test => 'Logged-out user cannot access private comment on public bug', + error => 'is private', + }, + { args => { comment_ids => [$comments{'public_comment_private_bug'}] }, + test => 'Logged-out user cannot access comments by id on private bug', + error => 'You are not authorized to access', + }, + { args => { comment_ids => [$comments{'private_comment_private_bug'}] }, + test => 'Logged-out user cannot access private comment on private bug', + error => 'You are not authorized to access', + }, + + # Logged-in, unprivileged user. + { user => 'unprivileged', + args => { comment_ids => [$comments{'public_comment_public_bug'}] }, + test => 'Logged-in user can see a public comment on a public bug by id', + }, + { user => 'unprivileged', + args => { comment_ids => [$comments{'private_comment_public_bug'}] }, + test => 'Logged-in user cannot access private comment on public bug', + error => 'is private', + }, + { user => 'unprivileged', + args => { comment_ids => [$comments{'public_comment_private_bug'}] }, + test => 'Logged-in user cannot access comments by id on private bug', + error => "You are not authorized to access", + }, + { user => 'unprivileged', + args => { comment_ids => [$comments{'private_comment_private_bug'}] }, + test => 'Logged-in user cannot access private comment on private bug', + error => "You are not authorized to access", + }, + + # User who can see private bugs and private comments + { user => PRIVATE_BUG_USER, + args => { comment_ids => [$comments{'private_comment_public_bug'}] }, + test => PRIVATE_BUG_USER . ' can see private comment on public bug', + }, + { user => PRIVATE_BUG_USER, + args => { comment_ids => [$comments{'private_comment_private_bug'}] }, + test => PRIVATE_BUG_USER . ' can see private comment on private bug', + }, +); + +sub post_comments { + my ($call) = @_; + my @comments = values %{ $call->result->{comments} }; + is(scalar @comments, 1, "Got exactly one comment"); + test_comments(\@comments, @_); +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@comment_tests, method => 'Bug.comments', + post_success => \&post_comments); +} diff --git a/qa/t/webservice_bug_create.t b/qa/t/webservice_bug_create.t new file mode 100644 index 000000000..640a714be --- /dev/null +++ b/qa/t/webservice_bug_create.t @@ -0,0 +1,239 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################## +# Test for xmlrpc call to Bug.create() # +######################################## + +use strict; +use warnings; +use lib qw(lib); +use Storable qw(dclone); +use Test::More tests => 293; +use QA::Util; +use QA::Tests qw(create_bug_fields PRIVATE_BUG_USER); + +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +######################## +# Bug.create() testing # +######################## + +my $bug_fields = create_bug_fields($config); + +# hash to contain all the possible $bug_fields values that +# can be passed to createBug() +my $fields = { + summary => { + undefined => { + faultstring => 'You must enter a summary for this bug', + value => undef + }, + }, + + product => { + undefined => { faultstring => 'You must select/enter a product.', value => undef }, + invalid => + { faultstring => 'does not exist', value => 'does-not-exist' }, + }, + + component => { + undefined => { + faultstring => 'you must first choose a component', + value => undef + }, + invalid => { + faultstring => "There is no component named 'does-not-exist'", + value => 'does-not-exist' + }, + }, + + version => { + undefined => + { faultstring => 'You must select/enter a version.', value => undef }, + invalid => { + faultstring => "There is no version named 'does-not-exist' in the", + value => 'does-not-exist' + }, + }, + platform => { + undefined => + { faultstring => 'You must select/enter a Hardware.', + value => '' }, + invalid => { + faultstring => "There is no Hardware named 'does-not-exist'.", + value => 'does-not-exist' + }, + }, + + status => { + invalid => { + faultstring => "There is no status named 'does-not-exist'", + value => 'does-not-exist' + }, + }, + + severity => { + undefined => + { faultstring => 'You must select/enter a Severity.', + value => '' }, + invalid => { + faultstring => "There is no Severity named 'does-not-exist'.", + value => 'does-not-exist' + }, + }, + + priority => { + undefined => + { faultstring => 'You must select/enter a Priority.', + value => '' }, + invalid => { + faultstring => "There is no Priority named 'does-not-exist'.", + value => 'does-not-exist' + }, + }, + + op_sys => { + undefined => { + faultstring => 'You must select/enter a OS.', + value => '' + }, + invalid => { + faultstring => "There is no OS named 'does-not-exist'.", + value => 'does-not-exist' + }, + }, + + cc => { + invalid => { + faultstring => 'not a valid username', + value => ['nonuserATbugillaDOTorg'] + }, + }, + + assigned_to => { + invalid => { + faultstring => "There is no user named 'does-not-exist'", + value => 'does-not-exist' + }, + }, + qa_contact => { + invalid => { + faultstring => "There is no user named 'does-not-exist'", + value => 'does-not-exist' + }, + }, + alias => { + long => { + faultstring => 'Bug aliases cannot be longer than 20 characters', + value => 'MyyyyyyyyyyyyyyyyyyBugggggggggggggggggggggg' + }, + existing => { + faultstring => 'already taken the alias', + value => 'public_bug' + }, + numeric => { + faultstring => 'aliases cannot be merely numbers', + value => '12345' + }, + commma_or_space_separated => { + faultstring => 'contains one or more commas or spaces', + value => 'Bug 12345' + }, + + }, + groups => { + non_existent => { + faultstring => 'either this group does not exist, or you are not allowed to restrict bugs to this group', + value => [random_string(20)], + }, + }, + comment_is_private => { + invalid => { + faultstring => 'you are not allowed to.+comments.+private', + value => 1, + } + }, +}; + +$jsonrpc_get->bz_call_fail('Bug.create', $bug_fields, + 'must use HTTP POST', 'create fails over GET'); + +my @tests = ( + { args => $bug_fields, + error => "You must log in", + test => "Cannot file bugs as a logged-out user", + }, + { user => PRIVATE_BUG_USER, + args => { %$bug_fields, product => 'QA-Selenium-TEST', + component => 'QA-Selenium-TEST', + target_milestone => 'QAMilestone', + version => 'QAVersion', + groups => ['QA-Selenium-TEST'], + # These are set here because we can't actually set them, + # and we need the values to be correct for post_success. + qa_contact => $config->{PRIVATE_BUG_USER . '_user_login'}, + status => 'UNCONFIRMED' }, + test => "Authorized user can file a bug against a group", + }, + { user => PRIVATE_BUG_USER, + args => { %$bug_fields, comment_is_private => 1, + # These are here because PRIVATE_BUG_USER can't set them + # and we need their values to be correct for post_success. + assigned_to => $config->{'permanent_user'}, + qa_contact => '', + status => 'UNCONFIRMED' }, + test => "Insider can create a private description" + }, + { user => 'editbugs', + args => $bug_fields, + test => "Creating a bug with standard values succeeds", + }, +); + +# Convert the $fields tests into standard bz_run_tests format. +foreach my $field (sort keys %$fields) { + my $test_values = $fields->{$field}; + foreach my $test_name (sort keys %$test_values) { + my $input_fields = dclone($bug_fields); + my $check_value = $test_values->{$test_name}->{value}; + my $error = $test_values->{$test_name}->{faultstring}; + $input_fields->{$field} = $check_value; + my $test = { user => 'editbugs', args => $input_fields, + error => $error, + test => "$field $test_name: fails as expected" }; + push(@tests, $test); + } +} + +sub post_success { + my ($call, $t, $rpc) = @_; + + my $id = $call->result->{id}; + ok($id, $rpc->TYPE . ": Result has an id: $id"); + + my $get_call = $rpc->bz_call_success('Bug.get', { ids => [$id] }); + my $bug = $get_call->result->{bugs}->[0]; + + my $expect = dclone $t->{args}; + + my $comment_is_private = delete $expect->{comment_is_private}; + $expect->{creator} = $rpc->bz_config->{$t->{user} . '_user_login'}; + + my @fields = keys %$expect; + $rpc->bz_test_bug(\@fields, $bug, $expect, $t); + + my $comment_call = $rpc->bz_call_success('Bug.comments', { ids => [$id] }); + my $comment = $comment_call->result->{bugs}->{$id}->{comments}->[0]; + is($comment->{is_private} ? 1 : 0, $comment_is_private ? 1 : 0, + $rpc->TYPE . ": comment privacy is correct"); +} + +foreach my $rpc ($jsonrpc, $xmlrpc) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.create', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_fields.t b/qa/t/webservice_bug_fields.t new file mode 100644 index 000000000..d72b25170 --- /dev/null +++ b/qa/t/webservice_bug_fields.t @@ -0,0 +1,219 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use Data::Dumper; +use Test::More; +use List::Util qw(first); +use QA::Util; + +my ($config, @clients) = get_rpc_clients(); +plan tests => ($config->{test_extensions} ? 1338 : 1320); + +use constant INVALID_FIELD_NAME => 'invalid_field'; +use constant INVALID_FIELD_ID => -1; +sub GLOBAL_GENERAL_FIELDS { + my @fields = qw( + attach_data.thedata + attachments.description + attachments.filename + attachments.isobsolete + attachments.ispatch + attachments.isprivate + attachments.mimetype + attachments.submitter + + flagtypes.name + requestees.login_name + setters.login_name + + alias + assigned_to + blocked + bug_file_loc + bug_group + bug_id + cc + cclist_accessible + classification + commenter + content + creation_ts + days_elapsed + delta_ts + dependson + everconfirmed + keywords + longdesc + longdescs.isprivate + owner_idle_time + product + qa_contact + reporter + reporter_accessible + see_also + short_desc + status_whiteboard + + deadline + estimated_time + percentage_complete + remaining_time + work_time + ); + push(@fields, 'votes') if QA::Util::get_config()->{test_extensions}; + + return @fields; +} + +use constant STANDARD_SELECT_FIELDS => + qw(bug_severity bug_status op_sys priority rep_platform resolution); + +use constant ALL_SELECT_FIELDS => (STANDARD_SELECT_FIELDS, + qw(cf_qa_status cf_single_select)); +use constant PRODUCT_FIELDS => qw(version target_milestone component); +use constant ALL_FIELDS => (GLOBAL_GENERAL_FIELDS, ALL_SELECT_FIELDS, + PRODUCT_FIELDS); +use constant MANDATORY_FIELDS => qw(short_desc product version component); + +use constant PUBLIC_PRODUCT => 'Another Product'; +use constant PRIVATE_PRODUCT => 'QA-Selenium-TEST'; + +sub get_field { + my ($fields, $field) = @_; + return first { $_->{name} eq $field } @$fields; +} + +sub get_products_from_field { + my $field = shift; + my %products; + foreach my $value (@{ $field->{values} }) { + foreach my $vis_value (@{ $value->{visibility_values} }) { + $products{$vis_value} = 1; + } + } + return \%products; +} + +our %field_ids; +foreach my $rpc (@clients) { + my $call = $rpc->bz_call_success('Bug.fields'); + my $fields = $call->result->{fields}; + foreach my $field (ALL_FIELDS) { + my $field_data = get_field($fields, $field); + ok($field_data, "$field is in the returned result") + or diag(Dumper($fields)); + $field_ids{$field} = $field_data->{id}; + + if (grep($_ eq $field, MANDATORY_FIELDS)) { + ok($field_data->{is_mandatory}, "$field is mandatory"); + } + else { + ok(!$field_data->{is_mandatory}, "$field is not mandatory"); + } + } + + foreach my $field (ALL_SELECT_FIELDS, PRODUCT_FIELDS) { + my $field_data = get_field($fields, $field); + ok(defined $field_data->{visibility_values}, + "$field has visibility_values defined"); + my $field_vis_undefs = grep { !defined $_ } + @{ $field_data->{visibility_values} }; + is($field_vis_undefs, 0, "$field.visibility_values has no undefs") + or diag(Dumper($field_data->{visibility_values})); + + ok(defined $field_data->{values}, + "$field has 'values' defined"); + my $num_values = scalar @{ $field_data->{values} }; + ok($num_values, "$field has $num_values values"); + # The first bug status is a fake one and has no name, so we choose the 2nd item. + my $first_value = $field_data->{values}->[1]; + ok(defined $first_value->{name}, 'The first value has a name') + or diag(Dumper($field_data->{values})); + # The sortkey for milestones can be negative. + cmp_ok($first_value->{sortkey}, '=~', qr/^-?\d+$/, + "The first value has a numeric sortkey"); + + ok(defined $first_value->{visibility_values}, + "$field has visibilty_values defined on its first value") + or diag(Dumper($field_data->{values})); + my @value_visibility_values = map { @{ $_->{visibility_values} } } + @{ $field_data->{values} }; + my $undefs = grep { !defined $_ } @value_visibility_values; + is($undefs, 0, + "$field.values.visibility_values has no undefs"); + } + + foreach my $field (PRODUCT_FIELDS) { + my $field_data = get_field($fields, $field); + is($field_data->{value_field}, 'product', + "The value_field for $field is 'product'"); + my $products = get_products_from_field($field_data); + ok($products->{+PUBLIC_PRODUCT}, + "$field values are returned for the public product"); + ok(!$products->{+PRIVATE_PRODUCT}, + "No $field values are returned for the private product"); + } +} + +my @all_tests = ( + { args => { ids => [values %field_ids], + names => [ALL_FIELDS] }, + test => 'Getting all fields by name and id simultaneously', + count => scalar ALL_FIELDS + }, + { args => { names => [INVALID_FIELD_NAME] }, + error => "There is no field named", + test => 'Invalid field name' + }, + { args => { ids => [INVALID_FIELD_ID] }, + error => 'must be numeric', + test => 'Invalid field id' + }, + { user => 'QA_Selenium_TEST', + args => { names => [PRODUCT_FIELDS] }, + test => 'Getting product-specific fields as a privileged user', + count => scalar PRODUCT_FIELDS, + product_private_values => 1 + }, +); + +foreach my $field (ALL_FIELDS) { + push(@all_tests, + { args => { names => [$field] }, + test => "Logged-out users can get the $field field by name" }); + push(@all_tests, + { args => { ids => [$field_ids{$field}] }, + test => "Logged-out users can get the $field by id" }); +} + +sub post_success { + my ($call, $t) = @_; + my $fields = $call->result->{fields}; + my $count = $t->{count}; + $count = 1 if !defined $count; + is(scalar @$fields, $count, "Exactly $count field(s) returned"); + + if ($t->{product_private_values}) { + foreach my $field (@$fields) { + my $name = $field->{name}; + my $field_data = get_field($fields, $name); + my $products = get_products_from_field($field_data); + ok($products->{+PUBLIC_PRODUCT}, + "$name values are returned for the public product"); + ok($products->{+PRIVATE_PRODUCT}, + "$name values are returned for the private product"); + } + } +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@all_tests, method => 'Bug.fields', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_get.t b/qa/t/webservice_bug_get.t new file mode 100644 index 000000000..a68f92899 --- /dev/null +++ b/qa/t/webservice_bug_get.t @@ -0,0 +1,146 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +########################################### +# Test for xmlrpc call to Bug.get() # +########################################### + +use strict; +use warnings; +use lib qw(lib); +use Data::Dumper; +use DateTime; +use QA::Util; +use QA::Tests qw(bug_tests PRIVATE_BUG_USER); +use Test::More tests => 1012; +my ($config, @clients) = get_rpc_clients(); + +my $xmlrpc = $clients[0]; +our $creation_time = DateTime->now(); +our ($public_bug, $private_bug) = $xmlrpc->bz_create_test_bugs('private'); +my $private_id = $private_bug->{id}; +my $public_id = $public_bug->{id}; + +my $base_url = $config->{browser_url} . "/" + . $config->{bugzilla_installation} . '/'; + +# Set a few fields on the private bug, including setting up +# a dependency relationship. +$xmlrpc->bz_log_in(PRIVATE_BUG_USER); +$xmlrpc->bz_call_success('Bug.update', { + ids => [$private_id], + blocks => { set => [$public_id] }, + dupe_of => $public_id, + is_creator_accessible => 0, + keywords => { set => ['test-keyword-1', 'test-keyword-2'] }, + see_also => { add => ["${base_url}show_bug.cgi?id=$public_id", + "http://landfill.bugzilla.org/show_bug.cgi?id=123456"] }, + cf_qa_status => ['in progress', 'verified'], + cf_single_select => 'two', +}, 'Update the private bug'); +$xmlrpc->bz_call_success('User.logout'); + +$private_bug->{blocks} = [$public_id]; +$private_bug->{dupe_of} = $public_id; +$private_bug->{status} = 'RESOLVED'; +$private_bug->{is_open} = 0; +$private_bug->{resolution} = 'DUPLICATE'; +$private_bug->{is_creator_accessible} = 0; +$private_bug->{is_cc_accessible} = 1; +$private_bug->{keywords} = ['test-keyword-1', 'test-keyword-2']; +$private_bug->{see_also} = ["${base_url}show_bug.cgi?id=$public_id", + "http://landfill.bugzilla.org/show_bug.cgi?id=123456"]; +$private_bug->{cf_qa_status} = ['in progress', 'verified']; +$private_bug->{cf_single_select} = 'two'; + +$public_bug->{depends_on} = [$private_id]; +$public_bug->{dupe_of} = undef; +$public_bug->{resolution} = ''; +$public_bug->{is_open} = 1; +$public_bug->{is_creator_accessible} = 1; +$public_bug->{is_cc_accessible} = 1; +$public_bug->{keywords} = []; +# Local Bugzilla bugs are automatically updated. +$public_bug->{see_also} = ["${base_url}show_bug.cgi?id=$private_id"]; +$public_bug->{cf_qa_status} = []; +$public_bug->{cf_single_select} = '---'; + +# Fill in the timetracking fields on the public bug. +$xmlrpc->bz_log_in('admin'); +$xmlrpc->bz_call_success('Bug.update', { + ids => [$public_id], + deadline => '2038-01-01', + estimated_time => '10.0', + remaining_time => '5.0', +}); +$xmlrpc->bz_call_success('User.logout'); + +# Populate other fields. +$public_bug->{classification} = 'Unclassified'; +$private_bug->{classification} = 'Unclassified'; +$private_bug->{groups} = ['QA-Selenium-TEST']; +$public_bug->{groups} = []; + +# The user filing $private_bug doesn't have permission to set the status +# or qa_contact, so they differ from normal $public_bug values. +$private_bug->{qa_contact} = $config->{PRIVATE_BUG_USER . '_user_login'}; + +sub post_success { + my ($call, $t, $rpc) = @_; + + is(scalar @{ $call->result->{bugs} }, 1, "Got exactly one bug"); + my $bug = $call->result->{bugs}->[0]; + + if ($t->{user} && $t->{user} eq 'admin') { + ok(exists $bug->{estimated_time} && exists $bug->{remaining_time}, + 'Admin correctly gets time-tracking fields'); + is($bug->{deadline}, '2038-01-01', 'deadline is correct'); + cmp_ok($bug->{estimated_time}, '==', '10.0', + 'estimated_time is correct'); + cmp_ok($bug->{remaining_time}, '==', '5.0', + 'remaining_time is correct'); + } + else { + ok(!exists $bug->{estimated_time} && !exists $bug->{remaining_time}, + 'Time-tracking fields are not returned to non-privileged users'); + } + + if ($t->{user}) { + ok($bug->{update_token}, 'Update token returned for logged-in user'); + } + else { + ok(!exists $bug->{update_token}, + 'Update token not returned for logged-out users'); + } + + my $expect = $bug->{id} == $private_bug->{id} ? $private_bug : $public_bug; + + my @fields = sort keys %$expect; + push(@fields, 'creation_time', 'last_change_time'); + + $rpc->bz_test_bug(\@fields, $bug, $expect, $t, $creation_time); +} + +my @tests = ( + @{ bug_tests($public_id, $private_id) }, + { args => { ids => [$public_id], + include_fields => ['id', 'summary', 'groups'] }, + test => 'include_fields', + }, + { args => { ids => [$public_id], + exclude_fields => ['assigned_to', 'cf_qa_status'] }, + test => 'exclude_fields' }, + { args => { ids => [$public_id], + include_fields => ['id', 'summary', 'groups'], + exclude_fields => ['summary'] }, + test => 'exclude_fields overrides include_fields' }, +); + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.get', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_get_bugs.t b/qa/t/webservice_bug_get_bugs.t new file mode 100644 index 000000000..d83861350 --- /dev/null +++ b/qa/t/webservice_bug_get_bugs.t @@ -0,0 +1,146 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +########################################### +# Test for xmlrpc call to Bug.get_bugs() # +########################################### + +use strict; +use warnings; +use lib qw(lib); +use Data::Dumper; +use DateTime; +use QA::Util; +use QA::Tests qw(bug_tests PRIVATE_BUG_USER); +use Test::More tests => 1012; +my ($config, @clients) = get_rpc_clients(); + +my $xmlrpc = $clients[0]; +our $creation_time = DateTime->now(); +our ($public_bug, $private_bug) = $xmlrpc->bz_create_test_bugs('private'); +my $private_id = $private_bug->{id}; +my $public_id = $public_bug->{id}; + +my $base_url = $config->{browser_url} . "/" + . $config->{bugzilla_installation} . '/'; + +# Set a few fields on the private bug, including setting up +# a dependency relationship. +$xmlrpc->bz_log_in(PRIVATE_BUG_USER); +$xmlrpc->bz_call_success('Bug.update', { + ids => [$private_id], + blocks => { set => [$public_id] }, + dupe_of => $public_id, + is_creator_accessible => 0, + keywords => { set => ['test-keyword-1', 'test-keyword-2'] }, + see_also => { add => ["${base_url}show_bug.cgi?id=$public_id"] }, + cf_qa_status => ['in progress', 'verified'], + cf_single_select => 'two', +}, 'Update the private bug'); +$xmlrpc->bz_call_success('User.logout'); + +$private_bug->{blocks} = [$public_id]; +$private_bug->{dupe_of} = $public_id; +$private_bug->{status} = 'RESOLVED'; +$private_bug->{is_open} = 0; +$private_bug->{resolution} = 'DUPLICATE'; +$private_bug->{is_creator_accessible} = 0; +$private_bug->{is_cc_accessible} = 1; +$private_bug->{keywords} = ['test-keyword-1', 'test-keyword-2']; +$private_bug->{see_also} = ["${base_url}show_bug.cgi?id=$public_id"]; +$private_bug->{cf_qa_status} = ['in progress', 'verified']; +$private_bug->{cf_single_select} = 'two'; + +$public_bug->{depends_on} = [$private_id]; +$public_bug->{dupe_of} = undef; +$public_bug->{resolution} = ''; +$public_bug->{is_open} = 1; +$public_bug->{is_creator_accessible} = 1; +$public_bug->{is_cc_accessible} = 1; +$public_bug->{keywords} = []; +$public_bug->{see_also} = ["${base_url}show_bug.cgi?id=$private_id"]; +$public_bug->{cf_qa_status} = []; +$public_bug->{cf_single_select} = '---'; + +# Fill in the timetracking fields on the public bug. +$xmlrpc->bz_log_in('admin'); +$xmlrpc->bz_call_success('Bug.update', { + ids => [$public_id], + deadline => '2038-01-01', + estimated_time => '10.0', + remaining_time => '5.0', +}); +$xmlrpc->bz_call_success('User.logout'); + +# Populate other fields. +$public_bug->{classification} = 'Unclassified'; +$private_bug->{classification} = 'Unclassified'; +$private_bug->{groups} = ['QA-Selenium-TEST']; +$public_bug->{groups} = []; + +# The user filing $private_bug doesn't have permission to set the status +# or qa_contact, so they differ from normal $public_bug values. +$private_bug->{qa_contact} = $config->{PRIVATE_BUG_USER . '_user_login'}; + +sub post_success { + my ($call, $t, $rpc) = @_; + + is(scalar @{ $call->result->{bugs} }, 1, "Got exactly one bug"); + my $bug = $call->result->{bugs}->[0]; + + if ($t->{user} && $t->{user} eq 'admin') { + ok(exists $bug->{estimated_time} && exists $bug->{remaining_time} + && exists $bug->{deadline}, + 'Admin correctly gets time-tracking fields'); + + is($bug->{deadline}, '2038-01-01', 'deadline is correct'); + cmp_ok($bug->{estimated_time}, '==', '10.0', + 'estimated_time is correct'); + cmp_ok($bug->{remaining_time}, '==', '5.0', + 'remaining_time is correct'); + } + else { + ok(!exists $bug->{estimated_time} && !exists $bug->{remaining_time} + && !exists $bug->{deadline}, + 'Time-tracking fields are not returned to non-privileged users'); + } + + if ($t->{user}) { + ok($bug->{update_token}, 'Update token returned for logged-in user'); + } + else { + ok(!exists $bug->{update_token}, + 'Update token not returned for logged-out users'); + } + + my $expect = $bug->{id} == $private_bug->{id} ? $private_bug : $public_bug; + + my @fields = sort keys %$expect; + push(@fields, 'creation_time', 'last_change_time'); + + $rpc->bz_test_bug(\@fields, $bug, $expect, $t, $creation_time); +} + +my @tests = ( + @{ bug_tests($public_id, $private_id) }, + { args => { ids => [$public_id], + include_fields => ['id', 'summary', 'groups'] }, + test => 'include_fields', + }, + { args => { ids => [$public_id], + exclude_fields => ['assigned_to', 'cf_qa_status'] }, + test => 'exclude_fields' }, + { args => { ids => [$public_id], + include_fields => ['id', 'summary', 'groups'], + exclude_fields => ['summary'] }, + test => 'exclude_fields overrides include_fields' }, +); + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.get', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_history.t b/qa/t/webservice_bug_history.t new file mode 100644 index 000000000..3153834fa --- /dev/null +++ b/qa/t/webservice_bug_history.t @@ -0,0 +1,29 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################### +# Test for xmlrpc call to Bug.history() # +######################################### + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use QA::Tests qw(STANDARD_BUG_TESTS); +use Test::More tests => 114; +my ($config, @clients) = get_rpc_clients(); + +sub post_success { + my ($call, $t) = @_; + is(scalar @{ $call->result->{bugs} }, 1, "Got exactly one bug"); + isa_ok($call->result->{bugs}->[0]->{history}, 'ARRAY', "Bug's history"); +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => STANDARD_BUG_TESTS, + method => 'Bug.history', post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_legal_values.t b/qa/t/webservice_bug_legal_values.t new file mode 100644 index 000000000..8e1b039a3 --- /dev/null +++ b/qa/t/webservice_bug_legal_values.t @@ -0,0 +1,100 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +############################################## +# Test for xmlrpc call to Bug.legal_values() # +############################################## + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 269; +use QA::Util; +my ($config, @clients) = get_rpc_clients(); + +use constant INVALID_PRODUCT_ID => -1; +use constant INVALID_FIELD_NAME => 'invalid_field'; +use constant GLOBAL_FIELDS => + qw(bug_severity bug_status op_sys priority rep_platform resolution + cf_qa_status cf_single_select); +use constant PRODUCT_FIELDS => qw(version target_milestone component); + + +my $products = $clients[0]->bz_get_products(); +my $public_product = $products->{'Another Product'}; +my $private_product = $products->{'QA-Selenium-TEST'}; + +my @all_tests; + +for my $field (GLOBAL_FIELDS) { + push(@all_tests, + { args => { field => $field }, + test => "Logged-out user can get $field values" }); +} + +for my $field (PRODUCT_FIELDS) { + my @tests = ( + { args => { field => $field }, + error => "argument was not set", + test => "$field can't be accessed without a value for 'product'", + }, + { args => { product_id => INVALID_PRODUCT_ID, field => $field }, + error => "does not exist", + test => "$field cannot be accessed with an invalid product id", + }, + + { args => { product_id => $private_product, field => $field }, + error => "you don't have access", + test => "Logged-out user cannot access $field in private product" + }, + { args => { product_id => $public_product, field => $field }, + test => "Logged-out user can access $field in a public product", + }, + + { user => 'unprivileged', + args => { product_id => $private_product, field => $field }, + error => "you don't have access", + test => "Unprivileged user cannot access $field in private product", + }, + { user => 'unprivileged', + args => { product_id => $public_product, field => $field }, + test => "Logged-in user can access $field in public product", + }, + + { user => 'QA_Selenium_TEST', + args => { product_id => $private_product, field => $field }, + test => "Privileged user can access $field in a private product", + }, + ); + + push(@all_tests, @tests); +} + +my @extra_tests = ( + { args => { product_id => $private_product, }, + error => "requires a field argument", + test => "Passing product_id without 'field' throws an error", + }, + { args => { field => INVALID_FIELD_NAME }, + error => "Can't use " . INVALID_FIELD_NAME . " as a field name", + test => 'Invalid field name' + }, +); + +push(@all_tests, @extra_tests); + +sub post_success { + my ($call) = @_; + + cmp_ok(scalar @{ $call->result->{'values'} }, '>', 0, + 'Got one or more values'); +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@all_tests, method => 'Bug.legal_values', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_search.t b/qa/t/webservice_bug_search.t new file mode 100644 index 000000000..0a4dcd666 --- /dev/null +++ b/qa/t/webservice_bug_search.t @@ -0,0 +1,185 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################## +# Test for xmlrpc call to Bug.search() # +######################################## + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use QA::Tests qw(PRIVATE_BUG_USER); +use DateTime; +use List::MoreUtils qw(uniq); +use Test::More; + +my ($config, @clients) = get_rpc_clients(); +plan tests => $config->{test_extensions} ? 515 : 506; + +my ($public_bug, $private_bug) = $clients[0]->bz_create_test_bugs('private'); + +my @tests; +foreach my $field (keys %$public_bug) { + next if ($field eq 'cc' or $field eq 'description'); + my $test = { args => { $field => $public_bug->{$field} }, + test => "Search by $field" }; + if ( grep($_ eq $field, qw(alias whiteboard summary)) ) { + $test->{exactly} = 1; $test->{bugs} = 1; + } + push(@tests, $test); +} + + +push(@tests, ( + { args => { offset => 1 }, + test => "Offset without limit fails", + error => 'requires a limit argument', + }, + + { args => { alias => $private_bug->{alias} }, + test => 'Logged-out cannot find a private_bug by alias', + bugs => 0, + }, + + { args => { creation_time => '19700101T00:00:00' }, + test => 'Get all bugs by creation time', + }, + { args => { creation_time => '20380101T00:00:00' }, + test => 'Get no bugs, by creation time', + bugs => 0, + }, + { args => { last_change_time => '19700101T00:00:00' }, + test => 'Get all bugs by last_change_time', + }, + { args => { last_change_time => '20380101T00:00:00' }, + test => 'Get no bugs by last_change_time', + bugs => 0, + }, + + { args => { reporter => $config->{editbugs_user_login} }, + test => 'Search by reporter', + }, + { args => { resolution => '---' }, + test => 'Search for empty resolution', + }, + { args => { resolution => 'NO_SUCH_RESOLUTION' }, + test => 'Search for invalid resolution', + bugs => 0, + }, + { args => { summary => substr($public_bug->{summary}, 0, 50) }, + test => 'Search by partial summary', + bugs => 1, exactly => 1 + }, + { args => { summary => random_string() . ' ' . random_string() }, + test => 'Summary search that returns no results', + bugs => 0, + }, + { args => { summary => [split(/\s/, $public_bug->{summary})] }, + test => 'Summary search using multiple terms', + }, + + { args => { whiteboard => substr($public_bug->{whiteboard}, 0, 50) }, + test => 'Search by partial whiteboard', + bugs => 1, exactly => 1, + }, + { args => { whiteboard => random_string(100) }, + test => 'Whiteboard search that returns no results', + bugs => 0, + }, + { args => { whiteboard => [split(/\s/, $public_bug->{whiteboard})] }, + test => 'Whiteboard search using multiple terms', + bugs => 1, exactly => 1, + }, + + { args => { product => $public_bug->{product}, + component => $public_bug->{component}, + last_change_time => '19700101T00:00:00' }, + test => 'Search by multiple arguments', + }, + + # Logged-in user who can see private bugs + { user => PRIVATE_BUG_USER, + args => { alias => [$public_bug->{alias}, $private_bug->{alias}] }, + test => 'Search using two aliases (including one private)', + bugs => 2, exactly => 1, + }, + { user => PRIVATE_BUG_USER, + args => { product => [$public_bug->{product}, $private_bug->{product}], + limit => 1 }, + test => 'Limit 1', + bugs => 1, exactly => 1, + }, + { user => PRIVATE_BUG_USER, + args => { product => [$public_bug->{product}, $private_bug->{product}], + limit => 1, offset => 1 }, + test => 'Limit 1 Offset 1', + bugs => 1, exactly => 1, + }, + + # include_fields ane exclude_fields + { args => { id => $public_bug->{id}, + include_fields => ['id', 'alias', 'summary', 'groups'] }, + test => 'include_fields', + }, + { args => { id => $public_bug->{id}, + exclude_fields => ['assigned_to', 'cf_qa_status'] }, + test => 'exclude_fields' }, + { args => { id => $public_bug->{id}, + include_fields => ['id', 'alias', 'summary', 'groups'], + exclude_fields => ['summary'] }, + test => 'exclude_fields overrides include_fields' }, +)); + +push(@tests, + { args => { votes => 1 }, + test => 'Search by votes', + bugs => -1, # We don't care how many it returns, for now. + }) if $config->{test_extensions}; + +sub post_success { + my ($call, $t) = @_; + my $bugs = $call->result->{bugs}; + my $expected_count = $t->{bugs}; + $expected_count = 1 if !defined $expected_count; + if ($expected_count) { + my $operator = $t->{exactly} ? '==' : '>='; + cmp_ok(scalar @$bugs, $operator, $expected_count, + 'The right number of bugs are returned'); + unless ($t->{user} and $t->{user} eq PRIVATE_BUG_USER) { + ok(!grep($_->{alias} && $_->{alias} eq $private_bug->{alias}, @$bugs), + 'Result does not contain the private bug'); + } + + my @include = @{ $t->{args}->{include_fields} || [] }; + my @exclude = @{ $t->{args}->{exclude_fields} || [] }; + if (@include or @exclude) { + my @check_fields = uniq (keys %$public_bug, @include); + foreach my $field (sort @check_fields) { + next if $field eq 'description'; + if ((@include and !grep { $_ eq $field } @include ) + or (@exclude and grep { $_ eq $field } @exclude)) + { + ok(!exists $bugs->[0]->{$field}, "$field is not included") + or diag Dumper($bugs); + } + else { + ok(exists $bugs->[0]->{$field}, "$field is included"); + } + } + } + + } + else { + is(scalar @$bugs, 0, 'No bugs returned'); + } +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@tests, + method => 'Bug.search', post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_update.t b/qa/t/webservice_bug_update.t new file mode 100644 index 000000000..a9a01386a --- /dev/null +++ b/qa/t/webservice_bug_update.t @@ -0,0 +1,683 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use Data::Dumper; +use QA::Util; +use QA::Tests qw(PRIVATE_BUG_USER STANDARD_BUG_TESTS); +use Storable qw(dclone); +use Test::More tests => 927; + +use constant NONEXISTANT_BUG => 12_000_000; + +############### +# Subroutines # +############### + +# We have to generate different values for each RPC client, so we +# have a function to generate the tests for each client. +sub get_tests { + my ($config, $rpc) = @_; + + # update doesn't support logged-out users. + my @tests = grep { $_->{user} } @{ STANDARD_BUG_TESTS() }; + + my ($public_bug, $second_bug) = $rpc->bz_create_test_bugs(); + my ($public_id, $second_id) = ($public_bug->{id}, $second_bug->{id}); + + my $comment_call = $rpc->bz_call_success( + 'Bug.comments', { ids => [$public_id, $second_id] }); + $public_bug->{comment} = + $comment_call->result->{bugs}->{$public_id}->{comments}->[0]; + $second_bug->{comment} = + $comment_call->result->{bugs}->{$second_id}->{comments}->[0]; + + push(@tests, ( + { args => { ids => [$public_id] }, + error => 'You must log in', + test => 'Logged-out users cannot call update' }, + + # FIXME: We need a permissions test for canedit, but it's so uncommonly + # used that it's not a high priority. + )); + + my %valid = valid_values($config, $public_bug, $second_bug); + my $valid_value_tests = valid_values_to_tests(\%valid, $public_bug); + push(@tests, @$valid_value_tests); + + my %invalid = invalid_values($public_bug, $second_bug); + my $invalid_value_tests = invalid_values_to_tests(\%invalid, $public_bug); + push(@tests, @$invalid_value_tests); + + return \@tests; +} + +sub valid_values { + my ($config, $public_bug, $second_bug) = @_; + + my $admin = $config->{'admin_user_login'}; + my $second_id = $second_bug->{id}; + my $comment_id = $public_bug->{comment}->{id}; + my $bug_uri = $config->{browser_url} . '/' + . $config->{bugzilla_installation} . '/show_bug.cgi?id='; + + my %values = ( + alias => [ + { value => random_string(20) }, + ], + assigned_to => [ + { value => $config->{'unprivileged_user_login'} } + ], + blocks => [ + { value => { set => [$second_id] }, + added => $second_id, + test => 'set to second bug' }, + { value => { remove => [$second_id] }, + added => '', removed => $second_id, + test => 'remove second bug' }, + { value => { add => [$second_id] }, + added => $second_id, removed => '', + test => 'add second bug' }, + { value => { set => [] }, + added => '', removed => $second_id, + test => 'set to nothing' }, + ], + + cc => [ + { value => { add => [$admin] }, + added => $admin, removed => '', + test => 'add admin' }, + { value => { remove => [$admin] }, + added => '', removed => $admin, + test => 'remove admin' }, + { value => { remove => [$admin] }, + test => "removing user who isn't on the list works", + no_changes => 1 }, + ], + + is_cc_accessible => [ + { value => 0, test => 'set to 0' }, + { value => 1, test => 'set to 1' }, + ], + + comment => [ + { value => { body => random_string(100) }, test => 'public' }, + { value => { body => random_string(100), is_private => 1 }, + user => PRIVATE_BUG_USER, test => 'private' }, + ], + + comment_is_private => [ + { value => { $comment_id => 1 }, + user => PRIVATE_BUG_USER, test => 'make description private' }, + { value => { $comment_id => 0 }, + user => PRIVATE_BUG_USER, test => 'make description public' }, + ], + + component => [ + { value => 'c2' } + ], + + deadline => [ + { value => '2037-01-01' }, + { value => '', removed => '2037-01-01', test => 'remove' }, + ], + + dupe_of => [ + { value => $second_id }, + ], + + estimated_time => [ + { value => '10.0' }, + { value => '0.0', removed => '10.0', test => 'set to zero' }, + ], + + groups => [ + { value => { add => ['Master'] }, + user => 'admin', added => 'Master', test => 'add Master' }, + { value => { remove => ['Master'] }, + user => 'admin', added => '', removed => 'Master', + test => 'remove Master' }, + ], + + keywords => [ + { value => { add => ['test-keyword-1'] }, + test => 'add one', added => 'test-keyword-1' }, + { value => { set => ['test-keyword-1', 'test-keyword-2'] }, + test => 'set two', added => 'test-keyword-2' }, + { value => { remove => ['test-keyword-1'] }, + removed => 'test-keyword-1', added => '', + test => 'remove one' }, + { value => { set => [] }, + removed => 'test-keyword-2', added => '', + test => 'set to empty' }, + { value => { remove => ['test-keyword-2'] }, + test => 'removing removed keyword does nothing', + no_changes => 1 }, + ], + + op_sys => [ + { value => 'All' }, + ], + + platform => [ + { value => 'All' }, + ], + + priority => [ + { value => 'Normal' }, + ], + + product => [ + { value => 'C2 Forever', + extra => { + component => 'Helium', version => 'unspecified', + target_milestone => '---', + }, + test => 'move to C2 Forever' + }, + # This also tests that the extra fields transfer over properly + # when they have identical names in both products. + { value => $public_bug->{product}, + extra => { component => $public_bug->{component} }, + test => 'move back to original product' }, + ], + + qa_contact => [ + { value => $admin }, + { value => '', test => 'set blank', removed => $admin }, + # Reset to the original so that reset_qa_contact can also be tested. + { value => $public_bug->{qa_contact} }, + ], + + remaining_time => [ + { value => '1000.50' }, + { value => 0 }, + ], + + reset_assigned_to => [ + { value => 1, field => 'assigned_to', + added => $config->{permanent_user} }, + ], + + reset_qa_contact => [ + { value => 1, field => 'qa_contact', added => '' }, + ], + + resolution => [ + { value => 'FIXED', extra => { status => 'RESOLVED' }, + test => 'to RESOLVED FIXED' }, + { value => 'INVALID', test => 'just resolution' }, + ], + + see_also => [ + { value => { add => [$bug_uri . $second_id] }, + added => $bug_uri . $second_id, removed => '', + test => 'add local bug URI' }, + { value => { remove => [$bug_uri . $second_id] }, + removed => $bug_uri . $second_id, added => '', + test => 'remove local bug URI' }, + { value => { remove => ['http://landfill.bugzilla.org/bugzilla-tip/show_bug.cgi?id=1'] }, + no_changes => 1, + test => 'removing non-existent URI works' }, + { value => { add => [''] }, + no_changes => 1, + test => 'adding an empty string to see_also does nothing' }, + { value => { add => [undef] }, + no_changes => 1, + test => 'adding a null to see_also does nothing' }, + ], + + status => [ + # At this point, due to previous tests, the status is RESOLVED, + # so changing to CONFIRMED is our only real option if we want to + # test a simple open status. + { value => 'CONFIRMED' }, + ], + + severity => [ + { value => 'critical' }, + ], + + summary => [ + { value => random_string(100) }, + ], + + target_milestone => [ + { value => 'AnotherMS2' }, + ], + + url => [ + { value => 'http://' . random_string(20) . '/' }, + ], + + version => [ + { value => 'Another2' }, + ], + + whiteboard => [ + { value => random_string(1000) }, + ], + + work_time => [ + # FIXME: work_time really needs to start showing up in the changes hash. + { value => '1.2', no_changes => 1 }, + { value => '-1.2', test => 'negative value', no_changes => 1 }, + ], + ); + + $values{depends_on} = $values{blocks}; + $values{is_creator_accessible} = $values{is_cc_accessible}; + + return %values; +}; + +sub valid_values_to_tests { + my ($valid_values, $public_bug) = @_; + + my @tests; + foreach my $field (sort keys %$valid_values) { + my @tests_valid = @{ $valid_values->{$field} }; + foreach my $item (@tests_valid) { + my $desc = $item->{test} || 'valid value'; + my %args = ( + ids => [$public_bug->{id}], + $field => $item->{value}, + %{ $item->{extra} || {} }, + ); + my %test = ( user => 'editbugs', args => \%args, field => $field, + test => "$field: $desc" ); + foreach my $item_field (qw(no_changes added removed field user)) { + next if !exists $item->{$item_field}; + $test{$item_field} = $item->{$item_field}; + } + push(@tests, \%test); + } + } + + return \@tests; +} + +sub invalid_values { + my ($public_bug, $second_bug) = @_; + + my $public_id = $public_bug->{id}; + my $second_id = $second_bug->{id}; + + my $comment_id = $public_bug->{comment}->{id}; + my $second_comment_id = $second_bug->{comment}->{id}; + + my %values = ( + alias => [ + { value => random_string(41), + error => 'aliases cannot be longer than', + test => 'alias cannot be too long' }, + { value => $second_bug->{alias}, + error => 'has already taken the alias', + test => 'duplicate alias fails' }, + { value => 123456, + error => 'at least one letter', + test => 'numeric alias fails' }, + { value => random_string(20), ids => [$public_id, $second_id], + error => 'aliases when modifying multiple', + test => 'setting alias on multiple bugs fails' }, + ], + + assigned_to => [ + { value => random_string(20), + error => 'There is no user named', + test => 'changing assigned_to to invalid user fails' }, + # FIXME: Also check strict_isolation at some point in the future, perhaps. + ], + + blocks => [ + { value => { add => [NONEXISTANT_BUG] }, + error => 'does not exist', + test => 'Non-existent bug number fails in deps' }, + { value => { add => [$public_id] }, + error => 'block itself or depend on itself', + test => "can't add this bug itself in a dep field" }, + # FIXME: Could use strict_isolation checks at some point. + # FIXME: Could use a dependency_loop_multi test. + ], + + cc => [ + { value => { add => [random_string(20)] }, + error => 'There is no user named', + test => 'adding invalid user to cc fails' }, + { value => { remove => [random_string(20)] }, + error => 'There is no user named', + test => 'removing invalid user from cc fails' }, + ], + + comment => [ + { value => { body => random_string(100_000) }, + error => 'cannot be longer', + test => 'comment too long' }, + { value => { body => random_string(100), is_private => 1 }, + error => 'comments or attachments as private', + test => 'normal user cannot add private comments' }, + ], + + comment_is_private => [ + { value => { $comment_id => 1 }, + error => 'comments or attachments as private', + test => 'normal user cannot make a comment private' }, + { value => { $second_comment_id => 1 }, + error => 'You tried to modify the privacy of comment', + user => PRIVATE_BUG_USER, + test => 'cannot change privacy on a comment on another bug' }, + ], + + component => [ + { value => '', + error => 'you must first choose a component', + test => 'empty component fails' }, + { value => random_string(20), + error => 'There is no component named', + test => 'invalid component fails' }, + ], + + deadline => [ + { value => random_string(20), + error => 'is not a legal date', + test => 'Non-date fails in deadline' }, + { value => '2037', + error => 'is not a legal date', + test => 'year alone fails in deadline' }, + ], + + dupe_of => [ + { value => undef, + error => 'dup_id was not defined', + test => 'undefined dupe_of fails' }, + { value => NONEXISTANT_BUG, + error => 'does not exist', + test => 'Cannot dup to a nonexistant bug' }, + { value => $public_id, + error => 'as a duplicate of itself', + test => 'Cannot dup bug to itself' }, + ], + + estimated_time => [ + { value => -1, + error => 'less than the minimum allowable value', + test => 'negative estimated_time fails' }, + { value => 100_000_000, + error => 'more than the maximum allowable value', + test => 'too-large estimated_time fails' }, + { value => random_string(20), + error => 'is not a numeric value', + test => 'non-numeric estimated_time fails' }, + # We use PRIVATE_BUG_USER because he can modify the bug, but + # can't change time-tracking fields. + { value => '100', user => PRIVATE_BUG_USER, + error => 'only a user with the required permissions', + test => 'non-timetracker can not set estimated_time' }, + ], + + groups => [ + { value => { add => ['Master'] }, + error => 'either this group does not exist, or you are not allowed to restrict bugs to this group', + test => "adding group we don't have access to but is valid fails" }, + { value => { add => ['QA-Selenium-TEST'] }, + error => 'either this group does not exist, or you are not allowed to restrict bugs to this group', + test => 'adding valid group that is not in this product fails' }, + { value => { add => [random_string(20)] }, + error => 'either this group does not exist, or you are not allowed to restrict bugs to this group', + test => 'adding non-existent group fails' }, + { value => { remove => [random_string(20)] }, + error => 'either this group does not exist, or you are not allowed to remove bugs from this group', + test => 'removing non-existent group fails' }, + ], + + keywords => [ + { value => { add => [random_string(20)] }, + error => 'The legal keyword names are listed here', + test => 'adding invalid keyword fails' }, + { value => { remove => [random_string(20)] }, + error => 'The legal keyword names are listed here', + test => 'removing invalid keyword fails' }, + { value => { set => [random_string(20)] }, + error => 'The legal keyword names are listed here', + test => 'setting invalid keyword fails' }, + ], + + op_sys => [ + { value => random_string(20), + error => 'There is no', + test => 'invalid op_sys fails' }, + { value => '', + error => 'You must select/enter', + test => 'blank op_sys fails' }, + ], + + product => [ + { value => random_string(60), + error => "does not exist or you aren't authorized", + test => 'invalid product fails' }, + { value => '', + error => 'You must select/enter a product', + test => 'moving to blank product fails' }, + { value => 'TestProduct', + error => 'There is no component named', + test => 'moving products without other fields fails' }, + { value => 'QA-Selenium-TEST', + extra => { component => 'QA-Selenium-TEST' }, + error => "does not exist or you aren't authorized", + test => 'moving to inaccessible product fails' }, + { value => 'QA Entry Only', + error => "does not exist or you aren't authorized", + test => 'moving to product where ENTRY is denied fails' }, + ], + + qa_contact => [ + { value => random_string(20), + error => 'There is no user named', + test => 'changing qa_contact to invalid user fails' }, + ], + + remaining_time => [ + { value => -1, + error => 'less than the minimum allowable value', + test => 'negative remaining_time fails' }, + { value => 100_000_000, + error => 'more than the maximum allowable value', + test => 'too-large remaining_time fails' }, + { value => random_string(20), + error => 'is not a numeric value', + test => 'non-numeric remaining_time fails' }, + # We use PRIVATE_BUG_USER because he can modify the bug, but + # can't change time-tracking fields. + { value => '100', user => PRIVATE_BUG_USER, + error => 'only a user with the required permissions', + test => 'non-timetracker can not set remaining_time' }, + ], + + # We do all the failing resolution tests on the second bug, + # because we want to be sure that we're starting from an open + # status. + resolution => [ + { value => random_string(20), ids => [$second_id], + extra => { status => 'RESOLVED' }, + error => 'There is no Resolution named', + test => 'invalid resolution fails' }, + { value => 'FIXED', ids => [$second_id], + error => 'You cannot set a resolution for open bugs', + test => 'setting resolution on open bug fails' }, + { value => 'DUPLICATE', ids => [$second_id], + extra => { status => 'RESOLVED' }, + error => 'id to mark this bug as a duplicate', + test => 'setting DUPLICATE without dup_id fails' }, + { value => '', ids => [$second_id], + extra => { status => 'RESOLVED' }, + error => 'A valid resolution is required', + test => 'blank resolution fails with closed status' }, + ], + + see_also => [ + { value => { add => [random_string(20)] }, + error => 'is not a valid bug number nor an alias', + test => 'random string fails in see_also' }, + { value => { add => ['http://landfill.bugzilla.org/'] }, + error => 'See Also URLs should point to one of', + test => 'no show_bug.cgi in see_also URI' }, + ], + + status => [ + { value => random_string(20), + error => 'There is no status named', + test => 'invalid status fails' }, + { value => '', + error => 'You must select/enter a status', + test => 'blank status fails' }, + # We use the second bug for this because we can guarantee that + # it is open. + { value => 'VERIFIED', ids => [$second_id], + extra => { resolution => 'FIXED' }, + error => 'You are not allowed to change the bug status from', + test => 'invalid transition fails' }, + ], + + summary => [ + { value => random_string(300), + error => 'The text you entered in the Summary field is too long', + test => 'too-long summary fails' }, + { value => '', + error => 'You must enter a summary for this bug', + test => 'blank summary fails' }, + ], + + work_time => [ + { value => 100_000_000, + error => 'more than the maximum allowable value', + test => 'too-large work_time fails' }, + { value => random_string(20), + error => 'is not a numeric value', + test => 'non-numeric work_time fails' }, + # We use PRIVATE_BUG_USER because he can modify the bug, but + # can't change time-tracking fields. + { value => '10', user => PRIVATE_BUG_USER, + error => 'only a user with the required permissions', + test => 'non-timetracker can not set work_time' }, + ], + ); + + $values{depends_on} = $values{blocks}; + + foreach my $field (qw(platform priority severity target_milestone version)) + { + my $tests = dclone($values{op_sys}); + foreach my $test (@$tests) { + $test->{test} =~ s/op_sys/$field/g; + } + $values{$field} = $tests; + } + + return %values; +} + +sub invalid_values_to_tests { + my ($invalid_values, $public_bug) = @_; + + my @tests; + foreach my $field (sort keys %$invalid_values) { + my @tests_invalid = @{ $invalid_values->{$field} }; + foreach my $item (@tests_invalid) { + my %args = ( + ids => $item->{ids} || [$public_bug->{id}], + $field => $item->{value}, + %{ $item->{extra} || {} }, + ); + push(@tests, { user => $item->{user} || 'editbugs', + args => \%args, + error => $item->{error}, + test => $item->{test} }); + } + } + + return \@tests; +} + +############### +# Main Script # +############### + +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +$jsonrpc_get->bz_call_fail('Bug.update', + { ids => ['public_bug'] }, + 'must use HTTP POST', 'update fails over GET'); + +sub post_success { + my ($call, $t, $rpc) = @_; + return if $t->{no_changes}; + my $field = $t->{field}; + return if !$field; + + my @bugs = @{ $call->result->{bugs} }; + foreach my $bug (@bugs) { + if ($field =~ /^comment/) { + _check_comment($bug, $field, $t, $rpc); + } + else { + _check_changes($bug, $field, $t); + } + } +} + +sub _check_changes { + my ($bug, $field, $t) = @_; + + my $changes = $bug->{changes}->{$field}; + ok(defined $changes, "$field was changed") + or diag Dumper($bug, $t); + + my $new_value = $t->{added}; + $new_value = $t->{args}->{$field} if !defined $new_value; + _test_value($changes->{added}, $new_value, $field, 'added'); + + if (defined $t->{removed}) { + _test_value($changes->{removed}, $t->{removed}, $field, 'removed'); + } +} + +sub _test_value { + my ($got, $expected, $field, $type) = @_; + if ($field eq 'estimated_time' or $field eq 'remaining_time') { + cmp_ok($got, '==', $expected, "$field: $type is correct"); + } + else { + is($got, $expected, "$field: $type is correct"); + } +} + +sub _check_comment { + my ($bug, $field, $t, $rpc) = @_; + my $bug_id = $bug->{id}; + my $call = $rpc->bz_call_success('Bug.comments', { ids => [$bug_id] }); + my $comments = $call->result->{bugs}->{$bug_id}->{comments}; + + if ($field eq 'comment_is_private') { + my $first_private = $comments->[0]->{is_private}; + my ($expected) = values %{ $t->{args}->{comment_is_private} }; + cmp_ok($first_private, '==', $expected, + 'description privacy is correct'); + } + else { + my $last_comment = $comments->[-1]; + my $expected = $t->{args}->{comment}->{body}; + is($last_comment->{text}, $expected, 'comment added correctly'); + } + +} + +foreach my $rpc ($jsonrpc, $xmlrpc) { + $rpc->bz_run_tests(tests => get_tests($config, $rpc), + method => 'Bug.update', post_success => \&post_success); +} diff --git a/qa/t/webservice_bug_update_see_also.t b/qa/t/webservice_bug_update_see_also.t new file mode 100644 index 000000000..3bdc3dc25 --- /dev/null +++ b/qa/t/webservice_bug_update_see_also.t @@ -0,0 +1,82 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +################################################# +# Test for xmlrpc call to Bug.update_see_also() # +################################################# + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use QA::Tests qw(PRIVATE_BUG_USER STANDARD_BUG_TESTS); +use Test::More tests => 117; +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +my $bug_url = 'http://landfill.bugzilla.org/bugzilla-tip/show_bug.cgi?id=100'; + +# update_see_also doesn't support logged-out users. +my @tests = grep { $_->{user} } @{ STANDARD_BUG_TESTS() }; +foreach my $t (@tests) { + $t->{args}->{add} = $t->{args}->{remove} = []; +} + +push(@tests, ( + { user => 'unprivileged', + args => { ids => ['public_bug'], add => [$bug_url] }, + error => 'only the assignee or reporter of the bug, or a user', + test => 'Unprivileged user cannot add a URL to a bug', + }, + + { user => 'admin', + args => { ids => ['public_bug'], add => ['asdfasdfasdf'] }, + error => 'asdf', + test => 'Admin cannot add an invalid URL', + }, + { user => 'admin', + args => { ids => ['public_bug'], remove => ['asdfasdfasdf'] }, + test => 'Invalid URL silently ignored', + }, + + { user => 'admin', + args => { ids => ['public_bug'], add => [$bug_url] }, + test => 'Admin can add a URL to a public bug', + }, + { user => 'unprivileged', + args => { ids => ['public_bug'], remove => [$bug_url] }, + error => 'only the assignee or reporter of the bug, or a user', + test => 'Unprivileged user cannot remove a URL from a bug', + }, + { user => 'admin', + args => { ids => ['public_bug'], remove => [$bug_url] }, + test => 'Admin can remove a URL from a public bug', + }, + + { user => PRIVATE_BUG_USER, + args => { ids => ['private_bug'], add => [$bug_url] }, + test => PRIVATE_BUG_USER . ' can add a URL to a private bug', + }, + { user => PRIVATE_BUG_USER, + args => { ids => ['private_bug'], remove => [$bug_url] }, + test => PRIVATE_BUG_USER . ' can remove a URL from a private bug', + }, + +)); + +sub post_success { + my ($call, $t) = @_; + isa_ok($call->result->{changes}, 'HASH', "Changes"); +} + +$jsonrpc_get->bz_call_fail('Bug.update_see_also', + { ids => ['public_bug'], add => [$bug_url] }, + 'must use HTTP POST', 'update_see_also fails over GET'); + +foreach my $rpc ($jsonrpc, $xmlrpc) { + $rpc->bz_run_tests(tests => \@tests, method => 'Bug.update_see_also', + post_success => \&post_success); +} diff --git a/qa/t/webservice_bugzilla.t b/qa/t/webservice_bugzilla.t new file mode 100644 index 000000000..fef57cca1 --- /dev/null +++ b/qa/t/webservice_bugzilla.t @@ -0,0 +1,45 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +################################################## +# Test for xmlrpc call functions in Bugzilla.pm # +################################################## + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 11 * 3; +use QA::Util; +my ($config, @clients) = get_rpc_clients(); + +foreach my $rpc (@clients) { + my $vers_call = $rpc->bz_call_success('Bugzilla.version'); + my $version = $vers_call->result->{version}; + ok($version, "Bugzilla.version returns $version"); + + my $tz_call = $rpc->bz_call_success('Bugzilla.timezone'); + my $tz = $tz_call->result->{timezone}; + ok($tz, "Bugzilla.timezone retuns $tz"); + + my $ext_call = $rpc->bz_call_success('Bugzilla.extensions'); + my $extensions = $ext_call->result->{extensions}; + isa_ok($extensions, 'HASH', 'extensions'); + + # There is always at least the QA extension enabled. + my $cmp = $config->{test_extensions} ? '>' : '=='; + my @ext_names = keys %$extensions; + my $desc = scalar(@ext_names) . ' extension(s) returned: ' . join(', ', @ext_names); + cmp_ok(scalar(@ext_names), $cmp, 1, $desc); + ok(grep($_ eq 'QA', @ext_names), 'The QA extension is enabled'); + + my $time_call = $rpc->bz_call_success('Bugzilla.time'); + my $time_result = $time_call->result; + foreach my $type (qw(db_time web_time)) { + cmp_ok($time_result->{$type}, '=~', $rpc->DATETIME_REGEX, + "Bugzilla.time returns a datetime for $type"); + } +} diff --git a/qa/t/webservice_group_create.t b/qa/t/webservice_group_create.t new file mode 100644 index 000000000..346800b0e --- /dev/null +++ b/qa/t/webservice_group_create.t @@ -0,0 +1,97 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +########################################## +# Test for xmlrpc call to Group.create() # +########################################## + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 77; +use QA::Util; + +use constant DESCRIPTION => 'Group created by Group.create'; + +sub post_success { + my $call = shift; + my $gid = $call->result->{id}; + ok($gid, "Got a non-zero group ID: $gid"); +} + +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +my @tests = ( + { args => { name => random_string(20), description => DESCRIPTION }, + error => 'You must log in', + test => 'Logged-out user cannot call Group.create', + }, + { user => 'unprivileged', + args => { name => random_string(20), description => DESCRIPTION }, + error => 'you are not authorized', + test => 'Unprivileged user cannot call Group.create', + }, + { user => 'admin', + args => { description => DESCRIPTION }, + error => 'You must enter a name', + test => 'Missing name to Group.create', + }, + { user => 'admin', + args => { name => random_string(20) }, + error => 'You must enter a description', + test => 'Missing description to Group.create', + }, + { user => 'admin', + args => { name => '', description => DESCRIPTION }, + error => 'You must enter a name', + test => 'Name to Group.create cannot be empty', + }, + { user => 'admin', + args => { name => random_string(20), description => '' }, + error => 'You must enter a description', + test => 'Description to Group.create cannot be empty', + }, + { user => 'admin', + args => { name => 'canconfirm', description => DESCRIPTION }, + error => 'already exists', + test => 'Name to Group.create already exists', + }, + { user => 'admin', + args => { name => 'caNConFIrm', description => DESCRIPTION }, + error => 'already exists', + test => 'Name to Group.create already exists but with a different case', + }, + { user => 'admin', + args => { name => random_string(20), description => DESCRIPTION, + user_regexp => '\\'}, + error => 'The regular expression you entered is invalid', + test => 'The regular expression passed to Group.create is invalid', + }, +); + +$jsonrpc_get->bz_call_fail('Group.create', + { name => random_string(20), description => 'Created with JSON-RPC via GET' }, + 'must use HTTP POST', 'Group.create fails over GET'); + +foreach my $rpc ($xmlrpc, $jsonrpc) { + # Tests which work must be called from here, + # to avoid creating twice the same group. + my @all_tests = (@tests, + { user => 'admin', + args => { name => random_string(20), description => DESCRIPTION }, + test => 'Passing the name and description only works', + }, + { user => 'admin', + args => { name => random_string(20), description => DESCRIPTION, + user_regexp => '\@foo.com$', is_active => 1, + icon_url => 'http://www.bugzilla.org/favicon.ico' }, + test => 'Passing all arguments works', + }, + ); + $rpc->bz_run_tests(tests => \@all_tests, method => 'Group.create', + post_success => \&post_success); +} diff --git a/qa/t/webservice_jsonp.t b/qa/t/webservice_jsonp.t new file mode 100644 index 000000000..dd62b6392 --- /dev/null +++ b/qa/t/webservice_jsonp.t @@ -0,0 +1,30 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 85; +use QA::Util; +my $jsonrpc_get = QA::Util::get_jsonrpc_client('GET'); + +my @chars = (0..9, 'A'..'Z', 'a'..'z', '_[].'); + +our @tests = ( + { args => { callback => join('', @chars) }, + test => 'callback accepts all legal characters.' }, +); +foreach my $char (qw(! ~ ` @ $ % ^ & * - + = { } ; : ' " < > / ? |), + '(', ')', '\\', '#', ',') +{ + push(@tests, + { args => { callback => "a$char" }, + error => "as your 'callback' parameter", + test => "$char is not valid in callback" }); +} + +$jsonrpc_get->bz_run_tests(method => 'Bugzilla.version', tests => \@tests); diff --git a/qa/t/webservice_product.t b/qa/t/webservice_product.t new file mode 100644 index 000000000..7f993899f --- /dev/null +++ b/qa/t/webservice_product.t @@ -0,0 +1,109 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################## +# Test for xmlrpc calls to: # +# Product.get_selectable_products() # +# Product.get_enterable_products() # +# Product.get_accessible_products() # +# Product.get_products() # +######################################## + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 134; +use QA::Util; +my ($config, @clients) = get_rpc_clients(); + +my $products = $clients[0]->bz_get_products(); +my $public = $products->{'Another Product'}; +my $private = $products->{'QA-Selenium-TEST'}; +my $no_entry = $products->{'QA Entry Only'}; +my $no_search = $products->{'QA Search Only'}; + +my %id_map = reverse %$products; + +my $tests = { + 'QA_Selenium_TEST' => { + selectable => [$public, $private, $no_entry, $no_search], + enterable => [$public, $private, $no_entry, $no_search], + accessible => [$public, $private, $no_entry, $no_search], + }, + 'unprivileged' => { + selectable => [$public, $no_entry], + not_selectable => $no_search, + enterable => [$public, $no_search], + not_enterable => $no_entry, + accessible => [$public, $no_entry, $no_search], + not_accessible => $private, + }, + '' => { + selectable => [$public, $no_entry], + not_selectable => $no_search, + enterable => [$public, $no_search], + not_enterable => $no_entry, + accessible => [$public, $no_entry, $no_search], + not_accessible => $private, + }, +}; + +foreach my $rpc (@clients) { + foreach my $user (keys %$tests) { + my @selectable = @{ $tests->{$user}->{selectable} }; + my @enterable = @{ $tests->{$user}->{enterable} }; + my @accessible = @{ $tests->{$user}->{accessible} }; + my $not_selectable = $tests->{$user}->{not_selectable}; + my $not_enterable = $tests->{$user}->{not_enterable}; + my $not_accessible = $tests->{$user}->{not_accessible}; + + $rpc->bz_log_in($user) if $user; + $user ||= "Logged-out user"; + + my $select_call = + $rpc->bz_call_success('Product.get_selectable_products'); + my $select_ids = $select_call->result->{ids}; + foreach my $id (@selectable) { + ok(grep($_ == $id, @$select_ids), + "$user can select " . $id_map{$id}); + } + if ($not_selectable) { + ok(!grep($_ == $not_selectable, @$select_ids), + "$user cannot select " . $id_map{$not_selectable}); + } + + my $enter_call = + $rpc->bz_call_success('Product.get_enterable_products'); + my $enter_ids = $enter_call->result->{ids}; + foreach my $id (@enterable) { + ok(grep($_ == $id, @$enter_ids), "$user can enter " . $id_map{$id}); + } + if ($not_enterable) { + ok(!grep($_ == $not_enterable, @$enter_ids), + "$user cannot enter " . $id_map{$not_enterable}); + } + + my $access_call = + $rpc->bz_call_success('Product.get_accessible_products'); + my $get_call = $rpc->bz_call_success('Product.get', + { ids => \@accessible }); + my $products = $get_call->result->{products}; + my $expected_count = scalar @accessible; + cmp_ok(scalar @$products, '==', $expected_count, + "Product.get gets all $expected_count accessible products" + . " for $user."); + if ($not_accessible) { + my $no_access_call = $rpc->bz_call_success( + 'Product.get', { ids => [$not_accessible] }); + ok(!scalar @{ $no_access_call->result->{products} }, + "$user gets 0 products when asking for " + . $id_map{$not_accessible}); + } + + $rpc->bz_call_success('User.logout') if $user ne "Logged-out user"; + } +} diff --git a/qa/t/webservice_product_create.t b/qa/t/webservice_product_create.t new file mode 100644 index 000000000..05b82d60c --- /dev/null +++ b/qa/t/webservice_product_create.t @@ -0,0 +1,163 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +############################################ +# Test for xmlrpc call to Product.create() # +############################################ + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 121; +use QA::Util; + +use constant DESCRIPTION => 'Product created by Product.create'; +use constant PROD_VERSION => 'unspecified'; + +sub post_success { + my ($call, $test, $self) = @_; + my $args = $test->{args}; + my $prod_id = $call->result->{id}; + ok($prod_id, "Got a non-zero product ID: $prod_id"); + + $call = $self->bz_call_success("Product.get", {ids => [$prod_id]}); + my $product = $call->result->{products}->[0]; + my $prod_name = $product->{name}; + my $is_active = defined $args->{is_open} ? $args->{is_open} : 1; + ok($product->{is_active} == $is_active, + "Product $prod_name has the correct value for is_active/is_open: $is_active"); + my $has_unco = defined $args->{has_unconfirmed} ? $args->{has_unconfirmed} : 1; + ok($product->{has_unconfirmed} == $has_unco, + "Product $prod_name has the correct value for has_unconfirmed: $has_unco"); +} + +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +my @tests = ( + { args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION }, + error => 'You must log in', + test => 'Logged-out user cannot call Product.create', + }, + { user => 'unprivileged', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION }, + error => 'you are not authorized', + test => 'Unprivileged user cannot call Product.create', + }, + { user => 'admin', + args => { version => PROD_VERSION, description => DESCRIPTION }, + error => 'You must enter a name', + test => 'Missing name to Product.create', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION }, + error => 'You must enter a description', + test => 'Missing description to Product.create', + }, + { user => 'admin', + args => { name => random_string(20), description => DESCRIPTION }, + error => 'You must enter a valid version', + test => 'Missing version to Product.create', + }, + { user => 'admin', + args => { name => '', version => PROD_VERSION, description => DESCRIPTION }, + error => 'You must enter a name', + test => 'Name to Product.create cannot be empty', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, description => '' }, + error => 'You must enter a description', + test => 'Description to Product.create cannot be empty', + }, + { user => 'admin', + args => { name => random_string(20), version => '', description => DESCRIPTION }, + error => 'You must enter a valid version', + test => 'Version to Product.create cannot be empty', + }, + { user => 'admin', + args => { name => random_string(20000), version => PROD_VERSION, + description => DESCRIPTION }, + error => 'The name of a product is limited', + test => 'Name to Product.create too long', + }, + { user => 'admin', + args => { name => 'Another Product', version => PROD_VERSION, + description => DESCRIPTION }, + error => 'already exists', + test => 'Name to Product.create already exists', + }, + { user => 'admin', + args => { name => 'aNoThEr Product', version => PROD_VERSION, + description => DESCRIPTION }, + error => 'differs from existing product', + test => 'Name to Product.create already exists but with a different case', + }, +); + +# FIXME: Should be: if (classifications enabled). +# But there is currently now way to query the value of a parameter via WS. +if (0) { + push(@tests, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION, has_unconfirmed => 1, + classification => '', default_milestone => '2.0', + is_open => 1, create_series => 1 }, + error => 'You must select/enter a classification', + test => 'Passing an empty classification to Product.create fails', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION, has_unconfirmed => 1, + classification => random_string(10), default_milestone => '2.0', + is_open => 1, create_series => 1 }, + error => 'You must select/enter a classification', + test => 'Passing an invalid classification to Product.create fails', + }, + ) +} + +$jsonrpc_get->bz_call_fail('Product.create', + { name => random_string(20), version => PROD_VERSION, + description => 'Created with JSON-RPC via GET' }, + 'must use HTTP POST', 'Product.create fails over GET'); + +foreach my $rpc ($xmlrpc, $jsonrpc) { + # Tests which work must be called from here, + # to avoid creating twice the same product. + my @all_tests = (@tests, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION }, + test => 'Passing the name, description and version only works', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION, has_unconfirmed => 1, + classification => 'Class2_QA', default_milestone => '2.0', + is_open => 1, create_series => 1 }, + test => 'Passing all arguments works', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION, has_unconfirmed => 0, + classification => 'Class2_QA', default_milestone => '2.0', + is_open => 0, create_series => 0 }, + test => 'Passing null values works', + }, + { user => 'admin', + args => { name => random_string(20), version => PROD_VERSION, + description => DESCRIPTION, has_unconfirmed => 1, + classification => 'Class2_QA', default_milestone => '', + is_open => 1, create_series => 1 }, + test => 'Passing an empty default milestone works (falls back to "---")', + }, + ); + $rpc->bz_run_tests(tests => \@all_tests, method => 'Product.create', + post_success => \&post_success); +} diff --git a/qa/t/webservice_product_get.t b/qa/t/webservice_product_get.t new file mode 100644 index 000000000..0128f3348 --- /dev/null +++ b/qa/t/webservice_product_get.t @@ -0,0 +1,109 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################## +# Test for xmlrpc calls to: # +# Product.get_selectable_products() # +# Product.get_enterable_products() # +# Product.get_accessible_products() # +# Product.get() # +######################################## + +use strict; +use warnings; +use lib qw(lib); +use Test::More tests => 134; +use QA::Util; +my ($config, @clients) = get_rpc_clients(); + +my $products = $clients[0]->bz_get_products(); +my $public = $products->{'Another Product'}; +my $private = $products->{'QA-Selenium-TEST'}; +my $no_entry = $products->{'QA Entry Only'}; +my $no_search = $products->{'QA Search Only'}; + +my %id_map = reverse %$products; + +my $tests = { + 'QA_Selenium_TEST' => { + selectable => [$public, $private, $no_entry, $no_search], + enterable => [$public, $private, $no_entry, $no_search], + accessible => [$public, $private, $no_entry, $no_search], + }, + 'unprivileged' => { + selectable => [$public, $no_entry], + not_selectable => $no_search, + enterable => [$public, $no_search], + not_enterable => $no_entry, + accessible => [$public, $no_entry, $no_search], + not_accessible => $private, + }, + '' => { + selectable => [$public, $no_entry], + not_selectable => $no_search, + enterable => [$public, $no_search], + not_enterable => $no_entry, + accessible => [$public, $no_entry, $no_search], + not_accessible => $private, + }, +}; + +foreach my $rpc (@clients) { + foreach my $user (keys %$tests) { + my @selectable = @{ $tests->{$user}->{selectable} }; + my @enterable = @{ $tests->{$user}->{enterable} }; + my @accessible = @{ $tests->{$user}->{accessible} }; + my $not_selectable = $tests->{$user}->{not_selectable}; + my $not_enterable = $tests->{$user}->{not_enterable}; + my $not_accessible = $tests->{$user}->{not_accessible}; + + $rpc->bz_log_in($user) if $user; + $user ||= "Logged-out user"; + + my $select_call = + $rpc->bz_call_success('Product.get_selectable_products'); + my $select_ids = $select_call->result->{ids}; + foreach my $id (@selectable) { + ok(grep($_ == $id, @$select_ids), + "$user can select " . $id_map{$id}); + } + if ($not_selectable) { + ok(!grep($_ == $not_selectable, @$select_ids), + "$user cannot select " . $id_map{$not_selectable}); + } + + my $enter_call = + $rpc->bz_call_success('Product.get_enterable_products'); + my $enter_ids = $enter_call->result->{ids}; + foreach my $id (@enterable) { + ok(grep($_ == $id, @$enter_ids), "$user can enter " . $id_map{$id}); + } + if ($not_enterable) { + ok(!grep($_ == $not_enterable, @$enter_ids), + "$user cannot enter " . $id_map{$not_enterable}); + } + + my $access_call = + $rpc->bz_call_success('Product.get_accessible_products'); + my $get_call = $rpc->bz_call_success('Product.get', + { ids => \@accessible }); + my $products = $get_call->result->{products}; + my $expected_count = scalar @accessible; + cmp_ok(scalar @$products, '==', $expected_count, + "Product.get gets all $expected_count accessible products" + . " for $user."); + if ($not_accessible) { + my $no_access_call = $rpc->bz_call_success( + 'Product.get', { ids => [$not_accessible] }); + ok(!scalar @{ $no_access_call->result->{products} }, + "$user gets 0 products when asking for " + . $id_map{$not_accessible}); + } + + $rpc->bz_call_success('User.logout') if $user ne "Logged-out user"; + } +} diff --git a/qa/t/webservice_user_create.t b/qa/t/webservice_user_create.t new file mode 100644 index 000000000..20301a6c5 --- /dev/null +++ b/qa/t/webservice_user_create.t @@ -0,0 +1,108 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################### +# Test for xmlrpc call to User.Create() # +######################################### + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use Test::More tests => 69; +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +use constant NEW_PASSWORD => 'password'; +use constant NEW_FULLNAME => 'WebService Created User'; + +use constant PASSWORD_TOO_SHORT => 'a'; + +# These are the characters that are actually invalid per RFC. +use constant INVALID_EMAIL => '()[]\;:,<>@webservice.test'; + +sub new_login { + return 'created_' . random_string() . '@webservice.test'; +} + +sub post_success { + my ($call) = @_; + ok($call->result->{id}, "Got a non-zero user id"); +} + +$jsonrpc_get->bz_call_fail('User.create', + { email => new_login(), full_name => NEW_FULLNAME, + password => '*' }, + 'must use HTTP POST', 'User.create fails over GET'); + +# We have to wrap @tests in the foreach, because we want a different +# login for each user, separately for each RPC client. (You can't create +# two users with the same username, and XML-RPC would otherwise try to +# create the same users that JSON-RPC created.) +foreach my $rpc ($jsonrpc, $xmlrpc) { + my @tests = ( + # Permissions checks + { args => { email => new_login(), full_name => NEW_FULLNAME, + password => NEW_PASSWORD }, + error => "you are not authorized", + test => 'Logged-out user cannot call User.create', + }, + { user => 'unprivileged', + args => { email => new_login(), full_name => NEW_FULLNAME, + password => NEW_PASSWORD }, + error => "you are not authorized", + test => 'Unprivileged user cannot call User.create', + }, + + # Login name checks. + { user => 'admin', + args => { full_name => NEW_FULLNAME, password => NEW_PASSWORD }, + error => "argument was not set", + test => 'Leaving out email argument fails', + }, + { user => 'admin', + args => { email => '', full_name => NEW_FULLNAME, + password => NEW_PASSWORD }, + error => "argument was not set", + test => "Passing an empty email argument fails", + }, + { user => 'admin', + args => { email => INVALID_EMAIL, full_name => NEW_FULLNAME, + password => NEW_PASSWORD }, + error => "didn't pass our syntax checking", + test => 'Invalid email address fails', + }, + { user => 'admin', + args => { email => $config->{unprivileged_user_login}, + full_name => NEW_FULLNAME, password => NEW_PASSWORD }, + error => "There is already an account", + test => 'Trying to use an existing login name fails', + }, + + { user => 'admin', + args => { email => new_login(), full_name => NEW_FULLNAME, + password => PASSWORD_TOO_SHORT }, + error => 'password must be at least', + test => 'Password Too Short fails', + }, + { user => 'admin', + args => { email => new_login(), full_name => NEW_FULLNAME, + password => NEW_PASSWORD }, + test => 'Creating a user with all arguments and correct privileges', + }, + { user => 'admin', + args => { email => new_login(), password => NEW_PASSWORD }, + test => 'Leaving out fullname works', + }, + { user => 'admin', + args => { email => new_login(), full_name => NEW_FULLNAME }, + test => 'Leaving out password works', + }, + ); + + $rpc->bz_run_tests(tests => \@tests, method => 'User.create', + post_success => \&post_success); +} diff --git a/qa/t/webservice_user_get.t b/qa/t/webservice_user_get.t new file mode 100644 index 000000000..7d50bf22e --- /dev/null +++ b/qa/t/webservice_user_get.t @@ -0,0 +1,218 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +###################################### +# Test for xmlrpc call to User.get() # +###################################### + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use QA::Tests qw(PRIVATE_BUG_USER); +use Test::More tests => 330; +our ($config, @clients) = get_rpc_clients(); + +my $get_user = $config->{'unprivileged_user_login'}; +my $canconfirm_user = $config->{'canconfirm_user_login'}; +my $priv_user = $config->{PRIVATE_BUG_USER . '_user_login'}; +my $disabled = $config->{'disabled_user_login'}; +my $disabled_match = substr($disabled, 0, length($disabled) - 1); + +# These are the basic tests. There are tests for include_fields +# and exclude_field below. + +my @tests = ( + { args => { names => [$get_user] }, + test => "Logged-out user can get unprivileged user by name" + }, + { args => { match => [$get_user] }, + test => 'Logged-out user cannot use the match argument', + error => 'Logged-out users cannot use', + }, + { args => { ids => [1] }, + test => 'Logged-out users cannot use the "ids" argument', + error => 'Logged-out users cannot use', + }, + + # match & names + { user => 'unprivileged', + args => { names => [$get_user] }, + test => "Unprivileged user can get himself", + }, + { user => 'unprivileged', + args => { match => [$get_user] }, + test => 'Logged-in user can use the match argument', + }, + { user => 'unprivileged', + args => { match => [$get_user], names => [$get_user] }, + test => 'Specifying the same thing in "match" and "names"', + }, + + # include_disabled + { user => 'unprivileged', + args => { match => [$get_user, $disabled_match] }, + test => 'Disabled users are not normally returned' + }, + { user => 'unprivileged', + args => { match => [$disabled_match], include_disabled => 1 }, + test => 'Specifying include_disabled returns disabled users' + }, + { user => 'unprivileged', + args => { match => [$disabled] }, + test => 'Full match on a disabled user returns that user', + }, + + # groups and group_ids + { args => { groups => ['QA-Selenium-TEST'] }, + test => 'Specifying just groups fails', + error => 'one of the following parameters', + }, + { args => { group_ids => [1] }, + test => 'Specifying just group ids fails', + error => 'one of the following parameters', + }, + { args => { names => [$get_user, $priv_user], groups => ['QA-Selenium-TEST'] }, + test => 'Limiting the return value to a group while being logged out fails', + error => 'The group you specified, QA-Selenium-TEST, is not valid here', + }, + { user => 'unprivileged', + args => { names => [$get_user, $priv_user], groups => ['missing_group'] }, + test => 'Limiting the return value to a group which does not exist fails', + error => 'The group you specified, missing_group, is not valid here', + }, + { user => 'unprivileged', + args => { names => [$get_user, $priv_user], groups => ['QA-Selenium-TEST'] }, + test => 'Limiting the return value to a group you do not belong to fails', + error => 'The group you specified, QA-Selenium-TEST, is not valid here', + }, + { user => 'editbugs', + args => { names => [$get_user, $priv_user], groups => ['Master', 'editbugs'] }, + test => 'Limiting the return value to some groups you do not belong to fails', + error => 'The group you specified, Master, is not valid here', + }, + { user => 'admin', + args => { names => [$canconfirm_user], groups => ['canconfirm', 'editbugs'] }, + test => 'Limiting the return value to groups you belong to', + }, + + # groups returned + { user => 'admin', + args => { names => [$get_user] }, + test => 'Admin can get user', + }, + { user => 'admin', + args => { names => [$canconfirm_user] }, + test => 'Admin can get user', + }, + { user => 'canconfirm', + args => { names => [$canconfirm_user] }, + test => 'Privileged user can get himself', + }, + { user => 'editbugs', + args => { names => [$canconfirm_user] }, + test => 'Privileged user can get another user', + }, +); + +sub post_success { + my ($call, $t) = @_; + + my $result = $call->result; + is(scalar @{ $result->{users} }, 1, "Got exactly one user"); + my $item = $result->{users}->[0]; + my $user = $t->{user} || ''; + + if ($user eq 'admin') { + ok(exists $item->{email} && exists $item->{can_login} + && exists $item->{email_enabled} && exists $item->{login_denied_text}, + 'Admin correctly gets all user fields'); + } + elsif ($user) { + ok(exists $item->{email} && exists $item->{can_login}, + 'Logged-in user correctly gets email and can_login'); + ok(!exists $item->{email_enabled} + && !exists $item->{login_denied_text}, + "Non-admin user doesn't get email_enabled and login_denied_text"); + } + else { + my @item_keys = sort keys %$item; + is_deeply(\@item_keys, ['id', 'name', 'real_name'], + 'Only id, name, and real_name are returned to logged-out users'); + return; + } + + my $username = $config->{"${user}_user_login"}; + # FIXME: We have no way to create a saved search or a saved report from + # the WebService, so we cannot test that the correct data is returned + # if the user is accessing his own account. + if ($username eq $item->{name}) { + ok(exists $item->{saved_searches}, + 'Users can get the list of saved searches and reports for their own account'); + } + else { + ok(!exists $item->{saved_searches}, + "Users cannot get the list of saved searches and reports from someone else's acccount"); + } + + my @groups = map { $_->{name} } @{$item->{groups}}; + # Admins can see all groups a user belongs to (assuming they inherited + # membership for all groups). Same for a user querying his own account. + if ($username eq $item->{name} || $user eq 'admin') { + if ($username eq $get_user) { + ok(!scalar @groups, "The unprivileged user doesn't belong to any group"); + } + elsif ($username eq $canconfirm_user) { + ok(grep($_ eq 'canconfirm', @groups), "Group 'canconfirm' returned"); + } + } + else { + ok(!scalar @groups, "No groups are visible to users without bless privs"); + } +} + +foreach my $rpc (@clients) { + $rpc->bz_run_tests(tests => \@tests, method => 'User.get', + post_success => \&post_success); + + ############################# + # Include and Exclude Tests # + ############################# + + my $include_nothing = $rpc->bz_call_success('User.get', { + names => [$get_user], include_fields => ['asdfasdfsdf'], + }, 'User.get including only invalid fields'); + is(scalar keys %{ $include_nothing->result->{users}->[0] }, 0, + 'No fields returned for user'); + + my $include_one = $rpc->bz_call_success('User.get', { + names => [$get_user], include_fields => ['id'], + }, 'User.get including only id'); + is(scalar keys %{ $include_one->result->{users}->[0] }, 1, + 'Only one field returned for user'); + + my $exclude_none = $rpc->bz_call_success('User.get', { + names => [$get_user], exclude_fields => ['asdfasdfsdf'], + }, 'User.get excluding only invalid fields'); + is(scalar keys %{ $exclude_none->result->{users}->[0] }, 3, + 'All fields returned for user'); + + my $exclude_one = $rpc->bz_call_success('User.get', { + names => [$get_user], exclude_fields => ['id'], + }, 'User.get excluding id'); + is(scalar keys %{ $exclude_one->result->{users}->[0] }, 2, + 'Only two fields returned for user'); + + my $override = $rpc->bz_call_success('User.get', { + names => [$get_user], include_fields => ['id', 'name'], + exclude_fields => ['id'] + }, 'User.get with both include and exclude'); + is(scalar keys %{ $override->result->{users}->[0] }, 1, + 'Only one field returned'); + ok(exists $override->result->{users}->[0]->{name}, + '...and that field is the "name" field'); +} diff --git a/qa/t/webservice_user_login_logout.t b/qa/t/webservice_user_login_logout.t new file mode 100644 index 000000000..2affb961c --- /dev/null +++ b/qa/t/webservice_user_login_logout.t @@ -0,0 +1,124 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +########################################################## +# Test for xmlrpc call to User.login() and User.logout() # +########################################################## + +use strict; +use warnings; +use lib qw(lib); +use Data::Dumper; +use QA::Util; +use Test::More tests => 119; +my ($config, @clients) = get_rpc_clients(); + +use constant INVALID_EMAIL => '@invalid_user@'; + +my $user = $config->{unprivileged_user_login}; +my $pass = $config->{unprivileged_user_passwd}; +my $error = "The username or password you entered is not valid"; + +my @tests = ( + { user => 'unprivileged', + test => "Unprivileged user can log in successfully", + }, + + { args => { login => $user, password => '' }, + error => $error, + test => "Empty password can't log in", + }, + { args => { login => '', password => $pass }, + error => $error, + test => "Empty login can't log in", + }, + { args => { login => $user }, + error => "requires a password argument", + test => "Undef password can't log in", + }, + { args => { password => $pass }, + error => "requires a login argument", + test => "Undef login can't log in", + }, + + { args => { login => INVALID_EMAIL, password => $pass }, + error => $error, + test => "Invalid email can't log in", + }, + { args => { login => $user, password => '*' }, + error => $error, + test => "Invalid password can't log in", + }, + + { args => { login => $config->{disabled_user_login}, + password => $config->{disabled_user_passwd} }, + error => "!!This is the text!!", + test => "Can't log in with a disabled account", + }, + { args => { login => $config->{disabled_user_login}, password => '*' }, + error => $error, + test => "Logging in with invalid password doesn't show disabledtext", + }, +); + +sub _login_args { + my $args = shift; + my %fixed_args = %$args; + $fixed_args{Bugzilla_login} = delete $fixed_args{login}; + $fixed_args{Bugzilla_password} = delete $fixed_args{password}; + return \%fixed_args; +} + +foreach my $rpc (@clients) { + if ($rpc->bz_get_mode) { + $rpc->bz_call_fail('User.logout', undef, 'must use HTTP POST', + 'User.logout fails when called via GET'); + } + + foreach my $t (@tests) { + if ($t->{user}) { + my $username = $config->{$t->{user} . '_user_login'}; + my $password = $config->{$t->{user} . '_user_passwd'}; + + if ($rpc->bz_get_mode) { + $rpc->bz_call_fail('User.login', + { login => $username, password => $password }, + 'must use HTTP POST', $t->{test} . ' (fails on GET)'); + } + else { + $rpc->bz_log_in($t->{user}); + ok($rpc->{_bz_credentials}->{token}, 'Login token returned'); + $rpc->bz_call_success('User.logout'); + } + + if ($t->{error}) { + $rpc->bz_call_fail('Bugzilla.version', + { Bugzilla_login => $username, + Bugzilla_password => $password }); + } + else { + $rpc->bz_call_success('Bugzilla.version', + { Bugzilla_login => $username, + Bugzilla_password => $password }); + } + } + else { + # Under GET, there's no reason to have extra failing tests. + if (!$rpc->bz_get_mode) { + $rpc->bz_call_fail('User.login', $t->{args}, $t->{error}, + $t->{test}); + } + if (defined $t->{args}->{login} + and defined $t->{args}->{password}) + { + my $fixed_args = _login_args($t->{args}); + $rpc->bz_call_fail('Bugzilla.version', $fixed_args, + $t->{error}, "Bugzilla_login: " . $t->{test}); + } + } + } +} diff --git a/qa/t/webservice_user_offer_account_by_email.t b/qa/t/webservice_user_offer_account_by_email.t new file mode 100644 index 000000000..ae311afb8 --- /dev/null +++ b/qa/t/webservice_user_offer_account_by_email.t @@ -0,0 +1,59 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +######################################################### +# Test for xmlrpc call to User.offer_account_by_email() # +######################################################### + +use strict; +use warnings; +use lib qw(lib); +use QA::Util; +use Test::More tests => 29; +my ($config, $xmlrpc, $jsonrpc, $jsonrpc_get) = get_rpc_clients(); + +# These are the characters that are actually invalid per RFC. +use constant INVALID_EMAIL => '()[]\;:,<>@webservice.test'; + +sub new_login { + return 'requested_' . random_string() . '@webservice.test'; +} + +$jsonrpc_get->bz_call_fail('User.offer_account_by_email', + { email => new_login() }, + 'must use HTTP POST', 'offer_account_by_email fails over GET'); + +# Have to wrap @tests in the foreach so that new_login returns something +# different each time. +foreach my $rpc ($jsonrpc, $xmlrpc) { + my @tests = ( + # Login name checks. + { args => { }, + error => "argument was not set", + test => 'Leaving out email argument fails', + }, + { args => { email => '' }, + error => "argument was not set", + test => "Passing an empty email argument fails", + }, + { args => { email => INVALID_EMAIL }, + error => "didn't pass our syntax checking", + test => 'Invalid email address fails', + }, + { args => { email => $config->{unprivileged_user_login} }, + error => "There is already an account", + test => 'Trying to use an existing login name fails', + }, + + { args => { email => new_login() }, + test => 'Valid, non-existing email passes.', + }, + ); + + $rpc->bz_run_tests(tests => \@tests, + method => 'User.offer_account_by_email'); +} diff --git a/taskgraph.json b/taskgraph.json index a33606cd8..25270b328 100644 --- a/taskgraph.json +++ b/taskgraph.json @@ -13,8 +13,8 @@ "metadata": { "name": "Basic Sanity Tests" }, - "provisionerId": "aws-provisioner", - "workerType": "gaia", + "provisionerId": "aws-provisioner-v1", + "workerType": "b2gtest", "payload": { "image": "dklawren/webtools-bmo-bugzilla", "command": ["/runtests.sh"], @@ -35,6 +35,81 @@ } } } + }, + { + "reruns": 3, + "maxRunTime": 7200, + "task": { + "metadata": { + "name": "WebService API Tests" + }, + "provisionerId": "aws-provisioner-v1", + "workerType": "b2gtest", + "payload": { + "image": "dklawren/webtools-bmo-bugzilla", + "command": ["/runtests.sh"], + "env": { + "TEST_SUITE": "webservices" + }, + "artifacts": { + "public/runtests_log": { + "type": "file", + "path": "/runtests.log", + "expires": "2016-02-17T17:33:38.806Z" + }, + "public/httpd_error_log": { + "type": "file", + "path": "/var/log/httpd/error_log", + "expires": "2016-02-17T17:33:38.806Z" + } + } + }, + "extra": { + "treeherder": { + "symbol": "API" + } + } + } + }, + { + "reruns": 3, + "maxRunTime": 7200, + "task": { + "metadata": { + "name": "Selenium Tests" + }, + "provisionerId": "aws-provisioner-v1", + "workerType": "b2gtest", + "payload": { + "image": "dklawren/webtools-bmo-bugzilla", + "command": ["/runtests.sh"], + "env": { + "TEST_SUITE": "selenium" + }, + "artifacts": { + "public/runtests_log": { + "type": "file", + "path": "/runtests.log", + "expires": "2016-02-17T17:33:38.806Z" + }, + "public/httpd_error_log": { + "type": "file", + "path": "/var/log/httpd/error_log", + "expires": "2016-02-17T17:33:38.806Z" + }, + "public/selenium_log": { + "type": "file", + "path": "/selenium.log", + "expires": "2016-02-17T17:33:38.806Z" + } + } + }, + "extra": { + "treeherder": { + "symbol": "Sel" + } + } + } } ] } |