diff options
Diffstat (limited to 'spec')
30 files changed, 884 insertions, 155 deletions
diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index 1d844c847d6..54c2397625f 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::AvatarsController do - let(:project) { create(:project, :repository) } + let_it_be(:project) { create(:project, :repository) } before do controller.instance_variable_set(:@project, project) @@ -34,15 +34,18 @@ describe Projects::AvatarsController do expect(response).to have_gitlab_http_status(:ok) expect(response.header['Content-Disposition']).to eq('inline') expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') - expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' end + + it_behaves_like 'project cache control headers' end context 'when the avatar is stored in lfs' do - it_behaves_like 'a controller that can serve LFS files' do - let(:filename) { 'lfs_object.iso' } - let(:filepath) { "files/lfs/#{filename}" } - end + let(:filename) { 'lfs_object.iso' } + let(:filepath) { "files/lfs/#{filename}" } + + it_behaves_like 'a controller that can serve LFS files' + it_behaves_like 'project cache control headers' end end end diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb index 9d68104b755..3a29c3d4093 100644 --- a/spec/controllers/projects/import/jira_controller_spec.rb +++ b/spec/controllers/projects/import/jira_controller_spec.rb @@ -118,10 +118,9 @@ describe Projects::Import::JiraController do end it 'uses the existing import data' do - expect(controller).not_to receive(:schedule_import) - post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' } + expect(flash[:notice]).to eq('Jira import is already running.') expect(response).to redirect_to(project_import_jira_path(project)) end end @@ -153,8 +152,6 @@ describe Projects::Import::JiraController do end it 'uses the existing import data' do - expect(controller).to receive(:schedule_import).and_call_original - post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' } project.reload diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index add7778b57a..094b50322d1 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1377,7 +1377,7 @@ describe Projects::IssuesController do it 'returns discussion json' do get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } - expect(json_response.first.keys).to match_array(%w[id reply_id expanded notes diff_discussion discussion_path individual_note resolvable resolved resolved_at resolved_by resolved_by_push commit_id for_commit project_id]) + expect(json_response.first.keys).to match_array(%w[id reply_id expanded notes diff_discussion discussion_path individual_note resolvable resolved resolved_at resolved_by resolved_by_push commit_id for_commit project_id confidential]) end it 'renders the author status html if there is a status' do diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index 8cb48dca095..4a684dcfbc6 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -6,6 +6,7 @@ describe Projects::RawController do include RepoHelpers let(:project) { create(:project, :public, :repository) } + let(:inline) { nil } describe 'GET #show' do subject do @@ -13,7 +14,8 @@ describe Projects::RawController do params: { namespace_id: project.namespace, project_id: project, - id: filepath + id: filepath, + inline: inline }) end @@ -25,10 +27,12 @@ describe Projects::RawController do expect(response).to have_gitlab_http_status(:ok) expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') - expect(response.header['Content-Disposition']).to eq('inline') - expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') end + + it_behaves_like 'project cache control headers' + it_behaves_like 'content disposition headers' end context 'image header' do @@ -38,15 +42,20 @@ describe Projects::RawController do subject expect(response).to have_gitlab_http_status(:ok) - expect(response.header['Content-Disposition']).to eq('inline') expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') end + + it_behaves_like 'project cache control headers' + it_behaves_like 'content disposition headers' end - it_behaves_like 'a controller that can serve LFS files' do + context 'with LFS files' do let(:filename) { 'lfs_object.iso' } let(:filepath) { "be93687/files/lfs/#{filename}" } + + it_behaves_like 'a controller that can serve LFS files' + it_behaves_like 'project cache control headers' end context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 900569af6c6..9fa07cbc7a6 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -449,44 +449,76 @@ describe Projects::SnippetsController do end describe 'GET #raw' do - let(:content) { "first line\r\nsecond line\r\nthird line" } - let(:formatted_content) { content.gsub(/\r\n/, "\n") } - let(:project_snippet) do - create( - :project_snippet, :public, :repository, - project: project, - author: user, - content: content - ) + let(:inline) { nil } + let(:line_ending) { nil } + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + id: project_snippet.to_param, + inline: inline, + line_ending: line_ending + } end - let(:blob) { project_snippet.blobs.first } - context 'CRLF line ending' do - let(:params) do - { - namespace_id: project.namespace, - project_id: project, - id: project_snippet.to_param - } + subject { get :raw, params: params } + + context 'when repository is empty' do + let(:content) { "first line\r\nsecond line\r\nthird line" } + let(:formatted_content) { content.gsub(/\r\n/, "\n") } + let(:project_snippet) do + create( + :project_snippet, :public, :empty_repo, + project: project, + author: user, + content: content + ) end - before do - allow_next_instance_of(Blob) do |instance| - allow(instance).to receive(:data).and_return(content) + context 'CRLF line ending' do + before do + allow_next_instance_of(Blob) do |instance| + allow(instance).to receive(:data).and_return(content) + end end - end - it 'returns LF line endings by default' do - get :raw, params: params + it 'returns LF line endings by default' do + subject - expect(response.body).to eq(formatted_content) + expect(response.body).to eq(formatted_content) + end + + context 'when line_ending parameter present' do + let(:line_ending) { :raw } + + it 'does not convert line endings' do + subject + + expect(response.body).to eq(content) + end + end + end + end + + context 'when repository is not empty' do + let(:project_snippet) do + create( + :project_snippet, :public, :repository, + project: project, + author: user + ) end - it 'does not convert line endings when parameter present' do - get :raw, params: params.merge(line_ending: :raw) + it 'sends the blob' do + subject - expect(response.body).to eq(content) + expect(response).to have_gitlab_http_status(:ok) + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' end + + it_behaves_like 'project cache control headers' + it_behaves_like 'content disposition headers' end end diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb index 6dd050af277..99d14298cd1 100644 --- a/spec/controllers/projects/wikis_controller_spec.rb +++ b/spec/controllers/projects/wikis_controller_spec.rb @@ -144,14 +144,12 @@ describe Projects::WikisController do let(:id) { upload_file_to_wiki(project, user, file_name) } - before do - subject - end - context 'when file is an image' do let(:file_name) { 'dk.png' } it 'delivers the image' do + subject + expect(response.headers['Content-Disposition']).to match(/^inline/) expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" end @@ -160,19 +158,27 @@ describe Projects::WikisController do let(:file_name) { 'unsanitized.svg' } it 'delivers the image' do + subject + expect(response.headers['Content-Disposition']).to match(/^inline/) expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" end end + + it_behaves_like 'project cache control headers' end context 'when file is a pdf' do let(:file_name) { 'git-cheat-sheet.pdf' } it 'sets the content type to sets the content response headers' do + subject + expect(response.headers['Content-Disposition']).to match(/^inline/) expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" end + + it_behaves_like 'project cache control headers' end end end diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index a675014a77b..3025521e189 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -501,6 +501,11 @@ describe SnippetsController do end describe "GET #raw" do + let(:inline) { nil } + let(:params) { { id: snippet.to_param, inline: inline } } + + subject { get :raw, params: params } + shared_examples '200 status' do before do subject @@ -511,11 +516,6 @@ describe SnippetsController do expect(response).to have_gitlab_http_status(:ok) end - it 'has expected headers' do - expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') - expect(response.header['Content-Disposition']).to match(/inline/) - end - it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' end @@ -551,12 +551,20 @@ describe SnippetsController do shared_examples 'successful response' do it_behaves_like '200 status' - it_behaves_like 'CRLF line ending' - it 'returns snippet first blob data' do + it 'has expected blob headers' do subject - expect(response.body).to eq snippet.blobs.first.data + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + end + + it_behaves_like 'content disposition headers' + + it 'sets cache_control public header based on snippet visibility' do + subject + + expect(response.cache_control[:public]).to eq snippet.public? end context 'when feature flag version_snippets is disabled' do @@ -571,12 +579,33 @@ describe SnippetsController 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) + 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 end context 'when the personal snippet is private' do - let_it_be(:personal_snippet) { create(:personal_snippet, :private, :repository, author: user) } + let_it_be(:snippet) { create(:personal_snippet, :private, :repository, author: user) } context 'when signed in' do before do @@ -595,18 +624,13 @@ describe SnippetsController do end context 'when signed in user is the author' do - it_behaves_like 'successful response' do - let(:snippet) { personal_snippet } - let(:params) { { id: snippet.to_param } } - - subject { get :raw, params: params } - end + it_behaves_like 'successful response' end end context 'when not signed in' do it 'redirects to the sign in page' do - get :raw, params: { id: personal_snippet.to_param } + subject expect(response).to redirect_to(new_user_session_path) end @@ -614,24 +638,19 @@ describe SnippetsController do end context 'when the personal snippet is internal' do - let_it_be(:personal_snippet) { create(:personal_snippet, :internal, :repository, author: user) } + let_it_be(:snippet) { create(:personal_snippet, :internal, :repository, author: user) } context 'when signed in' do before do sign_in(user) end - it_behaves_like 'successful response' do - let(:snippet) { personal_snippet } - let(:params) { { id: snippet.to_param } } - - subject { get :raw, params: params } - end + it_behaves_like 'successful response' end context 'when not signed in' do it 'redirects to the sign in page' do - get :raw, params: { id: personal_snippet.to_param } + subject expect(response).to redirect_to(new_user_session_path) end @@ -639,26 +658,21 @@ describe SnippetsController do end context 'when the personal snippet is public' do - let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository, author: user) } + let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) } context 'when signed in' do before do sign_in(user) end - it_behaves_like 'successful response' do - let(:snippet) { personal_snippet } - let(:params) { { id: snippet.to_param } } - - subject { get :raw, params: params } - end + it_behaves_like 'successful response' end context 'when not signed in' do it 'responds with status 200' do - get :raw, params: { id: personal_snippet.to_param } + subject - expect(assigns(:snippet)).to eq(personal_snippet) + expect(assigns(:snippet)).to eq(snippet) expect(response).to have_gitlab_http_status(:ok) end end diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index 11686ed5277..f2c342f76d0 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -99,6 +99,30 @@ FactoryBot.define do trait :repository_source do config_source { Ci::Pipeline.config_sources[:repository_source] } end + + trait :detached_merge_request_pipeline do + merge_request + + source { :merge_request_event } + project { merge_request.source_project } + sha { merge_request.source_branch_sha } + ref { merge_request.ref_path } + end + + trait :legacy_detached_merge_request_pipeline do + detached_merge_request_pipeline + + ref { merge_request.source_branch } + end + + trait :merged_result_pipeline do + detached_merge_request_pipeline + + sha { 'test-merge-sha'} + ref { merge_request.merge_ref_path } + source_sha { merge_request.source_branch_sha } + target_sha { merge_request.target_branch_sha } + end end end end diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index f717bab5f2a..08a8ede61b1 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -147,23 +147,13 @@ FactoryBot.define do trait :with_legacy_detached_merge_request_pipeline do after(:create) do |merge_request| - merge_request.pipelines_for_merge_request << create(:ci_pipeline, - source: :merge_request_event, - merge_request: merge_request, - project: merge_request.source_project, - ref: merge_request.source_branch, - sha: merge_request.source_branch_sha) + create(:ci_pipeline, :legacy_detached_merge_request_pipeline, merge_request: merge_request) end end trait :with_detached_merge_request_pipeline do after(:create) do |merge_request| - merge_request.pipelines_for_merge_request << create(:ci_pipeline, - source: :merge_request_event, - merge_request: merge_request, - project: merge_request.source_project, - ref: merge_request.ref_path, - sha: merge_request.source_branch_sha) + create(:ci_pipeline, :detached_merge_request_pipeline, merge_request: merge_request) end end @@ -175,14 +165,12 @@ FactoryBot.define do end after(:create) do |merge_request, evaluator| - merge_request.pipelines_for_merge_request << create(:ci_pipeline, - source: :merge_request_event, + create(:ci_pipeline, :merged_result_pipeline, merge_request: merge_request, - project: merge_request.source_project, - ref: merge_request.merge_ref_path, sha: evaluator.merge_sha, source_sha: evaluator.source_sha, - target_sha: evaluator.target_sha) + target_sha: evaluator.target_sha + ) end end diff --git a/spec/fixtures/api/schemas/entities/discussion.json b/spec/fixtures/api/schemas/entities/discussion.json index 16622ef6887..92863d2e084 100644 --- a/spec/fixtures/api/schemas/entities/discussion.json +++ b/spec/fixtures/api/schemas/entities/discussion.json @@ -55,7 +55,8 @@ "human_access": { "type": ["string", "null"] }, "toggle_award_path": { "type": "string" }, "path": { "type": "string" }, - "commands_changes": { "type": "object", "additionalProperties": true } + "commands_changes": { "type": "object", "additionalProperties": true }, + "confidential": { "type": ["boolean", "null"] } }, "required": [ "id", "attachment", "author", "created_at", "updated_at", diff --git a/spec/fixtures/api/schemas/public_api/v4/notes.json b/spec/fixtures/api/schemas/public_api/v4/notes.json index 9668327adc4..d15d2e90b05 100644 --- a/spec/fixtures/api/schemas/public_api/v4/notes.json +++ b/spec/fixtures/api/schemas/public_api/v4/notes.json @@ -28,7 +28,8 @@ "noteable_type": { "type": "string" }, "resolved": { "type": "boolean" }, "resolvable": { "type": "boolean" }, - "resolved_by": { "type": ["string", "null"] } + "resolved_by": { "type": ["string", "null"] }, + "confidential": { "type": ["boolean", "null"] } }, "required": [ "id", "body", "attachment", "author", "created_at", "updated_at", diff --git a/spec/frontend/maintenance_mode_settings/components/app_spec.js b/spec/frontend/maintenance_mode_settings/components/app_spec.js new file mode 100644 index 00000000000..a67bc63cfe1 --- /dev/null +++ b/spec/frontend/maintenance_mode_settings/components/app_spec.js @@ -0,0 +1,42 @@ +import { shallowMount } from '@vue/test-utils'; +import MaintenanceModeSettingsApp from '~/maintenance_mode_settings/components/app.vue'; +import { GlToggle, GlFormTextarea, GlButton } from '@gitlab/ui'; + +describe('MaintenanceModeSettingsApp', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(MaintenanceModeSettingsApp); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findMaintenanceModeSettingsContainer = () => wrapper.find('article'); + const findGlToggle = () => wrapper.find(GlToggle); + const findGlFormTextarea = () => wrapper.find(GlFormTextarea); + const findGlButton = () => wrapper.find(GlButton); + + describe('template', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders the Maintenance Mode Settings container', () => { + expect(findMaintenanceModeSettingsContainer().exists()).toBe(true); + }); + + it('renders the GlToggle', () => { + expect(findGlToggle().exists()).toBe(true); + }); + + it('renders the GlFormTextarea', () => { + expect(findGlFormTextarea().exists()).toBe(true); + }); + + it('renders the GlButton', () => { + expect(findGlButton().exists()).toBe(true); + }); + }); +}); diff --git a/spec/graphql/types/notes/note_type_spec.rb b/spec/graphql/types/notes/note_type_spec.rb index 809f54c120c..8cf84cd8dfd 100644 --- a/spec/graphql/types/notes/note_type_spec.rb +++ b/spec/graphql/types/notes/note_type_spec.rb @@ -5,7 +5,7 @@ describe GitlabSchema.types['Note'] do it 'exposes the expected fields' do expected_fields = [:id, :project, :author, :body, :created_at, :updated_at, :discussion, :resolvable, :position, :user_permissions, - :resolved_by, :resolved_at, :system, :body_html] + :resolved_by, :resolved_at, :system, :body_html, :confidential] expect(described_class).to have_graphql_fields(*expected_fields) end diff --git a/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb b/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb new file mode 100644 index 00000000000..3c3e37df200 --- /dev/null +++ b/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb @@ -0,0 +1,234 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::BackgroundMigration::FixProjectsWithoutPrometheusService, :migration, schema: 2020_02_20_115023 do + def service_params_for(project_id, params = {}) + { + project_id: project_id, + active: false, + properties: '{}', + type: 'PrometheusService', + template: false, + push_events: true, + issues_events: true, + merge_requests_events: true, + tag_push_events: true, + note_events: true, + category: 'monitoring', + default: false, + wiki_page_events: true, + pipeline_events: true, + confidential_issues_events: true, + commit_events: true, + job_events: true, + confidential_note_events: true, + deployment_events: false + }.merge(params) + end + + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:services) { table(:services) } + let(:clusters) { table(:clusters) } + let(:cluster_groups) { table(:cluster_groups) } + let(:clusters_applications_prometheus) { table(:clusters_applications_prometheus) } + let(:namespace) { namespaces.create(name: 'user', path: 'user') } + let(:project) { projects.create(namespace_id: namespace.id) } + + let(:application_statuses) do + { + errored: -1, + installed: 3, + updated: 5 + } + end + + let(:cluster_types) do + { + instance_type: 1, + group_type: 2, + project_type: 3 + } + end + + let(:columns) do + %w(project_id active properties type template push_events + issues_events merge_requests_events tag_push_events + note_events category default wiki_page_events pipeline_events + confidential_issues_events commit_events job_events + confidential_note_events deployment_events) + end + + describe '#perform' do + shared_examples 'fix services entries state' do + it 'is idempotent' do + expect { subject.perform(project.id, project.id + 1) }.to change { services.order(:id).map { |row| row.attributes } } + + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + + context 'non prometheus services' do + it 'does not change them' do + other_type = 'SomeOtherService' + services.create(service_params_for(project.id, active: true, type: other_type)) + + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.where(type: other_type).order(:id).map { |row| row.attributes } } + end + end + + context 'prometheus integration services do not exist' do + it 'creates missing services entries', :aggregate_failures do + expect { subject.perform(project.id, project.id + 1) }.to change { services.count }.by(1) + expect([service_params_for(project.id, active: true)]).to eq services.order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } + end + + context 'template is present for prometheus services' do + it 'creates missing services entries', :aggregate_failures do + services.create(service_params_for(nil, template: true, properties: { 'from_template' => true }.to_json)) + + expect { subject.perform(project.id, project.id + 1) }.to change { services.count }.by(1) + updated_rows = services.where(template: false).order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } + expect([service_params_for(project.id, active: true, properties: { 'from_template' => true }.to_json)]).to eq updated_rows + end + end + end + + context 'prometheus integration services exist' do + context 'in active state' do + it 'does not change them' do + services.create(service_params_for(project.id, active: true)) + + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + + context 'not in active state' do + it 'sets active attribute to true' do + service = services.create(service_params_for(project.id, active: false)) + + expect { subject.perform(project.id, project.id + 1) }.to change { service.reload.active? }.from(false).to(true) + end + + context 'prometheus services are configured manually ' do + it 'does not change them' do + properties = '{"api_url":"http://test.dev","manual_configuration":"1"}' + services.create(service_params_for(project.id, properties: properties, active: false)) + + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + end + end + end + + context 'k8s cluster shared on instance level' do + let(:cluster) { clusters.create(name: 'cluster', cluster_type: cluster_types[:instance_type]) } + + context 'with installed prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') + end + + it_behaves_like 'fix services entries state' + end + + context 'with updated prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:updated], version: '123') + end + + it_behaves_like 'fix services entries state' + end + + context 'with errored prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:errored], version: '123') + end + + it 'does not change services entries' do + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + end + + context 'k8s cluster shared on group level' do + let(:cluster) { clusters.create(name: 'cluster', cluster_type: cluster_types[:group_type]) } + + before do + cluster_groups.create(cluster_id: cluster.id, group_id: project.namespace_id) + end + + context 'with installed prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') + end + + it_behaves_like 'fix services entries state' + + context 'second k8s cluster without application available' do + let(:namespace_2) { namespaces.create(name: 'namespace2', path: 'namespace2') } + let(:project_2) { projects.create(namespace_id: namespace_2.id) } + + before do + cluster_2 = clusters.create(name: 'cluster2', cluster_type: cluster_types[:group_type]) + cluster_groups.create(cluster_id: cluster_2.id, group_id: project_2.namespace_id) + end + + it 'changed only affected services entries' do + expect { subject.perform(project.id, project_2.id + 1) }.to change { services.count }.by(1) + expect([service_params_for(project.id, active: true)]).to eq services.order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } + end + end + end + + context 'with updated prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:updated], version: '123') + end + + it_behaves_like 'fix services entries state' + end + + context 'with errored prometheus application' do + before do + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:errored], version: '123') + end + + it 'does not change services entries' do + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + + context 'with missing prometheus application' do + it 'does not change services entries' do + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + + context 'with inactive service' do + it 'does not change services entries' do + services.create(service_params_for(project.id)) + + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + end + end + + context 'k8s cluster for single project' do + let(:cluster) { clusters.create(name: 'cluster', cluster_type: cluster_types[:project_type]) } + let(:cluster_projects) { table(:cluster_projects) } + + context 'with installed prometheus application' do + before do + cluster_projects.create(cluster_id: cluster.id, project_id: project.id) + clusters_applications_prometheus.create(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') + end + + it 'does not change services entries' do + expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } + end + end + end + end +end diff --git a/spec/lib/gitlab/lets_encrypt/order_spec.rb b/spec/lib/gitlab/lets_encrypt/order_spec.rb index 1a759103c44..333fce8e36a 100644 --- a/spec/lib/gitlab/lets_encrypt/order_spec.rb +++ b/spec/lib/gitlab/lets_encrypt/order_spec.rb @@ -38,4 +38,23 @@ describe ::Gitlab::LetsEncrypt::Order do order.request_certificate(domain: 'example.com', private_key: private_key) end end + + describe '#challenge_error' do + it 'returns error if challenge has errors' do + challenge = acme_challenge_double + + # error just to give an example + error = { + "type" => "urn:ietf:params:acme:error:dns", + "detail" => "No valid IP addresses found for test.example.com", + "status" => 400 + } + + allow(challenge).to receive(:error).and_return(error) + + acme_order = acme_order_double(authorizations: [acme_authorization_double(challenge)]) + + expect(described_class.new(acme_order).challenge_error).to eq(error) + end + end end diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index f1b5393a2d8..5a2cf2eda8b 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -13,10 +13,6 @@ describe Gitlab::Regex do it { is_expected.not_to match('?gitlab') } end - shared_examples_for 'project/group name error message' do - it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.") } - end - describe '.project_name_regex' do subject { described_class.project_name_regex } @@ -27,18 +23,26 @@ describe Gitlab::Regex do subject { described_class.group_name_regex } it_behaves_like 'project/group name regex' + + it 'allows parenthesis' do + is_expected.to match('Group One (Test)') + end + + it 'does not start with parenthesis' do + is_expected.not_to match('(Invalid Group name)') + end end describe '.project_name_regex_message' do subject { described_class.project_name_regex_message } - it_behaves_like 'project/group name error message' + it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.") } end describe '.group_name_regex_message' do subject { described_class.group_name_regex_message } - it_behaves_like 'project/group name error message' + it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', dash, space, parenthesis. It must start with letter, digit, emoji or '_'.") } end describe '.environment_name_regex' do diff --git a/spec/migrations/fix_projects_without_prometheus_services_spec.rb b/spec/migrations/fix_projects_without_prometheus_services_spec.rb new file mode 100644 index 00000000000..ecfad313f58 --- /dev/null +++ b/spec/migrations/fix_projects_without_prometheus_services_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20200220115023_fix_projects_without_prometheus_service.rb') + +describe FixProjectsWithoutPrometheusService, :migration do + let(:namespace) { table(:namespaces).create(name: 'gitlab', path: 'gitlab-org') } + + let!(:projects) do + [ + table(:projects).create(namespace_id: namespace.id, name: 'foo 1'), + table(:projects).create(namespace_id: namespace.id, name: 'foo 2'), + table(:projects).create(namespace_id: namespace.id, name: 'foo 3') + ] + end + + before do + stub_const("#{described_class.name}::BATCH_SIZE", 2) + end + + around do |example| + Sidekiq::Testing.fake! do + Timecop.freeze do + example.call + end + end + end + + it 'schedules jobs for ranges of projects' do + migrate! + + expect(described_class::MIGRATION) + .to be_scheduled_delayed_migration(2.minutes, projects[0].id, projects[1].id) + + expect(described_class::MIGRATION) + .to be_scheduled_delayed_migration(4.minutes, projects[2].id, projects[2].id) + end + + it 'schedules jobs according to the configured batch size' do + expect { migrate! }.to change { BackgroundMigrationWorker.jobs.size }.by(2) + end +end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 0192c8ed17d..55af292e8f3 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -838,4 +838,33 @@ describe Ci::Runner do it { is_expected.to eq(contacted_at_stored) } end + + describe '.belonging_to_group' do + it 'returns the specific group runner' do + group = create(:group) + runner = create(:ci_runner, :group, groups: [group]) + unrelated_group = create(:group) + create(:ci_runner, :group, groups: [unrelated_group]) + + expect(described_class.belonging_to_group(group.id)).to contain_exactly(runner) + end + + context 'runner belonging to parent group' do + let_it_be(:parent_group) { create(:group) } + let_it_be(:parent_runner) { create(:ci_runner, :group, groups: [parent_group]) } + let_it_be(:group) { create(:group, parent: parent_group) } + + context 'when include_parent option is passed' do + it 'returns the group runner from the parent group' do + expect(described_class.belonging_to_group(group.id, include_ancestors: true)).to contain_exactly(parent_runner) + end + end + + context 'when include_parent option is not passed' do + it 'does not return the group runner from the parent group' do + expect(described_class.belonging_to_group(group.id)).to be_empty + end + end + end + end end diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index 70094ef4388..f6b257e6288 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -12,7 +12,6 @@ describe API::Runners do let(:project2) { create(:project, creator_id: user.id) } let(:group) { create(:group).tap { |group| group.add_owner(user) } } - let(:group2) { create(:group).tap { |group| group.add_owner(user) } } let!(:shared_runner) { create(:ci_runner, :instance, description: 'Shared runner') } let!(:project_runner) { create(:ci_runner, :project, description: 'Project runner', projects: [project]) } @@ -734,6 +733,24 @@ describe API::Runners do end end + shared_examples_for 'unauthorized access to runners list' do + context 'authorized user without maintainer privileges' do + it "does not return group's runners" do + get api("/#{entity_type}/#{entity.id}/runners", user2) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'unauthorized user' do + it "does not return project's runners" do + get api("/#{entity_type}/#{entity.id}/runners") + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + end + describe 'GET /projects/:id/runners' do context 'authorized user with maintainer privileges' do it 'returns response status and headers' do @@ -813,20 +830,77 @@ describe API::Runners do end end - context 'authorized user without maintainer privileges' do - it "does not return project's runners" do - get api("/projects/#{project.id}/runners", user2) + it_behaves_like 'unauthorized access to runners list' do + let(:entity_type) { 'projects' } + let(:entity) { project } + end + end - expect(response).to have_gitlab_http_status(:forbidden) + describe 'GET /groups/:id/runners' do + context 'authorized user with maintainer privileges' do + it 'returns all runners' do + get api("/groups/#{group.id}/runners", user) + + expect(json_response).to match_array([ + a_hash_including('description' => 'Group runner') + ]) end - end - context 'unauthorized user' do - it "does not return project's runners" do - get api("/projects/#{project.id}/runners") + context 'filter by type' do + it 'returns record when valid and present' do + get api("/groups/#{group.id}/runners?type=group_type", user) - expect(response).to have_gitlab_http_status(:unauthorized) + expect(json_response).to match_array([ + a_hash_including('description' => 'Group runner') + ]) + end + + it 'returns empty result when type does not match' do + get api("/groups/#{group.id}/runners?type=project_type", user) + + expect(json_response).to be_empty + end + + it 'does not filter by invalid type' do + get api("/groups/#{group.id}/runners?type=bogus", user) + + expect(response).to have_gitlab_http_status(:bad_request) + end end + + context 'filter runners by status' do + it 'returns runners by valid status' do + create(:ci_runner, :group, :inactive, description: 'Inactive group runner', groups: [group]) + + get api("/groups/#{group.id}/runners?status=paused", user) + + expect(json_response).to match_array([ + a_hash_including('description' => 'Inactive group runner') + ]) + end + + it 'does not filter by invalid status' do + get api("/groups/#{group.id}/runners?status=bogus", user) + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + + it 'filters runners by tag_list' do + create(:ci_runner, :group, description: 'Runner tagged with tag1 and tag2', groups: [group], tag_list: %w[tag1 tag2]) + create(:ci_runner, :group, description: 'Runner tagged with tag2', groups: [group], tag_list: %w[tag1]) + + get api("/groups/#{group.id}/runners?tag_list=tag1,tag2", user) + + expect(json_response).to match_array([ + a_hash_including('description' => 'Runner tagged with tag1 and tag2') + ]) + end + end + + it_behaves_like 'unauthorized access to runners list' do + let(:entity_type) { 'groups' } + let(:entity) { group } end end diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 7a7712c2f5d..1aa5e21dddb 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -3,23 +3,23 @@ require 'spec_helper' describe API::Todos do - let(:group) { create(:group) } - let(:project_1) { create(:project, :repository, group: group) } - let(:project_2) { create(:project) } - let(:author_1) { create(:user) } - let(:author_2) { create(:user) } - let(:john_doe) { create(:user, username: 'john_doe') } - let(:merge_request) { create(:merge_request, source_project: project_1) } - let!(:merge_request_todo) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } - let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) } - let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } - let!(:pending_3) { create(:on_commit_todo, project: project_1, author: author_2, user: john_doe) } - let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } - let!(:award_emoji_1) { create(:award_emoji, awardable: merge_request, user: author_1, name: 'thumbsup') } - let!(:award_emoji_2) { create(:award_emoji, awardable: pending_1.target, user: author_1, name: 'thumbsup') } - let!(:award_emoji_3) { create(:award_emoji, awardable: pending_2.target, user: author_2, name: 'thumbsdown') } - - before do + let_it_be(:group) { create(:group) } + let_it_be(:project_1) { create(:project, :repository, group: group) } + let_it_be(:project_2) { create(:project) } + let_it_be(:author_1) { create(:user) } + let_it_be(:author_2) { create(:user) } + let_it_be(:john_doe) { create(:user, username: 'john_doe') } + let_it_be(:merge_request) { create(:merge_request, source_project: project_1) } + let_it_be(:merge_request_todo) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } + let_it_be(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) } + let_it_be(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } + let_it_be(:pending_3) { create(:on_commit_todo, project: project_1, author: author_2, user: john_doe) } + let_it_be(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } + let_it_be(:award_emoji_1) { create(:award_emoji, awardable: merge_request, user: author_1, name: 'thumbsup') } + let_it_be(:award_emoji_2) { create(:award_emoji, awardable: pending_1.target, user: author_1, name: 'thumbsup') } + let_it_be(:award_emoji_3) { create(:award_emoji, awardable: pending_2.target, user: author_2, name: 'thumbsdown') } + + before_all do project_1.add_developer(john_doe) project_2.add_developer(john_doe) end @@ -29,7 +29,7 @@ describe API::Todos do it 'returns authentication error' do get api('/todos') - expect(response.status).to eq(401) + expect(response).to have_gitlab_http_status(:unauthorized) end end @@ -37,7 +37,7 @@ describe API::Todos do it 'returns an array of pending todos for current user' do get api('/todos', john_doe) - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(4) @@ -74,7 +74,7 @@ describe API::Todos do it 'filters based on author_id param' do get api('/todos', john_doe), params: { author_id: author_2.id } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) @@ -87,7 +87,7 @@ describe API::Todos do get api('/todos', john_doe), params: { type: 'MergeRequest' } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(2) @@ -98,7 +98,7 @@ describe API::Todos do it 'filters based on state param' do get api('/todos', john_doe), params: { state: 'done' } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -109,7 +109,7 @@ describe API::Todos do it 'filters based on project_id param' do get api('/todos', john_doe), params: { project_id: project_2.id } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -120,7 +120,7 @@ describe API::Todos do it 'filters based on project_id param' do get api('/todos', john_doe), params: { group_id: group.id, sort: :target_id } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) @@ -131,7 +131,7 @@ describe API::Todos do it 'filters based on action param' do get api('/todos', john_doe), params: { action: 'mentioned' } - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -157,7 +157,7 @@ describe API::Todos do create(:on_commit_todo, project: project_3, author: author_1, user: john_doe) expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control) - expect(response.status).to eq(200) + expect(response).to have_gitlab_http_status(:ok) end end @@ -189,7 +189,7 @@ describe API::Todos do it 'returns 404 if the todo does not belong to the current user' do post api("/todos/#{pending_1.id}/mark_as_done", author_1) - expect(response.status).to eq(404) + expect(response).to have_gitlab_http_status(:not_found) end end end @@ -225,7 +225,7 @@ describe API::Todos do it 'creates a todo on an issuable' do post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", john_doe) - expect(response.status).to eq(201) + expect(response).to have_gitlab_http_status(:created) expect(json_response['project']).to be_a Hash expect(json_response['author']).to be_a Hash expect(json_response['target_type']).to eq(issuable.class.name) @@ -242,13 +242,15 @@ describe API::Todos do post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", john_doe) - expect(response.status).to eq(304) + expect(response).to have_gitlab_http_status(:not_modified) end it 'returns 404 if the issuable is not found' do - post api("/projects/#{project_1.id}/#{issuable_type}/123/todo", john_doe) + unknown_id = 0 + + post api("/projects/#{project_1.id}/#{issuable_type}/#{unknown_id}/todo", john_doe) - expect(response.status).to eq(404) + expect(response).to have_gitlab_http_status(:not_found) end it 'returns an error if the issuable is not accessible' do @@ -268,13 +270,17 @@ describe API::Todos do describe 'POST :id/issuable_type/:issueable_id/todo' do context 'for an issue' do it_behaves_like 'an issuable', 'issues' do - let(:issuable) { create(:issue, :confidential, author: author_1, project: project_1) } + let_it_be(:issuable) do + create(:issue, :confidential, author: author_1, project: project_1) + end end end context 'for a merge request' do it_behaves_like 'an issuable', 'merge_requests' do - let(:issuable) { create(:merge_request, :simple, source_project: project_1) } + let_it_be(:issuable) do + create(:merge_request, :simple, source_project: project_1) + end end end end diff --git a/spec/serializers/discussion_entity_spec.rb b/spec/serializers/discussion_entity_spec.rb index b194623099d..4adf1dc5994 100644 --- a/spec/serializers/discussion_entity_spec.rb +++ b/spec/serializers/discussion_entity_spec.rb @@ -34,7 +34,8 @@ describe DiscussionEntity do :discussion_path, :resolved_at, :for_commit, - :commit_id + :commit_id, + :confidential ) end diff --git a/spec/services/jira_import/start_import_service_spec.rb b/spec/services/jira_import/start_import_service_spec.rb new file mode 100644 index 00000000000..038c53b2b22 --- /dev/null +++ b/spec/services/jira_import/start_import_service_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe JiraImport::StartImportService do + let_it_be(:user) { create(:user) } + let(:project) { create(:project) } + + subject { described_class.new(user, project, '').execute } + + context 'when feature flag disabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'responds with error', 'Jira import feature is disabled.' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when user does not have permissions to run the import' do + before do + project.add_developer(user) + end + + it_behaves_like 'responds with error', 'You do not have permissions to run the import.' + end + + context 'when user has permission to run import' do + before do + project.add_maintainer(user) + end + + context 'when Jira service was not setup' do + it_behaves_like 'responds with error', 'Jira integration not configured.' + end + + context 'when Jira service exists' do + let!(:jira_service) { create(:jira_service, project: project, active: true) } + + context 'when Jira project key is not provided' do + it_behaves_like 'responds with error', 'Unable to find Jira project to import data from.' + end + + context 'when correct data provided' do + subject { described_class.new(user, project, 'some-key').execute } + + context 'when import is already running' do + let!(:import_state) { create(:import_state, project: project, status: :started) } + + it_behaves_like 'responds with error', 'Jira import is already running.' + end + + it 'returns success response' do + expect(subject).to be_a(ServiceResponse) + expect(subject).to be_success + end + + it 'schedules jira import' do + subject + + expect(project.import_state.status).to eq('scheduled') + end + + it 'creates jira import data' do + subject + + jira_import_data = project.import_data.becomes(JiraImportData) + expect(jira_import_data.force_import?).to be true + imported_project_data = jira_import_data.projects.last + expect(imported_project_data.key).to eq('some-key') + expect(imported_project_data.scheduled_by['user_id']).to eq(user.id) + end + end + end + end + end +end diff --git a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb index 9832ba95524..163276db7e6 100644 --- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb +++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb @@ -163,4 +163,22 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil end end + + context 'when order is invalid' do + let(:existing_order) do + create(:pages_domain_acme_order, pages_domain: pages_domain) + end + + let!(:api_order) do + stub_lets_encrypt_order(existing_order.url, 'invalid') + end + + it 'saves error to domain and deletes acme order' do + expect do + service.execute + end.to change { pages_domain.reload.auto_ssl_failed }.from(false).to(true) + + expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil + end + end end diff --git a/spec/support/helpers/lets_encrypt_helpers.rb b/spec/support/helpers/lets_encrypt_helpers.rb index 2857416ad95..0f378893895 100644 --- a/spec/support/helpers/lets_encrypt_helpers.rb +++ b/spec/support/helpers/lets_encrypt_helpers.rb @@ -11,7 +11,8 @@ module LetsEncryptHelpers status: 'pending', token: 'tokenvalue', file_content: 'hereisfilecontent', - request_validation: true + request_validation: true, + error: nil }.freeze def stub_lets_encrypt_settings @@ -43,16 +44,17 @@ module LetsEncryptHelpers challenge end - def acme_authorization_double + def acme_authorization_double(challenge = acme_challenge_double) authorization = instance_double('Acme::Client::Resources::Authorization') - allow(authorization).to receive(:http).and_return(acme_challenge_double) + allow(authorization).to receive(:http).and_return(challenge) + allow(authorization).to receive(:challenges).and_return([challenge]) authorization end def acme_order_double(attributes = {}) acme_order = instance_double('Acme::Client::Resources::Order') allow(acme_order).to receive_messages(ACME_ORDER_METHODS.merge(attributes)) - allow(acme_order).to receive(:authorizations).and_return([acme_authorization_double]) + allow(acme_order).to receive(:authorizations).and_return([acme_authorization_double]) unless attributes[:authorizations] allow(acme_order).to receive(:finalize) acme_order end diff --git a/spec/support/shared_examples/controllers/cache_control_shared_examples.rb b/spec/support/shared_examples/controllers/cache_control_shared_examples.rb new file mode 100644 index 00000000000..426d7f95222 --- /dev/null +++ b/spec/support/shared_examples/controllers/cache_control_shared_examples.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'project cache control headers' do + before do + project.update(visibility_level: visibility_level) + end + + context 'when project is public' do + let(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC } + + it 'returns cache_control public header to true' do + subject + + expect(response.cache_control[:public]).to be_truthy + end + end + + context 'when project is private' do + let(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } + + it 'returns cache_control public header to true' do + subject + + expect(response.cache_control[:public]).to be_falsey + end + end + + context 'when project is internal' do + let(:visibility_level) { Gitlab::VisibilityLevel::INTERNAL } + + it 'returns cache_control public header to true' do + subject + + expect(response.cache_control[:public]).to be_falsey + end + end +end diff --git a/spec/support/shared_examples/controllers/content_disposition_shared_examples.rb b/spec/support/shared_examples/controllers/content_disposition_shared_examples.rb new file mode 100644 index 00000000000..a1ece5fcc7f --- /dev/null +++ b/spec/support/shared_examples/controllers/content_disposition_shared_examples.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'content disposition headers' do + it 'sets content disposition to inline' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.header['Content-Disposition']).to match(/inline/) + end + + context 'when inline param is false' do + let(:inline) { 'false' } + + it 'sets content disposition to attachment' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.header['Content-Disposition']).to match(/attachment/) + end + end +end diff --git a/spec/support/shared_examples/services/jira_import/start_import_service_shared_examples.rb b/spec/support/shared_examples/services/jira_import/start_import_service_shared_examples.rb new file mode 100644 index 00000000000..c5e56ed3539 --- /dev/null +++ b/spec/support/shared_examples/services/jira_import/start_import_service_shared_examples.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +shared_examples 'responds with error' do |message| + it 'returns error' do + expect(subject).to be_a(ServiceResponse) + expect(subject).to be_error + expect(subject.message).to eq(message) + end +end diff --git a/spec/views/admin/application_settings/general.html.haml_spec.rb b/spec/views/admin/application_settings/general.html.haml_spec.rb index e6a0307afd9..d8ca5dd1b49 100644 --- a/spec/views/admin/application_settings/general.html.haml_spec.rb +++ b/spec/views/admin/application_settings/general.html.haml_spec.rb @@ -33,4 +33,32 @@ describe 'admin/application_settings/general.html.haml' do end end end + + describe 'Maintenance mode' do + let(:maintenance_mode_flag) { true } + + before do + assign(:application_setting, app_settings) + stub_feature_flags(maintenance_mode: maintenance_mode_flag) + allow(view).to receive(:current_user).and_return(user) + end + + context 'when maintenance_mode feature is enabled' do + it 'show the Maintenance mode section' do + render + + expect(rendered).to have_css('#js-maintenance-mode-toggle') + end + end + + context 'when maintenance_mode feature is disabled' do + let(:maintenance_mode_flag) { false } + + it 'hide the Maintenance mode section' do + render + + expect(rendered).not_to have_css('#js-maintenance-mode-toggle') + end + end + end end diff --git a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb index 736acc40371..1349a80029b 100644 --- a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb +++ b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb @@ -21,6 +21,10 @@ describe PagesDomainSslRenewalCronWorker do let!(:domain_without_auto_certificate) do create(:pages_domain, :without_certificate, :without_key, project: project, auto_ssl_enabled: true) end + let!(:domain_with_failed_auto_ssl) do + create(:pages_domain, :without_certificate, :without_key, project: project, + auto_ssl_enabled: true, auto_ssl_failed: true) + end let!(:domain_with_expired_auto_ssl) do create(:pages_domain, :letsencrypt, :with_expired_certificate, project: project) @@ -34,7 +38,8 @@ describe PagesDomainSslRenewalCronWorker do end [domain, - domain_with_obtained_letsencrypt].each do |domain| + domain_with_obtained_letsencrypt, + domain_with_failed_auto_ssl].each do |domain| expect(PagesDomainSslRenewalWorker).not_to receive(:perform_async).with(domain.id) end diff --git a/spec/workers/pages_domain_ssl_renewal_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb index 3552ff0823a..a35965f49b2 100644 --- a/spec/workers/pages_domain_ssl_renewal_worker_spec.rb +++ b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb @@ -26,6 +26,8 @@ describe PagesDomainSslRenewalWorker do shared_examples 'does nothing' do it 'does nothing' do expect(::PagesDomains::ObtainLetsEncryptCertificateService).not_to receive(:new) + + worker.perform(domain.id) end end |