summaryrefslogtreecommitdiff
path: root/spec/controllers/projects
diff options
context:
space:
mode:
Diffstat (limited to 'spec/controllers/projects')
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb42
-rw-r--r--spec/controllers/projects/cycle_analytics_controller_spec.rb7
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb46
-rw-r--r--spec/controllers/projects/discussions_controller_spec.rb3
-rw-r--r--spec/controllers/projects/environments/prometheus_api_controller_spec.rb206
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb45
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb9
-rw-r--r--spec/controllers/projects/imports_controller_spec.rb171
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb39
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb103
-rw-r--r--spec/controllers/projects/logs_controller_spec.rb28
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb12
-rw-r--r--spec/controllers/projects/merge_requests/drafts_controller_spec.rb9
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb4
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb84
-rw-r--r--spec/controllers/projects/pipelines/stages_controller_spec.rb (renamed from spec/controllers/projects/stages_controller_spec.rb)4
-rw-r--r--spec/controllers/projects/pipelines/tests_controller_spec.rb112
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb95
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb23
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb9
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb11
-rw-r--r--spec/controllers/projects/service_desk_controller_spec.rb111
-rw-r--r--spec/controllers/projects/services_controller_spec.rb19
-rw-r--r--spec/controllers/projects/settings/operations_controller_spec.rb100
-rw-r--r--spec/controllers/projects/snippets/blobs_controller_spec.rb85
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb28
-rw-r--r--spec/controllers/projects/tree_controller_spec.rb28
-rw-r--r--spec/controllers/projects/wikis_controller_spec.rb2
28 files changed, 961 insertions, 474 deletions
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 5645e25b741..da4faad2a39 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -200,6 +200,48 @@ RSpec.describe Projects::ClustersController do
end
end
+ describe 'GET #prometheus_proxy' do
+ let(:proxyable) do
+ create(:cluster, :provided_by_gcp, projects: [project])
+ end
+
+ it_behaves_like 'metrics dashboard prometheus api proxy' do
+ let(:proxyable_params) do
+ {
+ id: proxyable.id.to_s,
+ namespace_id: project.namespace.full_path,
+ project_id: project.name
+ }
+ end
+
+ context 'with anonymous user' do
+ let(:prometheus_body) { nil }
+
+ before do
+ sign_out(user)
+ end
+
+ it 'redirects to signin page' do
+ get :prometheus_proxy, params: prometheus_proxy_params
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+ end
+
+ it_behaves_like 'GET #metrics_dashboard for dashboard', 'Cluster health' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
+
+ let(:metrics_dashboard_req_params) do
+ {
+ id: cluster.id,
+ namespace_id: project.namespace.full_path,
+ project_id: project.name
+ }
+ end
+ end
+
describe 'POST create for new cluster' do
let(:legacy_abac_param) { 'true' }
let(:params) do
diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb
index 8feb964cdde..ec853b74b9b 100644
--- a/spec/controllers/projects/cycle_analytics_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb
@@ -25,6 +25,13 @@ RSpec.describe Projects::CycleAnalyticsController do
end
end
+ context 'tracking visits to html page' do
+ it_behaves_like 'tracking unique visits', :show do
+ let(:request_params) { { namespace_id: project.namespace, project_id: project } }
+ let(:target_id) { 'p_analytics_valuestream' }
+ end
+ end
+
describe 'cycle analytics not set up flag' do
context 'with no data' do
it 'is true' do
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
index 85dd86d91e9..c6532e83441 100644
--- a/spec/controllers/projects/deployments_controller_spec.rb
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -36,6 +36,52 @@ RSpec.describe Projects::DeploymentsController do
expect(response).to be_ok
expect(response).to match_response_schema('deployments')
end
+
+ context 'anonymous user' do
+ let(:anonymous_user) { create(:user) }
+
+ before do
+ sign_in(anonymous_user)
+ end
+
+ context 'project and metrics dashboard are public' do
+ before do
+ project.update!(
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC,
+ project_feature_attributes: {
+ metrics_dashboard_access_level: Gitlab::VisibilityLevel::PUBLIC
+ }
+ )
+ end
+
+ it 'returns a list with deployments information' do
+ create(:deployment, :success, environment: environment)
+
+ get :index, params: deployment_params
+
+ expect(response).to be_ok
+ end
+ end
+
+ context 'project and metrics dashboard are private' do
+ before do
+ project.update!(
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE,
+ project_feature_attributes: {
+ metrics_dashboard_access_level: Gitlab::VisibilityLevel::PRIVATE
+ }
+ )
+ end
+
+ it 'responds with not found' do
+ create(:deployment, :success, environment: environment)
+
+ get :index, params: deployment_params
+
+ expect(response).to be_not_found
+ end
+ end
+ end
end
describe 'GET #metrics' do
diff --git a/spec/controllers/projects/discussions_controller_spec.rb b/spec/controllers/projects/discussions_controller_spec.rb
index f2efd40afdb..f9d16e761cb 100644
--- a/spec/controllers/projects/discussions_controller_spec.rb
+++ b/spec/controllers/projects/discussions_controller_spec.rb
@@ -182,7 +182,8 @@ RSpec.describe Projects::DiscussionsController do
it "unresolves the discussion" do
delete :unresolve, params: request_params
- expect(note.reload.discussion.resolved?).to be false
+ # discussion is memoized and reload doesn't clear the memoization
+ expect(Note.find(note.id).discussion.resolved?).to be false
end
it "returns status 200" do
diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
index 17952aa0683..68d50cf19f0 100644
--- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
+++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
@@ -3,215 +3,73 @@
require 'spec_helper'
RSpec.describe Projects::Environments::PrometheusApiController do
- let_it_be(:project) { create(:project) }
- let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:proxyable) { create(:environment, project: project) }
before do
project.add_reporter(user)
sign_in(user)
end
- describe 'GET #proxy' do
- let(:prometheus_proxy_service) { instance_double(Prometheus::ProxyService) }
-
- let(:expected_params) do
- ActionController::Parameters.new(
- environment_params(
- proxy_path: 'query',
- controller: 'projects/environments/prometheus_api',
- action: 'proxy'
- )
- ).permit!
- end
-
- context 'with valid requests' do
- before do
- allow(Prometheus::ProxyService).to receive(:new)
- .with(environment, 'GET', 'query', expected_params)
- .and_return(prometheus_proxy_service)
-
- allow(prometheus_proxy_service).to receive(:execute)
- .and_return(service_result)
+ describe 'GET #prometheus_proxy' do
+ it_behaves_like 'metrics dashboard prometheus api proxy' do
+ let(:proxyable_params) do
+ {
+ id: proxyable.id.to_s,
+ namespace_id: project.namespace.full_path,
+ project_id: project.name
+ }
end
- context 'with success result' do
- let(:service_result) { { status: :success, body: prometheus_body } }
+ context 'with variables' do
let(:prometheus_body) { '{"status":"success"}' }
- let(:prometheus_json_body) { Gitlab::Json.parse(prometheus_body) }
+ let(:pod_name) { "pod1" }
- it 'returns prometheus response' do
- get :proxy, params: environment_params
-
- expect(Prometheus::ProxyService).to have_received(:new)
- .with(environment, 'GET', 'query', expected_params)
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to eq(prometheus_json_body)
+ before do
+ expected_params[:query] = %{up{pod_name="#{pod_name}"}}
+ expected_params[:variables] = { 'pod_name' => pod_name }
end
- context 'with format string' do
- before do
- expected_params[:query] = %{up{environment="#{environment.slug}"}}
- end
-
- it 'replaces variables with values' do
- get :proxy, params: environment_params.merge(query: 'up{environment="{{ci_environment_slug}}"}')
-
- expect(Prometheus::ProxyService).to have_received(:new)
- .with(environment, 'GET', 'query', expected_params)
- end
-
- context 'with nil query' do
- let(:params_without_query) do
- environment_params.except(:query)
- end
-
- before do
- expected_params.delete(:query)
- end
-
- it 'does not raise error' do
- get :proxy, params: params_without_query
+ it 'replaces variables with values' do
+ get :prometheus_proxy, params: prometheus_proxy_params.merge(
+ query: 'up{pod_name="{{pod_name}}"}', variables: { 'pod_name' => pod_name }
+ )
- expect(Prometheus::ProxyService).to have_received(:new)
- .with(environment, 'GET', 'query', expected_params)
- end
- end
+ expect(response).to have_gitlab_http_status(:success)
+ expect(Prometheus::ProxyService).to have_received(:new)
+ .with(proxyable, 'GET', 'query', expected_params)
end
- context 'with variables' do
- let(:pod_name) { "pod1" }
-
- before do
- expected_params[:query] = %{up{pod_name="#{pod_name}"}}
- expected_params[:variables] = { 'pod_name' => pod_name }
- end
-
- it 'replaces variables with values' do
- get :proxy, params: environment_params.merge(
- query: 'up{pod_name="{{pod_name}}"}', variables: { 'pod_name' => pod_name }
+ context 'with invalid variables' do
+ let(:params_with_invalid_variables) do
+ prometheus_proxy_params.merge(
+ query: 'up{pod_name="{{pod_name}}"}', variables: ['a']
)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(Prometheus::ProxyService).to have_received(:new)
- .with(environment, 'GET', 'query', expected_params)
- end
-
- context 'with invalid variables' do
- let(:params_with_invalid_variables) do
- environment_params.merge(
- query: 'up{pod_name="{{pod_name}}"}', variables: ['a']
- )
- end
-
- it 'returns 400' do
- get :proxy, params: params_with_invalid_variables
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(Prometheus::ProxyService).not_to receive(:new)
- end
- end
- end
- end
-
- context 'with nil result' do
- let(:service_result) { nil }
-
- it 'returns 204 no_content' do
- get :proxy, params: environment_params
-
- expect(json_response['status']).to eq(_('processing'))
- expect(json_response['message']).to eq(_('Not ready yet. Try again later.'))
- expect(response).to have_gitlab_http_status(:no_content)
- end
- end
-
- context 'with 404 result' do
- let(:service_result) { { http_status: 404, status: :success, body: '{"body": "value"}' } }
-
- it 'returns body' do
- get :proxy, params: environment_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['body']).to eq('value')
- end
- end
-
- context 'with error result' do
- context 'with http_status' do
- let(:service_result) do
- { http_status: :service_unavailable, status: :error, message: 'error message' }
- end
-
- it 'sets the http response status code' do
- get :proxy, params: environment_params
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- expect(json_response['status']).to eq('error')
- expect(json_response['message']).to eq('error message')
end
- end
-
- context 'without http_status' do
- let(:service_result) { { status: :error, message: 'error message' } }
- it 'returns bad_request' do
- get :proxy, params: environment_params
+ it 'returns 400' do
+ get :prometheus_proxy, params: params_with_invalid_variables
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['status']).to eq('error')
- expect(json_response['message']).to eq('error message')
+ expect(Prometheus::ProxyService).not_to receive(:new)
end
end
end
- end
- context 'with inappropriate requests' do
context 'with anonymous user' do
+ let(:prometheus_body) { nil }
+
before do
sign_out(user)
end
it 'redirects to signin page' do
- get :proxy, params: environment_params
+ get :prometheus_proxy, params: prometheus_proxy_params
expect(response).to redirect_to(new_user_session_path)
end
end
-
- context 'without correct permissions' do
- before do
- project.team.truncate
- end
-
- it 'returns 404' do
- get :proxy, params: environment_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
end
-
- context 'with invalid environment id' do
- let(:other_environment) { create(:environment) }
-
- it 'returns 404' do
- get :proxy, params: environment_params(id: other_environment.id)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- private
-
- def environment_params(params = {})
- {
- id: environment.id.to_s,
- namespace_id: project.namespace.full_path,
- project_id: project.name,
- proxy_path: 'query',
- query: '1'
- }.merge(params)
end
end
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index cca4b597f4c..85ec1f7396d 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -546,28 +546,20 @@ RSpec.describe Projects::EnvironmentsController do
end
describe 'GET #metrics_dashboard' do
- shared_examples_for 'correctly formatted response' do |status_code|
- it 'returns a json object with the correct keys' do
- get :metrics_dashboard, params: environment_params(dashboard_params)
-
- # Exlcude `all_dashboards` to handle separately.
- found_keys = json_response.keys - ['all_dashboards']
-
- expect(response).to have_gitlab_http_status(status_code)
- expect(found_keys).to contain_exactly(*expected_keys)
- end
- end
+ let(:metrics_dashboard_req_params) { environment_params(dashboard_params) }
shared_examples_for '200 response' do
- let(:expected_keys) { %w(dashboard status metrics_data) }
-
- it_behaves_like 'correctly formatted response', :ok
+ it_behaves_like 'GET #metrics_dashboard correctly formatted response' do
+ let(:expected_keys) { %w(dashboard status metrics_data) }
+ let(:status_code) { :ok }
+ end
end
shared_examples_for 'error response' do |status_code|
- let(:expected_keys) { %w(message status) }
-
- it_behaves_like 'correctly formatted response', status_code
+ it_behaves_like 'GET #metrics_dashboard correctly formatted response' do
+ let(:expected_keys) { %w(message status) }
+ let(:status_code) { status_code }
+ end
end
shared_examples_for 'includes all dashboards' do
@@ -581,29 +573,14 @@ RSpec.describe Projects::EnvironmentsController do
end
shared_examples_for 'the default dashboard' do
- it_behaves_like '200 response'
it_behaves_like 'includes all dashboards'
-
- it 'is the default dashboard' do
- get :metrics_dashboard, params: environment_params(dashboard_params)
-
- expect(json_response['dashboard']['dashboard']).to eq('Environment metrics')
- end
+ it_behaves_like 'GET #metrics_dashboard for dashboard', 'Environment metrics'
end
shared_examples_for 'the specified dashboard' do |expected_dashboard|
- it_behaves_like '200 response'
it_behaves_like 'includes all dashboards'
- it 'has the correct name' do
- get :metrics_dashboard, params: environment_params(dashboard_params)
-
- dashboard_name = json_response['dashboard']['dashboard']
-
- # 'Environment metrics' is the default dashboard.
- expect(dashboard_name).not_to eq('Environment metrics')
- expect(dashboard_name).to eq(expected_dashboard)
- end
+ it_behaves_like 'GET #metrics_dashboard for dashboard', expected_dashboard
context 'when the dashboard cannot not be processed' do
before do
diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb
index 12cef6bea09..49def8f80b0 100644
--- a/spec/controllers/projects/graphs_controller_spec.rb
+++ b/spec/controllers/projects/graphs_controller_spec.rb
@@ -80,6 +80,15 @@ RSpec.describe Projects::GraphsController do
expect(assigns[:daily_coverage_options]).to be_nil
end
end
+
+ it_behaves_like 'tracking unique visits', :charts do
+ before do
+ sign_in(user)
+ end
+
+ let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } }
+ let(:target_id) { 'p_analytics_repo' }
+ end
end
context 'when languages were previously detected' do
diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb
index 29cfd1c352e..029b4210f19 100644
--- a/spec/controllers/projects/imports_controller_spec.rb
+++ b/spec/controllers/projects/imports_controller_spec.rb
@@ -8,33 +8,15 @@ RSpec.describe Projects::ImportsController do
before do
sign_in(user)
- project.add_maintainer(user)
end
describe 'GET #show' do
- context 'when repository does not exists' do
- it 'renders template' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
-
- expect(response).to render_template :show
- end
-
- it 'sets flash.now if params is present' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'Started' } }
-
- expect(flash.now[:notice]).to eq 'Started'
+ context 'when the user has maintainer rights' do
+ before do
+ project.add_maintainer(user)
end
- end
-
- context 'when repository exists' do
- let(:project) { create(:project_empty_repo, import_url: 'https://github.com/vim/vim.git') }
- let(:import_state) { project.import_state }
-
- context 'when import is in progress' do
- before do
- import_state.update(status: :started)
- end
+ context 'when repository does not exists' do
it 'renders template' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
@@ -42,82 +24,138 @@ RSpec.describe Projects::ImportsController do
end
it 'sets flash.now if params is present' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'In progress' } }
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'Started' } }
- expect(flash.now[:notice]).to eq 'In progress'
+ expect(flash.now[:notice]).to eq 'Started'
end
end
- context 'when import failed' do
- before do
- import_state.update(status: :failed)
- end
+ context 'when repository exists' do
+ let(:project) { create(:project_empty_repo, import_url: 'https://github.com/vim/vim.git') }
+ let(:import_state) { project.import_state }
- it 'redirects to new_namespace_project_import_path' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+ context 'when import is in progress' do
+ before do
+ import_state.update(status: :started)
+ end
- expect(response).to redirect_to new_project_import_path(project)
- end
- end
+ it 'renders template' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
- context 'when import finished' do
- before do
- import_state.update(status: :finished)
+ expect(response).to render_template :show
+ end
+
+ it 'sets flash.now if params is present' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'In progress' } }
+
+ expect(flash.now[:notice]).to eq 'In progress'
+ end
end
- context 'when project is a fork' do
- it 'redirects to namespace_project_path' do
- allow_any_instance_of(Project).to receive(:forked?).and_return(true)
+ context 'when import failed' do
+ before do
+ import_state.update(status: :failed)
+ end
+ it 'redirects to new_namespace_project_import_path' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
- expect(flash[:notice]).to eq 'The project was successfully forked.'
- expect(response).to redirect_to project_path(project)
+ expect(response).to redirect_to new_project_import_path(project)
end
end
- context 'when project is external' do
- it 'redirects to namespace_project_path' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+ context 'when import finished' do
+ before do
+ import_state.update(status: :finished)
+ end
- expect(flash[:notice]).to eq 'The project was successfully imported.'
- expect(response).to redirect_to project_path(project)
+ context 'when project is a fork' do
+ it 'redirects to namespace_project_path' do
+ allow_any_instance_of(Project).to receive(:forked?).and_return(true)
+
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+
+ expect(flash[:notice]).to eq 'The project was successfully forked.'
+ expect(response).to redirect_to project_path(project)
+ end
end
- end
- context 'when continue params is present' do
- let(:params) do
- {
- to: project_path(project),
- notice: 'Finished'
- }
+ context 'when project is external' do
+ it 'redirects to namespace_project_path' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+
+ expect(flash[:notice]).to eq 'The project was successfully imported.'
+ expect(response).to redirect_to project_path(project)
+ end
end
- it 'redirects to internal params[:to]' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: params }
+ context 'when continue params is present' do
+ let(:params) do
+ {
+ to: project_path(project),
+ notice: 'Finished'
+ }
+ end
+
+ it 'redirects to internal params[:to]' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: params }
+
+ expect(flash[:notice]).to eq params[:notice]
+ expect(response).to redirect_to params[:to]
+ end
- expect(flash[:notice]).to eq params[:notice]
- expect(response).to redirect_to params[:to]
+ it 'does not redirect to external params[:to]' do
+ params[:to] = "//google.com"
+
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: params }
+ expect(response).not_to redirect_to params[:to]
+ end
end
+ end
- it 'does not redirect to external params[:to]' do
- params[:to] = "//google.com"
+ context 'when import never happened' do
+ before do
+ import_state.update(status: :none)
+ end
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project, continue: params }
- expect(response).not_to redirect_to params[:to]
+ it 'redirects to namespace_project_path' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+
+ expect(response).to redirect_to project_path(project)
end
end
end
+ end
+
+ context 'when project is in group' do
+ let(:project) { create(:project_empty_repo, import_url: 'https://github.com/vim/vim.git', namespace: group) }
+
+ context 'when user has developer access to group and import is in progress' do
+ let(:import_state) { project.import_state }
- context 'when import never happened' do
before do
- import_state.update(status: :none)
+ group.add_developer(user)
+ import_state.update!(status: :started)
end
- it 'redirects to namespace_project_path' do
- get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+ context 'when group allows developers to create projects' do
+ let(:group) { create(:group, project_creation_level: Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
- expect(response).to redirect_to project_path(project)
+ it 'renders template' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+
+ expect(response).to render_template :show
+ end
+ end
+
+ context 'when group prohibits developers to create projects' do
+ let(:group) { create(:group, project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
+
+ it 'returns 404 response' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
end
end
@@ -128,6 +166,7 @@ RSpec.describe Projects::ImportsController do
let(:project) { create(:project) }
before do
+ project.add_maintainer(user)
allow(RepositoryImportWorker).to receive(:perform_async)
post :create, params: { project: params, namespace_id: project.namespace.to_param, project_id: project }
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index bcd1a53bd47..f9580c79390 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -237,7 +237,7 @@ RSpec.describe Projects::IssuesController do
context 'external issue tracker' do
let!(:service) do
- create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', new_issue_url: 'http://test.com')
+ create(:custom_issue_tracker_service, project: project, new_issue_url: 'http://test.com')
end
before do
@@ -1564,6 +1564,43 @@ RSpec.describe Projects::IssuesController do
end
end
+ describe 'GET service_desk' do
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:support_bot) { User.support_bot }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:service_desk_issue_1) { create(:issue, project: project, author: support_bot) }
+ let_it_be(:service_desk_issue_2) { create(:issue, project: project, author: support_bot, assignees: [other_user]) }
+ let_it_be(:other_user_issue) { create(:issue, project: project, author: other_user) }
+
+ def get_service_desk(extra_params = {})
+ get :service_desk, params: extra_params.merge(namespace_id: project.namespace, project_id: project)
+ end
+
+ it 'adds an author filter for the support bot user' do
+ get_service_desk
+
+ expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
+ end
+
+ it 'does not allow any other author to be set' do
+ get_service_desk(author_username: other_user.username)
+
+ expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
+ end
+
+ it 'supports other filters' do
+ get_service_desk(assignee_username: other_user.username)
+
+ expect(assigns(:issues)).to contain_exactly(service_desk_issue_2)
+ end
+
+ it 'allows an assignee to be specified by id' do
+ get_service_desk(assignee_id: other_user.id)
+
+ expect(assigns(:users)).to contain_exactly(other_user, support_bot)
+ end
+ end
+
describe 'GET #discussions' do
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 44dcb0caab2..818b1c30b37 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -646,109 +646,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
end
- describe 'GET legacy trace.json' do
- before do
- stub_feature_flags(job_log_json: false)
- get_trace
- end
-
- context 'when job has a trace artifact' do
- let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
-
- it 'returns a trace' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['id']).to eq job.id
- expect(json_response['status']).to eq job.status
- expect(json_response['state']).to be_present
- expect(json_response['append']).not_to be_nil
- expect(json_response['truncated']).not_to be_nil
- expect(json_response['size']).to be_present
- expect(json_response['total']).to be_present
- expect(json_response['html']).to eq(job.trace.html)
- end
- end
-
- context 'when job has a trace' do
- let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
-
- it 'returns a trace' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['id']).to eq job.id
- expect(json_response['status']).to eq job.status
- expect(json_response['html']).to eq('<span>BUILD TRACE</span>')
- end
- end
-
- context 'when job has no traces' do
- let(:job) { create(:ci_build, pipeline: pipeline) }
-
- it 'returns no traces' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['id']).to eq job.id
- expect(json_response['status']).to eq job.status
- expect(json_response['html']).to be_nil
- end
- end
-
- context 'when job has a trace with ANSI sequence and Unicode' do
- let(:job) { create(:ci_build, :unicode_trace_live, pipeline: pipeline) }
-
- it 'returns a trace with Unicode' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['id']).to eq job.id
- expect(json_response['status']).to eq job.status
- expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ")
- end
- end
-
- context 'when trace artifact is in ObjectStorage' do
- let(:url) { 'http://object-storage/trace' }
- let(:file_path) { expand_fixture_path('trace/sample_trace') }
- let!(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) }
-
- before do
- allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
- allow_any_instance_of(JobArtifactUploader).to receive(:url) { url }
- allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) }
- end
-
- context 'when there are no network issues' do
- before do
- stub_remote_url_206(url, file_path)
-
- get_trace
- end
-
- it 'returns a trace' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['id']).to eq job.id
- expect(json_response['status']).to eq job.status
- expect(json_response['html']).to eq(job.trace.html)
- end
- end
-
- context 'when there is a network issue' do
- before do
- stub_remote_url_500(url)
- end
-
- it 'returns a trace' do
- expect { get_trace }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError)
- end
- end
- end
-
- def get_trace
- get :trace,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: job.id
- },
- format: :json
- end
- end
-
describe 'GET status.json' do
let(:job) { create(:ci_build, pipeline: pipeline) }
let(:status) { job.detailed_status(double('user')) }
diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb
index 1eb5a6fcc12..0f34e536064 100644
--- a/spec/controllers/projects/logs_controller_spec.rb
+++ b/spec/controllers/projects/logs_controller_spec.rb
@@ -104,6 +104,34 @@ RSpec.describe Projects::LogsController do
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 }
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 02b4c2d1da9..217447c2ad6 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -91,6 +91,17 @@ RSpec.describe Projects::MergeRequests::DiffsController do
end
end
+ shared_examples "diff note on-demand position creation" do
+ it "updates diff discussion positions" do
+ service = double("service")
+
+ expect(Discussions::CaptureDiffNotePositionsService).to receive(:new).with(merge_request).and_return(service)
+ expect(service).to receive(:execute)
+
+ go
+ end
+ end
+
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
@@ -146,6 +157,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
it_behaves_like 'persisted preferred diff view cookie'
it_behaves_like 'cached diff collection'
+ it_behaves_like 'diff note on-demand position creation'
end
describe 'GET diffs_metadata' do
diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
index 7d74e872d29..af39d4dec72 100644
--- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
@@ -331,8 +331,10 @@ RSpec.describe Projects::MergeRequests::DraftsController do
notes = merge_request.notes.reload
expect(notes.pluck(:note)).to include(*drafts.map(&:note))
- expect(note.discussion.notes.last.note).to eq(draft_reply.note)
- expect(diff_note.discussion.notes.last.note).to eq(diff_draft_reply.note)
+
+ # discussion is memoized and reload doesn't clear the memoization
+ expect(Note.find(note.id).discussion.notes.last.note).to eq(draft_reply.note)
+ expect(Note.find(diff_note.id).discussion.notes.last.note).to eq(diff_draft_reply.note)
end
it 'can publish just a single draft note' do
@@ -376,7 +378,8 @@ RSpec.describe Projects::MergeRequests::DraftsController do
post :publish, params: params
- discussion = note.discussion
+ # discussion is memoized and reload doesn't clear the memoization
+ discussion = Note.find(note.id).discussion
expect(discussion.notes.last.note).to eq(draft_reply.note)
expect(discussion.resolved?).to eq(false)
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 382593fd7cb..4327e0bbb7a 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -442,7 +442,7 @@ RSpec.describe Projects::MergeRequestsController do
merge_request.update(squash: false)
merge_with_sha(squash: '1')
- expect(merge_request.reload.squash).to be_truthy
+ expect(merge_request.reload.squash_on_merge?).to be_truthy
end
end
@@ -451,7 +451,7 @@ RSpec.describe Projects::MergeRequestsController do
merge_request.update(squash: true)
merge_with_sha(squash: '0')
- expect(merge_request.reload.squash).to be_falsey
+ expect(merge_request.reload.squash_on_merge?).to be_falsey
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index b3a83723189..9728fad417e 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -38,9 +38,9 @@ RSpec.describe Projects::NotesController do
end
it 'passes last_fetched_at from headers to NotesFinder and MergeIntoNotesService' do
- last_fetched_at = 3.hours.ago.to_i
+ last_fetched_at = Time.zone.at(3.hours.ago.to_i) # remove nanoseconds
- request.headers['X-Last-Fetched-At'] = last_fetched_at
+ request.headers['X-Last-Fetched-At'] = microseconds(last_fetched_at)
expect(NotesFinder).to receive(:new)
.with(anything, hash_including(last_fetched_at: last_fetched_at))
@@ -84,6 +84,81 @@ 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|
+ Timecop.freeze 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
+ 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
+ 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
+ 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
+ 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) }
@@ -870,4 +945,9 @@ RSpec.describe Projects::NotesController do
end
end
end
+
+ # Convert a time to an integer number of microseconds
+ def microseconds(time)
+ (time.to_i * 1_000_000) + time.usec
+ end
end
diff --git a/spec/controllers/projects/stages_controller_spec.rb b/spec/controllers/projects/pipelines/stages_controller_spec.rb
index dcf8607ae18..6e8c08d95a1 100644
--- a/spec/controllers/projects/stages_controller_spec.rb
+++ b/spec/controllers/projects/pipelines/stages_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::StagesController do
+RSpec.describe Projects::Pipelines::StagesController do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
@@ -60,7 +60,7 @@ RSpec.describe Projects::StagesController do
post :play_manual, params: {
namespace_id: project.namespace,
project_id: project,
- id: pipeline.id,
+ pipeline_id: pipeline.id,
stage_name: stage_name
}, format: :json
end
diff --git a/spec/controllers/projects/pipelines/tests_controller_spec.rb b/spec/controllers/projects/pipelines/tests_controller_spec.rb
new file mode 100644
index 00000000000..e2abd1238c5
--- /dev/null
+++ b/spec/controllers/projects/pipelines/tests_controller_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Pipelines::TestsController do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET #summary.json' do
+ context 'when pipeline has build report results' do
+ let(:pipeline) { create(:ci_pipeline, :with_report_results, project: project) }
+
+ it 'renders test report summary data' do
+ get_tests_summary_json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['total_count']).to eq(2)
+ end
+ end
+
+ context 'when pipeline does not have build report results' do
+ it 'renders test report summary data' do
+ get_tests_summary_json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['total_count']).to eq(0)
+ end
+ end
+
+ context 'when feature is disabled' do
+ before do
+ stub_feature_flags(build_report_summary: false)
+ end
+
+ it 'returns 404' do
+ get_tests_summary_json
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.body).to be_empty
+ end
+ end
+ end
+
+ describe 'GET #show.json' do
+ context 'when pipeline has build report results' do
+ let(:pipeline) { create(:ci_pipeline, :with_report_results, project: project) }
+ let(:suite_name) { 'test' }
+ let(:build_ids) { pipeline.latest_builds.pluck(:id) }
+
+ it 'renders test suite data' do
+ get_tests_show_json(build_ids)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq('test')
+ end
+ end
+
+ context 'when pipeline does not have build report results' do
+ let(:pipeline) { create(:ci_empty_pipeline) }
+ let(:suite_name) { 'test' }
+
+ it 'renders 404' do
+ get_tests_show_json([])
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.body).to be_empty
+ end
+ end
+
+ context 'when feature is disabled' do
+ let(:suite_name) { 'test' }
+
+ before do
+ stub_feature_flags(build_report_summary: false)
+ end
+
+ it 'returns 404' do
+ get_tests_show_json([])
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.body).to be_empty
+ end
+ end
+ end
+
+ def get_tests_summary_json
+ get :summary,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ pipeline_id: pipeline.id
+ },
+ format: :json
+ end
+
+ def get_tests_show_json(build_ids)
+ get :show,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ pipeline_id: pipeline.id,
+ suite_name: suite_name,
+ build_ids: build_ids
+ },
+ format: :json
+ end
+end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index ca09d2b1428..872f0e97b09 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -37,16 +37,13 @@ RSpec.describe Projects::PipelinesController do
expect(json_response).to include('pipelines')
expect(json_response['pipelines'].count).to eq 6
expect(json_response['count']['all']).to eq '6'
- expect(json_response['count']['running']).to eq '2'
- expect(json_response['count']['pending']).to eq '1'
- expect(json_response['count']['finished']).to eq '3'
json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages|
expect(stages.count).to eq 3
end
end
- it 'does not execute N+1 queries' do
+ it 'executes N+1 queries' do
get_pipelines_index_json
control_count = ActiveRecord::QueryRecorder.new do
@@ -56,10 +53,31 @@ RSpec.describe Projects::PipelinesController do
create_all_pipeline_types
# There appears to be one extra query for Pipelines#has_warnings? for some reason
- expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
+ expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 7)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['pipelines'].count).to eq 12
end
+
+ context 'with build_report_summary turned off' do
+ before do
+ stub_feature_flags(build_report_summary: false)
+ end
+
+ it 'does not execute N+1 queries' do
+ get_pipelines_index_json
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ get_pipelines_index_json
+ end.count
+
+ create_all_pipeline_types
+
+ # There appears to be one extra query for Pipelines#has_warnings? for some reason
+ expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['pipelines'].count).to eq 12
+ end
+ end
end
it 'does not include coverage data for the pipelines' do
@@ -77,9 +95,9 @@ RSpec.describe Projects::PipelinesController do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
- # ListCommitsByOid, RepositoryExists, HasLocalBranches
+ # ListCommitsByOid, RepositoryExists, HasLocalBranches, ListCommitsByRefNames
expect { get_pipelines_index_json }
- .to change { Gitlab::GitalyClient.get_request_count }.by(3)
+ .to change { Gitlab::GitalyClient.get_request_count }.by(4)
end
end
@@ -101,23 +119,27 @@ RSpec.describe Projects::PipelinesController do
end
end
- context 'filter by scope' do
- it 'returns matched pipelines' do
- get_pipelines_index_json(scope: 'running')
+ context 'when user tries to access legacy scope via URL' do
+ it 'redirects to all pipelines with that status instead' do
+ get_pipelines_index_html(scope: 'running')
- check_pipeline_response(returned: 2, all: 6, running: 2, pending: 1, finished: 3)
+ expect(response).to redirect_to(project_pipelines_path(project, status: 'running', format: :html))
end
+ end
+ context 'filter by scope' do
context 'scope is branches or tags' do
before do
create(:ci_pipeline, :failed, project: project, ref: 'v1.0.0', tag: true)
+ create(:ci_pipeline, :failed, project: project, ref: 'master', tag: false)
+ create(:ci_pipeline, :failed, project: project, ref: 'feature', tag: false)
end
context 'when scope is branches' do
it 'returns matched pipelines' do
get_pipelines_index_json(scope: 'branches')
- check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
+ check_pipeline_response(returned: 2, all: 9)
end
end
@@ -125,7 +147,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns matched pipelines' do
get_pipelines_index_json(scope: 'tags')
- check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
+ check_pipeline_response(returned: 1, all: 9)
end
end
end
@@ -138,7 +160,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns matched pipelines' do
get_pipelines_index_json(username: user.username)
- check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0)
+ check_pipeline_response(returned: 1, all: 1)
end
end
@@ -146,7 +168,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns empty' do
get_pipelines_index_json(username: 'invalid-username')
- check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0)
+ check_pipeline_response(returned: 0, all: 0)
end
end
end
@@ -158,7 +180,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns matched pipelines' do
get_pipelines_index_json(ref: 'branch-1')
- check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0)
+ check_pipeline_response(returned: 1, all: 1)
end
end
@@ -166,7 +188,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns empty list' do
get_pipelines_index_json(ref: 'invalid-ref')
- check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0)
+ check_pipeline_response(returned: 0, all: 0)
end
end
end
@@ -176,15 +198,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns matched pipelines' do
get_pipelines_index_json(status: 'success')
- check_pipeline_response(returned: 1, all: 1, running: 0, pending: 0, finished: 1)
- end
-
- context 'when filter by unrelated scope' do
- it 'returns empty list' do
- get_pipelines_index_json(status: 'success', scope: 'running')
-
- check_pipeline_response(returned: 0, all: 1, running: 0, pending: 0, finished: 1)
- end
+ check_pipeline_response(returned: 1, all: 1)
end
end
@@ -192,7 +206,7 @@ RSpec.describe Projects::PipelinesController do
it 'returns empty list' do
get_pipelines_index_json(status: 'manual')
- check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0)
+ check_pipeline_response(returned: 0, all: 0)
end
end
@@ -200,11 +214,19 @@ RSpec.describe Projects::PipelinesController do
it 'returns all list' do
get_pipelines_index_json(status: 'invalid-status')
- check_pipeline_response(returned: 6, all: 6, running: 2, pending: 1, finished: 3)
+ check_pipeline_response(returned: 6, all: 6)
end
end
end
+ def get_pipelines_index_html(params = {})
+ get :index, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }.merge(params),
+ format: :html
+ end
+
def get_pipelines_index_json(params = {})
get :index, params: {
namespace_id: project.namespace,
@@ -234,7 +256,8 @@ RSpec.describe Projects::PipelinesController do
user = create(:user)
pipeline = create(:ci_empty_pipeline, status: status,
project: project,
- sha: sha,
+ sha: sha.id,
+ ref: sha.id.first(8),
user: user,
merge_request: merge_request)
@@ -260,15 +283,12 @@ RSpec.describe Projects::PipelinesController do
)
end
- def check_pipeline_response(returned:, all:, running:, pending:, finished:)
+ def check_pipeline_response(returned:, all:)
aggregate_failures do
expect(response).to match_response_schema('pipeline')
expect(json_response['pipelines'].count).to eq returned
expect(json_response['count']['all'].to_i).to eq all
- expect(json_response['count']['running'].to_i).to eq running
- expect(json_response['count']['pending'].to_i).to eq pending
- expect(json_response['count']['finished'].to_i).to eq finished
end
end
end
@@ -689,6 +709,15 @@ RSpec.describe Projects::PipelinesController do
end
end
+ describe 'GET #charts' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ it_behaves_like 'tracking unique visits', :charts do
+ let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id } }
+ let(:target_id) { 'p_analytics_pipelines' }
+ end
+ end
+
describe 'POST create' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 7457e4c5023..40a220d57a7 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -106,6 +106,29 @@ RSpec.describe Projects::ProjectMembersController do
expect(response).to redirect_to(project_project_members_path(project))
end
end
+
+ context 'adding project bot' do
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+
+ before do
+ project.add_maintainer(user)
+
+ unrelated_project = create(:project)
+ unrelated_project.add_maintainer(project_bot)
+ end
+
+ it 'returns error' do
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ user_ids: project_bot.id,
+ access_level: Gitlab::Access::GUEST
+ }
+
+ expect(flash[:alert]).to include('project bots cannot be added to other groups / projects')
+ expect(response).to redirect_to(project_project_members_path(project))
+ end
+ end
end
describe 'PUT update' do
diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb
index a6a4aff7ce9..d10351feb9e 100644
--- a/spec/controllers/projects/refs_controller_spec.rb
+++ b/spec/controllers/projects/refs_controller_spec.rb
@@ -41,19 +41,12 @@ RSpec.describe Projects::RefsController do
expect { xhr_get }.not_to raise_error
end
- it 'renders 404 for non-JS requests' do
+ it 'renders 404 for HTML requests' do
xhr_get
expect(response).to be_not_found
end
- it 'renders JS' do
- expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
-
- xhr_get(:js)
- expect(response).to be_successful
- end
-
context 'when json is requested' do
it 'renders JSON' do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index 96c38c1b726..45beccfeef5 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Projects::ReleasesController do
+ include AccessMatchersForController
+
let!(:project) { create(:project, :repository, :public) }
let_it_be(:private_project) { create(:project, :repository, :private) }
let_it_be(:developer) { create(:user) }
@@ -118,6 +120,15 @@ RSpec.describe Projects::ReleasesController do
end
end
+ describe 'GET #new' do
+ let(:request) do
+ get :new, params: { namespace_id: project.namespace, project_id: project }
+ end
+
+ it { expect { request }.to be_denied_for(:reporter).of(project) }
+ it { expect { request }.to be_allowed_for(:developer).of(project) }
+ end
+
describe 'GET #edit' do
subject do
get :edit, params: { namespace_id: project.namespace, project_id: project, tag: tag }
diff --git a/spec/controllers/projects/service_desk_controller_spec.rb b/spec/controllers/projects/service_desk_controller_spec.rb
new file mode 100644
index 00000000000..1c4d6665414
--- /dev/null
+++ b/spec/controllers/projects/service_desk_controller_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ServiceDeskController do
+ let_it_be(:project) do
+ create(:project, :private, :custom_repo, service_desk_enabled: true,
+ files: { '.gitlab/issue_templates/service_desk.md' => 'template' })
+ end
+
+ let_it_be(:user) { create(:user) }
+
+ before do
+ allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
+ allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
+
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ describe 'GET service desk properties' do
+ it 'returns service_desk JSON data' do
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
+
+ expect(json_response["service_desk_address"]).to match(/\A[^@]+@[^@]+\z/)
+ expect(json_response["service_desk_enabled"]).to be_truthy
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when user is not project maintainer' do
+ let(:guest) { create(:user) }
+
+ it 'renders 404' do
+ project.add_guest(guest)
+ sign_in(guest)
+
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when issue template is present' do
+ it 'returns template_file_missing as false' do
+ create(:service_desk_setting, project: project, issue_template_key: 'service_desk')
+
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
+
+ response_hash = Gitlab::Json.parse(response.body)
+ expect(response_hash['template_file_missing']).to eq(false)
+ end
+ end
+
+ context 'when issue template file becomes outdated' do
+ it 'returns template_file_missing as true' do
+ service = ServiceDeskSetting.new(project_id: project.id, issue_template_key: 'deleted')
+ service.save!(validate: false)
+
+ get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
+
+ expect(json_response['template_file_missing']).to eq(true)
+ end
+ end
+ end
+
+ describe 'PUT service desk properties' do
+ it 'toggles services desk incoming email' do
+ project.update!(service_desk_enabled: false)
+
+ put :update, params: { namespace_id: project.namespace.to_param,
+ project_id: project,
+ service_desk_enabled: true }, format: :json
+
+ expect(json_response["service_desk_address"]).to be_present
+ expect(json_response["service_desk_enabled"]).to be_truthy
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'sets issue_template_key' do
+ put :update, params: { namespace_id: project.namespace.to_param,
+ project_id: project,
+ issue_template_key: 'service_desk' }, format: :json
+
+ settings = project.service_desk_setting
+ expect(settings).to be_present
+ expect(settings.issue_template_key).to eq('service_desk')
+ expect(json_response['template_file_missing']).to eq(false)
+ expect(json_response['issue_template_key']).to eq('service_desk')
+ end
+
+ it 'returns an error when update of service desk settings fails' do
+ put :update, params: { namespace_id: project.namespace.to_param,
+ project_id: project,
+ issue_template_key: 'invalid key' }, format: :json
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response['message']).to eq('Issue template key is empty or does not exist')
+ end
+
+ context 'when user cannot admin the project' do
+ let(:other_user) { create(:user) }
+
+ it 'renders 404' do
+ sign_in(other_user)
+ put :update, params: { namespace_id: project.namespace.to_param, project_id: project, service_desk_enabled: true }, format: :json
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 04c74dfdefe..e8a23dcfafb 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -137,7 +137,7 @@ RSpec.describe Projects::ServicesController do
let(:params) { project_params(service: service_params) }
let(:message) { 'Jira activated.' }
- let(:redirect_url) { project_settings_integrations_path(project) }
+ let(:redirect_url) { edit_project_service_path(project, service) }
before do
put :update, params: params
@@ -179,6 +179,23 @@ RSpec.describe Projects::ServicesController do
it_behaves_like 'service update'
end
+
+ context 'wehn param `inherit_from_id` is set to empty string' do
+ let(:service_params) { { inherit_from_id: '' } }
+
+ it 'sets inherit_from_id to nil' do
+ expect(service.reload.inherit_from_id).to eq(nil)
+ end
+ end
+
+ context 'wehn param `inherit_from_id` is set to some value' do
+ let(:instance_service) { create(:jira_service, :instance) }
+ let(:service_params) { { inherit_from_id: instance_service.id } }
+
+ it 'sets inherit_from_id to value' do
+ expect(service.reload.inherit_from_id).to eq(instance_service.id)
+ end
+ end
end
describe 'as JSON' do
diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb
index 6b440e910ad..d4f3c5d0c9b 100644
--- a/spec/controllers/projects/settings/operations_controller_spec.rb
+++ b/spec/controllers/projects/settings/operations_controller_spec.rb
@@ -151,7 +151,8 @@ RSpec.describe Projects::Settings::OperationsController do
incident_management_setting_attributes: {
create_issue: 'false',
send_email: 'false',
- issue_template_key: 'some-other-template'
+ issue_template_key: 'some-other-template',
+ pagerduty_active: 'true'
}
}
end
@@ -159,7 +160,6 @@ RSpec.describe Projects::Settings::OperationsController do
it_behaves_like 'PATCHable'
context 'updating each incident management setting' do
- let(:project) { create(:project) }
let(:new_incident_management_settings) { {} }
before do
@@ -185,6 +185,98 @@ RSpec.describe Projects::Settings::OperationsController do
it_behaves_like 'a gitlab tracking event', { issue_template_key: nil }, 'disabled_issue_template_on_alerts'
it_behaves_like 'a gitlab tracking event', { send_email: '1' }, 'enabled_sending_emails'
it_behaves_like 'a gitlab tracking event', { send_email: '0' }, 'disabled_sending_emails'
+ it_behaves_like 'a gitlab tracking event', { pagerduty_active: '1' }, 'enabled_pagerduty_webhook'
+ it_behaves_like 'a gitlab tracking event', { pagerduty_active: '0' }, 'disabled_pagerduty_webhook'
+ end
+ end
+
+ describe 'POST #reset_pagerduty_token' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'with existing incident management setting has active PagerDuty webhook' do
+ let!(:incident_management_setting) do
+ create(:project_incident_management_setting, project: project, pagerduty_active: true)
+ end
+
+ let!(:old_token) { incident_management_setting.pagerduty_token }
+
+ it 'returns newly reset token' do
+ reset_pagerduty_token
+
+ new_token = incident_management_setting.reload.pagerduty_token
+ new_webhook_url = project_incidents_pagerduty_url(project, token: new_token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['pagerduty_webhook_url']).to eq(new_webhook_url)
+ expect(json_response['pagerduty_token']).to eq(new_token)
+ expect(old_token).not_to eq(new_token)
+ end
+ end
+
+ context 'without existing incident management setting' do
+ it 'does not reset a token' do
+ reset_pagerduty_token
+
+ new_webhook_url = project_incidents_pagerduty_url(project, token: nil)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['pagerduty_webhook_url']).to eq(new_webhook_url)
+ expect(project.incident_management_setting.pagerduty_token).to be_nil
+ end
+ end
+
+ context 'when update fails' do
+ let(:operations_update_service) { spy(:operations_update_service) }
+ let(:pagerduty_token_params) do
+ { incident_management_setting_attributes: { regenerate_token: true } }
+ end
+
+ before do
+ expect(::Projects::Operations::UpdateService)
+ .to receive(:new).with(project, user, pagerduty_token_params)
+ .and_return(operations_update_service)
+ expect(operations_update_service).to receive(:execute)
+ .and_return(status: :error)
+ end
+
+ it 'returns unprocessable_entity' do
+ reset_pagerduty_token
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to be_empty
+ end
+ end
+
+ context 'with insufficient permissions' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'returns 404' do
+ reset_pagerduty_token
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'as an anonymous user' do
+ before do
+ sign_out(user)
+ end
+
+ it 'returns a redirect' do
+ reset_pagerduty_token
+
+ expect(response).to have_gitlab_http_status(:redirect)
+ end
+ end
+
+ private
+
+ def reset_pagerduty_token
+ post :reset_pagerduty_token, params: project_params(project), format: :json
end
end
end
@@ -296,9 +388,7 @@ RSpec.describe Projects::Settings::OperationsController do
end
end
- describe 'POST reset_alerting_token' do
- let(:project) { create(:project) }
-
+ describe 'POST #reset_alerting_token' do
before do
project.add_maintainer(user)
end
diff --git a/spec/controllers/projects/snippets/blobs_controller_spec.rb b/spec/controllers/projects/snippets/blobs_controller_spec.rb
new file mode 100644
index 00000000000..ca656705e07
--- /dev/null
+++ b/spec/controllers/projects/snippets/blobs_controller_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Snippets::BlobsController do
+ using RSpec::Parameterized::TableSyntax
+ include SnippetHelpers
+
+ let_it_be(:author) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
+
+ let(:visibility) { :public }
+ let(:project_visibility) { :public }
+ let(:project) { create(:project, project_visibility) }
+ let(:snippet) { create(:project_snippet, visibility, :repository, project: project, author: author) }
+
+ before do
+ project.add_maintainer(author)
+ project.add_developer(developer)
+ end
+
+ describe 'GET #raw' do
+ let(:filepath) { 'file1' }
+ let(:ref) { TestEnv::BRANCH_SHA['snippet/single-file'] }
+ let(:inline) { nil }
+
+ subject do
+ get(:raw,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ snippet_id: snippet,
+ path: filepath,
+ ref: ref,
+ inline: inline
+ })
+ end
+
+ context 'with a snippet without a repository' do
+ let(:snippet) { create(:project_snippet, visibility, project: project, author: author) }
+
+ it_behaves_like 'raw snippet without repository', :not_found
+ end
+
+ where(:project_visibility_level, :snippet_visibility_level, :user, :status) do
+ :public | :public | :author | :ok
+ :public | :public | :developer | :ok
+ :public | :public | :other_user | :ok
+ :public | :public | nil | :ok
+
+ :public | :private | :author | :ok
+ :public | :private | :developer | :ok
+ :public | :private | :other_user | :not_found
+ :public | :private | nil | :not_found
+
+ :private | :public | :author | :ok
+ :private | :public | :developer | :ok
+ :private | :public | :other_user | :not_found
+ :private | :public | nil | :redirect
+
+ :private | :private | :author | :ok
+ :private | :private | :developer | :ok
+ :private | :private | :other_user | :not_found
+ :private | :private | nil | :redirect
+ end
+
+ with_them do
+ let(:visibility) { snippet_visibility_level }
+ let(:project_visibility) { project_visibility_level }
+
+ before do
+ sign_in_as(user)
+
+ subject
+ end
+
+ it 'responds with correct status' do
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+
+ it_behaves_like 'raw snippet blob'
+ end
+end
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index 8bbfaa8d327..6fcb24da3cd 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -15,14 +15,18 @@ RSpec.describe Projects::SnippetsController do
end
describe 'GET #index' do
+ let(:base_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project
+ }
+ end
+
+ subject { get :index, params: base_params }
+
it_behaves_like 'paginated collection' do
let(:collection) { project.snippets }
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project
- }
- end
+ let(:params) { base_params }
before do
create(:project_snippet, :public, project: project, author: user)
@@ -35,7 +39,11 @@ RSpec.describe Projects::SnippetsController do
.to receive(:new).with(nil, project: project)
.and_return(service)
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ subject
+ end
+
+ it_behaves_like 'snippets sort order' do
+ let(:params) { base_params }
end
context 'when the project snippet is private' do
@@ -43,7 +51,7 @@ RSpec.describe Projects::SnippetsController do
context 'when anonymous' do
it 'does not include the private snippet' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ subject
expect(assigns(:snippets)).not_to include(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
@@ -56,7 +64,7 @@ RSpec.describe Projects::SnippetsController do
end
it 'renders the snippet' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ subject
expect(assigns(:snippets)).to include(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
@@ -69,7 +77,7 @@ RSpec.describe Projects::SnippetsController do
end
it 'renders the snippet' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ subject
expect(assigns(:snippets)).to include(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index f6ec04d4dd7..8e4e275bdbe 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -89,34 +89,6 @@ RSpec.describe Projects::TreeController do
end
end
- describe "GET show" do
- context 'lfs_blob_ids instance variable' do
- let(:id) { 'master' }
-
- context 'with vue tree view enabled' do
- before do
- get(:show, params: { namespace_id: project.namespace.to_param, project_id: project, id: id })
- end
-
- it 'is not set' do
- expect(assigns[:lfs_blob_ids]).to be_nil
- end
- end
-
- context 'with vue tree view disabled' do
- before do
- stub_feature_flags(vue_file_list: false)
-
- get(:show, params: { namespace_id: project.namespace.to_param, project_id: project, id: id })
- end
-
- it 'is set' do
- expect(assigns[:lfs_blob_ids]).not_to be_nil
- end
- end
- end
- end
-
describe 'GET show with whitespace in ref' do
render_views
diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb
index 4e58822b613..7243588681d 100644
--- a/spec/controllers/projects/wikis_controller_spec.rb
+++ b/spec/controllers/projects/wikis_controller_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::WikisController do
it_behaves_like 'wiki controller actions' do
- let(:container) { create(:project, :public, :repository, namespace: user.namespace) }
+ let(:container) { create(:project, :public, namespace: user.namespace) }
let(:routing_params) { { namespace_id: container.namespace, project_id: container } }
end
end