summaryrefslogtreecommitdiffstats
path: root/qa/t
diff options
context:
space:
mode:
Diffstat (limited to 'qa/t')
-rw-r--r--qa/t/lib/QA/REST.pm61
-rw-r--r--qa/t/rest_bugzilla.t60
-rw-r--r--qa/t/rest_classification.t61
-rw-r--r--qa/t/test_password_complexity.t99
4 files changed, 281 insertions, 0 deletions
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");
+}