diff options
Diffstat (limited to 'spec/controllers')
55 files changed, 1226 insertions, 466 deletions
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb index 7b8528009d8..4f223811be8 100644 --- a/spec/controllers/admin/application_settings_controller_spec.rb +++ b/spec/controllers/admin/application_settings_controller_spec.rb @@ -105,22 +105,6 @@ RSpec.describe Admin::ApplicationSettingsController do expect(ApplicationSetting.current.minimum_password_length).to eq(10) end - it 'updates namespace_storage_size_limit setting' do - put :update, params: { application_setting: { namespace_storage_size_limit: '100' } } - - expect(response).to redirect_to(general_admin_application_settings_path) - expect(response).to set_flash[:notice].to('Application settings saved successfully') - expect(ApplicationSetting.current.namespace_storage_size_limit).to eq(100) - end - - it 'does not accept an invalid namespace_storage_size_limit' do - put :update, params: { application_setting: { namespace_storage_size_limit: '-100' } } - - expect(response).to render_template(:general) - expect(assigns(:application_setting).errors[:namespace_storage_size_limit]).to be_present - expect(ApplicationSetting.current.namespace_storage_size_limit).not_to eq(-100) - end - it 'updates repository_storages_weighted setting' do put :update, params: { application_setting: { repository_storages_weighted_default: 75 } } @@ -158,23 +142,12 @@ RSpec.describe Admin::ApplicationSettingsController do end describe 'verify panel actions' do - before do - stub_feature_flags(instance_level_integrations: false) - end - Admin::ApplicationSettingsController::VALID_SETTING_PANELS.each do |valid_action| it_behaves_like 'renders correct panels' do let(:action) { valid_action } end end end - end - - describe 'PATCH #integrations' do - before do - stub_feature_flags(instance_level_integrations: false) - sign_in(admin) - end describe 'EKS integration' do let(:application_setting) { ApplicationSetting.current } @@ -188,7 +161,7 @@ RSpec.describe Admin::ApplicationSettingsController do end it 'updates EKS settings' do - patch :integrations, params: { application_setting: settings_params } + put :update, params: { application_setting: settings_params } expect(application_setting.eks_integration_enabled).to be_truthy expect(application_setting.eks_account_id).to eq '123456789012' @@ -202,7 +175,7 @@ RSpec.describe Admin::ApplicationSettingsController do it 'does not update the secret key' do application_setting.update!(eks_secret_access_key: 'dummy secret key') - patch :integrations, params: { application_setting: settings_params } + put :update, params: { application_setting: settings_params } expect(application_setting.reload.eks_secret_access_key).to eq 'dummy secret key' end diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb index 7e7b60db2dc..4a5d5ede728 100644 --- a/spec/controllers/admin/integrations_controller_spec.rb +++ b/spec/controllers/admin/integrations_controller_spec.rb @@ -10,16 +10,6 @@ RSpec.describe Admin::IntegrationsController do end describe '#edit' do - context 'when instance_level_integrations not enabled' do - it 'returns not_found' do - stub_feature_flags(instance_level_integrations: false) - - get :edit, params: { id: Service.available_services_names.sample } - - expect(response).to have_gitlab_http_status(:not_found) - end - end - Service.available_services_names.each do |integration_name| context "#{integration_name}" do it 'successfully displays the template' do diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index aec629ba330..357044a144c 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -190,20 +190,10 @@ RSpec.describe ApplicationController do expect(response).to redirect_to new_user_session_path end - context 'request format is unknown' do - it 'redirects if unauthenticated' do - get :index, format: 'unknown' + it 'redirects if unauthenticated and request format is unknown' do + get :index, format: 'unknown' - expect(response).to redirect_to new_user_session_path - end - - it 'returns a 401 if the feature flag is disabled' do - stub_feature_flags(devise_redirect_unknown_formats: false) - - get :index, format: 'unknown' - - expect(response).to have_gitlab_http_status(:unauthorized) - end + expect(response).to redirect_to new_user_session_path end end diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index 601b8d427e0..a7f3ab0089f 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -265,6 +265,7 @@ RSpec.describe Boards::IssuesController do hash[:ids] = [issue2.id] end end + let(:requesting_user) { user } let(:expected_status) { 200 } let(:expected_issue_count) { 2 } @@ -280,6 +281,7 @@ RSpec.describe Boards::IssuesController do hash[:ids] = [issue2.id] end end + let(:requesting_user) { user } let(:expected_status) { 403 } let(:expected_issue_count) { 1 } @@ -296,6 +298,7 @@ RSpec.describe Boards::IssuesController do hash[:move_before_id] = nil end end + let(:requesting_user) { user } let(:expected_status) { 200 } let(:expected_issue_count) { 4 } @@ -317,6 +320,7 @@ RSpec.describe Boards::IssuesController do hash[:move_before_id] = nil end end + let(:requesting_user) { user } let(:expected_status) { 200 } let(:expected_issue_count) { 3 } @@ -332,6 +336,7 @@ RSpec.describe Boards::IssuesController do hash[:move_before_id] = nil end end + let(:requesting_user) { user } let(:expected_status) { 200 } let(:expected_issue_count) { 4 } @@ -350,6 +355,7 @@ RSpec.describe Boards::IssuesController do hash[:move_after_id] = issue4.id end end + let(:requesting_user) { user } let(:expected_status) { 200 } let(:expected_issue_count) { 5 } @@ -365,6 +371,7 @@ RSpec.describe Boards::IssuesController do hash[:ids] = (0..51).to_a end end + let(:requesting_user) { user } let(:expected_status) { 422 } let(:expected_issue_count) { 1 } @@ -380,6 +387,7 @@ RSpec.describe Boards::IssuesController do hash[:ids] = 'foobar' end end + let(:requesting_user) { user } let(:expected_status) { 400 } let(:expected_issue_count) { 1 } diff --git a/spec/controllers/concerns/checks_collaboration_spec.rb b/spec/controllers/concerns/checks_collaboration_spec.rb index be8beff5dd6..7fcd190d71a 100644 --- a/spec/controllers/concerns/checks_collaboration_spec.rb +++ b/spec/controllers/concerns/checks_collaboration_spec.rb @@ -33,7 +33,7 @@ RSpec.describe ChecksCollaboration do it 'is true when the user can push to a branch of the project' do fake_access = double('Gitlab::UserAccess') expect(fake_access).to receive(:can_push_to_branch?).with('a-branch').and_return(true) - expect(Gitlab::UserAccess).to receive(:new).with(user, project: project).and_return(fake_access) + expect(Gitlab::UserAccess).to receive(:new).with(user, container: project).and_return(fake_access) expect(helper.can_collaborate_with_project?(project, ref: 'a-branch')).to be_truthy end diff --git a/spec/controllers/concerns/graceful_timeout_handling_spec.rb b/spec/controllers/concerns/graceful_timeout_handling_spec.rb new file mode 100644 index 00000000000..cece36f06b2 --- /dev/null +++ b/spec/controllers/concerns/graceful_timeout_handling_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GracefulTimeoutHandling, type: :controller do + controller(ApplicationController) do + include GracefulTimeoutHandling + + skip_before_action :authenticate_user! + + def index + raise ActiveRecord::QueryCanceled.new + end + end + + context 'for json request' do + subject { get :index, format: :json } + + it 'renders graceful error message' do + subject + + expect(json_response['error']).to eq(_('There is too much data to calculate. Please change your selection.')) + expect(response.code).to eq '200' + end + + it 'logs exception' do + expect(Gitlab::ErrorTracking).to receive(:track_exception).with(kind_of(ActiveRecord::QueryCanceled)) + + subject + end + end + + context 'for html request' do + subject { get :index, format: :html } + + it 'has no effect' do + expect do + subject + end.to raise_error(ActiveRecord::QueryCanceled) + end + end +end diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index f0c9874965e..8a4d8828aaa 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -165,13 +165,14 @@ RSpec.describe MetricsDashboard do it 'adds starred dashboard information and sorts the list' do all_dashboards = json_response['all_dashboards'].map { |dashboard| dashboard.slice('display_name', 'starred', 'user_starred_path') } expected_response = [ - { "display_name" => "Default dashboard", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/common_metrics.yml' }) }, { "display_name" => "anomaly.yml", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/anomaly.yml' }) }, { "display_name" => "errors.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/errors.yml' }) }, + { "display_name" => "K8s pod health", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/pod_metrics.yml' }) }, + { "display_name" => "Overview", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/common_metrics.yml' }) }, { "display_name" => "test.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/test.yml' }) } ] - expect(all_dashboards).to eql expected_response + expect(all_dashboards).to eq(expected_response) end end end diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb index 7cfaf1b248f..e24e4cbf5e7 100644 --- a/spec/controllers/concerns/send_file_upload_spec.rb +++ b/spec/controllers/concerns/send_file_upload_spec.rb @@ -21,6 +21,12 @@ RSpec.describe SendFileUpload do let(:controller_class) do Class.new do include SendFileUpload + + def params + {} + end + + def current_user; end end end @@ -42,6 +48,89 @@ RSpec.describe SendFileUpload do FileUtils.rm_f(temp_file) end + shared_examples 'handles image resize requests' do + let(:headers) { double } + + before do + allow(uploader).to receive(:image?).and_return(true) + allow(uploader).to receive(:mounted_as).and_return(:avatar) + + allow(controller).to receive(:headers).and_return(headers) + # both of these are valid cases, depending on whether we are dealing with + # local or remote files + allow(controller).to receive(:send_file) + allow(controller).to receive(:redirect_to) + end + + context 'when feature is enabled for current user' do + let(:user) { build(:user) } + + before do + stub_feature_flags(dynamic_image_resizing: user) + allow(controller).to receive(:current_user).and_return(user) + end + + context 'with valid width parameter' do + it 'renders OK with workhorse command header' do + expect(controller).not_to receive(:send_file) + expect(controller).to receive(:params).at_least(:once).and_return(width: '64') + expect(controller).to receive(:head).with(:ok) + expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + + context 'with missing width parameter' do + it 'does not write workhorse command header' do + expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + + context 'with invalid width parameter' do + it 'does not write workhorse command header' do + expect(controller).to receive(:params).at_least(:once).and_return(width: 'not a number') + expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + + context 'with width that is not allowed' do + it 'does not write workhorse command header' do + expect(controller).to receive(:params).at_least(:once).and_return(width: '63') + expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + + context 'when image file is not an avatar' do + it 'does not write workhorse command header' do + expect(uploader).to receive(:mounted_as).and_return(nil) # FileUploader is not mounted + expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + end + + context 'when feature is disabled' do + before do + stub_feature_flags(dynamic_image_resizing: false) + end + + it 'does not write workhorse command header' do + expect(controller).to receive(:params).at_least(:once).and_return(width: '64') + expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) + + subject + end + end + end + context 'when local file is used' do before do uploader.store!(temp_file) @@ -52,6 +141,8 @@ RSpec.describe SendFileUpload do subject end + + it_behaves_like 'handles image resize requests' end context 'with inline image' do @@ -155,6 +246,8 @@ RSpec.describe SendFileUpload do it_behaves_like 'proxied file' end end + + it_behaves_like 'handles image resize requests' end end end diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index 2e3328ae4d2..f0aa351bee0 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -42,15 +42,6 @@ RSpec.describe Dashboard::TodosController do expect(response).to have_gitlab_http_status(:ok) end - - context 'tracking visits' do - let_it_be(:authorized_project) { create(:project, :public) } - - it_behaves_like 'tracking unique visits', :index do - let(:request_params) { { project_id: authorized_project.id } } - let(:target_id) { 'u_analytics_todos' } - end - end end context "with render_views" do diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index fd86501ff5d..4ec890a528f 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -138,6 +138,33 @@ RSpec.describe Explore::ProjectsController do end end + shared_examples 'avoids N+1 queries' do + [:index, :trending, :starred].each do |endpoint| + describe "GET #{endpoint}" do + render_views + + # some N+1 queries still exist + it 'avoids N+1 queries' do + projects = create_list(:project, 3, :repository, :public) + projects.each do |project| + pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) + create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + end + + control = ActiveRecord::QueryRecorder.new { get endpoint } + + new_projects = create_list(:project, 2, :repository, :public) + new_projects.each do |project| + pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) + create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + end + + expect { get endpoint }.not_to exceed_query_limit(control).with_threshold(8) + end + end + end + end + context 'when user is signed in' do let(:user) { create(:user) } @@ -147,6 +174,7 @@ RSpec.describe Explore::ProjectsController do include_examples 'explore projects' include_examples "blocks high page numbers" + include_examples 'avoids N+1 queries' context 'user preference sorting' do let(:project) { create(:project) } @@ -160,6 +188,7 @@ RSpec.describe Explore::ProjectsController do context 'when user is not signed in' do include_examples 'explore projects' include_examples "blocks high page numbers" + include_examples 'avoids N+1 queries' context 'user preference sorting' do let(:project) { create(:project) } diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index e47bb75af22..5c7b88a218a 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -86,6 +86,7 @@ RSpec.describe Groups::MilestonesController do let!(:public_project_with_private_issues_and_mrs) do create(:project, :public, :issues_private, :merge_requests_private, group: public_group) end + let!(:private_milestone) { create(:milestone, project: public_project_with_private_issues_and_mrs, title: 'project milestone') } context 'when anonymous user' do diff --git a/spec/controllers/groups/releases_controller_spec.rb b/spec/controllers/groups/releases_controller_spec.rb new file mode 100644 index 00000000000..0925548f60a --- /dev/null +++ b/spec/controllers/groups/releases_controller_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Groups::ReleasesController do + let(:group) { create(:group) } + let!(:project) { create(:project, :repository, :public, namespace: group) } + let!(:private_project) { create(:project, :repository, :private, namespace: group) } + let(:developer) { create(:user) } + let!(:release_1) { create(:release, project: project, tag: 'v1', released_at: Time.zone.parse('2020-02-15')) } + let!(:release_2) { create(:release, project: project, tag: 'v2', released_at: Time.zone.parse('2020-02-20')) } + let!(:private_release_1) { create(:release, project: private_project, tag: 'p1', released_at: Time.zone.parse('2020-03-01')) } + let!(:private_release_2) { create(:release, project: private_project, tag: 'p2', released_at: Time.zone.parse('2020-03-05')) } + + before do + private_project.add_developer(developer) + end + + describe 'GET #index' do + context 'as json' do + let(:format) { :json } + + subject { get :index, params: { group_id: group }, format: format } + + context 'json_response' do + before do + subject + end + + it 'returns an application/json content_type' do + expect(response.content_type).to eq 'application/json' + end + + it 'returns OK' do + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'the user is not authorized' do + before do + subject + end + + it 'does not return any releases' do + expect(json_response.map {|r| r['tag'] } ).to match_array(%w(v2 v1)) + end + + it 'returns OK' do + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'the user is authorized' do + it "returns all group's public and private project's releases as JSON, ordered by released_at" do + sign_in(developer) + + subject + + expect(json_response.map {|r| r['tag'] } ).to match_array(%w(p2 p1 v2 v1)) + end + end + + context 'N+1 queries' do + it 'avoids N+1 database queries' do + control_count = ActiveRecord::QueryRecorder.new { subject }.count + + create_list(:release, 5, project: project) + create_list(:release, 5, project: private_project) + + expect { subject }.not_to exceed_query_limit(control_count) + end + end + end + end +end diff --git a/spec/controllers/groups/settings/repository_controller_spec.rb b/spec/controllers/groups/settings/repository_controller_spec.rb index 6d0caf6d655..14bbdc05282 100644 --- a/spec/controllers/groups/settings/repository_controller_spec.rb +++ b/spec/controllers/groups/settings/repository_controller_spec.rb @@ -36,6 +36,7 @@ RSpec.describe Groups::Settings::RepositoryController do deploy_token_type: DeployToken.deploy_token_types[:group_type] } end + let(:request_params) do { group_id: group.to_param, @@ -60,7 +61,7 @@ RSpec.describe Groups::Settings::RepositoryController do 'token' => be_a(String), 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv - key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes + key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes end } end diff --git a/spec/controllers/groups/shared_projects_controller_spec.rb b/spec/controllers/groups/shared_projects_controller_spec.rb index dafce094b14..528d5c073b7 100644 --- a/spec/controllers/groups/shared_projects_controller_spec.rb +++ b/spec/controllers/groups/shared_projects_controller_spec.rb @@ -17,9 +17,9 @@ RSpec.describe Groups::SharedProjectsController do ).execute(group) end - let_it_be(:group) { create(:group) } - let_it_be(:user) { create(:user) } - let_it_be(:shared_project) do + let!(:group) { create(:group) } + let!(:user) { create(:user) } + let!(:shared_project) do shared_project = create(:project, namespace: user.namespace) share_project(shared_project) diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 6c0b3efa53b..3049396dd0f 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -159,15 +159,6 @@ RSpec.describe HelpController do end end - describe 'GET #ui' do - context 'for UI Development Kit' do - it 'renders found' do - get :ui - expect(response).to have_gitlab_http_status(:ok) - end - end - end - def stub_readme(content) expect(File).to receive(:read).and_return(content) end diff --git a/spec/controllers/import/available_namespaces_controller_spec.rb b/spec/controllers/import/available_namespaces_controller_spec.rb new file mode 100644 index 00000000000..ebccc862a13 --- /dev/null +++ b/spec/controllers/import/available_namespaces_controller_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Import::AvailableNamespacesController do + let_it_be(:user) { create(:user) } + let_it_be(:manageable_groups) { [create(:group), create(:group)] } + + before do + sign_in(user) + manageable_groups.each { |group| group.add_maintainer(user) } + end + + describe "GET index" do + it "returns list of available namespaces" do + unrelated_group = create(:group) + + get :index + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_kind_of(Array) + + response_ids = json_response.map { |n| n["id"] } + + expect(response_ids).not_to include(unrelated_group.id) + expect(response_ids).to contain_exactly(*manageable_groups.map(&:id)) + end + + context "with an anonymous user" do + before do + sign_out(user) + end + + it "redirects to sign-in page" do + get :index + + expect(response).to redirect_to(new_user_session_path) + end + end + end +end diff --git a/spec/controllers/import/bitbucket_server_controller_spec.rb b/spec/controllers/import/bitbucket_server_controller_spec.rb index bb80de6425f..d5f94be65b6 100644 --- a/spec/controllers/import/bitbucket_server_controller_spec.rb +++ b/spec/controllers/import/bitbucket_server_controller_spec.rb @@ -139,8 +139,6 @@ RSpec.describe Import::BitbucketServerController do describe 'GET status' do render_views - let(:repos) { instance_double(BitbucketServer::Collection) } - before do allow(controller).to receive(:client).and_return(client) @@ -157,14 +155,14 @@ RSpec.describe Import::BitbucketServerController do expect(response).to have_gitlab_http_status(:ok) expect(json_response['incompatible_repos'].length).to eq(1) - expect(json_response.dig("incompatible_repos", 0, "id")).to eq(@invalid_repo.full_name) + expect(json_response.dig("incompatible_repos", 0, "id")).to eq("#{@invalid_repo.project_key}/#{@invalid_repo.slug}") expect(json_response['provider_repos'].length).to eq(1) expect(json_response.dig("provider_repos", 0, "id")).to eq(@repo.full_name) end it_behaves_like 'import controller status' do let(:repo) { @repo } - let(:repo_id) { @repo.full_name } + let(:repo_id) { "#{@repo.project_key}/#{@repo.slug}" } let(:import_source) { @repo.browse_url } let(:provider_name) { 'bitbucket_server' } let(:client_repos_field) { :repos } diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb index 9001faef408..3e4b159271a 100644 --- a/spec/controllers/import/gitea_controller_spec.rb +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -34,6 +34,14 @@ RSpec.describe Import::GiteaController do assign_host_url end + it "requests provider repos list" do + expect(stub_client(repos: [], orgs: [])).to receive(:repos) + + get :status + + expect(response).to have_gitlab_http_status(:ok) + end + context 'when host url is local or not http' do %w[https://localhost:3000 http://192.168.0.1 ftp://testing].each do |url| let(:host_url) { url } diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index a5a3dc463d3..e19b6caca5b 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -15,10 +15,7 @@ RSpec.describe Import::GithubController do it "redirects to GitHub for an access token if logged in with GitHub" do allow(controller).to receive(:logged_in_with_provider?).and_return(true) expect(controller).to receive(:go_to_provider_for_permissions).and_call_original - allow_any_instance_of(Gitlab::LegacyGithubImport::Client) - .to receive(:authorize_url) - .with(users_import_github_callback_url) - .and_call_original + allow(controller).to receive(:authorize_url).and_call_original get :new @@ -46,13 +43,15 @@ RSpec.describe Import::GithubController do end describe "GET callback" do + before do + allow(controller).to receive(:get_token).and_return(token) + allow(controller).to receive(:oauth_options).and_return({}) + + stub_omniauth_provider('github') + end + it "updates access token" do token = "asdasd12345" - allow_any_instance_of(Gitlab::LegacyGithubImport::Client) - .to receive(:get_token).and_return(token) - allow_any_instance_of(Gitlab::LegacyGithubImport::Client) - .to receive(:github_options).and_return({}) - stub_omniauth_provider('github') get :callback @@ -66,7 +65,86 @@ RSpec.describe Import::GithubController do end describe "GET status" do - it_behaves_like 'a GitHub-ish import controller: GET status' + context 'when using OAuth' do + before do + allow(controller).to receive(:logged_in_with_provider?).and_return(true) + end + + context 'when OAuth config is missing' do + let(:new_import_url) { public_send("new_import_#{provider}_url") } + + before do + allow(controller).to receive(:oauth_config).and_return(nil) + end + + it 'returns missing config error' do + expect(controller).to receive(:go_to_provider_for_permissions).and_call_original + + get :status + + expect(session[:"#{provider}_access_token"]).to be_nil + expect(controller).to redirect_to(new_import_url) + expect(flash[:alert]).to eq('Missing OAuth configuration for GitHub.') + end + end + end + + context 'when feature remove_legacy_github_client is disabled' do + before do + stub_feature_flags(remove_legacy_github_client: false) + session[:"#{provider}_access_token"] = 'asdasd12345' + end + + it_behaves_like 'a GitHub-ish import controller: GET status' + + it 'uses Gitlab::LegacyGitHubImport::Client' do + expect(controller.send(:client)).to be_instance_of(Gitlab::LegacyGithubImport::Client) + end + + it 'fetches repos using legacy client' do + expect_next_instance_of(Gitlab::LegacyGithubImport::Client) do |client| + expect(client).to receive(:repos) + end + + get :status + end + end + + context 'when feature remove_legacy_github_client is enabled' do + before do + stub_feature_flags(remove_legacy_github_client: true) + session[:"#{provider}_access_token"] = 'asdasd12345' + end + + it_behaves_like 'a GitHub-ish import controller: GET status' + + it 'uses Gitlab::GithubImport::Client' do + expect(controller.send(:client)).to be_instance_of(Gitlab::GithubImport::Client) + end + + it 'fetches repos using latest github client' do + expect_next_instance_of(Gitlab::GithubImport::Client) do |client| + expect(client).to receive(:each_page).with(:repos).and_return([].to_enum) + end + + get :status + end + + it 'concatenates list of repos from multiple pages' do + repo_1 = OpenStruct.new(login: 'emacs', full_name: 'asd/emacs', name: 'emacs', owner: { login: 'owner' }) + repo_2 = OpenStruct.new(login: 'vim', full_name: 'asd/vim', name: 'vim', owner: { login: 'owner' }) + repos = [OpenStruct.new(objects: [repo_1]), OpenStruct.new(objects: [repo_2])].to_enum + + allow(stub_client).to receive(:each_page).and_return(repos) + + get :status, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.dig('provider_repos').count).to eq(2) + expect(json_response.dig('provider_repos', 0, 'id')).to eq(repo_1.id) + expect(json_response.dig('provider_repos', 1, 'id')).to eq(repo_2.id) + end + end end describe "POST create" do diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb index 42c4348dac2..826625ba9c3 100644 --- a/spec/controllers/import/gitlab_controller_spec.rb +++ b/spec/controllers/import/gitlab_controller_spec.rb @@ -53,6 +53,7 @@ RSpec.describe Import::GitlabController do let(:gitlab_user) do { username: gitlab_username }.with_indifferent_access end + let(:gitlab_repo) do { path: 'vim', diff --git a/spec/controllers/import/manifest_controller_spec.rb b/spec/controllers/import/manifest_controller_spec.rb new file mode 100644 index 00000000000..ec8bd45b65c --- /dev/null +++ b/spec/controllers/import/manifest_controller_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Import::ManifestController do + include ImportSpecHelper + + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group)} + + before(:all) do + group.add_maintainer(user) + end + + before do + sign_in(user) + end + + def assign_session_group + session[:manifest_import_repositories] = [] + session[:manifest_import_group_id] = group.id + end + + describe 'GET status' do + let(:repo1) { OpenStruct.new(id: 'test1', url: 'http://demo.host/test1') } + let(:repo2) { OpenStruct.new(id: 'test2', url: 'http://demo.host/test2') } + let(:repos) { [repo1, repo2] } + + before do + assign_session_group + + session[:manifest_import_repositories] = repos + end + + it "returns variables for json request" do + project = create(:project, import_type: 'manifest', creator_id: user.id) + + get :status, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) + expect(json_response.dig("provider_repos", 0, "id")).to eq(repo1.id) + expect(json_response.dig("provider_repos", 1, "id")).to eq(repo2.id) + expect(json_response.dig("namespaces", 0, "id")).to eq(group.id) + end + + it "does not show already added project" do + project = create(:project, import_type: 'manifest', namespace: user.namespace, import_status: :finished, import_url: repo1.url) + + get :status, format: :json + + expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) + expect(json_response.dig("provider_repos").length).to eq(1) + expect(json_response.dig("provider_repos", 0, "id")).not_to eq(repo1.id) + end + end +end diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index a9e4073780d..2b222331b55 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -34,25 +34,4 @@ RSpec.describe InvitesController do expect(flash[:notice]).to be_nil end end - - describe 'POST #accept' do - it 'accepts user' do - expect do - post :accept, params: { id: token } - end.to change { project_members.include?(user) }.from(false).to(true) - - expect(response).to have_gitlab_http_status(:found) - expect(flash[:notice]).to include 'You have been granted' - end - end - - describe 'GET #decline' do - it 'declines user' do - get :decline, params: { id: token } - - expect { member.reload }.to raise_error ActiveRecord::RecordNotFound - expect(response).to have_gitlab_http_status(:found) - expect(flash[:notice]).to include 'You have declined the invitation to join' - end - end end diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index 0b99f28f79b..dce996b977d 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -181,6 +181,23 @@ RSpec.describe OmniauthCallbacksController, type: :controller do end end + context 'when user with 2FA is unconfirmed' do + render_views + + let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider) } + + before do + user.update_column(:confirmed_at, nil) + end + + it 'redirects to login page' do + post provider + + expect(response).to redirect_to(new_user_session_path) + expect(flash[:alert]).to match(/You have to confirm your email address before continuing./) + end + end + context 'sign up' do include_context 'sign_up' diff --git a/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb index 252ad6ec9c4..594c24bb7e3 100644 --- a/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb +++ b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb @@ -149,8 +149,4 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do date: date ) end - - def csv_response - CSV.parse(response.body) - end end diff --git a/spec/controllers/projects/ci/lints_controller_spec.rb b/spec/controllers/projects/ci/lints_controller_spec.rb index eb92385fc83..b3e08292546 100644 --- a/spec/controllers/projects/ci/lints_controller_spec.rb +++ b/spec/controllers/projects/ci/lints_controller_spec.rb @@ -45,6 +45,9 @@ RSpec.describe Projects::Ci::LintsController do end describe 'POST #create' do + subject { post :create, params: params } + + let(:params) { { namespace_id: project.namespace, project_id: project, content: content } } let(:remote_file_path) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } let(:remote_file_content) do @@ -72,18 +75,62 @@ RSpec.describe Projects::Ci::LintsController do before do stub_full_request(remote_file_path).to_return(body: remote_file_content) project.add_developer(user) + end - post :create, params: { namespace_id: project.namespace, project_id: project, content: content } + shared_examples 'returns a successful validation' do + it 'returns successfully' do + subject + expect(response).to be_successful + end + + it 'render show page' do + subject + expect(response).to render_template :show + end + + it 'retrieves project' do + subject + expect(assigns(:project)).to eq(project) + end end - it { expect(response).to be_successful } + context 'using legacy validation (YamlProcessor)' do + it_behaves_like 'returns a successful validation' - it 'render show page' do - expect(response).to render_template :show + it 'runs validations through YamlProcessor' do + expect(Gitlab::Ci::YamlProcessor).to receive(:new_with_validation_errors).and_call_original + + subject + end end - it 'retrieves project' do - expect(assigns(:project)).to eq(project) + context 'using dry_run mode' do + subject { post :create, params: params.merge(dry_run: 'true') } + + it_behaves_like 'returns a successful validation' + + it 'runs validations through Ci::CreatePipelineService' do + expect(Ci::CreatePipelineService) + .to receive(:new) + .with(project, user, ref: 'master') + .and_call_original + + subject + end + + context 'when dry_run feature flag is disabled' do + before do + stub_feature_flags(ci_lint_creates_pipeline_with_dry_run: false) + end + + it_behaves_like 'returns a successful validation' + + it 'runs validations through YamlProcessor' do + expect(Gitlab::Ci::YamlProcessor).to receive(:new_with_validation_errors).and_call_original + + subject + end + end end end @@ -98,13 +145,23 @@ RSpec.describe Projects::Ci::LintsController do before do project.add_developer(user) - - post :create, params: { namespace_id: project.namespace, project_id: project, content: content } end it 'assigns errors' do + subject + expect(assigns[:errors]).to eq(['root config contains unknown keys: rubocop']) end + + context 'with dry_run mode' do + subject { post :create, params: params.merge(dry_run: 'true') } + + it 'assigns errors' do + subject + + expect(assigns[:errors]).to eq(['root config contains unknown keys: rubocop']) + end + end end context 'without enough privileges' do diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb index 408ce51d34b..c5b72ff2b3b 100644 --- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb @@ -57,6 +57,8 @@ RSpec.describe Projects::CycleAnalytics::EventsController do end end + include_examples GracefulTimeoutHandling + def get_issue(additional_params: {}) params = additional_params.merge(namespace_id: project.namespace, project_id: project) get(:issue, params: params, format: :json) diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index ec853b74b9b..e956065972f 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -67,4 +67,6 @@ RSpec.describe Projects::CycleAnalyticsController do end end end + + include_examples GracefulTimeoutHandling end diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 85ec1f7396d..d1142cbd129 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -348,34 +348,10 @@ RSpec.describe Projects::EnvironmentsController do end describe 'GET #metrics_redirect' do - it 'redirects to environment if it exists' do + it 'redirects to metrics dashboard page' do get :metrics_redirect, params: { namespace_id: project.namespace, project_id: project } - expect(response).to redirect_to(environment_metrics_path(environment)) - end - - context 'with anonymous user and public dashboard visibility' do - let(:project) { create(:project, :public) } - let(:user) { create(:user) } - - it 'redirects successfully' do - project.project_feature.update!(metrics_dashboard_access_level: ProjectFeature::ENABLED) - - get :metrics_redirect, params: { namespace_id: project.namespace, project_id: project } - - expect(response).to redirect_to(environment_metrics_path(environment)) - end - end - - context 'when there are no environments' do - let(:environment) { } - - it 'redirects to empty metrics page' do - get :metrics_redirect, params: { namespace_id: project.namespace, project_id: project } - - expect(response).to be_ok - expect(response).to render_template 'empty_metrics' - end + expect(response).to redirect_to(project_metrics_dashboard_path(project)) end end @@ -385,12 +361,12 @@ RSpec.describe Projects::EnvironmentsController do end context 'when environment has no metrics' do - it 'returns a metrics page' do + it 'redirects to metrics dashboard page' do expect(environment).not_to receive(:metrics) get :metrics, params: environment_params - expect(response).to be_ok + expect(response).to redirect_to(project_metrics_dashboard_path(project, environment: environment)) end context 'when requesting metrics as JSON' do @@ -440,12 +416,12 @@ RSpec.describe Projects::EnvironmentsController do let(:project) { create(:project, :public) } let(:user) { create(:user) } - it 'returns success' do + it 'redirects to metrics dashboard page' do project.project_feature.update!(metrics_dashboard_access_level: ProjectFeature::ENABLED) get :metrics, params: environment_params - expect(response).to have_gitlab_http_status(:ok) + expect(response).to redirect_to(project_metrics_dashboard_path(project, environment: environment)) end end end diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index 4c0fd7b8954..e8b30294cdd 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -162,9 +162,25 @@ RSpec.describe Projects::ForksController do end context 'when user is signed in' do - it 'responds with status 200' do + before do sign_in(user) + end + + context 'when JSON requested' do + it 'responds with available groups' do + get :new, + format: :json, + params: { + namespace_id: project.namespace, + project_id: project + } + + expect(json_response['namespaces'].length).to eq(1) + expect(json_response['namespaces'].first['id']).to eq(group.id) + end + end + it 'responds with status 200' do subject expect(response).to have_gitlab_http_status(:ok) @@ -229,6 +245,7 @@ RSpec.describe Projects::ForksController do continue: continue_params } end + let(:continue_params) do { to: '/-/ide/project/path', diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index 440e6b2a74c..85d036486ee 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -36,7 +36,8 @@ RSpec.describe Projects::HooksController do note_events: true, job_events: true, pipeline_events: true, - wiki_page_events: true + wiki_page_events: true, + deployment_events: true } post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params } diff --git a/spec/controllers/projects/incidents_controller_spec.rb b/spec/controllers/projects/incidents_controller_spec.rb new file mode 100644 index 00000000000..2baae0661cb --- /dev/null +++ b/spec/controllers/projects/incidents_controller_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::IncidentsController do + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user) } + let_it_be(:guest) { create(:user) } + + before_all do + project.add_developer(developer) + project.add_guest(guest) + end + + describe 'GET #index' do + def make_request + get :index, params: { namespace_id: project.namespace, project_id: project } + end + + it 'shows the page for user with developer role' do + sign_in(developer) + make_request + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:index) + end + + context 'when user is unauthorized' do + it 'redirects to the login page' do + sign_out(developer) + make_request + + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'when user is a guest' do + it 'shows 404' do + sign_in(guest) + make_request + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index f9580c79390..a0e478ef368 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -181,10 +181,11 @@ RSpec.describe Projects::IssuesController do project.add_developer(user) end - it 'builds a new issue' do + it 'builds a new issue', :aggregate_failures do get :new, params: { namespace_id: project.namespace, project_id: project } expect(assigns(:issue)).to be_a_new(Issue) + expect(assigns(:issue).issue_type).to eq('issue') end where(:conf_value, :conf_result) do @@ -214,6 +215,24 @@ RSpec.describe Projects::IssuesController do end end + context 'setting issue type' do + let(:issue_type) { 'issue' } + + before do + get :new, params: { namespace_id: project.namespace, project_id: project, issue: { issue_type: issue_type } } + end + + subject { assigns(:issue).issue_type } + + it { is_expected.to eq('issue') } + + context 'incident issue' do + let(:issue_type) { 'incident' } + + it { is_expected.to eq(issue_type) } + end + end + it 'fills in an issue for a merge request' do project_with_repository = create(:project, :repository) project_with_repository.add_developer(user) @@ -964,6 +983,33 @@ RSpec.describe Projects::IssuesController do expect { issue.update(description: [issue.description, labels].join(' ')) } .not_to exceed_query_limit(control_count + 2 * labels.count) end + + context 'real-time sidebar feature flag' do + using RSpec::Parameterized::TableSyntax + + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + + where(:action_cable_in_app_enabled, :feature_flag_enabled, :gon_feature_flag) do + true | true | true + true | false | true + false | true | true + false | false | false + end + + with_them do + before do + expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(action_cable_in_app_enabled) + stub_feature_flags(real_time_issue_sidebar: feature_flag_enabled) + end + + it 'broadcasts to the issues channel based on ActionCable and feature flag values' do + go(id: issue.to_param) + + expect(Gon.features).to include('realTimeIssueSidebar' => gon_feature_flag) + end + end + end end describe 'GET #realtime_changes' do @@ -1022,6 +1068,14 @@ RSpec.describe Projects::IssuesController do project.issues.first end + it 'creates the issue successfully', :aggregate_failures do + issue = post_new_issue + + expect(issue).to be_a(Issue) + expect(issue.persisted?).to eq(true) + expect(issue.issue_type).to eq('issue') + end + context 'resolving discussions in MergeRequest' do let(:discussion) { create(:diff_note_on_merge_request).to_discussion } let(:merge_request) { discussion.noteable } @@ -1262,6 +1316,20 @@ RSpec.describe Projects::IssuesController do end end end + + context 'setting issue type' do + let(:issue_type) { 'issue' } + + subject { post_new_issue(issue_type: issue_type)&.issue_type } + + it { is_expected.to eq('issue') } + + context 'incident issue' do + let(:issue_type) { 'incident' } + + it { is_expected.to eq(issue_type) } + end + end end describe 'POST #mark_as_spam' do diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb index 0f34e536064..d5c602df41d 100644 --- a/spec/controllers/projects/logs_controller_spec.rb +++ b/spec/controllers/projects/logs_controller_spec.rb @@ -22,8 +22,8 @@ RSpec.describe Projects::LogsController do describe 'GET #index' do let(:empty_project) { create(:project) } - it 'returns 404 with developer access' do - project.add_developer(user) + it 'returns 404 with reporter access' do + project.add_reporter(user) get :index, params: environment_params @@ -31,7 +31,7 @@ RSpec.describe Projects::LogsController do end it 'renders empty logs page if no environment exists' do - empty_project.add_maintainer(user) + empty_project.add_developer(user) get :index, params: { namespace_id: empty_project.namespace, project_id: empty_project } @@ -40,7 +40,7 @@ RSpec.describe Projects::LogsController do end it 'renders index template' do - project.add_maintainer(user) + project.add_developer(user) get :index, params: environment_params @@ -59,6 +59,7 @@ RSpec.describe Projects::LogsController do container_name: container } end + let(:service_result_json) { Gitlab::Json.parse(service_result.to_json) } let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*', projects: [project]) } @@ -69,14 +70,27 @@ RSpec.describe Projects::LogsController do end end - it 'returns 404 with developer access' do - project.add_developer(user) + it 'returns 404 with reporter access' do + project.add_reporter(user) get endpoint, params: environment_params(pod_name: pod_name, format: :json) expect(response).to have_gitlab_http_status(:not_found) end + context 'with developer access' do + before do + project.add_developer(user) + end + + it 'returns the service result' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) + + expect(response).to have_gitlab_http_status(:success) + expect(json_response).to eq(service_result_json) + end + end + context 'with maintainer access' do before do project.add_maintainer(user) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 4327e0bbb7a..8e1b250cd3c 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -334,7 +334,7 @@ RSpec.describe Projects::MergeRequestsController do it 'closes MR without errors' do update_merge_request(state_event: 'close') - expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request]) + expect(response).to redirect_to([merge_request.target_project, merge_request]) expect(merge_request.reload.closed?).to be_truthy end @@ -343,7 +343,7 @@ RSpec.describe Projects::MergeRequestsController do update_merge_request(title: 'New title') - expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request]) + expect(response).to redirect_to([merge_request.target_project, merge_request]) expect(merge_request.reload.title).to eq 'New title' end diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 9728fad417e..570d65dba4f 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -302,6 +302,7 @@ RSpec.describe Projects::NotesController do target_id: merge_request.id }.merge(extra_request_params) end + let(:extra_request_params) { {} } let(:project_visibility) { Gitlab::VisibilityLevel::PUBLIC } diff --git a/spec/controllers/projects/pipelines/tests_controller_spec.rb b/spec/controllers/projects/pipelines/tests_controller_spec.rb index e2abd1238c5..61118487e20 100644 --- a/spec/controllers/projects/pipelines/tests_controller_spec.rb +++ b/spec/controllers/projects/pipelines/tests_controller_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Projects::Pipelines::TestsController do get_tests_summary_json expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(2) + expect(json_response.dig('total', 'count')).to eq(2) end end @@ -28,20 +28,7 @@ RSpec.describe Projects::Pipelines::TestsController do get_tests_summary_json expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end - end - - context 'when feature is disabled' do - before do - stub_feature_flags(build_report_summary: false) - end - - it 'returns 404' do - get_tests_summary_json - - expect(response).to have_gitlab_http_status(:not_found) - expect(response.body).to be_empty + expect(json_response.dig('total', 'count')).to eq(0) end end end @@ -71,21 +58,6 @@ RSpec.describe Projects::Pipelines::TestsController do expect(response.body).to be_empty end end - - context 'when feature is disabled' do - let(:suite_name) { 'test' } - - before do - stub_feature_flags(build_report_summary: false) - end - - it 'returns 404' do - get_tests_show_json([]) - - expect(response).to have_gitlab_http_status(:not_found) - expect(response.body).to be_empty - end - end end def get_tests_summary_json diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 872f0e97b09..ef560f6426b 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -57,27 +57,6 @@ RSpec.describe Projects::PipelinesController do expect(response).to have_gitlab_http_status(:ok) expect(json_response['pipelines'].count).to eq 12 end - - context 'with build_report_summary turned off' do - before do - stub_feature_flags(build_report_summary: false) - end - - it 'does not execute N+1 queries' do - get_pipelines_index_json - - control_count = ActiveRecord::QueryRecorder.new do - get_pipelines_index_json - end.count - - create_all_pipeline_types - - # There appears to be one extra query for Pipelines#has_warnings? for some reason - expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1) - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['pipelines'].count).to eq 12 - end - end end it 'does not include coverage data for the pipelines' do @@ -880,113 +859,88 @@ RSpec.describe Projects::PipelinesController do end end - context 'when feature is enabled' do - before do - stub_feature_flags(junit_pipeline_view: project) - end - - context 'when pipeline does not have a test report' do - it 'renders an empty test report' do - get_test_report_json + context 'when pipeline does not have a test report' do + it 'renders an empty test report' do + get_test_report_json - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(0) end + end - context 'when pipeline has a test report' do - before do - create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| - create(:ci_job_artifact, :junit, job: build) - end - end - - it 'renders the test report' do - get_test_report_json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(4) - end + context 'when pipeline has a test report' do + before do + create(:ci_build, :test_reports, name: 'rspec', pipeline: pipeline) end - context 'when pipeline has a corrupt test report artifact' do - before do - create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| - create(:ci_job_artifact, :junit_with_corrupted_data, job: build) - end + it 'renders the test report' do + get_test_report_json - get_test_report_json - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(4) + end + end - it 'renders the test reports' do - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['test_suites'].count).to eq(1) - end + context 'when pipeline has a corrupt test report artifact' do + before do + create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline) - it 'returns a suite_error on the suite with corrupted XML' do - expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') - end + get_test_report_json 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) } + it 'renders the test reports' do + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['test_suites'].count).to eq(1) + end - it 'returns a test reports with attachment' do - get_test_report_json(scope: 'with_attachment') + it 'returns a suite_error on the suite with corrupted XML' do + expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') + end + 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 enabled' do + before do + stub_feature_flags(junit_pipeline_screenshots_view: project) + 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) } + 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 empty values' 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_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 end - context 'when feature is disabled' do - let(:pipeline) { create(:ci_empty_pipeline, project: project) } - + context 'when junit_pipeline_screenshots_view is disabled' do before do - stub_feature_flags(junit_pipeline_view: false) + stub_feature_flags(junit_pipeline_screenshots_view: false) end - it 'renders empty response' do - get_test_report_json + 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 without attachment_url' do + get_test_report_json(scope: 'with_attachment') - expect(response).to have_gitlab_http_status(:no_content) - expect(response.body).to be_empty + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url") + end end end @@ -1010,76 +964,6 @@ RSpec.describe Projects::PipelinesController do end end - describe 'GET test_report_count.json' do - subject(:test_reports_count_json) do - get :test_reports_count, params: { - namespace_id: project.namespace, - project_id: project, - id: pipeline.id - }, - format: :json - end - - context 'when feature is enabled' do - before do - stub_feature_flags(junit_pipeline_view: true) - end - - context 'when pipeline does not have a test report' do - let(:pipeline) { create(:ci_pipeline, project: project) } - - it 'renders an empty badge counter' do - test_reports_count_json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end - end - - context 'when pipeline has a test report' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - - it 'renders the badge counter value' do - test_reports_count_json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(4) - end - end - - context 'when pipeline has corrupt test reports' do - let(:pipeline) { create(:ci_pipeline, project: project) } - - before do - job = create(:ci_build, pipeline: pipeline) - create(:ci_job_artifact, :junit_with_corrupted_data, job: job, project: project) - end - - it 'renders 0' do - test_reports_count_json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end - end - end - - context 'when feature is disabled' do - let(:pipeline) { create(:ci_empty_pipeline, project: project) } - - before do - stub_feature_flags(junit_pipeline_view: false) - end - - it 'renders empty response' do - test_reports_count_json - - expect(response).to have_gitlab_http_status(:no_content) - expect(response.body).to be_empty - end - end - end - describe 'GET latest' do let(:branch_main) { project.repository.branches[0] } let(:branch_secondary) { project.repository.branches[1] } diff --git a/spec/controllers/projects/product_analytics_controller_spec.rb b/spec/controllers/projects/product_analytics_controller_spec.rb new file mode 100644 index 00000000000..47f1d96c70b --- /dev/null +++ b/spec/controllers/projects/product_analytics_controller_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::ProductAnalyticsController do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + before(:all) do + project.add_maintainer(user) + end + + before do + sign_in(user) + stub_feature_flags(product_analytics: true) + end + + describe 'GET #index' do + it 'renders index with 200 status code' do + get :index, params: project_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:index) + end + + context 'with an anonymous user' do + before do + sign_out(user) + end + + it 'redirects to sign-in page' do + get :index, params: project_params + + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'feature flag disabled' do + before do + stub_feature_flags(product_analytics: false) + end + + it 'returns not found' do + get :index, params: project_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'GET #test' do + it 'renders test with 200 status code' do + get :test, params: project_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:test) + end + end + + describe 'GET #setup' do + it 'renders setup with 200 status code' do + get :setup, params: project_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:setup) + end + end + + describe 'GET #graphs' do + it 'renders graphs with 200 status code' do + get :graphs, params: project_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:graphs) + end + + context 'feature flag disabled' do + before do + stub_feature_flags(product_analytics: false) + end + + it 'returns not found' do + get :graphs, params: project_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + private + + def project_params(opts = {}) + opts.reverse_merge(namespace_id: project.namespace, project_id: project) + end +end diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb index 6e3148231bd..cbd599506df 100644 --- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb +++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb @@ -111,6 +111,7 @@ RSpec.describe Projects::Prometheus::AlertsController do describe 'GET #show' do let(:alert) do create(:prometheus_alert, + :with_runbook_url, project: project, environment: environment, prometheus_metric: metric) @@ -140,6 +141,7 @@ RSpec.describe Projects::Prometheus::AlertsController do 'query' => alert.query, 'operator' => alert.computed_operator, 'threshold' => alert.threshold, + 'runbook_url' => alert.runbook_url, 'alert_path' => alert_path(alert) } end @@ -225,7 +227,8 @@ RSpec.describe Projects::Prometheus::AlertsController do 'title' => metric.title, 'query' => metric.query, 'operator' => '>', - 'threshold' => 1.0 + 'threshold' => 1.0, + 'runbook_url' => 'https://sample.runbook.com' } end @@ -234,6 +237,7 @@ RSpec.describe Projects::Prometheus::AlertsController do opts, operator: '>', threshold: '1', + runbook_url: 'https://sample.runbook.com', environment_id: environment, prometheus_metric_id: metric ) @@ -250,14 +254,14 @@ RSpec.describe Projects::Prometheus::AlertsController do expect(json_response).to include(alert_params) end - it 'returns no_content for an invalid metric' do + it 'returns bad_request for an invalid metric' do make_request(prometheus_metric_id: 'invalid') - expect(response).to have_gitlab_http_status(:no_content) + expect(response).to have_gitlab_http_status(:bad_request) end it_behaves_like 'unprivileged' - it_behaves_like 'project non-specific environment', :no_content + it_behaves_like 'project non-specific environment', :bad_request end describe 'PUT #update' do @@ -304,6 +308,12 @@ RSpec.describe Projects::Prometheus::AlertsController do expect(json_response).to include(alert_params) end + it 'returns bad_request for an invalid alert data' do + make_request(runbook_url: 'bad-url') + + expect(response).to have_gitlab_http_status(:bad_request) + end + it_behaves_like 'unprivileged' it_behaves_like 'project non-specific environment', :not_found it_behaves_like 'project non-specific metric', :not_found diff --git a/spec/controllers/projects/protected_branches_controller_spec.rb b/spec/controllers/projects/protected_branches_controller_spec.rb index 09eb1a45c73..a0cb5c1473a 100644 --- a/spec/controllers/projects/protected_branches_controller_spec.rb +++ b/spec/controllers/projects/protected_branches_controller_spec.rb @@ -27,6 +27,7 @@ RSpec.describe Projects::ProtectedBranchesController do { merge_access_levels_attributes: maintainer_access_level, push_access_levels_attributes: maintainer_access_level } end + let(:create_params) { attributes_for(:protected_branch).merge(access_level_params) } before do diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb index 3071d0b7f54..7f558ad9231 100644 --- a/spec/controllers/projects/serverless/functions_controller_spec.rb +++ b/spec/controllers/projects/serverless/functions_controller_spec.rb @@ -18,6 +18,7 @@ RSpec.describe Projects::Serverless::FunctionsController do let(:knative_stub_options) do { namespace: namespace.namespace, name: function_name, description: function_description } end + let(:knative) { create(:clusters_applications_knative, :installed, cluster: cluster) } let(:namespace) do diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index e8a23dcfafb..50f474c0222 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -82,7 +82,7 @@ RSpec.describe Projects::ServicesController do 'active' => '1', 'push_events' => '1', 'token' => 'token', - 'project_url' => 'http://test.com' + 'project_url' => 'https://buildkite.com/organization/pipeline' } end diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb index d4f3c5d0c9b..191b718af56 100644 --- a/spec/controllers/projects/settings/operations_controller_spec.rb +++ b/spec/controllers/projects/settings/operations_controller_spec.rb @@ -206,7 +206,7 @@ RSpec.describe Projects::Settings::OperationsController do reset_pagerduty_token new_token = incident_management_setting.reload.pagerduty_token - new_webhook_url = project_incidents_pagerduty_url(project, token: new_token) + new_webhook_url = project_incidents_integrations_pagerduty_url(project, token: new_token) expect(response).to have_gitlab_http_status(:ok) expect(json_response['pagerduty_webhook_url']).to eq(new_webhook_url) @@ -219,7 +219,7 @@ RSpec.describe Projects::Settings::OperationsController do it 'does not reset a token' do reset_pagerduty_token - new_webhook_url = project_incidents_pagerduty_url(project, token: nil) + new_webhook_url = project_incidents_integrations_pagerduty_url(project, token: nil) expect(response).to have_gitlab_http_status(:ok) expect(json_response['pagerduty_webhook_url']).to eq(new_webhook_url) diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 46dba691bc4..d93f23ae142 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -56,6 +56,7 @@ RSpec.describe Projects::Settings::RepositoryController do deploy_token_type: DeployToken.deploy_token_types[:project_type] } end + let(:request_params) do { namespace_id: project.namespace.to_param, @@ -77,7 +78,7 @@ RSpec.describe Projects::Settings::RepositoryController do 'token' => be_a(String), 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv - key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes + key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes end } end diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 6fcb24da3cd..bb9b556f442 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -416,12 +416,13 @@ RSpec.describe Projects::SnippetsController do describe "GET #show for embeddable content" do let(:project_snippet) { create(:project_snippet, :repository, snippet_permission, project: project, author: user) } + let(:extra_params) { {} } before do sign_in(user) end - subject { get :show, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }, format: :js } + subject { get :show, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param, **extra_params }, format: :js } context 'when snippet is private' do let(:snippet_permission) { :private } @@ -436,7 +437,29 @@ RSpec.describe Projects::SnippetsController do context 'when snippet is public' do let(:snippet_permission) { :public } - it_behaves_like 'successful response' + it 'renders the blob from the repository' do + subject + + expect(assigns(:snippet)).to eq(project_snippet) + expect(assigns(:blobs)).to eq(project_snippet.blobs) + expect(response).to have_gitlab_http_status(:ok) + end + + it 'does not show the blobs expanded by default' do + subject + + expect(project_snippet.blobs.map(&:expanded?)).to be_all(false) + end + + context 'when param expanded is set' do + let(:extra_params) { { expanded: true } } + + it 'shows all blobs expanded' do + subject + + expect(project_snippet.blobs.map(&:expanded?)).to be_all(true) + end + end end context 'when the project is private' do diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb index 122d1b072d0..d213d003bed 100644 --- a/spec/controllers/projects/tags_controller_spec.rb +++ b/spec/controllers/projects/tags_controller_spec.rb @@ -120,10 +120,14 @@ RSpec.describe Projects::TagsController do request - release = project.releases.find_by_tag!('1.0') + aggregate_failures do + expect(response).to have_gitlab_http_status(:found) - expect(release).to be_present - expect(release.description).to eq(release_description) + release = project.releases.find_by_tag('1.0') + + expect(release).to be_present + expect(release&.description).to eq(release_description) + end end end end diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index 8bb4c2dae4b..768d2ec00bd 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -47,6 +47,7 @@ RSpec.describe Projects::VariablesController do protected: variable.protected?.to_s, environment_scope: variable.environment_scope } end + let(:new_variable_attributes) do { key: 'new_key', secret_value: 'dummy_value', diff --git a/spec/controllers/registrations/experience_levels_controller_spec.rb b/spec/controllers/registrations/experience_levels_controller_spec.rb index 5a217a3a684..cd46cec1641 100644 --- a/spec/controllers/registrations/experience_levels_controller_spec.rb +++ b/spec/controllers/registrations/experience_levels_controller_spec.rb @@ -23,6 +23,7 @@ RSpec.describe Registrations::ExperienceLevelsController do end it { is_expected.to have_gitlab_http_status(:ok) } + it { is_expected.to render_template('layouts/devise_experimental_onboarding_issues') } it { is_expected.to render_template(:show) } context 'when not part of the onboarding issues experiment' do diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 66caa58666f..2c766035d87 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -18,16 +18,6 @@ RSpec.describe RegistrationsController do stub_experiment_for_user(signup_flow: true) end - it 'tracks the event with the right parameters' do - expect(Gitlab::Tracking).to receive(:event).with( - 'Growth::Acquisition::Experiment::SignUpFlow', - 'start', - label: anything, - property: 'experimental_group' - ) - subject - end - it 'renders new template and sets the resource variable' do expect(subject).to render_template(:new) expect(response).to have_gitlab_http_status(:ok) @@ -41,17 +31,52 @@ RSpec.describe RegistrationsController do stub_experiment_for_user(signup_flow: false) end - it 'does not track the event' do - expect(Gitlab::Tracking).not_to receive(:event) - subject - end - it 'renders new template and sets the resource variable' do subject expect(response).to have_gitlab_http_status(:found) expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane')) end end + + context 'with sign up flow and terms_opt_in experiment being enabled' do + before do + stub_experiment(signup_flow: true, terms_opt_in: true) + end + + context 'when user is not part of the experiment' do + before do + stub_experiment_for_user(signup_flow: true, terms_opt_in: false) + end + + it 'tracks event with right parameters' do + expect(Gitlab::Tracking).to receive(:event).with( + 'Growth::Acquisition::Experiment::TermsOptIn', + 'start', + label: anything, + property: 'control_group' + ) + + subject + end + end + + context 'when user is part of the experiment' do + before do + stub_experiment_for_user(signup_flow: true, terms_opt_in: true) + end + + it 'tracks event with right parameters' do + expect(Gitlab::Tracking).to receive(:event).with( + 'Growth::Acquisition::Experiment::TermsOptIn', + 'start', + label: anything, + property: 'experimental_group' + ) + + subject + end + end + end end describe '#create' do @@ -250,35 +275,79 @@ RSpec.describe RegistrationsController do expect(subject.current_user).to be_present expect(subject.current_user.terms_accepted?).to be(true) end - end - describe 'tracking data' do - context 'with the experimental signup flow enabled and the user is part of the control group' do + context 'when experiment terms_opt_in is enabled' do before do - stub_experiment(signup_flow: true) - stub_experiment_for_user(signup_flow: false) + stub_experiment(terms_opt_in: true) end - it 'tracks the event with the right parameters' do - expect(Gitlab::Tracking).to receive(:event).with( - 'Growth::Acquisition::Experiment::SignUpFlow', - 'end', - label: anything, - property: 'control_group' - ) - post :create, params: user_params + context 'when user is part of the experiment' do + before do + stub_experiment_for_user(terms_opt_in: true) + end + + it 'creates the user with accepted terms' do + post :create, params: user_params + + expect(subject.current_user).to be_present + expect(subject.current_user.terms_accepted?).to be(true) + end + end + + context 'when user is not part of the experiment' do + before do + stub_experiment_for_user(terms_opt_in: false) + end + + it 'creates the user without accepted terms' do + post :create, params: user_params + + expect(flash[:alert]).to eq(_('You must accept our Terms of Service and privacy policy in order to register an account')) + end end end + end + + describe 'tracking data' do + context 'with sign up flow and terms_opt_in experiment being enabled' do + subject { post :create, params: user_params } - context 'with the experimental signup flow enabled and the user is part of the experimental group' do before do - stub_experiment(signup_flow: true) - stub_experiment_for_user(signup_flow: true) + stub_experiment(signup_flow: true, terms_opt_in: true) end - it 'does not track the event' do - expect(Gitlab::Tracking).not_to receive(:event) - post :create, params: user_params + context 'when user is not part of the experiment' do + before do + stub_experiment_for_user(signup_flow: true, terms_opt_in: false) + end + + it 'tracks event with right parameters' do + expect(Gitlab::Tracking).to receive(:event).with( + 'Growth::Acquisition::Experiment::TermsOptIn', + 'end', + label: anything, + property: 'control_group' + ) + + subject + end + end + + context 'when user is part of the experiment' do + before do + stub_experiment_for_user(signup_flow: true, terms_opt_in: true) + end + + it 'tracks event with right parameters' do + expect(Gitlab::Tracking).to receive(:event).with( + 'Growth::Acquisition::Experiment::TermsOptIn', + 'end', + label: anything, + property: 'experimental_group' + ) + + subject + end end end end @@ -386,24 +455,6 @@ RSpec.describe RegistrationsController do end end - describe '#update_registration' do - before do - stub_experiment(signup_flow: true) - stub_experiment_for_user(signup_flow: true) - sign_in(create(:user)) - end - - it 'tracks the event with the right parameters' do - expect(Gitlab::Tracking).to receive(:event).with( - 'Growth::Acquisition::Experiment::SignUpFlow', - 'end', - label: anything, - property: 'experimental_group' - ) - patch :update_registration, params: { user: { role: 'software_developer', setup_for_company: 'false' } } - end - end - describe '#welcome' do subject { get :welcome } diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb index c938df8cf4e..851c1b7e519 100644 --- a/spec/controllers/repositories/git_http_controller_spec.rb +++ b/spec/controllers/repositories/git_http_controller_spec.rb @@ -17,6 +17,7 @@ RSpec.describe Repositories::GitHttpController do repository_id: repository_id } end + let(:params) { container_params } describe 'HEAD #info_refs' do diff --git a/spec/controllers/repositories/lfs_storage_controller_spec.rb b/spec/controllers/repositories/lfs_storage_controller_spec.rb new file mode 100644 index 00000000000..0201e73728f --- /dev/null +++ b/spec/controllers/repositories/lfs_storage_controller_spec.rb @@ -0,0 +1,160 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Repositories::LfsStorageController do + using RSpec::Parameterized::TableSyntax + include GitHttpHelpers + + let_it_be(:project) { create(:project, :public) } + let_it_be(:user) { create(:user) } + let_it_be(:pat) { create(:personal_access_token, user: user, scopes: ['write_repository']) } + + let(:lfs_enabled) { true } + + before do + stub_config(lfs: { enabled: lfs_enabled }) + end + + describe 'PUT #upload_finalize' do + let(:headers) { workhorse_internal_api_request_header } + let(:extra_headers) { {} } + let(:uploaded_file) { temp_file } + + let(:params) do + { + namespace_id: project.namespace.path, + repository_id: "#{project.path}.git", + oid: '6b9765d3888aaec789e8c309eb05b05c3a87895d6ad70d2264bd7270fff665ac', + size: '6725030' + } + end + + before do + request.headers.merge!(extra_headers) + request.headers.merge!(headers) + + if uploaded_file + allow_next_instance_of(ActionController::Parameters) do |params| + allow(params).to receive(:[]).and_call_original + allow(params).to receive(:[]).with(:file).and_return(uploaded_file) + end + end + end + + after do + FileUtils.rm_r(temp_file) if temp_file + end + + subject do + put :upload_finalize, params: params + end + + context 'with lfs enabled' do + context 'with unauthorized roles' do + where(:user_role, :expected_status) do + :guest | :forbidden + :anonymous | :unauthorized + end + + with_them do + let(:extra_headers) do + if user_role == :anonymous + {} + else + { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user.username, pat.token) } + end + end + + before do + project.send("add_#{user_role}", user) unless user_role == :anonymous + end + + it_behaves_like 'returning response status', params[:expected_status] + end + end + + context 'with at least developer role' do + let(:extra_headers) { { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user.username, pat.token) } } + + before do + project.add_developer(user) + end + + it 'creates the objects' do + expect { subject } + .to change { LfsObject.count }.by(1) + .and change { LfsObjectsProject.count }.by(1) + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'without the workhorse header' do + let(:headers) { {} } + + it { expect { subject }.to raise_error(JWT::DecodeError) } + end + + context 'without file' do + let(:uploaded_file) { nil } + + it_behaves_like 'returning response status', :unprocessable_entity + end + + context 'with an invalid file' do + let(:uploaded_file) { 'test' } + + it_behaves_like 'returning response status', :unprocessable_entity + end + + context 'when an expected error' do + [ + ActiveRecord::RecordInvalid, + UploadedFile::InvalidPathError, + ObjectStorage::RemoteStoreError + ].each do |exception_class| + context "#{exception_class} raised" do + it 'renders lfs forbidden' do + expect(LfsObjectsProject).to receive(:safe_find_or_create_by!).and_raise(exception_class) + + subject + + expect(response).to have_gitlab_http_status(:forbidden) + expect(json_response['documentation_url']).to be_present + expect(json_response['message']).to eq('Access forbidden. Check your access level.') + end + end + end + end + + context 'when file is not stored' do + it 'renders unprocessable entity' do + expect(controller).to receive(:store_file!).and_return(nil) + + subject + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + expect(response.body).to eq('Unprocessable entity') + end + end + end + end + + context 'with lfs disabled' do + let(:lfs_enabled) { false } + let(:extra_headers) { { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user.username, pat.token) } } + + it_behaves_like 'returning response status', :not_implemented + end + + def temp_file + upload_path = LfsObjectUploader.workhorse_local_upload_path + file_path = "#{upload_path}/lfs" + + FileUtils.mkdir_p(upload_path) + File.write(file_path, 'test') + + UploadedFile.new(file_path, filename: File.basename(file_path)) + end + end +end diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb index 9eefbcb0835..1db99a09404 100644 --- a/spec/controllers/root_controller_spec.rb +++ b/spec/controllers/root_controller_spec.rb @@ -122,6 +122,30 @@ RSpec.describe RootController do expect(response).to render_template 'dashboard/projects/index' end + + context 'when experiment is enabled' do + before do + stub_experiment_for_user(customize_homepage: true) + end + + it 'renders the default dashboard' do + get :index + + expect(assigns[:customize_homepage]).to be true + end + end + + context 'when experiment not enabled' do + before do + stub_experiment(customize_homepage: false) + end + + it 'renders the default dashboard' do + get :index + + expect(assigns[:customize_homepage]).to be false + end + end end end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 0849fb00e73..a41ff28841d 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -216,4 +216,23 @@ RSpec.describe SearchController do it_behaves_like 'when the user cannot read cross project', :autocomplete, { term: 'hello' } it_behaves_like 'with external authorization service enabled', :autocomplete, { term: 'hello' } end + + describe '#append_info_to_payload' do + it 'appends search metadata for logging' do + last_payload = nil + original_append_info_to_payload = controller.method(:append_info_to_payload) + + expect(controller).to receive(:append_info_to_payload) do |payload| + original_append_info_to_payload.call(payload) + last_payload = payload + end + + get :show, params: { scope: 'issues', search: 'hello world', group_id: '123', project_id: '456' } + + expect(last_payload[:metadata]['meta.search.group_id']).to eq('123') + expect(last_payload[:metadata]['meta.search.project_id']).to eq('456') + expect(last_payload[:metadata]['meta.search.search']).to eq('hello world') + expect(last_payload[:metadata]['meta.search.scope']).to eq('issues') + end + end end diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb index 0c4a77d5926..02aaa5b16f1 100644 --- a/spec/controllers/sent_notifications_controller_spec.rb +++ b/spec/controllers/sent_notifications_controller_spec.rb @@ -216,6 +216,7 @@ RSpec.describe SentNotificationsController do merge_request.subscriptions.create(user: user, project: project, subscribed: true) end end + let(:sent_notification) { create(:sent_notification, project: project, noteable: merge_request, recipient: user) } before do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 16a58112479..257dcce0899 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -59,39 +59,6 @@ RSpec.describe SessionsController do end end end - - describe 'tracking data' do - context 'when the user is part of the experimental group' do - before do - stub_experiment_for_user(signup_flow: true) - end - - it 'doesn\'t pass tracking parameters to the frontend' do - get(:new) - expect(Gon.tracking_data).to be_nil - end - end - - context 'with the experimental signup flow enabled and the user is part of the control group' do - before do - stub_experiment(signup_flow: true) - stub_experiment_for_user(signup_flow: false) - allow_any_instance_of(described_class).to receive(:experimentation_subject_id).and_return('uuid') - end - - it 'passes the right tracking parameters to the frontend' do - get(:new) - expect(Gon.tracking_data).to eq( - { - category: 'Growth::Acquisition::Experiment::SignUpFlow', - action: 'start', - label: 'uuid', - property: 'control_group' - } - ) - end - end - end end describe '#create' do @@ -216,7 +183,7 @@ RSpec.describe SessionsController do before do stub_application_setting(recaptcha_enabled: true) - request.headers[described_class::CAPTCHA_HEADER] = 1 + request.headers[described_class::CAPTCHA_HEADER] = '1' end it 'displays an error when the reCAPTCHA is not solved' do @@ -399,7 +366,7 @@ RSpec.describe SessionsController do end it 'warns about invalid login' do - expect(response).to set_flash.now[:alert].to /Your account is locked./ + expect(flash[:alert]).to eq('Your account is locked.') end it 'locks the user' do @@ -409,7 +376,7 @@ RSpec.describe SessionsController do it 'keeps the user locked on future login attempts' do post(:create, params: { user: { login: user.username, password: user.password } }) - expect(response).to set_flash.now[:alert].to /Your account is locked./ + expect(flash[:alert]).to eq('Your account is locked.') end end end |