summaryrefslogtreecommitdiff
path: root/spec/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/admin/dev_ops_report_controller_spec.rb6
-rw-r--r--spec/controllers/admin/projects_controller_spec.rb30
-rw-r--r--spec/controllers/application_controller_spec.rb43
-rw-r--r--spec/controllers/concerns/redis_tracking_spec.rb2
-rw-r--r--spec/controllers/concerns/spammable_actions_spec.rb198
-rw-r--r--spec/controllers/dashboard/projects_controller_spec.rb9
-rw-r--r--spec/controllers/dashboard/snippets_controller_spec.rb19
-rw-r--r--spec/controllers/explore/projects_controller_spec.rb2
-rw-r--r--spec/controllers/groups/labels_controller_spec.rb41
-rw-r--r--spec/controllers/import/bulk_imports_controller_spec.rb36
-rw-r--r--spec/controllers/jwks_controller_spec.rb36
-rw-r--r--spec/controllers/metrics_controller_spec.rb75
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb76
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb6
-rw-r--r--spec/controllers/projects/feature_flags_controller_spec.rb418
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb24
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb34
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb44
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb74
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb66
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb133
-rw-r--r--spec/controllers/projects_controller_spec.rb25
-rw-r--r--spec/controllers/registrations_controller_spec.rb8
-rw-r--r--spec/controllers/repositories/git_http_controller_spec.rb2
-rw-r--r--spec/controllers/runner_setup_controller_spec.rb21
-rw-r--r--spec/controllers/users_controller_spec.rb925
26 files changed, 798 insertions, 1555 deletions
diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb
index 0be30fff0c2..913921b9630 100644
--- a/spec/controllers/admin/dev_ops_report_controller_spec.rb
+++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb
@@ -3,6 +3,12 @@
require 'spec_helper'
RSpec.describe Admin::DevOpsReportController do
+ describe 'show_adoption?' do
+ it 'is always false' do
+ expect(controller.show_adoption?).to be false
+ end
+ end
+
describe 'GET #show' do
context 'as admin' do
let(:user) { create(:admin) }
diff --git a/spec/controllers/admin/projects_controller_spec.rb b/spec/controllers/admin/projects_controller_spec.rb
index b5f411c9121..d81b067ffb6 100644
--- a/spec/controllers/admin/projects_controller_spec.rb
+++ b/spec/controllers/admin/projects_controller_spec.rb
@@ -77,4 +77,34 @@ RSpec.describe Admin::ProjectsController do
expect(response.body).to match(project.name)
end
end
+
+ describe 'PUT /projects/transfer/:id' do
+ let_it_be(:project, reload: true) { create(:project) }
+ let_it_be(:new_namespace) { create(:namespace) }
+
+ it 'updates namespace' do
+ put :transfer, params: { namespace_id: project.namespace.path, new_namespace_id: new_namespace.id, id: project.path }
+
+ project.reload
+
+ expect(project.namespace).to eq(new_namespace)
+ expect(response).to have_gitlab_http_status(:redirect)
+ expect(response).to redirect_to(admin_project_path(project))
+ end
+
+ context 'when project transfer fails' do
+ it 'flashes error' do
+ old_namespace = project.namespace
+
+ put :transfer, params: { namespace_id: old_namespace.path, new_namespace_id: nil, id: project.path }
+
+ project.reload
+
+ expect(project.namespace).to eq(old_namespace)
+ expect(response).to have_gitlab_http_status(:redirect)
+ expect(response).to redirect_to(admin_project_path(project))
+ expect(flash[:alert]).to eq s_('TransferProject|Please select a new namespace for your project.')
+ end
+ end
+ end
end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 9342513d224..4a729008e67 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -720,6 +720,49 @@ RSpec.describe ApplicationController do
end
end
+ describe '#stream_csv_headers' do
+ controller(described_class) do
+ def index
+ respond_to do |format|
+ format.csv do
+ stream_csv_headers('test.csv')
+
+ self.response_body = fixture_file_upload('spec/fixtures/csv_comma.csv')
+ end
+ end
+ end
+ end
+
+ subject { get :index, format: :csv }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'sets no-cache headers', :aggregate_failures do
+ subject
+
+ expect(response.headers['Cache-Control']).to eq 'no-cache, no-store'
+ expect(response.headers['Pragma']).to eq 'no-cache'
+ expect(response.headers['Expires']).to eq 'Fri, 01 Jan 1990 00:00:00 GMT'
+ end
+
+ it 'sets stream headers', :aggregate_failures do
+ subject
+
+ expect(response.headers['Content-Length']).to be nil
+ expect(response.headers['X-Accel-Buffering']).to eq 'no'
+ expect(response.headers['Last-Modified']).to eq '0'
+ end
+
+ it 'sets the csv specific headers', :aggregate_failures do
+ subject
+
+ expect(response.headers['Content-Type']).to eq 'text/csv; charset=utf-8; header=present'
+ expect(response.headers['Content-Disposition']).to eq "attachment; filename=\"test.csv\""
+ end
+ end
+
context 'Gitlab::Session' do
controller(described_class) do
prepend_before_action do
diff --git a/spec/controllers/concerns/redis_tracking_spec.rb b/spec/controllers/concerns/redis_tracking_spec.rb
index 831f5ad7bb1..ef59adf8c1d 100644
--- a/spec/controllers/concerns/redis_tracking_spec.rb
+++ b/spec/controllers/concerns/redis_tracking_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe RedisTracking do
def expect_tracking
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
- .with(instance_of(String), 'g_compliance_approval_rules')
+ .with('g_compliance_approval_rules', values: instance_of(String))
end
def expect_no_tracking
diff --git a/spec/controllers/concerns/spammable_actions_spec.rb b/spec/controllers/concerns/spammable_actions_spec.rb
new file mode 100644
index 00000000000..3b5b4d11a9b
--- /dev/null
+++ b/spec/controllers/concerns/spammable_actions_spec.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe SpammableActions do
+ controller(ActionController::Base) do
+ include SpammableActions
+
+ # #create is used to test spammable_params
+ # for testing purposes
+ def create
+ spam_params = spammable_params
+
+ # replace the actual request with a string in the JSON response, all we care is that it got set
+ spam_params[:request] = 'this is the request' if spam_params[:request]
+
+ # just return the params in the response so they can be verified in this fake controller spec.
+ # Normally, they are processed further by the controller action
+ render json: spam_params.to_json, status: :ok
+ end
+
+ # #update is used to test recaptcha_check_with_fallback
+ # for testing purposes
+ def update
+ should_redirect = params[:should_redirect] == 'true'
+
+ recaptcha_check_with_fallback(should_redirect) { render json: :ok }
+ end
+
+ private
+
+ def spammable_path
+ '/fake_spammable_path'
+ end
+ end
+
+ before do
+ # Ordinarily we would not stub a method on the class under test, but :ensure_spam_config_loaded!
+ # returns false in the test environment, and is also strong_memoized, so we need to stub it
+ allow(controller).to receive(:ensure_spam_config_loaded!) { true }
+ end
+
+ describe '#spammable_params' do
+ subject { post :create, format: :json, params: params }
+
+ shared_examples 'expects request param only' do
+ it do
+ subject
+
+ expect(response).to be_successful
+ expect(json_response).to eq({ 'request' => 'this is the request' })
+ end
+ end
+
+ shared_examples 'expects all spammable params' do
+ it do
+ subject
+
+ expect(response).to be_successful
+ expect(json_response['request']).to eq('this is the request')
+ expect(json_response['recaptcha_verified']).to eq(true)
+ expect(json_response['spam_log_id']).to eq('1')
+ end
+ end
+
+ let(:recaptcha_response) { nil }
+ let(:spam_log_id) { nil }
+
+ context 'when recaptcha response is not present' do
+ let(:params) do
+ {
+ spam_log_id: spam_log_id
+ }
+ end
+
+ it_behaves_like 'expects request param only'
+ end
+
+ context 'when recaptcha response is present' do
+ let(:recaptcha_response) { 'abd123' }
+ let(:params) do
+ {
+ 'g-recaptcha-response': recaptcha_response,
+ spam_log_id: spam_log_id
+ }
+ end
+
+ context 'when verify_recaptcha returns falsey' do
+ before do
+ expect(controller).to receive(:verify_recaptcha).with(
+ {
+ response: recaptcha_response
+ }) { false }
+ end
+
+ it_behaves_like 'expects request param only'
+ end
+
+ context 'when verify_recaptcha returns truthy' do
+ let(:spam_log_id) { 1 }
+
+ before do
+ expect(controller).to receive(:verify_recaptcha).with(
+ {
+ response: recaptcha_response
+ }) { true }
+ end
+
+ it_behaves_like 'expects all spammable params'
+ end
+ end
+ end
+
+ describe '#recaptcha_check_with_fallback' do
+ shared_examples 'yields to block' do
+ it do
+ subject
+
+ expect(json_response).to eq({ json: 'ok' })
+ end
+ end
+
+ let(:format) { :html }
+
+ subject { post :update, format: format, params: params }
+
+ let(:spammable) { double(:spammable) }
+ let(:should_redirect) { nil }
+ let(:params) do
+ {
+ should_redirect: should_redirect
+ }
+ end
+
+ before do
+ routes.draw { get 'update' => 'anonymous#update' }
+ allow(controller).to receive(:spammable) { spammable }
+ end
+
+ context 'when should_redirect is true and spammable is valid' do
+ let(:should_redirect) { true }
+
+ before do
+ allow(spammable).to receive(:valid?) { true }
+ end
+
+ it 'redirects to spammable_path' do
+ expect(subject).to redirect_to('/fake_spammable_path')
+ end
+ end
+
+ context 'when should_redirect is false or spammable is not valid' do
+ before do
+ allow(spammable).to receive(:valid?) { false }
+ end
+
+ # NOTE: Not adding coverage of details of render_recaptcha?, the plan is to refactor it out
+ # of this module anyway as part of adding support for the GraphQL reCAPTCHA flow.
+
+ context 'when render_recaptcha? is true' do
+ before do
+ expect(controller).to receive(:render_recaptcha?) { true }
+ end
+
+ context 'when format is :html' do
+ it 'renders :verify' do
+ expect(controller).to receive(:render).with(:verify)
+
+ subject
+ end
+ end
+
+ context 'when format is :json' do
+ let(:format) { :json }
+ let(:recaptcha_html) { '<recaptcha-html/>' }
+
+ it 'renders json with recaptcha_html' do
+ expect(controller).to receive(:render_to_string).with(
+ {
+ partial: 'shared/recaptcha_form',
+ formats: :html,
+ locals: {
+ spammable: spammable,
+ script: false,
+ has_submit: false
+ }
+ }
+ ) { recaptcha_html }
+
+ subject
+
+ expect(json_response).to eq({ 'recaptcha_html' => recaptcha_html })
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb
index 2719b7c8a24..dcec8012f03 100644
--- a/spec/controllers/dashboard/projects_controller_spec.rb
+++ b/spec/controllers/dashboard/projects_controller_spec.rb
@@ -13,8 +13,8 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
end
context 'user logged in' do
- let_it_be(:project) { create(:project) }
- let_it_be(:project2) { create(:project) }
+ let_it_be(:project) { create(:project, name: 'Project 1') }
+ let_it_be(:project2) { create(:project, name: 'Project Two') }
let(:projects) { [project, project2] }
before_all do
@@ -36,10 +36,7 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
end
end
- it 'orders the projects by last activity by default' do
- project.update!(last_repository_updated_at: 3.days.ago, last_activity_at: 3.days.ago)
- project2.update!(last_repository_updated_at: 10.days.ago, last_activity_at: 10.days.ago)
-
+ it 'orders the projects by name by default' do
get :index
expect(assigns(:projects)).to eq(projects)
diff --git a/spec/controllers/dashboard/snippets_controller_spec.rb b/spec/controllers/dashboard/snippets_controller_spec.rb
index d981f738e70..016a9f53129 100644
--- a/spec/controllers/dashboard/snippets_controller_spec.rb
+++ b/spec/controllers/dashboard/snippets_controller_spec.rb
@@ -28,5 +28,24 @@ RSpec.describe Dashboard::SnippetsController do
end
it_behaves_like 'snippets sort order'
+
+ context 'when views are rendered' do
+ render_views
+
+ it 'avoids N+1 database queries' do
+ # Warming call to load everything non snippet related
+ get(:index)
+
+ project = create(:project, namespace: user.namespace)
+ create(:project_snippet, project: project, author: user)
+
+ control_count = ActiveRecord::QueryRecorder.new { get(:index) }.count
+
+ project = create(:project, namespace: user.namespace)
+ create(:project_snippet, project: project, author: user)
+
+ expect { get(:index) }.not_to exceed_query_limit(control_count)
+ end
+ end
end
end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index 4ec890a528f..cfbd129388d 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Explore::ProjectsController do
end
shared_examples "blocks high page numbers" do
- let(:page_limit) { 200 }
+ let(:page_limit) { described_class::PAGE_LIMIT }
context "page number is too high" do
[:index, :trending, :starred].each do |endpoint|
diff --git a/spec/controllers/groups/labels_controller_spec.rb b/spec/controllers/groups/labels_controller_spec.rb
index 33041f1af9f..b2320615778 100644
--- a/spec/controllers/groups/labels_controller_spec.rb
+++ b/spec/controllers/groups/labels_controller_spec.rb
@@ -9,8 +9,6 @@ RSpec.describe Groups::LabelsController do
before do
group.add_owner(user)
- # by default FFs are enabled in specs so we turn it off
- stub_feature_flags(show_inherited_labels: false)
sign_in(user)
end
@@ -34,41 +32,12 @@ RSpec.describe Groups::LabelsController do
subgroup.add_owner(user)
end
- RSpec.shared_examples 'returns ancestor group labels' do
- it 'returns ancestor group labels' do
- get :index, params: params, format: :json
+ it 'returns ancestor group labels' do
+ params = { group_id: subgroup, only_group_labels: true }
+ get :index, params: params, format: :json
- label_ids = json_response.map {|label| label['title']}
- expect(label_ids).to match_array([group_label_1.title, subgroup_label_1.title])
- end
- end
-
- context 'when include_ancestor_groups true' do
- let(:params) { { group_id: subgroup, include_ancestor_groups: true, only_group_labels: true } }
-
- it_behaves_like 'returns ancestor group labels'
- end
-
- context 'when include_ancestor_groups false' do
- let(:params) { { group_id: subgroup, only_group_labels: true } }
-
- it 'does not return ancestor group labels', :aggregate_failures do
- get :index, params: params, format: :json
-
- label_ids = json_response.map {|label| label['title']}
- expect(label_ids).to match_array([subgroup_label_1.title])
- expect(label_ids).not_to include([group_label_1.title])
- end
- end
-
- context 'when show_inherited_labels enabled' do
- let(:params) { { group_id: subgroup } }
-
- before do
- stub_feature_flags(show_inherited_labels: true)
- end
-
- it_behaves_like 'returns ancestor group labels'
+ label_ids = json_response.map {|label| label['title']}
+ expect(label_ids).to match_array([group_label_1.title, subgroup_label_1.title])
end
end
diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb
index 436daed0af6..d1c138617bb 100644
--- a/spec/controllers/import/bulk_imports_controller_spec.rb
+++ b/spec/controllers/import/bulk_imports_controller_spec.rb
@@ -63,9 +63,16 @@ RSpec.describe Import::BulkImportsController do
)
end
+ let(:client_params) do
+ {
+ top_level_only: true,
+ min_access_level: Gitlab::Access::MAINTAINER
+ }
+ end
+
before do
allow(controller).to receive(:client).and_return(client)
- allow(client).to receive(:get).with('groups', top_level_only: true).and_return(client_response)
+ allow(client).to receive(:get).with('groups', client_params).and_return(client_response)
end
it 'returns serialized group data' do
@@ -73,6 +80,17 @@ RSpec.describe Import::BulkImportsController do
expect(json_response).to eq({ importable_data: client_response.parsed_response }.as_json)
end
+
+ context 'when filtering' do
+ it 'returns filtered result' do
+ filter = 'test'
+ search_params = client_params.merge(search: filter)
+
+ expect(client).to receive(:get).with('groups', search_params).and_return(client_response)
+
+ get :status, format: :json, params: { filter: filter }
+ end
+ end
end
context 'when host url is local or not http' do
@@ -131,6 +149,22 @@ RSpec.describe Import::BulkImportsController do
end
end
+ describe 'GET realtime_changes' do
+ let_it_be(:bulk_import) { create(:bulk_import, :created, user: user) }
+
+ it 'returns bulk imports created by current user' do
+ get :realtime_changes
+
+ expect(json_response).to eq([{ 'id' => bulk_import.id, 'status_name' => bulk_import.status_name.to_s }])
+ end
+
+ it 'sets a Poll-Interval header' do
+ get :realtime_changes
+
+ expect(response.headers['Poll-Interval']).to eq(Import::BulkImportsController::POLLING_INTERVAL.to_s)
+ end
+ end
+
describe 'POST create' do
let(:instance_url) { "http://fake-intance" }
let(:pat) { "fake-pat" }
diff --git a/spec/controllers/jwks_controller_spec.rb b/spec/controllers/jwks_controller_spec.rb
deleted file mode 100644
index 013ec01eba2..00000000000
--- a/spec/controllers/jwks_controller_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe JwksController do
- describe 'GET #index' do
- let(:ci_jwt_signing_key) { OpenSSL::PKey::RSA.generate(1024) }
- let(:ci_jwk) { ci_jwt_signing_key.to_jwk }
- let(:oidc_jwk) { OpenSSL::PKey::RSA.new(Rails.application.secrets.openid_connect_signing_key).to_jwk }
-
- before do
- stub_application_setting(ci_jwt_signing_key: ci_jwt_signing_key.to_s)
- end
-
- it 'returns signing keys used to sign CI_JOB_JWT' do
- get :index
-
- expect(response).to have_gitlab_http_status(:ok)
-
- ids = json_response['keys'].map { |jwk| jwk['kid'] }
- expect(ids).to contain_exactly(ci_jwk['kid'], oidc_jwk['kid'])
- end
-
- it 'does not leak private key data' do
- get :index
-
- aggregate_failures do
- json_response['keys'].each do |jwk|
- expect(jwk.keys).to contain_exactly('kty', 'kid', 'e', 'n', 'use', 'alg')
- expect(jwk['use']).to eq('sig')
- expect(jwk['alg']).to eq('RS256')
- end
- end
- end
- end
-end
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
index f350d7378dc..9fa90dde997 100644
--- a/spec/controllers/metrics_controller_spec.rb
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -28,8 +28,38 @@ RSpec.describe MetricsController, :request_store do
end
end
+ shared_examples_for 'protected metrics endpoint' do |examples|
+ context 'accessed from whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(whitelisted_ip)
+ end
+
+ it_behaves_like examples
+ end
+
+ context 'accessed from ip in whitelisted range' do
+ before do
+ allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(ip_in_whitelisted_range)
+ end
+
+ it_behaves_like examples
+ end
+
+ context 'accessed from not whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(not_whitelisted_ip)
+ end
+
+ it 'returns the expected error response' do
+ get :index
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
describe '#index' do
- shared_examples_for 'endpoint providing metrics' do
+ shared_examples_for 'providing metrics' do
it 'returns prometheus metrics' do
get :index
@@ -51,32 +81,35 @@ RSpec.describe MetricsController, :request_store do
end
end
- context 'accessed from whitelisted ip' do
- before do
- allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(whitelisted_ip)
- end
-
- it_behaves_like 'endpoint providing metrics'
- end
+ include_examples 'protected metrics endpoint', 'providing metrics'
+ end
- context 'accessed from ip in whitelisted range' do
- before do
- allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(ip_in_whitelisted_range)
+ describe '#system' do
+ shared_examples_for 'providing system stats' do
+ let(:summary) do
+ {
+ version: 'ruby-3.0-patch1',
+ memory_rss: 1024
+ }
end
- it_behaves_like 'endpoint providing metrics'
- end
+ it 'renders system stats JSON' do
+ expect(Prometheus::PidProvider).to receive(:worker_id).and_return('worker-0')
+ expect(Gitlab::Metrics::System).to receive(:summary).and_return(summary)
- context 'accessed from not whitelisted ip' do
- before do
- allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(not_whitelisted_ip)
- end
-
- it 'returns the expected error response' do
- get :index
+ get :system
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response_json['version']).to eq('ruby-3.0-patch1')
+ expect(response_json['worker_id']).to eq('worker-0')
+ expect(response_json['memory_rss']).to eq(1024)
end
end
+
+ include_examples 'protected metrics endpoint', 'providing system stats'
+ end
+
+ def response_json
+ Gitlab::Json.parse(response.body)
end
end
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index a56425c2a22..16be7394174 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -7,6 +7,82 @@ RSpec.describe Projects::BlobController do
let(:project) { create(:project, :public, :repository) }
+ describe "GET new" do
+ context 'with no jobs' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:file_name) { '.gitlab-ci.yml' }
+
+ def request
+ get(:new, params: { namespace_id: project.namespace, project_id: project, id: 'master', file_name: file_name } )
+ end
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+
+ stub_experiment(ci_syntax_templates: experiment_active)
+ stub_experiment_for_subject(ci_syntax_templates: in_experiment_group)
+ end
+
+ context 'when the experiment is not active' do
+ let(:experiment_active) { false }
+ let(:in_experiment_group) { false }
+
+ it 'does not record the experiment user' do
+ expect(Experiment).not_to receive(:add_user)
+
+ request
+ end
+ end
+
+ context 'when the experiment is active and the user is in the control group' do
+ let(:experiment_active) { true }
+ let(:in_experiment_group) { false }
+
+ it 'records the experiment user in the control group' do
+ expect(Experiment).to receive(:add_user)
+ .with(:ci_syntax_templates, :control, user, namespace_id: project.namespace_id)
+
+ request
+ end
+ end
+
+ context 'when the experiment is active and the user is in the experimental group' do
+ let(:experiment_active) { true }
+ let(:in_experiment_group) { true }
+
+ it 'records the experiment user in the experimental group' do
+ expect(Experiment).to receive(:add_user)
+ .with(:ci_syntax_templates, :experimental, user, namespace_id: project.namespace_id)
+
+ request
+ end
+
+ context 'when requesting a non default config file type' do
+ let(:file_name) { '.non_default_ci_config' }
+ let(:project) { create(:project, :public, :repository, ci_config_path: file_name) }
+
+ it 'records the experiment user in the experimental group' do
+ expect(Experiment).to receive(:add_user)
+ .with(:ci_syntax_templates, :experimental, user, namespace_id: project.namespace_id)
+
+ request
+ end
+ end
+
+ context 'when requesting a different file type' do
+ let(:file_name) { '.gitignore' }
+
+ it 'does not record the experiment user' do
+ expect(Experiment).not_to receive(:add_user)
+
+ request
+ end
+ end
+ end
+ end
+ end
+
describe "GET show" do
def request
get(:show, params: { namespace_id: project.namespace, project_id: project, id: id })
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index d1142cbd129..83ad36b217f 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::EnvironmentsController do
include MetricsDashboardHelpers
+ include KubernetesHelpers
let_it_be(:project) { create(:project) }
let_it_be(:maintainer) { create(:user, name: 'main-dos').tap { |u| project.add_maintainer(u) } }
@@ -34,6 +35,9 @@ RSpec.describe Projects::EnvironmentsController do
context 'when requesting JSON response for folders' do
before do
+ allow_any_instance_of(Environment).to receive(:has_terminals?).and_return(true)
+ allow_any_instance_of(Environment).to receive(:rollout_status).and_return(kube_deployment_rollout_status)
+
create(:environment, project: project,
name: 'staging/review-1',
state: :available)
@@ -91,9 +95,11 @@ RSpec.describe Projects::EnvironmentsController do
it 'responds with a payload describing available environments' do
expect(environments.count).to eq 2
expect(environments.first['name']).to eq 'production'
+ expect(environments.first['latest']['rollout_status']).to be_present
expect(environments.second['name']).to eq 'staging'
expect(environments.second['size']).to eq 2
expect(environments.second['latest']['name']).to eq 'staging/review-2'
+ expect(environments.second['latest']['rollout_status']).to be_present
end
it 'contains values describing environment scopes sizes' do
diff --git a/spec/controllers/projects/feature_flags_controller_spec.rb b/spec/controllers/projects/feature_flags_controller_spec.rb
index d5fc80bd5a7..f69cc0ddfd8 100644
--- a/spec/controllers/projects/feature_flags_controller_spec.rb
+++ b/spec/controllers/projects/feature_flags_controller_spec.rb
@@ -845,413 +845,64 @@ RSpec.describe Projects::FeatureFlagsController do
put(:update, params: params, format: :json, as: :json)
end
- before do
- stub_feature_flags(
- feature_flags_legacy_read_only: false,
- feature_flags_legacy_read_only_override: false
- )
- end
-
- subject { put(:update, params: params, format: :json) }
-
- let!(:feature_flag) do
- create(:operations_feature_flag,
- :legacy_flag,
- name: 'ci_live_trace',
- active: true,
- project: project)
- end
-
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- name: 'ci_new_live_trace'
- }
- }
- end
-
- it 'returns 200' do
- is_expected.to have_gitlab_http_status(:ok)
- end
-
- it 'updates the name of the feature flag name' do
- subject
-
- expect(json_response['name']).to eq('ci_new_live_trace')
- end
-
- it 'matches json schema' do
- is_expected.to match_response_schema('feature_flag')
- end
-
- context 'when updates active' do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- active: false
- }
- }
- end
-
- it 'updates active from true to false' do
- expect { subject }
- .to change { feature_flag.reload.active }.from(true).to(false)
- end
-
- it "does not change default scope's active" do
- expect { subject }
- .not_to change { feature_flag.default_scope.reload.active }.from(true)
- end
-
- it 'updates active from false to true when an inactive feature flag has an active scope' do
- feature_flag = create(:operations_feature_flag, project: project, name: 'my_flag', active: false)
- create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'production', active: true)
-
- put_request(feature_flag, { active: true })
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('feature_flag')
- expect(json_response['active']).to eq(true)
- expect(feature_flag.reload.active).to eq(true)
- expect(feature_flag.default_scope.reload.active).to eq(false)
- end
- end
-
- context 'when user is reporter' do
- let(:user) { reporter }
-
- it 'returns 404' do
- is_expected.to have_gitlab_http_status(:not_found)
- end
- end
-
- context "when creates an additional scope for production environment" do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- scopes_attributes: [{ environment_scope: 'production', active: false }]
- }
- }
- end
-
- it 'creates a production scope' do
- expect { subject }.to change { feature_flag.reload.scopes.count }.by(1)
-
- expect(json_response['scopes'].last['environment_scope']).to eq('production')
- expect(json_response['scopes'].last['active']).to be_falsy
- end
- end
-
- context "when creates a default scope" do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- scopes_attributes: [{ environment_scope: '*', active: false }]
- }
- }
- end
-
- it 'returns 400' do
- is_expected.to have_gitlab_http_status(:bad_request)
- end
- end
-
- context "when updates a default scope's active value" do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- scopes_attributes: [
- {
- id: feature_flag.default_scope.id,
- environment_scope: '*',
- active: false
- }
- ]
- }
- }
- end
-
- it "updates successfully" do
- subject
-
- expect(json_response['scopes'].first['environment_scope']).to eq('*')
- expect(json_response['scopes'].first['active']).to be_falsy
- end
- end
-
- context "when changes default scope's spec" do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- scopes_attributes: [
- {
- id: feature_flag.default_scope.id,
- environment_scope: 'review/*'
- }
- ]
- }
- }
- end
-
- it 'returns 400' do
- is_expected.to have_gitlab_http_status(:bad_request)
- end
- end
+ context 'with a legacy feature flag' do
+ subject { put(:update, params: params, format: :json) }
- context "when destroys the default scope" do
- let(:params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- iid: feature_flag.iid,
- operations_feature_flag: {
- scopes_attributes: [
- {
- id: feature_flag.default_scope.id,
- _destroy: 1
- }
- ]
- }
- }
- end
-
- it 'raises an error' do
- expect { subject }.to raise_error(ActiveRecord::ReadOnlyRecord)
+ let!(:feature_flag) do
+ create(:operations_feature_flag,
+ :legacy_flag,
+ name: 'ci_live_trace',
+ active: true,
+ project: project)
end
- end
- context "when destroys a production scope" do
- let!(:production_scope) { create_scope(feature_flag, 'production', true) }
let(:params) do
{
namespace_id: project.namespace,
project_id: project,
iid: feature_flag.iid,
operations_feature_flag: {
- scopes_attributes: [
- {
- id: production_scope.id,
- _destroy: 1
- }
- ]
+ name: 'ci_new_live_trace'
}
}
end
- it 'destroys successfully' do
- subject
-
- scopes = json_response['scopes']
- expect(scopes.any? { |scope| scope['environment_scope'] == 'production' })
- .to be_falsy
- end
- end
-
- describe "updating the strategy" do
- it 'creates a default strategy' do
- scope = create_scope(feature_flag, 'production', true, [])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [{ name: 'default', parameters: {} }]
- }])
+ context 'when user is reporter' do
+ let(:user) { reporter }
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
end
- expect(scope_json['strategies']).to eq([{
- "name" => "default",
- "parameters" => {}
- }])
end
- it 'creates a gradualRolloutUserId strategy' do
- scope = create_scope(feature_flag, 'production', true, [])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: 'default', percentage: "70" } }]
- }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
- end
- expect(scope_json['strategies']).to eq([{
- "name" => "gradualRolloutUserId",
- "parameters" => {
- "groupId" => "default",
- "percentage" => "70"
- }
- }])
- end
-
- it 'creates a userWithId strategy' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [{ name: 'userWithId', parameters: { userIds: 'sam,fred' } }]
- }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
- end
- expect(scope_json['strategies']).to eq([{
- "name" => "userWithId",
- "parameters" => { "userIds" => "sam,fred" }
- }])
- end
-
- it 'updates an existing strategy' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: 'default', percentage: "50" } }]
- }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
- end
- expect(scope_json['strategies']).to eq([{
- "name" => "gradualRolloutUserId",
- "parameters" => {
- "groupId" => "default",
- "percentage" => "50"
+ context "when changing default scope's spec" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [
+ {
+ id: feature_flag.default_scope.id,
+ environment_scope: 'review/*'
+ }
+ ]
+ }
}
- }])
- end
-
- it 'clears an existing strategy' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: []
- }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
- end
- expect(scope_json['strategies']).to eq([])
- end
-
- it 'accepts multiple strategies' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [
- { name: 'gradualRolloutUserId', parameters: { groupId: 'mygroup', percentage: '55' } },
- { name: 'userWithId', parameters: { userIds: 'joe' } }
- ]
- }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
- end
- expect(scope_json['strategies'].length).to eq(2)
- expect(scope_json['strategies']).to include({
- "name" => "gradualRolloutUserId",
- "parameters" => { "groupId" => "mygroup", "percentage" => "55" }
- })
- expect(scope_json['strategies']).to include({
- "name" => "userWithId",
- "parameters" => { "userIds" => "joe" }
- })
- end
-
- it 'does not modify strategies when there is no strategies key in the params' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{ id: scope.id }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
end
- expect(scope_json['strategies']).to eq([{
- "name" => "default",
- "parameters" => {}
- }])
- end
-
- it 'leaves an existing strategy when there are no strategies in the params' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'gradualRolloutUserId',
- parameters: { groupId: 'default', percentage: '10' } }])
- put_request(feature_flag, scopes_attributes: [{ id: scope.id }])
-
- expect(response).to have_gitlab_http_status(:ok)
- scope_json = json_response['scopes'].find do |s|
- s['environment_scope'] == 'production'
+ it 'returns 400' do
+ is_expected.to have_gitlab_http_status(:bad_request)
end
- expect(scope_json['strategies']).to eq([{
- "name" => "gradualRolloutUserId",
- "parameters" => { "groupId" => "default", "percentage" => "10" }
- }])
end
- it 'does not accept extra parameters in the strategy params' do
- scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
-
- put_request(feature_flag, scopes_attributes: [{
- id: scope.id,
- strategies: [{ name: 'userWithId', parameters: { userIds: 'joe', groupId: 'default' } }]
- }])
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to eq(["Scopes strategies parameters are invalid"])
- end
- end
-
- context 'when legacy feature flags are set to be read only' do
- it 'does not update the flag' do
- stub_feature_flags(feature_flags_legacy_read_only: true)
-
+ it 'does not update a legacy feature flag' do
put_request(feature_flag, name: 'ci_new_live_trace')
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq(["Legacy feature flags are read-only"])
end
-
- it 'updates the flag if the legacy read-only override is enabled for a particular project' do
- stub_feature_flags(
- feature_flags_legacy_read_only: true,
- feature_flags_legacy_read_only_override: project
- )
-
- put_request(feature_flag, name: 'ci_new_live_trace')
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['name']).to eq('ci_new_live_trace')
- end
end
context 'with a version 2 feature flag' do
@@ -1517,15 +1168,6 @@ RSpec.describe Projects::FeatureFlagsController do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['strategies'].first['scopes']).to eq([])
end
-
- it 'updates the flag when legacy feature flags are set to be read only' do
- stub_feature_flags(feature_flags_legacy_read_only: true)
-
- put_request(new_version_flag, name: 'some-other-name')
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(new_version_flag.reload.name).to eq('some-other-name')
- end
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 12c8c84dd77..d3bdf1baaae 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -227,6 +227,22 @@ RSpec.describe Projects::IssuesController do
end
end
+ describe "GET #show" do
+ before do
+ sign_in(user)
+ project.add_developer(user)
+ end
+
+ it "returns issue_email_participants" 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 })
+ end
+ end
+
describe 'GET #new' do
it 'redirects to signin if not logged in' do
get :new, params: { namespace_id: project.namespace, project_id: project }
@@ -1003,7 +1019,7 @@ RSpec.describe Projects::IssuesController do
def update_verified_issue
update_issue(
issue_params: { title: spammy_title },
- additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true })
+ additional_params: { spam_log_id: spam_logs.last.id, 'g-recaptcha-response': true })
end
it 'returns 200 status' do
@@ -1021,7 +1037,7 @@ RSpec.describe Projects::IssuesController do
it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
spam_log = create(:spam_log)
- expect { update_issue(issue_params: { spam_log_id: spam_log.id, recaptcha_verification: true }) }
+ expect { update_issue(issue_params: { spam_log_id: spam_log.id, 'g-recaptcha-response': true }) }
.not_to change { SpamLog.last.recaptcha_verified }
end
end
@@ -1298,7 +1314,7 @@ RSpec.describe Projects::IssuesController do
let!(:last_spam_log) { spam_logs.last }
def post_verified_issue
- post_new_issue({}, { spam_log_id: last_spam_log.id, recaptcha_verification: true } )
+ post_new_issue({}, { spam_log_id: last_spam_log.id, 'g-recaptcha-response': true } )
end
before do
@@ -1316,7 +1332,7 @@ RSpec.describe Projects::IssuesController do
it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
spam_log = create(:spam_log)
- expect { post_new_issue({}, { spam_log_id: spam_log.id, recaptcha_verification: true } ) }
+ expect { post_new_issue({}, { spam_log_id: spam_log.id, 'g-recaptcha-response': true } ) }
.not_to change { last_spam_log.recaptcha_verified }
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index eb5e62f3d44..430808e1c63 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -675,16 +675,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:forbidden)
end
-
- context 'with restrict_access_to_build_debug_mode feature disabled' do
- before do
- stub_feature_flags(restrict_access_to_build_debug_mode: false)
- end
-
- it 'returns response forbidden' do
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
end
end
end
@@ -1139,18 +1129,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:ok)
end
-
- context 'with restrict_access_to_build_debug_mode feature disabled' do
- before do
- stub_feature_flags(restrict_access_to_build_debug_mode: false)
- end
-
- it 'returns response ok' do
- response = subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
end
context 'without proper permissions for debug logging on a project' do
@@ -1164,18 +1142,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:forbidden)
end
-
- context 'with restrict_access_to_build_debug_mode feature disabled' do
- before do
- stub_feature_flags(restrict_access_to_build_debug_mode: false)
- end
-
- it 'returns response ok' do
- response = subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
end
end
end
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index 8a3c55033cb..f452c22a5ca 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -84,46 +84,12 @@ RSpec.describe Projects::LabelsController do
create(:label_priority, project: project, label: subgroup_label_2, priority: 1)
end
- RSpec.shared_examples 'returns ancestor group labels' do
- it 'returns ancestor group labels', :aggregate_failures do
- get :index, params: params
+ it 'returns ancestor group labels', :aggregate_failures do
+ params = { namespace_id: project.namespace.to_param, project_id: project }
+ get :index, params: params
- expect(assigns(:labels)).to match_array([subgroup_label_1] + group_labels + project_labels)
- expect(assigns(:prioritized_labels)).to match_array([subgroup_label_2] + group_priority_labels + project_priority_labels)
- end
- end
-
- context 'when show_inherited_labels disabled' do
- before do
- stub_feature_flags(show_inherited_labels: false)
- end
-
- context 'when include_ancestor_groups false' do
- let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
-
- it 'does not return ancestor group labels', :aggregate_failures do
- get :index, params: params
-
- expect(assigns(:labels)).to match_array([subgroup_label_1] + project_labels)
- expect(assigns(:prioritized_labels)).to match_array([subgroup_label_2] + project_priority_labels)
- end
- end
-
- context 'when include_ancestor_groups true' do
- let(:params) { { namespace_id: project.namespace.to_param, project_id: project, include_ancestor_groups: true } }
-
- it_behaves_like 'returns ancestor group labels'
- end
- end
-
- context 'when show_inherited_labels enabled' do
- let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
-
- before do
- stub_feature_flags(show_inherited_labels: true)
- end
-
- it_behaves_like 'returns ancestor group labels'
+ expect(assigns(:labels)).to match_array([subgroup_label_1] + group_labels + project_labels)
+ expect(assigns(:prioritized_labels)).to match_array([subgroup_label_2] + group_priority_labels + project_priority_labels)
end
end
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index f4f0a9f8108..f54a07de853 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -193,6 +193,29 @@ RSpec.describe Projects::MergeRequests::DiffsController do
end
end
+ context "with the :default_merge_ref_for_diffs flag on" do
+ let(:diffable_merge_ref) { true }
+
+ subject do
+ go(diff_head: true,
+ diff_id: merge_request.merge_request_diff.id,
+ start_sha: merge_request.merge_request_diff.start_commit_sha)
+ end
+
+ it "correctly generates the right diff between versions" do
+ MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request)
+
+ expect_next_instance_of(CompareService) do |service|
+ expect(service).to receive(:execute).with(
+ project,
+ merge_request.merge_request_diff.head_commit_sha,
+ straight: true)
+ end
+
+ subject
+ end
+ end
+
context 'with diff_head param passed' do
before do
allow(merge_request).to receive(:diffable_merge_ref?)
@@ -378,6 +401,57 @@ RSpec.describe Projects::MergeRequests::DiffsController do
expect(response).to have_gitlab_http_status(:ok)
end
+
+ it 'tracks mr_diffs event' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_mr_diffs_action)
+ .with(merge_request: merge_request)
+
+ subject
+ end
+
+ context 'when DNT is enabled' do
+ before do
+ request.headers['DNT'] = '1'
+ end
+
+ it 'does not track any mr_diffs event' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .not_to receive(:track_mr_diffs_action)
+
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .not_to receive(:track_mr_diffs_single_file_action)
+
+ subject
+ end
+ end
+
+ context 'when user has view_diffs_file_by_file set to false' do
+ before do
+ user.update!(view_diffs_file_by_file: false)
+ end
+
+ it 'does not track single_file_diffs events' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .not_to receive(:track_mr_diffs_single_file_action)
+
+ subject
+ end
+ end
+
+ context 'when user has view_diffs_file_by_file set to true' do
+ before do
+ user.update!(view_diffs_file_by_file: true)
+ end
+
+ it 'tracks single_file_diffs events' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_mr_diffs_single_file_action)
+ .with(merge_request: merge_request, user: user)
+
+ subject
+ end
+ end
end
def collection_arguments(pagination_data = {})
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index e1405660ccb..be4a1504fc9 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -272,6 +272,72 @@ RSpec.describe Projects::PipelinesController do
end
end
+ describe 'GET #index' do
+ subject(:request) { get :index, params: { namespace_id: project.namespace, project_id: project } }
+
+ context 'experiment not active' do
+ it 'does not push tracking_data to gon' do
+ request
+
+ expect(Gon.tracking_data).to be_nil
+ end
+
+ it 'does not record experiment_user' do
+ expect { request }.not_to change(ExperimentUser, :count)
+ end
+ end
+
+ context 'when experiment active' do
+ before do
+ stub_experiment(pipelines_empty_state: true)
+ stub_experiment_for_subject(pipelines_empty_state: true)
+ end
+
+ it 'pushes tracking_data to Gon' do
+ request
+
+ expect(Gon.experiments["pipelinesEmptyState"]).to eq(true)
+ expect(Gon.tracking_data).to match(
+ {
+ category: 'Growth::Activation::Experiment::PipelinesEmptyState',
+ action: 'view',
+ label: anything,
+ property: 'experimental_group',
+ value: anything
+ }
+ )
+ end
+
+ context 'no pipelines created an no CI set up' do
+ before do
+ stub_application_setting(auto_devops_enabled: false)
+ end
+
+ it 'records experiment_user' do
+ expect { request }.to change(ExperimentUser, :count).by(1)
+ end
+ end
+
+ context 'CI set up' do
+ it 'does not record experiment_user' do
+ expect { request }.not_to change(ExperimentUser, :count)
+ end
+ end
+
+ context 'pipelines created' do
+ let!(:pipeline) { create(:ci_pipeline, project: project) }
+
+ before do
+ stub_application_setting(auto_devops_enabled: false)
+ end
+
+ it 'does not record experiment_user' do
+ expect { request }.not_to change(ExperimentUser, :count)
+ end
+ end
+ end
+ end
+
describe 'GET show.json' do
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 74311fa89f3..971eb782fa4 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -14,32 +14,137 @@ RSpec.describe Projects::ProjectMembersController do
expect(response).to have_gitlab_http_status(:ok)
end
- context 'when project belongs to group' do
- let(:user_in_group) { create(:user) }
- let(:project_in_group) { create(:project, :public, group: group) }
+ context 'project members' do
+ context 'when project belongs to group' do
+ let(:user_in_group) { create(:user) }
+ let(:project_in_group) { create(:project, :public, group: group) }
+
+ before do
+ group.add_owner(user_in_group)
+ project_in_group.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'lists inherited project members by default' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
+
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
+ end
+
+ it 'lists direct project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
+
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
+ end
+
+ it 'lists inherited project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
+
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ end
+ end
+
+ context 'when invited members are present' do
+ let!(:invited_member) { create(:project_member, :invited, project: project) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'excludes the invited members from project members list' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(assigns(:project_members).map(&:invite_email)).not_to contain_exactly(invited_member.invite_email)
+ end
+ end
+ end
+
+ context 'group links' do
+ let!(:project_group_link) { create(:project_group_link, project: project, group: group) }
+
+ it 'lists group links' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link.id)
+ end
+
+ context 'when `search_groups` param is present' do
+ let(:group_2) { create(:group, :public, name: 'group_2') }
+ let!(:project_group_link_2) { create(:project_group_link, project: project, group: group_2) }
+
+ it 'lists group links that match search' do
+ get :index, params: { namespace_id: project.namespace, project_id: project, search_groups: 'group_2' }
+
+ expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link_2.id)
+ end
+ end
+ end
+
+ context 'invited members' do
+ let!(:invited_member) { create(:project_member, :invited, project: project) }
before do
- group.add_owner(user_in_group)
- project_in_group.add_maintainer(user)
+ project.add_maintainer(user)
sign_in(user)
end
- it 'lists inherited project members by default' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
+ context 'when user has `admin_project_member` permissions' do
+ before do
+ allow(controller.helpers).to receive(:can_manage_project_members?).with(project).and_return(true)
+ end
+
+ it 'lists invited members' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(assigns(:invited_members).map(&:invite_email)).to contain_exactly(invited_member.invite_email)
+ end
+ end
+
+ context 'when user does not have `admin_project_member` permissions' do
+ before do
+ allow(controller.helpers).to receive(:can_manage_project_members?).with(project).and_return(false)
+ end
+
+ it 'does not list invited members' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(assigns(:invited_members)).to be_nil
+ end
+ end
+ end
+
+ context 'access requests' do
+ let(:access_requester_user) { create(:user) }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
+ before do
+ project.request_access(access_requester_user)
+ project.add_maintainer(user)
+ sign_in(user)
end
- it 'lists direct project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
+ context 'when user has `admin_project_member` permissions' do
+ before do
+ allow(controller.helpers).to receive(:can_manage_project_members?).with(project).and_return(true)
+ end
+
+ it 'lists access requests' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
+ expect(assigns(:requesters).map(&:user_id)).to contain_exactly(access_requester_user.id)
+ end
end
- it 'lists inherited project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
+ context 'when user does not have `admin_project_member` permissions' do
+ before do
+ allow(controller.helpers).to receive(:can_manage_project_members?).with(project).and_return(false)
+ end
+
+ it 'does not list access requests' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ expect(assigns(:requesters)).to be_nil
+ end
end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index bd7ef3db8b6..a611ac16cd9 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -211,28 +211,13 @@ RSpec.describe ProjectsController do
end
end
- context 'when the storage is not available', :broken_storage do
- let_it_be(:project) { create(:project, :broken_storage) }
-
- before do
- project.add_developer(user)
- sign_in(user)
- end
-
- it 'renders a 503' do
- get :show, params: { namespace_id: project.namespace, id: project }
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- end
- end
-
context "project with empty repo" do
let_it_be(:empty_project) { create(:project_empty_repo, :public) }
before do
sign_in(user)
- allow(controller).to receive(:record_experiment_user).with(:invite_members_empty_project_version_a)
+ allow(controller).to receive(:record_experiment_user)
end
User.project_views.keys.each do |project_view|
@@ -498,14 +483,14 @@ RSpec.describe ProjectsController do
describe '#housekeeping' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
- let(:housekeeping) { Projects::HousekeepingService.new(project) }
+ let(:housekeeping) { Repositories::HousekeepingService.new(project) }
context 'when authenticated as owner' do
before do
group.add_owner(user)
sign_in(user)
- allow(Projects::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping)
+ allow(Repositories::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping)
end
it 'forces a full garbage collection' do
@@ -616,7 +601,7 @@ RSpec.describe ProjectsController do
expect { update_project path: 'renamed_path' }
.not_to change { project.reload.path }
- expect(controller).to set_flash.now[:alert].to(s_('UpdateProject|Cannot rename project because it contains container registry tags!'))
+ expect(controller).to set_flash[:alert].to(s_('UpdateProject|Cannot rename project because it contains container registry tags!'))
expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -748,7 +733,7 @@ RSpec.describe ProjectsController do
describe '#transfer', :enable_admin_mode do
render_views
- let_it_be(:project, reload: true) { create(:project, :repository) }
+ let_it_be(:project, reload: true) { create(:project) }
let_it_be(:admin) { create(:admin) }
let_it_be(:new_namespace) { create(:namespace) }
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 2fb17e56f37..737ec4f95c5 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe RegistrationsController do
include TermsHelper
before do
- stub_feature_flags(invisible_captcha: false)
stub_application_setting(require_admin_approval_after_user_signup: false)
end
@@ -193,15 +192,10 @@ RSpec.describe RegistrationsController do
context 'when invisible captcha is enabled' do
before do
- stub_feature_flags(invisible_captcha: true)
- InvisibleCaptcha.timestamp_enabled = true
+ stub_application_setting(invisible_captcha_enabled: true)
InvisibleCaptcha.timestamp_threshold = treshold
end
- after do
- InvisibleCaptcha.timestamp_enabled = false
- end
-
let(:treshold) { 4 }
let(:session_params) { { invisible_captcha_timestamp: form_rendered_time.iso8601 } }
let(:form_rendered_time) { Time.current }
diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb
index 551abf9241d..34052496871 100644
--- a/spec/controllers/repositories/git_http_controller_spec.rb
+++ b/spec/controllers/repositories/git_http_controller_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe Repositories::GitHttpController do
}.from(0).to(1)
end
- it 'records a namespace onboarding progress action' do
+ it 'records an onboarding progress action' do
expect_next_instance_of(OnboardingProgressService) do |service|
expect(service).to receive(:execute).with(action: :git_read)
end
diff --git a/spec/controllers/runner_setup_controller_spec.rb b/spec/controllers/runner_setup_controller_spec.rb
deleted file mode 100644
index 0b237500907..00000000000
--- a/spec/controllers/runner_setup_controller_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe RunnerSetupController do
- let(:user) { create(:user) }
-
- before do
- sign_in(user)
- end
-
- describe 'GET #platforms' do
- it 'renders the platforms' do
- get :platforms
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to have_key("windows")
- expect(json_response).to have_key("kubernetes")
- end
- end
-end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
deleted file mode 100644
index 916befe3f62..00000000000
--- a/spec/controllers/users_controller_spec.rb
+++ /dev/null
@@ -1,925 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe UsersController do
- # This user should have the same e-mail address associated with the GPG key prepared for tests
- let(:user) { create(:user, email: GpgHelpers::User1.emails[0]) }
- let(:private_user) { create(:user, private_profile: true) }
- let(:public_user) { create(:user) }
-
- describe 'GET #show' do
- context 'with rendered views' do
- render_views
-
- describe 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders the show template' do
- get :show, params: { username: user.username }
-
- expect(response).to be_successful
- expect(response).to render_template('show')
- end
- end
-
- describe 'when logged out' do
- it 'renders the show template' do
- get :show, params: { username: user.username }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('show')
- end
- end
- end
-
- context 'when public visibility level is restricted' do
- before do
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
- end
-
- context 'when logged out' do
- it 'redirects to login page' do
- get :show, params: { username: user.username }
- expect(response).to redirect_to new_user_session_path
- end
- end
-
- context 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders show' do
- get :show, params: { username: user.username }
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('show')
- end
- end
- end
-
- context 'when a user by that username does not exist' do
- context 'when logged out' do
- it 'redirects to login page' do
- get :show, params: { username: 'nonexistent' }
- expect(response).to redirect_to new_user_session_path
- end
- end
-
- context 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders 404' do
- get :show, params: { username: 'nonexistent' }
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- context 'json with events' do
- let(:project) { create(:project) }
-
- before do
- project.add_developer(user)
- Gitlab::DataBuilder::Push.build_sample(project, user)
-
- sign_in(user)
- end
-
- it 'loads events' do
- get :show, params: { username: user }, format: :json
-
- expect(assigns(:events)).not_to be_empty
- end
-
- it 'hides events if the user cannot read cross project' do
- allow(Ability).to receive(:allowed?).and_call_original
- expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
-
- get :show, params: { username: user }, format: :json
-
- expect(assigns(:events)).to be_empty
- end
-
- it 'hides events if the user has a private profile' do
- Gitlab::DataBuilder::Push.build_sample(project, private_user)
-
- get :show, params: { username: private_user.username }, format: :json
-
- expect(assigns(:events)).to be_empty
- end
- end
- end
-
- describe 'GET #activity' do
- context 'with rendered views' do
- render_views
-
- describe 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders the show template' do
- get :show, params: { username: user.username }
-
- expect(response).to be_successful
- expect(response).to render_template('show')
- end
- end
-
- describe 'when logged out' do
- it 'renders the show template' do
- get :activity, params: { username: user.username }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('show')
- end
- end
- end
-
- context 'when public visibility level is restricted' do
- before do
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
- end
-
- context 'when logged out' do
- it 'redirects to login page' do
- get :activity, params: { username: user.username }
- expect(response).to redirect_to new_user_session_path
- end
- end
-
- context 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders show' do
- get :activity, params: { username: user.username }
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('show')
- end
- end
- end
-
- context 'when a user by that username does not exist' do
- context 'when logged out' do
- it 'redirects to login page' do
- get :activity, params: { username: 'nonexistent' }
- expect(response).to redirect_to new_user_session_path
- end
- end
-
- context 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'renders 404' do
- get :activity, params: { username: 'nonexistent' }
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- context 'json with events' do
- let(:project) { create(:project) }
-
- before do
- project.add_developer(user)
- Gitlab::DataBuilder::Push.build_sample(project, user)
-
- sign_in(user)
- end
-
- it 'loads events' do
- get :activity, params: { username: user }, format: :json
-
- expect(assigns(:events)).not_to be_empty
- end
-
- it 'hides events if the user cannot read cross project' do
- allow(Ability).to receive(:allowed?).and_call_original
- expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
-
- get :activity, params: { username: user }, format: :json
-
- expect(assigns(:events)).to be_empty
- end
-
- it 'hides events if the user has a private profile' do
- Gitlab::DataBuilder::Push.build_sample(project, private_user)
-
- get :activity, params: { username: private_user.username }, format: :json
-
- expect(assigns(:events)).to be_empty
- end
- end
- end
-
- describe "#ssh_keys" do
- describe "non existent user" do
- it "does not generally work" do
- get :ssh_keys, params: { username: 'not-existent' }
-
- expect(response).not_to be_successful
- end
- end
-
- describe "user with no keys" do
- it "does generally work" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all keys separated with a new line" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response.body).to eq("")
- end
-
- it "responds with text/plain content type" do
- get :ssh_keys, params: { username: user.username }
- expect(response.content_type).to eq("text/plain")
- end
- end
-
- describe "user with keys" do
- let!(:key) { create(:key, user: user) }
- let!(:another_key) { create(:another_key, user: user) }
- let!(:deploy_key) { create(:deploy_key, user: user) }
-
- describe "while signed in" do
- before do
- sign_in(user)
- end
-
- it "does generally work" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all non deploy keys separated with a new line" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
- expect(response.body).to eq(user.all_ssh_keys.join("\n"))
-
- expect(response.body).to include(key.key.sub(' dummy@gitlab.com', ''))
- expect(response.body).to include(another_key.key.sub(' dummy@gitlab.com', ''))
-
- expect(response.body).not_to include(deploy_key.key)
- end
-
- it "does not render the comment of the key" do
- get :ssh_keys, params: { username: user.username }
- expect(response.body).not_to match(/dummy@gitlab.com/)
- end
-
- it "responds with text/plain content type" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response.content_type).to eq("text/plain")
- end
- end
-
- describe 'when logged out' do
- before do
- sign_out(user)
- end
-
- it "still does generally work" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all non deploy keys separated with a new line" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
- expect(response.body).to eq(user.all_ssh_keys.join("\n"))
-
- expect(response.body).to include(key.key.sub(' dummy@gitlab.com', ''))
- expect(response.body).to include(another_key.key.sub(' dummy@gitlab.com', ''))
-
- expect(response.body).not_to include(deploy_key.key)
- end
-
- it "does not render the comment of the key" do
- get :ssh_keys, params: { username: user.username }
- expect(response.body).not_to match(/dummy@gitlab.com/)
- end
-
- it "responds with text/plain content type" do
- get :ssh_keys, params: { username: user.username }
-
- expect(response.content_type).to eq("text/plain")
- end
- end
- end
- end
-
- describe "#gpg_keys" do
- describe "non existent user" do
- it "does not generally work" do
- get :gpg_keys, params: { username: 'not-existent' }
-
- expect(response).not_to be_successful
- end
- end
-
- describe "user with no keys" do
- it "does generally work" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all keys separated with a new line" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.body).to eq("")
- end
-
- it "responds with text/plain content type" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.content_type).to eq("text/plain")
- end
- end
-
- describe "user with keys" do
- let!(:gpg_key) { create(:gpg_key, user: user) }
- let!(:another_gpg_key) { create(:another_gpg_key, user: user) }
-
- describe "while signed in" do
- before do
- sign_in(user)
- end
-
- it "does generally work" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all verified keys separated with a new line" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
- expect(response.body).to eq(user.gpg_keys.select(&:verified?).map(&:key).join("\n"))
-
- expect(response.body).to include(gpg_key.key)
- expect(response.body).to include(another_gpg_key.key)
- end
-
- it "responds with text/plain content type" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.content_type).to eq("text/plain")
- end
- end
-
- describe 'when logged out' do
- before do
- sign_out(user)
- end
-
- it "still does generally work" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response).to be_successful
- end
-
- it "renders all verified keys separated with a new line" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
- expect(response.body).to eq(user.gpg_keys.map(&:key).join("\n"))
-
- expect(response.body).to include(gpg_key.key)
- expect(response.body).to include(another_gpg_key.key)
- end
-
- it "responds with text/plain content type" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.content_type).to eq("text/plain")
- end
- end
-
- describe 'when revoked' do
- before do
- sign_in(user)
- another_gpg_key.revoke
- end
-
- it "doesn't render revoked keys" do
- get :gpg_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
-
- expect(response.body).to include(gpg_key.key)
- expect(response.body).not_to include(another_gpg_key.key)
- end
-
- it "doesn't render revoked keys for non-authorized users" do
- sign_out(user)
- get :gpg_keys, params: { username: user.username }
-
- expect(response.body).not_to eq('')
-
- expect(response.body).to include(gpg_key.key)
- expect(response.body).not_to include(another_gpg_key.key)
- end
- end
- end
- end
-
- describe 'GET #calendar' do
- context 'for user' do
- let(:project) { create(:project) }
-
- before do
- sign_in(user)
- project.add_developer(user)
- end
-
- context 'with public profile' do
- it 'renders calendar' do
- push_data = Gitlab::DataBuilder::Push.build_sample(project, public_user)
- EventCreateService.new.push(project, public_user, push_data)
-
- get :calendar, params: { username: public_user.username }, format: :json
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- context 'with private profile' do
- it 'does not render calendar' do
- push_data = Gitlab::DataBuilder::Push.build_sample(project, private_user)
- EventCreateService.new.push(project, private_user, push_data)
-
- get :calendar, params: { username: private_user.username }, format: :json
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- context 'forked project' do
- let(:project) { create(:project) }
- let(:forked_project) { Projects::ForkService.new(project, user).execute }
-
- before do
- sign_in(user)
- project.add_developer(user)
-
- push_data = Gitlab::DataBuilder::Push.build_sample(project, user)
-
- fork_push_data = Gitlab::DataBuilder::Push
- .build_sample(forked_project, user)
-
- EventCreateService.new.push(project, user, push_data)
- EventCreateService.new.push(forked_project, user, fork_push_data)
- end
-
- it 'includes forked projects' do
- get :calendar, params: { username: user.username }
- expect(assigns(:contributions_calendar).projects.count).to eq(2)
- end
- end
- end
-
- describe 'GET #calendar_activities' do
- let!(:project) { create(:project) }
- let(:user) { create(:user) }
-
- before do
- allow_next_instance_of(User) do |instance|
- allow(instance).to receive(:contributed_projects_ids).and_return([project.id])
- end
-
- sign_in(user)
- project.add_developer(user)
- end
-
- it 'assigns @calendar_date' do
- get :calendar_activities, params: { username: user.username, date: '2014-07-31' }
- expect(assigns(:calendar_date)).to eq(Date.parse('2014-07-31'))
- end
-
- context 'for user' do
- context 'with public profile' do
- let(:issue) { create(:issue, project: project, author: user) }
- let(:note) { create(:note, noteable: issue, author: user, project: project) }
-
- render_views
-
- before do
- create_push_event
- create_note_event
- end
-
- it 'renders calendar_activities' do
- get :calendar_activities, params: { username: public_user.username }
-
- expect(assigns[:events]).not_to be_empty
- end
-
- it 'avoids N+1 queries', :request_store do
- get :calendar_activities, params: { username: public_user.username }
-
- control = ActiveRecord::QueryRecorder.new { get :calendar_activities, params: { username: public_user.username } }
-
- create_push_event
- create_note_event
-
- expect { get :calendar_activities, params: { username: public_user.username } }.not_to exceed_query_limit(control)
- end
- end
-
- context 'with private profile' do
- it 'does not render calendar_activities' do
- push_data = Gitlab::DataBuilder::Push.build_sample(project, private_user)
- EventCreateService.new.push(project, private_user, push_data)
-
- get :calendar_activities, params: { username: private_user.username }
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'external authorization' do
- subject { get :calendar_activities, params: { username: user.username } }
-
- it_behaves_like 'disabled when using an external authorization service'
- end
-
- def create_push_event
- push_data = Gitlab::DataBuilder::Push.build_sample(project, public_user)
- EventCreateService.new.push(project, public_user, push_data)
- end
-
- def create_note_event
- EventCreateService.new.leave_note(note, public_user)
- end
- end
- end
-
- describe 'GET #contributed' do
- let(:project) { create(:project, :public) }
-
- subject do
- get :contributed, params: { username: author.username }, format: format
- end
-
- before do
- sign_in(user)
-
- project.add_developer(public_user)
- project.add_developer(private_user)
- create(:push_event, project: project, author: author)
-
- subject
- end
-
- shared_examples_for 'renders contributed projects' do
- it 'renders contributed projects' do
- expect(assigns[:contributed_projects]).not_to be_empty
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- %i(html json).each do |format|
- context "format: #{format}" do
- let(:format) { format }
-
- context 'with public profile' do
- let(:author) { public_user }
-
- it_behaves_like 'renders contributed projects'
- end
-
- context 'with private profile' do
- let(:author) { private_user }
-
- it 'returns 404' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
-
- context 'with a user that has the ability to read private profiles', :enable_admin_mode do
- let(:user) { create(:admin) }
-
- it_behaves_like 'renders contributed projects'
- end
- end
- end
- end
- end
-
- describe 'GET #starred' do
- let(:project) { create(:project, :public) }
-
- subject do
- get :starred, params: { username: author.username }, format: format
- end
-
- before do
- author.toggle_star(project)
-
- sign_in(user)
- subject
- end
-
- shared_examples_for 'renders starred projects' do
- it 'renders starred projects' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns[:starred_projects]).not_to be_empty
- end
- end
-
- %i(html json).each do |format|
- context "format: #{format}" do
- let(:format) { format }
-
- context 'with public profile' do
- let(:author) { public_user }
-
- it_behaves_like 'renders starred projects'
- end
-
- context 'with private profile' do
- let(:author) { private_user }
-
- it 'returns 404' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
-
- context 'with a user that has the ability to read private profiles', :enable_admin_mode do
- let(:user) { create(:admin) }
-
- it_behaves_like 'renders starred projects'
- end
- end
- end
- end
- end
-
- describe 'GET #snippets' do
- before do
- sign_in(user)
- end
-
- context 'format html' do
- it 'renders snippets page' do
- get :snippets, params: { username: user.username }
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('show')
- end
- end
-
- context 'format json' do
- it 'response with snippets json data' do
- get :snippets, params: { username: user.username }, format: :json
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to have_key('html')
- end
- end
-
- context 'external authorization' do
- subject { get :snippets, params: { username: user.username } }
-
- it_behaves_like 'disabled when using an external authorization service'
- end
- end
-
- describe 'GET #exists' do
- before do
- sign_in(user)
- end
-
- context 'when user exists' do
- it 'returns JSON indicating the user exists' do
- get :exists, params: { username: user.username }
-
- expected_json = { exists: true }.to_json
- expect(response.body).to eq(expected_json)
- end
-
- context 'when the casing is different' do
- let(:user) { create(:user, username: 'CamelCaseUser') }
-
- it 'returns JSON indicating the user exists' do
- get :exists, params: { username: user.username.downcase }
-
- expected_json = { exists: true }.to_json
- expect(response.body).to eq(expected_json)
- end
- end
- end
-
- context 'when the user does not exist' do
- it 'returns JSON indicating the user does not exist' do
- get :exists, params: { username: 'foo' }
-
- expected_json = { exists: false }.to_json
- expect(response.body).to eq(expected_json)
- end
-
- context 'when a user changed their username' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
-
- it 'returns JSON indicating a user by that username does not exist' do
- get :exists, params: { username: 'old-username' }
-
- expected_json = { exists: false }.to_json
- expect(response.body).to eq(expected_json)
- end
- end
- end
- end
-
- describe 'GET #suggests' do
- context 'when user exists' do
- it 'returns JSON indicating the user exists and a suggestion' do
- get :suggests, params: { username: user.username }
-
- expected_json = { exists: true, suggests: ["#{user.username}1"] }.to_json
- expect(response.body).to eq(expected_json)
- end
-
- context 'when the casing is different' do
- let(:user) { create(:user, username: 'CamelCaseUser') }
-
- it 'returns JSON indicating the user exists and a suggestion' do
- get :suggests, params: { username: user.username.downcase }
-
- expected_json = { exists: true, suggests: ["#{user.username.downcase}1"] }.to_json
- expect(response.body).to eq(expected_json)
- end
- end
- end
-
- context 'when the user does not exist' do
- it 'returns JSON indicating the user does not exist' do
- get :suggests, params: { username: 'foo' }
-
- expected_json = { exists: false, suggests: [] }.to_json
- expect(response.body).to eq(expected_json)
- end
-
- context 'when a user changed their username' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
-
- it 'returns JSON indicating a user by that username does not exist' do
- get :suggests, params: { username: 'old-username' }
-
- expected_json = { exists: false, suggests: [] }.to_json
- expect(response.body).to eq(expected_json)
- end
- end
- end
- end
-
- describe '#ensure_canonical_path' do
- before do
- sign_in(user)
- end
-
- context 'for a GET request' do
- context 'when requesting users at the root path' do
- context 'when requesting the canonical path' do
- let(:user) { create(:user, username: 'CamelCaseUser') }
-
- context 'with exactly matching casing' do
- it 'responds with success' do
- get :show, params: { username: user.username }
-
- expect(response).to be_successful
- end
- end
-
- context 'with different casing' do
- it 'redirects to the correct casing' do
- get :show, params: { username: user.username.downcase }
-
- expect(response).to redirect_to(user)
- expect(controller).not_to set_flash[:notice]
- end
- end
- end
-
- context 'when requesting a redirected path' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
-
- it 'redirects to the canonical path' do
- get :show, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user)
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
-
- context 'when the old path is a substring of the scheme or host' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
-
- it 'does not modify the requested host' do
- get :show, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user)
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
- end
-
- context 'when the old path is substring of users' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
-
- it 'redirects to the canonical path' do
- get :show, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user)
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
- end
- end
- end
-
- context 'when requesting users under the /users path' do
- context 'when requesting the canonical path' do
- let(:user) { create(:user, username: 'CamelCaseUser') }
-
- context 'with exactly matching casing' do
- it 'responds with success' do
- get :projects, params: { username: user.username }
-
- expect(response).to be_successful
- end
- end
-
- context 'with different casing' do
- it 'redirects to the correct casing' do
- get :projects, params: { username: user.username.downcase }
-
- expect(response).to redirect_to(user_projects_path(user))
- expect(controller).not_to set_flash[:notice]
- end
- end
- end
-
- context 'when requesting a redirected path' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
-
- it 'redirects to the canonical path' do
- get :projects, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user_projects_path(user))
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
-
- context 'when the old path is a substring of the scheme or host' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
-
- it 'does not modify the requested host' do
- get :projects, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user_projects_path(user))
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
- end
-
- context 'when the old path is substring of users' do
- let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
-
- # I.e. /users/ser should not become /ufoos/ser
- it 'does not modify the /users part of the path' do
- get :projects, params: { username: redirect_route.path }
-
- expect(response).to redirect_to(user_projects_path(user))
- expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
- end
- end
- end
- end
- end
- end
-
- context 'token authentication' do
- it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do
- before do
- default_params.merge!(username: user.username)
- end
- end
- end
-
- def user_moved_message(redirect_route, user)
- "User '#{redirect_route.path}' was moved to '#{user.full_path}'. Please update any links and bookmarks that may still have the old path."
- end
-end