diff options
Diffstat (limited to 'spec')
50 files changed, 979 insertions, 357 deletions
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index fa49438287f..35cbab57037 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -340,7 +340,6 @@ describe Projects::ClustersController do describe 'security' do before do - allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end @@ -438,7 +437,6 @@ describe Projects::ClustersController do end before do - allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 32607fc5f56..f82e3c8c7dc 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -320,6 +320,90 @@ describe Projects::IssuesController do end end + describe 'PUT #reorder' do + let(:group) { create(:group, projects: [project]) } + let!(:issue1) { create(:issue, project: project, relative_position: 10) } + let!(:issue2) { create(:issue, project: project, relative_position: 20) } + let!(:issue3) { create(:issue, project: project, relative_position: 30) } + + before do + sign_in(user) + end + + context 'when user has access' do + before do + project.add_developer(user) + end + + context 'with valid params' do + it 'reorders issues and returns a successful 200 response' do + reorder_issue(issue1, + move_after_id: issue2.id, + move_before_id: issue3.id, + group_full_path: group.full_path) + + [issue1, issue2, issue3].map(&:reload) + + expect(response).to have_gitlab_http_status(200) + expect(issue1.relative_position) + .to be_between(issue2.relative_position, issue3.relative_position) + end + end + + context 'with invalid params' do + it 'returns a unprocessable entity 422 response for invalid move ids' do + reorder_issue(issue1, move_after_id: 99, move_before_id: 999) + + expect(response).to have_gitlab_http_status(422) + end + + it 'returns a not found 404 response for invalid issue id' do + reorder_issue(object_double(issue1, iid: 999), + move_after_id: issue2.id, + move_before_id: issue3.id) + + expect(response).to have_gitlab_http_status(404) + end + + it 'returns a unprocessable entity 422 response for issues not in group' do + another_group = create(:group) + + reorder_issue(issue1, + move_after_id: issue2.id, + move_before_id: issue3.id, + group_full_path: another_group.full_path) + + expect(response).to have_gitlab_http_status(422) + end + end + end + + context 'with unauthorized user' do + before do + project.add_guest(user) + end + + it 'responds with 404' do + reorder_issue(issue1, move_after_id: issue2.id, move_before_id: issue3.id) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + def reorder_issue(issue, move_after_id: nil, move_before_id: nil, group_full_path: nil) + put :reorder, + params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: issue.iid, + move_after_id: move_after_id, + move_before_id: move_before_id, + group_full_path: group_full_path + }, + format: :json + end + end + describe 'PUT #update' do subject do put :update, diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 34cbf0c8723..0eca663a683 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1001,6 +1001,8 @@ describe Projects::MergeRequestsController do before do project.add_developer(user) sign_in(user) + + expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original end it 'returns 200' do diff --git a/spec/controllers/projects/pages_domains_controller_spec.rb b/spec/controllers/projects/pages_domains_controller_spec.rb index ff3afd51cd8..032f4f1418f 100644 --- a/spec/controllers/projects/pages_domains_controller_spec.rb +++ b/spec/controllers/projects/pages_domains_controller_spec.rb @@ -15,7 +15,10 @@ describe Projects::PagesDomainsController do end let(:pages_domain_params) do - build(:pages_domain, domain: 'my.otherdomain.com').slice(:key, :certificate, :domain) + attributes_for(:pages_domain, domain: 'my.otherdomain.com').slice(:key, :certificate, :domain).tap do |params| + params[:user_provided_key] = params.delete(:key) + params[:user_provided_certificate] = params.delete(:certificate) + end end before do @@ -84,48 +87,59 @@ describe Projects::PagesDomainsController do controller.instance_variable_set(:@domain, pages_domain) end - let(:pages_domain_params) do - attributes_for(:pages_domain).slice(:key, :certificate) - end - let(:params) do request_params.merge(id: pages_domain.domain, pages_domain: pages_domain_params) end - it 'updates the domain' do - expect(pages_domain) - .to receive(:update) - .with(ActionController::Parameters.new(pages_domain_params).permit!) - .and_return(true) + context 'with valid params' do + let(:pages_domain_params) do + attributes_for(:pages_domain, :with_trusted_chain).slice(:key, :certificate).tap do |params| + params[:user_provided_key] = params.delete(:key) + params[:user_provided_certificate] = params.delete(:certificate) + end + end + + it 'updates the domain' do + expect do + patch(:update, params: params) + end.to change { pages_domain.reload.certificate }.to(pages_domain_params[:user_provided_certificate]) + end + + it 'redirects to the project page' do + patch(:update, params: params) - patch(:update, params: params) + expect(flash[:notice]).to eq 'Domain was updated' + expect(response).to redirect_to(project_pages_path(project)) + end end - it 'redirects to the project page' do - patch(:update, params: params) + context 'with key parameter' do + before do + pages_domain.update!(key: nil, certificate: nil, certificate_source: 'gitlab_provided') + end - expect(flash[:notice]).to eq 'Domain was updated' - expect(response).to redirect_to(project_pages_path(project)) + it 'marks certificate as provided by user' do + expect do + patch(:update, params: params) + end.to change { pages_domain.reload.certificate_source }.from('gitlab_provided').to('user_provided') + end end context 'the domain is invalid' do - it 'renders the edit action' do - allow(pages_domain).to receive(:update).and_return(false) + let(:pages_domain_params) { { user_provided_certificate: 'blabla' } } + it 'renders the edit action' do patch(:update, params: params) expect(response).to render_template('edit') end end - context 'the parameters include the domain' do - it 'renders 400 Bad Request' do - expect(pages_domain) - .to receive(:update) - .with(hash_not_including(:domain)) - .and_return(true) - - patch(:update, params: params.deep_merge(pages_domain: { domain: 'abc' })) + context 'when parameters include the domain' do + it 'does not update domain' do + expect do + patch(:update, params: params.deep_merge(pages_domain: { domain: 'abc' })) + end.not_to change { pages_domain.reload.domain } end end end diff --git a/spec/factories/pages_domains.rb b/spec/factories/pages_domains.rb index db8384877b0..8da19a37a6a 100644 --- a/spec/factories/pages_domains.rb +++ b/spec/factories/pages_domains.rb @@ -180,5 +180,9 @@ Iy6oRpHaCF/2obZdIdgf9rlyz0fkqyHJc9GkioSoOhJZxEV2SgAkap8yS0sX2tJ9 ZDXgrA== -----END CERTIFICATE-----' end + + trait :letsencrypt do + certificate_source { :gitlab_provided } + end end end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 29545779a34..dafec29dfcc 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -419,6 +419,32 @@ describe "Admin::Users" do end end end + + describe 'Email verification status' do + let!(:secondary_email) do + create :email, email: 'secondary@example.com', user: user + end + + it 'displays the correct status for an unverified email address' do + user.update(confirmed_at: nil, unconfirmed_email: user.email) + visit admin_user_path(user) + + expect(page).to have_content("#{user.email} Unverified") + + expect(page).to have_content("#{secondary_email.email} Unverified") + end + + it 'displays the correct status for a verified email address' do + visit admin_user_path(user) + expect(page).to have_content("#{user.email} Verified") + + secondary_email.confirm + expect(secondary_email.confirmed?).to be_truthy + + visit admin_user_path(user) + expect(page).to have_content("#{secondary_email.email} Verified") + end + end end describe "GET /admin/users/:id/edit" do diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb index 6f9901815e1..21d97aba0c5 100644 --- a/spec/features/container_registry_spec.rb +++ b/spec/features/container_registry_spec.rb @@ -42,6 +42,8 @@ describe "Container Registry", :js do .to receive(:delete_tags!).and_return(true) click_on(class: 'js-remove-repo') + expect(find('.modal .modal-title')).to have_content 'Remove repository' + find('.modal .modal-footer .btn-danger').click end it 'user removes a specific tag from container repository' do @@ -54,6 +56,8 @@ describe "Container Registry", :js do .to receive(:delete).and_return(true) click_on(class: 'js-delete-registry') + expect(find('.modal .modal-title')).to have_content 'Remove image' + find('.modal .modal-footer .btn-danger').click end end diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index e4a3a1a8c92..974e0f84681 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -118,7 +118,6 @@ describe 'Gcp Cluster', :js do context 'when user changes cluster parameters' do before do - allow(ClusterConfigureWorker).to receive(:perform_async) fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' page.within('#js-cluster-details') { click_button 'Save changes' } end diff --git a/spec/features/projects/pages_lets_encrypt_spec.rb b/spec/features/projects/pages_lets_encrypt_spec.rb index baa217cbe58..a5f8702302c 100644 --- a/spec/features/projects/pages_lets_encrypt_spec.rb +++ b/spec/features/projects/pages_lets_encrypt_spec.rb @@ -2,124 +2,119 @@ require 'spec_helper' describe "Pages with Let's Encrypt", :https_pages_enabled do + include LetsEncryptHelpers + let(:project) { create(:project) } let(:user) { create(:user) } let(:role) { :maintainer } - let(:certificate_pem) do - <<~PEM - -----BEGIN CERTIFICATE----- - MIICGzCCAYSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAbMRkwFwYDVQQDExB0ZXN0 - LWNlcnRpZmljYXRlMB4XDTE2MDIxMjE0MzIwMFoXDTIwMDQxMjE0MzIwMFowGzEZ - MBcGA1UEAxMQdGVzdC1jZXJ0aWZpY2F0ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw - gYkCgYEApL4J9L0ZxFJ1hI1LPIflAlAGvm6ZEvoT4qKU5Xf2JgU7/2geNR1qlNFa - SvCc08Knupp5yTgmvyK/Xi09U0N82vvp4Zvr/diSc4A/RA6Mta6egLySNT438kdT - nY2tR5feoTLwQpX0t4IMlwGQGT5h6Of2fKmDxzuwuyffcIHqLdsCAwEAAaNvMG0w - DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxl9WSxBprB0z0ibJs3rXEk0+95AwCwYD - VR0PBAQDAgXgMBEGCWCGSAGG+EIBAQQEAwIGQDAeBglghkgBhvhCAQ0EERYPeGNh - IGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAGC4T8SlFHK0yPSa+idGLQFQ - joZp2JHYvNlTPkRJ/J4TcXxBTJmArcQgTIuNoBtC+0A/SwdK4MfTCUY4vNWNdese - 5A4K65Nb7Oh1AdQieTBHNXXCdyFsva9/ScfQGEl7p55a52jOPs0StPd7g64uvjlg - YHi2yesCrOvVXt+lgPTd - -----END CERTIFICATE----- - PEM - end + let(:certificate_pem) { attributes_for(:pages_domain)[:certificate] } - let(:certificate_key) do - <<~KEY - -----BEGIN PRIVATE KEY----- - MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKS+CfS9GcRSdYSN - SzyH5QJQBr5umRL6E+KilOV39iYFO/9oHjUdapTRWkrwnNPCp7qaeck4Jr8iv14t - PVNDfNr76eGb6/3YknOAP0QOjLWunoC8kjU+N/JHU52NrUeX3qEy8EKV9LeCDJcB - kBk+Yejn9nypg8c7sLsn33CB6i3bAgMBAAECgYA2D26w80T7WZvazYr86BNMePpd - j2mIAqx32KZHzt/lhh40J/SRtX9+Kl0Y7nBoRR5Ja9u/HkAIxNxLiUjwg9r6cpg/ - uITEF5nMt7lAk391BuI+7VOZZGbJDsq2ulPd6lO+C8Kq/PI/e4kXcIjeH6KwQsuR - 5vrXfBZ3sQfflaiN4QJBANBt8JY2LIGQF8o89qwUpRL5vbnKQ4IzZ5+TOl4RLR7O - AQpJ81tGuINghO7aunctb6rrcKJrxmEH1whzComybrMCQQDKV49nOBudRBAIgG4K - EnLzsRKISUHMZSJiYTYnablof8cKw1JaQduw7zgrUlLwnroSaAGX88+Jw1f5n2Lh - Vlg5AkBDdUGnrDLtYBCDEQYZHblrkc7ZAeCllDOWjxUV+uMqlCv8A4Ey6omvY57C - m6I8DkWVAQx8VPtozhvHjUw80rZHAkB55HWHAM3h13axKG0htCt7klhPsZHpx6MH - EPjGlXIT+aW2XiPmK3ZlCDcWIenE+lmtbOpI159Wpk8BGXs/s/xBAkEAlAY3ymgx - 63BDJEwvOb2IaP8lDDxNsXx9XJNVvQbv5n15vNsLHbjslHfAhAbxnLQ1fLhUPqSi - nNp/xedE1YxutQ== - -----END PRIVATE KEY----- - KEY - end + let(:certificate_key) { attributes_for(:pages_domain)[:key] } before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) + stub_lets_encrypt_settings + project.add_role(user, role) sign_in(user) project.namespace.update(owner: user) allow_any_instance_of(Project).to receive(:pages_deployed?) { true } end - context 'when the page_auto_ssl feature flag is enabled' do - before do - stub_feature_flags(pages_auto_ssl: true) + context 'when the auto SSL management is initially disabled' do + let(:domain) do + create(:pages_domain, auto_ssl_enabled: false, project: project) end - context 'when the auto SSL management is initially disabled' do - let(:domain) do - create(:pages_domain, auto_ssl_enabled: false, project: project) - end + it 'enables auto SSL and dynamically updates the form accordingly', :js do + visit edit_project_pages_domain_path(project, domain) - it 'enables auto SSL and dynamically updates the form accordingly', :js do - visit edit_project_pages_domain_path(project, domain) + expect(domain.auto_ssl_enabled).to eq false - expect(domain.auto_ssl_enabled).to eq false + expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' + expect(page).to have_field 'Certificate (PEM)', type: 'textarea' + expect(page).to have_field 'Key (PEM)', type: 'textarea' - expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' - expect(page).to have_field 'Certificate (PEM)', type: 'textarea' - expect(page).to have_field 'Key (PEM)', type: 'textarea' + find('.js-auto-ssl-toggle-container .project-feature-toggle').click - find('.js-auto-ssl-toggle-container .project-feature-toggle').click + expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' + expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' + expect(page).not_to have_field 'Key (PEM)', type: 'textarea' - expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' - expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' - expect(page).not_to have_field 'Key (PEM)', type: 'textarea' - expect(page).to have_content "The certificate will be shown here once it has been obtained from Let's Encrypt. This process may take up to an hour to complete." + click_on 'Save Changes' - click_on 'Save Changes' + expect(domain.reload.auto_ssl_enabled).to eq true + end + end - expect(domain.reload.auto_ssl_enabled).to eq true - end + context 'when the auto SSL management is initially enabled' do + let(:domain) do + create(:pages_domain, :letsencrypt, auto_ssl_enabled: true, project: project) end - context 'when the auto SSL management is initially enabled' do - let(:domain) do - create(:pages_domain, auto_ssl_enabled: true, project: project) - end + it 'disables auto SSL and dynamically updates the form accordingly', :js do + visit edit_project_pages_domain_path(project, domain) - it 'disables auto SSL and dynamically updates the form accordingly', :js do - visit edit_project_pages_domain_path(project, domain) + expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' + expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' + expect(page).not_to have_field 'Key (PEM)', type: 'textarea' - expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' - expect(page).to have_field 'Certificate (PEM)', type: 'textarea', disabled: true - expect(page).not_to have_field 'Key (PEM)', type: 'textarea' + find('.js-auto-ssl-toggle-container .project-feature-toggle').click - find('.js-auto-ssl-toggle-container .project-feature-toggle').click + expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' + expect(page).to have_field 'Certificate (PEM)', type: 'textarea' + expect(page).to have_field 'Key (PEM)', type: 'textarea' - expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' - expect(page).to have_field 'Certificate (PEM)', type: 'textarea' - expect(page).to have_field 'Key (PEM)', type: 'textarea' + fill_in 'Certificate (PEM)', with: certificate_pem + fill_in 'Key (PEM)', with: certificate_key - fill_in 'Certificate (PEM)', with: certificate_pem - fill_in 'Key (PEM)', with: certificate_key + click_on 'Save Changes' - click_on 'Save Changes' + expect(domain.reload.auto_ssl_enabled).to eq false + end + end - expect(domain.reload.auto_ssl_enabled).to eq false + shared_examples 'user sees private keys only for user provided certificate' do + before do + visit edit_project_pages_domain_path(project, domain) + end + + shared_examples 'user do not see private key' do + it 'user do not see private key' do + expect(find_field('Key (PEM)', visible: :all, disabled: :all).value).to be_blank + end + end + + context 'when auto_ssl is enabled for domain' do + let(:domain) { create(:pages_domain, :letsencrypt, project: project, auto_ssl_enabled: true) } + + include_examples 'user do not see private key' + end + + context 'when auto_ssl is disabled for domain' do + let(:domain) { create(:pages_domain, :letsencrypt, project: project) } + + include_examples 'user do not see private key' + end + + context 'when certificate is provided by user' do + let(:domain) { create(:pages_domain, project: project) } + + it 'user sees private key' do + expect(find_field('Key (PEM)').value).not_to be_blank end end end - context 'when the page_auto_ssl feature flag is disabled' do + include_examples 'user sees private keys only for user provided certificate' + + context 'when letsencrypt is disabled' do let(:domain) do create(:pages_domain, auto_ssl_enabled: false, project: project) end before do - stub_feature_flags(pages_auto_ssl: false) + stub_application_setting(lets_encrypt_terms_of_service_accepted: false) visit edit_project_pages_domain_path(project, domain) end @@ -127,5 +122,7 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do it "does not render the Let's Encrypt field", :js do expect(page).not_to have_selector '.js-auto-ssl-toggle-container' end + + include_examples 'user sees private keys only for user provided certificate' end end diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 9bb0ba81ef5..c4b3ddb2088 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -shared_examples 'pages domain editing' do +shared_examples 'pages settings editing' do let(:project) { create(:project) } let(:user) { create(:user) } let(:role) { :maintainer } @@ -321,19 +321,15 @@ shared_examples 'pages domain editing' do end describe 'Pages' do - context 'when pages_auto_ssl feature flag is disabled' do - before do - stub_feature_flags(pages_auto_ssl: false) - end + include LetsEncryptHelpers - include_examples 'pages domain editing' - end + include_examples 'pages settings editing' - context 'when pages_auto_ssl feature flag is enabled' do + context 'when letsencrypt support is enabled' do before do - stub_feature_flags(pages_auto_ssl: true) + stub_lets_encrypt_settings end - include_examples 'pages domain editing' + include_examples 'pages settings editing' end end diff --git a/spec/frontend/vue_shared/components/paginated_list_spec.js b/spec/frontend/vue_shared/components/paginated_list_spec.js new file mode 100644 index 00000000000..31ac362d35f --- /dev/null +++ b/spec/frontend/vue_shared/components/paginated_list_spec.js @@ -0,0 +1,56 @@ +import PaginatedList from '~/vue_shared/components/paginated_list.vue'; +import { PREV, NEXT } from '~/vue_shared/components/pagination/constants'; +import { mount } from '@vue/test-utils'; + +describe('Pagination links component', () => { + let wrapper; + let glPaginatedList; + + const template = ` + <div class="slot" slot-scope="{ listItem }"> + <span class="item">Item Name: {{listItem.id}}</span> + </div> + `; + + const props = { + prevText: PREV, + nextText: NEXT, + }; + + beforeEach(() => { + wrapper = mount(PaginatedList, { + scopedSlots: { + default: template, + }, + propsData: { + list: [{ id: 'foo' }, { id: 'bar' }], + props, + }, + }); + + [glPaginatedList] = wrapper.vm.$children; + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('Paginated List Component', () => { + describe('props', () => { + // We test attrs and not props because we pass through to child component using v-bind:"$attrs" + it('should pass prevText to GitLab UI paginated list', () => { + expect(glPaginatedList.$attrs['prev-text']).toBe(props.prevText); + }); + it('should pass nextText to GitLab UI paginated list', () => { + expect(glPaginatedList.$attrs['next-text']).toBe(props.nextText); + }); + }); + + describe('rendering', () => { + it('it renders the gl-paginated-list', () => { + expect(wrapper.contains('ul.list-group')).toBe(true); + expect(wrapper.findAll('li.list-group-item').length).toBe(2); + }); + }); + }); +}); diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb index a3511e078ce..ed3e31b3c53 100644 --- a/spec/helpers/appearances_helper_spec.rb +++ b/spec/helpers/appearances_helper_spec.rb @@ -8,6 +8,22 @@ describe AppearancesHelper do allow(helper).to receive(:current_user).and_return(user) end + describe '.current_appearance' do + it 'memoizes empty appearance' do + expect(Appearance).to receive(:current).once + + 2.times { helper.current_appearance } + end + + it 'memoizes custom appearance' do + create(:appearance) + + expect(Appearance).to receive(:current).once.and_call_original + + 2.times { helper.current_appearance } + end + end + describe '#header_message' do it 'returns nil when header message field is not set' do create(:appearance) diff --git a/spec/javascripts/jobs/components/stages_dropdown_spec.js b/spec/javascripts/jobs/components/stages_dropdown_spec.js index 52bb5161123..86b7a8d7848 100644 --- a/spec/javascripts/jobs/components/stages_dropdown_spec.js +++ b/spec/javascripts/jobs/components/stages_dropdown_spec.js @@ -101,9 +101,7 @@ describe('Stages Dropdown', () => { }); it(`renders the pipeline info text like "Pipeline #123 for !456 with source_branch into target_branch"`, () => { - const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${ - pipeline.merge_request.source_branch - } into ${pipeline.merge_request.target_branch}`; + const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch} into ${pipeline.merge_request.target_branch}`; const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText); expect(actual).toBe(expected); @@ -144,9 +142,7 @@ describe('Stages Dropdown', () => { }); it(`renders the pipeline info like "Pipeline #123 for !456 with source_branch"`, () => { - const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${ - pipeline.merge_request.source_branch - }`; + const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch}`; const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText); expect(actual).toBe(expected); diff --git a/spec/javascripts/notes/components/diff_with_note_spec.js b/spec/javascripts/notes/components/diff_with_note_spec.js index 0752bd05904..f849fe9d8bb 100644 --- a/spec/javascripts/notes/components/diff_with_note_spec.js +++ b/spec/javascripts/notes/components/diff_with_note_spec.js @@ -47,6 +47,19 @@ describe('diff_with_note', () => { vm = mountComponentWithStore(Component, { props, store }); }); + it('removes trailing "+" char', () => { + const richText = vm.$el.querySelectorAll('.line_holder')[4].querySelector('.line_content') + .textContent[0]; + + expect(richText).not.toEqual('+'); + }); + + it('removes trailing "-" char', () => { + const richText = vm.$el.querySelector('#LC13').parentNode.textContent[0]; + + expect(richText).not.toEqual('-'); + }); + it('shows text diff', () => { expect(selectors.container).toHaveClass('text-file'); expect(selectors.diffTable).toExist(); diff --git a/spec/javascripts/pages/labels/components/promote_label_modal_spec.js b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js index 08a8362797b..75912612255 100644 --- a/spec/javascripts/pages/labels/components/promote_label_modal_spec.js +++ b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js @@ -26,9 +26,7 @@ describe('Promote label modal', () => { it('contains the proper description', () => { expect(vm.text).toContain( - `Promoting ${labelMockData.labelTitle} will make it available for all projects inside ${ - labelMockData.groupName - }`, + `Promoting ${labelMockData.labelTitle} will make it available for all projects inside ${labelMockData.groupName}`, ); }); diff --git a/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js index 2ac73ef3024..3d25a278cef 100644 --- a/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js +++ b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js @@ -24,9 +24,7 @@ describe('Promote milestone modal', () => { it('contains the proper description', () => { expect(vm.text).toContain( - `Promoting ${ - milestoneMockData.milestoneTitle - } will make it available for all projects inside ${milestoneMockData.groupName}.`, + `Promoting ${milestoneMockData.milestoneTitle} will make it available for all projects inside ${milestoneMockData.groupName}.`, ); }); diff --git a/spec/javascripts/registry/components/collapsible_container_spec.js b/spec/javascripts/registry/components/collapsible_container_spec.js index a3f7ff76dc7..9ed4b04324a 100644 --- a/spec/javascripts/registry/components/collapsible_container_spec.js +++ b/spec/javascripts/registry/components/collapsible_container_spec.js @@ -12,6 +12,8 @@ describe('collapsible registry container', () => { let mock; const Component = Vue.extend(collapsibleComponent); + const findDeleteBtn = () => vm.$el.querySelector('.js-remove-repo'); + beforeEach(() => { mock = new MockAdapter(axios); @@ -67,7 +69,25 @@ describe('collapsible registry container', () => { describe('delete repo', () => { it('should be possible to delete a repo', () => { - expect(vm.$el.querySelector('.js-remove-repo')).not.toBeNull(); + expect(findDeleteBtn()).not.toBeNull(); + }); + + describe('clicked on delete', () => { + beforeEach(done => { + findDeleteBtn().click(); + Vue.nextTick(done); + }); + + it('should open confirmation modal', () => { + expect(vm.$el.querySelector('#confirm-repo-deletion-modal')).not.toBeNull(); + }); + + it('should call deleteItem when confirming deletion', () => { + spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve()); + vm.$el.querySelector('#confirm-repo-deletion-modal .btn-danger').click(); + + expect(vm.deleteItem).toHaveBeenCalledWith(vm.repo); + }); }); }); }); diff --git a/spec/javascripts/registry/components/table_registry_spec.js b/spec/javascripts/registry/components/table_registry_spec.js index 7f5252a7d6c..d366c67a1b9 100644 --- a/spec/javascripts/registry/components/table_registry_spec.js +++ b/spec/javascripts/registry/components/table_registry_spec.js @@ -3,10 +3,14 @@ import tableRegistry from '~/registry/components/table_registry.vue'; import store from '~/registry/stores'; import { repoPropsData } from '../mock_data'; +const [firstImage] = repoPropsData.list; + describe('table registry', () => { let vm; let Component; + const findDeleteBtn = () => vm.$el.querySelector('.js-delete-registry'); + beforeEach(() => { Component = Vue.extend(tableRegistry); vm = new Component({ @@ -37,8 +41,30 @@ describe('table registry', () => { expect(textRendered).toContain(repoPropsData.list[0].size); }); - it('should be possible to delete a registry', () => { - expect(vm.$el.querySelector('.table tbody tr .js-delete-registry')).toBeDefined(); + describe('delete registry', () => { + it('should be possible to delete a registry', () => { + expect(findDeleteBtn()).toBeDefined(); + }); + + describe('clicked on delete', () => { + beforeEach(done => { + findDeleteBtn().click(); + Vue.nextTick(done); + }); + + it('should open confirmation modal and set itemToBeDeleted properly', () => { + expect(vm.itemToBeDeleted).toEqual(firstImage); + expect(vm.$el.querySelector('#confirm-image-deletion-modal')).not.toBeNull(); + }); + + it('should call deleteItem and reset itemToBeDeleted when confirming deletion', () => { + spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve()); + vm.$el.querySelector('#confirm-image-deletion-modal .btn-danger').click(); + + expect(vm.deleteItem).toHaveBeenCalledWith(firstImage); + expect(vm.itemToBeDeleted).toBeNull(); + }); + }); }); describe('pagination', () => { diff --git a/spec/javascripts/registry/stores/actions_spec.js b/spec/javascripts/registry/stores/actions_spec.js index c9aa82dba90..0613ec8e0f1 100644 --- a/spec/javascripts/registry/stores/actions_spec.js +++ b/spec/javascripts/registry/stores/actions_spec.js @@ -105,4 +105,28 @@ describe('Actions Registry Store', () => { ); }); }); + + describe('deleteItem', () => { + it('should perform DELETE request on destroyPath', done => { + const destroyPath = `${TEST_HOST}/mygroup/myproject/container_registry/1.json`; + let deleted = false; + mock.onDelete(destroyPath).replyOnce(() => { + deleted = true; + return [200]; + }); + testAction( + actions.deleteItem, + { + destroyPath, + }, + mockedState, + ) + .then(() => { + expect(mock.history.delete.length).toBe(1); + expect(deleted).toBe(true); + done(); + }) + .catch(done.fail); + }); + }); }); diff --git a/spec/javascripts/releases/components/release_block_spec.js b/spec/javascripts/releases/components/release_block_spec.js index 36b181f24ef..e98c665f99d 100644 --- a/spec/javascripts/releases/components/release_block_spec.js +++ b/spec/javascripts/releases/components/release_block_spec.js @@ -78,8 +78,10 @@ describe('Release block', () => { }; let vm; + const factory = props => mountComponent(Component, { release: props }); + beforeEach(() => { - vm = mountComponent(Component, { release }); + vm = factory(release); }); afterEach(() => { @@ -149,4 +151,14 @@ describe('Release block', () => { ); }); }); + + describe('with pre_release flag', () => { + beforeEach(() => { + vm = factory(Object.assign({}, release, { pre_release: true })); + }); + + it('renders pre-release badge', () => { + expect(vm.$el.textContent).toContain('Pre-release'); + }); + }); }); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js index 75017d20473..fe831094ecf 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js @@ -222,9 +222,7 @@ describe('MRWidgetPipeline', () => { sourceBranchLink: mockCopy.source_branch_link, }); - const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${ - pipeline.commit.short_id - } on ${mockCopy.source_branch_link}`; + const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockCopy.source_branch_link}`; const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); @@ -247,11 +245,7 @@ describe('MRWidgetPipeline', () => { sourceBranchLink: mockCopy.source_branch_link, }); - const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${ - pipeline.commit.short_id - } on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch} into ${ - pipeline.merge_request.target_branch - }`; + const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch} into ${pipeline.merge_request.target_branch}`; const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); @@ -274,9 +268,7 @@ describe('MRWidgetPipeline', () => { sourceBranchLink: mockCopy.source_branch_link, }); - const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${ - pipeline.commit.short_id - } on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch}`; + const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch}`; const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index dad0a5535c0..8ff971114d6 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -101,6 +101,13 @@ describe Banzai::Filter::RelativeLinkFilter do .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" end + it 'does not modify relative URLs in system notes' do + path = "#{project_path}/merge_requests/1/diffs" + doc = filter(link(path), system_note: true) + + expect(doc.at_css('a')['href']).to eq path + end + it 'ignores absolute URLs with two leading slashes' do doc = filter(link('//doc/api/README.md')) expect(doc.at_css('a')['href']).to eq '//doc/api/README.md' diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index 2e90f6c7f71..35700e0b588 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -98,12 +98,8 @@ describe Gitlab::BitbucketImport::Importer do describe '#import_pull_requests' do let(:source_branch_sha) { sample.commits.last } let(:target_branch_sha) { sample.commits.first } - - before do - allow(subject).to receive(:import_wiki) - allow(subject).to receive(:import_issues) - - pull_request = instance_double( + let(:pull_request) do + instance_double( Bitbucket::Representation::PullRequest, iid: 10, source_branch_sha: source_branch_sha, @@ -116,6 +112,11 @@ describe Gitlab::BitbucketImport::Importer do author: 'other', created_at: Time.now, updated_at: Time.now) + end + + before do + allow(subject).to receive(:import_wiki) + allow(subject).to receive(:import_issues) # https://gitlab.com/gitlab-org/gitlab-test/compare/c1acaa58bbcbc3eafe538cb8274ba387047b69f8...5937ac0a7beb003549fc5fd26fc247ad @inline_note = instance_double( @@ -167,6 +168,20 @@ describe Gitlab::BitbucketImport::Importer do expect(reply_note.note).to eq(@reply.note) end + context 'when importing a pull request throws an exception' do + before do + allow(pull_request).to receive(:raw).and_return('hello world') + allow(subject.client).to receive(:pull_request_comments).and_raise(HTTParty::Error) + end + + it 'logs an error without the backtrace' do + subject.execute + + expect(subject.errors.count).to eq(1) + expect(subject.errors.first.keys).to match_array(%i(type iid errors)) + end + end + context "when branches' sha is not found in the repository" do let(:source_branch_sha) { 'a' * Commit::MIN_SHA_LENGTH } let(:target_branch_sha) { 'b' * Commit::MIN_SHA_LENGTH } diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb index 3d57ce431ab..aa4e358b148 100644 --- a/spec/lib/gitlab/ci/ansi2html_spec.rb +++ b/spec/lib/gitlab/ci/ansi2html_spec.rb @@ -141,11 +141,11 @@ describe Gitlab::Ci::Ansi2html do end it "replaces newlines with line break tags" do - expect(convert_html("\n")).to eq('<span class=""><br/><span class=""></span></span>') + expect(convert_html("\n")).to eq('<span class=""></span><br/><span class=""></span>') end it "groups carriage returns with newlines" do - expect(convert_html("\r\n")).to eq('<span class=""><br/><span class=""></span></span>') + expect(convert_html("\r\n")).to eq('<span class=""></span><br/><span class=""></span>') end describe "incremental update" do @@ -193,7 +193,7 @@ describe Gitlab::Ci::Ansi2html do let(:pre_text) { "Hello\r" } let(:pre_html) { "<span class=\"\">Hello\r</span>" } let(:text) { "\nWorld" } - let(:html) { "<span class=\"\"><br/><span class=\"\">World</span></span>" } + let(:html) { "<span class=\"\"></span><br/><span class=\"\">World</span>" } it_behaves_like 'stateable converter' end @@ -232,7 +232,7 @@ describe Gitlab::Ci::Ansi2html do it 'prints light red' do text = "#{section_start}\e[91mHello\e[0m\n#{section_end}" header = %{<span class="term-fg-l-red section js-section-header section-header js-s-#{class_name(section_name)}">Hello</span>} - line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"><br/></span>} + line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"></span><br/>} line = %{<span class="section line s_#{class_name(section_name)}"></span>} empty_line = %{<span class="section js-s-#{class_name(section_name)}"></span>} html = "#{section_start_html}#{header}#{line_break}#{line}#{empty_line}#{section_end_html}" diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb index 5ac5122e800..c5bc81a2b9e 100644 --- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb +++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb @@ -45,12 +45,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do it { is_expected.to be_truthy } end end - - context 'and cluster is project type' do - let(:cluster) { create(:cluster, :project) } - - it { is_expected.to be_falsey } - end end context 'and no cluster to deploy to' do diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb index 35250632e86..0d03eef99c8 100644 --- a/spec/lib/gitlab/ci/trace/stream_spec.rb +++ b/spec/lib/gitlab/ci/trace/stream_spec.rb @@ -65,9 +65,9 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do result = stream.html expect(result).to eq( - "<span class=\"\">ヾ(´༎ຶД༎ຶ`)ノ<br/><span class=\"\"></span></span>"\ - "<span class=\"term-fg-green\">許功蓋</span><span class=\"\"><br/>"\ - "<span class=\"\"></span></span>") + "<span class=\"\">ヾ(´༎ຶД༎ຶ`)ノ</span><br/><span class=\"\"></span>"\ + "<span class=\"term-fg-green\">許功蓋</span><span class=\"\"></span><br/>"\ + "<span class=\"\"></span>") expect(result.encoding).to eq(Encoding.default_external) end end @@ -306,8 +306,8 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do shared_examples_for 'htmls' do it "returns html" do expect(stream.html).to eq( - "<span class=\"\">12<br/><span class=\"\">34<br/>"\ - "<span class=\"\">56</span></span></span>") + "<span class=\"\">12</span><br/><span class=\"\">34</span><br/>"\ + "<span class=\"\">56</span>") end it "returns html for last line only" do diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index fe0e9702f8a..4676db6b8d8 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -18,9 +18,10 @@ describe Gitlab::Highlight do end describe '#highlight' do + let(:plain_text_file_name) { "test.txt" } + let(:plain_text_content) { "plain text contents" } let(:file_name) { 'test.lisp' } - let(:no_context_content) { ":type \"assem\"))" } - let(:content) { "(make-pathname :defaults name\n#{no_context_content}" } + let(:content) { "(make-pathname :defaults name\n:type \"assem\")" } let(:multiline_content) do %q( def test(input): @@ -32,22 +33,22 @@ describe Gitlab::Highlight do it 'highlights' do expected = %Q[<span id="LC1" class="line" lang="common_lisp"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span> -<span id="LC2" class="line" lang="common_lisp"><span class="ss">:type</span> <span class="s">"assem"</span><span class="p">))</span></span>] +<span id="LC2" class="line" lang="common_lisp"><span class="ss">:type</span> <span class="s">"assem"</span><span class="p">)</span></span>] expect(described_class.highlight(file_name, content)).to eq(expected) end it 'returns plain version for unknown lexer context' do - result = described_class.highlight(file_name, no_context_content) + result = described_class.highlight(plain_text_file_name, plain_text_content) - expect(result).to eq(%[<span id="LC1" class="line" lang="">:type "assem"))</span>]) + expect(result).to eq(%[<span id="LC1" class="line" lang="plaintext">plain text contents</span>]) end it 'returns plain version for long content' do stub_const('Gitlab::Highlight::MAXIMUM_TEXT_HIGHLIGHT_SIZE', 1) result = described_class.highlight(file_name, content) - expect(result).to eq(%[<span id="LC1" class="line" lang="">(make-pathname :defaults name</span>\n<span id="LC2" class="line" lang="">:type "assem"))</span>]) + expect(result).to eq(%[<span id="LC1" class="line" lang="">(make-pathname :defaults name</span>\n<span id="LC2" class="line" lang="">:type "assem")</span>]) end it 'highlights multi-line comments' do diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb index c6a6042c65c..59160741c45 100644 --- a/spec/lib/gitlab/json_cache_spec.rb +++ b/spec/lib/gitlab/json_cache_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::JsonCache do let(:backend) { double('backend').as_null_object } let(:namespace) { 'geo' } let(:key) { 'foo' } - let(:expanded_key) { "#{namespace}:#{key}:#{Rails.version}" } + let(:expanded_key) { "#{namespace}:#{key}:#{Gitlab::VERSION}:#{Rails.version}" } set(:broadcast_message) { create(:broadcast_message) } subject(:cache) { described_class.new(namespace: namespace, backend: backend) } @@ -35,42 +35,68 @@ describe Gitlab::JsonCache do describe '#cache_key' do context 'when namespace is not defined' do - it 'expands out the key with Rails version' do - cache = described_class.new(cache_key_with_version: true) + context 'when cache_key_with_version is true' do + it 'expands out the key with GitLab, and Rails versions' do + cache = described_class.new(cache_key_with_version: true) - cache_key = cache.cache_key(key) + cache_key = cache.cache_key(key) - expect(cache_key).to eq("#{key}:#{Rails.version}") + expect(cache_key).to eq("#{key}:#{Gitlab::VERSION}:#{Rails.version}") + end end - end - context 'when cache_key_with_version is true' do - it 'expands out the key with namespace and Rails version' do - cache = described_class.new(namespace: namespace, cache_key_with_version: true) + context 'when cache_key_with_version is false' do + it 'returns the key' do + cache = described_class.new(namespace: nil, cache_key_with_version: false) - cache_key = cache.cache_key(key) + cache_key = cache.cache_key(key) - expect(cache_key).to eq("#{namespace}:#{key}:#{Rails.version}") + expect(cache_key).to eq(key) + end end end - context 'when cache_key_with_version is false' do - it 'expands out the key with namespace' do - cache = described_class.new(namespace: namespace, cache_key_with_version: false) + context 'when namespace is nil' do + context 'when cache_key_with_version is true' do + it 'expands out the key with GitLab, and Rails versions' do + cache = described_class.new(cache_key_with_version: true) - cache_key = cache.cache_key(key) + cache_key = cache.cache_key(key) - expect(cache_key).to eq("#{namespace}:#{key}") + expect(cache_key).to eq("#{key}:#{Gitlab::VERSION}:#{Rails.version}") + end + end + + context 'when cache_key_with_version is false' do + it 'returns the key' do + cache = described_class.new(namespace: nil, cache_key_with_version: false) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq(key) + end end end - context 'when namespace is nil, and cache_key_with_version is false' do - it 'returns the key' do - cache = described_class.new(namespace: nil, cache_key_with_version: false) + context 'when namespace is set' do + context 'when cache_key_with_version is true' do + it 'expands out the key with namespace and Rails version' do + cache = described_class.new(namespace: namespace, cache_key_with_version: true) + + cache_key = cache.cache_key(key) - cache_key = cache.cache_key(key) + expect(cache_key).to eq("#{namespace}:#{key}:#{Gitlab::VERSION}:#{Rails.version}") + end + end - expect(cache_key).to eq(key) + context 'when cache_key_with_version is false' do + it 'expands out the key with namespace' do + cache = described_class.new(namespace: namespace, cache_key_with_version: false) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq("#{namespace}:#{key}") + end end end end diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb index 45369b91ed6..a7ea942960b 100644 --- a/spec/lib/gitlab/kubernetes_spec.rb +++ b/spec/lib/gitlab/kubernetes_spec.rb @@ -67,6 +67,30 @@ describe Gitlab::Kubernetes do end end + describe '#filter_by_legacy_label' do + let(:non_matching_pod) { kube_pod(environment_slug: 'production', project_slug: 'my-cool-app') } + + let(:non_matching_pod_2) do + kube_pod(environment_slug: 'production', project_slug: 'my-cool-app').tap do |pod| + pod['metadata']['labels']['app'] = 'production' + end + end + + let(:matching_pod) do + kube_pod.tap do |pod| + pod['metadata']['annotations'].delete('app.gitlab.com/env') + pod['metadata']['annotations'].delete('app.gitlab.com/app') + pod['metadata']['labels']['app'] = 'production' + end + end + + it 'returns matching labels' do + items = [non_matching_pod, non_matching_pod_2, matching_pod] + + expect(filter_by_legacy_label(items, 'my-cool-app', 'production')).to contain_exactly(matching_pod) + end + end + describe '#to_kubeconfig' do let(:token) { 'TOKEN' } let(:ca_pem) { 'PEM' } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index cbbb22ad78c..11af6837dab 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -99,15 +99,9 @@ describe Notify do end end - context 'when enabled email_author_in_body' do - before do - stub_application_setting(email_author_in_body: true) - end - - it 'contains a link to note author' do - is_expected.to have_body_text(issue.author_name) - is_expected.to have_body_text 'created an issue:' - end + it 'contains a link to issue author' do + is_expected.to have_body_text(issue.author_name) + is_expected.to have_body_text 'created an issue:' end end @@ -314,15 +308,9 @@ describe Notify do end end - context 'when enabled email_author_in_body' do - before do - stub_application_setting(email_author_in_body: true) - end - - it 'contains a link to note author' do - is_expected.to have_body_text merge_request.author_name - is_expected.to have_body_text 'created a merge request:' - end + it 'contains a link to merge request author' do + is_expected.to have_body_text merge_request.author_name + is_expected.to have_body_text 'created a merge request:' end end @@ -907,7 +895,9 @@ describe Notify do end it 'contains an introduction' do - is_expected.to have_body_text 'started a new discussion' + issuable_url = "project_#{note.noteable_type.underscore}_url" + + is_expected.to have_body_text "started a new <a href=\"#{public_send(issuable_url, project, note.noteable, anchor: "note_#{note.id}")}\">discussion</a>" end context 'when a comment on an existing discussion' do diff --git a/spec/migrations/migrate_legacy_managed_clusters_to_unmanaged_spec.rb b/spec/migrations/migrate_legacy_managed_clusters_to_unmanaged_spec.rb new file mode 100644 index 00000000000..93426f1f273 --- /dev/null +++ b/spec/migrations/migrate_legacy_managed_clusters_to_unmanaged_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20190606163724_migrate_legacy_managed_clusters_to_unmanaged.rb') + +describe MigrateLegacyManagedClustersToUnmanaged, :migration do + let(:cluster_type) { 'project_type' } + let(:created_at) { 1.hour.ago } + + let!(:cluster) do + table(:clusters).create!( + name: 'cluster', + cluster_type: described_class::Cluster.cluster_types[cluster_type], + managed: true, + created_at: created_at + ) + end + + it 'marks the cluster as unmanaged' do + migrate! + expect(cluster.reload).not_to be_managed + end + + context 'cluster is not project type' do + let(:cluster_type) { 'group_type' } + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end + + context 'cluster has a kubernetes namespace associated' do + before do + table(:clusters_kubernetes_namespaces).create!( + cluster_id: cluster.id, + namespace: 'namespace' + ) + end + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end + + context 'cluster was recently created' do + let(:created_at) { 2.minutes.ago } + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end +end diff --git a/spec/migrations/migrate_managed_clusters_with_no_token_to_unmanaged_spec.rb b/spec/migrations/migrate_managed_clusters_with_no_token_to_unmanaged_spec.rb new file mode 100644 index 00000000000..b73bd16cb60 --- /dev/null +++ b/spec/migrations/migrate_managed_clusters_with_no_token_to_unmanaged_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20190613231640_migrate_managed_clusters_with_no_token_to_unmanaged.rb') + +describe MigrateManagedClustersWithNoTokenToUnmanaged, :migration do + let(:cluster_type) { 'project_type' } + let(:created_at) { Date.new(2018, 11, 1).midnight } + + let!(:cluster) do + table(:clusters).create!( + name: 'cluster', + cluster_type: described_class::Cluster.cluster_types[cluster_type], + managed: true, + created_at: created_at + ) + end + + let!(:kubernetes_namespace) do + table(:clusters_kubernetes_namespaces).create!( + cluster_id: cluster.id, + namespace: 'namespace' + ) + end + + it 'marks the cluster as unmanaged' do + migrate! + expect(cluster.reload).not_to be_managed + end + + context 'cluster is not project type' do + let(:cluster_type) { 'group_type' } + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end + + context 'kubernetes namespace has a service account token' do + before do + kubernetes_namespace.update!(encrypted_service_account_token: "TOKEN") + end + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end + + context 'cluster was created after the cutoff' do + let(:created_at) { Date.new(2019, 1, 1).midnight } + + it 'does not update the cluster' do + migrate! + expect(cluster.reload).to be_managed + end + end +end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index 1fb3a8de808..05b3035e591 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -281,14 +281,14 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching it_behaves_like 'setting variables' - it 'sets KUBE_TOKEN' do - expect(subject).to include( + it 'does not set KUBE_TOKEN' do + expect(subject).not_to include( { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } ) end end - context 'kubernetes namespace is created with no service account token' do + context 'kubernetes namespace is created with service account token' do let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster) } it_behaves_like 'setting variables' @@ -340,32 +340,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching end end - context 'namespace is provided' do - let(:namespace) { 'my-project' } - - before do - kubernetes.namespace = namespace - end - - it_behaves_like 'setting variables' - - it 'sets KUBE_TOKEN' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } - ) - end - end - - context 'no namespace provided' do - it_behaves_like 'setting variables' - - it 'sets KUBE_TOKEN' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } - ) - end - end - context 'group level cluster' do let!(:cluster) { create(:cluster, :group, platform_kubernetes: kubernetes) } @@ -510,27 +484,4 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching it { is_expected.to include(pods: []) } end end - - describe '#update_kubernetes_namespace' do - let(:cluster) { create(:cluster, :provided_by_gcp) } - let(:platform) { cluster.platform } - - context 'when namespace is updated' do - it 'calls ConfigureWorker' do - expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id).once - - platform.namespace = 'new-namespace' - platform.save - end - end - - context 'when namespace is not updated' do - it 'does not call ConfigureWorker' do - expect(ClusterConfigureWorker).not_to receive(:perform_async) - - platform.username = "new-username" - platform.save - end - end - end end diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb index 0e34d8fccf3..96465a51db2 100644 --- a/spec/models/concerns/deployment_platform_spec.rb +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -8,40 +8,7 @@ describe DeploymentPlatform do describe '#deployment_platform' do subject { project.deployment_platform } - context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and a Kubernetes template configured' do - let!(:kubernetes_service) { create(:kubernetes_service, template: true) } - - it 'returns a platform kubernetes' do - expect(subject).to be_a_kind_of(Clusters::Platforms::Kubernetes) - end - - it 'creates a cluster and a platform kubernetes' do - expect { subject } - .to change { Clusters::Cluster.count }.by(1) - .and change { Clusters::Platforms::Kubernetes.count }.by(1) - end - - it 'includes appropriate attributes for Cluster' do - cluster = subject.cluster - expect(cluster.name).to eq('kubernetes-template') - expect(cluster.project).to eq(project) - expect(cluster.provider_type).to eq('user') - expect(cluster.platform_type).to eq('kubernetes') - end - - it 'creates a platform kubernetes' do - expect { subject }.to change { Clusters::Platforms::Kubernetes.count }.by(1) - end - - it 'copies attributes from Clusters::Platform::Kubernetes template into the new Cluster::Platforms::Kubernetes' do - expect(subject.api_url).to eq(kubernetes_service.api_url) - expect(subject.ca_pem).to eq(kubernetes_service.ca_pem) - expect(subject.token).to eq(kubernetes_service.token) - expect(subject.namespace).to eq(kubernetes_service.namespace) - end - end - - context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and no Kubernetes template configured' do + context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service' do it { is_expected.to be_nil } end @@ -126,23 +93,5 @@ describe DeploymentPlatform do end end end - - context 'when user configured kubernetes integration from project services' do - let!(:kubernetes_service) { create(:kubernetes_service, project: project) } - - it 'returns the Kubernetes service' do - expect(subject).to eq(kubernetes_service) - end - end - - context 'when the cluster creation fails' do - let!(:kubernetes_service) { create(:kubernetes_service, template: true) } - - before do - allow_any_instance_of(Clusters::Cluster).to receive(:persisted?).and_return(false) - end - - it { is_expected.to be_nil } - end end end diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index fdc81359d34..4fb7b71a3c7 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -356,6 +356,102 @@ describe PagesDomain do end end + describe '#user_provided_key' do + subject { domain.user_provided_key } + + context 'when certificate is provided by user' do + let(:domain) { create(:pages_domain) } + + it 'returns key' do + is_expected.to eq(domain.key) + end + end + + context 'when certificate is provided by gitlab' do + let(:domain) { create(:pages_domain, :letsencrypt) } + + it 'returns nil' do + is_expected.to be_nil + end + end + end + + describe '#user_provided_certificate' do + subject { domain.user_provided_certificate } + + context 'when certificate is provided by user' do + let(:domain) { create(:pages_domain) } + + it 'returns key' do + is_expected.to eq(domain.certificate) + end + end + + context 'when certificate is provided by gitlab' do + let(:domain) { create(:pages_domain, :letsencrypt) } + + it 'returns nil' do + is_expected.to be_nil + end + end + end + + shared_examples 'certificate setter' do |attribute, setter_name, old_certificate_source, new_certificate_source| + let(:domain) do + create(:pages_domain, certificate_source: old_certificate_source) + end + + let(:old_value) { domain.public_send(attribute) } + + subject { domain.public_send(setter_name, new_value) } + + context 'when value has been changed' do + let(:new_value) { 'new_value' } + + it "assignes new value to #{attribute}" do + expect do + subject + end.to change { domain.public_send(attribute) }.from(old_value).to('new_value') + end + + it 'changes certificate source' do + expect do + subject + end.to change { domain.certificate_source }.from(old_certificate_source).to(new_certificate_source) + end + end + + context 'when value has not been not changed' do + let(:new_value) { old_value } + + it 'does not change certificate source' do + expect do + subject + end.not_to change { domain.certificate_source }.from(old_certificate_source) + end + end + end + + describe '#user_provided_key=' do + include_examples('certificate setter', 'key', 'user_provided_key=', + 'gitlab_provided', 'user_provided') + end + + describe '#gitlab_provided_key=' do + include_examples('certificate setter', 'key', 'gitlab_provided_key=', + 'user_provided', 'gitlab_provided') + end + + describe '#user_provided_certificate=' do + include_examples('certificate setter', 'certificate', 'user_provided_certificate=', + 'gitlab_provided', 'user_provided') + end + + describe '#gitlab_provided_certificate=' do + include_examples('certificate setter', 'certificate', 'gitlab_provided_certificate=', + 'user_provided', 'gitlab_provided') + end + describe '.for_removal' do subject { described_class.for_removal } diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 34ee1eafd5c..5d7d6c34e67 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -7,7 +7,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers let(:project) { create(:kubernetes_project) } - let(:service) { project.deployment_platform } + let(:service) { create(:kubernetes_service, project: project) } describe 'Associations' do it { is_expected.to belong_to :project } @@ -78,7 +78,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do it 'includes an error with a deprecation message' do kubernetes_service.valid? - expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been deprecated/) + expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been disabled/) end end @@ -383,13 +383,13 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do let(:kubernetes_service) { create(:kubernetes_service) } it 'indicates the service is deprecated' do - expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been deprecated/) + expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been disabled/) end context 'if the service is not active' do it 'returns a message' do kubernetes_service.update_attribute(:active, false) - expect(kubernetes_service.deprecation_message).to match(/Fields on this page are now uneditable/) + expect(kubernetes_service.deprecation_message).to match(/Fields on this page are not used by GitLab/) end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 20b98b5eb85..cc0f5002a1e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2656,8 +2656,8 @@ describe Project do let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:project) { cluster.project } - it 'returns variables from this service' do - expect(project.deployment_variables).to include( + it 'does not return variables from this service' do + expect(project.deployment_variables).not_to include( { key: 'KUBE_TOKEN', value: project.deployment_platform.token, public: false, masked: true } ) end diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb index 3eb68a6abb6..449032b95b7 100644 --- a/spec/requests/api/pages_domains_spec.rb +++ b/spec/requests/api/pages_domains_spec.rb @@ -359,6 +359,14 @@ describe API::PagesDomains do expect(pages_domain_secure.certificate).to eq(params_secure_nokey[:certificate]) end + it 'updates certificate source to user_provided if is changed' do + pages_domain.update!(certificate_source: 'gitlab_provided') + + expect do + put api(route_domain, user), params: params_secure + end.to change { pages_domain.reload.certificate_source }.from('gitlab_provided').to('user_provided') + end + it 'fails to update pages domain adding certificate without key' do put api(route_domain, user), params: params_secure_nokey diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index a27c22191f4..ffbfac9b326 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -32,6 +32,19 @@ describe MergeRequestWidgetEntity do end end + describe 'issues links' do + it 'includes issues links when requested' do + data = described_class.new(resource, request: request, issues_links: true).as_json + + expect(data).to include(:issues_links) + expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing) + end + + it 'omits issue links by default' do + expect(subject).not_to include(:issues_links) + end + end + describe 'pipeline' do let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) } diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb index 2664649df47..5f91acb8e84 100644 --- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb +++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb @@ -19,10 +19,6 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do subject { described_class.new.execute(provider) } - before do - allow(ClusterConfigureWorker).to receive(:perform_async) - end - shared_examples 'success' do it 'configures provider and kubernetes' do subject @@ -42,12 +38,6 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do expect(platform.password).to eq(password) expect(platform.token).to eq(token) end - - it 'calls ClusterConfigureWorker in a ascync fashion' do - expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id) - - subject - end end shared_examples 'error' do diff --git a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb index a5806559b14..93c0dc37ade 100644 --- a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb +++ b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb @@ -17,7 +17,7 @@ describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do ) end - subject { described_class.new(kubeclient, service_account_token_name, namespace).execute } + subject { described_class.new(kubeclient, service_account_token_name, namespace, token_retry_delay: 0).execute } before do stub_kubeclient_discover(api_url) @@ -26,8 +26,7 @@ describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do context 'when params correct' do let(:decoded_token) { 'xxx.token.xxx' } let(:token) { Base64.encode64(decoded_token) } - - context 'when gitlab-token exists' do + context 'when the secret exists' do before do stub_kubeclient_get_secret( api_url, @@ -50,13 +49,62 @@ describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do it { expect { subject }.to raise_error(Kubeclient::HttpError) } end - context 'when gitlab-token does not exist' do + context 'when the secret does not exist on the first try' do + before do + stub_kubeclient_get_secret_not_found_then_found( + api_url, + { + metadata_name: service_account_token_name, + namespace: namespace, + token: token + } + ) + end + + it 'retries and finds the token' do + expect(subject).to eq(decoded_token) + end + end + + context 'when the secret permanently does not exist' do before do stub_kubeclient_get_secret_error(api_url, service_account_token_name, namespace: namespace, status: 404) end it { is_expected.to be_nil } end + + context 'when the secret is missing a token on the first try' do + before do + stub_kubeclient_get_secret_missing_token_then_with_token( + api_url, + { + metadata_name: service_account_token_name, + namespace: namespace, + token: token + } + ) + end + + it 'retries and finds the token' do + expect(subject).to eq(decoded_token) + end + end + + context 'when the secret is permanently missing a token' do + before do + stub_kubeclient_get_secret( + api_url, + { + metadata_name: service_account_token_name, + namespace: namespace, + token: nil + } + ) + end + + it { is_expected.to be_nil } + end end end end diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb index 21b37f88fd8..3ee45375dca 100644 --- a/spec/services/clusters/update_service_spec.rb +++ b/spec/services/clusters/update_service_spec.rb @@ -39,7 +39,6 @@ describe Clusters::UpdateService do end before do - allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end diff --git a/spec/services/issues/reorder_service_spec.rb b/spec/services/issues/reorder_service_spec.rb new file mode 100644 index 00000000000..b147cdf4e64 --- /dev/null +++ b/spec/services/issues/reorder_service_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Issues::ReorderService do + set(:user) { create(:user) } + set(:project) { create(:project) } + set(:group) { create(:group) } + + shared_examples 'issues reorder service' do + context 'when reordering issues' do + it 'returns false with no params' do + expect(service({}).execute(issue1)).to be_falsey + end + + it 'returns false with both invalid params' do + params = { move_after_id: nil, move_before_id: 1 } + + expect(service(params).execute(issue1)).to be_falsey + end + + it 'sorts issues' do + params = { move_after_id: issue2.id, move_before_id: issue3.id } + + service(params).execute(issue1) + + expect(issue1.relative_position) + .to be_between(issue2.relative_position, issue3.relative_position) + end + end + end + + describe '#execute' do + let(:issue1) { create(:issue, project: project, relative_position: 10) } + let(:issue2) { create(:issue, project: project, relative_position: 20) } + let(:issue3) { create(:issue, project: project, relative_position: 30) } + + context 'when ordering issues in a project' do + let(:parent) { project } + + before do + parent.add_developer(user) + end + + it_behaves_like 'issues reorder service' + end + + context 'when ordering issues in a group' do + let(:project) { create(:project, namespace: group) } + + before do + group.add_developer(user) + end + + it_behaves_like 'issues reorder service' + + context 'when ordering in a group issue list' do + let(:params) { { move_after_id: issue2.id, move_before_id: issue3.id, group_full_path: group.full_path } } + + subject { service(params) } + + it 'sends the board_group_id parameter' do + match_params = { move_between_ids: [issue2.id, issue3.id], board_group_id: group.id } + + expect(Issues::UpdateService) + .to receive(:new).with(project, user, match_params) + .and_return(double(execute: build(:issue))) + + subject.execute(issue1) + end + + it 'sorts issues' do + project2 = create(:project, namespace: group) + issue4 = create(:issue, project: project2) + + subject.execute(issue4) + + expect(issue4.relative_position) + .to be_between(issue2.relative_position, issue3.relative_position) + end + end + end + end + + def service(params) + described_class.new(project, user, params) + end +end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 22f5607cb9c..28fa5d12d9c 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -687,6 +687,22 @@ describe Issues::UpdateService, :mailer do end end + context 'when moving an issue ', :nested_groups do + it 'raises an error for invalid move ids within a project' do + opts = { move_between_ids: [9000, 9999] } + + expect { described_class.new(issue.project, user, opts).execute(issue) } + .to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises an error for invalid move ids within a group' do + opts = { move_between_ids: [9000, 9999], board_group_id: create(:group).id } + + expect { described_class.new(issue.project, user, opts).execute(issue) } + .to raise_error(ActiveRecord::RecordNotFound) + end + end + include_examples 'issuable update service' do let(:open_issuable) { issue } let(:closed_issuable) { create(:closed_issue, project: project) } 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 6d7be27939c..d5f77f3354b 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 @@ -137,6 +137,12 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do expect(pages_domain.certificate).to eq(certificate) end + it 'marks certificate as gitlab_provided' do + service.execute + + expect(pages_domain.certificate_source).to eq("gitlab_provided") + end + it 'removes order from database' do service.execute diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb index 011c4df0fe5..3c7bcba2b42 100644 --- a/spec/support/helpers/kubernetes_helpers.rb +++ b/spec/support/helpers/kubernetes_helpers.rb @@ -104,6 +104,26 @@ module KubernetesHelpers .to_return(status: [status, "Internal Server Error"]) end + def stub_kubeclient_get_secret_not_found_then_found(api_url, **options) + options[:metadata_name] ||= "default-token-1" + options[:namespace] ||= "default" + + WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{options[:namespace]}/secrets/#{options[:metadata_name]}") + .to_return(status: [404, "Not Found"]) + .then + .to_return(kube_response(kube_v1_secret_body(options))) + end + + def stub_kubeclient_get_secret_missing_token_then_with_token(api_url, **options) + options[:metadata_name] ||= "default-token-1" + options[:namespace] ||= "default" + + WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{options[:namespace]}/secrets/#{options[:metadata_name]}") + .to_return(kube_response(kube_v1_secret_body(options.merge(token: nil)))) + .then + .to_return(kube_response(kube_v1_secret_body(options))) + end + def stub_kubeclient_get_service_account(api_url, name, namespace: 'default') WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}") .to_return(kube_response({})) @@ -184,11 +204,11 @@ module KubernetesHelpers "kind" => "SecretList", "apiVersion": "v1", "metadata": { - "name": options[:metadata_name] || "default-token-1", + "name": options.fetch(:metadata_name, "default-token-1"), "namespace": "kube-system" }, "data": { - "token": options[:token] || Base64.encode64('token-sample-123') + "token": options.fetch(:token, Base64.encode64('token-sample-123')) } } end diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index f985b2dcbba..7993b2870e5 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -5,7 +5,7 @@ shared_examples_for 'common trace features' do end it "returns formatted html" do - expect(trace.html).to eq("<span class=\"\">12<br/><span class=\"\">34</span></span>") + expect(trace.html).to eq("<span class=\"\">12</span><br/><span class=\"\">34</span>") end it "returns last line of formatted html" do diff --git a/spec/support/shared_examples/notify_shared_examples.rb b/spec/support/shared_examples/notify_shared_examples.rb index 897c9106d77..6894a63ce42 100644 --- a/spec/support/shared_examples/notify_shared_examples.rb +++ b/spec/support/shared_examples/notify_shared_examples.rb @@ -281,18 +281,8 @@ shared_examples 'a note email' do is_expected.to have_body_text note.note end - it 'does not contain note author' do - is_expected.not_to have_body_text note.author_name - end - - context 'when enabled email_author_in_body' do - before do - stub_application_setting(email_author_in_body: true) - end - - it 'contains a link to note author' do - is_expected.to have_body_text note.author_name - end + it 'contains a link to note author' do + is_expected.to have_body_text note.author_name end end diff --git a/spec/tasks/gitlab/check_rake_spec.rb b/spec/tasks/gitlab/check_rake_spec.rb index 06525e3c771..0fcb9b269f3 100644 --- a/spec/tasks/gitlab/check_rake_spec.rb +++ b/spec/tasks/gitlab/check_rake_spec.rb @@ -96,6 +96,15 @@ describe 'check.rake' do subject end + + it 'sanitizes output' do + user = double(dn: 'uid=fake_user1', uid: 'fake_user1') + allow(adapter).to receive(:users).and_return([user]) + stub_env('SANITIZE', 'true') + + expect { subject }.to output(/User output sanitized/).to_stdout + expect { subject }.not_to output('fake_user1').to_stdout + end end end end diff --git a/spec/workers/cluster_provision_worker_spec.rb b/spec/workers/cluster_provision_worker_spec.rb index 9cc2ad12bfc..3f69962f25d 100644 --- a/spec/workers/cluster_provision_worker_spec.rb +++ b/spec/workers/cluster_provision_worker_spec.rb @@ -23,18 +23,11 @@ describe ClusterProvisionWorker do described_class.new.perform(cluster.id) end - - it 'configures kubernetes platform' do - expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id) - - described_class.new.perform(cluster.id) - end end context 'when cluster does not exist' do it 'does not provision a cluster' do expect_any_instance_of(Clusters::Gcp::ProvisionService).not_to receive(:execute) - expect(ClusterConfigureWorker).not_to receive(:perform_async) described_class.new.perform(123) end |