diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 15:26:25 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 15:26:25 +0300 |
commit | a09983ae35713f5a2bbb100981116d31ce99826e (patch) | |
tree | 2ee2af7bd104d57086db360a7e6d8c9d5d43667a /spec/support/shared_examples/controllers | |
parent | 18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff) |
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'spec/support/shared_examples/controllers')
10 files changed, 494 insertions, 130 deletions
diff --git a/spec/support/shared_examples/controllers/import_controller_new_import_ui_shared_examples.rb b/spec/support/shared_examples/controllers/import_controller_new_import_ui_shared_examples.rb deleted file mode 100644 index 88ad1f6cde2..00000000000 --- a/spec/support/shared_examples/controllers/import_controller_new_import_ui_shared_examples.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'import controller with new_import_ui feature flag' do - include ImportSpecHelper - - context 'with new_import_ui feature flag enabled' do - let(:group) { create(:group) } - - before do - stub_feature_flags(new_import_ui: true) - group.add_owner(user) - end - - it "returns variables for json request" do - project = create(:project, import_type: provider_name, creator_id: user.id) - stub_client(client_repos_field => [repo]) - - get :status, format: :json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) - expect(json_response.dig("provider_repos", 0, "id")).to eq(repo_id) - expect(json_response.dig("namespaces", 0, "id")).to eq(group.id) - end - - it "does not show already added project" do - project = create(:project, import_type: provider_name, namespace: user.namespace, import_status: :finished, import_source: import_source) - stub_client(client_repos_field => [repo]) - - get :status, format: :json - - expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) - expect(json_response.dig("provider_repos")).to eq([]) - end - end -end diff --git a/spec/support/shared_examples/controllers/import_controller_status_shared_examples.rb b/spec/support/shared_examples/controllers/import_controller_status_shared_examples.rb new file mode 100644 index 00000000000..ecb9abc5c46 --- /dev/null +++ b/spec/support/shared_examples/controllers/import_controller_status_shared_examples.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'import controller status' do + include ImportSpecHelper + + let(:group) { create(:group) } + + before do + group.add_owner(user) + end + + it "returns variables for json request" do + project = create(:project, import_type: provider_name, creator_id: user.id) + stub_client(client_repos_field => [repo]) + + get :status, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) + expect(json_response.dig("provider_repos", 0, "id")).to eq(repo_id) + expect(json_response.dig("namespaces", 0, "id")).to eq(group.id) + end + + it "does not show already added project" do + project = create(:project, import_type: provider_name, namespace: user.namespace, import_status: :finished, import_source: import_source) + stub_client(client_repos_field => [repo]) + + get :status, format: :json + + expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id) + expect(json_response.dig("provider_repos")).to eq([]) + end +end diff --git a/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb b/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb index 60abb76acec..7f26155f9d6 100644 --- a/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb +++ b/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb @@ -9,13 +9,38 @@ RSpec.shared_examples 'known sign in' do user.update!(current_sign_in_ip: ip) end - context 'with a valid post' do - context 'when remote IP does not match user last sign in IP' do - before do - stub_user_ip('127.0.0.1') - stub_remote_ip('169.0.0.1') - end + def stub_cookie(value = user.id) + cookies.encrypted[KnownSignIn::KNOWN_SIGN_IN_COOKIE] = { + value: value, expires: KnownSignIn::KNOWN_SIGN_IN_COOKIE_EXPIRY + } + end + + context 'when the remote IP and the last sign in IP match' do + before do + stub_user_ip('169.0.0.1') + stub_remote_ip('169.0.0.1') + end + + it 'does not notify the user' do + expect(NotificationService).not_to receive(:new) + post_action + end + + it 'sets/updates the encrypted cookie' do + post_action + + expect(cookies.encrypted[KnownSignIn::KNOWN_SIGN_IN_COOKIE]).to eq(user.id) + end + end + + context 'when the remote IP and the last sign in IP do not match' do + before do + stub_user_ip('127.0.0.1') + stub_remote_ip('169.0.0.1') + end + + context 'when the cookie is not previously set' do it 'notifies the user' do expect_next_instance_of(NotificationService) do |instance| expect(instance).to receive(:unknown_sign_in) @@ -23,37 +48,68 @@ RSpec.shared_examples 'known sign in' do post_action end - end - - context 'when remote IP matches an active session' do - before do - existing_sessions = ActiveSession.session_ids_for_user(user.id) - existing_sessions.each { |sessions| ActiveSession.destroy(user, sessions) } - stub_user_ip('169.0.0.1') - stub_remote_ip('127.0.0.1') + it 'sets the encrypted cookie' do + post_action - ActiveSession.set(user, request) + expect(cookies.encrypted[KnownSignIn::KNOWN_SIGN_IN_COOKIE]).to eq(user.id) end + end - it 'does not notify the user' do - expect_any_instance_of(NotificationService).not_to receive(:unknown_sign_in) + it 'notifies the user when the cookie is expired' do + stub_cookie + + Timecop.freeze((KnownSignIn::KNOWN_SIGN_IN_COOKIE_EXPIRY + 1.day).from_now) do + expect_next_instance_of(NotificationService) do |instance| + expect(instance).to receive(:unknown_sign_in) + end post_action end end - context 'when remote IP address matches last sign in IP' do + context 'when notify_on_unknown_sign_in global setting is false' do before do - stub_user_ip('127.0.0.1') - stub_remote_ip('127.0.0.1') + stub_application_setting(notify_on_unknown_sign_in: false) end it 'does not notify the user' do - expect_any_instance_of(NotificationService).not_to receive(:unknown_sign_in) + expect(NotificationService).not_to receive(:new) + + post_action + end + it 'does not set a cookie' do post_action + + expect(cookies.encrypted[KnownSignIn::KNOWN_SIGN_IN_COOKIE]).to be_nil + end + end + + it 'notifies the user when the cookie is for another user' do + stub_cookie(create(:user).id) + + expect_next_instance_of(NotificationService) do |instance| + expect(instance).to receive(:unknown_sign_in) end + + post_action + end + + it 'does not notify the user when remote IP matches an active session' do + ActiveSession.set(user, request) + + expect(NotificationService).not_to receive(:new) + + post_action + end + + it 'does not notify the user when the cookie is present and not expired' do + stub_cookie + + expect(NotificationService).not_to receive(:new) + + post_action end end end diff --git a/spec/support/shared_examples/controllers/metrics/dashboard/prometheus_api_proxy_shared_examples.rb b/spec/support/shared_examples/controllers/metrics/dashboard/prometheus_api_proxy_shared_examples.rb new file mode 100644 index 00000000000..94cd6971f7c --- /dev/null +++ b/spec/support/shared_examples/controllers/metrics/dashboard/prometheus_api_proxy_shared_examples.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +RSpec.shared_examples_for 'metrics dashboard prometheus api proxy' do + let(:service_params) { [proxyable, 'GET', 'query', expected_params] } + let(:service_result) { { status: :success, body: prometheus_body } } + let(:prometheus_proxy_service) { instance_double(Prometheus::ProxyService) } + let(:proxyable_params) do + { + id: proxyable.id.to_s + } + end + let(:expected_params) do + ActionController::Parameters.new( + prometheus_proxy_params( + proxy_path: 'query', + controller: described_class.controller_path, + action: 'prometheus_proxy' + ) + ).permit! + end + + before do + allow_next_instance_of(Prometheus::ProxyService, *service_params) do |proxy_service| + allow(proxy_service).to receive(:execute).and_return(service_result) + end + end + + context 'with valid requests' do + context 'with success result' do + let(:prometheus_body) { '{"status":"success"}' } + let(:prometheus_json_body) { Gitlab::Json.parse(prometheus_body) } + + it 'returns prometheus response' do + get :prometheus_proxy, params: prometheus_proxy_params + + expect(Prometheus::ProxyService).to have_received(:new).with(*service_params) + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq(prometheus_json_body) + end + + context 'with nil query' do + let(:params_without_query) do + prometheus_proxy_params.except(:query) + end + + before do + expected_params.delete(:query) + end + + it 'does not raise error' do + get :prometheus_proxy, params: params_without_query + + expect(Prometheus::ProxyService).to have_received(:new).with(*service_params) + end + end + end + + context 'with nil result' do + let(:service_result) { nil } + + it 'returns 204 no_content' do + get :prometheus_proxy, params: prometheus_proxy_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 :prometheus_proxy, params: prometheus_proxy_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 :prometheus_proxy, params: prometheus_proxy_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 :prometheus_proxy, params: prometheus_proxy_params + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['status']).to eq('error') + expect(json_response['message']).to eq('error message') + end + end + end + end + + context 'with inappropriate requests' do + let(:prometheus_body) { nil } + + context 'without correct permissions' do + let(:user2) { create(:user) } + + before do + sign_out(user) + sign_in(user2) + end + + it 'returns 404' do + get :prometheus_proxy, params: prometheus_proxy_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'with invalid proxyable id' do + let(:prometheus_body) { nil } + + it 'returns 404' do + get :prometheus_proxy, params: prometheus_proxy_params(id: proxyable.id + 1) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + private + + def prometheus_proxy_params(params = {}) + { + proxy_path: 'query', + query: '1' + }.merge(proxyable_params).merge(params) + end +end diff --git a/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb b/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb new file mode 100644 index 00000000000..cb8f6721d66 --- /dev/null +++ b/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +RSpec.shared_examples_for 'GET #metrics_dashboard correctly formatted response' do + it 'returns a json object with the correct keys' do + get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json + + # Exclude `all_dashboards` to handle separately, at spec/controllers/projects/environments_controller_spec.rb:565 + # because `all_dashboards` key is not part of expected shared behavior + 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 + +RSpec.shared_examples_for 'GET #metrics_dashboard for dashboard' do |dashboard_name| + let(:expected_keys) { %w(dashboard status metrics_data) } + let(:status_code) { :ok } + + it_behaves_like 'GET #metrics_dashboard correctly formatted response' + + it 'returns correct dashboard' do + get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json + + expect(json_response['dashboard']['dashboard']).to eq(dashboard_name) + end +end diff --git a/spec/support/shared_examples/controllers/namespace_storage_limit_alert_shared_examples.rb b/spec/support/shared_examples/controllers/namespace_storage_limit_alert_shared_examples.rb deleted file mode 100644 index 7885eb6c1f8..00000000000 --- a/spec/support/shared_examples/controllers/namespace_storage_limit_alert_shared_examples.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'namespace storage limit alert' do - let(:alert_level) { :info } - - before do - allow_next_instance_of(Namespaces::CheckStorageSizeService, namespace, user) do |check_storage_size_service| - expect(check_storage_size_service).to receive(:execute).and_return( - ServiceResponse.success( - payload: { - alert_level: alert_level, - usage_message: "Usage", - explanation_message: "Explanation", - root_namespace: namespace - } - ) - ) - end - - allow(controller).to receive(:current_user).and_return(user) - end - - render_views - - it 'does render' do - subject - - expect(response.body).to match(/Explanation/) - expect(response.body).to have_css('.js-namespace-storage-alert-dismiss') - end - - context 'when alert_level is error' do - let(:alert_level) { :error } - - it 'does not render a dismiss button' do - subject - - expect(response.body).not_to have_css('.js-namespace-storage-alert-dismiss') - end - end - - context 'when cookie is set' do - before do - cookies["hide_storage_limit_alert_#{namespace.id}_info"] = 'true' - end - - it 'does not render alert' do - subject - - expect(response.body).not_to match(/Explanation/) - end - end -end diff --git a/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb b/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb new file mode 100644 index 00000000000..c3e8f807afb --- /dev/null +++ b/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'raw snippet blob' do + context 'with valid params' do + before do + subject + end + + it 'delivers file with correct Workhorse headers' do + expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + + it 'responds with status 200' do + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with invalid file path' do + let(:filepath) { 'doesnotexist' } + + it_behaves_like 'returning response status', :not_found + end + + context 'with invalid ref' do + let(:ref) { 'doesnotexist' } + + it_behaves_like 'returning response status', :not_found + end + + it_behaves_like 'content disposition headers' +end + +RSpec.shared_examples 'raw snippet without repository' do |unauthorized_status| + context 'when authorized' do + it 'returns a 422' do + subject + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + + context 'when unauthorized' do + let(:visibility) { :private } + + it_behaves_like 'returning response status', unauthorized_status + end +end diff --git a/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb b/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb new file mode 100644 index 00000000000..aa4d78b23f4 --- /dev/null +++ b/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'snippets sort order' do + let(:params) { {} } + let(:sort_argument) { {} } + let(:sort_params) { params.merge(sort_argument)} + + before do + sign_in(user) + + stub_snippet_counter + end + + subject { get :index, params: sort_params } + + context 'when no sort param is provided' do + it 'calls SnippetsFinder with updated_at sort option' do + expect(SnippetsFinder).to receive(:new).with(user, + hash_including(sort: 'updated_desc')).and_call_original + + subject + end + end + + context 'when sort param is provided' do + let(:order) { 'created_desc' } + let(:sort_argument) { { sort: order } } + + it 'calls SnippetsFinder with the given sort param' do + expect(SnippetsFinder).to receive(:new).with(user, + hash_including(sort: order)).and_call_original + + subject + end + end + + def stub_snippet_counter + allow(Snippets::CountService) + .to receive(:new).and_return(double(:count_service, execute: {})) + end +end diff --git a/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb b/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb new file mode 100644 index 00000000000..90588756eb0 --- /dev/null +++ b/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'tracking unique visits' do |method| + it 'tracks unique visit if the format is HTML' do + expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit).with(instance_of(String), target_id) + + get method, params: request_params, format: :html + end + + it 'tracks unique visit if DNT is not enabled' do + expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit).with(instance_of(String), target_id) + request.headers['DNT'] = '0' + + get method, params: request_params, format: :html + end + + it 'does not track unique visit if DNT is enabled' do + expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) + request.headers['DNT'] = '1' + + get method, params: request_params, format: :html + end + + it 'does not track unique visit if the format is JSON' do + expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) + + get method, params: request_params, format: :json + end +end diff --git a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb index b5f2c0d07bf..4df3139d56e 100644 --- a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb +++ b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb @@ -104,6 +104,35 @@ RSpec.shared_examples 'wiki controller actions' do end end + describe 'GET #diff' do + context 'when commit exists' do + it 'renders the diff' do + get :diff, params: routing_params.merge(id: wiki_title, version_id: wiki.repository.commit.id) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('shared/wikis/diff') + expect(assigns(:diffs)).to be_a(Gitlab::Diff::FileCollection::Base) + expect(assigns(:diff_notes_disabled)).to be(true) + end + end + + context 'when commit does not exist' do + it 'returns a 404 error' do + get :diff, params: routing_params.merge(id: wiki_title, version_id: 'invalid') + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when page does not exist' do + it 'returns a 404 error' do + get :diff, params: routing_params.merge(id: 'invalid') + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + describe 'GET #show' do render_views @@ -118,6 +147,7 @@ RSpec.shared_examples 'wiki controller actions' do subject expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('shared/wikis/show') expect(assigns(:page).title).to eq(wiki_title) expect(assigns(:sidebar_wiki_entries)).to contain_exactly(an_instance_of(WikiPage)) expect(assigns(:sidebar_limited)).to be(false) @@ -130,6 +160,7 @@ RSpec.shared_examples 'wiki controller actions' do subject expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('shared/wikis/show') expect(flash[:notice]).to eq(_('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')) end end @@ -138,19 +169,37 @@ RSpec.shared_examples 'wiki controller actions' do context 'when the page does not exist' do let(:id) { 'does not exist' } - before do - subject - end + context 'when the user can create pages' do + before do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('shared/wikis/edit') + end + + it 'builds a new wiki page with the id as the title' do + expect(assigns(:page).title).to eq(id) + end + + context 'when a random_title param is present' do + let(:random_title) { true } - it 'builds a new wiki page with the id as the title' do - expect(assigns(:page).title).to eq(id) + it 'builds a new wiki page with no title' do + expect(assigns(:page).title).to be_empty + end + end end - context 'when a random_title param is present' do - let(:random_title) { true } + context 'when the user cannot create pages' do + before do + sign_out(:user) + end - it 'builds a new wiki page with no title' do - expect(assigns(:page).title).to be_empty + it 'shows the empty state' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('shared/wikis/empty') end end end @@ -166,6 +215,7 @@ RSpec.shared_examples 'wiki controller actions' do it 'delivers the file with the correct headers' do subject + expect(response).to have_gitlab_http_status(:ok) expect(response.headers['Content-Disposition']).to match(/^inline/) expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq('true') expect(response.cache_control[:public]).to be(false) @@ -179,12 +229,31 @@ RSpec.shared_examples 'wiki controller actions' do it 'renders json in a correct format' do post :preview_markdown, params: routing_params.merge(id: 'page/path', text: '*Markdown* text') + expect(response).to have_gitlab_http_status(:ok) expect(json_response.keys).to match_array(%w(body references)) end end - describe 'GET #edit' do - subject { get(:edit, params: routing_params.merge(id: wiki_title)) } + shared_examples 'edit action' do + context 'when the page does not exist' do + let(:id_param) { 'invalid' } + + it 'redirects to show' do + subject + + expect(response).to redirect_to_wiki(wiki, 'invalid') + end + end + + context 'when id param is blank' do + let(:id_param) { ' ' } + + it 'redirects to the home page' do + subject + + expect(response).to redirect_to_wiki(wiki, 'home') + end + end context 'when page content encoding is invalid' do it 'redirects to show' do @@ -208,6 +277,14 @@ RSpec.shared_examples 'wiki controller actions' do expect(response).to redirect_to_wiki(wiki, page) end end + end + + describe 'GET #edit' do + let(:id_param) { wiki_title } + + subject { get(:edit, params: routing_params.merge(id: id_param)) } + + it_behaves_like 'edit action' context 'when page content encoding is valid' do render_views @@ -224,23 +301,17 @@ RSpec.shared_examples 'wiki controller actions' do describe 'PATCH #update' do let(:new_title) { 'New title' } let(:new_content) { 'New content' } + let(:id_param) { wiki_title } subject do patch(:update, params: routing_params.merge( - id: wiki_title, + id: id_param, wiki: { title: new_title, content: new_content } )) end - context 'when page content encoding is invalid' do - it 'redirects to show' do - allow(controller).to receive(:valid_encoding?).and_return(false) - - subject - expect(response).to redirect_to_wiki(wiki, wiki.list_pages.first) - end - end + it_behaves_like 'edit action' context 'when page content encoding is valid' do render_views |