From 26384c9a61da9922b8fa4b8351d4e42d51661b37 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 5 Feb 2020 09:08:43 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../concerns/confirm_email_warning_spec.rb | 4 - .../dashboard/snippets_controller_spec.rb | 9 + .../projects/snippets_controller_spec.rb | 9 + spec/controllers/registrations_controller_spec.rb | 30 +--- spec/factories/serverless/domain_cluster.rb | 36 ++++ spec/features/dashboard/snippets_spec.rb | 4 + spec/features/invites_spec.rb | 46 +---- .../merge_request/user_sees_versions_spec.rb | 26 ++- .../projects/snippets/user_views_snippets_spec.rb | 10 ++ spec/features/users/login_spec.rb | 1 - spec/features/users/signup_spec.rb | 68 ++----- .../diffs/components/compare_versions_spec.js | 3 +- spec/frontend/diffs/components/diff_stats_spec.js | 12 +- .../components/error_details_spec.js | 82 +++++---- .../components/error_tracking_list_spec.js | 4 +- .../error_tracking/store/details/actions_spec.js | 47 ----- spec/frontend/jobs/components/log/mock_data.js | 2 +- .../helpers/projects/error_tracking_helper_spec.rb | 5 - spec/lib/gitlab/kubernetes/generic_secret_spec.rb | 24 +++ spec/lib/gitlab/kubernetes/tls_secret_spec.rb | 32 ++++ spec/lib/gitlab/utils/deep_size_spec.rb | 38 ++-- spec/models/serverless/domain_cluster_spec.rb | 8 + .../configure_istio_ingress_service_spec.rb | 197 +++++++++++++++++++++ spec/services/snippets/count_service_spec.rb | 66 +++++++ .../features/snippets_shared_examples.rb | 32 ++++ .../workers/cluster_configure_istio_worker_spec.rb | 41 +++++ 26 files changed, 586 insertions(+), 250 deletions(-) create mode 100644 spec/lib/gitlab/kubernetes/generic_secret_spec.rb create mode 100644 spec/lib/gitlab/kubernetes/tls_secret_spec.rb create mode 100644 spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb create mode 100644 spec/services/snippets/count_service_spec.rb create mode 100644 spec/workers/cluster_configure_istio_worker_spec.rb (limited to 'spec') diff --git a/spec/controllers/concerns/confirm_email_warning_spec.rb b/spec/controllers/concerns/confirm_email_warning_spec.rb index 93e3423261c..2aad380203b 100644 --- a/spec/controllers/concerns/confirm_email_warning_spec.rb +++ b/spec/controllers/concerns/confirm_email_warning_spec.rb @@ -3,10 +3,6 @@ require 'spec_helper' describe ConfirmEmailWarning do - before do - stub_feature_flags(soft_email_confirmation: true) - end - controller(ApplicationController) do # `described_class` is not available in this context include ConfirmEmailWarning diff --git a/spec/controllers/dashboard/snippets_controller_spec.rb b/spec/controllers/dashboard/snippets_controller_spec.rb index 2d839094d34..d5e3a348cd2 100644 --- a/spec/controllers/dashboard/snippets_controller_spec.rb +++ b/spec/controllers/dashboard/snippets_controller_spec.rb @@ -17,5 +17,14 @@ describe Dashboard::SnippetsController do create(:personal_snippet, :public, author: user) end end + + it 'fetches snippet counts via the snippet count service' do + service = double(:count_service, execute: {}) + expect(Snippets::CountService) + .to receive(:new).with(user, author: user) + .and_return(service) + + get :index + end end end diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 0a8aa60ee02..4d1537ae787 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -27,6 +27,15 @@ describe Projects::SnippetsController do end end + it 'fetches snippet counts via the snippet count service' do + service = double(:count_service, execute: {}) + expect(Snippets::CountService) + .to receive(:new).with(nil, project: project) + .and_return(service) + + get :index, params: { namespace_id: project.namespace, project_id: project } + end + context 'when the project snippet is private' do let!(:project_snippet) { create(:project_snippet, :private, project: project, author: user) } diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index d7fe3e87056..e36d87a7224 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -77,34 +77,14 @@ describe RegistrationsController do context 'when send_user_confirmation_email is true' do before do stub_application_setting(send_user_confirmation_email: true) + allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days end - context 'when soft email confirmation is not enabled' do - before do - stub_feature_flags(soft_email_confirmation: false) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 - end - - it 'does not authenticate the user and sends a confirmation email' do - post(:create, params: user_params) - - expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) - expect(subject.current_user).to be_nil - end - end + it 'authenticates the user and sends a confirmation email' do + post(:create, params: user_params) - context 'when soft email confirmation is enabled' do - before do - stub_feature_flags(soft_email_confirmation: true) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days - end - - it 'authenticates the user and sends a confirmation email' do - post(:create, params: user_params) - - expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) - expect(response).to redirect_to(dashboard_projects_path) - end + expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) + expect(response).to redirect_to(dashboard_projects_path) end end diff --git a/spec/factories/serverless/domain_cluster.rb b/spec/factories/serverless/domain_cluster.rb index c44295e2405..bc32552d4c7 100644 --- a/spec/factories/serverless/domain_cluster.rb +++ b/spec/factories/serverless/domain_cluster.rb @@ -5,5 +5,41 @@ FactoryBot.define do pages_domain { create(:pages_domain) } knative { create(:clusters_applications_knative) } creator { create(:user) } + + certificate do + '-----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-----' + end + + key do + '-----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-----' + end end end diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index 94dc8601abb..eb9d722e164 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -59,6 +59,10 @@ describe 'Dashboard snippets' do visit dashboard_snippets_path end + it_behaves_like 'tabs with counts' do + let_it_be(:counts) { { all: '3', public: '1', private: '1', internal: '1' } } + end + it 'contains all snippets of logged user' do expect(page).to have_selector('.snippet-row', count: 3) diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index 2a1980346e9..0571ab007e9 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -153,24 +153,6 @@ describe 'Invites' do context 'email confirmation enabled' do let(:send_email_confirmation) { true } - context 'when soft email confirmation is not enabled' do - before do - # stub_feature_flags(soft_email_confirmation: false) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 - end - - it 'signs up and redirects to root page with all the project/groups invitation automatically accepted' do - fill_in_sign_up_form(new_user) - confirm_email(new_user) - fill_in_sign_in_form(new_user) - - expect(current_path).to eq(root_path) - expect(page).to have_content(project.full_name) - visit group_path(group) - expect(page).to have_content(group.full_name) - end - end - context 'when soft email confirmation is enabled' do before do allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days @@ -198,32 +180,14 @@ describe 'Invites' do context 'the user sign-up using a different email address' do let(:invite_email) { build_stubbed(:user).email } - context 'when soft email confirmation is not enabled' do - before do - stub_feature_flags(soft_email_confirmation: false) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 - end - - it 'signs up and redirects to the invitation page' do - fill_in_sign_up_form(new_user) - confirm_email(new_user) - fill_in_sign_in_form(new_user) - - expect(current_path).to eq(invite_path(group_invite.raw_invite_token)) - end + before do + allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days end - context 'when soft email confirmation is enabled' do - before do - stub_feature_flags(soft_email_confirmation: true) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days - end - - it 'signs up and redirects to the invitation page' do - fill_in_sign_up_form(new_user) + it 'signs up and redirects to the invitation page' do + fill_in_sign_up_form(new_user) - expect(current_path).to eq(invite_path(group_invite.raw_invite_token)) - end + expect(current_path).to eq(invite_path(group_invite.raw_invite_token)) end end end diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index cab86f3fd94..cd62bab412a 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -50,7 +50,7 @@ describe 'Merge request > User sees versions', :js do expect(page).to have_content 'latest version' end - expect(page).to have_content '8 Files' + expect(page).to have_content '8 files' end it_behaves_like 'allows commenting', @@ -84,7 +84,7 @@ describe 'Merge request > User sees versions', :js do end it 'shows comments that were last relevant at that version' do - expect(page).to have_content '5 Files' + expect(page).to have_content '5 files' position = Gitlab::Diff::Position.new( old_path: ".gitmodules", @@ -128,12 +128,10 @@ describe 'Merge request > User sees versions', :js do diff_id: merge_request_diff3.id, start_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' ) - expect(page).to have_content '4 Files' + expect(page).to have_content '4 files' - additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-addition') - .ancestor('.diff-stats-group').text - deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-deletion') - .ancestor('.diff-stats-group').text + additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-addition-line').text + deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-deletion-line').text expect(additions_content).to eq '15' expect(deletions_content).to eq '6' @@ -156,12 +154,10 @@ describe 'Merge request > User sees versions', :js do end it 'show diff between new and old version' do - additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-addition') - .ancestor('.diff-stats-group').text - deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-deletion') - .ancestor('.diff-stats-group').text + additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-addition-line').text + deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-deletion-line').text - expect(page).to have_content '4 Files' + expect(page).to have_content '4 files' expect(additions_content).to eq '15' expect(deletions_content).to eq '6' end @@ -171,7 +167,7 @@ describe 'Merge request > User sees versions', :js do page.within '.mr-version-dropdown' do expect(page).to have_content 'latest version' end - expect(page).to have_content '8 Files' + expect(page).to have_content '8 files' end it_behaves_like 'allows commenting', @@ -197,7 +193,7 @@ describe 'Merge request > User sees versions', :js do find('.btn-default').click click_link 'version 1' end - expect(page).to have_content '0 Files' + expect(page).to have_content '0 files' end end @@ -223,7 +219,7 @@ describe 'Merge request > User sees versions', :js do expect(page).to have_content 'version 1' end - expect(page).to have_content '0 Files' + expect(page).to have_content '0 files' end end diff --git a/spec/features/projects/snippets/user_views_snippets_spec.rb b/spec/features/projects/snippets/user_views_snippets_spec.rb index a02f7f8a8d2..22910029ee5 100644 --- a/spec/features/projects/snippets/user_views_snippets_spec.rb +++ b/spec/features/projects/snippets/user_views_snippets_spec.rb @@ -31,6 +31,16 @@ describe 'Projects > Snippets > User views snippets' do it_behaves_like 'paginated snippets' end + context 'filtering by visibility' do + before do + visit_project_snippets + end + + it_behaves_like 'tabs with counts' do + let_it_be(:counts) { { all: '1', public: '0', private: '1', internal: '0' } } + end + end + it 'shows snippets' do visit_project_snippets diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index 5a8db3c070d..0bef61a4854 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -797,7 +797,6 @@ describe 'Login' do before do stub_application_setting(send_user_confirmation_email: true) - stub_feature_flags(soft_email_confirmation: true) allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period end diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index daa987ea389..8d5c0657fa5 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -129,63 +129,29 @@ shared_examples 'Signup' do stub_application_setting(send_user_confirmation_email: true) end - context 'when soft email confirmation is not enabled' do - before do - stub_feature_flags(soft_email_confirmation: false) - end - - it 'creates the user account and sends a confirmation email' do - visit new_user_registration_path - - fill_in 'new_user_username', with: new_user.username - fill_in 'new_user_email', with: new_user.email - - if Gitlab::Experimentation.enabled?(:signup_flow) - fill_in 'new_user_first_name', with: new_user.first_name - fill_in 'new_user_last_name', with: new_user.last_name - else - fill_in 'new_user_name', with: new_user.name - fill_in 'new_user_email_confirmation', with: new_user.email - end - - fill_in 'new_user_password', with: new_user.password - - expect { click_button 'Register' }.to change { User.count }.by(1) + it 'creates the user account and sends a confirmation email' do + visit new_user_registration_path - expect(current_path).to eq users_almost_there_path - expect(page).to have_content('Please check your email to confirm your account') - end - end + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email - context 'when soft email confirmation is enabled' do - before do - stub_feature_flags(soft_email_confirmation: true) + if Gitlab::Experimentation.enabled?(:signup_flow) + fill_in 'new_user_first_name', with: new_user.first_name + fill_in 'new_user_last_name', with: new_user.last_name + else + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_email_confirmation', with: new_user.email end - it 'creates the user account and sends a confirmation email' do - visit new_user_registration_path - - fill_in 'new_user_username', with: new_user.username - fill_in 'new_user_email', with: new_user.email - - if Gitlab::Experimentation.enabled?(:signup_flow) - fill_in 'new_user_first_name', with: new_user.first_name - fill_in 'new_user_last_name', with: new_user.last_name - else - fill_in 'new_user_name', with: new_user.name - fill_in 'new_user_email_confirmation', with: new_user.email - end - - fill_in 'new_user_password', with: new_user.password + fill_in 'new_user_password', with: new_user.password - expect { click_button 'Register' }.to change { User.count }.by(1) + expect { click_button 'Register' }.to change { User.count }.by(1) - if Gitlab::Experimentation.enabled?(:signup_flow) - expect(current_path).to eq users_sign_up_welcome_path - else - expect(current_path).to eq dashboard_projects_path - expect(page).to have_content("Please check your email (#{new_user.email}) to verify that you own this address and unlock the power of CI/CD.") - end + if Gitlab::Experimentation.enabled?(:signup_flow) + expect(current_path).to eq users_sign_up_welcome_path + else + expect(current_path).to eq dashboard_projects_path + expect(page).to have_content("Please check your email (#{new_user.email}) to verify that you own this address and unlock the power of CI/CD.") end end end diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 5f919408459..ff92a12eaf6 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -49,8 +49,7 @@ describe('CompareVersions', () => { expect(treeListBtn.exists()).toBe(true); expect(treeListBtn.attributes('title')).toBe('Hide file browser'); - expect(treeListBtn.findAll(Icon).length).not.toBe(0); - expect(treeListBtn.find(Icon).props('name')).toBe('collapse-left'); + expect(treeListBtn.find(Icon).props('name')).toBe('file-tree'); }); it('should render comparison dropdowns with correct values', () => { diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 0dffc74f608..5956b478019 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -1,6 +1,6 @@ import { shallowMount } from '@vue/test-utils'; -import Icon from '~/vue_shared/components/icon.vue'; import DiffStats from '~/diffs/components/diff_stats.vue'; +import Icon from '~/vue_shared/components/icon.vue'; describe('diff_stats', () => { it('does not render a group if diffFileLengths is empty', () => { @@ -37,18 +37,18 @@ describe('diff_stats', () => { }, }); + const findFileLine = name => wrapper.find(name); const findIcon = name => wrapper .findAll(Icon) .filter(c => c.attributes('name') === name) .at(0).element.parentNode; - - const additions = findIcon('file-addition'); - const deletions = findIcon('file-deletion'); + const additions = findFileLine('.js-file-addition-line'); + const deletions = findFileLine('.js-file-deletion-line'); const filesChanged = findIcon('doc-code'); - expect(additions.textContent).toContain('100'); - expect(deletions.textContent).toContain('200'); + expect(additions.text()).toBe('100'); + expect(deletions.text()).toBe('200'); expect(filesChanged.textContent).toContain('300'); }); }); diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index cfb9ce51979..94bf0189c91 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -37,14 +37,13 @@ describe('ErrorDetails', () => { projectPath: '/root/gitlab-test', listPath: '/error_tracking', issueUpdatePath: '/123', - issueDetailsPath: '/123/details', issueStackTracePath: '/stacktrace', projectIssuesPath: '/test-project/issues/', csrfToken: 'fakeToken', }, }); wrapper.setData({ - GQLerror: { + error: { id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381', sentryId: 129381, title: 'Issue title', @@ -59,7 +58,6 @@ describe('ErrorDetails', () => { beforeEach(() => { actions = { - startPollingDetails: () => {}, startPollingStacktrace: () => {}, updateIgnoreStatus: jest.fn(), updateResolveStatus: jest.fn().mockResolvedValue({ closed_issue_iid: 1 }), @@ -71,8 +69,6 @@ describe('ErrorDetails', () => { }; const state = { - error: {}, - loading: true, stacktraceData: {}, loadingStacktrace: true, }; @@ -93,7 +89,7 @@ describe('ErrorDetails', () => { $apollo: { query, queries: { - GQLerror: { + error: { loading: true, stopPolling: jest.fn(), }, @@ -122,9 +118,7 @@ describe('ErrorDetails', () => { describe('Error details', () => { beforeEach(() => { - store.state.details.loading = false; - store.state.details.error.id = 1; - mocks.$apollo.queries.GQLerror.loading = false; + mocks.$apollo.queries.error.loading = false; mountComponent(); }); @@ -138,16 +132,22 @@ describe('ErrorDetails', () => { describe('Badges', () => { it('should show language and error level badges', () => { - store.state.details.error.tags = { level: 'error', logger: 'ruby' }; - mountComponent(); + wrapper.setData({ + error: { + tags: { level: 'error', logger: 'ruby' }, + }, + }); return wrapper.vm.$nextTick().then(() => { expect(wrapper.findAll(GlBadge).length).toBe(2); }); }); it('should NOT show the badge if the tag is not present', () => { - store.state.details.error.tags = { level: 'error' }; - mountComponent(); + wrapper.setData({ + error: { + tags: { level: 'error' }, + }, + }); return wrapper.vm.$nextTick().then(() => { expect(wrapper.findAll(GlBadge).length).toBe(1); }); @@ -156,8 +156,11 @@ describe('ErrorDetails', () => { it.each(Object.keys(severityLevel))( 'should set correct severity level variant for %s badge', level => { - store.state.details.error.tags = { level: severityLevel[level] }; - mountComponent(); + wrapper.setData({ + error: { + tags: { level: severityLevel[level] }, + }, + }); return wrapper.vm.$nextTick().then(() => { expect(wrapper.find(GlBadge).attributes('variant')).toEqual( severityLevelVariant[severityLevel[level]], @@ -167,8 +170,11 @@ describe('ErrorDetails', () => { ); it('should fallback for ERROR severityLevelVariant when severityLevel is unknown', () => { - store.state.details.error.tags = { level: 'someNewErrorLevel' }; - mountComponent(); + wrapper.setData({ + error: { + tags: { level: 'someNewErrorLevel' }, + }, + }); return wrapper.vm.$nextTick().then(() => { expect(wrapper.find(GlBadge).attributes('variant')).toEqual( severityLevelVariant[severityLevel.ERROR], @@ -180,7 +186,6 @@ describe('ErrorDetails', () => { describe('Stacktrace', () => { it('should show stacktrace', () => { store.state.details.loadingStacktrace = false; - mountComponent(); return wrapper.vm.$nextTick().then(() => { expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); expect(wrapper.find(Stacktrace).exists()).toBe(true); @@ -190,9 +195,10 @@ describe('ErrorDetails', () => { it('should NOT show stacktrace if no entries', () => { store.state.details.loadingStacktrace = false; store.getters = { 'details/sentryUrl': () => 'sentry.io', 'details/stacktrace': () => [] }; - mountComponent(); - expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); - expect(wrapper.find(Stacktrace).exists()).toBe(false); + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); + expect(wrapper.find(Stacktrace).exists()).toBe(false); + }); }); }); @@ -331,19 +337,18 @@ describe('ErrorDetails', () => { }); describe('GitLab issue link', () => { - const gitlabIssue = 'https://gitlab.example.com/issues/1'; - const findGitLabLink = () => wrapper.find(`[href="${gitlabIssue}"]`); + const gitlabIssuePath = 'https://gitlab.example.com/issues/1'; + const findGitLabLink = () => wrapper.find(`[href="${gitlabIssuePath}"]`); const findCreateIssueButton = () => wrapper.find('[data-qa-selector="create_issue_button"]'); const findViewIssueButton = () => wrapper.find('[data-qa-selector="view_issue_button"]'); describe('is present', () => { beforeEach(() => { - store.state.details.loading = false; - store.state.details.error = { - id: 1, - gitlab_issue: gitlabIssue, - }; - mountComponent(); + wrapper.setData({ + error: { + gitlabIssuePath, + }, + }); }); it('should display the View issue button', () => { @@ -361,12 +366,11 @@ describe('ErrorDetails', () => { describe('is not present', () => { beforeEach(() => { - store.state.details.loading = false; - store.state.details.error = { - id: 1, - gitlab_issue: null, - }; - mountComponent(); + wrapper.setData({ + error: { + gitlabIssuePath: null, + }, + }); }); it('should not display the View issue button', () => { @@ -390,9 +394,9 @@ describe('ErrorDetails', () => { const findGitLabCommitLink = () => wrapper.find(`[href$="${gitlabCommitPath}"]`); it('should display a link', () => { - mocks.$apollo.queries.GQLerror.loading = false; + mocks.$apollo.queries.error.loading = false; wrapper.setData({ - GQLerror: { + error: { gitlabCommit, gitlabCommitPath, }, @@ -403,9 +407,9 @@ describe('ErrorDetails', () => { }); it('should not display a link', () => { - mocks.$apollo.queries.GQLerror.loading = false; + mocks.$apollo.queries.error.loading = false; wrapper.setData({ - GQLerror: { + error: { gitlabCommit: null, }, }); diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js index 310cd676ca1..9cf73d54d9b 100644 --- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js +++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js @@ -239,7 +239,7 @@ describe('ErrorTrackingList', () => { expect(actions.updateStatus).toHaveBeenCalledWith( expect.anything(), { - endpoint: '/project/test/-/error_tracking/3.json', + endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`, redirectUrl: '/error_tracking', status: 'ignored', }, @@ -267,7 +267,7 @@ describe('ErrorTrackingList', () => { expect(actions.updateStatus).toHaveBeenCalledWith( expect.anything(), { - endpoint: '/project/test/-/error_tracking/3.json', + endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`, redirectUrl: '/error_tracking', status: 'resolved', }, diff --git a/spec/frontend/error_tracking/store/details/actions_spec.js b/spec/frontend/error_tracking/store/details/actions_spec.js index fa37886f176..6802300b0f5 100644 --- a/spec/frontend/error_tracking/store/details/actions_spec.js +++ b/spec/frontend/error_tracking/store/details/actions_spec.js @@ -26,53 +26,6 @@ describe('Sentry error details store actions', () => { } }); - describe('startPollingDetails', () => { - const endpoint = '123/details'; - it('should commit SET_ERROR with received response', done => { - const payload = { error: { id: 1 } }; - mockedAdapter.onGet().reply(200, payload); - testAction( - actions.startPollingDetails, - { endpoint }, - {}, - [ - { type: types.SET_ERROR, payload: payload.error }, - { type: types.SET_LOADING, payload: false }, - ], - [], - () => { - done(); - }, - ); - }); - - it('should show flash on API error', done => { - mockedAdapter.onGet().reply(400); - - testAction( - actions.startPollingDetails, - { endpoint }, - {}, - [{ type: types.SET_LOADING, payload: false }], - [], - () => { - expect(createFlash).toHaveBeenCalledTimes(1); - done(); - }, - ); - }); - - it('should not restart polling when receiving an empty 204 response', done => { - mockedRestart = jest.spyOn(Poll.prototype, 'restart'); - mockedAdapter.onGet().reply(204); - - testAction(actions.startPollingDetails, { endpoint }, {}, [], [], () => { - expect(mockedRestart).toHaveBeenCalledTimes(0); - done(); - }); - }); - }); - describe('startPollingStacktrace', () => { const endpoint = '123/stacktrace'; it('should commit SET_ERROR with received response', done => { diff --git a/spec/frontend/jobs/components/log/mock_data.js b/spec/frontend/jobs/components/log/mock_data.js index 587818045eb..cdf5a3e10b1 100644 --- a/spec/frontend/jobs/components/log/mock_data.js +++ b/spec/frontend/jobs/components/log/mock_data.js @@ -34,7 +34,7 @@ export const utilsMockData = [ content: [ { text: - 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33', + 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.34', }, ], section: 'prepare-executor', diff --git a/spec/helpers/projects/error_tracking_helper_spec.rb b/spec/helpers/projects/error_tracking_helper_spec.rb index d4dcd7eb54e..38a6ef6826b 100644 --- a/spec/helpers/projects/error_tracking_helper_spec.rb +++ b/spec/helpers/projects/error_tracking_helper_spec.rb @@ -83,7 +83,6 @@ describe Projects::ErrorTrackingHelper do describe '#error_details_data' do let(:issue_id) { 1234 } let(:route_params) { [project.owner, project, issue_id, { format: :json }] } - let(:details_path) { details_namespace_project_error_tracking_index_path(*route_params) } let(:project_path) { project.full_path } let(:stack_trace_path) { stack_trace_namespace_project_error_tracking_index_path(*route_params) } let(:issues_path) { project_issues_path(project) } @@ -98,10 +97,6 @@ describe Projects::ErrorTrackingHelper do expect(result['project-path']).to eq project_path end - it 'returns the correct details path' do - expect(result['issue-details-path']).to eq details_path - end - it 'returns the correct stack trace path' do expect(result['issue-stack-trace-path']).to eq stack_trace_path end diff --git a/spec/lib/gitlab/kubernetes/generic_secret_spec.rb b/spec/lib/gitlab/kubernetes/generic_secret_spec.rb new file mode 100644 index 00000000000..fe1d4cc11e6 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/generic_secret_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Kubernetes::GenericSecret do + let(:secret) { described_class.new(name, data, namespace) } + let(:name) { 'example-name' } + let(:data) { 'example-data' } + let(:namespace) { 'example-namespace' } + + describe '#generate' do + subject { secret.generate } + + let(:resource) do + ::Kubeclient::Resource.new( + type: 'Opaque', + metadata: { name: name, namespace: namespace }, + data: data + ) + end + + it { is_expected.to eq(resource) } + end +end diff --git a/spec/lib/gitlab/kubernetes/tls_secret_spec.rb b/spec/lib/gitlab/kubernetes/tls_secret_spec.rb new file mode 100644 index 00000000000..438a0dc79fc --- /dev/null +++ b/spec/lib/gitlab/kubernetes/tls_secret_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Kubernetes::TlsSecret do + let(:secret) { described_class.new(name, cert, key, namespace) } + let(:name) { 'example-name' } + let(:cert) { 'example-cert' } + let(:key) { 'example-key' } + let(:namespace) { 'example-namespace' } + + let(:data) do + { + 'tls.crt': Base64.strict_encode64(cert), + 'tls.key': Base64.strict_encode64(key) + } + end + + describe '#generate' do + subject { secret.generate } + + let(:resource) do + ::Kubeclient::Resource.new( + type: 'kubernetes.io/tls', + metadata: { name: name, namespace: namespace }, + data: data + ) + end + + it { is_expected.to eq(resource) } + end +end diff --git a/spec/lib/gitlab/utils/deep_size_spec.rb b/spec/lib/gitlab/utils/deep_size_spec.rb index ccd202b33f7..5a155fb6c80 100644 --- a/spec/lib/gitlab/utils/deep_size_spec.rb +++ b/spec/lib/gitlab/utils/deep_size_spec.rb @@ -17,29 +17,45 @@ describe Gitlab::Utils::DeepSize do let(:max_size) { 1.kilobyte } let(:max_depth) { 10 } - let(:deep_size) { described_class.new(data, max_size: max_size, max_depth: max_depth) } - describe '#evaluate' do - context 'when data within size and depth limits' do - it 'returns true' do - expect(deep_size).to be_valid + subject(:deep_size) { described_class.new(data, max_size: max_size, max_depth: max_depth) } + + it { expect(described_class::DEFAULT_MAX_SIZE).to eq(1.megabyte) } + it { expect(described_class::DEFAULT_MAX_DEPTH).to eq(100) } + + describe '#initialize' do + context 'when max_size is nil' do + let(:max_size) { nil } + + it 'sets max_size to DEFAULT_MAX_SIZE' do + expect(subject.instance_variable_get(:@max_size)).to eq(described_class::DEFAULT_MAX_SIZE) + end + end + + context 'when max_depth is nil' do + let(:max_depth) { nil } + + it 'sets max_depth to DEFAULT_MAX_DEPTH' do + expect(subject.instance_variable_get(:@max_depth)).to eq(described_class::DEFAULT_MAX_DEPTH) end end + end + + describe '#valid?' do + context 'when data within size and depth limits' do + it { is_expected.to be_valid } + end context 'when data not within size limit' do let(:max_size) { 200.bytes } - it 'returns false' do - expect(deep_size).not_to be_valid - end + it { is_expected.not_to be_valid } end context 'when data not within depth limit' do let(:max_depth) { 2 } - it 'returns false' do - expect(deep_size).not_to be_valid - end + it { is_expected.not_to be_valid } end end diff --git a/spec/models/serverless/domain_cluster_spec.rb b/spec/models/serverless/domain_cluster_spec.rb index 9bc5c04678b..bd645b7d0aa 100644 --- a/spec/models/serverless/domain_cluster_spec.rb +++ b/spec/models/serverless/domain_cluster_spec.rb @@ -50,4 +50,12 @@ describe ::Serverless::DomainCluster do describe 'domain' do it { is_expected.to respond_to(:domain) } end + + describe 'certificate' do + it { is_expected.to respond_to(:certificate) } + end + + describe 'key' do + it { is_expected.to respond_to(:key) } + end end diff --git a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb new file mode 100644 index 00000000000..572e2b91187 --- /dev/null +++ b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do + include KubernetesHelpers + + let(:cluster) { create(:cluster, :project, :provided_by_gcp) } + let(:api_url) { 'https://kubernetes.example.com' } + let(:project) { cluster.project } + let(:environment) { create(:environment, project: project) } + let(:cluster_project) { cluster.cluster_project } + let(:namespace) { "#{project.name}-#{project.id}-#{environment.slug}" } + let(:kubeclient) { cluster.kubeclient } + + subject do + described_class.new( + cluster: cluster + ).execute + end + + before do + stub_kubeclient_discover_istio(api_url) + stub_kubeclient_create_secret(api_url, namespace: namespace) + stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace) + + stub_kubeclient_get_secret( + api_url, + { + metadata_name: "#{namespace}-token", + token: Base64.encode64('sample-token'), + namespace: namespace + } + ) + + stub_kubeclient_get_secret( + api_url, + { + metadata_name: 'istio-ingressgateway-ca-certs', + namespace: 'istio-system' + } + ) + + stub_kubeclient_get_secret( + api_url, + { + metadata_name: 'istio-ingressgateway-certs', + namespace: 'istio-system' + } + ) + + stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-ca-certs', namespace: 'istio-system') + stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-certs', namespace: 'istio-system') + stub_kubeclient_get_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving') + stub_kubeclient_put_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving') + end + + context 'without a serverless_domain_cluster' do + it 'configures gateway to use PASSTHROUGH' do + subject + + expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with( + body: hash_including( + apiVersion: "networking.istio.io/v1alpha3", + kind: "Gateway", + metadata: { + generation: 1, + labels: { + "networking.knative.dev/ingress-provider" => "istio", + "serving.knative.dev/release" => "v0.7.0" + }, + name: "knative-ingress-gateway", + namespace: "knative-serving", + selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway" + }, + spec: { + selector: { + istio: "ingressgateway" + }, + servers: [ + { + hosts: ["*"], + port: { + name: "http", + number: 80, + protocol: "HTTP" + } + }, + { + hosts: ["*"], + port: { + name: "https", + number: 443, + protocol: "HTTPS" + }, + tls: { + mode: "PASSTHROUGH" + } + } + ] + } + ) + ) + end + end + + context 'with a serverless_domain_cluster' do + let(:serverless_domain_cluster) { create(:serverless_domain_cluster) } + let(:certificate) { OpenSSL::X509::Certificate.new(serverless_domain_cluster.certificate) } + + before do + cluster.application_knative = serverless_domain_cluster.knative + end + + it 'configures certificates' do + subject + + expect(serverless_domain_cluster.reload.key).not_to be_blank + expect(serverless_domain_cluster.reload.certificate).not_to be_blank + + expect(certificate.subject.to_s).to include(serverless_domain_cluster.knative.hostname) + + expect(certificate.not_before).to be_within(1.minute).of(Time.now) + expect(certificate.not_after).to be_within(1.minute).of(Time.now + 1000.years) + + expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-ca-certs').with( + body: hash_including( + metadata: { + name: 'istio-ingressgateway-ca-certs', + namespace: 'istio-system' + }, + type: 'Opaque' + ) + ) + + expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-certs').with( + body: hash_including( + metadata: { + name: 'istio-ingressgateway-certs', + namespace: 'istio-system' + }, + type: 'kubernetes.io/tls' + ) + ) + end + + it 'configures gateway to use MUTUAL' do + subject + + expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with( + body: { + apiVersion: "networking.istio.io/v1alpha3", + kind: "Gateway", + metadata: { + generation: 1, + labels: { + "networking.knative.dev/ingress-provider" => "istio", + "serving.knative.dev/release" => "v0.7.0" + }, + name: "knative-ingress-gateway", + namespace: "knative-serving", + selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway" + }, + spec: { + selector: { + istio: "ingressgateway" + }, + servers: [ + { + hosts: ["*"], + port: { + name: "http", + number: 80, + protocol: "HTTP" + } + }, + { + hosts: ["*"], + port: { + name: "https", + number: 443, + protocol: "HTTPS" + }, + tls: { + mode: "MUTUAL", + privateKey: "/etc/istio/ingressgateway-certs/tls.key", + serverCertificate: "/etc/istio/ingressgateway-certs/tls.crt", + caCertificates: "/etc/istio/ingressgateway-ca-certs/cert.pem" + } + } + ] + } + } + ) + end + end +end diff --git a/spec/services/snippets/count_service_spec.rb b/spec/services/snippets/count_service_spec.rb new file mode 100644 index 00000000000..4137e65dcca --- /dev/null +++ b/spec/services/snippets/count_service_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Snippets::CountService do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + + describe '#new' do + it 'raises an error if no author or project' do + expect { described_class.new(user) }.to raise_error(ArgumentError) + end + + it 'uses the SnippetsFinder to scope snippets by user' do + expect(SnippetsFinder) + .to receive(:new) + .with(user, author: user, project: nil) + + described_class.new(user, author: user) + end + + it 'allows scoping to project' do + expect(SnippetsFinder) + .to receive(:new) + .with(user, author: nil, project: project) + + described_class.new(user, project: project) + end + end + + describe '#execute' do + subject { described_class.new(user, author: user).execute } + + it 'returns a hash of counts' do + expect(subject).to match({ + are_public: 0, + are_internal: 0, + are_private: 0, + are_public_or_internal: 0, + total: 0 + }) + end + + it 'only counts snippets the user has access to' do + create(:personal_snippet, :private, author: user) + create(:project_snippet, :private, author: user) + create(:project_snippet, :private, author: create(:user)) + + expect(subject).to match({ + are_public: 0, + are_internal: 0, + are_private: 1, + are_public_or_internal: 0, + total: 1 + }) + end + + it 'returns an empty hash if select returns nil' do + allow_next_instance_of(described_class) do |instance| + allow(instance).to receive(:snippet_counts).and_return(nil) + end + + expect(subject).to match({}) + end + end +end diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb index 5c35617bd36..1c8a9714bdf 100644 --- a/spec/support/shared_examples/features/snippets_shared_examples.rb +++ b/spec/support/shared_examples/features/snippets_shared_examples.rb @@ -18,3 +18,35 @@ RSpec.shared_examples 'paginated snippets' do |remote: false| end end end + +RSpec.shared_examples 'tabs with counts' do + let(:tabs) { page.all('.snippet-scope-menu li') } + + it 'shows a tab for All snippets and count' do + tab = tabs[0] + + expect(tab.text).to include('All') + expect(tab.find('.badge').text).to eq(counts[:all]) + end + + it 'shows a tab for Private snippets and count' do + tab = tabs[1] + + expect(tab.text).to include('Private') + expect(tab.find('.badge').text).to eq(counts[:private]) + end + + it 'shows a tab for Internal snippets and count' do + tab = tabs[2] + + expect(tab.text).to include('Internal') + expect(tab.find('.badge').text).to eq(counts[:internal]) + end + + it 'shows a tab for Public snippets and count' do + tab = tabs[3] + + expect(tab.text).to include('Public') + expect(tab.find('.badge').text).to eq(counts[:public]) + end +end diff --git a/spec/workers/cluster_configure_istio_worker_spec.rb b/spec/workers/cluster_configure_istio_worker_spec.rb new file mode 100644 index 00000000000..0f02d428ced --- /dev/null +++ b/spec/workers/cluster_configure_istio_worker_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ClusterConfigureIstioWorker do + describe '#perform' do + shared_examples 'configure istio service' do + it 'configures istio' do + expect_any_instance_of(Clusters::Kubernetes::ConfigureIstioIngressService).to receive(:execute) + + described_class.new.perform(cluster.id) + end + end + + context 'when provider type is gcp' do + let(:cluster) { create(:cluster, :project, :provided_by_gcp) } + + it_behaves_like 'configure istio service' + end + + context 'when provider type is aws' do + let(:cluster) { create(:cluster, :project, :provided_by_aws) } + + it_behaves_like 'configure istio service' + end + + context 'when provider type is user' do + let(:cluster) { create(:cluster, :project, :provided_by_user) } + + it_behaves_like 'configure istio service' + end + + context 'when cluster does not exist' do + it 'does not provision a cluster' do + expect_any_instance_of(Clusters::Kubernetes::ConfigureIstioIngressService).not_to receive(:execute) + + described_class.new.perform(123) + end + end + end +end -- cgit v1.2.3