From 4555e1b21c365ed8303ffb7a3325d773c9b8bf31 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 19 May 2021 15:44:42 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-12-stable-ee --- spec/controllers/admin/cohorts_controller_spec.rb | 2 +- .../admin/dev_ops_report_controller_spec.rb | 8 +- spec/controllers/admin/groups_controller_spec.rb | 6 +- .../admin/integrations_controller_spec.rb | 4 +- spec/controllers/admin/runners_controller_spec.rb | 11 ++ spec/controllers/admin/users_controller_spec.rb | 78 ++++++++++- spec/controllers/application_controller_spec.rb | 42 +++++- spec/controllers/boards/issues_controller_spec.rb | 13 ++ .../concerns/confirm_email_warning_spec.rb | 2 +- .../concerns/graceful_timeout_handling_spec.rb | 2 +- .../redirects_for_missing_path_on_tree_spec.rb | 2 +- spec/controllers/concerns/renders_commits_spec.rb | 1 + .../groups/group_members_controller_spec.rb | 66 ++++++--- spec/controllers/groups/runners_controller_spec.rb | 3 + .../groups/settings/ci_cd_controller_spec.rb | 19 ++- .../settings/integrations_controller_spec.rb | 4 +- .../groups/settings/repository_controller_spec.rb | 2 + spec/controllers/invites_controller_spec.rb | 142 ++++++++++++------- .../oauth/authorizations_controller_spec.rb | 69 +++++++--- .../oauth/jira/authorizations_controller_spec.rb | 12 +- .../cycle_analytics/stages_controller_spec.rb | 67 +++++++++ .../value_streams_controller_spec.rb | 43 ++++++ spec/controllers/projects/blob_controller_spec.rb | 119 ++++------------ spec/controllers/projects/hooks_controller_spec.rb | 56 +++++++- .../controllers/projects/issues_controller_spec.rb | 17 ++- .../controllers/projects/labels_controller_spec.rb | 2 +- .../projects/mattermosts_controller_spec.rb | 2 +- .../merge_requests/diffs_controller_spec.rb | 11 +- .../projects/merge_requests_controller_spec.rb | 6 +- .../dashboards_controller_spec.rb | 4 +- .../projects/pipelines_controller_spec.rb | 150 +++++++++++++++------ .../projects/project_members_controller_spec.rb | 14 +- .../projects/runners_controller_spec.rb | 88 +++--------- .../projects/services_controller_spec.rb | 8 +- .../projects/settings/ci_cd_controller_spec.rb | 52 +++++-- .../settings/repository_controller_spec.rb | 2 + .../projects/static_site_editor_controller_spec.rb | 2 +- .../experience_levels_controller_spec.rb | 4 +- .../registrations/welcome_controller_spec.rb | 24 ++++ spec/controllers/registrations_controller_spec.rb | 113 +++++++++++++++- spec/controllers/sessions_controller_spec.rb | 7 +- 41 files changed, 921 insertions(+), 358 deletions(-) create mode 100644 spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb create mode 100644 spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb (limited to 'spec/controllers') diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb index 77a9c8eb223..ba5406f25ab 100644 --- a/spec/controllers/admin/cohorts_controller_spec.rb +++ b/spec/controllers/admin/cohorts_controller_spec.rb @@ -12,6 +12,6 @@ RSpec.describe Admin::CohortsController do it 'redirects to Overview->Users' do get :index - expect(response).to redirect_to(admin_users_path(tab: 'cohorts')) + expect(response).to redirect_to(cohorts_admin_users_path) end end diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb index 142db175a15..49e6c0f69bd 100644 --- a/spec/controllers/admin/dev_ops_report_controller_spec.rb +++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb @@ -9,12 +9,6 @@ RSpec.describe Admin::DevOpsReportController do end end - describe 'should_track_devops_score?' do - it 'is always true' do - expect(controller.should_track_devops_score?).to be_truthy - end - end - describe 'GET #show' do context 'as admin' do let(:user) { create(:admin) } @@ -31,6 +25,8 @@ RSpec.describe Admin::DevOpsReportController do it_behaves_like 'tracking unique visits', :show do let(:target_id) { 'i_analytics_dev_ops_score' } + + let(:request_params) { { tab: 'devops-score' } } end end end diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index 8441a52b454..8e31ef12adf 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -55,7 +55,7 @@ RSpec.describe Admin::GroupsController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(admin_group_path(group)) expect(group.users).to include group_user end @@ -67,7 +67,7 @@ RSpec.describe Admin::GroupsController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(admin_group_path(group)) end @@ -78,7 +78,7 @@ RSpec.describe Admin::GroupsController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'No users specified.' + expect(controller).to set_flash.to 'No users specified.' expect(response).to redirect_to(admin_group_path(group)) expect(group.users).not_to include group_user end diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb index e14619a9916..971f2f121aa 100644 --- a/spec/controllers/admin/integrations_controller_spec.rb +++ b/spec/controllers/admin/integrations_controller_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Admin::IntegrationsController do end describe '#edit' do - Service.available_services_names.each do |integration_name| + Integration.available_services_names.each do |integration_name| context "#{integration_name}" do it 'successfully displays the template' do get :edit, params: { id: integration_name } @@ -27,7 +27,7 @@ RSpec.describe Admin::IntegrationsController do end it 'returns 404' do - get :edit, params: { id: Service.available_services_names.sample } + get :edit, params: { id: Integration.available_services_names.sample } expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb index 45ea8949bf2..3984784f045 100644 --- a/spec/controllers/admin/runners_controller_spec.rb +++ b/spec/controllers/admin/runners_controller_spec.rb @@ -34,6 +34,17 @@ RSpec.describe Admin::RunnersController do expect(response.body).to have_content('tag1') expect(response.body).to have_content('tag2') end + + it 'paginates runners' do + stub_const("Admin::RunnersController::NUMBER_OF_RUNNERS_PER_PAGE", 1) + + create(:ci_runner) + + get :index + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:runners).count).to be(1) + end end describe '#show' do diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 6faec315eb6..722c9c322cc 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -30,9 +30,33 @@ RSpec.describe Admin::UsersController do expect(assigns(:users).first.association(:authorized_projects)).to be_loaded end - it_behaves_like 'tracking unique visits', :index do + context 'pagination' do + context 'when number of users is over the pagination limit' do + before do + stub_const('Admin::UsersController::PAGINATION_WITH_COUNT_LIMIT', 5) + allow(Gitlab::Database::Count).to receive(:approximate_counts).with([User]).and_return({ User => 6 }) + end + + it 'marks the relation for pagination without counts' do + get :index + + expect(assigns(:users)).to be_a(Kaminari::PaginatableWithoutCount) + end + end + + context 'when number of users is below the pagination limit' do + it 'marks the relation for pagination with counts' do + get :index + + expect(assigns(:users)).not_to be_a(Kaminari::PaginatableWithoutCount) + end + end + end + end + + describe 'GET #cohorts' do + it_behaves_like 'tracking unique visits', :cohorts do let(:target_id) { 'i_analytics_cohorts' } - let(:request_params) { { tab: 'cohorts' } } end end @@ -341,6 +365,56 @@ RSpec.describe Admin::UsersController do end end + describe 'PUT ban/:id' do + context 'when ban_user_feature_flag is enabled' do + it 'bans user' do + put :ban, params: { id: user.username } + + user.reload + expect(user.banned?).to be_truthy + expect(flash[:notice]).to eq _('Successfully banned') + end + + context 'when unsuccessful' do + let(:user) { create(:user, :blocked) } + + it 'does not ban user' do + put :ban, params: { id: user.username } + + user.reload + expect(user.banned?).to be_falsey + expect(flash[:alert]).to eq _('Error occurred. User was not banned') + end + end + end + + context 'when ban_user_feature_flag is not enabled' do + before do + stub_feature_flags(ban_user_feature_flag: false) + end + + it 'does not ban user, renders 404' do + put :ban, params: { id: user.username } + + user.reload + expect(user.banned?).to be_falsey + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'PUT unban/:id' do + let(:banned_user) { create(:user, :banned) } + + it 'unbans user' do + put :unban, params: { id: banned_user.username } + + banned_user.reload + expect(banned_user.banned?).to be_falsey + expect(flash[:notice]).to eq _('Successfully unbanned') + end + end + describe 'PUT unlock/:id' do before do request.env["HTTP_REFERER"] = "/" diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 3d34db6c2c0..0235d7eb95a 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -725,7 +725,7 @@ RSpec.describe ApplicationController do format.csv do stream_csv_headers('test.csv') - self.response_body = fixture_file_upload('spec/fixtures/csv_comma.csv') + self.response_body = Rack::Test::UploadedFile.new('spec/fixtures/csv_comma.csv') end end end @@ -1027,4 +1027,44 @@ RSpec.describe ApplicationController do get :index end end + + describe 'setting permissions-policy header' do + controller do + skip_before_action :authenticate_user! + + def index + render html: 'It is a flock of sheep, not a floc of sheep.' + end + end + + before do + routes.draw do + get 'index' => 'anonymous#index' + end + end + + context 'with FloC enabled' do + before do + stub_application_setting floc_enabled: true + end + + it 'does not set the Permissions-Policy header' do + get :index + + expect(response.headers['Permissions-Policy']).to eq(nil) + end + end + + context 'with FloC disabled' do + before do + stub_application_setting floc_enabled: false + end + + it 'sets the Permissions-Policy header' do + get :index + + expect(response.headers['Permissions-Policy']).to eq('interest-cohort=()') + end + end + end end diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index d23f099e382..48000284264 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -49,6 +49,7 @@ RSpec.describe Boards::IssuesController do create(:labeled_issue, project: project, labels: [development], due_date: Date.tomorrow) create(:labeled_issue, project: project, labels: [development], assignees: [johndoe]) issue.subscribe(johndoe, project) + expect(Issue).to receive(:move_nulls_to_end) list_issues user: user, board: board, list: list2 @@ -119,6 +120,18 @@ RSpec.describe Boards::IssuesController do expect(query_count).to eq(1) end + + context 'when block_issue_repositioning feature flag is enabled' do + before do + stub_feature_flags(block_issue_repositioning: true) + end + + it 'does not reposition issues with null position' do + expect(Issue).not_to receive(:move_nulls_to_end) + + list_issues(user: user, board: group_board, list: list3) + end + end end context 'with invalid list id' do diff --git a/spec/controllers/concerns/confirm_email_warning_spec.rb b/spec/controllers/concerns/confirm_email_warning_spec.rb index 24ee6fb30d2..334c156e1ae 100644 --- a/spec/controllers/concerns/confirm_email_warning_spec.rb +++ b/spec/controllers/concerns/confirm_email_warning_spec.rb @@ -18,7 +18,7 @@ RSpec.describe ConfirmEmailWarning do RSpec::Matchers.define :set_confirm_warning_for do |email| match do |response| - expect(response).to set_flash.now[:warning].to include("Please check your email (#{email}) to verify that you own this address and unlock the power of CI/CD.") + expect(controller).to set_flash.now[:warning].to include("Please check your email (#{email}) to verify that you own this address and unlock the power of CI/CD.") end end diff --git a/spec/controllers/concerns/graceful_timeout_handling_spec.rb b/spec/controllers/concerns/graceful_timeout_handling_spec.rb index cece36f06b2..e496d12856b 100644 --- a/spec/controllers/concerns/graceful_timeout_handling_spec.rb +++ b/spec/controllers/concerns/graceful_timeout_handling_spec.rb @@ -9,7 +9,7 @@ RSpec.describe GracefulTimeoutHandling, type: :controller do skip_before_action :authenticate_user! def index - raise ActiveRecord::QueryCanceled.new + raise ActiveRecord::QueryCanceled end end diff --git a/spec/controllers/concerns/redirects_for_missing_path_on_tree_spec.rb b/spec/controllers/concerns/redirects_for_missing_path_on_tree_spec.rb index 5c3b6e13ee3..ccd5570f2bd 100644 --- a/spec/controllers/concerns/redirects_for_missing_path_on_tree_spec.rb +++ b/spec/controllers/concerns/redirects_for_missing_path_on_tree_spec.rb @@ -27,7 +27,7 @@ RSpec.describe RedirectsForMissingPathOnTree, type: :controller do get :fake, params: { project_id: project.id, ref: 'theref', file_path: long_file_path } expect(response).to redirect_to project_tree_path(project, 'theref') - expect(response.flash[:notice]).to eq(expected_message) + expect(controller).to set_flash[:notice].to eq(expected_message) end end end diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb index 7b241fc29af..5c918267f50 100644 --- a/spec/controllers/concerns/renders_commits_spec.rb +++ b/spec/controllers/concerns/renders_commits_spec.rb @@ -66,6 +66,7 @@ RSpec.describe RendersCommits do expect do subject.prepare_commits_for_rendering(merge_request.commits) + merge_request.commits.each(&:latest_pipeline) end.not_to exceed_all_query_limit(control.count) end end diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 19655687028..b666f73110a 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -5,9 +5,8 @@ require 'spec_helper' RSpec.describe Groups::GroupMembersController do include ExternalAuthorizationServiceHelpers - let(:user) { create(:user) } - let(:group) { create(:group, :public) } - let(:membership) { create(:group_member, group: group) } + let_it_be(:user) { create(:user) } + let_it_be(:group, reload: true) { create(:group, :public) } before do travel_to DateTime.new(2019, 4, 1) @@ -25,14 +24,22 @@ RSpec.describe Groups::GroupMembersController do expect(response).to render_template(:index) end - context 'user with owner access' do - let!(:invited) { create_list(:group_member, 3, :invited, group: group) } + context 'when user can manage members' do + let_it_be(:invited) { create_list(:group_member, 3, :invited, group: group) } before do group.add_owner(user) sign_in(user) end + it 'assigns max_access_for_group' do + allow(controller).to receive(:current_user).and_return(user) + + get :index, params: { group_id: group } + + expect(user.max_access_for_group[group.id]).to eq(Gitlab::Access::OWNER) + end + it 'assigns invited members' do get :index, params: { group_id: group } @@ -64,9 +71,22 @@ RSpec.describe Groups::GroupMembersController do end end + context 'when user cannot manage members' do + before do + sign_in(user) + end + + it 'does not assign invited members or skip_groups', :aggregate_failures do + get :index, params: { group_id: group } + + expect(assigns(:invited_members)).to be_nil + expect(assigns(:skip_groups)).to be_nil + end + end + context 'when user has owner access to subgroup' do - let(:nested_group) { create(:group, parent: group) } - let(:nested_group_user) { create(:user) } + let_it_be(:nested_group) { create(:group, parent: group) } + let_it_be(:nested_group_user) { create(:user) } before do group.add_owner(user) @@ -95,7 +115,7 @@ RSpec.describe Groups::GroupMembersController do end describe 'POST create' do - let(:group_user) { create(:user) } + let_it_be(:group_user) { create(:user) } before do sign_in(user) @@ -130,7 +150,7 @@ RSpec.describe Groups::GroupMembersController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(group_group_members_path(group)) expect(group.users).to include group_user end @@ -142,7 +162,7 @@ RSpec.describe Groups::GroupMembersController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'No users specified.' + expect(controller).to set_flash.to 'No users specified.' expect(response).to redirect_to(group_group_members_path(group)) expect(group.users).not_to include group_user end @@ -180,7 +200,7 @@ RSpec.describe Groups::GroupMembersController do it 'adds user to members' do subject - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(group_group_members_path(group)) expect(group.users).to include group_user end @@ -189,7 +209,7 @@ RSpec.describe Groups::GroupMembersController do end describe 'PUT update' do - let(:requester) { create(:group_member, :access_request, group: group) } + let_it_be(:requester) { create(:group_member, :access_request, group: group) } before do group.add_owner(user) @@ -292,9 +312,9 @@ RSpec.describe Groups::GroupMembersController do end describe 'DELETE destroy' do - let(:sub_group) { create(:group, parent: group) } - let!(:member) { create(:group_member, :developer, group: group) } - let!(:sub_member) { create(:group_member, :developer, group: sub_group, user: member.user) } + let_it_be(:sub_group) { create(:group, parent: group) } + let_it_be(:member) { create(:group_member, :developer, group: group) } + let_it_be(:sub_member) { create(:group_member, :developer, group: sub_group, user: member.user) } before do sign_in(user) @@ -330,7 +350,7 @@ RSpec.describe Groups::GroupMembersController do it '[HTML] removes user from members' do delete :destroy, params: { group_id: group, id: member } - expect(response).to set_flash.to 'User was successfully removed from group.' + expect(controller).to set_flash.to 'User was successfully removed from group.' expect(response).to redirect_to(group_group_members_path(group)) expect(group.members).not_to include member expect(sub_group.members).to include sub_member @@ -339,7 +359,7 @@ RSpec.describe Groups::GroupMembersController do it '[HTML] removes user from members including subgroups and projects' do delete :destroy, params: { group_id: group, id: member, remove_sub_memberships: true } - expect(response).to set_flash.to 'User was successfully removed from group and any subgroups and projects.' + expect(controller).to set_flash.to 'User was successfully removed from group and any subgroups and projects.' expect(response).to redirect_to(group_group_members_path(group)) expect(group.members).not_to include member expect(sub_group.members).not_to include sub_member @@ -377,7 +397,7 @@ RSpec.describe Groups::GroupMembersController do it 'removes user from members' do delete :leave, params: { group_id: group } - expect(response).to set_flash.to "You left the \"#{group.name}\" group." + expect(controller).to set_flash.to "You left the \"#{group.name}\" group." expect(response).to redirect_to(dashboard_groups_path) expect(group.users).not_to include user end @@ -403,6 +423,8 @@ RSpec.describe Groups::GroupMembersController do end context 'and is a requester' do + let(:group) { create(:group, :public) } + before do group.request_access(user) end @@ -410,7 +432,7 @@ RSpec.describe Groups::GroupMembersController do it 'removes user from members' do delete :leave, params: { group_id: group } - expect(response).to set_flash.to 'Your access request to the group has been withdrawn.' + expect(controller).to set_flash.to 'Your access request to the group has been withdrawn.' expect(response).to redirect_to(group_path(group)) expect(group.requesters).to be_empty expect(group.users).not_to include user @@ -427,7 +449,7 @@ RSpec.describe Groups::GroupMembersController do it 'creates a new GroupMember that is not a team member' do post :request_access, params: { group_id: group } - expect(response).to set_flash.to 'Your request for access has been queued for review.' + expect(controller).to set_flash.to 'Your request for access has been queued for review.' expect(response).to redirect_to(group_path(group)) expect(group.requesters.exists?(user_id: user)).to be_truthy expect(group.users).not_to include user @@ -435,7 +457,7 @@ RSpec.describe Groups::GroupMembersController do end describe 'POST approve_access_request' do - let(:member) { create(:group_member, :access_request, group: group) } + let_it_be(:member) { create(:group_member, :access_request, group: group) } before do sign_in(user) @@ -479,6 +501,8 @@ RSpec.describe Groups::GroupMembersController do end context 'with external authorization enabled' do + let_it_be(:membership) { create(:group_member, group: group) } + before do enable_external_authorization_service_check group.add_owner(user) diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index d6da9a4e8d0..2f1c6c813cf 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -302,6 +302,9 @@ RSpec.describe Groups::RunnersController do context 'when user is not an owner' do before do + # Disable limit checking + allow(runner).to receive(:runner_scope).and_return(nil) + group.add_maintainer(user) end diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb index 880d5fe8951..f225d798886 100644 --- a/spec/controllers/groups/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb @@ -32,6 +32,17 @@ RSpec.describe Groups::Settings::CiCdController do expect(response).to render_template(:show) expect(assigns(:group_runners)).to match_array([runner_group, runner_project_1, runner_project_2, runner_project_3]) end + + it 'paginates runners' do + stub_const("Groups::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE", 1) + + create(:ci_runner) + + get :show, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:group_runners).count).to be(1) + end end context 'when user is not owner' do @@ -128,7 +139,7 @@ RSpec.describe Groups::Settings::CiCdController do end it 'returns a flash alert' do - expect(response).to set_flash[:alert] + expect(controller).to set_flash[:alert] .to eq("There was a problem updating Auto DevOps pipeline: [\"Error 1\"].") end end @@ -137,7 +148,7 @@ RSpec.describe Groups::Settings::CiCdController do it 'returns a flash notice' do subject - expect(response).to set_flash[:notice] + expect(controller).to set_flash[:notice] .to eq('Auto DevOps pipeline was updated for the group') end end @@ -209,7 +220,7 @@ RSpec.describe Groups::Settings::CiCdController do end it 'returns a flash alert' do - expect(response).to set_flash[:alert] + expect(controller).to set_flash[:alert] .to eq("There was a problem updating the pipeline settings: [\"Error 1\"].") end end @@ -218,7 +229,7 @@ RSpec.describe Groups::Settings::CiCdController do it 'returns a flash notice' do subject - expect(response).to set_flash[:notice] + expect(controller).to set_flash[:notice] .to eq('Pipeline settings was updated for the group') end end diff --git a/spec/controllers/groups/settings/integrations_controller_spec.rb b/spec/controllers/groups/settings/integrations_controller_spec.rb index 3233e814184..63d99a1fab1 100644 --- a/spec/controllers/groups/settings/integrations_controller_spec.rb +++ b/spec/controllers/groups/settings/integrations_controller_spec.rb @@ -36,7 +36,7 @@ RSpec.describe Groups::Settings::IntegrationsController do describe '#edit' do context 'when user is not owner' do it 'renders not_found' do - get :edit, params: { group_id: group, id: Service.available_services_names(include_project_specific: false).sample } + get :edit, params: { group_id: group, id: Integration.available_services_names(include_project_specific: false).sample } expect(response).to have_gitlab_http_status(:not_found) end @@ -47,7 +47,7 @@ RSpec.describe Groups::Settings::IntegrationsController do group.add_owner(user) end - Service.available_services_names(include_project_specific: false).each do |integration_name| + Integration.available_services_names(include_project_specific: false).each do |integration_name| context "#{integration_name}" do it 'successfully displays the template' do get :edit, params: { group_id: group, id: integration_name } diff --git a/spec/controllers/groups/settings/repository_controller_spec.rb b/spec/controllers/groups/settings/repository_controller_spec.rb index 14bbdc05282..cbf55218b94 100644 --- a/spec/controllers/groups/settings/repository_controller_spec.rb +++ b/spec/controllers/groups/settings/repository_controller_spec.rb @@ -59,6 +59,8 @@ RSpec.describe Groups::Settings::RepositoryController do 'username' => deploy_token_params[:username], 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), 'token' => be_a(String), + 'expired' => false, + 'revoked' => false, 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index 5195f482084..6b94d186d5f 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -8,16 +8,18 @@ RSpec.describe InvitesController do let(:raw_invite_token) { member.raw_invite_token } let(:project_members) { member.source.users } let(:md5_member_global_id) { Digest::MD5.hexdigest(member.to_global_id.to_s) } - let(:params) { { id: raw_invite_token } } + let(:extra_params) { {} } + let(:params) { { id: raw_invite_token }.merge(extra_params) } shared_examples 'invalid token' do context 'when invite token is not valid' do - let(:params) { { id: '_bogus_token_' } } + let(:raw_invite_token) { '_bogus_token_' } - it 'renders the 404 page' do + it 'redirects to root' do request - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to redirect_to(root_path) + expect(controller).to set_flash[:alert].to('The invitation can not be found with the provided invite token.') end end end @@ -25,6 +27,37 @@ RSpec.describe InvitesController do describe 'GET #show' do subject(:request) { get :show, params: params } + context 'when it is part of our invite email experiment' do + let(:extra_params) { { invite_type: 'initial_email' } } + + it 'tracks the experiment' do + experiment = double(track: true) + allow(controller).to receive(:experiment).with('members/invite_email', actor: member).and_return(experiment) + + request + + expect(experiment).to have_received(:track).with(:join_clicked) + end + + context 'when member does not exist' do + let(:raw_invite_token) { '_bogus_token_' } + + it 'does not track the experiment' do + expect(controller).not_to receive(:experiment).with('members/invite_email', actor: member) + + request + end + end + end + + context 'when it is not part of our invite email experiment' do + it 'does not track via experiment' do + expect(controller).not_to receive(:experiment).with('members/invite_email', actor: member) + + request + end + end + context 'when logged in' do before do sign_in(user) @@ -51,32 +84,10 @@ RSpec.describe InvitesController do end it_behaves_like 'invalid token' - - context 'when invite comes from the initial email invite' do - let(:params) { { id: raw_invite_token, invite_type: Members::InviteEmailExperiment::INVITE_TYPE } } - - it 'tracks via experiment', :aggregate_failures do - experiment = double(track: true) - allow(controller).to receive(:experiment).and_return(experiment) - - request - - expect(experiment).to have_received(:track).with(:opened) - expect(experiment).to have_received(:track).with(:accepted) - end - end - - context 'when invite does not come from initial email invite' do - it 'does not track via experiment' do - expect(controller).not_to receive(:experiment) - - request - end - end end context 'when not logged in' do - context 'when inviter is a member' do + context 'when invite token belongs to a valid member' do context 'when instance allows sign up' do it 'indicates an account can be created in notice' do request @@ -116,10 +127,62 @@ RSpec.describe InvitesController do expect(flash[:notice]).to include('create an account or sign in') end - it 'is redirected to a new registration with invite email param' do + context 'when it is part of our invite email experiment', :experiment, :aggregate_failures do + let(:experience) { :control } + + before do + stub_experiments(invite_signup_page_interaction: experience) + end + + it 'sets originating_member_id session key' do + request + + expect(session[:originating_member_id]).to eq(member.id) + end + + context 'with control experience' do + it 'is redirected to a new registration with invite email param and flash message' do + request + + expect(response).to redirect_to(new_user_registration_path(invite_email: member.invite_email)) + expect(flash[:notice]).to eq 'To accept this invitation, create an account or sign in.' + end + end + + context 'with candidate experience' do + let(:experience) { :candidate } + + it 'is redirected to a new invite registration with invite email param and no flash message' do + request + + expect(response).to redirect_to(new_users_sign_up_invite_path(invite_email: member.invite_email)) + expect(flash[:notice]).to be_nil + end + end + end + + it 'sets session keys for auto email confirmation on sign up' do request - expect(response).to redirect_to(new_user_registration_path(invite_email: member.invite_email)) + expect(session[:invite_email]).to eq(member.invite_email) + end + + context 'when it is part of our invite email experiment' do + let(:extra_params) { { invite_type: 'initial_email' } } + + it 'sets session key for invite acceptance tracking on sign-up' do + request + + expect(session[:originating_member_id]).to eq(member.id) + end + end + + context 'when it is not part of our invite email experiment' do + it 'does not set the session key for invite acceptance tracking on sign-up' do + request + + expect(session[:originating_member_id]).to be_nil + end end end end @@ -157,7 +220,7 @@ RSpec.describe InvitesController do end end - context 'when inviter is not a member' do + context 'when invite token does not belong to a valid member' do let(:params) { { id: '_bogus_token_' } } it 'is redirected to a new session' do @@ -177,25 +240,6 @@ RSpec.describe InvitesController do subject(:request) { post :accept, params: params } it_behaves_like 'invalid token' - - context 'when invite comes from the initial email invite' do - it 'tracks via experiment' do - experiment = double(track: true) - allow(controller).to receive(:experiment).and_return(experiment) - - post :accept, params: params, session: { invite_type: Members::InviteEmailExperiment::INVITE_TYPE } - - expect(experiment).to have_received(:track).with(:accepted) - end - end - - context 'when invite does not come from initial email invite' do - it 'does not track via experiment' do - expect(controller).not_to receive(:experiment) - - request - end - end end describe 'POST #decline for link in UI' do diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index 21124299b25..5fc5cdfc9b9 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -73,39 +73,74 @@ RSpec.describe Oauth::AuthorizationsController do include_examples 'OAuth Authorizations require confirmed user' include_examples "Implicit grant can't be used in confidential application" - context 'when the user is confirmed' do - let(:confirmed_at) { 1.hour.ago } + context 'rendering of views based on the ownership of the application' do + shared_examples 'render views' do + render_views - context 'without valid params' do - it 'returns 200 code and renders error view' do - get :new + it 'returns 200 and renders view with correct info', :aggregate_failures do + subject expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template('doorkeeper/authorizations/error') + expect(response.body).to include(application.owner.name) + expect(response).to render_template('doorkeeper/authorizations/new') end end - context 'with valid params' do - render_views + subject { get :new, params: params } - it 'returns 200 code and renders view' do - subject + context 'when auth app owner is a user' do + context 'with valid params' do + it_behaves_like 'render views' + end + end - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template('doorkeeper/authorizations/new') + context 'when auth app owner is a group' do + let(:group) { create(:group) } + + context 'when auth app owner is a root group' do + let(:application) { create(:oauth_application, owner_id: group.id, owner_type: 'Namespace') } + + it_behaves_like 'render views' + end + + context 'when auth app owner is a subgroup' do + let(:subgroup) { create(:group, parent: group) } + let(:application) { create(:oauth_application, owner_id: subgroup.id, owner_type: 'Namespace') } + + it_behaves_like 'render views' end + end - it 'deletes session.user_return_to and redirects when skip authorization' do - application.update!(trusted: true) - request.session['user_return_to'] = 'http://example.com' + context 'when there is no owner associated' do + let(:application) { create(:oauth_application, owner_id: nil, owner_type: nil) } + it 'renders view' do subject - expect(request.session['user_return_to']).to be_nil - expect(response).to have_gitlab_http_status(:found) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/new') end end end + + context 'without valid params' do + it 'returns 200 code and renders error view' do + get :new + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/error') + end + end + + it 'deletes session.user_return_to and redirects when skip authorization' do + application.update!(trusted: true) + request.session['user_return_to'] = 'http://example.com' + + subject + + expect(request.session['user_return_to']).to be_nil + expect(response).to have_gitlab_http_status(:found) + end end describe 'POST #create' do diff --git a/spec/controllers/oauth/jira/authorizations_controller_spec.rb b/spec/controllers/oauth/jira/authorizations_controller_spec.rb index 0b4a691d7ec..f4a335b30f4 100644 --- a/spec/controllers/oauth/jira/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/jira/authorizations_controller_spec.rb @@ -5,10 +5,20 @@ require 'spec_helper' RSpec.describe Oauth::Jira::AuthorizationsController do describe 'GET new' do it 'redirects to OAuth authorization with correct params' do - get :new, params: { client_id: 'client-123', redirect_uri: 'http://example.com/' } + get :new, params: { client_id: 'client-123', scope: 'foo', redirect_uri: 'http://example.com/' } expect(response).to redirect_to(oauth_authorization_url(client_id: 'client-123', response_type: 'code', + scope: 'foo', + redirect_uri: oauth_jira_callback_url)) + end + + it 'replaces the GitHub "repo" scope with "api"' do + get :new, params: { client_id: 'client-123', scope: 'repo', redirect_uri: 'http://example.com/' } + + expect(response).to redirect_to(oauth_authorization_url(client_id: 'client-123', + response_type: 'code', + scope: 'api', redirect_uri: oauth_jira_callback_url)) end end diff --git a/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb b/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb new file mode 100644 index 00000000000..3bb841c7c9f --- /dev/null +++ b/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::Analytics::CycleAnalytics::StagesController do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + let(:params) { { namespace_id: group, project_id: project, value_stream_id: 'default' } } + + before do + sign_in(user) + end + + describe 'GET index' do + context 'when user is member of the project' do + before do + project.add_developer(user) + end + + it 'succeeds' do + get :index, params: params + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'exposes the default stages' do + get :index, params: params + + expect(json_response['stages'].size).to eq(Gitlab::Analytics::CycleAnalytics::DefaultStages.all.size) + end + + context 'when list service fails' do + it 'renders 403' do + expect_next_instance_of(Analytics::CycleAnalytics::Stages::ListService) do |list_service| + expect(list_service).to receive(:allowed?).and_return(false) + end + + get :index, params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + context 'when invalid value stream id is given' do + before do + params[:value_stream_id] = 1 + end + + it 'renders 404' do + get :index, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when user is not member of the project' do + it 'renders 404' do + get :index, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb b/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb new file mode 100644 index 00000000000..5b434eb2011 --- /dev/null +++ b/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::Analytics::CycleAnalytics::ValueStreamsController do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + let(:params) { { namespace_id: group, project_id: project } } + + before do + sign_in(user) + end + + describe 'GET index' do + context 'when user is member of the project' do + before do + project.add_developer(user) + end + + it 'succeeds' do + get :index, params: params + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'exposes the default value stream' do + get :index, params: params + + expect(json_response.first['name']).to eq('default') + end + end + + context 'when user is not member of the project' do + it 'renders 404' do + get :index, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index c9a76049e19..b965feee645 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -7,96 +7,6 @@ RSpec.describe Projects::BlobController do let(:project) { create(:project, :public, :repository) } - describe "GET new" do - context 'with no jobs' do - let_it_be(:user) { create(:user) } - let_it_be(:file_name) { '.gitlab-ci.yml' } - - def request - get(:new, params: { namespace_id: project.namespace, project_id: project, id: 'master', file_name: file_name } ) - end - - before do - project.add_maintainer(user) - sign_in(user) - - stub_experiment(ci_syntax_templates_b: experiment_active) - stub_experiment_for_subject(ci_syntax_templates_b: in_experiment_group) - end - - context 'when the experiment is not active' do - let(:experiment_active) { false } - let(:in_experiment_group) { false } - - it 'does not record the experiment user' do - expect(Experiment).not_to receive(:add_user) - - request - end - end - - context 'when the experiment is active' do - let(:experiment_active) { true } - - context 'when the user is in the control group' do - let(:in_experiment_group) { false } - - it 'records the experiment user in the control group' do - expect(Experiment).to receive(:add_user) - .with(:ci_syntax_templates_b, :control, user, namespace_id: project.namespace_id) - - request - end - end - - context 'when the user is in the experimental group' do - let(:in_experiment_group) { true } - - it 'records the experiment user in the experimental group' do - expect(Experiment).to receive(:add_user) - .with(:ci_syntax_templates_b, :experimental, user, namespace_id: project.namespace_id) - - request - end - - context 'when requesting a non default config file type' do - let(:file_name) { '.non_default_ci_config' } - let(:project) { create(:project, :public, :repository, ci_config_path: file_name) } - - it 'records the experiment user in the experimental group' do - expect(Experiment).to receive(:add_user) - .with(:ci_syntax_templates_b, :experimental, user, namespace_id: project.namespace_id) - - request - end - end - - context 'when requesting a different file type' do - let(:file_name) { '.gitignore' } - - it 'does not record the experiment user' do - expect(Experiment).not_to receive(:add_user) - - request - end - end - - context 'when the group is created longer than 90 days ago' do - before do - project.namespace.update_attribute(:created_at, 91.days.ago) - end - - it 'does not record the experiment user' do - expect(Experiment).not_to receive(:add_user) - - request - end - end - end - end - end - end - describe "GET show" do def request get(:show, params: { namespace_id: project.namespace, project_id: project, id: id }) @@ -554,11 +464,36 @@ RSpec.describe Projects::BlobController do sign_in(user) end - it_behaves_like 'tracking unique hll events' do - subject(:request) { post :create, params: default_params } + subject(:request) { post :create, params: default_params } + it_behaves_like 'tracking unique hll events' do let(:target_id) { 'g_edit_by_sfe' } let(:expected_type) { instance_of(Integer) } end + + it 'redirects to blob' do + request + + expect(response).to redirect_to(project_blob_path(project, 'master/docs/EXAMPLE_FILE')) + end + + context 'when code_quality_walkthrough param is present' do + let(:default_params) { super().merge(code_quality_walkthrough: true) } + + it 'redirects to the pipelines page' do + request + + expect(response).to redirect_to(project_pipelines_path(project, code_quality_walkthrough: true)) + end + + it 'creates an "commit_created" experiment tracking event' do + experiment = double(track: true) + expect(controller).to receive(:experiment).with(:code_quality_walkthrough, namespace: project.root_ancestor).and_return(experiment) + + request + + expect(experiment).to have_received(:track).with(:commit_created) + end + end end end diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index b9c008d2950..17baf38ef32 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' RSpec.describe Projects::HooksController do - let(:project) { create(:project) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + let(:user) { project.owner } before do - project.add_maintainer(user) sign_in(user) end @@ -20,6 +20,56 @@ RSpec.describe Projects::HooksController do end end + describe '#edit' do + let_it_be(:hook) { create(:project_hook, project: project) } + + let(:params) do + { namespace_id: project.namespace, project_id: project, id: hook.id } + end + + render_views + + it 'does not error if the hook cannot be found' do + get :edit, params: params.merge(id: non_existing_record_id) + + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'assigns hook_logs' do + get :edit, params: params + + expect(assigns[:hook]).to be_present + expect(assigns[:hook_logs]).to be_empty + it_renders_correctly + end + + it 'handles when logs are present' do + create_list(:web_hook_log, 3, web_hook: hook) + + get :edit, params: params + + expect(assigns[:hook]).to be_present + expect(assigns[:hook_logs].count).to eq 3 + it_renders_correctly + end + + it 'can paginate logs' do + create_list(:web_hook_log, 21, web_hook: hook) + + get :edit, params: params.merge(page: 2) + + expect(assigns[:hook]).to be_present + expect(assigns[:hook_logs].count).to eq 1 + it_renders_correctly + end + + def it_renders_correctly + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:edit) + expect(response).to render_template('projects/hook_logs/_index') + end + end + describe '#create' do it 'sets all parameters' do hook_params = { diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 3e016a5e8d2..059e7884d55 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -586,13 +586,15 @@ RSpec.describe Projects::IssuesController do end describe 'PUT #update' do + let(:issue_params) { { title: 'New title' } } + subject do put :update, params: { namespace_id: project.namespace, project_id: project, id: issue.to_param, - issue: { title: 'New title' } + issue: issue_params }, format: :json end @@ -614,6 +616,17 @@ RSpec.describe Projects::IssuesController do expect(issue.reload.title).to eq('New title') end + context 'with issue_type param' do + let(:issue_params) { { issue_type: 'incident' } } + + it 'permits the parameter' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(issue.reload.issue_type).to eql('incident') + end + end + context 'when the SpamVerdictService disallows' do before do stub_application_setting(recaptcha_enabled: true) @@ -1704,7 +1717,7 @@ RSpec.describe Projects::IssuesController do request_csv expect(response).to redirect_to(project_issues_path(project)) - expect(response.flash[:notice]).to match(/\AYour CSV export has started/i) + expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i) end end diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index 081927ea73c..776ed9774b1 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -201,7 +201,7 @@ RSpec.describe Projects::LabelsController do context 'service raising InvalidRecord' do before do expect_any_instance_of(Labels::PromoteService).to receive(:execute) do |label| - raise ActiveRecord::RecordInvalid.new(label_1) + raise ActiveRecord::RecordInvalid, label_1 end end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 001f2564698..10bcee28f71 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -60,7 +60,7 @@ RSpec.describe Projects::MattermostsController do it 'redirects to the new page' do subject - service = project.services.last + service = project.integrations.last expect(subject).to redirect_to(edit_project_service_url(project, service)) end diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 50f8942d9d5..989f941caea 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -180,7 +180,8 @@ RSpec.describe Projects::MergeRequests::DiffsController do start_version: nil, start_sha: nil, commit: nil, - latest_diff: true + latest_diff: true, + only_context_commits: false } expect_next_instance_of(DiffsMetadataSerializer) do |instance| @@ -203,7 +204,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do end it "correctly generates the right diff between versions" do - MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request) + MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author).execute(merge_request) expect_next_instance_of(CompareService) do |service| expect(service).to receive(:execute).with( @@ -261,7 +262,8 @@ RSpec.describe Projects::MergeRequests::DiffsController do start_version: nil, start_sha: nil, commit: nil, - latest_diff: true + latest_diff: true, + only_context_commits: false } expect_next_instance_of(DiffsMetadataSerializer) do |instance| @@ -290,7 +292,8 @@ RSpec.describe Projects::MergeRequests::DiffsController do start_version: nil, start_sha: nil, commit: merge_request.diff_head_commit, - latest_diff: nil + latest_diff: nil, + only_context_commits: false } expect_next_instance_of(DiffsMetadataSerializer) do |instance| diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 337a4a19b2e..d4c52e1c7ca 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -531,7 +531,7 @@ RSpec.describe Projects::MergeRequestsController do sha: merge_request.diff_head_sha, merge_request: merge_request } - expect_next_instance_of(MergeRequests::SquashService, project, user, expected_squash_params) do |squash_service| + expect_next_instance_of(MergeRequests::SquashService, project: project, current_user: user, params: expected_squash_params) do |squash_service| expect(squash_service).to receive(:execute).and_return({ status: :success, squash_sha: SecureRandom.hex(20) @@ -1831,7 +1831,7 @@ RSpec.describe Projects::MergeRequestsController do it 'calls MergeRequests::AssignIssuesService' do expect(MergeRequests::AssignIssuesService).to receive(:new) - .with(project, user, merge_request: merge_request) + .with(project: project, current_user: user, params: { merge_request: merge_request }) .and_return(double(execute: { count: 1 })) post_assign_issues @@ -2229,7 +2229,7 @@ RSpec.describe Projects::MergeRequestsController do subject expect(response).to redirect_to(project_merge_requests_path(project)) - expect(response.flash[:notice]).to match(/\AYour CSV export has started/i) + expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i) end it 'enqueues an IssuableExportCsvWorker worker' do diff --git a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb index 923581d9367..939366e5b0b 100644 --- a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb +++ b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb @@ -64,7 +64,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do post :create, params: params expect(response).to have_gitlab_http_status :created - expect(response).to set_flash[:notice].to eq("Your dashboard has been copied. You can edit it here.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been copied. You can edit it here.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'path' => ".gitlab/dashboards/#{file_name}" }) end @@ -203,7 +203,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do put :update, params: params expect(response).to have_gitlab_http_status :created - expect(response).to set_flash[:notice].to eq("Your dashboard has been updated. You can edit it here.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been updated. You can edit it here.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'default' => false, 'display_name' => "custom_dashboard.yml", 'path' => ".gitlab/dashboards/#{file_name}", 'system_dashboard' => false }) end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 4a1d01f0e82..0e6b5e84d85 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -288,6 +288,17 @@ RSpec.describe Projects::PipelinesController do get :index, params: { namespace_id: project.namespace, project_id: project } end end + + context 'code_quality_walkthrough experiment' do + it 'tracks the view', :experiment do + expect(experiment(:code_quality_walkthrough)) + .to track(:view, property: project.root_ancestor.id.to_s) + .with_context(namespace: project.root_ancestor) + .on_next_instance + + get :index, params: { namespace_id: project.namespace, project_id: project } + end + end end describe 'GET #show' do @@ -842,10 +853,7 @@ RSpec.describe Projects::PipelinesController do end describe 'POST retry.json' do - let!(:pipeline) { create(:ci_pipeline, :failed, project: project) } - let!(:build) { create(:ci_build, :failed, pipeline: pipeline) } - - before do + subject(:post_retry) do post :retry, params: { namespace_id: project.namespace, project_id: project, @@ -854,15 +862,41 @@ RSpec.describe Projects::PipelinesController do format: :json end - it 'retries a pipeline without returning any content' do + let!(:pipeline) { create(:ci_pipeline, :failed, project: project) } + let!(:build) { create(:ci_build, :failed, pipeline: pipeline) } + + let(:worker_spy) { class_spy(::Ci::RetryPipelineWorker) } + + before do + stub_const('::Ci::RetryPipelineWorker', worker_spy) + end + + it 'retries a pipeline in the background without returning any content' do + post_retry + expect(response).to have_gitlab_http_status(:no_content) - expect(build.reload).to be_retried + expect(::Ci::RetryPipelineWorker).to have_received(:perform_async).with(pipeline.id, user.id) + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(background_pipeline_retry_endpoint: false) + end + + it 'retries the pipeline without returning any content' do + post_retry + + expect(response).to have_gitlab_http_status(:no_content) + expect(build.reload).to be_retried + end end context 'when builds are disabled' do let(:feature) { ProjectFeature::DISABLED } it 'fails to retry pipeline' do + post_retry + expect(response).to have_gitlab_http_status(:not_found) end end @@ -976,49 +1010,26 @@ RSpec.describe Projects::PipelinesController do end end - context 'when junit_pipeline_screenshots_view is enabled' do - before do - stub_feature_flags(junit_pipeline_screenshots_view: project) - end - - context 'when test_report contains attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } + context 'when test_report contains attachment and scope is with_attachment as a URL param' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } - it 'returns a test reports with attachment' do - get_test_report_json(scope: 'with_attachment') + it 'returns a test reports with attachment' do + get_test_report_json(scope: 'with_attachment') - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"]).to be_present - expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url") - end - end - - context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - - it 'returns a test reports with empty values' do - get_test_report_json(scope: 'with_attachment') - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"]).to be_empty - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"]).to be_present + expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url") end end - context 'when junit_pipeline_screenshots_view is disabled' do - before do - stub_feature_flags(junit_pipeline_screenshots_view: false) - end - - context 'when test_report contains attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } + context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - it 'returns a test reports without attachment_url' do - get_test_report_json(scope: 'with_attachment') + it 'returns a test reports with empty values' do + get_test_report_json(scope: 'with_attachment') - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url") - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"]).to be_empty end end @@ -1280,4 +1291,59 @@ RSpec.describe Projects::PipelinesController do format: :json end end + + describe 'GET downloadable_artifacts.json' do + context 'when pipeline is empty' do + let(:pipeline) { create(:ci_empty_pipeline) } + + it 'returns status not_found' do + get_downloadable_artifacts_json + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when pipeline exists' do + context 'when pipeline does not have any downloadable artifacts' do + let(:pipeline) { create(:ci_pipeline, project: project) } + + it 'returns an empty array' do + get_downloadable_artifacts_json + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['artifacts']).to be_empty + end + end + + context 'when pipeline has downloadable artifacts' do + let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) } + + before do + create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| + create(:ci_job_artifact, :junit, job: build) + end + end + + it 'returns an array of artifacts' do + get_downloadable_artifacts_json + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['artifacts']).to be_kind_of(Array) + expect(json_response['artifacts'].size).to eq(2) + end + end + end + + private + + def get_downloadable_artifacts_json + get :downloadable_artifacts, + params: { + namespace_id: project.namespace, + project_id: project, + id: pipeline.id + }, + format: :json + end + end end diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 46a0fc8edb0..bb817fc94b2 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -199,7 +199,7 @@ RSpec.describe Projects::ProjectMembersController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(project_project_members_path(project)) end @@ -215,7 +215,7 @@ RSpec.describe Projects::ProjectMembersController do access_level: Gitlab::Access::GUEST } - expect(response).to set_flash.to 'Message' + expect(controller).to set_flash.to 'Message' expect(response).to redirect_to(project_project_members_path(project)) end end @@ -276,7 +276,7 @@ RSpec.describe Projects::ProjectMembersController do it 'adds user to members' do subject - expect(response).to set_flash.to 'Users were successfully added.' + expect(controller).to set_flash.to 'Users were successfully added.' expect(response).to redirect_to(project_project_members_path(project)) expect(project.users).to include project_user end @@ -489,7 +489,7 @@ RSpec.describe Projects::ProjectMembersController do project_id: project } - expect(response).to set_flash.to "You left the \"#{project.human_name}\" project." + expect(controller).to set_flash.to "You left the \"#{project.human_name}\" project." expect(response).to redirect_to(dashboard_projects_path) expect(project.users).not_to include user end @@ -523,7 +523,7 @@ RSpec.describe Projects::ProjectMembersController do project_id: project } - expect(response).to set_flash.to 'Your access request to the project has been withdrawn.' + expect(controller).to set_flash.to 'Your access request to the project has been withdrawn.' expect(response).to redirect_to(project_path(project)) expect(project.requesters).to be_empty expect(project.users).not_to include user @@ -543,7 +543,7 @@ RSpec.describe Projects::ProjectMembersController do project_id: project } - expect(response).to set_flash.to 'Your request for access has been queued for review.' + expect(controller).to set_flash.to 'Your request for access has been queued for review.' expect(response).to redirect_to( project_path(project) ) @@ -639,7 +639,7 @@ RSpec.describe Projects::ProjectMembersController do it 'imports source project members' do expect(project.team_members).to include member - expect(response).to set_flash.to 'Successfully imported' + expect(controller).to set_flash.to 'Successfully imported' expect(response).to redirect_to( project_project_members_path(project) ) diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 3021ad42c9f..39b45a7133c 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -78,84 +78,40 @@ RSpec.describe Projects::RunnersController do let(:group) { create(:group) } let(:project) { create(:project, group: group) } - context 'without feature flag' do - before do - stub_feature_flags(vueify_shared_runners_toggle: false) - end + it 'toggles shared_runners_enabled when the group allows shared runners' do + project.update!(shared_runners_enabled: true) - it 'toggles shared_runners_enabled when the group allows shared runners' do - project.update!(shared_runners_enabled: true) + post :toggle_shared_runners, params: params - post :toggle_shared_runners, params: params + project.reload - project.reload - - expect(response).to have_gitlab_http_status(:found) - expect(project.shared_runners_enabled).to eq(false) - end - - it 'toggles shared_runners_enabled when the group disallows shared runners but allows overrides' do - group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true) - project.update!(shared_runners_enabled: false) - - post :toggle_shared_runners, params: params - - project.reload - - expect(response).to have_gitlab_http_status(:found) - expect(project.shared_runners_enabled).to eq(true) - end - - it 'does not enable if the group disallows shared runners' do - group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false) - project.update!(shared_runners_enabled: false) - - post :toggle_shared_runners, params: params - - project.reload - - expect(response).to have_gitlab_http_status(:found) - expect(project.shared_runners_enabled).to eq(false) - expect(flash[:alert]).to eq('Cannot enable shared runners because parent group does not allow it') - end + expect(response).to have_gitlab_http_status(:ok) + expect(project.shared_runners_enabled).to eq(false) end - context 'with feature flag: vueify_shared_runners_toggle' do - it 'toggles shared_runners_enabled when the group allows shared runners' do - project.update!(shared_runners_enabled: true) - - post :toggle_shared_runners, params: params - - project.reload + it 'toggles shared_runners_enabled when the group disallows shared runners but allows overrides' do + group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true) + project.update!(shared_runners_enabled: false) - expect(response).to have_gitlab_http_status(:ok) - expect(project.shared_runners_enabled).to eq(false) - end + post :toggle_shared_runners, params: params - it 'toggles shared_runners_enabled when the group disallows shared runners but allows overrides' do - group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true) - project.update!(shared_runners_enabled: false) + project.reload - post :toggle_shared_runners, params: params - - project.reload - - expect(response).to have_gitlab_http_status(:ok) - expect(project.shared_runners_enabled).to eq(true) - end + expect(response).to have_gitlab_http_status(:ok) + expect(project.shared_runners_enabled).to eq(true) + end - it 'does not enable if the group disallows shared runners' do - group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false) - project.update!(shared_runners_enabled: false) + it 'does not enable if the group disallows shared runners' do + group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false) + project.update!(shared_runners_enabled: false) - post :toggle_shared_runners, params: params + post :toggle_shared_runners, params: params - project.reload + project.reload - expect(response).to have_gitlab_http_status(:unauthorized) - expect(project.shared_runners_enabled).to eq(false) - expect(json_response['error']).to eq('Cannot enable shared runners because parent group does not allow it') - end + expect(response).to have_gitlab_http_status(:unauthorized) + expect(project.shared_runners_enabled).to eq(false) + expect(json_response['error']).to eq('Cannot enable shared runners because parent group does not allow it') end end end diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 488a34b74df..d8fb3b226ed 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Projects::ServicesController do describe '#test' do context 'when can_test? returns false' do it 'renders 404' do - allow_any_instance_of(Service).to receive(:can_test?).and_return(false) + allow_any_instance_of(Integration).to receive(:can_test?).and_return(false) put :test, params: project_params @@ -271,7 +271,7 @@ RSpec.describe Projects::ServicesController do expect(response).to redirect_to(edit_project_service_path(project, service)) expected_alert = "You can now manage your Prometheus settings on the Operations page. Fields on this page has been deprecated." - expect(response).to set_flash.now[:alert].to(expected_alert) + expect(controller).to set_flash.now[:alert].to(expected_alert) end it 'does not modify service' do @@ -317,7 +317,7 @@ RSpec.describe Projects::ServicesController do it 'renders deprecation warning notice' do expected_alert = "You can now manage your Prometheus settings on the Operations page. Fields on this page has been deprecated." - expect(response).to set_flash.now[:alert].to(expected_alert) + expect(controller).to set_flash.now[:alert].to(expected_alert) end end @@ -328,7 +328,7 @@ RSpec.describe Projects::ServicesController do end it 'does not render deprecation warning notice' do - expect(response).not_to set_flash.now[:alert] + expect(controller).not_to set_flash.now[:alert] end end end diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index d953249c139..dc7066f6b61 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -14,6 +14,10 @@ RSpec.describe Projects::Settings::CiCdController do end describe 'GET show' do + let_it_be(:parent_group) { create(:group) } + let_it_be(:group) { create(:group, parent: parent_group) } + let_it_be(:other_project) { create(:project, group: group) } + it 'renders show with 200 status code' do get :show, params: { namespace_id: project.namespace, project_id: project } @@ -22,12 +26,9 @@ RSpec.describe Projects::Settings::CiCdController do end context 'with group runners' do - let(:parent_group) { create(:group) } - let(:group) { create(:group, parent: parent_group) } - let(:group_runner) { create(:ci_runner, :group, groups: [group]) } - let(:other_project) { create(:project, group: group) } - let!(:project_runner) { create(:ci_runner, :project, projects: [other_project]) } - let!(:shared_runner) { create(:ci_runner, :instance) } + let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) } + let_it_be(:project_runner) { create(:ci_runner, :project, projects: [other_project]) } + let_it_be(:shared_runner) { create(:ci_runner, :instance) } it 'sets assignable project runners only' do group.add_maintainer(user) @@ -37,6 +38,33 @@ RSpec.describe Projects::Settings::CiCdController do expect(assigns(:assignable_runners)).to contain_exactly(project_runner) end end + + context 'prevents N+1 queries for tags' do + render_views + + def show + get :show, params: { namespace_id: project.namespace, project_id: project } + end + + it 'has the same number of queries with one tag or with many tags', :request_store do + group.add_maintainer(user) + + show # warmup + + # with one tag + create(:ci_runner, :instance, tag_list: %w(shared_runner)) + create(:ci_runner, :project, projects: [other_project], tag_list: %w(project_runner)) + create(:ci_runner, :group, groups: [group], tag_list: %w(group_runner)) + control = ActiveRecord::QueryRecorder.new { show } + + # with several tags + create(:ci_runner, :instance, tag_list: %w(shared_runner tag2 tag3)) + create(:ci_runner, :project, projects: [other_project], tag_list: %w(project_runner tag2 tag3)) + create(:ci_runner, :group, groups: [group], tag_list: %w(group_runner tag2 tag3)) + + expect { show }.not_to exceed_query_limit(control) + end + end end describe '#reset_cache' do @@ -134,7 +162,9 @@ RSpec.describe Projects::Settings::CiCdController do context 'when the project repository is empty' do it 'sets a notice flash' do - expect(subject).to set_flash[:notice] + subject + + expect(controller).to set_flash[:notice] end it 'does not queue a CreatePipelineWorker' do @@ -150,7 +180,9 @@ RSpec.describe Projects::Settings::CiCdController do it 'displays a toast message' do allow(CreatePipelineWorker).to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) - expect(subject).to set_flash[:toast] + subject + + expect(controller).to set_flash[:toast] end it 'queues a CreatePipelineWorker' do @@ -211,7 +243,9 @@ RSpec.describe Projects::Settings::CiCdController do let(:params) { { build_timeout_human_readable: '5m' } } it 'set specified timeout' do - expect(subject).to set_flash[:alert] + subject + + expect(controller).to set_flash[:alert] expect(response).to redirect_to(namespace_project_settings_ci_cd_path) end end diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 394f1ff28f2..2bb93990c58 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -78,6 +78,8 @@ RSpec.describe Projects::Settings::RepositoryController do 'username' => deploy_token_params[:username], 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), 'token' => be_a(String), + 'expired' => false, + 'revoked' => false, 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb index 73b0e3bba69..26161b5fb5c 100644 --- a/spec/controllers/projects/static_site_editor_controller_spec.rb +++ b/spec/controllers/projects/static_site_editor_controller_spec.rb @@ -102,7 +102,7 @@ RSpec.describe Projects::StaticSiteEditorController do it 'redirects to project page and flashes error message' do expect(response).to redirect_to(project_path(project)) - expect(response).to set_flash[:alert].to('invalid') + expect(controller).to set_flash[:alert].to('invalid') end end diff --git a/spec/controllers/registrations/experience_levels_controller_spec.rb b/spec/controllers/registrations/experience_levels_controller_spec.rb index 79fa3f1474a..6b8ab3ec715 100644 --- a/spec/controllers/registrations/experience_levels_controller_spec.rb +++ b/spec/controllers/registrations/experience_levels_controller_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Registrations::ExperienceLevelsController do let(:learn_gitlab_available?) { true } before do - allow_next_instance_of(LearnGitlab) do |learn_gitlab| + allow_next_instance_of(LearnGitlab::Project) do |learn_gitlab| allow(learn_gitlab).to receive(:available?).and_return(learn_gitlab_available?) allow(learn_gitlab).to receive(:project).and_return(project) allow(learn_gitlab).to receive(:board).and_return(issues_board) @@ -136,7 +136,7 @@ RSpec.describe Registrations::ExperienceLevelsController do let(:params) { super().merge(experience_level: :novice) } before do - allow_next(LearnGitlab).to receive(:available?).and_return(false) + allow_next(LearnGitlab::Project).to receive(:available?).and_return(false) end it 'does not add a BoardLabel' do diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb index 008259a8bfa..6d34b56df09 100644 --- a/spec/controllers/registrations/welcome_controller_spec.rb +++ b/spec/controllers/registrations/welcome_controller_spec.rb @@ -77,6 +77,30 @@ RSpec.describe Registrations::WelcomeController do it { is_expected.to redirect_to(dashboard_projects_path)} + context 'when the new user already has any accepted group membership' do + let!(:member1) { create(:group_member, user: user) } + + it 'redirects to the group activity page' do + expect(subject).to redirect_to(activity_group_path(member1.source)) + end + + context 'when the new user already has more than 1 accepted group membership' do + it 'redirects to the most recent membership group activty page' do + member2 = create(:group_member, user: user) + + expect(subject).to redirect_to(activity_group_path(member2.source)) + end + end + + context 'when the member has an orphaned source at the time of the welcome' do + it 'redirects to the project dashboard page' do + member1.source.delete + + expect(subject).to redirect_to(dashboard_projects_path) + end + end + end + context 'when the user opted in' do let(:email_opted_in) { '1' } diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index aac7c10d878..ff73c0aafe8 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -20,10 +20,15 @@ RSpec.describe RegistrationsController do end describe '#create' do - let(:base_user_params) { { first_name: 'first', last_name: 'last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } - let(:user_params) { { user: base_user_params } } + let_it_be(:base_user_params) do + { first_name: 'first', last_name: 'last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } + end + + let_it_be(:user_params) { { user: base_user_params } } - subject { post(:create, params: user_params) } + let(:session_params) { {} } + + subject { post(:create, params: user_params, session: session_params) } context '`blocked_pending_approval` state' do context 'when the `require_admin_approval_after_user_signup` setting is turned on' do @@ -148,6 +153,90 @@ RSpec.describe RegistrationsController do expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) expect(controller.current_user).to be_nil end + + context 'when registration is triggered from an accepted invite' do + context 'when it is part of our invite email experiment', :experiment do + let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) } + + let(:originating_member_id) { member.id } + let(:session_params) do + { + invite_email: user_params.dig(:user, :email), + originating_member_id: originating_member_id + } + end + + context 'when member exists from the session key value' do + it 'tracks the experiment' do + expect(experiment('members/invite_email')).to track(:accepted) + .with_context(actor: member) + .on_next_instance + + subject + end + end + + context 'when member does not exist from the session key value' do + let(:originating_member_id) { -1 } + + it 'tracks the experiment' do + expect(experiment('members/invite_email')).not_to track(:accepted) + + subject + end + end + end + + context 'when it is part of our invite_signup_page_interaction experiment', :experiment do + let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) } + + let(:originating_member_id) { member.id } + let(:session_params) do + { + invite_email: user_params.dig(:user, :email), + originating_member_id: originating_member_id + } + end + + context 'when member exists from the session key value' do + it 'tracks the experiment' do + expect(experiment(:invite_signup_page_interaction)).to track(:form_submission) + .with_context(actor: member) + .on_next_instance + + subject + end + end + + context 'when member does not exist from the session key value' do + let(:originating_member_id) { -1 } + + it 'tracks the experiment' do + expect(experiment(:invite_signup_page_interaction)).not_to track(:form_submission) + + subject + end + end + end + + context 'when invite email matches email used on registration' do + let(:session_params) { { invite_email: user_params.dig(:user, :email) } } + + it 'signs the user in without sending a confirmation email', :aggregate_failures do + expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_confirmed + end + end + + context 'when invite email does not match the email used on registration' do + let(:session_params) { { invite_email: 'bogus@email.com' } } + + it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_nil + end + end + end end context 'when soft email confirmation is enabled' do @@ -161,6 +250,24 @@ RSpec.describe RegistrationsController do expect(controller.current_user).to be_present expect(response).to redirect_to(users_sign_up_welcome_path) end + + context 'when invite email matches email used on registration' do + let(:session_params) { { invite_email: user_params.dig(:user, :email) } } + + it 'signs the user in without sending a confirmation email', :aggregate_failures do + expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_confirmed + end + end + + context 'when invite email does not match the email used on registration' do + let(:session_params) { { invite_email: 'bogus@email.com' } } + + it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).not_to be_confirmed + end + end end end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index abdafa2880a..c233e5b7c15 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -85,8 +85,7 @@ RSpec.describe SessionsController do it 'does not authenticate user' do post(:create, params: { user: { login: 'invalid', password: 'invalid' } }) - expect(response) - .to set_flash.now[:alert].to(/Invalid login or password/) + expect(controller).to set_flash.now[:alert].to(/Invalid login or password/) end end @@ -348,7 +347,7 @@ RSpec.describe SessionsController do otp_user_id: user.id ) - expect(response).to set_flash.now[:alert].to(/Invalid login or password/) + expect(controller).to set_flash.now[:alert].to(/Invalid login or password/) end end @@ -396,7 +395,7 @@ RSpec.describe SessionsController do end it 'warns about invalid OTP code' do - expect(response).to set_flash.now[:alert] + expect(controller).to set_flash.now[:alert] .to(/Invalid two-factor code/) end end -- cgit v1.2.1