diff options
Diffstat (limited to 'spec/controllers')
35 files changed, 613 insertions, 503 deletions
diff --git a/spec/controllers/concerns/import_url_params_spec.rb b/spec/controllers/concerns/import_url_params_spec.rb index ddffb243f7a..170263d10a4 100644 --- a/spec/controllers/concerns/import_url_params_spec.rb +++ b/spec/controllers/concerns/import_url_params_spec.rb @@ -55,4 +55,22 @@ RSpec.describe ImportUrlParams do end end end + + context 'url with provided mixed credentials' do + let(:params) do + ActionController::Parameters.new(project: { + import_url: 'https://user@url.com', + import_url_user: '', import_url_password: 'password' + }) + end + + describe '#import_url_params' do + it 'returns import_url built from both url and hash credentials' do + expect(import_url_params).to eq( + import_url: 'https://user:password@url.com', + import_type: 'git' + ) + end + end + end end diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index c3f6c653376..bf578489916 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -112,6 +112,13 @@ RSpec.describe Explore::ProjectsController do expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template('topic') end + + it 'finds topic by case insensitive name' do + get :topic, params: { topic_name: 'TOPIC1' } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('topic') + end end end end diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index dbaed8aaa19..4de31e2e135 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -134,6 +134,47 @@ RSpec.describe GraphqlController do post :execute end + + it 'calls the track gitlab cli when trackable method' do + agent = 'GLab - GitLab CLI' + request.env['HTTP_USER_AGENT'] = agent + + expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter) + .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user) + + post :execute + end + + it "assigns username in ApplicationContext" do + post :execute + + expect(Gitlab::ApplicationContext.current).to include('meta.user' => user.username) + end + end + + context 'when 2FA is required for the user' do + let(:user) { create(:user, last_activity_on: Date.yesterday) } + + before do + group = create(:group, require_two_factor_authentication: true) + group.add_developer(user) + + sign_in(user) + end + + it 'does not redirect if 2FA is enabled' do + expect(controller).not_to receive(:redirect_to) + + post :execute + + expect(response).to have_gitlab_http_status(:unauthorized) + + expected_message = "Authentication error: " \ + "enable 2FA in your profile settings to continue using GitLab: %{mfa_help_page}" % + { mfa_help_page: EnforcesTwoFactorAuthentication::MFA_HELP_PAGE } + + expect(json_response).to eq({ 'errors' => [{ 'message' => expected_message }] }) + end end context 'when user uses an API token' do @@ -189,6 +230,12 @@ RSpec.describe GraphqlController do expect(assigns(:context)[:is_sessionless_user]).to be true end + it "assigns username in ApplicationContext" do + subject + + expect(Gitlab::ApplicationContext.current).to include('meta.user' => user.username) + end + it 'calls the track api when trackable method' do agent = 'vs-code-gitlab-workflow/3.11.1 VSCode/1.52.1 Node.js/12.14.1 (darwin; x64)' request.env['HTTP_USER_AGENT'] = agent @@ -208,6 +255,16 @@ RSpec.describe GraphqlController do subject end + + it 'calls the track gitlab cli when trackable method' do + agent = 'GLab - GitLab CLI' + request.env['HTTP_USER_AGENT'] = agent + + expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter) + .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user) + + subject + end end context 'when user is not logged in' do @@ -222,6 +279,12 @@ RSpec.describe GraphqlController do expect(assigns(:context)[:is_sessionless_user]).to be false end + + it "does not assign a username in ApplicationContext" do + subject + + expect(Gitlab::ApplicationContext.current.key?('meta.user')).to be false + end end it 'includes request object in context' do diff --git a/spec/controllers/groups/group_links_controller_spec.rb b/spec/controllers/groups/group_links_controller_spec.rb index fafe9715946..28febd786de 100644 --- a/spec/controllers/groups/group_links_controller_spec.rb +++ b/spec/controllers/groups/group_links_controller_spec.rb @@ -35,120 +35,6 @@ RSpec.describe Groups::GroupLinksController do end end - describe '#create' do - let(:shared_with_group_id) { shared_with_group.id } - let(:shared_group_access) { GroupGroupLink.default_access } - - subject do - post(:create, - params: { group_id: shared_group, - shared_with_group_id: shared_with_group_id, - shared_group_access: shared_group_access }) - end - - shared_examples 'creates group group link' do - it 'links group with selected group' do - expect { subject }.to change { shared_with_group.shared_groups.include?(shared_group) }.from(false).to(true) - end - - it 'redirects to group links page' do - subject - - expect(response).to(redirect_to(group_group_members_path(shared_group))) - end - - it 'allows access for group member' do - expect { subject }.to( - change { group_member.can?(:read_group, shared_group) }.from(false).to(true)) - end - end - - context 'when user has correct access to both groups' do - before do - shared_with_group.add_developer(user) - shared_group.add_owner(user) - end - - context 'when default access level is requested' do - include_examples 'creates group group link' - end - - context 'when owner access is requested' do - let(:shared_group_access) { Gitlab::Access::OWNER } - - before do - shared_with_group.add_owner(group_member) - end - - include_examples 'creates group group link' - - it 'allows admin access for group member' do - expect { subject }.to( - change { group_member.can?(:admin_group, shared_group) }.from(false).to(true)) - end - end - - it 'updates project permissions', :sidekiq_inline do - expect { subject }.to change { group_member.can?(:read_project, project) }.from(false).to(true) - end - - context 'when shared with group id is not present' do - let(:shared_with_group_id) { nil } - - it 'redirects to group links page' do - subject - - expect(response).to(redirect_to(group_group_members_path(shared_group))) - expect(flash[:alert]).to eq('Please select a group.') - end - end - - context 'when link is not persisted in the database' do - before do - allow(::Groups::GroupLinks::CreateService).to( - receive_message_chain(:new, :execute) - .and_return({ status: :error, - http_status: 409, - message: 'error' })) - end - - it 'redirects to group links page' do - subject - - expect(response).to(redirect_to(group_group_members_path(shared_group))) - expect(flash[:alert]).to eq('error') - end - end - end - - context 'when user does not have access to the group' do - before do - shared_group.add_owner(user) - end - - it 'renders 404' do - subject - - expect(response).to have_gitlab_http_status(:not_found) - end - end - - context 'when user does not have admin access to the shared group' do - before do - shared_with_group.add_developer(user) - shared_group.add_developer(user) - end - - it 'renders 404' do - subject - - expect(response).to have_gitlab_http_status(:not_found) - end - end - - include_examples 'placeholder is passed as `id` parameter', :create - end - describe '#update' do let!(:link) do create(:group_group_link, { shared_group: shared_group, @@ -193,7 +79,8 @@ RSpec.describe Groups::GroupLinksController do subject - expect(json_response).to eq({ "expires_in" => "about 1 month", "expires_soon" => false }) + expect(json_response).to eq({ "expires_in" => controller.helpers.time_ago_with_tooltip(expiry_date), + "expires_soon" => false }) end end diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index b4950b93a3f..a53f09e2afc 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Groups::RunnersController do sign_in(user) end - describe '#index' do + describe '#index', :snowplow do context 'when user is owner' do before do group.add_owner(user) @@ -30,6 +30,12 @@ RSpec.describe Groups::RunnersController do expect(response).to render_template(:index) expect(assigns(:group_runners_limited_count)).to be(2) end + + it 'tracks the event' do + get :index, params: { group_id: group } + + expect_snowplow_event(category: described_class.name, action: 'index', user: user, namespace: group) + end end context 'when user is not owner' do @@ -42,6 +48,12 @@ RSpec.describe Groups::RunnersController do expect(response).to have_gitlab_http_status(:not_found) end + + it 'does not track the event' do + get :index, params: { group_id: group } + + expect_no_snowplow_event + end end end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index a82c5681911..be30011905c 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -509,6 +509,14 @@ RSpec.describe GroupsController, factory_default: :keep do expect(assigns(:issues)).to eq([issue_1]) end end + + it 'saves the sort order to user preferences' do + stub_feature_flags(vue_issues_list: true) + + get :issues, params: { id: group.to_param, sort: 'priority' } + + expect(user.reload.user_preference.issues_sort).to eq('priority') + end end describe 'GET #merge_requests', :sidekiq_might_not_need_inline do @@ -1076,19 +1084,6 @@ RSpec.describe GroupsController, factory_default: :keep do enable_admin_mode!(admin) end - context 'when the group export feature flag is not enabled' do - before do - sign_in(admin) - stub_feature_flags(group_import_export: false) - end - - it 'returns a not found error' do - post :export, params: { id: group.to_param } - - expect(response).to have_gitlab_http_status(:not_found) - end - end - context 'when the user does not have permission to export the group' do before do sign_in(guest) @@ -1189,19 +1184,6 @@ RSpec.describe GroupsController, factory_default: :keep do end end - context 'when the group export feature flag is not enabled' do - before do - sign_in(admin) - stub_feature_flags(group_import_export: false) - end - - it 'returns a not found error' do - post :export, params: { id: group.to_param } - - expect(response).to have_gitlab_http_status(:not_found) - end - end - context 'when the user does not have the required permissions' do before do sign_in(guest) diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 4e2123c8cc4..70dc710f604 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -142,11 +142,11 @@ RSpec.describe HelpController do context 'for Markdown formats' do subject { get :show, params: { path: path }, format: :md } - let(:path) { 'ssh/index' } + let(:path) { 'user/ssh' } context 'when requested file exists' do before do - expect_file_read(File.join(Rails.root, 'doc/ssh/index.md'), content: fixture_file('blockquote_fence_after.md')) + expect_file_read(File.join(Rails.root, 'doc/user/ssh.md'), content: fixture_file('blockquote_fence_after.md')) subject end @@ -257,7 +257,7 @@ RSpec.describe HelpController do it 'always renders not found' do get :show, params: { - path: 'ssh/index' + path: 'user/ssh' }, format: :foo expect(response).to be_not_found diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index 91e43adc472..6d24830af27 100644 --- a/spec/controllers/import/bitbucket_controller_spec.rb +++ b/spec/controllers/import/bitbucket_controller_spec.rb @@ -26,31 +26,55 @@ RSpec.describe Import::BitbucketController do session[:oauth_request_token] = {} end - it "updates access token" do - expires_at = Time.current + 1.day - expires_in = 1.day - access_token = double(token: token, - secret: secret, - expires_at: expires_at, - expires_in: expires_in, - refresh_token: refresh_token) - allow_any_instance_of(OAuth2::Client) - .to receive(:get_token) - .with(hash_including( - 'grant_type' => 'authorization_code', - 'code' => code, - redirect_uri: users_import_bitbucket_callback_url), - {}) - .and_return(access_token) - stub_omniauth_provider('bitbucket') - - get :callback, params: { code: code } - - expect(session[:bitbucket_token]).to eq(token) - expect(session[:bitbucket_refresh_token]).to eq(refresh_token) - expect(session[:bitbucket_expires_at]).to eq(expires_at) - expect(session[:bitbucket_expires_in]).to eq(expires_in) - expect(controller).to redirect_to(status_import_bitbucket_url) + context "when auth state param is invalid" do + let(:random_key) { "pure_random" } + let(:external_bitbucket_auth_url) { "http://fake.bitbucket.host/url" } + + it "redirects to external auth url" do + allow(SecureRandom).to receive(:base64).and_return(random_key) + allow_next_instance_of(OAuth2::Client) do |client| + allow(client).to receive_message_chain(:auth_code, :authorize_url) + .with(redirect_uri: users_import_bitbucket_callback_url, state: random_key) + .and_return(external_bitbucket_auth_url) + end + + get :callback, params: { code: code, state: "invalid-token" } + + expect(controller).to redirect_to(external_bitbucket_auth_url) + end + end + + context "when auth state param is valid" do + before do + session[:bitbucket_auth_state] = 'state' + end + + it "updates access token" do + expires_at = Time.current + 1.day + expires_in = 1.day + access_token = double(token: token, + secret: secret, + expires_at: expires_at, + expires_in: expires_in, + refresh_token: refresh_token) + allow_any_instance_of(OAuth2::Client) + .to receive(:get_token) + .with(hash_including( + 'grant_type' => 'authorization_code', + 'code' => code, + redirect_uri: users_import_bitbucket_callback_url), + {}) + .and_return(access_token) + stub_omniauth_provider('bitbucket') + + get :callback, params: { code: code, state: 'state' } + + expect(session[:bitbucket_token]).to eq(token) + expect(session[:bitbucket_refresh_token]).to eq(refresh_token) + expect(session[:bitbucket_expires_at]).to eq(expires_at) + expect(session[:bitbucket_expires_in]).to eq(expires_in) + expect(controller).to redirect_to(status_import_bitbucket_url) + end end end @@ -59,46 +83,68 @@ RSpec.describe Import::BitbucketController do @repo = double(name: 'vim', slug: 'vim', owner: 'asd', full_name: 'asd/vim', clone_url: 'http://test.host/demo/url.git', 'valid?' => true) @invalid_repo = double(name: 'mercurialrepo', slug: 'mercurialrepo', owner: 'asd', full_name: 'asd/mercurialrepo', clone_url: 'http://test.host/demo/mercurialrepo.git', 'valid?' => false) allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org') + end - assign_session_tokens + context "when token does not exists" do + let(:random_key) { "pure_random" } + let(:external_bitbucket_auth_url) { "http://fake.bitbucket.host/url" } + + it 'redirects to authorize url with state included' do + allow(SecureRandom).to receive(:base64).and_return(random_key) + allow_next_instance_of(OAuth2::Client) do |client| + allow(client).to receive_message_chain(:auth_code, :authorize_url) + .with(redirect_uri: users_import_bitbucket_callback_url, state: random_key) + .and_return(external_bitbucket_auth_url) + end + + get :status, format: :json + + expect(controller).to redirect_to(external_bitbucket_auth_url) + end end - it_behaves_like 'import controller status' do + context "when token is valid" do before do - allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org') + assign_session_tokens end - let(:repo) { @repo } - let(:repo_id) { @repo.full_name } - let(:import_source) { @repo.full_name } - let(:provider_name) { 'bitbucket' } - let(:client_repos_field) { :repos } - end + it_behaves_like 'import controller status' do + before do + allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org') + end - it 'returns invalid repos' do - allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo, @invalid_repo]) + let(:repo) { @repo } + let(:repo_id) { @repo.full_name } + let(:import_source) { @repo.full_name } + let(:provider_name) { 'bitbucket' } + let(:client_repos_field) { :repos } + end - get :status, format: :json + it 'returns invalid repos' do + allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo, @invalid_repo]) - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['incompatible_repos'].length).to eq(1) - expect(json_response.dig("incompatible_repos", 0, "id")).to eq(@invalid_repo.full_name) - expect(json_response['provider_repos'].length).to eq(1) - expect(json_response.dig("provider_repos", 0, "id")).to eq(@repo.full_name) - end + get :status, format: :json - context 'when filtering' do - let(:filter) { '<html>test</html>' } - let(:expected_filter) { 'test' } + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['incompatible_repos'].length).to eq(1) + expect(json_response.dig("incompatible_repos", 0, "id")).to eq(@invalid_repo.full_name) + expect(json_response['provider_repos'].length).to eq(1) + expect(json_response.dig("provider_repos", 0, "id")).to eq(@repo.full_name) + end - subject { get :status, params: { filter: filter }, as: :json } + context 'when filtering' do + let(:filter) { '<html>test</html>' } + let(:expected_filter) { 'test' } - it 'passes sanitized filter param to bitbucket client' do - expect_next_instance_of(Bitbucket::Client) do |client| - expect(client).to receive(:repos).with(filter: expected_filter).and_return([@repo]) - end + subject { get :status, params: { filter: filter }, as: :json } - subject + it 'passes sanitized filter param to bitbucket client' do + expect_next_instance_of(Bitbucket::Client) do |client| + expect(client).to receive(:repos).with(filter: expected_filter).and_return([@repo]) + end + + subject + end end end end diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index fd380f9b763..ef66124bff1 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -82,11 +82,33 @@ RSpec.describe Import::GithubController do expect(controller).to redirect_to(new_import_url) expect(flash[:alert]).to eq('Access denied to your GitHub account.') end + + it "includes namespace_id from session if it is present" do + namespace_id = 1 + session[:namespace_id] = 1 + + get :callback, params: { state: valid_auth_state } + + expect(controller).to redirect_to(status_import_github_url(namespace_id: namespace_id)) + end end end describe "POST personal_access_token" do it_behaves_like 'a GitHub-ish import controller: POST personal_access_token' + + it 'passes namespace_id param as query param if it was present' do + namespace_id = 5 + status_import_url = public_send("status_import_#{provider}_url", { namespace_id: namespace_id }) + + allow_next_instance_of(Gitlab::LegacyGithubImport::Client) do |client| + allow(client).to receive(:user).and_return(true) + end + + post :personal_access_token, params: { personal_access_token: 'some-token', namespace_id: 5 } + + expect(controller).to redirect_to(status_import_url) + end end describe "GET status" do @@ -258,7 +280,9 @@ RSpec.describe Import::GithubController do context 'when user input contains colons and spaces' do before do - allow(controller).to receive(:client_repos).and_return([]) + allow_next_instance_of(Gitlab::GithubImport::Client) do |client| + allow(client).to receive(:search_repos_by_name).and_return(items: []) + end end it 'sanitizes user input' do @@ -293,6 +317,22 @@ RSpec.describe Import::GithubController do end describe "GET realtime_changes" do + let(:user) { create(:user) } + it_behaves_like 'a GitHub-ish import controller: GET realtime_changes' + + before do + assign_session_token(provider) + end + + it 'includes stats in response' do + create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo') + + get :realtime_changes + + expect(json_response[0]).to include('stats') + expect(json_response[0]['stats']).to include('fetched') + expect(json_response[0]['stats']).to include('imported') + end end end diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb index 2129b24b2fb..5e90ceb0f9c 100644 --- a/spec/controllers/jira_connect/events_controller_spec.rb +++ b/spec/controllers/jira_connect/events_controller_spec.rb @@ -114,17 +114,6 @@ RSpec.describe JiraConnect::EventsController do base_url: base_url ) end - - context 'when the `jira_connect_installation_update` feature flag is disabled' do - before do - stub_feature_flags(jira_connect_installation_update: false) - end - - it 'does not update the installation', :aggregate_failures do - expect { subject }.not_to change { installation.reload.attributes } - expect(response).to have_gitlab_http_status(:ok) - end - end end context 'when the new base_url is invalid' do diff --git a/spec/controllers/jira_connect/subscriptions_controller_spec.rb b/spec/controllers/jira_connect/subscriptions_controller_spec.rb index f548c1f399d..e9c94f09c99 100644 --- a/spec/controllers/jira_connect/subscriptions_controller_spec.rb +++ b/spec/controllers/jira_connect/subscriptions_controller_spec.rb @@ -75,6 +75,18 @@ RSpec.describe JiraConnect::SubscriptionsController do expect(json_response).to include('login_path' => nil) end end + + context 'with context qsh' do + # The JSON endpoint will be requested by frontend using a JWT that Atlassian provides via Javascript. + # This JWT will likely use a context-qsh because Atlassian don't know for which endpoint it will be used. + # Read more about context JWT here: https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/ + + let(:qsh) { 'context-qsh' } + + specify do + expect(response).to have_gitlab_http_status(:ok) + end + end end end end @@ -102,7 +114,7 @@ RSpec.describe JiraConnect::SubscriptionsController do end context 'with valid JWT' do - let(:claims) { { iss: installation.client_key, sub: 1234 } } + let(:claims) { { iss: installation.client_key, sub: 1234, qsh: '123' } } let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) } let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } } let(:jira_group_name) { 'site-admins' } @@ -158,7 +170,7 @@ RSpec.describe JiraConnect::SubscriptionsController do .stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups") .to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' }) - delete :destroy, params: { jwt: jwt, id: subscription.id } + delete :destroy, params: { jwt: jwt, id: subscription.id, format: :json } end context 'without JWT' do @@ -170,7 +182,7 @@ RSpec.describe JiraConnect::SubscriptionsController do end context 'with valid JWT' do - let(:claims) { { iss: installation.client_key, sub: 1234 } } + let(:claims) { { iss: installation.client_key, sub: 1234, qsh: '123' } } let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) } it 'deletes the subscription' do diff --git a/spec/controllers/oauth/jira/authorizations_controller_spec.rb b/spec/controllers/oauth/jira_dvcs/authorizations_controller_spec.rb index f4a335b30f4..496ef7859f9 100644 --- a/spec/controllers/oauth/jira/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/jira_dvcs/authorizations_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Oauth::Jira::AuthorizationsController do +RSpec.describe Oauth::JiraDvcs::AuthorizationsController do describe 'GET new' do it 'redirects to OAuth authorization with correct params' do get :new, params: { client_id: 'client-123', scope: 'foo', redirect_uri: 'http://example.com/' } @@ -10,7 +10,7 @@ RSpec.describe Oauth::Jira::AuthorizationsController do expect(response).to redirect_to(oauth_authorization_url(client_id: 'client-123', response_type: 'code', scope: 'foo', - redirect_uri: oauth_jira_callback_url)) + redirect_uri: oauth_jira_dvcs_callback_url)) end it 'replaces the GitHub "repo" scope with "api"' do @@ -19,7 +19,7 @@ RSpec.describe Oauth::Jira::AuthorizationsController do expect(response).to redirect_to(oauth_authorization_url(client_id: 'client-123', response_type: 'code', scope: 'api', - redirect_uri: oauth_jira_callback_url)) + redirect_uri: oauth_jira_dvcs_callback_url)) end end diff --git a/spec/controllers/profiles/accounts_controller_spec.rb b/spec/controllers/profiles/accounts_controller_spec.rb index 011528016ce..1b4b67eeaff 100644 --- a/spec/controllers/profiles/accounts_controller_spec.rb +++ b/spec/controllers/profiles/accounts_controller_spec.rb @@ -31,7 +31,7 @@ RSpec.describe Profiles::AccountsController do end end - [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :authentiq, :dingtalk].each do |provider| + [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :authentiq, :dingtalk, :alicloud].each do |provider| describe "#{provider} provider" do let(:user) { create(:omniauth_user, provider: provider.to_s) } diff --git a/spec/controllers/profiles/keys_controller_spec.rb b/spec/controllers/profiles/keys_controller_spec.rb index 66f6135df1e..63818337722 100644 --- a/spec/controllers/profiles/keys_controller_spec.rb +++ b/spec/controllers/profiles/keys_controller_spec.rb @@ -17,7 +17,25 @@ RSpec.describe Profiles::KeysController do post :create, params: { key: build(:key, expires_at: expires_at).attributes } end.to change { Key.count }.by(1) - expect(Key.last.expires_at).to be_like_time(expires_at) + key = Key.last + expect(key.expires_at).to be_like_time(expires_at) + expect(key.fingerprint_md5).to be_present + expect(key.fingerprint_sha256).to be_present + end + + context 'with FIPS mode', :fips_mode do + it 'creates a new key without MD5 fingerprint' do + expires_at = 3.days.from_now + + expect do + post :create, params: { key: build(:rsa_key_4096, expires_at: expires_at).attributes } + end.to change { Key.count }.by(1) + + key = Key.last + expect(key.expires_at).to be_like_time(expires_at) + expect(key.fingerprint_md5).to be_nil + expect(key.fingerprint_sha256).to be_present + end end end end diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb index b7870a63f9d..7add3a72337 100644 --- a/spec/controllers/profiles/preferences_controller_spec.rb +++ b/spec/controllers/profiles/preferences_controller_spec.rb @@ -46,6 +46,8 @@ RSpec.describe Profiles::PreferencesController do it "changes the user's preferences" do prefs = { color_scheme_id: '1', + diffs_deletion_color: '#123456', + diffs_addition_color: '#abcdef', dashboard: 'stars', theme_id: '2', first_day_of_week: '1', @@ -84,5 +86,27 @@ RSpec.describe Profiles::PreferencesController do expect(response.parsed_body['type']).to eq('alert') end end + + context 'on invalid diffs colors setting' do + it 'responds with error for diffs_deletion_color' do + prefs = { diffs_deletion_color: '#1234567' } + + go params: prefs + + expect(response).to have_gitlab_http_status(:bad_request) + expect(response.parsed_body['message']).to eq _('Failed to save preferences.') + expect(response.parsed_body['type']).to eq('alert') + end + + it 'responds with error for diffs_addition_color' do + prefs = { diffs_addition_color: '#1234567' } + + go params: prefs + + expect(response).to have_gitlab_http_status(:bad_request) + expect(response.parsed_body['message']).to eq _('Failed to save preferences.') + expect(response.parsed_body['type']).to eq('alert') + end + end end end diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb index 47086ccdd2c..33cba675777 100644 --- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb +++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb @@ -104,17 +104,29 @@ RSpec.describe Profiles::TwoFactorAuthsController do expect(subject).to receive(:build_qr_code).and_return(code) get :show - expect(assigns[:qr_code]).to eq code + expect(assigns[:qr_code]).to eq(code) end - it 'generates a unique otp_secret every time the page is loaded' do - expect(User).to receive(:generate_otp_secret).with(32).and_call_original.twice + it 'generates a single otp_secret with multiple page loads', :freeze_time do + expect(User).to receive(:generate_otp_secret).with(32).and_call_original.once + + user.update!(otp_secret: nil, otp_secret_expires_at: nil) 2.times do get :show end end + it 'generates a new otp_secret once the ttl has expired' do + expect(User).to receive(:generate_otp_secret).with(32).and_call_original.once + + user.update!(otp_secret: "FT7KAVNU63YZH7PBRVPVL7CPSAENXY25", otp_secret_expires_at: 2.minutes.from_now) + + travel_to(10.minutes.from_now) do + get :show + end + end + it_behaves_like 'user must first verify their primary email address' do let(:go) { get :show } end @@ -183,7 +195,12 @@ RSpec.describe Profiles::TwoFactorAuthsController do expect(subject).to receive(:build_qr_code).and_return(code) go - expect(assigns[:qr_code]).to eq code + expect(assigns[:qr_code]).to eq(code) + end + + it 'assigns account_string' do + go + expect(assigns[:account_string]).to eq("#{Gitlab.config.gitlab.host}:#{user.email}") end it 'renders show' do diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index f410c16b30b..d51880b282d 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -323,6 +323,7 @@ RSpec.describe Projects::ArtifactsController do subject expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Gitlab-Workhorse-Detect-Content-Type']).to eq('true') expect(send_data).to start_with('artifacts-entry:') expect(params.keys).to eq(%w(Archive Entry)) @@ -338,7 +339,7 @@ RSpec.describe Projects::ArtifactsController do def params @params ||= begin - base64_params = send_data.sub(/\Aartifacts\-entry:/, '') + base64_params = send_data.delete_prefix('artifacts-entry:') Gitlab::Json.parse(Base64.urlsafe_decode64(base64_params)) end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index ea22e6b6f10..1580ad9361d 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -688,21 +688,23 @@ RSpec.describe Projects::BranchesController do end context 'when gitaly is not available' do + let(:request) { get :index, format: :html, params: { namespace_id: project.namespace, project_id: project } } + before do allow_next_instance_of(Gitlab::GitalyClient::RefService) do |ref_service| allow(ref_service).to receive(:local_branches).and_raise(GRPC::DeadlineExceeded) end - - get :index, format: :html, params: { - namespace_id: project.namespace, project_id: project - } end - it 'returns with a status 200' do - expect(response).to have_gitlab_http_status(:ok) + it 'returns with a status 503' do + request + + expect(response).to have_gitlab_http_status(:service_unavailable) end it 'sets gitaly_unavailable variable' do + request + expect(assigns[:gitaly_unavailable]).to be_truthy end end diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 72fee40a6e9..a72c98552a5 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -60,6 +60,22 @@ RSpec.describe Projects::CommitController do end end + context 'with valid page' do + it 'responds with 200' do + go(id: commit.id, page: 1) + + expect(response).to be_ok + end + end + + context 'with invalid page' do + it 'does not return an error' do + go(id: commit.id, page: ['invalid']) + + expect(response).to be_ok + end + end + it 'handles binary files' do go(id: TestEnv::BRANCH_SHA['binary-encoding'], format: 'html') @@ -212,6 +228,21 @@ RSpec.describe Projects::CommitController do end end + context 'when the revert commit is missing' do + it 'renders the 404 page' do + post(:revert, + params: { + namespace_id: project.namespace, + project_id: project, + start_branch: 'master', + id: '1234567890' + }) + + expect(response).not_to be_successful + expect(response).to have_gitlab_http_status(:not_found) + end + end + context 'when the revert was successful' do it 'redirects to the commits page' do post(:revert, @@ -269,6 +300,21 @@ RSpec.describe Projects::CommitController do end end + context 'when the cherry-pick commit is missing' do + it 'renders the 404 page' do + post(:cherry_pick, + params: { + namespace_id: project.namespace, + project_id: project, + start_branch: 'master', + id: '1234567890' + }) + + expect(response).not_to be_successful + expect(response).to have_gitlab_http_status(:not_found) + end + end + context 'when the cherry-pick was successful' do it 'redirects to the commits page' do post(:cherry_pick, diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 62b93a2728b..9821618df8d 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -58,11 +58,13 @@ RSpec.describe Projects::CompareController do from_project_id: from_project_id, from: from_ref, to: to_ref, - w: whitespace + w: whitespace, + page: page } end let(:whitespace) { nil } + let(:page) { nil } context 'when the refs exist in the same project' do context 'when we set the white space param' do @@ -196,6 +198,34 @@ RSpec.describe Projects::CompareController do expect(response).to have_gitlab_http_status(:found) end end + + context 'when page is valid' do + let(:from_project_id) { nil } + let(:from_ref) { '08f22f25' } + let(:to_ref) { '66eceea0' } + let(:page) { 1 } + + it 'shows the diff' do + show_request + + expect(response).to be_successful + expect(assigns(:diffs).diff_files.first).to be_present + expect(assigns(:commits).length).to be >= 1 + end + end + + context 'when page is not valid' do + let(:from_project_id) { nil } + let(:from_ref) { '08f22f25' } + let(:to_ref) { '66eceea0' } + let(:page) { ['invalid'] } + + it 'does not return an error' do + show_request + + expect(response).to be_successful + end + end end describe 'GET diff_for_path' do diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index fdfc21887a6..f4cad5790a3 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -254,38 +254,54 @@ RSpec.describe Projects::EnvironmentsController do end describe 'PATCH #stop' do + subject { patch :stop, params: environment_params(format: :json) } + context 'when env not available' do it 'returns 404' do allow_any_instance_of(Environment).to receive(:available?) { false } - patch :stop, params: environment_params(format: :json) + subject expect(response).to have_gitlab_http_status(:not_found) end end context 'when stop action' do - it 'returns action url' do + it 'returns action url for single stop action' do action = create(:ci_build, :manual) allow_any_instance_of(Environment) - .to receive_messages(available?: true, stop_with_action!: action) + .to receive_messages(available?: true, stop_with_actions!: [action]) - patch :stop, params: environment_params(format: :json) + subject expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq( { 'redirect_url' => project_job_url(project, action) }) end + + it 'returns environment url for multiple stop actions' do + actions = create_list(:ci_build, 2, :manual) + + allow_any_instance_of(Environment) + .to receive_messages(available?: true, stop_with_actions!: actions) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq( + { 'redirect_url' => + project_environment_url(project, environment) }) + end end context 'when no stop action' do it 'returns env url' do allow_any_instance_of(Environment) - .to receive_messages(available?: true, stop_with_action!: nil) + .to receive_messages(available?: true, stop_with_actions!: nil) - patch :stop, params: environment_params(format: :json) + subject expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq( diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index ea15d483c90..96705d82ac5 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -18,136 +18,6 @@ RSpec.describe Projects::GroupLinksController do travel_back end - describe '#create' do - shared_context 'link project to group' do - before do - post(:create, params: { - namespace_id: project.namespace, - project_id: project, - link_group_id: group.id, - link_group_access: ProjectGroupLink.default_access - }) - end - end - - context 'when project is not allowed to be shared with a group' do - before do - group.update!(share_with_group_lock: false) - end - - include_context 'link project to group' - - it 'responds with status 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end - - context 'when user has access to group they want to link project to' do - before do - group.add_developer(user) - end - - include_context 'link project to group' - - it 'links project with selected group' do - expect(group.shared_projects).to include project - end - - it 'redirects to project group links page' do - expect(response).to redirect_to( - project_project_members_path(project) - ) - end - end - - context 'when user doers not have access to group they want to link to' do - include_context 'link project to group' - - it 'renders 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - - it 'does not share project with that group' do - expect(group.shared_projects).not_to include project - end - end - - context 'when user does not have access to the public group' do - let(:group) { create(:group, :public) } - - include_context 'link project to group' - - it 'renders 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - - it 'does not share project with that group' do - expect(group.shared_projects).not_to include project - end - end - - context 'when project group id equal link group id' do - before do - group2.add_developer(user) - - post(:create, params: { - namespace_id: project.namespace, - project_id: project, - link_group_id: group2.id, - link_group_access: ProjectGroupLink.default_access - }) - end - - it 'does not share project with selected group' do - expect(group2.shared_projects).not_to include project - end - - it 'redirects to project group links page' do - expect(response).to redirect_to( - project_project_members_path(project) - ) - end - end - - context 'when link group id is not present' do - before do - post(:create, params: { - namespace_id: project.namespace, - project_id: project, - link_group_access: ProjectGroupLink.default_access - }) - end - - it 'redirects to project group links page' do - expect(response).to redirect_to( - project_project_members_path(project) - ) - expect(flash[:alert]).to eq('Please select a group.') - end - end - - context 'when link is not persisted in the database' do - before do - allow(::Projects::GroupLinks::CreateService).to receive_message_chain(:new, :execute) - .and_return({ status: :error, http_status: 409, message: 'error' }) - - post(:create, params: { - namespace_id: project.namespace, - project_id: project, - link_group_id: group.id, - link_group_access: ProjectGroupLink.default_access - }) - end - - it 'redirects to project group links page' do - expect(response).to redirect_to( - project_project_members_path(project) - ) - expect(flash[:alert]).to eq('error') - end - end - end - describe '#update' do let_it_be(:link) do create( diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 9d3711d8a96..ce0af784cdf 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -148,6 +148,13 @@ RSpec.describe Projects::IssuesController do allow(Kaminari.config).to receive(:default_per_page).and_return(1) end + it 'redirects to last page when out of bounds on non-html requests' do + get :index, params: params.merge(page: last_page + 1), format: 'atom' + + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to(action: 'index', format: 'atom', page: last_page, state: 'opened') + end + it 'does not use pagination if disabled' do allow(controller).to receive(:pagination_disabled?).and_return(true) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index ed68d6a87b8..e9f1232b5e7 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -796,7 +796,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do retried_build = Ci::Build.last - Ci::RetryBuildService.clone_accessors.each do |accessor| + Ci::Build.clone_accessors.each do |accessor| expect(job.read_attribute(accessor)) .to eq(retried_build.read_attribute(accessor)), "Mismatched attribute on \"#{accessor}\". " \ diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 2df31904380..07874c8a8af 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -423,7 +423,21 @@ RSpec.describe Projects::NotesController do end context 'when creating a confidential note' do - let(:extra_request_params) { { format: :json } } + let(:project) { create(:project) } + let(:note_params) do + { note: note_text, noteable_id: issue.id, noteable_type: 'Issue' }.merge(extra_note_params) + end + + let(:request_params) do + { + note: note_params, + namespace_id: project.namespace, + project_id: project, + target_type: 'issue', + target_id: issue.id, + format: :json + } + end context 'when `confidential` parameter is not provided' do it 'sets `confidential` to `false` in JSON response' do diff --git a/spec/controllers/projects/packages/infrastructure_registry_controller_spec.rb b/spec/controllers/projects/packages/infrastructure_registry_controller_spec.rb index a655c742973..fc741d0f3f6 100644 --- a/spec/controllers/projects/packages/infrastructure_registry_controller_spec.rb +++ b/spec/controllers/projects/packages/infrastructure_registry_controller_spec.rb @@ -41,17 +41,5 @@ RSpec.describe Projects::Packages::InfrastructureRegistryController do it_behaves_like 'returning response status', :not_found end - - context 'with package file pending destruction' do - let_it_be(:package_file_pending_destruction) { create(:package_file, :pending_destruction, package: terraform_module) } - - let(:terraform_module_package_file) { terraform_module.package_files.first } - - it 'does not return them' do - subject - - expect(assigns(:package_files)).to contain_exactly(terraform_module_package_file) - end - end end end diff --git a/spec/controllers/projects/pipelines/tests_controller_spec.rb b/spec/controllers/projects/pipelines/tests_controller_spec.rb index e6ff3a487ac..113781bab7c 100644 --- a/spec/controllers/projects/pipelines/tests_controller_spec.rb +++ b/spec/controllers/projects/pipelines/tests_controller_spec.rb @@ -40,28 +40,56 @@ RSpec.describe Projects::Pipelines::TestsController do let(:suite_name) { 'test' } let(:build_ids) { pipeline.latest_builds.pluck(:id) } - before do - build = main_pipeline.builds.last - build.update_column(:finished_at, 1.day.ago) # Just to be sure we are included in the report window - - # The JUnit fixture for the given build has 3 failures. - # This service will create 1 test case failure record for each. - Ci::TestFailureHistoryService.new(main_pipeline).execute + context 'when artifacts are expired' do + before do + pipeline.job_artifacts.first.update!(expire_at: Date.yesterday) + end + + it 'renders not_found errors', :aggregate_failures do + get_tests_show_json(build_ids) + + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['errors']).to eq('Test report artifacts have expired') + end + + context 'when ci_test_report_artifacts_expired is disabled' do + before do + stub_feature_flags(ci_test_report_artifacts_expired: false) + end + it 'renders test suite', :aggregate_failures do + get_tests_show_json(build_ids) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['name']).to eq('test') + end + end end - it 'renders test suite data' do - get_tests_show_json(build_ids) - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['name']).to eq('test') - - # Each test failure in this pipeline has a matching failure in the default branch - recent_failures = json_response['test_cases'].map { |tc| tc['recent_failures'] } - expect(recent_failures).to eq([ - { 'count' => 1, 'base_branch' => 'master' }, - { 'count' => 1, 'base_branch' => 'master' }, - { 'count' => 1, 'base_branch' => 'master' } - ]) + context 'when artifacts are not expired' do + before do + build = main_pipeline.builds.last + build.update_column(:finished_at, 1.day.ago) # Just to be sure we are included in the report window + + # The JUnit fixture for the given build has 3 failures. + # This service will create 1 test case failure record for each. + Ci::TestFailureHistoryService.new(main_pipeline).execute + end + + it 'renders test suite data', :aggregate_failures do + get_tests_show_json(build_ids) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['name']).to eq('test') + expect(json_response['artifacts_expired']).to be_falsey + + # Each test failure in this pipeline has a matching failure in the default branch + recent_failures = json_response['test_cases'].map { |tc| tc['recent_failures'] } + expect(recent_failures).to eq([ + { 'count' => 1, 'base_branch' => 'master' }, + { 'count' => 1, 'base_branch' => 'master' }, + { 'count' => 1, 'base_branch' => 'master' } + ]) + end end end diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 35e5422d072..7e96c59fbb1 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -359,10 +359,9 @@ RSpec.describe Projects::ServicesController do def prometheus_integration_as_data pi = project.prometheus_integration.reload attrs = pi.attributes.except('encrypted_properties', - 'encrypted_properties_iv', - 'encrypted_properties_tmp') + 'encrypted_properties_iv') - [attrs, pi.encrypted_properties_tmp] + [attrs, pi.properties] end end diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb index 26161b5fb5c..e1f25589eeb 100644 --- a/spec/controllers/projects/static_site_editor_controller_spec.rb +++ b/spec/controllers/projects/static_site_editor_controller_spec.rb @@ -76,12 +76,11 @@ RSpec.describe Projects::StaticSiteEditorController do get :show, params: default_params end - it 'increases the views counter' do - expect(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to have_received(:increment_views_count) - end + it 'redirects to the Web IDE' do + get :show, params: default_params - it 'renders the edit page' do - expect(response).to render_template(:show) + expected_path_regex = %r[-/ide/project/#{project.full_path}/edit/master/-/README.md] + expect(response).to redirect_to(expected_path_regex) end it 'assigns ref and path variables' do @@ -96,62 +95,6 @@ RSpec.describe Projects::StaticSiteEditorController do expect(response).to have_gitlab_http_status(:not_found) end end - - context 'when invalid config file' do - let(:service_response) { ServiceResponse.error(message: 'invalid') } - - it 'redirects to project page and flashes error message' do - expect(response).to redirect_to(project_path(project)) - expect(controller).to set_flash[:alert].to('invalid') - end - end - - context 'with a service response payload containing multiple data types' do - let(:data) do - { - a_string: 'string', - an_array: [ - { - foo: 'bar' - } - ], - an_integer: 123, - a_hash: { - a_deeper_hash: { - foo: 'bar' - } - }, - a_boolean: true, - a_nil: nil - } - end - - let(:assigns_data) { assigns(:data) } - - it 'leaves data values which are strings as strings' do - expect(assigns_data[:a_string]).to eq('string') - end - - it 'leaves data values which are integers as integers' do - expect(assigns_data[:an_integer]).to eq(123) - end - - it 'serializes data values which are booleans to JSON' do - expect(assigns_data[:a_boolean]).to eq('true') - end - - it 'serializes data values which are arrays to JSON' do - expect(assigns_data[:an_array]).to eq('[{"foo":"bar"}]') - end - - it 'serializes data values which are hashes to JSON' do - expect(assigns_data[:a_hash]).to eq('{"a_deeper_hash":{"foo":"bar"}}') - end - - it 'serializes data values which are nil to an empty string' do - expect(assigns_data[:a_nil]).to eq('') - end - end end end end diff --git a/spec/controllers/projects/todos_controller_spec.rb b/spec/controllers/projects/todos_controller_spec.rb index 9a73417ffdb..d87f4258b9c 100644 --- a/spec/controllers/projects/todos_controller_spec.rb +++ b/spec/controllers/projects/todos_controller_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Projects::TodosController do let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } - let(:design) { create(:design, project: project, issue: issue) } + let(:design) { create(:design, :with_versions, project: project, issue: issue) } let(:parent) { project } shared_examples 'issuable todo actions' do diff --git a/spec/controllers/projects/usage_quotas_controller_spec.rb b/spec/controllers/projects/usage_quotas_controller_spec.rb index 6125ba13f96..2831de00348 100644 --- a/spec/controllers/projects/usage_quotas_controller_spec.rb +++ b/spec/controllers/projects/usage_quotas_controller_spec.rb @@ -4,17 +4,44 @@ require 'spec_helper' RSpec.describe Projects::UsageQuotasController do let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, namespace: user.namespace) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } describe 'GET #index' do render_views - it 'does not render search settings partial' do + subject { get(:index, params: { namespace_id: project.namespace, project_id: project }) } + + before do sign_in(user) - get(:index, params: { namespace_id: user.namespace, project_id: project }) + end + + context 'when user does not have read_usage_quotas permission' do + before do + project.add_developer(user) + end + + it 'renders not_found' do + subject + + expect(response).to render_template('errors/not_found') + expect(response).not_to render_template('shared/search_settings') + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when user has read_usage_quotas permission' do + before do + project.add_maintainer(user) + end + + it 'renders index with 200 status code' do + subject - expect(response).to render_template('index') - expect(response).not_to render_template('shared/search_settings') + expect(response).to render_template('index') + expect(response).not_to render_template('shared/search_settings') + expect(response).to have_gitlab_http_status(:ok) + end end end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index c098ea71f7a..07bd198137a 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -473,28 +473,6 @@ RSpec.describe ProjectsController do end end end - - context 'with new_project_sast_enabled', :experiment do - let(:params) do - { - path: 'foo', - description: 'bar', - namespace_id: user.namespace.id, - initialize_with_sast: '1' - } - end - - it 'tracks an event on project creation' do - expect(experiment(:new_project_sast_enabled)).to track(:created, - property: 'blank', - checked: true, - project: an_instance_of(Project), - namespace: user.namespace - ).on_next_instance.with_context(user: user) - - post :create, params: { project: params } - end - end end describe 'GET edit' do @@ -1159,16 +1137,15 @@ RSpec.describe ProjectsController do context 'when gitaly is unavailable' do before do expect_next_instance_of(TagsFinder) do |finder| - allow(finder).to receive(:execute).and_raise(Gitlab::Git::CommandError) + allow(finder).to receive(:execute).and_raise(Gitlab::Git::CommandError, 'something went wrong') end end - it 'gets an empty list of tags' do + it 'responds with 503 error' do get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" } - expect(json_response["Branches"]).to include("master") - expect(json_response["Tags"]).to eq([]) - expect(json_response["Commits"]).to include("123456") + expect(response).to have_gitlab_http_status(:service_unavailable) + expect(json_response['error']).to eq 'Unable to load refs' end end @@ -1466,14 +1443,15 @@ RSpec.describe ProjectsController do end describe '#download_export', :clean_gitlab_redis_rate_limiting do + let(:project) { create(:project, :with_export, service_desk_enabled: false) } let(:action) { :download_export } context 'object storage enabled' do context 'when project export is enabled' do - it 'returns 302' do + it 'returns 200' do get action, params: { namespace_id: project.namespace, id: project } - expect(response).to have_gitlab_http_status(:found) + expect(response).to have_gitlab_http_status(:ok) end end @@ -1513,14 +1491,37 @@ RSpec.describe ProjectsController do expect(response.body).to eq('This endpoint has been requested too many times. Try again later.') expect(response).to have_gitlab_http_status(:too_many_requests) end + end + + context 'applies correct scope when throttling', :clean_gitlab_redis_rate_limiting do + before do + stub_application_setting(project_download_export_limit: 1) + end - it 'applies correct scope when throttling' do + it 'applies throttle per namespace' do expect(Gitlab::ApplicationRateLimiter) .to receive(:throttled?) - .with(:project_download_export, scope: [user, project]) + .with(:project_download_export, scope: [user, project.namespace]) post action, params: { namespace_id: project.namespace, id: project } end + + it 'throttles downloads within same namespaces' do + # simulate prior request to the same namespace, which increments the rate limit counter for that scope + Gitlab::ApplicationRateLimiter.throttled?(:project_download_export, scope: [user, project.namespace]) + + get action, params: { namespace_id: project.namespace, id: project } + expect(response).to have_gitlab_http_status(:too_many_requests) + end + + it 'allows downloads from different namespaces' do + # simulate prior request to a different namespace, which increments the rate limit counter for that scope + Gitlab::ApplicationRateLimiter.throttled?(:project_download_export, + scope: [user, create(:project, :with_export).namespace]) + + get action, params: { namespace_id: project.namespace, id: project } + expect(response).to have_gitlab_http_status(:ok) + end end end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 9482448fc03..4abcd414e51 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -211,6 +211,7 @@ RSpec.describe SearchController do :global_search_merge_requests_tab | 'merge_requests' :global_search_wiki_tab | 'wiki_blobs' :global_search_commits_tab | 'commits' + :global_search_users_tab | 'users' end with_them do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 03d053e6f97..877ca7cd6c6 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -193,6 +193,10 @@ RSpec.describe SessionsController do end context 'with reCAPTCHA' do + before do + stub_feature_flags(arkose_labs_login_challenge: false) + end + def unsuccesful_login(user_params, sesion_params: {}) # Without this, `verify_recaptcha` arbitrarily returns true in test env Recaptcha.configuration.skip_verify_env.delete('test') @@ -234,7 +238,7 @@ RSpec.describe SessionsController do unsuccesful_login(user_params) - expect(response).to render_template(:new) + expect(response).to redirect_to new_user_session_path expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.') expect(subject.current_user).to be_nil end @@ -258,7 +262,7 @@ RSpec.describe SessionsController do it 'displays an error when the reCAPTCHA is not solved' do unsuccesful_login(user_params, sesion_params: { failed_login_attempts: 6 }) - expect(response).to render_template(:new) + expect(response).to redirect_to new_user_session_path expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.') expect(subject.current_user).to be_nil end @@ -278,7 +282,7 @@ RSpec.describe SessionsController do it 'displays an error when the reCAPTCHA is not solved' do unsuccesful_login(user_params) - expect(response).to render_template(:new) + expect(response).to redirect_to new_user_session_path expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.') expect(subject.current_user).to be_nil end diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 8442c214cd3..ffcd759435c 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -701,6 +701,24 @@ RSpec.describe UploadsController do end end end + + context 'when viewing alert metric images' do + let!(:user) { create(:user) } + let!(:project) { create(:project) } + let(:alert) { create(:alert_management_alert, project: project) } + let(:metric_image) { create(:alert_metric_image, alert: alert) } + + before do + project.add_developer(user) + sign_in(user) + end + + it "responds with status 200" do + get :show, params: { model: "alert_management_metric_image", mounted_as: 'file', id: metric_image.id, filename: metric_image.filename } + + expect(response).to have_gitlab_http_status(:ok) + end + end end def post_authorize(verified: true) |