Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/controllers/projects')
-rw-r--r--spec/controllers/projects/autocomplete_sources_controller_spec.rb12
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb144
-rw-r--r--spec/controllers/projects/commits_controller_spec.rb8
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb27
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb11
-rw-r--r--spec/controllers/projects/import/jira_controller_spec.rb2
-rw-r--r--spec/controllers/projects/incidents_controller_spec.rb1
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb99
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb92
-rw-r--r--spec/controllers/projects/mattermosts_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests/drafts_controller_spec.rb32
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb8
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb94
-rw-r--r--spec/controllers/projects/pipelines/tests_controller_spec.rb12
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb12
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb83
-rw-r--r--spec/controllers/projects/prometheus/alerts_controller_spec.rb106
-rw-r--r--spec/controllers/projects/prometheus/metrics_controller_spec.rb6
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb23
-rw-r--r--spec/controllers/projects/services_controller_spec.rb356
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb13
-rw-r--r--spec/controllers/projects/settings/integration_hook_logs_controller_spec.rb (renamed from spec/controllers/projects/service_hook_logs_controller_spec.rb)5
-rw-r--r--spec/controllers/projects/settings/integrations_controller_spec.rb382
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb101
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb10
25 files changed, 696 insertions, 945 deletions
diff --git a/spec/controllers/projects/autocomplete_sources_controller_spec.rb b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
index 79edc261809..a5274b6543e 100644
--- a/spec/controllers/projects/autocomplete_sources_controller_spec.rb
+++ b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
@@ -114,17 +114,5 @@ RSpec.describe Projects::AutocompleteSourcesController do
end
end
end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(customer_relations: false)
- end
-
- it 'renders 404' do
- get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
end
end
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 01420e30d24..d45ea268e64 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -272,150 +272,6 @@ RSpec.describe Projects::ClustersController do
end
end
- describe 'POST #create_aws' do
- let(:params) do
- {
- cluster: {
- name: 'new-cluster',
- provider_aws_attributes: {
- key_name: 'key',
- role_arn: 'arn:role',
- region: 'region',
- vpc_id: 'vpc',
- instance_type: 'instance type',
- num_nodes: 3,
- security_group_id: 'security group',
- subnet_ids: %w(subnet1 subnet2)
- }
- }
- }
- end
-
- def post_create_aws
- post :create_aws, params: params.merge(namespace_id: project.namespace, project_id: project)
- end
-
- include_examples ':certificate_based_clusters feature flag controller responses' do
- let(:subject) { post_create_aws }
- end
-
- it 'creates a new cluster' do
- expect(ClusterProvisionWorker).to receive(:perform_async)
- expect { post_create_aws }.to change { Clusters::Cluster.count }
- .and change { Clusters::Providers::Aws.count }
-
- cluster = project.clusters.first
-
- expect(response).to have_gitlab_http_status(:created)
- expect(response.location).to eq(project_cluster_path(project, cluster))
- expect(cluster).to be_aws
- expect(cluster).to be_kubernetes
- end
-
- context 'params are invalid' do
- let(:params) do
- {
- cluster: { name: '' }
- }
- end
-
- it 'does not create a cluster' do
- expect { post_create_aws }.not_to change { Clusters::Cluster.count }
-
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- expect(response.media_type).to eq('application/json')
- expect(response.body).to include('is invalid')
- end
- end
-
- describe 'security' do
- before do
- allow(WaitForClusterCreationWorker).to receive(:perform_in)
- end
-
- it 'is allowed for admin when admin mode enabled', :enable_admin_mode do
- expect { post_create_aws }.to be_allowed_for(:admin)
- end
- it 'is disabled for admin when admin mode disabled' do
- expect { post_create_aws }.to be_denied_for(:admin)
- end
- it { expect { post_create_aws }.to be_allowed_for(:owner).of(project) }
- it { expect { post_create_aws }.to be_allowed_for(:maintainer).of(project) }
- it { expect { post_create_aws }.to be_denied_for(:developer).of(project) }
- it { expect { post_create_aws }.to be_denied_for(:reporter).of(project) }
- it { expect { post_create_aws }.to be_denied_for(:guest).of(project) }
- it { expect { post_create_aws }.to be_denied_for(:user) }
- it { expect { post_create_aws }.to be_denied_for(:external) }
- end
- end
-
- describe 'POST authorize AWS role for EKS cluster' do
- let!(:role) { create(:aws_role, user: user) }
-
- let(:role_arn) { 'arn:new-role' }
- let(:params) do
- {
- cluster: {
- role_arn: role_arn
- }
- }
- end
-
- def go
- post :authorize_aws_role, params: params.merge(namespace_id: project.namespace, project_id: project)
- end
-
- before do
- allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
- .and_return(double(execute: double))
- end
-
- include_examples ':certificate_based_clusters feature flag controller responses' do
- let(:subject) { go }
- end
-
- it 'updates the associated role with the supplied ARN' do
- go
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(role.reload.role_arn).to eq(role_arn)
- end
-
- context 'supplied role is invalid' do
- let(:role_arn) { 'invalid-role' }
-
- it 'does not update the associated role' do
- expect { go }.not_to change { role.role_arn }
-
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
- end
-
- describe 'security' do
- before do
- allow_next_instance_of(Clusters::Aws::AuthorizeRoleService) do |service|
- response = double(status: :ok, body: double)
-
- allow(service).to receive(:execute).and_return(response)
- end
- end
-
- it 'is allowed for admin when admin mode enabled', :enable_admin_mode do
- expect { go }.to be_allowed_for(:admin)
- end
- it 'is disabled for admin when admin mode disabled' do
- expect { go }.to be_denied_for(:admin)
- end
- it { expect { go }.to be_allowed_for(:owner).of(project) }
- it { expect { go }.to be_allowed_for(:maintainer).of(project) }
- it { expect { go }.to be_denied_for(:developer).of(project) }
- it { expect { go }.to be_denied_for(:reporter).of(project) }
- it { expect { go }.to be_denied_for(:guest).of(project) }
- it { expect { go }.to be_denied_for(:user) }
- it { expect { go }.to be_denied_for(:external) }
- end
- end
-
describe 'DELETE clear cluster cache' do
let(:cluster) { create(:cluster, :project, projects: [project]) }
let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) }
diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb
index c7f98406201..26d4725656f 100644
--- a/spec/controllers/projects/commits_controller_spec.rb
+++ b/spec/controllers/projects/commits_controller_spec.rb
@@ -166,6 +166,14 @@ RSpec.describe Projects::CommitsController do
end
end
end
+
+ context 'with markdown cache' do
+ it 'preloads markdown cache for commits' do
+ expect(Commit).to receive(:preload_markdown_cache!).and_call_original
+
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: 'master/README.md' }
+ end
+ end
end
describe "GET /commits/:id/signatures" do
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 9821618df8d..e6e0307d0ca 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -44,6 +44,14 @@ RSpec.describe Projects::CompareController do
expect(response).to be_successful
end
end
+
+ context 'with missing parameters' do
+ let(:params) { super().merge(from: '', to: '') }
+
+ it 'returns successfully' do
+ expect(response).to be_successful
+ end
+ end
end
describe 'GET show' do
@@ -102,6 +110,23 @@ RSpec.describe Projects::CompareController do
end
end
+ context 'when refs have CI::Pipeline' do
+ let(:from_project_id) { nil }
+ let(:from_ref) { '08f22f25' }
+ let(:to_ref) { '59e29889' }
+
+ before do
+ create(:ci_pipeline, project: project)
+ end
+
+ it 'avoids N+1 queries' do
+ control = ActiveRecord::QueryRecorder.new { show_request }
+
+ # Only 1 query to ci/pipeline.rb is allowed
+ expect(control.find_query(/pipeline\.rb/, 1)).to be_empty
+ end
+ end
+
context 'when the refs exist in different projects that the user can see' do
let(:from_project_id) { public_fork.id }
let(:from_ref) { 'improve%2Fmore-awesome' }
@@ -434,7 +459,7 @@ RSpec.describe Projects::CompareController do
expect(CompareService).to receive(:new).with(project, escaped_to_ref).and_return(compare_service)
expect(compare_service).to receive(:execute).with(project, escaped_from_ref).and_return(compare)
- expect(compare).to receive(:commits).and_return([signature_commit, non_signature_commit])
+ expect(compare).to receive(:commits).and_return(CommitCollection.new(project, [signature_commit, non_signature_commit]))
expect(non_signature_commit).to receive(:has_signature?).and_return(false)
end
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index f63e0cea04c..f4cad5790a3 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -208,17 +208,6 @@ RSpec.describe Projects::EnvironmentsController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
-
- it_behaves_like 'avoids N+1 queries on environment detail page'
-
- def create_deployment_with_associations(sequence:)
- commit = project.commit("HEAD~#{sequence}")
- create(:user, email: commit.author_email)
-
- deployer = create(:user)
- build = create(:ci_build, environment: environment.name, pipeline: create(:ci_pipeline, project: environment.project), user: deployer)
- create(:deployment, :success, environment: environment, deployable: build, user: deployer, project: project, sha: commit.sha)
- end
end
describe 'GET edit' do
diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb
index 5288c0fcf21..3f149afbb02 100644
--- a/spec/controllers/projects/import/jira_controller_spec.rb
+++ b/spec/controllers/projects/import/jira_controller_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Projects::Import::JiraController do
- include JiraServiceHelper
+ include JiraIntegrationHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/controllers/projects/incidents_controller_spec.rb b/spec/controllers/projects/incidents_controller_spec.rb
index 20cf0dcfd3a..460821634b0 100644
--- a/spec/controllers/projects/incidents_controller_spec.rb
+++ b/spec/controllers/projects/incidents_controller_spec.rb
@@ -43,7 +43,6 @@ RSpec.describe Projects::IncidentsController do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
- expect(Gon.features).to include('incidentEscalations' => true)
end
context 'when user is unauthorized' do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 8a03c1e709b..1305693372c 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -12,10 +12,6 @@ RSpec.describe Projects::IssuesController do
let(:issue) { create(:issue, project: project) }
let(:spam_action_response_fields) { { 'stub_spam_action_response_fields' => true } }
- before do
- stub_feature_flags(vue_issues_list: true)
- end
-
describe "GET #index" do
context 'external issue tracker' do
before do
@@ -145,13 +141,104 @@ RSpec.describe Projects::IssuesController do
project.add_developer(user)
end
- it "returns issue_email_participants" do
+ it "returns issue attributes" do
participants = create_list(:issue_email_participant, 2, issue: issue)
get :show, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }, format: :json
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['issue_email_participants']).to contain_exactly({ "email" => participants[0].email }, { "email" => participants[1].email })
+ expect(json_response).to include(
+ 'issue_email_participants' => contain_exactly(
+ { "email" => participants[0].email }, { "email" => participants[1].email }
+ ),
+ 'type' => 'ISSUE'
+ )
+ end
+
+ context 'when issue is not a task and work items feature flag is enabled' do
+ it 'does not redirect to work items route' do
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
+
+ expect(response).to render_template(:show)
+ end
+ end
+
+ context 'when issue is of type task' do
+ let(:query) { {} }
+
+ let_it_be(:task) { create(:issue, :task, project: project) }
+
+ context 'when work_items feature flag is enabled' do
+ shared_examples 'redirects to show work item page' do
+ it 'redirects to work item page' do
+ expect(response).to redirect_to(project_work_items_path(project, task.id, query))
+ end
+ end
+
+ context 'show action' do
+ let(:query) { { query: 'any' } }
+
+ before do
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
+ end
+
+ it_behaves_like 'redirects to show work item page'
+ end
+
+ context 'edit action' do
+ let(:query) { { query: 'any' } }
+
+ before do
+ get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
+ end
+
+ it_behaves_like 'redirects to show work item page'
+ end
+
+ context 'update action' do
+ before do
+ put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } }
+ end
+
+ it_behaves_like 'redirects to show work item page'
+ end
+ end
+
+ context 'when work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(work_items: false)
+ end
+
+ shared_examples 'renders 404' do
+ it 'renders 404 for show action' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'show action' do
+ before do
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid }
+ end
+
+ it_behaves_like 'renders 404'
+ end
+
+ context 'edit action' do
+ before do
+ get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid }
+ end
+
+ it_behaves_like 'renders 404'
+ end
+
+ context 'update action' do
+ before do
+ put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } }
+ end
+
+ it_behaves_like 'renders 404'
+ end
+ end
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index f0fbbb65fa5..107eb1ed3a3 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -1075,63 +1075,81 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
before do
project.add_role(user, role)
sign_in(user)
-
- post_erase
end
- shared_examples_for 'erases' do
- it 'redirects to the erased job page' do
- expect(response).to have_gitlab_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: job.id))
+ context 'when project is not undergoing stats refresh' do
+ before do
+ post_erase
end
- it 'erases artifacts' do
- expect(job.artifacts_file.present?).to be_falsey
- expect(job.artifacts_metadata.present?).to be_falsey
- end
+ shared_examples_for 'erases' do
+ it 'redirects to the erased job page' do
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(namespace_project_job_path(id: job.id))
+ end
- it 'erases trace' do
- expect(job.trace.exist?).to be_falsey
+ it 'erases artifacts' do
+ expect(job.artifacts_file.present?).to be_falsey
+ expect(job.artifacts_metadata.present?).to be_falsey
+ end
+
+ it 'erases trace' do
+ expect(job.trace.exist?).to be_falsey
+ end
end
- end
- context 'when job is successful and has artifacts' do
- let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline) }
+ context 'when job is successful and has artifacts' do
+ let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline) }
- it_behaves_like 'erases'
- end
+ it_behaves_like 'erases'
+ end
- context 'when job has live trace and unarchived artifact' do
- let(:job) { create(:ci_build, :success, :trace_live, :unarchived_trace_artifact, pipeline: pipeline) }
+ context 'when job has live trace and unarchived artifact' do
+ let(:job) { create(:ci_build, :success, :trace_live, :unarchived_trace_artifact, pipeline: pipeline) }
- it_behaves_like 'erases'
- end
+ it_behaves_like 'erases'
+ end
- context 'when job is erased' do
- let(:job) { create(:ci_build, :erased, pipeline: pipeline) }
+ context 'when job is erased' do
+ let(:job) { create(:ci_build, :erased, pipeline: pipeline) }
- it 'returns unprocessable_entity' do
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ it 'returns unprocessable_entity' do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
end
- end
- context 'when user is developer' do
- let(:role) { :developer }
- let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline, user: triggered_by) }
+ context 'when user is developer' do
+ let(:role) { :developer }
+ let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline, user: triggered_by) }
- context 'when triggered by same user' do
- let(:triggered_by) { user }
+ context 'when triggered by same user' do
+ let(:triggered_by) { user }
- it 'has successful status' do
- expect(response).to have_gitlab_http_status(:found)
+ it 'has successful status' do
+ expect(response).to have_gitlab_http_status(:found)
+ end
+ end
+
+ context 'when triggered by different user' do
+ let(:triggered_by) { create(:user) }
+
+ it 'does not have successful status' do
+ expect(response).not_to have_gitlab_http_status(:found)
+ end
end
end
+ end
+
+ context 'when project is undergoing stats refresh' do
+ it_behaves_like 'preventing request because of ongoing project stats refresh' do
+ let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline) }
+ let(:make_request) { post_erase }
- context 'when triggered by different user' do
- let(:triggered_by) { create(:user) }
+ it 'does not erase artifacts' do
+ make_request
- it 'does not have successful status' do
- expect(response).not_to have_gitlab_http_status(:found)
+ expect(job.artifacts_file).to be_present
+ expect(job.artifacts_metadata).to be_present
end
end
end
diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb
index 596cd5c1a20..19a04654114 100644
--- a/spec/controllers/projects/mattermosts_controller_spec.rb
+++ b/spec/controllers/projects/mattermosts_controller_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe Projects::MattermostsController do
subject
integration = project.integrations.last
- expect(subject).to redirect_to(edit_project_integration_path(project, integration))
+ expect(subject).to redirect_to(edit_project_settings_integration_path(project, integration))
end
end
end
diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
index 222bb977beb..b9ede84157d 100644
--- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
@@ -385,6 +385,38 @@ RSpec.describe Projects::MergeRequests::DraftsController do
expect(discussion.resolved?).to eq(false)
end
end
+
+ context 'publish with note' do
+ before do
+ create(:draft_note, merge_request: merge_request, author: user)
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(mr_review_submit_comment: false)
+ end
+
+ it 'does not create note' do
+ post :publish, params: params.merge!(note: 'Hello world')
+
+ expect(merge_request.notes.reload.size).to be(1)
+ end
+ end
+
+ context 'when feature flag is enabled' do
+ it 'creates note' do
+ post :publish, params: params.merge!(note: 'Hello world')
+
+ expect(merge_request.notes.reload.size).to be(2)
+ end
+
+ it 'does not create note when note param is empty' do
+ post :publish, params: params.merge!(note: '')
+
+ expect(merge_request.notes.reload.size).to be(1)
+ end
+ end
+ end
end
describe 'DELETE #destroy' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index f6db809c2e3..8ccbc0d3fe2 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -1094,7 +1094,7 @@ RSpec.describe Projects::MergeRequestsController do
end
context 'when processing coverage reports is completed' do
- let(:report) { { status: :parsed, data: pipeline.coverage_reports } }
+ let(:report) { { status: :parsed, data: { 'files' => {} } } }
it 'returns coverage reports' do
subject
@@ -1730,7 +1730,7 @@ RSpec.describe Projects::MergeRequestsController do
describe 'POST remove_wip' do
before do
- merge_request.title = merge_request.wip_title
+ merge_request.title = merge_request.draft_title
merge_request.save!
post :remove_wip,
@@ -1743,8 +1743,8 @@ RSpec.describe Projects::MergeRequestsController do
xhr: true
end
- it 'removes the wip status' do
- expect(merge_request.reload.title).to eq(merge_request.wipless_title)
+ it 'removes the draft status' do
+ expect(merge_request.reload.title).to eq(merge_request.draftless_title)
end
it 'renders MergeRequest as JSON' do
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 07874c8a8af..85e5de46afd 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -84,100 +84,6 @@ RSpec.describe Projects::NotesController do
end
end
- context 'for multiple pages of notes', :aggregate_failures do
- # 3 pages worth: 1 normal page, 1 oversized due to clashing updated_at,
- # and a final, short page
- let!(:page_1) { create_list(:note, 2, noteable: issue, project: project, updated_at: 3.days.ago) }
- let!(:page_2) { create_list(:note, 3, noteable: issue, project: project, updated_at: 2.days.ago) }
- let!(:page_3) { create_list(:note, 2, noteable: issue, project: project, updated_at: 1.day.ago) }
-
- # Include a resource event in the middle page as well
- let!(:resource_event) { create(:resource_state_event, issue: issue, user: user, created_at: 2.days.ago) }
-
- let(:page_1_boundary) { microseconds(page_1.last.updated_at + NotesFinder::FETCH_OVERLAP) }
- let(:page_2_boundary) { microseconds(page_2.last.updated_at + NotesFinder::FETCH_OVERLAP) }
-
- around do |example|
- freeze_time do
- example.run
- end
- end
-
- before do
- stub_const('Gitlab::UpdatedNotesPaginator::LIMIT', 2)
- end
-
- context 'feature flag enabled' do
- before do
- stub_feature_flags(paginated_notes: true)
- end
-
- it 'returns the first page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_1.count)
- expect(json_response['more']).to be_truthy
- expect(json_response['last_fetched_at']).to eq(page_1_boundary)
- expect(response.headers['Poll-Interval'].to_i).to eq(1)
- end
-
- it 'returns the second page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = page_1_boundary
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_2.count + 1) # resource event
- expect(json_response['more']).to be_truthy
- expect(json_response['last_fetched_at']).to eq(page_2_boundary)
- expect(response.headers['Poll-Interval'].to_i).to eq(1)
- end
-
- it 'returns the final page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = page_2_boundary
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_3.count)
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- expect(response.headers['Poll-Interval'].to_i).to be > 1
- end
-
- it 'returns an empty page of notes' do
- expect(Gitlab::EtagCaching::Middleware).not_to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = microseconds(Time.zone.now)
-
- get :index, params: request_params
-
- expect(json_response['notes']).to be_empty
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- expect(response.headers['Poll-Interval'].to_i).to be > 1
- end
- end
-
- context 'feature flag disabled' do
- before do
- stub_feature_flags(paginated_notes: false)
- end
-
- it 'returns all notes' do
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq((page_1 + page_2 + page_3).size + 1)
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- end
- end
- end
-
context 'for a discussion note' do
let(:project) { create(:project, :repository) }
let!(:note) { create(:discussion_note_on_merge_request, project: project) }
diff --git a/spec/controllers/projects/pipelines/tests_controller_spec.rb b/spec/controllers/projects/pipelines/tests_controller_spec.rb
index 113781bab7c..2db54dbe671 100644
--- a/spec/controllers/projects/pipelines/tests_controller_spec.rb
+++ b/spec/controllers/projects/pipelines/tests_controller_spec.rb
@@ -51,18 +51,6 @@ RSpec.describe Projects::Pipelines::TestsController do
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['errors']).to eq('Test report artifacts have expired')
end
-
- context 'when ci_test_report_artifacts_expired is disabled' do
- before do
- stub_feature_flags(ci_test_report_artifacts_expired: false)
- 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')
- end
- end
end
context 'when artifacts are not expired' do
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 1be4177acd1..b3b803649d1 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -1289,6 +1289,18 @@ RSpec.describe Projects::PipelinesController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ context 'and project is undergoing stats refresh' do
+ it_behaves_like 'preventing request because of ongoing project stats refresh' do
+ let(:make_request) { delete_pipeline }
+
+ it 'does not delete the pipeline' do
+ make_request
+
+ expect(Ci::Pipeline.exists?(pipeline.id)).to be_truthy
+ end
+ end
+ end
end
context 'when user has no privileges' do
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 20a114bbe8c..9bb34a38005 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -170,6 +170,46 @@ RSpec.describe Projects::ProjectMembersController do
expect(requester.reload.human_access).to eq(label)
end
end
+
+ describe 'managing project direct owners' do
+ context 'when a Maintainer tries to elevate another user to OWNER' do
+ it 'does not allow the operation' do
+ params = {
+ project_member: { access_level: Gitlab::Access::OWNER },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }
+
+ put :update, params: params, xhr: true
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when a user with OWNER access tries to elevate another user to OWNER' do
+ # inherited owner role via personal project association
+ let(:user) { project.first_owner }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ params = {
+ project_member: { access_level: Gitlab::Access::OWNER },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }
+
+ put :update, params: params, xhr: true
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(requester.reload.access_level).to eq(Gitlab::Access::OWNER)
+ end
+ end
+ end
end
context 'access expiry date' do
@@ -275,19 +315,40 @@ RSpec.describe Projects::ProjectMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before do
- project.add_developer(user)
+ context 'when user does not have rights to manage other members' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns 404', :aggregate_failures do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(project.members).to include member
+ end
end
- it 'returns 404', :aggregate_failures do
- delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: member
- }
+ context 'when user does not have rights to manage Owner members' do
+ let_it_be(:member) { create(:project_member, project: project, access_level: Gitlab::Access::OWNER) }
- expect(response).to have_gitlab_http_status(:not_found)
- expect(project.members).to include member
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns 403', :aggregate_failures do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(project.members).to include member
+ end
end
end
@@ -434,7 +495,7 @@ RSpec.describe Projects::ProjectMembersController do
end
context 'when member is found' do
- context 'when user does not have enough rights' do
+ context 'when user does not have rights to manage other members' do
before do
project.add_developer(user)
end
diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
index f42119e7811..2c2c8180143 100644
--- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb
+++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
@@ -53,112 +53,6 @@ RSpec.describe Projects::Prometheus::AlertsController do
end
end
- describe 'GET #index' do
- def make_request(opts = {})
- get :index, params: request_params(opts, environment_id: environment)
- end
-
- context 'when project has no prometheus alert' do
- it 'returns an empty response' do
- make_request
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_empty
- end
- end
-
- context 'when project has prometheus alerts' do
- let(:production) { create(:environment, project: project) }
- let(:staging) { create(:environment, project: project) }
- let(:json_alert_ids) { json_response.map { |alert| alert['id'] } }
-
- let!(:production_alerts) do
- create_list(:prometheus_alert, 2, project: project, environment: production)
- end
-
- let!(:staging_alerts) do
- create_list(:prometheus_alert, 1, project: project, environment: staging)
- end
-
- it 'contains prometheus alerts only for the production environment' do
- make_request(environment_id: production)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.count).to eq(2)
- expect(json_alert_ids).to eq(production_alerts.map(&:id))
- end
-
- it 'contains prometheus alerts only for the staging environment' do
- make_request(environment_id: staging)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.count).to eq(1)
- expect(json_alert_ids).to eq(staging_alerts.map(&:id))
- end
-
- it 'does not return prometheus alerts without environment' do
- make_request(environment_id: nil)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_empty
- end
- end
-
- it_behaves_like 'unprivileged'
- it_behaves_like 'project non-specific environment', :ok
- end
-
- describe 'GET #show' do
- let(:alert) do
- create(:prometheus_alert,
- :with_runbook_url,
- project: project,
- environment: environment,
- prometheus_metric: metric)
- end
-
- def make_request(opts = {})
- get :show, params: request_params(
- opts,
- id: alert.prometheus_metric_id,
- environment_id: environment
- )
- end
-
- context 'when alert does not exist' do
- it 'returns not_found' do
- make_request(id: 0)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when alert exists' do
- let(:alert_params) do
- {
- 'id' => alert.id,
- 'title' => alert.title,
- 'query' => alert.query,
- 'operator' => alert.computed_operator,
- 'threshold' => alert.threshold,
- 'runbook_url' => alert.runbook_url,
- 'alert_path' => alert_path(alert)
- }
- end
-
- it 'renders the alert' do
- make_request
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to include(alert_params)
- end
-
- it_behaves_like 'unprivileged'
- it_behaves_like 'project non-specific environment', :not_found
- it_behaves_like 'project non-specific metric', :not_found
- end
- end
-
describe 'POST #notify' do
let(:alert_1) { build(:alert_management_alert, :prometheus, project: project) }
let(:alert_2) { build(:alert_management_alert, :prometheus, project: project) }
diff --git a/spec/controllers/projects/prometheus/metrics_controller_spec.rb b/spec/controllers/projects/prometheus/metrics_controller_spec.rb
index 7dfa283195e..cd195b95100 100644
--- a/spec/controllers/projects/prometheus/metrics_controller_spec.rb
+++ b/spec/controllers/projects/prometheus/metrics_controller_spec.rb
@@ -141,7 +141,7 @@ RSpec.describe Projects::Prometheus::MetricsController do
expect(flash[:notice]).to include('Metric was successfully added.')
- expect(response).to redirect_to(edit_project_integration_path(project, ::Integrations::Prometheus))
+ expect(response).to redirect_to(edit_project_settings_integration_path(project, ::Integrations::Prometheus))
end
end
@@ -168,7 +168,7 @@ RSpec.describe Projects::Prometheus::MetricsController do
expect(metric.reload.title).to eq('new_title')
expect(flash[:notice]).to include('Metric was successfully updated.')
- expect(response).to redirect_to(edit_project_integration_path(project, ::Integrations::Prometheus))
+ expect(response).to redirect_to(edit_project_settings_integration_path(project, ::Integrations::Prometheus))
end
end
end
@@ -180,7 +180,7 @@ RSpec.describe Projects::Prometheus::MetricsController do
it 'destroys the metric' do
delete :destroy, params: project_params(id: metric.id)
- expect(response).to redirect_to(edit_project_integration_path(project, ::Integrations::Prometheus))
+ expect(response).to redirect_to(edit_project_settings_integration_path(project, ::Integrations::Prometheus))
expect(PrometheusMetric.find_by(id: metric.id)).to be_nil
end
end
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index 0dba7dab643..ad6682601f3 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -115,15 +115,6 @@ RSpec.describe Projects::ReleasesController do
expect(json_response.map { |release| release["id"] } ).to eq([release_2.id, release_1.id])
end
- # TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/360903
- it "returns release sha when remove_sha_from_releases_json is disabled" do
- stub_feature_flags(remove_sha_from_releases_json: false)
-
- get_index
-
- expect(json_response).to eq([release_2, release_1].as_json)
- end
-
it_behaves_like 'common access controls'
context 'when the project is private and the user is not logged in' do
@@ -157,19 +148,19 @@ RSpec.describe Projects::ReleasesController do
end
let(:release) { create(:release, project: project) }
- let(:tag) { CGI.escape(release.tag) }
+ let(:tag) { release.tag }
it_behaves_like 'successful request'
context 'when tag name contains slash' do
let(:release) { create(:release, project: project, tag: 'awesome/v1.0') }
- let(:tag) { CGI.escape(release.tag) }
+ let(:tag) { release.tag }
it_behaves_like 'successful request'
it 'is accesible at a URL encoded path' do
expect(edit_project_release_path(project, release))
- .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%252Fv1.0/edit")
+ .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0/edit")
end
end
@@ -196,19 +187,19 @@ RSpec.describe Projects::ReleasesController do
end
let(:release) { create(:release, project: project) }
- let(:tag) { CGI.escape(release.tag) }
+ let(:tag) { release.tag }
it_behaves_like 'successful request'
context 'when tag name contains slash' do
let(:release) { create(:release, project: project, tag: 'awesome/v1.0') }
- let(:tag) { CGI.escape(release.tag) }
+ let(:tag) { release.tag }
it_behaves_like 'successful request'
it 'is accesible at a URL encoded path' do
expect(project_release_path(project, release))
- .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%252Fv1.0")
+ .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0")
end
end
@@ -248,7 +239,7 @@ RSpec.describe Projects::ReleasesController do
end
let(:release) { create(:release, project: project) }
- let(:tag) { CGI.escape(release.tag) }
+ let(:tag) { release.tag }
context 'when user is a guest' do
let(:project) { private_project }
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
deleted file mode 100644
index 6802ebeb63e..00000000000
--- a/spec/controllers/projects/services_controller_spec.rb
+++ /dev/null
@@ -1,356 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::ServicesController do
- include JiraServiceHelper
- include AfterNextHelpers
-
- let_it_be(:project) { create(:project, :repository) }
- let_it_be(:user) { create(:user) }
- let_it_be(:jira_integration) { create(:jira_integration, project: project) }
-
- let(:integration) { jira_integration }
- let(:integration_params) { { username: 'username', password: 'password', url: 'http://example.com' } }
-
- before do
- sign_in(user)
- project.add_maintainer(user)
- end
-
- it_behaves_like Integrations::Actions do
- let(:integration_attributes) { { project: project } }
-
- let(:routing_params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- id: integration.to_param
- }
- end
- end
-
- describe '#test' do
- context 'when the integration is not testable' do
- it 'renders 404' do
- allow_any_instance_of(Integration).to receive(:testable?).and_return(false)
-
- put :test, params: project_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when validations fail' do
- let(:integration_params) { { active: 'true', url: '' } }
-
- it 'returns error messages in JSON response' do
- put :test, params: project_params(service: integration_params)
-
- expect(json_response['message']).to eq 'Validations failed.'
- expect(json_response['service_response']).to include "Url can't be blank"
- expect(response).to be_successful
- end
- end
-
- context 'when successful' do
- context 'with empty project' do
- let_it_be(:project) { create(:project) }
-
- context 'with chat notification integration' do
- let_it_be(:teams_integration) { project.create_microsoft_teams_integration(webhook: 'http://webhook.com') }
-
- let(:integration) { teams_integration }
-
- it 'returns success' do
- allow_next(::MicrosoftTeams::Notifier).to receive(:ping).and_return(true)
-
- put :test, params: project_params
-
- expect(response).to be_successful
- end
- end
-
- it 'returns success' do
- stub_jira_integration_test
-
- expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
-
- put :test, params: project_params(service: integration_params)
-
- expect(response).to be_successful
- end
- end
-
- it 'returns success' do
- stub_jira_integration_test
-
- expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
-
- put :test, params: project_params(service: integration_params)
-
- expect(response).to be_successful
- end
-
- context 'when service is configured for the first time' do
- let(:integration_params) do
- {
- 'active' => '1',
- 'push_events' => '1',
- 'token' => 'token',
- 'project_url' => 'https://buildkite.com/organization/pipeline'
- }
- end
-
- before do
- allow_any_instance_of(ServiceHook).to receive(:execute).and_return(true)
- end
-
- it 'persist the object' do
- do_put
-
- expect(response).to be_successful
- expect(json_response).to be_empty
- expect(Integrations::Buildkite.first).to be_present
- end
-
- it 'creates the ServiceHook object' do
- do_put
-
- expect(response).to be_successful
- expect(json_response).to be_empty
- expect(Integrations::Buildkite.first.service_hook).to be_present
- end
-
- def do_put
- put :test, params: project_params(id: 'buildkite',
- service: integration_params)
- end
- end
- end
-
- context 'when unsuccessful' 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)
-
- put :test, params: project_params(service: integration_params)
-
- expect(response).to be_successful
- expect(json_response).to eq(
- 'error' => true,
- 'message' => 'Connection failed. Please check your settings.',
- 'service_response' => '',
- 'test_failed' => true
- )
- end
-
- context 'with the Slack integration' do
- let_it_be(:integration) { build(:integrations_slack) }
-
- it 'returns an error response when the URL is blocked' do
- put :test, params: project_params(service: { webhook: 'http://127.0.0.1' })
-
- expect(response).to be_successful
- expect(json_response).to eq(
- 'error' => true,
- 'message' => 'Connection failed. Please check your settings.',
- 'service_response' => "URL 'http://127.0.0.1' is blocked: Requests to localhost are not allowed",
- 'test_failed' => true
- )
- end
-
- it 'returns an error response when a network exception is raised' do
- expect_next(Integrations::Slack).to receive(:test).and_raise(Errno::ECONNREFUSED)
-
- put :test, params: project_params
-
- expect(response).to be_successful
- expect(json_response).to eq(
- 'error' => true,
- 'message' => 'Connection failed. Please check your settings.',
- 'service_response' => 'Connection refused',
- 'test_failed' => true
- )
- end
- end
- end
- end
-
- describe 'PUT #update' do
- describe 'as HTML' do
- let(:integration_params) { { active: true } }
- let(:params) { project_params(service: integration_params) }
-
- let(:message) { 'Jira settings saved and active.' }
- let(:redirect_url) { edit_project_integration_path(project, integration) }
-
- before do
- stub_jira_integration_test
-
- put :update, params: params
- end
-
- shared_examples 'integration update' do
- it 'redirects to the correct url with a flash message' do
- expect(response).to redirect_to(redirect_url)
- expect(flash[:notice]).to eq(message)
- end
- end
-
- context 'when param `active` is set to true' do
- let(:params) { project_params(service: integration_params, redirect_to: redirect) }
-
- context 'when redirect_to param is present' do
- let(:redirect) { '/redirect_here' }
- let(:redirect_url) { redirect }
-
- it_behaves_like 'integration update'
- end
-
- context 'when redirect_to is an external domain' do
- let(:redirect) { 'http://examle.com' }
-
- it_behaves_like 'integration update'
- end
-
- context 'when redirect_to param is an empty string' do
- let(:redirect) { '' }
-
- it_behaves_like 'integration update'
- end
- end
-
- context 'when param `active` is set to false' do
- let(:integration_params) { { active: false } }
- let(:message) { 'Jira settings saved, but not active.' }
-
- it_behaves_like 'integration update'
- end
-
- context 'when param `inherit_from_id` is set to empty string' do
- let(:integration_params) { { inherit_from_id: '' } }
-
- it 'sets inherit_from_id to nil' do
- expect(integration.reload.inherit_from_id).to eq(nil)
- end
- end
-
- context 'when param `inherit_from_id` is set to an instance integration' do
- let(:instance_integration) { create(:jira_integration, :instance, url: 'http://instance.com', password: 'instance') }
- let(:integration_params) { { inherit_from_id: instance_integration.id, url: 'http://custom.com', password: 'custom' } }
-
- it 'ignores submitted params and inherits instance settings' do
- expect(integration.reload).to have_attributes(
- inherit_from_id: instance_integration.id,
- url: instance_integration.url,
- password: instance_integration.password
- )
- end
- end
-
- context 'when param `inherit_from_id` is set to a group integration' do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
- let_it_be(:jira_integration) { create(:jira_integration, project: project) }
-
- let(:group_integration) { create(:jira_integration, :group, group: group, url: 'http://group.com', password: 'group') }
- let(:integration_params) { { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' } }
-
- it 'ignores submitted params and inherits group settings' do
- expect(integration.reload).to have_attributes(
- inherit_from_id: group_integration.id,
- url: group_integration.url,
- password: group_integration.password
- )
- end
- end
-
- context 'when param `inherit_from_id` is set to an unrelated group' do
- let_it_be(:group) { create(:group) }
-
- let(:group_integration) { create(:jira_integration, :group, group: group, url: 'http://group.com', password: 'group') }
- let(:integration_params) { { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' } }
-
- it 'ignores the param and saves the submitted settings' do
- expect(integration.reload).to have_attributes(
- inherit_from_id: nil,
- url: 'http://custom.com',
- password: 'custom'
- )
- end
- end
- end
-
- describe 'as JSON' do
- before do
- stub_jira_integration_test
- put :update, params: project_params(service: integration_params, format: :json)
- end
-
- context 'when update succeeds' do
- let(:integration_params) { { url: 'http://example.com', password: 'password' } }
-
- it 'returns success response' do
- expect(response).to be_successful
- expect(json_response).to include(
- 'active' => true,
- 'errors' => {}
- )
- end
- end
-
- context 'when update fails with missing password' do
- let(:integration_params) { { url: 'http://example.com' } }
-
- it 'returns JSON response errors' do
- expect(response).not_to be_successful
- expect(json_response).to include(
- 'active' => true,
- 'errors' => {
- 'password' => ["can't be blank"]
- }
- )
- end
- end
-
- context 'when update fails with invalid URL' do
- let(:integration_params) { { url: '', password: 'password' } }
-
- it 'returns JSON response with errors' do
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- expect(json_response).to include(
- 'active' => true,
- 'errors' => { 'url' => ['must be a valid URL', "can't be blank"] }
- )
- end
- end
- end
- end
-
- describe 'GET #edit' do
- context 'with Jira service' do
- let(:integration_param) { 'jira' }
-
- before do
- get :edit, params: project_params(id: integration_param)
- end
-
- context 'with approved services' do
- it 'renders edit page' do
- expect(response).to be_successful
- end
- end
- end
- end
-
- private
-
- def project_params(opts = {})
- opts.reverse_merge(
- namespace_id: project.namespace,
- project_id: project,
- id: integration.to_param
- )
- 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 7e96e99640a..d50f1aa1dd8 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -25,19 +25,6 @@ RSpec.describe Projects::Settings::CiCdController do
expect(response).to render_template(:show)
end
- context 'when the FF ci_owned_runners_cross_joins_fix is disabled' do
- before do
- stub_feature_flags(ci_owned_runners_cross_joins_fix: false)
- end
-
- it 'renders show with 200 status code' 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
-
context 'with CI/CD disabled' do
before do
project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
diff --git a/spec/controllers/projects/service_hook_logs_controller_spec.rb b/spec/controllers/projects/settings/integration_hook_logs_controller_spec.rb
index be78668aa88..8261461e8aa 100644
--- a/spec/controllers/projects/service_hook_logs_controller_spec.rb
+++ b/spec/controllers/projects/settings/integration_hook_logs_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ServiceHookLogsController do
+RSpec.describe Projects::Settings::IntegrationHookLogsController do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:integration) { create(:drone_ci_integration, project: project) }
@@ -44,7 +44,8 @@ RSpec.describe Projects::ServiceHookLogsController do
it 'executes the hook and redirects to the service form' do
expect_any_instance_of(ServiceHook).to receive(:execute)
expect_any_instance_of(described_class).to receive(:set_hook_execution_notice)
- expect(subject).to redirect_to(edit_project_integration_path(project, integration))
+
+ expect(subject).to redirect_to(edit_project_settings_integration_path(project, integration))
end
it 'renders a 404 if the hook does not exist' do
diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb
index 0652786c787..e6ca088a533 100644
--- a/spec/controllers/projects/settings/integrations_controller_spec.rb
+++ b/spec/controllers/projects/settings/integrations_controller_spec.rb
@@ -3,20 +3,388 @@
require 'spec_helper'
RSpec.describe Projects::Settings::IntegrationsController do
- let(:project) { create(:project, :public) }
- let(:user) { create(:user) }
+ include JiraIntegrationHelpers
+ include AfterNextHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:jira_integration) { create(:jira_integration, project: project) }
+
+ let(:integration) { jira_integration }
+ let(:integration_params) { { username: 'username', password: 'password', url: 'http://example.com' } }
before do
- project.add_maintainer(user)
sign_in(user)
+ project.add_maintainer(user)
+ end
+
+ it_behaves_like Integrations::Actions do
+ let(:integration_attributes) { { project: project } }
+
+ let(:routing_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: integration.to_param
+ }
+ end
end
- describe 'GET show' do
- it 'renders show with 200 status code' do
- get :show, params: { namespace_id: project.namespace, project_id: project }
+ describe 'GET index' do
+ it 'renders index with 200 status code' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:show)
+ expect(response).to render_template(:index)
+ end
+ end
+
+ describe '#test' do
+ context 'when the integration is not testable' do
+ it 'renders 404' do
+ allow_any_instance_of(Integration).to receive(:testable?).and_return(false)
+
+ put :test, params: project_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when validations fail' do
+ let(:integration_params) { { active: 'true', url: '' } }
+
+ it 'returns error messages in JSON response' do
+ put :test, params: project_params(service: integration_params)
+
+ expect(json_response['message']).to eq 'Validations failed.'
+ expect(json_response['service_response']).to include "Url can't be blank"
+ expect(response).to be_successful
+ end
+ end
+
+ context 'when successful' do
+ context 'with empty project' do
+ let_it_be(:project) { create(:project) }
+
+ context 'with chat notification integration' do
+ let_it_be(:teams_integration) { project.create_microsoft_teams_integration(webhook: 'http://webhook.com') }
+
+ let(:integration) { teams_integration }
+
+ it 'returns success' do
+ allow_next(::MicrosoftTeams::Notifier).to receive(:ping).and_return(true)
+
+ put :test, params: project_params
+
+ expect(response).to be_successful
+ end
+ end
+
+ it 'returns success' do
+ stub_jira_integration_test
+
+ expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
+
+ put :test, params: project_params(service: integration_params)
+
+ expect(response).to be_successful
+ end
+ end
+
+ it 'returns success' do
+ stub_jira_integration_test
+
+ expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
+
+ put :test, params: project_params(service: integration_params)
+
+ expect(response).to be_successful
+ end
+
+ context 'when service is configured for the first time' do
+ let(:integration_params) do
+ {
+ 'active' => '1',
+ 'push_events' => '1',
+ 'token' => 'token',
+ 'project_url' => 'https://buildkite.com/organization/pipeline'
+ }
+ end
+
+ before do
+ allow_next(ServiceHook).to receive(:execute).and_return(true)
+ end
+
+ it 'persist the object' do
+ do_put
+
+ expect(response).to be_successful
+ expect(json_response).to be_empty
+ expect(Integrations::Buildkite.first).to be_present
+ end
+
+ it 'creates the ServiceHook object' do
+ do_put
+
+ expect(response).to be_successful
+ expect(json_response).to be_empty
+ expect(Integrations::Buildkite.first.service_hook).to be_present
+ end
+
+ def do_put
+ put :test, params: project_params(id: 'buildkite',
+ service: integration_params)
+ end
+ end
+ end
+
+ context 'when unsuccessful' 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)
+
+ put :test, params: project_params(service: integration_params)
+
+ expect(response).to be_successful
+ expect(json_response).to eq(
+ 'error' => true,
+ 'message' => 'Connection failed. Please check your settings.',
+ 'service_response' => '',
+ 'test_failed' => true
+ )
+ end
+
+ context 'with the Slack integration' do
+ let_it_be(:integration) { build(:integrations_slack) }
+
+ it 'returns an error response when the URL is blocked' do
+ put :test, params: project_params(service: { webhook: 'http://127.0.0.1' })
+
+ expect(response).to be_successful
+ expect(json_response).to eq(
+ 'error' => true,
+ 'message' => 'Connection failed. Please check your settings.',
+ 'service_response' => "URL 'http://127.0.0.1' is blocked: Requests to localhost are not allowed",
+ 'test_failed' => true
+ )
+ end
+
+ it 'returns an error response when a network exception is raised' do
+ expect_next(Integrations::Slack).to receive(:test).and_raise(Errno::ECONNREFUSED)
+
+ put :test, params: project_params
+
+ expect(response).to be_successful
+ expect(json_response).to eq(
+ 'error' => true,
+ 'message' => 'Connection failed. Please check your settings.',
+ 'service_response' => 'Connection refused',
+ 'test_failed' => true
+ )
+ end
+ end
+ end
+ end
+
+ describe 'PUT #update' do
+ describe 'as HTML' do
+ let(:integration_params) { { active: true } }
+ let(:params) { project_params(service: integration_params) }
+
+ let(:message) { 'Jira settings saved and active.' }
+ let(:redirect_url) { edit_project_settings_integration_path(project, integration) }
+
+ before do
+ stub_jira_integration_test
+
+ put :update, params: params
+ end
+
+ shared_examples 'integration update' do
+ it 'redirects to the correct url with a flash message' do
+ expect(response).to redirect_to(redirect_url)
+ expect(flash[:notice]).to eq(message)
+ end
+ end
+
+ context 'when update fails' do
+ let(:integration_params) { { url: 'https://new.com', password: '' } }
+
+ it 'renders the edit form' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:edit)
+ expect(integration.reload.url).not_to eq('https://new.com')
+ end
+ end
+
+ context 'when param `active` is set to true' do
+ let(:params) { project_params(service: integration_params, redirect_to: redirect) }
+
+ context 'when redirect_to param is present' do
+ let(:redirect) { '/redirect_here' }
+ let(:redirect_url) { redirect }
+
+ it_behaves_like 'integration update'
+ end
+
+ context 'when redirect_to is an external domain' do
+ let(:redirect) { 'http://examle.com' }
+
+ it_behaves_like 'integration update'
+ end
+
+ context 'when redirect_to param is an empty string' do
+ let(:redirect) { '' }
+
+ it_behaves_like 'integration update'
+ end
+ end
+
+ context 'when param `active` is set to false' do
+ let(:integration_params) { { active: false } }
+ let(:message) { 'Jira settings saved, but not active.' }
+
+ it_behaves_like 'integration update'
+ end
+
+ context 'when param `inherit_from_id` is set to empty string' do
+ let(:integration_params) { { inherit_from_id: '' } }
+
+ it 'sets inherit_from_id to nil' do
+ expect(integration.reload.inherit_from_id).to eq(nil)
+ end
+ end
+
+ context 'when param `inherit_from_id` is set to an instance integration' do
+ let(:instance_integration) do
+ create(:jira_integration, :instance, url: 'http://instance.com', password: 'instance')
+ end
+
+ let(:integration_params) do
+ { inherit_from_id: instance_integration.id, url: 'http://custom.com', password: 'custom' }
+ end
+
+ it 'ignores submitted params and inherits instance settings' do
+ expect(integration.reload).to have_attributes(
+ inherit_from_id: instance_integration.id,
+ url: instance_integration.url,
+ password: instance_integration.password
+ )
+ end
+ end
+
+ context 'when param `inherit_from_id` is set to a group integration' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:jira_integration) { create(:jira_integration, project: project) }
+
+ let(:group_integration) do
+ create(:jira_integration, :group, group: group, url: 'http://group.com', password: 'group')
+ end
+
+ let(:integration_params) do
+ { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' }
+ end
+
+ it 'ignores submitted params and inherits group settings' do
+ expect(integration.reload).to have_attributes(
+ inherit_from_id: group_integration.id,
+ url: group_integration.url,
+ password: group_integration.password
+ )
+ end
+ end
+
+ context 'when param `inherit_from_id` is set to an unrelated group' do
+ let_it_be(:group) { create(:group) }
+
+ let(:group_integration) do
+ create(:jira_integration, :group, group: group, url: 'http://group.com', password: 'group')
+ end
+
+ let(:integration_params) do
+ { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' }
+ end
+
+ it 'ignores the param and saves the submitted settings' do
+ expect(integration.reload).to have_attributes(
+ inherit_from_id: nil,
+ url: 'http://custom.com',
+ password: 'custom'
+ )
+ end
+ end
+ end
+
+ describe 'as JSON' do
+ before do
+ stub_jira_integration_test
+ put :update, params: project_params(service: integration_params, format: :json)
+ end
+
+ context 'when update succeeds' do
+ let(:integration_params) { { url: 'http://example.com', password: 'password' } }
+
+ it 'returns success response' do
+ expect(response).to be_successful
+ expect(json_response).to include(
+ 'active' => true,
+ 'errors' => {}
+ )
+ end
+ end
+
+ context 'when update fails with missing password' do
+ let(:integration_params) { { url: 'http://example.com' } }
+
+ it 'returns JSON response errors' do
+ expect(response).not_to be_successful
+ expect(json_response).to include(
+ 'active' => true,
+ 'errors' => {
+ 'password' => ["can't be blank"]
+ }
+ )
+ end
+ end
+
+ context 'when update fails with invalid URL' do
+ let(:integration_params) { { url: '', password: 'password' } }
+
+ it 'returns JSON response with errors' do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to include(
+ 'active' => true,
+ 'errors' => { 'url' => ['must be a valid URL', "can't be blank"] }
+ )
+ end
+ end
+ end
+ end
+
+ describe 'GET #edit' do
+ context 'with Jira service' do
+ let(:integration_param) { 'jira' }
+
+ before do
+ get :edit, params: project_params(id: integration_param)
+ end
+
+ context 'with approved services' do
+ it 'renders edit page' do
+ expect(response).to be_successful
+ end
+ end
end
end
+
+ private
+
+ def project_params(opts = {})
+ opts.reverse_merge(
+ namespace_id: project.namespace,
+ project_id: project,
+ id: integration.to_param
+ )
+ end
end
diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb
deleted file mode 100644
index e1f25589eeb..00000000000
--- a/spec/controllers/projects/static_site_editor_controller_spec.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::StaticSiteEditorController do
- let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:user) { create(:user) }
-
- let(:data) { { key: 'value' } }
-
- describe 'GET index' do
- let(:default_params) do
- {
- namespace_id: project.namespace,
- project_id: project
- }
- end
-
- it 'responds with 404 page' do
- get :index, params: default_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- describe 'GET show' do
- render_views
-
- let(:default_params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- id: 'master/README.md',
- return_url: 'http://example.com'
- }
- end
-
- let(:service_response) do
- ServiceResponse.success(payload: data)
- end
-
- before do
- allow_next_instance_of(::StaticSiteEditor::ConfigService) do |instance|
- allow(instance).to receive(:execute).and_return(service_response)
- end
- end
-
- context 'User roles' do
- context 'anonymous' do
- before do
- get :show, params: default_params
- end
-
- it 'redirects to sign in and returns' do
- expect(response).to redirect_to(new_user_session_path)
- end
- end
-
- context 'as guest' do
- before do
- project.add_guest(user)
- sign_in(user)
- get :show, params: default_params
- end
-
- it 'responds with 404 page' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context "as developer" do
- before do
- allow(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to receive(:increment_views_count)
- project.add_role(user, 'developer')
- sign_in(user)
- get :show, params: default_params
- end
-
- it 'redirects to the Web IDE' do
- get :show, params: default_params
-
- expected_path_regex = %r[-/ide/project/#{project.full_path}/edit/master/-/README.md]
- expect(response).to redirect_to(expected_path_regex)
- end
-
- it 'assigns ref and path variables' do
- expect(assigns(:ref)).to eq('master')
- expect(assigns(:path)).to eq('README.md')
- end
-
- context 'when combination of ref and path is incorrect' do
- let(:default_params) { super().merge(id: 'unknown') }
-
- it 'responds with 404 page' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
- end
- end
-end
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index d0971e96910..3d1f8c12022 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -205,15 +205,13 @@ RSpec.describe Projects::TagsController do
before do
project.add_developer(user)
sign_in(user)
- end
-
- it 'deletes tag' do
request
+ end
- expect(response).to be_successful
- expect(response.body).to include("Tag was removed")
-
+ it 'deletes tag and redirects to tags path' do
expect(project.repository.find_tag(tag.name)).not_to be_present
+ expect(controller).to set_flash[:notice].to(/Tag was removed/)
+ expect(response).to redirect_to(project_tags_path(project))
end
end
end