From 5f310e5b9e7afbd5badb17178349fefaaabfacce Mon Sep 17 00:00:00 2001 From: Dylan William Hardison Date: Thu, 30 Jun 2016 23:32:40 -0400 Subject: Bug 1283930 - Add Makefile.PL & local/lib/perl5 support to bmo/master + local symlink to data/ directory --- qa/t/lib/QA/REST.pm | 61 +++++++++++++++++++++++++ qa/t/rest_bugzilla.t | 60 +++++++++++++++++++++++++ qa/t/rest_classification.t | 61 +++++++++++++++++++++++++ qa/t/test_password_complexity.t | 99 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 qa/t/lib/QA/REST.pm create mode 100644 qa/t/rest_bugzilla.t create mode 100644 qa/t/rest_classification.t create mode 100644 qa/t/test_password_complexity.t (limited to 'qa') diff --git a/qa/t/lib/QA/REST.pm b/qa/t/lib/QA/REST.pm new file mode 100644 index 000000000..f900cc352 --- /dev/null +++ b/qa/t/lib/QA/REST.pm @@ -0,0 +1,61 @@ +# 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 QA::REST; + +use 5.10.1; +use strict; +use warnings; +use autodie; + +use LWP::UserAgent; +use JSON; +use QA::Util; + +use parent qw(LWP::UserAgent Exporter); + +@QA::REST::EXPORT = qw( + MUST_FAIL + get_rest_client +); + +use constant MUST_FAIL => 1; + +sub get_rest_client { + my $rest_client = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0 } ); + bless($rest_client, 'QA::REST'); + my $config = $rest_client->{bz_config} = get_config(); + $rest_client->{bz_url} = $config->{browser_url} . '/' . $config->{bugzilla_installation} . '/rest/'; + $rest_client->{bz_default_headers} = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}; + return $rest_client; +} + +sub bz_config { return $_[0]->{bz_config}; } + +sub call { + my ($self, $method, $data, $http_verb, $expect_to_fail) = @_; + $http_verb = lc($http_verb || 'GET'); + $data //= {}; + + my %args = %{ $self->{bz_default_headers} }; + # We do not pass the API key in the URL, so that it's not logged by the web server. + if ($http_verb eq 'get' && $data->{api_key}) { + $args{'X-BUGZILLA-API-KEY'} = $data->{api_key}; + } + elsif ($http_verb ne 'get') { + $args{Content} = encode_json($data); + } + + my $response = $self->$http_verb($self->{bz_url} . $method, %args); + my $res = decode_json($response->decoded_content); + if ($response->is_success xor $expect_to_fail) { + return $res; + } + else { + die 'error ' . $res->{code} . ': ' . $res->{message} . "\n"; + } +} diff --git a/qa/t/rest_bugzilla.t b/qa/t/rest_bugzilla.t new file mode 100644 index 000000000..cffab80db --- /dev/null +++ b/qa/t/rest_bugzilla.t @@ -0,0 +1,60 @@ +# 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. + +####################################### +# Tests for REST calls in Bugzilla.pm # +####################################### + +use 5.10.1; +use strict; +use warnings; + +use FindBin qw($RealBin); +use lib "$RealBin/lib", "$RealBin/../../lib", "$RealBin/../../local/lib/perl5"; + +use Test::More tests => 11; +use QA::REST; + +my $rest = get_rest_client(); +my $config = $rest->bz_config; + +my $version = $rest->call('version')->{version}; +ok($version, "GET /rest/version returns $version"); + +my $extensions = $rest->call('extensions')->{extensions}; +isa_ok($extensions, 'HASH', 'GET /rest/extensions'); +my @ext_names = sort keys %$extensions; +# There is always at least the QA extension enabled. +ok(scalar(@ext_names), scalar(@ext_names) . ' extension(s) found: ' . join(', ', @ext_names)); +ok($extensions->{QA}, 'The QA extension is enabled, with version ' . $extensions->{QA}->{version}); + +my $timezone = $rest->call('timezone')->{timezone}; +ok($timezone, "GET /rest/timezone retuns $timezone"); + +my $time = $rest->call('time'); +foreach my $type (qw(db_time web_time)) { + ok($time->{$type}, "GET /rest/time returns $type = " . $time->{$type}); +} + +# Logged-out users can only access the maintainer and requirelogin parameters. +my $params = $rest->call('parameters')->{parameters}; +my @param_names = sort keys %$params; +ok(@param_names == 2 && defined $params->{maintainer} && defined $params->{requirelogin}, + 'Only 2 parameters accessible to logged-out users: ' . join(', ', @param_names)); + +# Powerless users can access much more parameters. +$params = $rest->call('parameters', { api_key => $config->{unprivileged_user_api_key} })->{parameters}; +@param_names = sort keys %$params; +ok(@param_names > 2, scalar(@param_names) . ' parameters accessible to powerless users'); + +# Admins can access all parameters. +$params = $rest->call('parameters', { api_key => $config->{admin_user_api_key} })->{parameters}; +@param_names = sort keys %$params; +ok(@param_names > 2, scalar(@param_names) . ' parameters accessible to admins'); + +my $timestamp = $rest->call('last_audit_time')->{last_audit_time}; +ok($timestamp, "GET /rest/last_audit_time returns $timestamp"); diff --git a/qa/t/rest_classification.t b/qa/t/rest_classification.t new file mode 100644 index 000000000..d3806680a --- /dev/null +++ b/qa/t/rest_classification.t @@ -0,0 +1,61 @@ +# 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. + +############################################# +# Tests for REST calls in Classification.pm # +############################################# + +use 5.10.1; +use strict; +use warnings; + +use FindBin qw($RealBin); +use lib "$RealBin/lib", "$RealBin/../../lib", "$RealBin/../../local/lib/perl5"; + +use Test::More tests => 7; +use QA::REST; + +my $rest = get_rest_client(); +my $config = $rest->bz_config; +my $args = { api_key => $config->{admin_user_api_key} }; + +my $params = $rest->call('parameters', $args)->{parameters}; +my $use_class = $params->{useclassification}; +ok(defined($use_class), 'Classifications are ' . ($use_class ? 'enabled' : 'disabled')); + +# Admins can always access classifications, even when they are disabled. +my $class = $rest->call('classification/1', $args)->{classifications}->[0]; +ok($class->{id}, "Admin found classification '" . $class->{name} . "' with the description '" . $class->{description} . "'"); +my @products = sort map { $_->{name} } @{ $class->{products} }; +ok(scalar(@products), scalar(@products) . ' product(s) found: ' . join(', ', @products)); + +$class = $rest->call('classification/Class2_QA', $args)->{classifications}->[0]; +ok($class->{id}, "Admin found classification '" . $class->{name} . "' with the description '" . $class->{description} . "'"); +@products = sort map { $_->{name} } @{ $class->{products} }; +ok(scalar(@products), scalar(@products) . ' product(s) found: ' . join(', ', @products)); + +if ($use_class) { + # When classifications are enabled, everybody can query classifications... + # ... including logged-out users. + $class = $rest->call('classification/1')->{classifications}->[0]; + ok($class->{id}, 'Logged-out users can access classification ' . $class->{name}); + # ... and non-admins. + $class = $rest->call('classification/1', { api_key => $config->{editbugs_user_api_key} })->{classifications}->[0]; + ok($class->{id}, 'Non-admins can access classification ' . $class->{name}); +} +else { + # When classifications are disabled, only users in the 'editclassifications' + # group can access this method... + # ... logged-out users get an error. + my $error = $rest->call('classification/1', undef, undef, MUST_FAIL); + ok($error->{error} && $error->{code} == 900, + 'Logged-out users cannot query classifications when disabled: ' . $error->{message}); + # ... as well as non-admins. + $error = $rest->call('classification/1', { api_key => $config->{editbugs_user_api_key} }, undef, MUST_FAIL); + ok($error->{error} && $error->{code} == 900, + 'Non-admins cannot query classifications when disabled: ' . $error->{message}); +} diff --git a/qa/t/test_password_complexity.t b/qa/t/test_password_complexity.t new file mode 100644 index 000000000..5d358864b --- /dev/null +++ b/qa/t/test_password_complexity.t @@ -0,0 +1,99 @@ +# 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 5.10.1; +use strict; +use warnings; + +use FindBin qw($RealBin); +use lib "$RealBin/lib", "$RealBin/../../lib", "$RealBin/../../local/lib/perl5"; + +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}, + "User Authentication" => {"createemailregexp" => {type => "text", value => '.*'}, + "emailsuffix" => {type => "text", value => ''}} }); + +# Set the password complexity to BMO. +# Password must contain at least one UPPER and one lowercase letter. +my @invalid_bmo = qw(lowercase UPPERCASE 1234567890 123lowercase 123UPPERCASE !@%&^lower !@&^UPPER); + +check_passwords($sel, 'bmo', \@invalid_bmo, ['Longerthan12chars', '%9rT#j22S']); + +# Set the password complexity to No Constraints. +check_passwords($sel, 'no_constraints', ['12xY!', 'aaaaa'], ['aaaaaaaa', '>F12Xy?#']); + +logout($sel); + +sub check_passwords { + my ($sel, $param, $invalid_passwords, $valid_passwords) = @_; + + set_parameters($sel, { "User Authentication" => {"password_complexity" => {type => "select", value => $param}} }); + my $new_user = 'selenium-' . random_string(10) . '@bugzilla.org'; + + 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', $new_user); + + foreach my $password (@$invalid_passwords) { + $sel->type_ok('password', $password, 'Enter password'); + $sel->click_ok('add'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + if ($param eq 'no_constraints') { + $sel->title_is('Password Too Short'); + } + else { + $sel->title_is('Password Fails Requirements'); + } + + my $error_msg = trim($sel->get_text("error_msg")); + if ($param eq 'bmo') { + ok($error_msg =~ /must meet three of the following requirements/, + "Password fails requirement: $password"); + } + else { + ok($error_msg =~ /The password must be at least \d+ characters long/, + "Password Too Short: $password"); + } + $sel->go_back_ok(); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + } + + my $created = 0; + + foreach my $password (@$valid_passwords) { + $sel->type_ok('password', $password, 'Enter password'); + $sel->click_ok($created ? 'update' : 'add'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is($created ? "User $new_user updated" : "Edit user $new_user"); + my $msg = trim($sel->get_text('message')); + if ($created++) { + ok($msg =~ /A new password has been set/, 'Account updated'); + } + else { + ok($msg =~ /The user account $new_user has been created successfully/, 'Account created'); + } + } + + return unless $created; + + $sel->click_ok('delete'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("Confirm deletion of user $new_user"); + $sel->click_ok('delete'); + $sel->wait_for_page_to_load_ok(WAIT_TIME); + $sel->title_is("User $new_user deleted"); +} -- cgit v1.2.3-24-g4f1b