diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /spec/controllers/projects | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'spec/controllers/projects')
13 files changed, 403 insertions, 660 deletions
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index ebcf35a7ecd..a275bc28631 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Projects::HooksController do + include AfterNextHelpers + let_it_be(:project) { create(:project) } let(:user) { project.first_owner } @@ -20,6 +22,36 @@ RSpec.describe Projects::HooksController do end end + describe '#update' do + let_it_be(:hook) { create(:project_hook, project: project) } + + let(:params) do + { namespace_id: project.namespace, project_id: project, id: hook.id } + end + + it 'adds, updates and deletes URL variables' do + hook.update!(url_variables: { 'a' => 'bar', 'b' => 'woo' }) + + params[:hook] = { + url_variables: [ + { key: 'a', value: 'updated' }, + { key: 'b', value: nil }, + { key: 'c', value: 'new' } + ] + } + + put :update, params: params + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:notice]).to include('successfully updated') + + expect(hook.reload.url_variables).to eq( + 'a' => 'updated', + 'c' => 'new' + ) + end + end + describe '#edit' do let_it_be(:hook) { create(:project_hook, project: project) } @@ -87,14 +119,30 @@ RSpec.describe Projects::HooksController do job_events: true, pipeline_events: true, wiki_page_events: true, - deployment_events: true + deployment_events: true, + + url_variables: [{ key: 'token', value: 'some secret value' }] } post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params } expect(response).to have_gitlab_http_status(:found) - expect(ProjectHook.all.size).to eq(1) - expect(ProjectHook.first).to have_attributes(hook_params) + expect(flash[:alert]).to be_blank + expect(ProjectHook.count).to eq(1) + expect(ProjectHook.first).to have_attributes(hook_params.except(:url_variables)) + expect(ProjectHook.first).to have_attributes(url_variables: { 'token' => 'some secret value' }) + end + + it 'alerts the user if the new hook is invalid' do + hook_params = { + token: "TEST\nTOKEN", + url: "http://example.com" + } + + post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params } + + expect(flash[:alert]).to be_present + expect(ProjectHook.count).to eq(0) end end @@ -109,6 +157,45 @@ RSpec.describe Projects::HooksController do describe '#test' do let(:hook) { create(:project_hook, project: project) } + context 'when the hook executes successfully' do + before do + stub_request(:post, hook.url).to_return(status: 200) + end + + it 'informs the user' do + post :test, params: { namespace_id: project.namespace, project_id: project, id: hook } + + expect(flash[:notice]).to include('executed successfully') + expect(flash[:notice]).to include('HTTP 200') + end + end + + context 'when the hook runs, but fails' do + before do + stub_request(:post, hook.url).to_return(status: 400) + end + + it 'informs the user' do + post :test, params: { namespace_id: project.namespace, project_id: project, id: hook } + + expect(flash[:alert]).to include('executed successfully but') + expect(flash[:alert]).to include('HTTP 400') + end + end + + context 'when the hook fails completely' do + before do + allow_next(::TestHooks::ProjectService) + .to receive(:execute).and_return({ message: 'All is woe' }) + end + + it 'informs the user' do + post :test, params: { namespace_id: project.namespace, project_id: project, id: hook } + + expect(flash[:alert]).to include('failed: All is woe') + end + end + context 'when the endpoint receives requests above the limit', :freeze_time, :clean_gitlab_redis_rate_limiting do before do allow(Gitlab::ApplicationRateLimiter).to receive(:rate_limits) diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 1305693372c..badac688229 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1818,7 +1818,7 @@ RSpec.describe Projects::IssuesController do context 'user is allowed access' do before do - project.add_user(user, :maintainer) + project.add_member(user, :maintainer) end it 'displays all available notes' do diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 107eb1ed3a3..e4e3151dd12 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -752,28 +752,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end end - describe 'GET status.json' do - let(:job) { create(:ci_build, pipeline: pipeline) } - let(:status) { job.detailed_status(double('user')) } - - before do - get :status, params: { - namespace_id: project.namespace, - project_id: project, - id: job.id - }, - format: :json - end - - it 'return a detailed job status in json' do - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['text']).to eq status.text - expect(json_response['label']).to eq status.label - expect(json_response['icon']).to eq status.icon - expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.png" - end - end - describe 'POST retry' do before do project.add_developer(user) diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb deleted file mode 100644 index 1c81ae93b42..00000000000 --- a/spec/controllers/projects/logs_controller_spec.rb +++ /dev/null @@ -1,214 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::LogsController do - include KubernetesHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - - let_it_be(:environment) do - create(:environment, name: 'production', project: project) - end - - let(:pod_name) { "foo" } - let(:container) { 'container-1' } - - before do - sign_in(user) - end - - describe 'GET #index' do - let(:empty_project) { create(:project) } - - it 'returns 404 with reporter access' do - project.add_reporter(user) - - get :index, params: environment_params - - expect(response).to have_gitlab_http_status(:not_found) - end - - it 'renders empty logs page if no environment exists' do - empty_project.add_developer(user) - - get :index, params: { namespace_id: empty_project.namespace, project_id: empty_project } - - expect(response).to be_ok - expect(response).to render_template 'empty_logs' - end - - it 'renders index template' do - project.add_developer(user) - - get :index, params: environment_params - - expect(response).to be_ok - expect(response).to render_template 'index' - end - - context 'with feature flag disabled' do - before do - stub_feature_flags(monitor_logging: false) - end - - it 'returns 404 with reporter access' do - project.add_developer(user) - - get :index, params: environment_params - - expect(response).to have_gitlab_http_status(:not_found) - end - end - end - - shared_examples 'pod logs service' do |endpoint, service| - let(:service_result) do - { - status: :success, - logs: ['Log 1', 'Log 2', 'Log 3'], - pods: [pod_name], - pod_name: pod_name, - 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]) } - - before do - allow_next_instance_of(service) do |instance| - allow(instance).to receive(:execute).and_return(service_result) - end - end - - 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) - 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 - - it 'sets the polling header' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) - - expect(response).to have_gitlab_http_status(:success) - expect(response.headers['Poll-Interval']).to eq('3000') - end - - context 'with gitlab managed apps logs' do - it 'uses cluster finder services to select cluster', :aggregate_failures do - cluster_list = [cluster] - service_params = { params: ActionController::Parameters.new(pod_name: pod_name).permit! } - request_params = { - namespace_id: project.namespace, - project_id: project, - cluster_id: cluster.id, - pod_name: pod_name, - format: :json - } - - expect_next_instance_of(ClusterAncestorsFinder, project, user) do |finder| - expect(finder).to receive(:execute).and_return(cluster_list) - expect(cluster_list).to receive(:find).and_call_original - end - - expect_next_instance_of(service, cluster, Gitlab::Kubernetes::Helm::NAMESPACE, service_params) do |instance| - expect(instance).to receive(:execute).and_return(service_result) - end - - get endpoint, params: request_params - - expect(response).to have_gitlab_http_status(:success) - expect(json_response).to eq(service_result_json) - end - end - - context 'when service is processing' do - let(:service_result) { nil } - - it 'returns a 202' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) - - expect(response).to have_gitlab_http_status(:accepted) - end - end - - shared_examples 'unsuccessful execution response' do |message| - let(:service_result) do - { - status: :error, - message: message - } - end - - it 'returns the error' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) - - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to eq(service_result_json) - end - end - - context 'when service is failing' do - it_behaves_like 'unsuccessful execution response', 'some error' - end - - context 'when cluster is nil' do - let!(:cluster) { nil } - - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' - end - - context 'when namespace is empty' do - before do - allow(environment).to receive(:deployment_namespace).and_return('') - end - - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' - end - end - end - - describe 'GET #k8s' do - it_behaves_like 'pod logs service', :k8s, PodLogs::KubernetesService - end - - describe 'GET #elasticsearch' do - it_behaves_like 'pod logs service', :elasticsearch, PodLogs::ElasticsearchService - end - - def environment_params(opts = {}) - opts.reverse_merge(namespace_id: project.namespace, - project_id: project, - environment_name: environment.name) - end -end diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb index 686effd799e..d33bc215cfc 100644 --- a/spec/controllers/projects/mirrors_controller_spec.rb +++ b/spec/controllers/projects/mirrors_controller_spec.rb @@ -211,7 +211,7 @@ RSpec.describe Projects::MirrorsController do context 'data in the cache' do let(:ssh_key) { 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf' } - let(:ssh_fp) { { type: 'ed25519', bits: 256, fingerprint: '2e:65:6a:c8:cf:bf:b2:8b:9a:bd:6d:9f:11:5c:12:16', index: 0 } } + let(:ssh_fp) { { type: 'ed25519', bits: 256, fingerprint: '2e:65:6a:c8:cf:bf:b2:8b:9a:bd:6d:9f:11:5c:12:16', fingerprint_sha256: 'SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8', index: 0 } } it 'returns the data with a 200 response' do stub_reactive_cache(cache, known_hosts: ssh_key) diff --git a/spec/controllers/projects/pipelines/tests_controller_spec.rb b/spec/controllers/projects/pipelines/tests_controller_spec.rb index 2db54dbe671..ddcab8b048e 100644 --- a/spec/controllers/projects/pipelines/tests_controller_spec.rb +++ b/spec/controllers/projects/pipelines/tests_controller_spec.rb @@ -45,11 +45,26 @@ RSpec.describe Projects::Pipelines::TestsController do pipeline.job_artifacts.first.update!(expire_at: Date.yesterday) end + it 'renders test suite', :aggregate_failures do + get_tests_show_json(build_ids) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['name']).to eq('test') + expect(json_response['total_count']).to eq(3) + expect(json_response['test_cases'].size).to eq(3) + end + end + + context 'when artifacts do not exist' do + before do + pipeline.job_artifacts.each(&:destroy) + end + it 'renders not_found errors', :aggregate_failures do get_tests_show_json(build_ids) expect(response).to have_gitlab_http_status(:not_found) - expect(json_response['errors']).to eq('Test report artifacts have expired') + expect(json_response['errors']).to eq('Test report artifacts not found') end end @@ -68,7 +83,6 @@ RSpec.describe Projects::Pipelines::TestsController do expect(response).to have_gitlab_http_status(:ok) expect(json_response['name']).to eq('test') - expect(json_response['artifacts_expired']).to be_falsey # Each test failure in this pipeline has a matching failure in the default branch recent_failures = json_response['test_cases'].map { |tc| tc['recent_failures'] } diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index b3b803649d1..06930d8727b 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -827,6 +827,14 @@ RSpec.describe Projects::PipelinesController do { chart_param: 'lead-time', event: 'p_analytics_ci_cd_lead_time' + }, + { + chart_param: 'time-to-restore-service', + event: 'p_analytics_ci_cd_time_to_restore_service' + }, + { + chart_param: 'change-failure-rate', + event: 'p_analytics_ci_cd_change_failure_rate' } ].each do |tab| it_behaves_like 'tracking unique visits', :charts do diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 9bb34a38005..46eb340cbba 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -68,27 +68,6 @@ RSpec.describe Projects::ProjectMembersController do end end - context 'group links' do - let_it_be(:project_group_link) { create(:project_group_link, project: project, group: group) } - - it 'lists group links' do - get :index, params: { namespace_id: project.namespace, project_id: project } - - expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link.id) - end - - context 'when `search_groups` param is present' do - let(:group_2) { create(:group, :public, name: 'group_2') } - let!(:project_group_link_2) { create(:project_group_link, project: project, group: group_2) } - - it 'lists group links that match search' do - get :index, params: { namespace_id: project.namespace, project_id: project, search_groups: 'group_2' } - - expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link_2.id) - end - end - end - context 'invited members' do let_it_be(:invited_member) { create(:project_member, :invited, project: project) } diff --git a/spec/controllers/projects/service_ping_controller_spec.rb b/spec/controllers/projects/service_ping_controller_spec.rb index fa92efee079..22fb18edc80 100644 --- a/spec/controllers/projects/service_ping_controller_spec.rb +++ b/spec/controllers/projects/service_ping_controller_spec.rb @@ -80,16 +80,24 @@ RSpec.describe Projects::ServicePingController do it_behaves_like 'counter is not increased' it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_SUCCESS_COUNT' - context 'when the user has access to the project' do + context 'when the user has access to the project', :snowplow do let(:user) { project.owner } it 'increases the live preview view counter' do - expect(Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_live_preview_edit_action).with(author: user) + expect(Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_live_preview_edit_action).with(author: user, project: project) subject expect(response).to have_gitlab_http_status(:ok) end + + it_behaves_like 'Snowplow event tracking' do + let(:project) { create(:project) } + let(:category) { 'ide_edit' } + let(:action) { 'g_edit_by_live_preview' } + let(:namespace) { project.namespace } + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + 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 d50f1aa1dd8..e5ae1b04a86 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -8,305 +8,294 @@ RSpec.describe Projects::Settings::CiCdController do let(:project) { project_auto_devops.project } - before do - project.add_maintainer(user) - sign_in(user) - 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) } + context 'as a maintainer' do + before do + project.add_maintainer(user) + sign_in(user) + end - it 'renders show with 200 status code' do - get :show, params: { namespace_id: project.namespace, project_id: project } + 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) } - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:show) - end + it 'renders show with 200 status code' do + get :show, params: { namespace_id: project.namespace, project_id: project } - context 'with CI/CD disabled' do - before do - project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:show) end - it 'renders show with 404 status code' do - get :show, params: { namespace_id: project.namespace, project_id: project } - expect(response).to have_gitlab_http_status(:not_found) + context 'with CI/CD disabled' do + before do + project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED) + end + + it 'renders show with 404 status code' do + get :show, params: { namespace_id: project.namespace, project_id: project } + expect(response).to have_gitlab_http_status(:not_found) + end end - end - context 'with group runners' do - 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) } + context 'with group runners' do + 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) + it 'sets assignable project runners only' do + group.add_maintainer(user) - get :show, params: { namespace_id: project.namespace, project_id: project } + get :show, params: { namespace_id: project.namespace, project_id: project } - expect(assigns(:assignable_runners)).to contain_exactly(project_runner) + expect(assigns(:assignable_runners)).to contain_exactly(project_runner) + end end - end - context 'prevents N+1 queries for tags' do - render_views + context 'prevents N+1 queries for tags' do + render_views - def show - get :show, params: { namespace_id: project.namespace, project_id: project } - end + 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) + it 'has the same number of queries with one tag or with many tags', :request_store do + group.add_maintainer(user) - show # warmup + 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 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)) + # 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) + expect { show }.not_to exceed_query_limit(control) + end end end - end - describe '#reset_cache' do - before do - sign_in(user) - - project.add_maintainer(user) + describe '#reset_cache' do + before do + sign_in(user) - allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) - end + project.add_maintainer(user) - subject { post :reset_cache, params: { namespace_id: project.namespace, project_id: project }, format: :json } + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) + end - it 'calls reset project cache service' do - expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) + subject { post :reset_cache, params: { namespace_id: project.namespace, project_id: project }, format: :json } - subject - end + it 'calls reset project cache service' do + expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) - context 'when service returns successfully' do - it 'returns a success header' do subject - - expect(response).to have_gitlab_http_status(:ok) end - end - context 'when service does not return successfully' do - before do - allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) + context 'when service returns successfully' do + it 'returns a success header' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end end - it 'returns an error header' do - subject + context 'when service does not return successfully' do + before do + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) + end - expect(response).to have_gitlab_http_status(:bad_request) + it 'returns an error header' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + end end end - end - describe 'PUT #reset_registration_token' do - subject { put :reset_registration_token, params: { namespace_id: project.namespace, project_id: project } } + describe 'PUT #reset_registration_token' do + subject { put :reset_registration_token, params: { namespace_id: project.namespace, project_id: project } } - it 'resets runner registration token' do - expect { subject }.to change { project.reload.runners_token } - expect(flash[:toast]).to eq('New runners registration token has been generated!') - end + it 'resets runner registration token' do + expect { subject }.to change { project.reload.runners_token } + expect(flash[:toast]).to eq('New runners registration token has been generated!') + end - it 'redirects the user to admin runners page' do - subject + it 'redirects the user to admin runners page' do + subject - expect(response).to redirect_to(namespace_project_settings_ci_cd_path) + expect(response).to redirect_to(namespace_project_settings_ci_cd_path) + end end - end - describe 'PATCH update' do - let(:params) { { ci_config_path: '' } } - - subject do - patch :update, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - project: params - } - end + describe 'PATCH update' do + let(:params) { { ci_config_path: '' } } - it 'redirects to the settings page' do - subject + subject do + patch :update, + params: { + namespace_id: project.namespace.to_param, + project_id: project, + project: params + } + end - expect(response).to have_gitlab_http_status(:found) - expect(flash[:toast]).to eq("Pipelines settings for '#{project.name}' were successfully updated.") - end + it 'redirects to the settings page' do + subject - context 'when updating the auto_devops settings' do - let(:params) { { auto_devops_attributes: { enabled: '' } } } + expect(response).to have_gitlab_http_status(:found) + expect(flash[:toast]).to eq("Pipelines settings for '#{project.name}' were successfully updated.") + end - context 'following the instance default' do + context 'when updating the auto_devops settings' do let(:params) { { auto_devops_attributes: { enabled: '' } } } - it 'allows enabled to be set to nil' do - subject - project_auto_devops.reload + context 'following the instance default' do + let(:params) { { auto_devops_attributes: { enabled: '' } } } - expect(project_auto_devops.enabled).to be_nil - end - end + it 'allows enabled to be set to nil' do + subject + project_auto_devops.reload - context 'when run_auto_devops_pipeline is true' do - before do - expect_next_instance_of(Projects::UpdateService) do |instance| - expect(instance).to receive(:run_auto_devops_pipeline?).and_return(true) + expect(project_auto_devops.enabled).to be_nil end end - context 'when the project repository is empty' do - it 'sets a notice flash' do - subject - - expect(controller).to set_flash[:notice] + context 'when run_auto_devops_pipeline is true' do + before do + expect_next_instance_of(Projects::UpdateService) do |instance| + expect(instance).to receive(:run_auto_devops_pipeline?).and_return(true) + end end - it 'does not queue a CreatePipelineWorker' do - expect(CreatePipelineWorker).not_to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) + context 'when the project repository is empty' do + it 'sets a notice flash' do + subject - subject + expect(controller).to set_flash[:notice] + end + + it 'does not queue a CreatePipelineWorker' do + expect(CreatePipelineWorker).not_to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) + + subject + end end - end - context 'when the project repository is not empty' do - let(:project) { create(:project, :repository) } + context 'when the project repository is not empty' do + let(:project) { create(:project, :repository) } - it 'displays a toast message' do - allow(CreatePipelineWorker).to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) + it 'displays a toast message' do + allow(CreatePipelineWorker).to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) - subject + subject - expect(controller).to set_flash[:toast] - end + expect(controller).to set_flash[:toast] + end - it 'queues a CreatePipelineWorker' do - expect(CreatePipelineWorker).to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) + it 'queues a CreatePipelineWorker' do + expect(CreatePipelineWorker).to receive(:perform_async).with(project.id, user.id, project.default_branch, :web, any_args) - subject - end + subject + end - it 'creates a pipeline', :sidekiq_inline do - project.repository.create_file(user, 'Gemfile', 'Gemfile contents', - message: 'Add Gemfile', - branch_name: 'master') + it 'creates a pipeline', :sidekiq_inline do + project.repository.create_file(user, 'Gemfile', 'Gemfile contents', + message: 'Add Gemfile', + branch_name: 'master') - expect { subject }.to change { Ci::Pipeline.count }.by(1) + expect { subject }.to change { Ci::Pipeline.count }.by(1) + end end end - end - context 'when run_auto_devops_pipeline is not true' do - before do - expect_next_instance_of(Projects::UpdateService) do |instance| - expect(instance).to receive(:run_auto_devops_pipeline?).and_return(false) + context 'when run_auto_devops_pipeline is not true' do + before do + expect_next_instance_of(Projects::UpdateService) do |instance| + expect(instance).to receive(:run_auto_devops_pipeline?).and_return(false) + end end - end - it 'does not queue a CreatePipelineWorker' do - expect(CreatePipelineWorker).not_to receive(:perform_async).with(project.id, user.id, :web, any_args) + it 'does not queue a CreatePipelineWorker' do + expect(CreatePipelineWorker).not_to receive(:perform_async).with(project.id, user.id, :web, any_args) - subject + subject + end end end - end - context 'when updating general settings' do - context 'when build_timeout_human_readable is not specified' do - let(:params) { { build_timeout_human_readable: '' } } + context 'when updating general settings' do + context 'when build_timeout_human_readable is not specified' do + let(:params) { { build_timeout_human_readable: '' } } - it 'set default timeout' do - subject + it 'set default timeout' do + subject - project.reload - expect(project.build_timeout).to eq(3600) + project.reload + expect(project.build_timeout).to eq(3600) + end end - end - context 'when build_timeout_human_readable is specified' do - let(:params) { { build_timeout_human_readable: '1h 30m' } } + context 'when build_timeout_human_readable is specified' do + let(:params) { { build_timeout_human_readable: '1h 30m' } } - it 'set specified timeout' do - subject + it 'set specified timeout' do + subject - project.reload - expect(project.build_timeout).to eq(5400) + project.reload + expect(project.build_timeout).to eq(5400) + end end - end - - context 'when build_timeout_human_readable is invalid' do - let(:params) { { build_timeout_human_readable: '5m' } } - it 'set specified timeout' do - subject - - expect(controller).to set_flash[:alert] - expect(response).to redirect_to(namespace_project_settings_ci_cd_path) - end - end + context 'when build_timeout_human_readable is invalid' do + let(:params) { { build_timeout_human_readable: '5m' } } - context 'when default_git_depth is not specified' do - let(:params) { { ci_cd_settings_attributes: { default_git_depth: 10 } } } + it 'set specified timeout' do + subject - before do - project.ci_cd_settings.update!(default_git_depth: nil) + expect(controller).to set_flash[:alert] + expect(response).to redirect_to(namespace_project_settings_ci_cd_path) + end end - it 'set specified git depth' do - subject + context 'when default_git_depth is not specified' do + let(:params) { { ci_cd_settings_attributes: { default_git_depth: 10 } } } - project.reload - expect(project.ci_default_git_depth).to eq(10) - end - end + before do + project.ci_cd_settings.update!(default_git_depth: nil) + end - context 'when forward_deployment_enabled is not specified' do - let(:params) { { ci_cd_settings_attributes: { forward_deployment_enabled: false } } } + it 'set specified git depth' do + subject - before do - project.ci_cd_settings.update!(forward_deployment_enabled: nil) + project.reload + expect(project.ci_default_git_depth).to eq(10) + end end - it 'sets forward deployment enabled' do - subject - - project.reload - expect(project.ci_forward_deployment_enabled).to eq(false) - end - end + context 'when forward_deployment_enabled is not specified' do + let(:params) { { ci_cd_settings_attributes: { forward_deployment_enabled: false } } } - context 'when max_artifacts_size is specified' do - let(:params) { { max_artifacts_size: 10 } } + before do + project.ci_cd_settings.update!(forward_deployment_enabled: nil) + end - context 'and user is not an admin' do - it 'does not set max_artifacts_size' do + it 'sets forward deployment enabled' do subject project.reload - expect(project.max_artifacts_size).to be_nil + expect(project.ci_forward_deployment_enabled).to eq(false) end end - context 'and user is an admin' do - let(:user) { create(:admin) } + context 'when max_artifacts_size is specified' do + let(:params) { { max_artifacts_size: 10 } } - context 'with admin mode disabled' do + context 'and user is not an admin' do it 'does not set max_artifacts_size' do subject @@ -315,33 +304,81 @@ RSpec.describe Projects::Settings::CiCdController do end end - context 'with admin mode enabled', :enable_admin_mode do - it 'sets max_artifacts_size' do - subject + context 'and user is an admin' do + let(:user) { create(:admin) } - project.reload - expect(project.max_artifacts_size).to eq(10) + context 'with admin mode disabled' do + it 'does not set max_artifacts_size' do + subject + + project.reload + expect(project.max_artifacts_size).to be_nil + end + end + + context 'with admin mode enabled', :enable_admin_mode do + it 'sets max_artifacts_size' do + subject + + project.reload + expect(project.max_artifacts_size).to eq(10) + end end end end end end + + describe 'GET #runner_setup_scripts' do + it 'renders the setup scripts' do + get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64', namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to have_key("install") + expect(json_response).to have_key("register") + end + + it 'renders errors if they occur' do + get :runner_setup_scripts, params: { os: 'foo', arch: 'bar', namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to have_key("errors") + end + end end - describe 'GET #runner_setup_scripts' do - it 'renders the setup scripts' do - get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64', namespace_id: project.namespace, project_id: project } + context 'as a developer' do + before do + sign_in(user) + project.add_developer(user) + get :show, params: { namespace_id: project.namespace, project_id: project } + end - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to have_key("install") - expect(json_response).to have_key("register") + it 'responds with 404' do + expect(response).to have_gitlab_http_status(:not_found) end + end - it 'renders errors if they occur' do - get :runner_setup_scripts, params: { os: 'foo', arch: 'bar', namespace_id: project.namespace, project_id: project } + context 'as a reporter' do + before do + sign_in(user) + project.add_reporter(user) + get :show, params: { namespace_id: project.namespace, project_id: project } + end - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to have_key("errors") + it 'responds with 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'as an unauthenticated user' do + before do + get :show, params: { namespace_id: project.namespace, project_id: project } + end + + it 'redirects to sign in' do + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to('/users/sign_in') end end end diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index e6ca088a533..8ee9f22aa7f 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -138,7 +138,7 @@ RSpec.describe Projects::Settings::IntegrationsController do end end - context 'when unsuccessful' do + context 'when unsuccessful', :clean_gitlab_redis_rate_limiting do it 'returns an error response when the integration test fails' do stub_request(:get, 'http://example.com/rest/api/2/serverInfo') .to_return(status: 404) @@ -148,7 +148,7 @@ RSpec.describe Projects::Settings::IntegrationsController do expect(response).to be_successful expect(json_response).to eq( 'error' => true, - 'message' => 'Connection failed. Please check your settings.', + 'message' => 'Connection failed. Check your integration settings.', 'service_response' => '', 'test_failed' => true ) @@ -163,7 +163,7 @@ RSpec.describe Projects::Settings::IntegrationsController do expect(response).to be_successful expect(json_response).to eq( 'error' => true, - 'message' => 'Connection failed. Please check your settings.', + 'message' => 'Connection failed. Check your integration settings.', 'service_response' => "URL 'http://127.0.0.1' is blocked: Requests to localhost are not allowed", 'test_failed' => true ) @@ -177,13 +177,33 @@ RSpec.describe Projects::Settings::IntegrationsController do expect(response).to be_successful expect(json_response).to eq( 'error' => true, - 'message' => 'Connection failed. Please check your settings.', + 'message' => 'Connection failed. Check your integration settings.', 'service_response' => 'Connection refused', 'test_failed' => true ) end end end + + context 'when the endpoint receives requests above the limit', :freeze_time, :clean_gitlab_redis_rate_limiting do + before do + allow(Gitlab::ApplicationRateLimiter).to receive(:rate_limits) + .and_return(project_testing_integration: { threshold: 1, interval: 1.minute }) + end + + it 'prevents making test requests' do + stub_jira_integration_test + + expect_next_instance_of(::Integrations::Test::ProjectService) do |service| + expect(service).to receive(:execute).and_return(http_status: 200) + end + + 2.times { post :test, params: project_params(service: integration_params) } + + expect(response.body).to eq(_('This endpoint has been requested too many times. Try again later.')) + expect(response).to have_gitlab_http_status(:too_many_requests) + end + end end describe 'PUT #update' do diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb index c1fa91e9f8b..76d8191e342 100644 --- a/spec/controllers/projects/settings/operations_controller_spec.rb +++ b/spec/controllers/projects/settings/operations_controller_spec.rb @@ -437,108 +437,6 @@ RSpec.describe Projects::Settings::OperationsController do end end - context 'tracing integration' do - describe 'GET #show' do - context 'with existing setting' do - let_it_be(:setting) do - create(:project_tracing_setting, project: project) - end - - it 'loads existing setting' do - get :show, params: project_params(project) - - expect(controller.helpers.tracing_setting).to eq(setting) - end - end - - context 'without an existing setting' do - it 'builds a new setting' do - get :show, params: project_params(project) - - expect(controller.helpers.tracing_setting).to be_new_record - end - end - end - - describe 'PATCH #update' do - let_it_be(:external_url) { 'https://gitlab.com' } - - let(:params) do - { - tracing_setting_attributes: { - external_url: external_url - } - } - end - - it_behaves_like 'PATCHable' - - describe 'gitlab tracking', :snowplow do - shared_examples 'event tracking' do - it 'tracks an event' do - expect_snowplow_event( - category: 'project:operations:tracing', - action: 'external_url_populated', - user: user, - project: project, - namespace: project.namespace - ) - end - end - - shared_examples 'no event tracking' do - it 'does not track an event' do - expect_no_snowplow_event - end - end - - before do - make_request - end - - subject(:make_request) do - patch :update, params: project_params(project, params), format: :json - end - - context 'without existing setting' do - context 'when creating a new setting' do - it_behaves_like 'event tracking' - end - - context 'with invalid external_url' do - let_it_be(:external_url) { nil } - - it_behaves_like 'no event tracking' - end - end - - context 'with existing setting' do - let_it_be(:existing_setting) do - create(:project_tracing_setting, - project: project, - external_url: external_url) - end - - context 'when changing external_url' do - let_it_be(:external_url) { 'https://example.com' } - - it_behaves_like 'no event tracking' - end - - context 'with unchanged external_url' do - it_behaves_like 'no event tracking' - end - - context 'with invalid external_url' do - let_it_be(:external_url) { nil } - - it_behaves_like 'no event tracking' - end - end - end - end - end - private def project_params(project, params = {}) diff --git a/spec/controllers/projects/tracings_controller_spec.rb b/spec/controllers/projects/tracings_controller_spec.rb deleted file mode 100644 index 80e21349e20..00000000000 --- a/spec/controllers/projects/tracings_controller_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::TracingsController do - let_it_be(:user) { create(:user) } - - describe 'GET show' do - shared_examples 'user with read access' do |visibility_level| - let(:project) { create(:project, visibility_level) } - - %w[developer maintainer].each do |role| - context "with a #{visibility_level} project and #{role} role" do - before do - project.add_role(user, role) - end - - it 'renders OK' do - get :show, params: { namespace_id: project.namespace, project_id: project } - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:show) - end - end - end - end - - shared_examples 'user without read access' do |visibility_level| - let(:project) { create(:project, visibility_level) } - - %w[guest reporter].each do |role| - context "with a #{visibility_level} project and #{role} role" do - before do - project.add_role(user, role) - end - - it 'returns 404' do - get :show, params: { namespace_id: project.namespace, project_id: project } - - expect(response).to have_gitlab_http_status(:not_found) - end - end - end - end - - before do - sign_in(user) - end - - context 'with maintainer role' do - it_behaves_like 'user with read access', :public - it_behaves_like 'user with read access', :internal - it_behaves_like 'user with read access', :private - - context 'feature flag disabled' do - before do - stub_feature_flags(monitor_tracing: false) - end - - it_behaves_like 'user without read access', :public - it_behaves_like 'user without read access', :internal - it_behaves_like 'user without read access', :private - end - end - - context 'without maintainer role' do - it_behaves_like 'user without read access', :public - it_behaves_like 'user without read access', :internal - it_behaves_like 'user without read access', :private - end - end -end |