diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /spec/controllers | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) | |
download | gitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/controllers')
56 files changed, 2142 insertions, 567 deletions
diff --git a/spec/controllers/admin/ci/variables_controller_spec.rb b/spec/controllers/admin/ci/variables_controller_spec.rb new file mode 100644 index 00000000000..57f2dd21f39 --- /dev/null +++ b/spec/controllers/admin/ci/variables_controller_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Admin::Ci::VariablesController do + let_it_be(:variable) { create(:ci_instance_variable) } + + before do + sign_in(user) + end + + describe 'GET #show' do + subject do + get :show, params: {}, format: :json + end + + context 'when signed in as admin' do + let(:user) { create(:admin) } + + include_examples 'GET #show lists all variables' + end + + context 'when signed in as regular user' do + let(:user) { create(:user) } + + it 'returns 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'PATCH #update' do + subject do + patch :update, + params: { + variables_attributes: variables_attributes + }, + format: :json + end + + context 'when signed in as admin' do + let(:user) { create(:admin) } + + include_examples 'PATCH #update updates variables' do + let(:variables_scope) { Ci::InstanceVariable.all } + let(:file_variables_scope) { variables_scope.file } + end + end + + context 'when signed in as regular user' do + let(:user) { create(:user) } + + let(:variables_attributes) do + [{ + id: variable.id, + key: variable.key, + secret_value: 'new value' + }] + end + + it 'returns 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb index bd6d5614ccd..d4a12e0dc52 100644 --- a/spec/controllers/admin/clusters_controller_spec.rb +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -27,7 +27,7 @@ describe Admin::ClustersController do create(:cluster, :disabled, :provided_by_gcp, :production_environment, :instance) end - it 'lists available clusters' do + it 'lists available clusters and displays html' do get_index expect(response).to have_gitlab_http_status(:ok) @@ -35,20 +35,39 @@ describe Admin::ClustersController do expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster]) end + it 'lists available clusters and renders json serializer' do + get_index(format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('cluster_list') + end + context 'when page is specified' do let(:last_page) { Clusters::Cluster.instance_type.page.total_pages } + let(:total_count) { Clusters::Cluster.instance_type.page.total_count } before do - allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) - create_list(:cluster, 2, :provided_by_gcp, :production_environment, :instance) + create_list(:cluster, 30, :provided_by_gcp, :production_environment, :instance) end it 'redirects to the page' do + expect(last_page).to be > 1 + get_index(page: last_page) expect(response).to have_gitlab_http_status(:ok) expect(assigns(:clusters).current_page).to eq(last_page) end + + it 'displays cluster list for associated page' do + expect(last_page).to be > 1 + + get_index(page: last_page, format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['X-Page'].to_i).to eq(last_page) + expect(response.headers['X-Total'].to_i).to eq(total_count) + end end end diff --git a/spec/controllers/admin/requests_profiles_controller_spec.rb b/spec/controllers/admin/requests_profiles_controller_spec.rb index 13123c8e486..629233b04e7 100644 --- a/spec/controllers/admin/requests_profiles_controller_spec.rb +++ b/spec/controllers/admin/requests_profiles_controller_spec.rb @@ -27,7 +27,7 @@ describe Admin::RequestsProfilesController do end context 'when loading HTML profile' do - let(:basename) { "profile_#{Time.now.to_i}_execution.html" } + let(:basename) { "profile_#{Time.current.to_i}_execution.html" } let(:sample_data) do '<html> <body> <h1>Heading</h1> <p>paragraph.</p> </body> </html>' @@ -42,7 +42,7 @@ describe Admin::RequestsProfilesController do end context 'when loading TXT profile' do - let(:basename) { "profile_#{Time.now.to_i}_memory.txt" } + let(:basename) { "profile_#{Time.current.to_i}_memory.txt" } let(:sample_data) do <<~TXT @@ -60,7 +60,7 @@ describe Admin::RequestsProfilesController do end context 'when loading PDF profile' do - let(:basename) { "profile_#{Time.now.to_i}_anything.pdf" } + let(:basename) { "profile_#{Time.current.to_i}_anything.pdf" } let(:sample_data) { 'mocked pdf content' } diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 387fc0407b6..7a7201a6454 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -296,7 +296,7 @@ describe Admin::UsersController do it 'sets the new password to expire immediately' do expect { update_password(user, 'AValidPassword1') } - .to change { user.reload.password_expires_at }.to be_within(2.seconds).of(Time.now) + .to change { user.reload.password_expires_at }.to be_within(2.seconds).of(Time.current) end end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 2a913069acc..ed2e61d6cf6 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -14,7 +14,7 @@ describe ApplicationController do end it 'redirects if the user is over their password expiry' do - user.password_expires_at = Time.new(2002) + user.password_expires_at = Time.zone.local(2002) expect(user.ldap_user?).to be_falsey allow(controller).to receive(:current_user).and_return(user) @@ -25,7 +25,7 @@ describe ApplicationController do end it 'does not redirect if the user is under their password expiry' do - user.password_expires_at = Time.now + 20010101 + user.password_expires_at = Time.current + 20010101 expect(user.ldap_user?).to be_falsey allow(controller).to receive(:current_user).and_return(user) @@ -35,7 +35,7 @@ describe ApplicationController do end it 'does not redirect if the user is over their password expiry but they are an ldap user' do - user.password_expires_at = Time.new(2002) + user.password_expires_at = Time.zone.local(2002) allow(user).to receive(:ldap_user?).and_return(true) allow(controller).to receive(:current_user).and_return(user) @@ -47,7 +47,7 @@ describe ApplicationController do it 'does not redirect if the user is over their password expiry but password authentication is disabled for the web interface' do stub_application_setting(password_authentication_enabled_for_web: false) stub_application_setting(password_authentication_enabled_for_git: false) - user.password_expires_at = Time.new(2002) + user.password_expires_at = Time.zone.local(2002) allow(controller).to receive(:current_user).and_return(user) expect(controller).not_to receive(:redirect_to) @@ -530,6 +530,14 @@ describe ApplicationController do expect(controller.last_payload).to include('correlation_id' => 'new-id') end + + it 'adds context metadata to the payload' do + sign_in user + + get :index + + expect(controller.last_payload[:metadata]).to include('meta.user' => user.username) + end end describe '#access_denied' do @@ -891,7 +899,7 @@ describe ApplicationController do end it 'sets the group if it was available' do - group = build(:group) + group = build_stubbed(:group) controller.instance_variable_set(:@group, group) get :index, format: :json @@ -900,7 +908,7 @@ describe ApplicationController do end it 'sets the project if one was available' do - project = build(:project) + project = build_stubbed(:project) controller.instance_variable_set(:@project, project) get :index, format: :json @@ -913,5 +921,58 @@ describe ApplicationController do expect(json_response['meta.caller_id']).to eq('AnonymousController#index') end + + it 'assigns the context to a variable for logging' do + get :index, format: :json + + expect(assigns(:current_context)).to include('meta.user' => user.username) + end + + it 'assigns the context when the action caused an error' do + allow(controller).to receive(:index) { raise 'Broken' } + + expect { get :index, format: :json }.to raise_error('Broken') + + expect(assigns(:current_context)).to include('meta.user' => user.username) + end + end + + describe '#current_user' do + controller(described_class) do + def index; end + end + + let_it_be(:impersonator) { create(:user) } + let_it_be(:user) { create(:user) } + + before do + sign_in(user) + end + + context 'when being impersonated' do + before do + allow(controller).to receive(:session).and_return({ impersonator_id: impersonator.id }) + end + + it 'returns a User with impersonator', :aggregate_failures do + get :index + + expect(controller.current_user).to be_a(User) + expect(controller.current_user.impersonator).to eq(impersonator) + end + end + + context 'when not being impersonated' do + before do + allow(controller).to receive(:session).and_return({}) + end + + it 'returns a User', :aggregate_failures do + get :index + + expect(controller.current_user).to be_a(User) + expect(controller.current_user.impersonator).to be_nil + end + end end end diff --git a/spec/controllers/concerns/issuable_actions_spec.rb b/spec/controllers/concerns/issuable_actions_spec.rb index 7b0b4497f3f..2ab46992b99 100644 --- a/spec/controllers/concerns/issuable_actions_spec.rb +++ b/spec/controllers/concerns/issuable_actions_spec.rb @@ -14,7 +14,7 @@ describe IssuableActions do klass = Class.new do attr_reader :current_user, :project, :issuable - def self.before_action(action, params = nil) + def self.before_action(action = nil, params = nil) end include IssuableActions diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index 4e42171e3d3..e2fa03670d9 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -45,7 +45,7 @@ describe MetricsDashboard do it 'returns the specified dashboard' do expect(json_response['dashboard']['dashboard']).to eq('Environment metrics') expect(json_response).not_to have_key('all_dashboards') - expect(json_response).not_to have_key('metrics_data') + expect(json_response).to have_key('metrics_data') end context 'when the params are in an alternate format' do @@ -54,7 +54,7 @@ describe MetricsDashboard do it 'returns the specified dashboard' do expect(json_response['dashboard']['dashboard']).to eq('Environment metrics') expect(json_response).not_to have_key('all_dashboards') - expect(json_response).not_to have_key('metrics_data') + expect(json_response).to have_key('metrics_data') end end @@ -114,6 +114,35 @@ describe MetricsDashboard do end end end + + context 'starred dashboards' do + let_it_be(:dashboard_yml) { fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') } + let_it_be(:dashboards) do + { + '.gitlab/dashboards/test.yml' => dashboard_yml, + '.gitlab/dashboards/anomaly.yml' => dashboard_yml, + '.gitlab/dashboards/errors.yml' => dashboard_yml + } + end + let_it_be(:project) { create(:project, :custom_repo, files: dashboards) } + + before do + create(:metrics_users_starred_dashboard, user: user, project: project, dashboard_path: '.gitlab/dashboards/errors.yml') + create(:metrics_users_starred_dashboard, user: user, project: project, dashboard_path: '.gitlab/dashboards/test.yml') + end + + it 'adds starred dashboard information and sorts the list' do + all_dashboards = json_response['all_dashboards'].map { |dashboard| dashboard.slice('display_name', 'starred', 'user_starred_path') } + expected_response = [ + { "display_name" => "Default", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/common_metrics.yml' }) }, + { "display_name" => "anomaly.yml", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/anomaly.yml' }) }, + { "display_name" => "errors.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/errors.yml' }) }, + { "display_name" => "test.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/test.yml' }) } + ] + + expect(all_dashboards).to eql expected_response + end + end end end end diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb index a13b56deb23..eeac696c3f2 100644 --- a/spec/controllers/dashboard/projects_controller_spec.rb +++ b/spec/controllers/dashboard/projects_controller_spec.rb @@ -86,11 +86,58 @@ describe Dashboard::ProjectsController do end describe 'GET /starred.json' do + subject { get :starred, format: :json } + + let(:projects) { create_list(:project, 2, creator: user) } + before do - get :starred, format: :json + allow(Kaminari.config).to receive(:default_per_page).and_return(1) + + projects.each do |project| + project.add_developer(user) + create(:users_star_project, project_id: project.id, user_id: user.id) + end end - it { is_expected.to respond_with(:success) } + it 'returns success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'paginates the records' do + subject + + expect(assigns(:projects).count).to eq(1) + end + end + end + + context 'atom requests' do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + describe '#index' do + context 'project pagination' do + let(:projects) { create_list(:project, 2, creator: user) } + + before do + allow(Kaminari.config).to receive(:default_per_page).and_return(1) + + projects.each do |project| + project.add_developer(user) + end + end + + it 'does not paginate projects, even if normally restricted by pagination' do + get :index, format: :atom + + expect(assigns(:events).count).to eq(2) + end + end end end end diff --git a/spec/controllers/google_api/authorizations_controller_spec.rb b/spec/controllers/google_api/authorizations_controller_spec.rb index 58bda2bd4e8..9d0e0d92978 100644 --- a/spec/controllers/google_api/authorizations_controller_spec.rb +++ b/spec/controllers/google_api/authorizations_controller_spec.rb @@ -12,10 +12,6 @@ describe GoogleApi::AuthorizationsController do before do sign_in(user) - - allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |instance| - allow(instance).to receive(:get_token).and_return([token, expires_at]) - end end shared_examples_for 'access denied' do @@ -38,6 +34,12 @@ describe GoogleApi::AuthorizationsController do context 'session key matches state param' do let(:state) { session_key } + before do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |instance| + allow(instance).to receive(:get_token).and_return([token, expires_at]) + end + end + it 'sets token and expires_at in session' do subject @@ -63,6 +65,22 @@ describe GoogleApi::AuthorizationsController do it_behaves_like 'access denied' end + + context 'when a Faraday exception occurs' do + let(:state) { session_key } + + [::Faraday::TimeoutError, ::Faraday::ConnectionFailed].each do |error| + it "sets a flash alert on #{error}" do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |instance| + allow(instance).to receive(:get_token).and_raise(error.new(nil)) + end + + subject + + expect(flash[:alert]).to eq('Timeout connecting to the Google API. Please try again.') + end + end + end end context 'state param is present, but session key is blank' do diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index 06a949471a7..68150504fe3 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe GraphqlController do + include GraphqlHelpers + before do stub_feature_flags(graphql: true) end @@ -30,7 +32,7 @@ describe GraphqlController do describe 'POST #execute' do context 'when user is logged in' do - let(:user) { create(:user) } + let(:user) { create(:user, last_activity_on: Date.yesterday) } before do sign_in(user) @@ -54,6 +56,19 @@ describe GraphqlController do expect(response).to have_gitlab_http_status(:forbidden) expect(response).to render_template('errors/access_denied') end + + it 'updates the users last_activity_on field' do + expect { post :execute }.to change { user.reload.last_activity_on } + end + end + + context 'when user uses an API token' do + let(:user) { create(:user, last_activity_on: Date.yesterday) } + let(:token) { create(:personal_access_token, user: user, scopes: [:api]) } + + it 'updates the users last_activity_on field' do + expect { post :execute, params: { access_token: token.token } }.to change { user.reload.last_activity_on } + end end context 'when user is not logged in' do @@ -64,4 +79,52 @@ describe GraphqlController do end end end + + describe 'Admin Mode' do + let(:admin) { create(:admin) } + let(:project) { create(:project) } + let(:graphql_query) { graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id name)) } + + before do + sign_in(admin) + end + + context 'when admin mode enabled' do + before do + Gitlab::Session.with_session(controller.session) do + controller.current_user_mode.request_admin_mode! + controller.current_user_mode.enable_admin_mode!(password: admin.password) + end + end + + it 'can query project data' do + post :execute, params: { query: graphql_query } + + expect(controller.current_user_mode.admin_mode?).to be(true) + expect(json_response['data']['project']['name']).to eq(project.name) + end + end + + context 'when admin mode disabled' do + it 'cannot query project data' do + post :execute, params: { query: graphql_query } + + expect(controller.current_user_mode.admin_mode?).to be(false) + expect(json_response['data']['project']).to be_nil + end + + context 'when admin is member of the project' do + before do + project.add_developer(admin) + end + + it 'can query project data' do + post :execute, params: { query: graphql_query } + + expect(controller.current_user_mode.admin_mode?).to be(false) + expect(json_response['data']['project']['name']).to eq(project.name) + end + end + end + end end diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index 28a174560dd..1f2f6bd811b 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -32,7 +32,7 @@ describe Groups::ClustersController do create(:cluster, :disabled, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group]) end - it 'lists available clusters' do + it 'lists available clusters and renders html' do go expect(response).to have_gitlab_http_status(:ok) @@ -40,20 +40,39 @@ describe Groups::ClustersController do expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster]) end + it 'lists available clusters with json serializer' do + go(format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('cluster_list') + end + context 'when page is specified' do let(:last_page) { group.clusters.page.total_pages } + let(:total_count) { group.clusters.page.total_count } before do - allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) - create_list(:cluster, 2, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group]) + create_list(:cluster, 30, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group]) end it 'redirects to the page' do + expect(last_page).to be > 1 + go(page: last_page) expect(response).to have_gitlab_http_status(:ok) expect(assigns(:clusters).current_page).to eq(last_page) end + + it 'displays cluster list for associated page' do + expect(last_page).to be > 1 + + go(page: last_page, format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['X-Page'].to_i).to eq(last_page) + expect(response.headers['X-Total'].to_i).to eq(total_count) + end end end diff --git a/spec/controllers/groups/group_links_controller_spec.rb b/spec/controllers/groups/group_links_controller_spec.rb index 21169188386..ca430414d17 100644 --- a/spec/controllers/groups/group_links_controller_spec.rb +++ b/spec/controllers/groups/group_links_controller_spec.rb @@ -99,18 +99,6 @@ describe Groups::GroupLinksController do expect(flash[:alert]).to eq('error') end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(share_group_with_group: false) - end - - it 'renders 404' do - subject - - expect(response).to have_gitlab_http_status(:not_found) - end - end end context 'when user does not have access to the group' do @@ -184,18 +172,6 @@ describe Groups::GroupLinksController do expect(response).to have_gitlab_http_status(:not_found) end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(share_group_with_group: false) - end - - it 'renders 404' do - subject - - expect(response).to have_gitlab_http_status(:not_found) - end - end end describe '#destroy' do @@ -231,17 +207,5 @@ describe Groups::GroupLinksController do expect(response).to have_gitlab_http_status(:not_found) end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(share_group_with_group: false) - end - - it 'renders 404' do - subject - - expect(response).to have_gitlab_http_status(:not_found) - end - end end end diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb index a84664c6c04..7b78aeadbd8 100644 --- a/spec/controllers/groups/registry/repositories_controller_spec.rb +++ b/spec/controllers/groups/registry/repositories_controller_spec.rb @@ -6,12 +6,13 @@ describe Groups::Registry::RepositoriesController do let_it_be(:user) { create(:user) } let_it_be(:guest) { create(:user) } let_it_be(:group, reload: true) { create(:group) } + let(:additional_parameters) { {} } subject do - get :index, params: { + get :index, params: additional_parameters.merge({ group_id: group, format: format - } + }) end before do @@ -36,6 +37,25 @@ describe Groups::Registry::RepositoriesController do end end + shared_examples 'with name parameter' do + let_it_be(:project) { create(:project, group: test_group) } + let_it_be(:repo) { create(:container_repository, project: project, name: 'my_searched_image') } + let_it_be(:another_repo) { create(:container_repository, project: project, name: 'bar') } + + let(:additional_parameters) { { name: 'my_searched_image' } } + + it 'returns the searched repo' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.length).to eq 1 + expect(json_response.first).to include( + 'id' => repo.id, + 'name' => repo.name + ) + end + end + shared_examples 'renders correctly' do context 'when user has access to registry' do let_it_be(:test_group) { group } @@ -64,6 +84,8 @@ describe Groups::Registry::RepositoriesController do it_behaves_like 'renders a list of repositories' + it_behaves_like 'with name parameter' + it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories' context 'with project in subgroup' do @@ -71,6 +93,8 @@ describe Groups::Registry::RepositoriesController do it_behaves_like 'renders a list of repositories' + it_behaves_like 'with name parameter' + context 'with project in subgroup and group' do let_it_be(:repo_in_test_group) { create_project_with_repo(test_group) } let_it_be(:repo_in_group) { create_project_with_repo(group) } @@ -81,6 +105,8 @@ describe Groups::Registry::RepositoriesController do expect(json_response).to be_kind_of(Array) expect(json_response.length).to eq 2 end + + it_behaves_like 'with name parameter' end end end diff --git a/spec/controllers/groups/settings/integrations_controller_spec.rb b/spec/controllers/groups/settings/integrations_controller_spec.rb index 76cd74de183..29c93c621bd 100644 --- a/spec/controllers/groups/settings/integrations_controller_spec.rb +++ b/spec/controllers/groups/settings/integrations_controller_spec.rb @@ -27,7 +27,7 @@ describe Groups::Settings::IntegrationsController do context 'when group_level_integrations not enabled' do it 'returns not_found' do - stub_feature_flags(group_level_integrations: { enabled: false, thing: group }) + stub_feature_flags(group_level_integrations: false) get :index, params: { group_id: group } @@ -60,7 +60,7 @@ describe Groups::Settings::IntegrationsController do context 'when group_level_integrations not enabled' do it 'returns not_found' do - stub_feature_flags(group_level_integrations: { enabled: false, thing: group }) + stub_feature_flags(group_level_integrations: false) get :edit, params: { group_id: group, id: Service.available_services_names.sample } diff --git a/spec/controllers/groups/settings/repository_controller_spec.rb b/spec/controllers/groups/settings/repository_controller_spec.rb index 20070fb17a0..9523d404538 100644 --- a/spec/controllers/groups/settings/repository_controller_spec.rb +++ b/spec/controllers/groups/settings/repository_controller_spec.rb @@ -15,7 +15,7 @@ describe Groups::Settings::RepositoryController do describe 'POST create_deploy_token' do context 'when ajax_new_deploy_token feature flag is disabled for the project' do before do - stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: group }) + stub_feature_flags(ajax_new_deploy_token: false) entity.add_owner(user) end @@ -56,7 +56,7 @@ describe Groups::Settings::RepositoryController do 'id' => be_a(Integer), 'name' => deploy_token_params[:name], 'username' => deploy_token_params[:username], - 'expires_at' => Time.parse(deploy_token_params[:expires_at]), + 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), 'token' => be_a(String), 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 93478bbff1d..354c9e047c8 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -270,6 +270,37 @@ describe GroupsController do it { expect(subject).to render_template(:new) } end + + context 'when creating a group with `default_branch_protection` attribute' do + before do + sign_in(user) + end + + subject do + post :create, params: { group: { name: 'new_group', path: 'new_group', default_branch_protection: Gitlab::Access::PROTECTION_NONE } } + end + + context 'for users who have the ability to create a group with `default_branch_protection`' do + it 'creates group with the specified branch protection level' do + subject + + expect(response).to have_gitlab_http_status(:found) + expect(Group.last.default_branch_protection).to eq(Gitlab::Access::PROTECTION_NONE) + end + end + + context 'for users who do not have the ability to create a group with `default_branch_protection`' do + it 'does not create the group with the specified branch protection level' do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :create_group_with_default_branch_protection) { false } + + subject + + expect(response).to have_gitlab_http_status(:found) + expect(Group.last.default_branch_protection).not_to eq(Gitlab::Access::PROTECTION_NONE) + end + end + end end describe 'GET #index' do @@ -423,11 +454,31 @@ describe GroupsController do expect(group.reload.project_creation_level).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS) end - it 'updates the default_branch_protection successfully' do - post :update, params: { id: group.to_param, group: { default_branch_protection: ::Gitlab::Access::PROTECTION_DEV_CAN_MERGE } } + context 'updating default_branch_protection' do + subject do + put :update, params: { id: group.to_param, group: { default_branch_protection: ::Gitlab::Access::PROTECTION_DEV_CAN_MERGE } } + end + + context 'for users who have the ability to update default_branch_protection' do + it 'updates the attribute' do + subject - expect(response).to have_gitlab_http_status(:found) - expect(group.reload.default_branch_protection).to eq(::Gitlab::Access::PROTECTION_DEV_CAN_MERGE) + expect(response).to have_gitlab_http_status(:found) + expect(group.reload.default_branch_protection).to eq(::Gitlab::Access::PROTECTION_DEV_CAN_MERGE) + end + end + + context 'for users who do not have the ability to update default_branch_protection' do + it 'does not update the attribute' do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :update_default_branch_protection, group) { false } + + subject + + expect(response).to have_gitlab_http_status(:found) + expect(group.reload.default_branch_protection).not_to eq(::Gitlab::Access::PROTECTION_DEV_CAN_MERGE) + end + end end context 'when a project inside the group has container repositories' do diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index f03fee8d3ae..fafbe6bffe1 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -99,6 +99,7 @@ describe HelpController do context 'for Markdown formats' do context 'when requested file exists' do before do + expect(File).to receive(:read).and_return(fixture_file('blockquote_fence_after.md')) get :show, params: { path: 'ssh/README' }, format: :md end @@ -108,7 +109,7 @@ describe HelpController do it 'renders HTML' do expect(response).to render_template('show.html.haml') - expect(response.content_type).to eq 'text/html' + expect(response.media_type).to eq 'text/html' end end @@ -129,7 +130,7 @@ describe HelpController do }, format: :png expect(response).to be_successful - expect(response.content_type).to eq 'image/png' + expect(response.media_type).to eq 'image/png' expect(response.headers['Content-Disposition']).to match(/^inline;/) end end @@ -168,6 +169,6 @@ describe HelpController do end def stub_readme(content) - allow(File).to receive(:read).and_return(content) + expect(File).to receive(:read).and_return(content) end end diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index ab4f6d5054c..d44edb63635 100644 --- a/spec/controllers/import/bitbucket_controller_spec.rb +++ b/spec/controllers/import/bitbucket_controller_spec.rb @@ -27,7 +27,7 @@ describe Import::BitbucketController do end it "updates access token" do - expires_at = Time.now + 1.day + expires_at = Time.current + 1.day expires_in = 1.day access_token = double(token: token, secret: secret, diff --git a/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb b/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb index ceab9754617..0242a91ac60 100644 --- a/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb @@ -65,4 +65,55 @@ describe Ldap::OmniauthCallbacksController do expect(request.env['warden']).to be_authenticated end end + + describe 'enable admin mode' do + include_context 'custom session' + + before do + sign_in user + end + + context 'with a regular user' do + it 'cannot be enabled' do + reauthenticate_and_check_admin_mode(expected_admin_mode: false) + + expect(response).to redirect_to(root_path) + end + end + + context 'with an admin user' do + let(:user) { create(:omniauth_user, :admin, extern_uid: uid, provider: provider) } + + context 'when requested first' do + before do + subject.current_user_mode.request_admin_mode! + end + + it 'can be enabled' do + reauthenticate_and_check_admin_mode(expected_admin_mode: true) + + expect(response).to redirect_to(admin_root_path) + end + end + + context 'when not requested first' do + it 'cannot be enabled' do + reauthenticate_and_check_admin_mode(expected_admin_mode: false) + + expect(response).to redirect_to(root_path) + end + end + end + end + + def reauthenticate_and_check_admin_mode(expected_admin_mode:) + # Initially admin mode disabled + expect(subject.current_user_mode.admin_mode?).to be(false) + + # Trigger OmniAuth admin mode flow and expect admin mode status + post provider + + expect(request.env['warden']).to be_authenticated + expect(subject.current_user_mode.admin_mode?).to be(expected_admin_mode) + end end diff --git a/spec/controllers/oauth/token_info_controller_spec.rb b/spec/controllers/oauth/token_info_controller_spec.rb index 4b3539879df..4658c2702ca 100644 --- a/spec/controllers/oauth/token_info_controller_spec.rb +++ b/spec/controllers/oauth/token_info_controller_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Oauth::TokenInfoController do get :show expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -23,7 +23,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:ok) - expect(JSON.parse(response.body)).to eq( + expect(Gitlab::Json.parse(response.body)).to eq( 'scope' => %w[api], 'scopes' => %w[api], 'created_at' => access_token.created_at.to_i, @@ -40,7 +40,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: 'unknown_token' } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -53,7 +53,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -64,7 +64,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end end diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index 9537ff62f8b..0d8a6827afe 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OmniauthCallbacksController, type: :controller, do_not_mock_admin_mode: true do +describe OmniauthCallbacksController, type: :controller do include LoginHelpers describe 'omniauth' do @@ -144,6 +144,10 @@ describe OmniauthCallbacksController, type: :controller, do_not_mock_admin_mode: let(:extern_uid) { 'my-uid' } let(:provider) { :github } + it_behaves_like 'known sign in' do + let(:post_action) { post provider } + end + it 'allows sign in' do post provider @@ -287,6 +291,11 @@ describe OmniauthCallbacksController, type: :controller, do_not_mock_admin_mode: request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth'] end + it_behaves_like 'known sign in' do + let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') } + let(:post_action) { post :saml, params: { SAMLResponse: mock_saml_response } } + end + context 'sign up' do before do user.destroy diff --git a/spec/controllers/profiles/emails_controller_spec.rb b/spec/controllers/profiles/emails_controller_spec.rb index 7c6b1863202..ffec43fea2c 100644 --- a/spec/controllers/profiles/emails_controller_spec.rb +++ b/spec/controllers/profiles/emails_controller_spec.rb @@ -9,13 +9,27 @@ describe Profiles::EmailsController do sign_in(user) end + around do |example| + perform_enqueued_jobs do + example.run + end + end + describe '#create' do - let(:email_params) { { email: "add_email@example.com" } } + context 'when email address is valid' do + let(:email_params) { { email: "add_email@example.com" } } - it 'sends an email confirmation' do - expect { post(:create, params: { email: email_params }) }.to change { ActionMailer::Base.deliveries.size } - expect(ActionMailer::Base.deliveries.last.to).to eq [email_params[:email]] - expect(ActionMailer::Base.deliveries.last.subject).to match "Confirmation instructions" + it 'sends an email confirmation' do + expect { post(:create, params: { email: email_params }) }.to change { ActionMailer::Base.deliveries.size } + end + end + + context 'when email address is invalid' do + let(:email_params) { { email: "test.@example.com" } } + + it 'does not send an email confirmation' do + expect { post(:create, params: { email: email_params }) }.not_to change { ActionMailer::Base.deliveries.size } + end end end diff --git a/spec/controllers/projects/alert_management_controller_spec.rb b/spec/controllers/projects/alert_management_controller_spec.rb new file mode 100644 index 00000000000..b84376db33d --- /dev/null +++ b/spec/controllers/projects/alert_management_controller_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::AlertManagementController do + let_it_be(:project) { create(:project) } + let_it_be(:role) { :developer } + let_it_be(:user) { create(:user) } + let_it_be(:id) { 1 } + + before do + project.add_role(user, role) + sign_in(user) + end + + describe 'GET #index' do + it 'shows the page' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when user is unauthorized' do + let(:role) { :reporter } + + it 'shows 404' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'GET #details' do + it 'shows the page' do + get :details, params: { namespace_id: project.namespace, project_id: project, id: id } + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when user is unauthorized' do + let(:role) { :reporter } + + it 'shows 404' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'set_alert_id' do + it 'sets alert id from the route' do + get :details, params: { namespace_id: project.namespace, project_id: project, id: id } + + expect(assigns(:alert_id)).to eq(id.to_s) + end + end +end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index c59983d5138..be616b566dd 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -308,10 +308,13 @@ describe Projects::ArtifactsController do end describe 'GET raw' do - subject { get(:raw, params: { namespace_id: project.namespace, project_id: project, job_id: job, path: path }) } + let(:query_params) { { namespace_id: project.namespace, project_id: project, job_id: job, path: path } } + + subject { get(:raw, params: query_params) } context 'when the file exists' do let(:path) { 'ci_artifacts.txt' } + let(:archive_matcher) { /build_artifacts.zip(\?[^?]+)?$/ } shared_examples 'a valid file' do it 'serves the file using workhorse' do @@ -323,8 +326,8 @@ describe Projects::ArtifactsController do expect(params.keys).to eq(%w(Archive Entry)) expect(params['Archive']).to start_with(archive_path) # On object storage, the URL can end with a query string - expect(params['Archive']).to match(/build_artifacts.zip(\?[^?]+)?$/) - expect(params['Entry']).to eq(Base64.encode64('ci_artifacts.txt')) + expect(params['Archive']).to match(archive_matcher) + expect(params['Entry']).to eq(Base64.encode64(path)) end def send_data @@ -334,7 +337,7 @@ describe Projects::ArtifactsController do def params @params ||= begin base64_params = send_data.sub(/\Aartifacts\-entry:/, '') - JSON.parse(Base64.urlsafe_decode64(base64_params)) + Gitlab::Json.parse(Base64.urlsafe_decode64(base64_params)) end end end @@ -359,6 +362,37 @@ describe Projects::ArtifactsController do let(:archive_path) { 'https://' } end end + + context 'fetching an artifact of different type' do + before do + job.job_artifacts.each(&:destroy) + end + + context 'when the artifact is zip' do + let!(:artifact) { create(:ci_job_artifact, :lsif, job: job, file_path: Rails.root.join("spec/fixtures/#{file_name}")) } + let(:path) { 'lsif/main.go.json' } + let(:file_name) { 'lsif.json.zip' } + let(:archive_matcher) { file_name } + let(:query_params) { super().merge(file_type: :lsif, path: path) } + + it_behaves_like 'a valid file' do + let(:store) { ObjectStorage::Store::LOCAL } + let(:archive_path) { JobArtifactUploader.root } + end + end + + context 'when the artifact is not zip' do + let(:query_params) { super().merge(file_type: :junit, path: '') } + + it 'responds with not found' do + create(:ci_job_artifact, :junit, job: job) + + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 85d3044993e..174d8904481 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -124,57 +124,39 @@ describe Projects::BranchesController do ) end - context 'create_confidential_merge_request feature is enabled' do + context 'user cannot update issue' do + let(:issue) { create(:issue, project: confidential_issue_project) } + + it 'does not post a system note' do + expect(SystemNoteService).not_to receive(:new_issue_branch) + + create_branch_with_confidential_issue_project + end + end + + context 'user can update issue' do before do - stub_feature_flags(create_confidential_merge_request: true) + confidential_issue_project.add_reporter(user) end - context 'user cannot update issue' do + context 'issue is under the specified project' do let(:issue) { create(:issue, project: confidential_issue_project) } - it 'does not post a system note' do - expect(SystemNoteService).not_to receive(:new_issue_branch) + it 'posts a system note' do + expect(SystemNoteService).to receive(:new_issue_branch).with(issue, confidential_issue_project, user, "1-feature-branch", branch_project: project) create_branch_with_confidential_issue_project end end - context 'user can update issue' do - before do - confidential_issue_project.add_reporter(user) - end - - context 'issue is under the specified project' do - let(:issue) { create(:issue, project: confidential_issue_project) } - - it 'posts a system note' do - expect(SystemNoteService).to receive(:new_issue_branch).with(issue, confidential_issue_project, user, "1-feature-branch", branch_project: project) - - create_branch_with_confidential_issue_project - end - end - - context 'issue is not under the specified project' do - it 'does not post a system note' do - expect(SystemNoteService).not_to receive(:new_issue_branch) + context 'issue is not under the specified project' do + it 'does not post a system note' do + expect(SystemNoteService).not_to receive(:new_issue_branch) - create_branch_with_confidential_issue_project - end + create_branch_with_confidential_issue_project end end end - - context 'create_confidential_merge_request feature is disabled' do - before do - stub_feature_flags(create_confidential_merge_request: false) - end - - it 'posts a system note on project' do - expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch", branch_project: project) - - create_branch_with_confidential_issue_project - end - end end context 'repository-less project' do diff --git a/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb new file mode 100644 index 00000000000..ac31045678f --- /dev/null +++ b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::Ci::DailyBuildGroupReportResultsController do + describe 'GET index' do + let(:project) { create(:project, :public, :repository) } + let(:ref_path) { 'refs/heads/master' } + let(:param_type) { 'coverage' } + let(:start_date) { '2019-12-10' } + let(:end_date) { '2020-03-09' } + + def create_daily_coverage(group_name, coverage, date) + create( + :ci_daily_build_group_report_result, + project: project, + ref_path: ref_path, + group_name: group_name, + data: { 'coverage' => coverage }, + date: date + ) + end + + def csv_response + CSV.parse(response.body) + end + + before do + create_daily_coverage('rspec', 79.0, '2020-03-09') + create_daily_coverage('karma', 81.0, '2019-12-10') + create_daily_coverage('rspec', 67.0, '2019-12-09') + create_daily_coverage('karma', 71.0, '2019-12-09') + + get :index, params: { + namespace_id: project.namespace, + project_id: project, + ref_path: ref_path, + param_type: param_type, + start_date: start_date, + end_date: end_date, + format: :csv + } + end + + it 'serves the results in CSV' do + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8') + + expect(csv_response).to eq([ + %w[date group_name coverage], + ['2020-03-09', 'rspec', '79.0'], + ['2019-12-10', 'karma', '81.0'] + ]) + end + + context 'when given date range spans more than 90 days' do + let(:start_date) { '2019-12-09' } + let(:end_date) { '2020-03-09' } + + it 'limits the result to 90 days from the given start_date' do + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8') + + expect(csv_response).to eq([ + %w[date group_name coverage], + ['2020-03-09', 'rspec', '79.0'], + ['2019-12-10', 'karma', '81.0'] + ]) + end + end + + context 'when given param_type is invalid' do + let(:param_type) { 'something_else' } + + it 'responds with 422 error' do + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + end +end diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index 07733ec30d9..698a3773d59 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -26,7 +26,7 @@ describe Projects::ClustersController do let!(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) } - it 'lists available clusters' do + it 'lists available clusters and renders html' do go expect(response).to have_gitlab_http_status(:ok) @@ -34,20 +34,39 @@ describe Projects::ClustersController do expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster]) end + it 'lists available clusters with json serializer' do + go(format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('cluster_list') + end + context 'when page is specified' do let(:last_page) { project.clusters.page.total_pages } + let(:total_count) { project.clusters.page.total_count } before do - allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) - create_list(:cluster, 2, :provided_by_gcp, :production_environment, projects: [project]) + create_list(:cluster, 30, :provided_by_gcp, :production_environment, projects: [project]) end it 'redirects to the page' do + expect(last_page).to be > 1 + go(page: last_page) expect(response).to have_gitlab_http_status(:ok) expect(assigns(:clusters).current_page).to eq(last_page) end + + it 'displays cluster list for associated page' do + expect(last_page).to be > 1 + + go(page: last_page, format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['X-Page'].to_i).to eq(last_page) + expect(response.headers['X-Total'].to_i).to eq(total_count) + end end end @@ -68,9 +87,11 @@ describe Projects::ClustersController do it 'is allowed for admin when admin mode enabled', :enable_admin_mode do expect { go }.to be_allowed_for(:admin) end + it 'is disabled for admin when admin mode disabled' do expect { go }.to be_denied_for(:admin) end + it { expect { go }.to be_allowed_for(:owner).of(project) } it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb index b828c678d0c..942e095d669 100644 --- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb @@ -17,7 +17,7 @@ describe Projects::CycleAnalytics::EventsController do get_issue expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end @@ -38,7 +38,7 @@ describe Projects::CycleAnalytics::EventsController do it 'contains event detais' do get_issue - events = JSON.parse(response.body)['events'] + events = Gitlab::Json.parse(response.body)['events'] expect(events).not_to be_empty expect(events.first).to include('title', 'author', 'iid', 'total_time', 'created_at', 'url') @@ -51,7 +51,7 @@ describe Projects::CycleAnalytics::EventsController do expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end end diff --git a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb new file mode 100644 index 00000000000..30d2b79a92f --- /dev/null +++ b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::RawImagesController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + let(:filename) { design.filename } + + before do + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha + }) + end + + before do + sign_in(viewer) + end + + context 'when the design is not an LFS file' do + let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq('attachment') + expect(response).to have_gitlab_http_status(:ok) + end + + it 'serves files with Workhorse' do + subject + + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response).to have_gitlab_http_status(:ok) + end + + it_behaves_like 'project cache control headers' + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + shared_examples 'a successful request for sha' do + it do + expect_next_instance_of(DesignManagement::Repository) do |repository| + expect(repository).to receive(:blob_at).with(expected_ref, design.full_path).and_call_original + end + + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is nil' do + let(:sha) { nil } + let(:expected_ref) { 'master' } + + it_behaves_like 'a successful request for sha' + end + end + end + + context 'when the design is an LFS file' do + let_it_be(:design) { create(:design, :with_lfs_file, issue: issue) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'sets appropriate caching headers' do + subject + + expect(response.header['ETag']).to be_present + expect(response.header['Cache-Control']).to eq("max-age=60, private") + end + end + + # Pass `skip_lfs_disabled_tests: true` to this shared example to disable + # the test scenarios for when LFS is disabled globally. + # + # When LFS is disabled then the design management feature also becomes disabled. + # When the feature is disabled, the `authorize :read_design` check within the + # controller will never authorize the user. Therefore #show will return a 403 and + # we cannot test the data that it serves. + it_behaves_like 'a controller that can serve LFS files', skip_lfs_disabled_tests: true do + let(:file) { fixture_file_upload('spec/fixtures/dk.png', '`/png') } + let(:lfs_pointer) { Gitlab::Git::LfsPointerFile.new(file.read) } + let(:design) { create(:design, :with_lfs_file, file: lfs_pointer.pointer, issue: issue) } + let(:lfs_oid) { project.design_repository.blob_at('HEAD', design.full_path).lfs_oid } + let(:filepath) { design.full_path } + end + end +end diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb new file mode 100644 index 00000000000..6bfec1b314e --- /dev/null +++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::ResizedImageController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let_it_be(:size) { :v432x230 } + let(:design) { create(:design, :with_smaller_image_versions, issue: issue, versions_count: 2) } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + + before do + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha, + id: size + }) + end + + before do + sign_in(viewer) + subject + end + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'Response headers' do + it 'completes the request successfully' do + expect(response).to have_gitlab_http_status(:ok) + end + + it 'sets Content-Disposition as attachment' do + filename = design.filename + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'serves files with Workhorse' do + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + end + + it 'sets appropriate caching headers' do + expect(response.header['Cache-Control']).to eq('private') + expect(response.header['ETag']).to be_present + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when size is invalid' do + let_it_be(:size) { :foo } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + # The design images generated by Factorybot are identical, so + # refer to the `ETag` header, which is uniquely generated from the Action + # (the record that represents the design at a specific version), to + # verify that the correct file is being returned. + def etag(action) + ActionDispatch::TestResponse.new.send(:generate_weak_etag, [action.cache_key, '']) + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + + it 'serves the oldest image' do + action = oldest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is nil' do + let(:sha) { nil } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is not a valid version sha' do + let(:sha) { '570e7b2abdd848b95f2f578043fc23bd6f6fd24d' } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when design does not have a smaller image size available' do + let(:design) { create(:design, :with_file, issue: issue) } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 793c10f0b21..64f90e44bb6 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -38,7 +38,7 @@ describe Projects::Environments::PrometheusApiController do context 'with success result' do let(:service_result) { { status: :success, body: prometheus_body } } let(:prometheus_body) { '{"status":"success"}' } - let(:prometheus_json_body) { JSON.parse(prometheus_body) } + let(:prometheus_json_body) { Gitlab::Json.parse(prometheus_body) } it 'returns prometheus response' do get :proxy, params: environment_params @@ -55,7 +55,7 @@ describe Projects::Environments::PrometheusApiController do end it 'replaces variables with values' do - get :proxy, params: environment_params.merge(query: 'up{environment="%{ci_environment_slug}"}') + get :proxy, params: environment_params.merge(query: 'up{environment="{{ci_environment_slug}}"}') expect(Prometheus::ProxyService).to have_received(:new) .with(environment, 'GET', 'query', expected_params) diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 3b035eea7d5..56fff2771ec 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -410,6 +410,18 @@ describe Projects::EnvironmentsController do expect(json_response['last_update']).to eq(42) end end + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #additional_metrics' do @@ -473,6 +485,18 @@ describe Projects::EnvironmentsController do .to raise_error(ActionController::ParameterMissing) end end + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #metrics_dashboard' do @@ -648,6 +672,18 @@ describe Projects::EnvironmentsController do it_behaves_like 'the default dashboard' it_behaves_like 'dashboard can be specified' it_behaves_like 'dashboard can be embedded' + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #search' do diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb index c62baa30fde..8502bd1ab0a 100644 --- a/spec/controllers/projects/grafana_api_controller_spec.rb +++ b/spec/controllers/projects/grafana_api_controller_spec.rb @@ -131,10 +131,11 @@ describe Projects::GrafanaApiController do get :metrics_dashboard, params: params expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to eq({ + expect(json_response).to include({ 'dashboard' => '{}', 'status' => 'success' }) + expect(json_response).to include('metrics_data') end end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index b5248c7f0c8..e589815c45d 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -41,6 +41,26 @@ describe Projects::GraphsController do expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:charts) end + + it 'sets the daily coverage options' do + Timecop.freeze do + get(:charts, params: { namespace_id: project.namespace.path, project_id: project.path, id: 'master' }) + + expect(assigns[:daily_coverage_options]).to eq( + base_params: { + start_date: Time.current.to_date - 90.days, + end_date: Time.current.to_date, + ref_path: project.repository.expand_ref('master'), + param_type: 'coverage' + }, + download_path: namespace_project_ci_daily_build_group_report_results_path( + namespace_id: project.namespace, + project_id: project, + format: :csv + ) + ) + end + end end context 'when languages were previously detected' do diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb index 4629aab65dd..d1b0a086576 100644 --- a/spec/controllers/projects/import/jira_controller_spec.rb +++ b/spec/controllers/projects/import/jira_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Projects::Import::JiraController do + include JiraServiceHelper + let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:jira_project_key) { 'Test' } @@ -61,9 +63,10 @@ describe Projects::Import::JiraController do before do stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import_vue: false) + stub_jira_service_test end - context 'when jira service is enabled for the project' do + context 'when Jira service is enabled for the project' do let_it_be(:jira_service) { create(:jira_service, project: project) } context 'when user is developer' do @@ -79,7 +82,7 @@ describe Projects::Import::JiraController do get :show, params: { namespace_id: project.namespace.to_param, project_id: project } end - it 'does not query jira service' do + it 'does not query Jira service' do expect(project).not_to receive(:jira_service) end @@ -118,7 +121,7 @@ describe Projects::Import::JiraController do end end - context 'when running jira import first time' do + context 'when running Jira import first time' do context 'get show' do before do allow(JIRA::Resource::Project).to receive(:all).and_return(jira_projects) @@ -147,12 +150,12 @@ describe Projects::Import::JiraController do end context 'post import' do - context 'when jira project key is empty' do + context 'when Jira project key is empty' do it 'redirects back to show with an error' do post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: '' } expect(response).to redirect_to(project_import_jira_path(project)) - expect(flash[:alert]).to eq('No jira project key has been provided.') + expect(flash[:alert]).to eq('No Jira project key has been provided.') end end @@ -197,7 +200,7 @@ describe Projects::Import::JiraController do end end - context 'when jira import ran before' do + context 'when Jira import ran before' do let_it_be(:jira_import_state) { create(:jira_import_state, :finished, project: project, jira_project_key: jira_project_key) } context 'get show' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 862a4bd3559..96f11f11dc4 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe Projects::IssuesController do include ProjectForksHelper + include_context 'includes Spam constants' let(:project) { create(:project) } let(:user) { create(:user) } @@ -186,6 +187,33 @@ describe Projects::IssuesController do expect(assigns(:issue)).to be_a_new(Issue) end + where(:conf_value, :conf_result) do + [ + [true, true], + ['true', true], + ['TRUE', true], + [false, false], + ['false', false], + ['FALSE', false] + ] + end + + with_them do + it 'sets the confidential flag to the expected value' do + get :new, params: { + namespace_id: project.namespace, + project_id: project, + issue: { + confidential: conf_value + } + } + + assigned_issue = assigns(:issue) + expect(assigned_issue).to be_a_new(Issue) + expect(assigned_issue.confidential).to eq conf_result + end + end + it 'fills in an issue for a merge request' do project_with_repository = create(:project, :repository) project_with_repository.add_developer(user) @@ -242,6 +270,91 @@ describe Projects::IssuesController do end end + describe '#related_branches' do + subject { get :related_branches, params: params, format: :json } + + before do + sign_in(user) + project.add_developer(developer) + end + + let(:developer) { user } + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + id: issue.iid + } + end + + context 'the current user cannot download code' do + it 'prevents access' do + allow(controller).to receive(:can?).with(any_args).and_return(true) + allow(controller).to receive(:can?).with(user, :download_code, project).and_return(false) + + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'there are no related branches' do + it 'assigns empty arrays', :aggregate_failures do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:related_branches)).to be_empty + expect(response).to render_template('projects/issues/_related_branches') + expect(json_response).to eq('html' => '') + end + end + + context 'there are related branches' do + let(:missing_branch) { "#{issue.to_branch_name}-missing" } + let(:unreadable_branch) { "#{issue.to_branch_name}-unreadable" } + let(:pipeline) { build(:ci_pipeline, :success, project: project) } + let(:master_branch) { 'master' } + + let(:related_branches) do + [ + branch_info(issue.to_branch_name, pipeline.detailed_status(user)), + branch_info(missing_branch, nil), + branch_info(unreadable_branch, nil) + ] + end + + def branch_info(name, status) + { + name: name, + link: controller.project_compare_path(project, from: master_branch, to: name), + pipeline_status: status + } + end + + before do + allow(controller).to receive(:find_routable!) + .with(Project, project.full_path, any_args).and_return(project) + allow(project).to receive(:default_branch).and_return(master_branch) + allow_next_instance_of(Issues::RelatedBranchesService) do |service| + allow(service).to receive(:execute).and_return(related_branches) + end + end + + it 'finds and assigns the appropriate branch information', :aggregate_failures do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:related_branches)).to contain_exactly( + branch_info(issue.to_branch_name, an_instance_of(Gitlab::Ci::Status::Success)), + branch_info(missing_branch, be_nil), + branch_info(unreadable_branch, be_nil) + ) + expect(response).to render_template('projects/issues/_related_branches') + expect(json_response).to match('html' => String) + end + end + end + # This spec runs as a request-style spec in order to invoke the # Rails router. A controller-style spec matches the wrong route, and # session['user_return_to'] becomes incorrect. @@ -419,11 +532,11 @@ describe Projects::IssuesController do expect(issue.reload.title).to eq('New title') end - context 'when Akismet is enabled and the issue is identified as spam' do + context 'when the SpamVerdictService disallows' do before do stub_application_setting(recaptcha_enabled: true) - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end @@ -496,7 +609,7 @@ describe Projects::IssuesController do before do project.add_developer(user) - issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now) + issue.update!(last_edited_by: deleted_user, last_edited_at: Time.current) deleted_user.destroy sign_in(user) @@ -712,20 +825,20 @@ describe Projects::IssuesController do update_issue(issue_params: { assignee_ids: [assignee.id] }) expect(json_response['assignees'].first.keys) - .to match_array(%w(id name username avatar_url state web_url)) + .to include(*%w(id name username avatar_url state web_url)) end end - context 'Akismet is enabled' do + context 'Recaptcha is enabled' do before do project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) stub_application_setting(recaptcha_enabled: true) end - context 'when an issue is not identified as spam' do + context 'when SpamVerdictService allows the issue' do before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: false) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(ALLOW) end end @@ -735,10 +848,10 @@ describe Projects::IssuesController do end context 'when an issue is identified as spam' do - context 'when captcha is not verified' do + context 'when recaptcha is not verified' do before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end @@ -751,7 +864,7 @@ describe Projects::IssuesController do expect { update_issue }.not_to change { issue.reload.title } end - it 'rejects an issue recognized as a spam when recaptcha disabled' do + it 'rejects an issue recognized as a spam when reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) expect { update_issue }.not_to change { issue.reload.title } @@ -796,7 +909,7 @@ describe Projects::IssuesController do end end - context 'when captcha is verified' do + context 'when recaptcha is verified' do let(:spammy_title) { 'Whatever' } let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: spammy_title) } @@ -810,7 +923,7 @@ describe Projects::IssuesController do expect(response).to have_gitlab_http_status(:ok) end - it 'accepts an issue after recaptcha is verified' do + it 'accepts an issue after reCAPTCHA is verified' do expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title) end @@ -967,17 +1080,17 @@ describe Projects::IssuesController do end end - context 'Akismet is enabled' do + context 'Recaptcha is enabled' do before do stub_application_setting(recaptcha_enabled: true) end - context 'when an issue is not identified as spam' do + context 'when SpamVerdictService allows the issue' do before do stub_feature_flags(allow_possible_spam: false) - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: false) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(ALLOW) end end @@ -986,18 +1099,18 @@ describe Projects::IssuesController do end end - context 'when an issue is identified as spam' do + context 'when SpamVerdictService requires recaptcha' do context 'when captcha is not verified' do - def post_spam_issue - post_new_issue(title: 'Spam Title', description: 'Spam lives here') - end - before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end + def post_spam_issue + post_new_issue(title: 'Spam Title', description: 'Spam lives here') + end + context 'when allow_possible_spam feature flag is false' do before do stub_feature_flags(allow_possible_spam: false) @@ -1016,7 +1129,7 @@ describe Projects::IssuesController do expect { post_new_issue(title: '') }.not_to change(Issue, :count) end - it 'does not create an issue when recaptcha is not enabled' do + it 'does not create an issue when reCAPTCHA is not enabled' do stub_application_setting(recaptcha_enabled: false) expect { post_spam_issue }.not_to change(Issue, :count) @@ -1039,30 +1152,31 @@ describe Projects::IssuesController do end end - context 'when captcha is verified' do + context 'when Recaptcha is verified' do let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: 'Title') } + let!(:last_spam_log) { spam_logs.last } def post_verified_issue - post_new_issue({}, { spam_log_id: spam_logs.last.id, recaptcha_verification: true } ) + post_new_issue({}, { spam_log_id: last_spam_log.id, recaptcha_verification: true } ) end before do expect(controller).to receive_messages(verify_recaptcha: true) end - it 'accepts an issue after recaptcha is verified' do + it 'accepts an issue after reCAPTCHA is verified' do expect { post_verified_issue }.to change(Issue, :count) end it 'marks spam log as recaptcha_verified' do - expect { post_verified_issue }.to change { SpamLog.last.recaptcha_verified }.from(false).to(true) + expect { post_verified_issue }.to change { last_spam_log.reload.recaptcha_verified }.from(false).to(true) end 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 } ) } - .not_to change { SpamLog.last.recaptcha_verified } + .not_to change { last_spam_log.recaptcha_verified } end end end @@ -1294,6 +1408,7 @@ describe Projects::IssuesController do it 'render merge request as json' do create_merge_request + expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('merge_request') end @@ -1337,24 +1452,8 @@ describe Projects::IssuesController do let(:target_project) { fork_project(project, user, repository: true) } let(:target_project_id) { target_project.id } - context 'create_confidential_merge_request feature is enabled' do - before do - stub_feature_flags(create_confidential_merge_request: true) - end - - it 'creates a new merge request', :sidekiq_might_not_need_inline do - expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1) - end - end - - context 'create_confidential_merge_request feature is disabled' do - before do - stub_feature_flags(create_confidential_merge_request: false) - end - - it 'creates a new merge request' do - expect { create_merge_request }.to change(project.merge_requests, :count).by(1) - end + it 'creates a new merge request', :sidekiq_might_not_need_inline do + expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1) end end @@ -1513,61 +1612,6 @@ describe Projects::IssuesController do expect(note_json['author']['status_tooltip_html']).to be_present end - context 'is_gitlab_employee attribute' do - subject { get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } } - - before do - allow(Gitlab).to receive(:com?).and_return(true) - note_user = discussion.author - note_user.update(email: email) - note_user.confirm - end - - shared_examples 'non inclusion of gitlab employee badge' do - it 'does not render the is_gitlab_employee attribute' do - subject - - note_json = json_response.first['notes'].first - - expect(note_json['author']['is_gitlab_employee']).to be nil - end - end - - context 'when user is a gitlab employee' do - let(:email) { 'test@gitlab.com' } - - it 'renders the is_gitlab_employee attribute' do - subject - - note_json = json_response.first['notes'].first - - expect(note_json['author']['is_gitlab_employee']).to be true - end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(gitlab_employee_badge: false) - end - - it_behaves_like 'non inclusion of gitlab employee badge' - end - end - - context 'when user is not a gitlab employee' do - let(:email) { 'test@example.com' } - - it_behaves_like 'non inclusion of gitlab employee badge' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(gitlab_employee_badge: false) - end - - it_behaves_like 'non inclusion of gitlab employee badge' - end - end - end - it 'does not cause an extra query for the status' do control = ActiveRecord::QueryRecorder.new do get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } @@ -1660,6 +1704,33 @@ describe Projects::IssuesController do end end + describe 'GET #designs' do + context 'when project has moved' do + let(:new_project) { create(:project) } + let(:issue) { create(:issue, project: new_project) } + + before do + sign_in(user) + + project.route.destroy + new_project.redirect_routes.create!(path: project.full_path) + new_project.add_developer(user) + end + + it 'redirects from an old issue/designs correctly' do + get :designs, + params: { + namespace_id: project.namespace, + project_id: project, + id: issue + } + + expect(response).to redirect_to(designs_project_issue_path(new_project, issue)) + expect(response).to have_gitlab_http_status(:found) + end + end + end + context 'private project with token authentication' do let(:private_project) { create(:project, :private) } diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb index ea71dbe45aa..e86a42b03c8 100644 --- a/spec/controllers/projects/logs_controller_spec.rb +++ b/spec/controllers/projects/logs_controller_spec.rb @@ -16,16 +16,23 @@ describe Projects::LogsController do let(:container) { 'container-1' } before do - project.add_maintainer(user) - sign_in(user) end describe 'GET #index' do let(:empty_project) { create(:project) } + it 'returns 404 with developer access' do + project.add_developer(user) + + get :index, params: environment_params + + expect(response).to have_gitlab_http_status(:not_found) + end + it 'renders empty logs page if no environment exists' do empty_project.add_maintainer(user) + get :index, params: { namespace_id: empty_project.namespace, project_id: empty_project } expect(response).to be_ok @@ -33,6 +40,8 @@ describe Projects::LogsController do end it 'renders index template' do + project.add_maintainer(user) + get :index, params: environment_params expect(response).to be_ok @@ -50,7 +59,7 @@ describe Projects::LogsController do container_name: container } end - let(:service_result_json) { JSON.parse(service_result.to_json) } + let(:service_result_json) { Gitlab::Json.parse(service_result.to_json) } let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*', projects: [project]) } @@ -60,70 +69,84 @@ describe Projects::LogsController do end end - it 'returns the service result' do + it 'returns 404 with developer access' do + project.add_developer(user) + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:success) - expect(json_response).to eq(service_result_json) + expect(response).to have_gitlab_http_status(:not_found) end - it 'registers a usage of the endpoint' do - expect(::Gitlab::UsageCounters::PodLogs).to receive(:increment).with(project.id) + context 'with maintainer access' do + before do + project.add_maintainer(user) + end - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'returns the service result' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:success) - end + expect(response).to have_gitlab_http_status(:success) + expect(json_response).to eq(service_result_json) + end - it 'sets the polling header' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'registers a usage of the endpoint' do + expect(::Gitlab::UsageCounters::PodLogs).to receive(:increment).with(project.id) - expect(response).to have_gitlab_http_status(:success) - expect(response.headers['Poll-Interval']).to eq('3000') - end + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - context 'when service is processing' do - let(:service_result) { nil } + expect(response).to have_gitlab_http_status(:success) + end - it 'returns a 202' do + it 'sets the polling header' do get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:accepted) + expect(response).to have_gitlab_http_status(:success) + expect(response.headers['Poll-Interval']).to eq('3000') end - end - shared_examples 'unsuccessful execution response' do |message| - let(:service_result) do - { - status: :error, - message: message - } - end + context 'when service is processing' do + let(:service_result) { nil } - it 'returns the error' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'returns a 202' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to eq(service_result_json) + expect(response).to have_gitlab_http_status(:accepted) + end end - end - context 'when service is failing' do - it_behaves_like 'unsuccessful execution response', 'some error' - end + shared_examples 'unsuccessful execution response' do |message| + let(:service_result) do + { + status: :error, + message: message + } + end - context 'when cluster is nil' do - let!(:cluster) { nil } + it 'returns the error' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' - end + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq(service_result_json) + end + end - context 'when namespace is empty' do - before do - allow(environment).to receive(:deployment_namespace).and_return('') + context 'when service is failing' do + it_behaves_like 'unsuccessful execution response', 'some error' + end + + context 'when cluster is nil' do + let!(:cluster) { nil } + + it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' end - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' + context 'when namespace is empty' do + before do + allow(environment).to receive(:deployment_namespace).and_return('') + end + + it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' + end end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index aaeaf53d100..7d9e42fcc2d 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -935,34 +935,6 @@ describe Projects::MergeRequestsController do }]) end end - - context 'when feature flag :ci_expose_arbitrary_artifacts_in_mr is disabled' do - let(:job_options) do - { - artifacts: { - paths: ['ci_artifacts.txt'], - expose_as: 'Exposed artifact' - } - } - end - let(:report) { double } - - before do - stub_feature_flags(ci_expose_arbitrary_artifacts_in_mr: false) - end - - it 'does not send polling interval' do - expect(Gitlab::PollingInterval).not_to receive(:set_header) - - subject - end - - it 'returns 204 HTTP status' do - subject - - expect(response).to have_gitlab_http_status(:no_content) - end - end end context 'when pipeline does not have jobs with exposed artifacts' do @@ -1114,6 +1086,150 @@ describe Projects::MergeRequestsController do end end + describe 'GET terraform_reports' do + let(:merge_request) do + create(:merge_request, + :with_merge_request_pipeline, + target_project: project, + source_project: project) + end + + let(:pipeline) do + create(:ci_pipeline, + :success, + :with_terraform_reports, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + before do + allow_any_instance_of(MergeRequest) + .to receive(:find_terraform_reports) + .and_return(report) + + allow_any_instance_of(MergeRequest) + .to receive(:actual_head_pipeline) + .and_return(pipeline) + end + + subject do + get :terraform_reports, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, + format: :json + end + + describe 'permissions on a public project with private CI/CD' do + let(:project) { create :project, :repository, :public, :builds_private } + let(:report) { { status: :parsed, data: [] } } + + context 'while signed out' do + before do + sign_out(user) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + + context 'while signed in as an unrelated user' do + before do + sign_in(create(:user)) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + end + + context 'when pipeline has jobs with terraform reports' do + before do + allow_next_instance_of(MergeRequest) do |merge_request| + allow(merge_request).to receive(:has_terraform_reports?).and_return(true) + end + end + + context 'when processing terraform reports is in progress' do + let(:report) { { status: :parsing } } + + it 'sends polling interval' do + expect(Gitlab::PollingInterval).to receive(:set_header) + + subject + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when processing terraform reports is completed' do + let(:report) { { status: :parsed, data: pipeline.terraform_reports.plans } } + + it 'returns terraform reports' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to match( + a_hash_including( + 'tfplan.json' => hash_including( + 'create' => 0, + 'delete' => 0, + 'update' => 1 + ) + ) + ) + end + end + + context 'when user created corrupted terraform reports' do + let(:report) { { status: :error, status_reason: 'Failed to parse terraform reports' } } + + it 'does not send polling interval' do + expect(Gitlab::PollingInterval).not_to receive(:set_header) + + subject + end + + it 'returns 400 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq({ 'status_reason' => 'Failed to parse terraform reports' }) + end + end + end + + context 'when pipeline does not have jobs with terraform reports' do + before do + allow_next_instance_of(MergeRequest) do |merge_request| + allow(merge_request).to receive(:has_terraform_reports?).and_return(false) + end + end + + let(:report) { { status: :error } } + + it 'returns error' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + end + describe 'GET test_reports' do let(:merge_request) do create(:merge_request, @@ -1225,6 +1341,141 @@ describe Projects::MergeRequestsController do end end + describe 'GET accessibility_reports' do + let(:merge_request) do + create(:merge_request, + :with_diffs, + :with_merge_request_pipeline, + target_project: project, + source_project: project + ) + end + + let(:pipeline) do + create(:ci_pipeline, + :success, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + before do + allow_any_instance_of(MergeRequest) + .to receive(:compare_accessibility_reports) + .and_return(accessibility_comparison) + + allow_any_instance_of(MergeRequest) + .to receive(:actual_head_pipeline) + .and_return(pipeline) + end + + subject do + get :accessibility_reports, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, + format: :json + end + + context 'permissions on a public project with private CI/CD' do + let(:project) { create(:project, :repository, :public, :builds_private) } + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + context 'while signed out' do + before do + sign_out(user) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + + context 'while signed in as an unrelated user' do + before do + sign_in(create(:user)) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + end + + context 'when feature flag is disabled' do + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + before do + stub_feature_flags(accessibility_report_view: false) + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when pipeline has jobs with accessibility reports' do + before do + allow_any_instance_of(MergeRequest) + .to receive(:has_accessibility_reports?) + .and_return(true) + end + + context 'when processing accessibility reports is in progress' do + let(:accessibility_comparison) { { status: :parsing } } + + it 'sends polling interval' do + expect(Gitlab::PollingInterval).to receive(:set_header) + + subject + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when processing accessibility reports is completed' do + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + it 'returns accessibility reports' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq({ 'summary' => 1 }) + end + end + + context 'when user created corrupted accessibility reports' do + let(:accessibility_comparison) { { status: :error, status_reason: 'This merge request does not have accessibility reports' } } + + it 'does not send polling interval' do + expect(Gitlab::PollingInterval).not_to receive(:set_header) + + subject + end + + it 'returns 400 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq({ 'status_reason' => 'This merge request does not have accessibility reports' }) + end + end + end + end + describe 'POST remove_wip' do before do merge_request.title = merge_request.wip_title diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb index faeade0d737..8cd940978c0 100644 --- a/spec/controllers/projects/mirrors_controller_spec.rb +++ b/spec/controllers/projects/mirrors_controller_spec.rb @@ -189,7 +189,7 @@ describe Projects::MirrorsController do context 'no data in cache' do it 'requests the cache to be filled and returns a 204 response' do - expect(ReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once) + expect(ExternalServiceReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once) do_get(project) diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9d243bf5a7f..b3d8fb94fb3 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -145,11 +145,81 @@ describe Projects::PipelinesController do end end - def get_pipelines_index_json + context 'filter by scope' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'running') + + check_pipeline_response(returned: 2, all: 6, running: 2, pending: 1, finished: 3) + end + + context 'scope is branches or tags' do + before do + create(:ci_pipeline, :failed, project: project, ref: 'v1.0.0', tag: true) + end + + context 'when scope is branches' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'branches') + + check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4) + end + end + + context 'when scope is tags' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'tags') + + check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4) + end + end + end + end + + context 'filter by username' do + let!(:pipeline) { create(:ci_pipeline, :running, project: project, user: user) } + + context 'when username exists' do + it 'returns matched pipelines' do + get_pipelines_index_json(username: user.username) + + check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0) + end + end + + context 'when username does not exist' do + it 'returns empty' do + get_pipelines_index_json(username: 'invalid-username') + + check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0) + end + end + end + + context 'filter by ref' do + let!(:pipeline) { create(:ci_pipeline, :running, project: project, ref: 'branch-1') } + + context 'when pipelines with the ref exists' do + it 'returns matched pipelines' do + get_pipelines_index_json(ref: 'branch-1') + + check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0) + end + end + + context 'when no pipeline with the ref exists' do + it 'returns empty list' do + get_pipelines_index_json(ref: 'invalid-ref') + + check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0) + end + end + end + + def get_pipelines_index_json(params = {}) get :index, params: { namespace_id: project.namespace, project_id: project - }, + }.merge(params), format: :json end @@ -199,6 +269,18 @@ describe Projects::PipelinesController do user: user ) end + + def check_pipeline_response(returned:, all:, running:, pending:, finished:) + aggregate_failures do + expect(response).to match_response_schema('pipeline') + + expect(json_response['pipelines'].count).to eq returned + expect(json_response['count']['all'].to_i).to eq all + expect(json_response['count']['running'].to_i).to eq running + expect(json_response['count']['pending'].to_i).to eq pending + expect(json_response['count']['finished'].to_i).to eq finished + end + end end describe 'GET show.json' do @@ -748,12 +830,10 @@ describe Projects::PipelinesController do context 'when feature is enabled' do before do - stub_feature_flags(junit_pipeline_view: true) + stub_feature_flags(junit_pipeline_view: project) end context 'when pipeline does not have a test report' do - let(:pipeline) { create(:ci_pipeline, project: project) } - it 'renders an empty test report' do get_test_report_json @@ -763,7 +843,11 @@ describe Projects::PipelinesController do end context 'when pipeline has a test report' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } + before do + create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| + create(:ci_job_artifact, :junit, job: build) + end + end it 'renders the test report' do get_test_report_json @@ -773,25 +857,28 @@ describe Projects::PipelinesController do end end - context 'when pipeline has corrupt test reports' do - let(:pipeline) { create(:ci_pipeline, project: project) } - + context 'when pipeline has a corrupt test report artifact' do before do - job = create(:ci_build, pipeline: pipeline) - create(:ci_job_artifact, :junit_with_corrupted_data, job: job, project: project) - end + create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| + create(:ci_job_artifact, :junit_with_corrupted_data, job: build) + end - it 'renders the test reports' do get_test_report_json + end + it 'renders the test reports' do expect(response).to have_gitlab_http_status(:ok) - expect(json_response['status']).to eq('error_parsing_report') + expect(json_response['test_suites'].count).to eq(1) + end + + it 'returns a suite_error on the suite with corrupted XML' do + expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') end end context 'when junit_pipeline_screenshots_view is enabled' do before do - stub_feature_flags(junit_pipeline_screenshots_view: { enabled: true, thing: project }) + stub_feature_flags(junit_pipeline_screenshots_view: project) end context 'when test_report contains attachment and scope is with_attachment as a URL param' do @@ -820,7 +907,7 @@ describe Projects::PipelinesController do context 'when junit_pipeline_screenshots_view is disabled' do before do - stub_feature_flags(junit_pipeline_screenshots_view: { enabled: false, thing: project }) + stub_feature_flags(junit_pipeline_screenshots_view: false) end context 'when test_report contains attachment and scope is with_attachment as a URL param' do diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb index 451834e0962..e936cb5916e 100644 --- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb +++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb @@ -352,7 +352,7 @@ describe Projects::Prometheus::AlertsController do get :metrics_dashboard, params: request_params(id: metric.id, environment_id: alert.environment.id), format: :json expect(response).to have_gitlab_http_status(:ok) - expect(json_response.keys).to contain_exactly('dashboard', 'status') + expect(json_response.keys).to contain_exactly('dashboard', 'status', 'metrics_data') end it 'is the correct embed' do diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index 646c7a7db7c..b043e7f2538 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -12,25 +12,27 @@ describe Projects::RefsController do end describe 'GET #logs_tree' do + let(:path) { 'foo/bar/baz.html' } + def default_get(format = :html) get :logs_tree, params: { namespace_id: project.namespace.to_param, project_id: project, id: 'master', - path: 'foo/bar/baz.html' + path: path }, format: format end - def xhr_get(format = :html) + def xhr_get(format = :html, params = {}) get :logs_tree, params: { namespace_id: project.namespace.to_param, project_id: project, id: 'master', - path: 'foo/bar/baz.html', + path: path, format: format - }, xhr: true + }.merge(params), xhr: true end it 'never throws MissingTemplate' do @@ -52,13 +54,27 @@ describe Projects::RefsController do expect(response).to be_successful end - it 'renders JSON' do - expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original + context 'when json is requested' do + it 'renders JSON' do + expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original - xhr_get(:json) + xhr_get(:json) - expect(response).to be_successful - expect(json_response).to be_kind_of(Array) + expect(response).to be_successful + expect(json_response).to be_kind_of(Array) + end + + it 'caches tree summary data', :use_clean_rails_memory_store_caching do + expect_next_instance_of(::Gitlab::TreeSummary) do |instance| + expect(instance).to receive_messages(summarize: ['logs'], next_offset: 50, more?: true) + end + + xhr_get(:json, offset: 25) + + cache_key = "projects/#{project.id}/logs/#{project.commit.id}/#{path}/25" + expect(Rails.cache.fetch(cache_key)).to eq(['logs', 50]) + expect(response.headers['More-Logs-Offset']).to eq(50) + end end end end diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index c641a45a216..badb84f9b50 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Projects::Registry::RepositoriesController do - let(:user) { create(:user) } - let(:project) { create(:project, :private) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :private) } before do sign_in(user) @@ -16,6 +16,22 @@ describe Projects::Registry::RepositoriesController do project.add_developer(user) end + shared_examples 'with name parameter' do + let_it_be(:repo) { create(:container_repository, project: project, name: 'my_searched_image') } + let_it_be(:another_repo) { create(:container_repository, project: project, name: 'bar') } + + it 'returns the searched repo' do + go_to_index(format: :json, params: { name: 'my_searched_image' }) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.length).to eq 1 + expect(json_response.first).to include( + 'id' => repo.id, + 'name' => repo.name + ) + end + end + shared_examples 'renders a list of repositories' do context 'when root container repository exists' do before do @@ -60,6 +76,8 @@ describe Projects::Registry::RepositoriesController do expect(response).to match_response_schema('registry/repositories') expect(response).to include_pagination_headers end + + it_behaves_like 'with name parameter' end context 'when there are no tags for this repository' do @@ -138,11 +156,11 @@ describe Projects::Registry::RepositoriesController do end end - def go_to_index(format: :html) - get :index, params: { + def go_to_index(format: :html, params: {} ) + get :index, params: params.merge({ namespace_id: project.namespace, project_id: project - }, + }), format: format end diff --git a/spec/controllers/projects/service_hook_logs_controller_spec.rb b/spec/controllers/projects/service_hook_logs_controller_spec.rb index ca57b0579a8..a5130cd6e32 100644 --- a/spec/controllers/projects/service_hook_logs_controller_spec.rb +++ b/spec/controllers/projects/service_hook_logs_controller_spec.rb @@ -24,7 +24,7 @@ describe Projects::ServiceHookLogsController do describe 'GET #show' do subject { get :show, params: log_params } - it do + specify do expect(response).to be_successful end end diff --git a/spec/controllers/projects/settings/access_tokens_controller_spec.rb b/spec/controllers/projects/settings/access_tokens_controller_spec.rb new file mode 100644 index 00000000000..884a5bc2836 --- /dev/null +++ b/spec/controllers/projects/settings/access_tokens_controller_spec.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +require('spec_helper') + +describe Projects::Settings::AccessTokensController do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + before_all do + project.add_maintainer(user) + end + + before do + sign_in(user) + end + + shared_examples 'feature unavailability' do + context 'when flag is disabled' do + before do + stub_feature_flags(resource_access_token: false) + end + + it { is_expected.to have_gitlab_http_status(:not_found) } + end + + context 'when environment is Gitlab.com' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it { is_expected.to have_gitlab_http_status(:not_found) } + end + end + + describe '#index' do + subject { get :index, params: { namespace_id: project.namespace, project_id: project } } + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + let_it_be(:bot_user) { create(:user, :project_bot) } + let_it_be(:active_project_access_token) { create(:personal_access_token, user: bot_user) } + let_it_be(:inactive_project_access_token) { create(:personal_access_token, :revoked, user: bot_user) } + + before_all do + project.add_maintainer(bot_user) + end + + before do + enable_feature + end + + it 'retrieves active project access tokens' do + subject + + expect(assigns(:active_project_access_tokens)).to contain_exactly(active_project_access_token) + end + + it 'retrieves inactive project access tokens' do + subject + + expect(assigns(:inactive_project_access_tokens)).to contain_exactly(inactive_project_access_token) + end + + it 'lists all available scopes' do + subject + + expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes) + end + + it 'retrieves newly created personal access token value' do + token_value = 'random-value' + allow(PersonalAccessToken).to receive(:redis_getdel).with("#{user.id}:#{project.id}").and_return(token_value) + + subject + + expect(assigns(:new_project_access_token)).to eq(token_value) + end + end + end + + describe '#create', :clean_gitlab_redis_shared_state do + subject { post :create, params: { namespace_id: project.namespace, project_id: project }.merge(project_access_token: access_token_params) } + + let_it_be(:access_token_params) { {} } + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + let_it_be(:access_token_params) { { name: 'Nerd bot', scopes: ["api"], expires_at: 1.month.since.to_date } } + + before do + enable_feature + end + + def created_token + PersonalAccessToken.order(:created_at).last + end + + it 'returns success message' do + subject + + expect(response.flash[:notice]).to match(/\AYour new project access token has been created./i) + end + + it 'creates project access token' do + subject + + expect(created_token.name).to eq(access_token_params[:name]) + expect(created_token.scopes).to eq(access_token_params[:scopes]) + expect(created_token.expires_at).to eq(access_token_params[:expires_at]) + end + + it 'creates project bot user' do + subject + + expect(created_token.user).to be_project_bot + end + + it 'stores newly created token redis store' do + expect(PersonalAccessToken).to receive(:redis_store!) + + subject + end + + it { expect { subject }.to change { User.count }.by(1) } + it { expect { subject }.to change { PersonalAccessToken.count }.by(1) } + + context 'when unsuccessful' do + before do + allow_next_instance_of(ResourceAccessTokens::CreateService) do |service| + allow(service).to receive(:execute).and_return ServiceResponse.error(message: 'Failed!') + end + end + + it { expect(subject).to render_template(:index) } + end + end + end + + describe '#revoke' do + subject { put :revoke, params: { namespace_id: project.namespace, project_id: project, id: project_access_token } } + + let_it_be(:bot_user) { create(:user, :project_bot) } + let_it_be(:project_access_token) { create(:personal_access_token, user: bot_user) } + + before_all do + project.add_maintainer(bot_user) + end + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + before do + enable_feature + end + + it 'revokes token access' do + subject + + expect(project_access_token.reload.revoked?).to be true + end + + it 'removed membership of bot user' do + subject + + expect(project.reload.bots).not_to include(bot_user) + end + + it 'blocks project bot user' do + subject + + expect(bot_user.reload.blocked?).to be true + end + + it 'converts issuables of the bot user to ghost user' do + issue = create(:issue, author: bot_user) + + subject + + expect(issue.reload.author.ghost?).to be true + end + end + end + + def enable_feature + allow(Gitlab).to receive(:com?).and_return(false) + stub_feature_flags(resource_access_token: true) + end +end diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 847c80e8917..fb9cdd860dc 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::Settings::RepositoryController do describe 'POST create_deploy_token' do context 'when ajax_new_deploy_token feature flag is disabled for the project' do before do - stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project }) + stub_feature_flags(ajax_new_deploy_token: false) end it_behaves_like 'a created deploy token' do @@ -73,7 +73,7 @@ describe Projects::Settings::RepositoryController do 'id' => be_a(Integer), 'name' => deploy_token_params[:name], 'username' => deploy_token_params[:username], - 'expires_at' => Time.parse(deploy_token_params[:expires_at]), + 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), 'token' => be_a(String), 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 284789305e2..b5f4929d8ce 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -127,7 +127,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Title', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :new with recaptcha disabled' do + it 'renders :new with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) create_snippet(project, visibility_level: Snippet::PUBLIC) @@ -135,18 +135,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:new) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify with reCAPTCHA enabled' do create_snippet(project, visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -223,7 +223,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo') @@ -231,18 +231,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:edit) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify with reCAPTCHA enabled' do update_snippet(title: 'Foo') expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -268,7 +268,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) @@ -276,18 +276,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:edit) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify' do update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -346,20 +346,6 @@ describe Projects::SnippetsController do expect(assigns(:blob)).to eq(project_snippet.blobs.first) end - - context 'when feature flag version_snippets is disabled' do - before do - stub_feature_flags(version_snippets: false) - end - - it 'returns the snippet database content' do - subject - - blob = assigns(:blob) - - expect(blob.data).to eq(project_snippet.content) - end - end end %w[show raw].each do |action| diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb index f7c8848b8cf..7b470254de1 100644 --- a/spec/controllers/projects/static_site_editor_controller_spec.rb +++ b/spec/controllers/projects/static_site_editor_controller_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe Projects::StaticSiteEditorController do - let(:project) { create(:project, :public, :repository) } + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } describe 'GET show' do let(:default_params) do @@ -27,8 +28,6 @@ describe Projects::StaticSiteEditorController do end context 'as guest' do - let(:user) { create(:user) } - before do project.add_guest(user) sign_in(user) @@ -42,10 +41,11 @@ describe Projects::StaticSiteEditorController do %w[developer maintainer].each do |role| context "as #{role}" do - let(:user) { create(:user) } + before_all do + project.add_role(user, role) + end before do - project.add_role(user, role) sign_in(user) get :show, params: default_params end @@ -54,8 +54,10 @@ describe Projects::StaticSiteEditorController do expect(response).to render_template(:show) end - it 'assigns a config variable' do + it 'assigns a required variables' do expect(assigns(:config)).to be_a(Gitlab::StaticSiteEditor::Config) + expect(assigns(:ref)).to eq('master') + expect(assigns(:path)).to eq('README.md') end context 'when combination of ref and file path is incorrect' do diff --git a/spec/controllers/projects/usage_ping_controller_spec.rb b/spec/controllers/projects/usage_ping_controller_spec.rb index 284db93d7a8..a68967c228f 100644 --- a/spec/controllers/projects/usage_ping_controller_spec.rb +++ b/spec/controllers/projects/usage_ping_controller_spec.rb @@ -6,45 +6,52 @@ describe Projects::UsagePingController do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } - describe 'POST #web_ide_clientside_preview' do - subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } } + before do + sign_in(user) if user + end - before do - sign_in(user) if user - end + shared_examples 'counter is not increased' do + context 'when the user is not authenticated' do + let(:user) { nil } - context 'when web ide clientside preview is enabled' do - before do - stub_application_setting(web_ide_clientside_preview_enabled: true) - end + it 'returns 302' do + subject - context 'when the user is not authenticated' do - let(:user) { nil } + expect(response).to have_gitlab_http_status(:found) + end + end - it 'returns 302' do - subject + context 'when the user does not have access to the project' do + it 'returns 404' do + subject - expect(response).to have_gitlab_http_status(:found) - end + expect(response).to have_gitlab_http_status(:not_found) end + end + end - context 'when the user does not have access to the project' do - it 'returns 404' do - subject + shared_examples 'counter is increased' do |counter| + context 'when the authenticated user has access to the project' do + let(:user) { project.owner } - expect(response).to have_gitlab_http_status(:not_found) - end + it 'increments the usage counter' do + expect do + subject + end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_count(counter) }.by(1) end + end + end - context 'when the user has access to the project' do - let(:user) { project.owner } + describe 'POST #web_ide_clientside_preview' do + subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } } - it 'increments the counter' do - expect do - subject - end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_previews_count }.by(1) - end + context 'when web ide clientside preview is enabled' do + before do + stub_application_setting(web_ide_clientside_preview_enabled: true) end + + it_behaves_like 'counter is not increased' + it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_COUNT' end context 'when web ide clientside preview is not enabled' do @@ -61,4 +68,11 @@ describe Projects::UsagePingController do end end end + + describe 'POST #web_ide_pipelines_count' do + subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } } + + it_behaves_like 'counter is not increased' + it_behaves_like 'counter is increased', 'WEB_IDE_PIPELINES_COUNT' + end end diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb index 99d14298cd1..b4bbf76ce18 100644 --- a/spec/controllers/projects/wikis_controller_spec.rb +++ b/spec/controllers/projects/wikis_controller_spec.rb @@ -98,13 +98,12 @@ describe Projects::WikisController do let(:id) { wiki_title } it 'limits the retrieved pages for the sidebar' do - expect(controller).to receive(:load_wiki).and_return(project_wiki) - expect(project_wiki).to receive(:list_pages).with(limit: 15).and_call_original - subject expect(response).to have_gitlab_http_status(:ok) 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) end context 'when page content encoding is invalid' do @@ -200,7 +199,20 @@ describe Projects::WikisController do subject - expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first)) + expect(response).to redirect_to_wiki(project, project_wiki.list_pages.first) + end + end + + context 'when the page has nil content' do + let(:page) { create(:wiki_page) } + + it 'redirects to show' do + allow(page).to receive(:content).and_return(nil) + allow(controller).to receive(:find_page).and_return(page) + + subject + + expect(response).to redirect_to_wiki(project, page) end end @@ -235,7 +247,7 @@ describe Projects::WikisController do allow(controller).to receive(:valid_encoding?).and_return(false) subject - expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first)) + expect(response).to redirect_to_wiki(project, project_wiki.list_pages.first) end end @@ -265,4 +277,8 @@ describe Projects::WikisController do page = wiki.page(title: title, dir: dir) project_wiki.delete_page(page, "test commit") end + + def redirect_to_wiki(project, page) + redirect_to(controller.project_wiki_path(project, page)) + end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index fc3efc8e805..6c00dad8bb7 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -1020,6 +1020,32 @@ describe ProjectsController do expect(json_response['body']).to include(expanded_path) end end + + context 'when path and ref parameters are provided' do + let(:project_with_repo) { create(:project, :repository) } + let(:preview_markdown_params) do + { + namespace_id: project_with_repo.namespace, + id: project_with_repo, + text: "![](./logo-white.png)\n", + ref: 'other_branch', + path: 'files/images/README.md' + } + end + + before do + project_with_repo.add_maintainer(user) + project_with_repo.repository.create_branch('other_branch') + end + + it 'renders JSON body with image links expanded' do + expanded_path = "/#{project_with_repo.full_path}/-/raw/other_branch/files/images/logo-white.png" + + post :preview_markdown, params: preview_markdown_params + + expect(json_response['body']).to include(expanded_path) + end + end end describe '#ensure_canonical_path' do diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 0b4ecb68cf7..01a9647a763 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -139,21 +139,11 @@ describe RegistrationsController do expect(flash[:alert]).to eq(_('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')) end - it 'redirects to the dashboard when the recaptcha is solved' do + it 'redirects to the dashboard when the reCAPTCHA is solved' do post(:create, params: user_params) expect(flash[:notice]).to eq(I18n.t('devise.registrations.signed_up')) end - - it 'does not require reCAPTCHA if disabled by feature flag' do - stub_feature_flags(registrations_recaptcha: false) - - post(:create, params: user_params) - - expect(controller).not_to receive(:verify_recaptcha) - expect(flash[:alert]).to be_nil - expect(flash[:notice]).to eq(I18n.t('devise.registrations.signed_up')) - end end context 'when invisible captcha is enabled' do @@ -294,8 +284,6 @@ describe RegistrationsController do end it "logs a 'User Created' message" do - stub_feature_flags(registrations_recaptcha: false) - expect(Gitlab::AppLogger).to receive(:info).with(/\AUser Created: username=new_username email=new@user.com.+\z/).and_call_original post(:create, params: user_params) @@ -419,24 +407,34 @@ describe RegistrationsController do describe '#welcome' do subject { get :welcome } - before do - sign_in(create(:user)) - end - context 'signup_flow experiment enabled' do before do stub_experiment_for_user(signup_flow: true) end it 'renders the devise_experimental_separate_sign_up_flow layout' do + sign_in(create(:user)) + expected_layout = Gitlab.ee? ? :checkout : :devise_experimental_separate_sign_up_flow expect(subject).to render_template(expected_layout) end + + context '2FA is required from group' do + before do + user = create(:user, require_two_factor_authentication_from_group: true) + sign_in(user) + end + + it 'does not perform a redirect' do + expect(subject).not_to redirect_to(profile_two_factor_auth_path) + end + end end context 'signup_flow experiment disabled' do before do + sign_in(create(:user)) stub_experiment_for_user(signup_flow: false) end diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb index 59455d90c25..1a2eee5d3a9 100644 --- a/spec/controllers/repositories/git_http_controller_spec.rb +++ b/spec/controllers/repositories/git_http_controller_spec.rb @@ -165,48 +165,11 @@ describe Repositories::GitHttpController do end end - shared_examples 'snippet feature flag disabled behavior' do - before do - stub_feature_flags(version_snippets: false) - - request.headers.merge! auth_env(user.username, user.password, nil) - end - - describe 'GET #info_refs' do - let(:params) { container_params.merge(service: 'git-upload-pack') } - - it 'returns 403' do - expect(controller).not_to receive(:access_check) - - get :info_refs, params: params - - expect(response).to have_gitlab_http_status(:forbidden) - expect(response.body).to eq 'Snippet git access is disabled.' - end - end - - describe 'POST #git_upload_pack' do - before do - allow(controller).to receive(:authenticate_user).and_return(true) - allow(controller).to receive(:verify_workhorse_api!).and_return(true) - allow(controller).to receive(:access_check).and_return(nil) - end - - it 'returns 403' do - expect(controller).not_to receive(:access_check) - - post :git_upload_pack, params: params - - expect(response).to have_gitlab_http_status(:forbidden) - expect(response.body).to eq 'Snippet git access is disabled.' - end - end - end - context 'when repository container is a project' do it_behaves_like 'info_refs behavior' do let(:user) { project.owner } end + it_behaves_like 'git_upload_pack behavior', true it_behaves_like 'access checker class' do let(:expected_class) { Gitlab::GitAccess } @@ -221,14 +184,12 @@ describe Repositories::GitHttpController do it_behaves_like 'info_refs behavior' do let(:user) { personal_snippet.author } end + it_behaves_like 'git_upload_pack behavior', false it_behaves_like 'access checker class' do let(:expected_class) { Gitlab::GitAccessSnippet } let(:expected_object) { personal_snippet } end - it_behaves_like 'snippet feature flag disabled behavior' do - let(:user) { personal_snippet.author } - end end context 'when repository container is a project snippet' do @@ -238,13 +199,11 @@ describe Repositories::GitHttpController do it_behaves_like 'info_refs behavior' do let(:user) { project_snippet.author } end + it_behaves_like 'git_upload_pack behavior', false it_behaves_like 'access checker class' do let(:expected_class) { Gitlab::GitAccessSnippet } let(:expected_object) { project_snippet } end - it_behaves_like 'snippet feature flag disabled behavior' do - let(:user) { project_snippet.author } - end end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 1fe313452fe..79ffa297da3 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -84,7 +84,7 @@ describe SearchController do with_them do it do project_wiki = create(:project_wiki, project: project, user: user) - create(:wiki_page, wiki: project_wiki, attrs: { title: 'merge', content: 'merge' }) + create(:wiki_page, wiki: project_wiki, title: 'merge', content: 'merge') expect(subject).to render_template("search/results/#{partial}") end @@ -140,14 +140,6 @@ describe SearchController do end end - context 'snippet search' do - it 'forces title search' do - get :show, params: { scope: 'snippet_blobs', snippets: 'true', search: 'foo' } - - expect(assigns[:scope]).to eq('snippet_titles') - end - end - it 'finds issue comments' do project = create(:project, :public) note = create(:note_on_issue, project: project) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index af2e452c0ca..a65698a5b56 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -41,10 +41,10 @@ describe SessionsController do stub_ldap_setting(enabled: true) end - it 'assigns ldap_servers' do + it 'ldap_servers available in helper' do get(:new) - expect(assigns[:ldap_servers].first.to_h).to include('label' => 'ldap', 'provider_name' => 'ldapmain') + expect(subject.ldap_servers.first.to_h).to include('label' => 'ldap', 'provider_name' => 'ldapmain') end context 'with sign_in disabled' do @@ -52,10 +52,10 @@ describe SessionsController do stub_ldap_setting(prevent_ldap_sign_in: true) end - it 'assigns no ldap_servers' do + it 'no ldap_servers available in helper' do get(:new) - expect(assigns[:ldap_servers]).to eq [] + expect(subject.ldap_servers).to eq [] end end end @@ -99,6 +99,11 @@ describe SessionsController do set_devise_mapping(context: @request) end + it_behaves_like 'known sign in' do + let(:user) { create(:user) } + let(:post_action) { post(:create, params: { user: { login: user.username, password: user.password } }) } + end + context 'when using standard authentications' do context 'invalid password' do it 'does not authenticate user' do diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 05c48fb190c..046ee40cec2 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -86,20 +86,6 @@ describe SnippetsController do expect(assigns(:blob)).to eq(personal_snippet.blobs.first) end - - context 'when feature flag version_snippets is disabled' do - before do - stub_feature_flags(version_snippets: false) - end - - it 'returns the snippet database content' do - subject - - blob = assigns(:blob) - - expect(blob.data).to eq(personal_snippet.content) - end - end end context 'when the personal snippet is private' do @@ -257,39 +243,13 @@ describe SnippetsController do end end - context 'when the snippet description contains a file' do - include FileMoverHelpers - - let(:picture_secret) { SecureRandom.hex } - let(:text_secret) { SecureRandom.hex } - let(:picture_file) { "/-/system/user/#{user.id}/#{picture_secret}/picture.jpg" } - let(:text_file) { "/-/system/user/#{user.id}/#{text_secret}/text.txt" } - let(:description) do - "Description with picture: ![picture](/uploads#{picture_file}) and "\ - "text: [text.txt](/uploads#{text_file})" - end - - before do - allow(FileUtils).to receive(:mkdir_p) - allow(FileUtils).to receive(:move) - stub_file_mover(text_file) - stub_file_mover(picture_file) - end - - subject { create_snippet({ description: description }, { files: [picture_file, text_file] }) } - - it 'creates the snippet' do - expect { subject }.to change { Snippet.count }.by(1) - end - - it 'stores the snippet description correctly' do - snippet = subject + context 'when the controller receives the files param' do + let(:files) { %w(foo bar) } - expected_description = "Description with picture: "\ - "![picture](/uploads/-/system/personal_snippet/#{snippet.id}/#{picture_secret}/picture.jpg) and "\ - "text: [text.txt](/uploads/-/system/personal_snippet/#{snippet.id}/#{text_secret}/text.txt)" + it 'passes the files param to the snippet create service' do + expect(Snippets::CreateService).to receive(:new).with(nil, user, hash_including(files: files)).and_call_original - expect(snippet.description).to eq(expected_description) + create_snippet({ title: nil }, { files: files }) end end @@ -318,7 +278,7 @@ describe SnippetsController do .to log_spam(title: 'Title', user: user, noteable_type: 'PersonalSnippet') end - it 'renders :new with recaptcha disabled' do + it 'renders :new with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) create_snippet(visibility_level: Snippet::PUBLIC) @@ -326,18 +286,18 @@ describe SnippetsController do expect(response).to render_template(:new) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify' do create_snippet(visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -403,7 +363,7 @@ describe SnippetsController do .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) @@ -411,18 +371,18 @@ describe SnippetsController do expect(response).to render_template(:edit) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify' do update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -446,7 +406,7 @@ describe SnippetsController do .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo') @@ -459,13 +419,13 @@ describe SnippetsController do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify' do update_snippet(title: 'Foo') expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -572,24 +532,6 @@ describe SnippetsController do expect(response.cache_control[:public]).to eq snippet.public? end - context 'when feature flag version_snippets is disabled' do - before do - stub_feature_flags(version_snippets: false) - end - - it_behaves_like '200 status' - it_behaves_like 'CRLF line ending' - - it 'returns snippet database content' do - subject - - expect(response.body).to eq snippet.content - expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') - end - - it_behaves_like 'content disposition headers' - end - context 'when snippet repository is empty' do before do allow_any_instance_of(Repository).to receive(:empty?).and_return(true) |