Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/profiles/emails_controller_spec.rb6
-rw-r--r--spec/factories/alert_management/alerts.rb5
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb42
-rw-r--r--spec/features/profiles/emails_spec.rb2
-rw-r--r--spec/features/projects/activity/user_sees_design_comment_spec.rb51
-rw-r--r--spec/features/projects/issues/design_management/user_paginates_designs_spec.rb40
-rw-r--r--spec/features/projects/issues/design_management/user_permissions_upload_spec.rb24
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb63
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_images_spec.rb41
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_spec.rb29
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_spec.rb47
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb55
-rw-r--r--spec/finders/alert_management/alerts_finder_spec.rb60
-rw-r--r--spec/frontend/notes/components/discussion_filter_spec.js4
-rw-r--r--spec/frontend/notes/mixins/discussion_navigation_spec.js4
-rw-r--r--spec/models/alert_management/alert_spec.rb45
-rw-r--r--spec/models/ci/build_spec.rb91
-rw-r--r--spec/models/ci/instance_variable_spec.rb59
-rw-r--r--spec/models/email_spec.rb18
-rw-r--r--spec/models/project_spec.rb39
-rw-r--r--spec/models/user_spec.rb13
-rw-r--r--spec/requests/api/graphql/project/alert_management/alerts_spec.rb34
-rw-r--r--spec/services/emails/confirm_service_spec.rb6
23 files changed, 693 insertions, 85 deletions
diff --git a/spec/controllers/profiles/emails_controller_spec.rb b/spec/controllers/profiles/emails_controller_spec.rb
index 91850e429a5..ffec43fea2c 100644
--- a/spec/controllers/profiles/emails_controller_spec.rb
+++ b/spec/controllers/profiles/emails_controller_spec.rb
@@ -9,6 +9,12 @@ describe Profiles::EmailsController do
sign_in(user)
end
+ around do |example|
+ perform_enqueued_jobs do
+ example.run
+ end
+ end
+
describe '#create' do
context 'when email address is valid' do
let(:email_params) { { email: "add_email@example.com" } }
diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb
index 0e1c0433905..01f40a7a465 100644
--- a/spec/factories/alert_management/alerts.rb
+++ b/spec/factories/alert_management/alerts.rb
@@ -24,6 +24,10 @@ FactoryBot.define do
monitoring_tool { FFaker::AWS.product_description }
end
+ trait :with_description do
+ description { FFaker::Lorem.sentence }
+ end
+
trait :with_host do
hosts { [FFaker::Internet.ip_v4_address] }
end
@@ -70,6 +74,7 @@ FactoryBot.define do
with_service
with_monitoring_tool
with_host
+ with_description
low_severity
end
end
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index 867281da1e6..63867d5796a 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -3,10 +3,10 @@
require 'spec_helper'
describe 'Dashboard Todos' do
- let(:user) { create(:user, username: 'john') }
- let(:author) { create(:user) }
- let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") }
+ let_it_be(:user) { create(:user, username: 'john') }
+ let_it_be(:author) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") }
context 'User does not have todos' do
before do
@@ -357,4 +357,38 @@ describe 'Dashboard Todos' do
expect(page).to have_link "merge request #{todo.target.to_reference}", href: href
end
end
+
+ context 'User has a todo regarding a design' do
+ let_it_be(:target) { create(:design, issue: issue, project: project) }
+ let_it_be(:note) { create(:note, project: project, note: 'I am note, hear me roar') }
+ let_it_be(:todo) do
+ create(:todo, :mentioned,
+ user: user,
+ project: project,
+ target: target,
+ author: author,
+ note: note)
+ end
+
+ before do
+ project.add_developer(user)
+ sign_in(user)
+
+ visit dashboard_todos_path
+ end
+
+ it 'has todo present' do
+ expect(page).to have_selector('.todos-list .todo', count: 1)
+ end
+
+ it 'has a link that will take me to the design page' do
+ click_link "design #{target.to_reference}"
+
+ expectation = Gitlab::Routing.url_helpers.designs_project_issue_path(
+ target.project, target.issue, target.filename
+ )
+
+ expect(current_path).to eq(expectation)
+ end
+ end
end
diff --git a/spec/features/profiles/emails_spec.rb b/spec/features/profiles/emails_spec.rb
index 5dfc03d711a..a41ef9e86ae 100644
--- a/spec/features/profiles/emails_spec.rb
+++ b/spec/features/profiles/emails_spec.rb
@@ -67,7 +67,7 @@ describe 'Profile > Emails' do
email = user.emails.create(email: 'my@email.com')
visit profile_emails_path
- expect { click_link("Resend confirmation email") }.to change { ActionMailer::Base.deliveries.size }
+ expect { click_link("Resend confirmation email") }.to have_enqueued_job.on_queue('mailers')
expect(page).to have_content("Confirmation email sent to #{email.email}")
end
diff --git a/spec/features/projects/activity/user_sees_design_comment_spec.rb b/spec/features/projects/activity/user_sees_design_comment_spec.rb
new file mode 100644
index 00000000000..9864e9ce29f
--- /dev/null
+++ b/spec/features/projects/activity/user_sees_design_comment_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Projects > Activity > User sees design comment', :js do
+ include DesignManagementTestHelpers
+
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:user) { project.creator }
+ let_it_be(:commenter) { create(:user) }
+ let_it_be(:issue) { create(:closed_issue, project: project) }
+ let_it_be(:design) { create(:design, issue: issue) }
+
+ let(:design_activity) do
+ "#{commenter.name} #{commenter.to_reference} commented on design"
+ end
+
+ let(:issue_activity) do
+ "#{user.name} #{user.to_reference} closed issue #{issue.to_reference}"
+ end
+
+ before_all do
+ project.add_developer(commenter)
+ create(:event, :for_design, project: project, author: commenter, design: design)
+ create(:closed_issue_event, project: project, author: user, target: issue)
+ end
+
+ before do
+ enable_design_management
+ end
+
+ it 'shows the design comment action in the activity page' do
+ visit activity_project_path(project)
+
+ expect(page).to have_content(design_activity)
+ end
+
+ it 'allows to filter out the design event with the "event_filter=issue" URL param', :aggregate_failures do
+ visit activity_project_path(project, event_filter: EventFilter::ISSUE)
+
+ expect(page).not_to have_content(design_activity)
+ expect(page).to have_content(issue_activity)
+ end
+
+ it 'allows to filter in the event with the "event_filter=comments" URL param', :aggregate_failures do
+ visit activity_project_path(project, event_filter: EventFilter::COMMENTS)
+
+ expect(page).to have_content(design_activity)
+ expect(page).not_to have_content(issue_activity)
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb
new file mode 100644
index 00000000000..d9a72f2d5c5
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User paginates issue designs', :js do
+ include DesignManagementTestHelpers
+
+ let(:project) { create(:project_empty_repo, :public) }
+ let(:issue) { create(:issue, project: project) }
+
+ before do
+ enable_design_management
+
+ create_list(:design, 2, :with_file, issue: issue)
+
+ visit project_issue_path(project, issue)
+
+ click_link 'Designs'
+
+ wait_for_requests
+
+ find('.js-design-list-item', match: :first).click
+ end
+
+ it 'paginates to next design' do
+ expect(find('.js-previous-design')[:disabled]).to eq('true')
+
+ page.within(find('.js-design-header')) do
+ expect(page).to have_content('1 of 2')
+ end
+
+ find('.js-next-design').click
+
+ expect(find('.js-previous-design')[:disabled]).not_to eq('true')
+
+ page.within(find('.js-design-header')) do
+ expect(page).to have_content('2 of 2')
+ end
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb
new file mode 100644
index 00000000000..2238e86a47f
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User design permissions', :js do
+ include DesignManagementTestHelpers
+
+ let(:project) { create(:project_empty_repo, :public) }
+ let(:issue) { create(:issue, project: project) }
+
+ before do
+ enable_design_management
+
+ visit project_issue_path(project, issue)
+
+ click_link 'Designs'
+
+ wait_for_requests
+ end
+
+ it 'user does not have permissions to upload design' do
+ expect(page).not_to have_field('design_file')
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
new file mode 100644
index 00000000000..d160ab95a65
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User uploads new design', :js do
+ include DesignManagementTestHelpers
+
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:user) { project.owner }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ before do
+ sign_in(user)
+ end
+
+ context "when the feature is available" do
+ before do
+ enable_design_management
+
+ visit project_issue_path(project, issue)
+
+ click_link 'Designs'
+
+ wait_for_requests
+ end
+
+ it 'uploads designs' do
+ attach_file(:design_file, logo_fixture, make_visible: true)
+
+ expect(page).to have_selector('.js-design-list-item', count: 1)
+
+ within first('#designs-tab .js-design-list-item') do
+ expect(page).to have_content('dk.png')
+ end
+
+ attach_file(:design_file, gif_fixture, make_visible: true)
+
+ expect(page).to have_selector('.js-design-list-item', count: 2)
+ end
+ end
+
+ context 'when the feature is not available' do
+ before do
+ visit project_issue_path(project, issue)
+
+ click_link 'Designs'
+
+ wait_for_requests
+ end
+
+ it 'shows the message about requirements' do
+ expect(page).to have_content("To enable design management, you'll need to meet the requirements.")
+ end
+ end
+
+ def logo_fixture
+ Rails.root.join('spec', 'fixtures', 'dk.png')
+ end
+
+ def gif_fixture
+ Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb
new file mode 100644
index 00000000000..3d0f4df55c4
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Users views raw design image files' do
+ include DesignManagementTestHelpers
+
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) }
+ let(:newest_version) { design.versions.ordered.first }
+ let(:oldest_version) { design.versions.ordered.last }
+
+ before do
+ enable_design_management
+ end
+
+ it 'serves the latest design version when no ref is given' do
+ visit project_design_management_designs_raw_image_path(design.project, design)
+
+ expect(response_headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to eq(
+ workhorse_data_header_for_version(oldest_version.sha)
+ )
+ end
+
+ it 'serves the correct design version when a ref is given' do
+ visit project_design_management_designs_raw_image_path(design.project, design, oldest_version.sha)
+
+ expect(response_headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to eq(
+ workhorse_data_header_for_version(oldest_version.sha)
+ )
+ end
+
+ private
+
+ def workhorse_data_header_for_version(ref)
+ blob = project.design_repository.blob_at(ref, design.full_path)
+
+ Gitlab::Workhorse.send_git_blob(project.design_repository, blob).last
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_views_design_spec.rb b/spec/features/projects/issues/design_management/user_views_design_spec.rb
new file mode 100644
index 00000000000..707049b0068
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_views_design_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User views issue designs', :js do
+ include DesignManagementTestHelpers
+
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:design) { create(:design, :with_file, issue: issue) }
+
+ before do
+ enable_design_management
+
+ visit project_issue_path(project, issue)
+
+ click_link 'Designs'
+ end
+
+ it 'opens design detail' do
+ click_link design.filename
+
+ page.within(find('.js-design-header')) do
+ expect(page).to have_content(design.filename)
+ end
+
+ expect(page).to have_selector('.js-design-image')
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_views_designs_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_spec.rb
new file mode 100644
index 00000000000..a4fb7456922
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_views_designs_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User views issue designs', :js do
+ include DesignManagementTestHelpers
+
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:design) { create(:design, :with_file, issue: issue) }
+
+ before do
+ enable_design_management
+ end
+
+ context 'navigates from the issue view' do
+ before do
+ visit project_issue_path(project, issue)
+ click_link 'Designs'
+ wait_for_requests
+ end
+
+ it 'fetches list of designs' do
+ expect(page).to have_selector('.js-design-list-item', count: 1)
+ end
+ end
+
+ context 'navigates directly to the design collection view' do
+ before do
+ visit designs_project_issue_path(project, issue)
+ end
+
+ it 'expands the sidebar' do
+ expect(page).to have_selector('.layout-page.right-sidebar-expanded')
+ end
+ end
+
+ context 'navigates directly to the individual design view' do
+ before do
+ visit designs_project_issue_path(project, issue, vueroute: design.filename)
+ end
+
+ it 'sees the design' do
+ expect(page).to have_selector('.js-design-detail')
+ end
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb
new file mode 100644
index 00000000000..a9e4aa899a7
--- /dev/null
+++ b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User views an SVG design that contains XSS', :js do
+ include DesignManagementTestHelpers
+
+ let(:project) { create(:project_empty_repo, :public) }
+ let(:issue) { create(:issue, project: project) }
+ let(:file) { Rails.root.join('spec', 'fixtures', 'logo_sample.svg') }
+ let(:design) { create(:design, :with_file, filename: 'xss.svg', file: file, issue: issue) }
+
+ before do
+ enable_design_management
+
+ visit designs_project_issue_path(
+ project,
+ issue,
+ { vueroute: design.filename }
+ )
+
+ wait_for_requests
+ end
+
+ it 'has XSS within the SVG file' do
+ file_content = File.read(file)
+
+ expect(file_content).to include("<script>alert('FAIL')</script>")
+ end
+
+ it 'displays the SVG' do
+ expect(page).to have_selector("img.design-img[alt='xss.svg']", count: 1, visible: false)
+ end
+
+ it 'does not execute the JavaScript within the SVG' do
+ # The expectation is that we can call the capybara `page.dismiss_prompt`
+ # method to close a JavaScript alert prompt without a `Capybara::ModalNotFound`
+ # being raised.
+ run_expectation = -> {
+ page.dismiss_prompt(wait: 1)
+ }
+
+ # With the page loaded, there should be no alert modal
+ expect(run_expectation).to raise_error(
+ Capybara::ModalNotFound,
+ 'Unable to find modal dialog'
+ )
+
+ # Perform a negative control test of the above expectation.
+ # With an alert modal displaying, the modal should be dismissable.
+ execute_script('alert(true)')
+
+ expect(run_expectation).not_to raise_error
+ end
+end
diff --git a/spec/finders/alert_management/alerts_finder_spec.rb b/spec/finders/alert_management/alerts_finder_spec.rb
index 70130fbd392..99db4ecbf03 100644
--- a/spec/finders/alert_management/alerts_finder_spec.rb
+++ b/spec/finders/alert_management/alerts_finder_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
describe AlertManagement::AlertsFinder, '#execute' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:alert_1) { create(:alert_management_alert, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) }
- let_it_be(:alert_2) { create(:alert_management_alert, :ignored, project: project, events: 1, severity: :critical) }
- let_it_be(:alert_3) { create(:alert_management_alert) }
+ let_it_be(:alert_1) { create(:alert_management_alert, :all_fields, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) }
+ let_it_be(:alert_2) { create(:alert_management_alert, :all_fields, :ignored, project: project, events: 1, severity: :critical) }
+ let_it_be(:alert_3) { create(:alert_management_alert, :all_fields) }
let(:params) { {} }
subject { described_class.new(current_user, project, params).execute }
@@ -222,5 +222,59 @@ describe AlertManagement::AlertsFinder, '#execute' do
end
end
end
+
+ context 'search query given' do
+ let_it_be(:alert) do
+ create(:alert_management_alert,
+ :with_fingerprint,
+ title: 'Title',
+ description: 'Desc',
+ service: 'Service',
+ monitoring_tool: 'Monitor'
+ )
+ end
+
+ before do
+ alert.project.add_developer(current_user)
+ end
+
+ subject { described_class.new(current_user, alert.project, params).execute }
+
+ context 'searching title' do
+ let(:params) { { search: alert.title } }
+
+ it { is_expected.to match_array([alert]) }
+ end
+
+ context 'searching description' do
+ let(:params) { { search: alert.description } }
+
+ it { is_expected.to match_array([alert]) }
+ end
+
+ context 'searching service' do
+ let(:params) { { search: alert.service } }
+
+ it { is_expected.to match_array([alert]) }
+ end
+
+ context 'searching monitoring tool' do
+ let(:params) { { search: alert.monitoring_tool } }
+
+ it { is_expected.to match_array([alert]) }
+ end
+
+ context 'searching something else' do
+ let(:params) { { search: alert.fingerprint } }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'empty search' do
+ let(:params) { { search: ' ' } }
+
+ it { is_expected.to match_array([alert]) }
+ end
+ end
end
end
diff --git a/spec/frontend/notes/components/discussion_filter_spec.js b/spec/frontend/notes/components/discussion_filter_spec.js
index b8d2d721443..7f042c0e9de 100644
--- a/spec/frontend/notes/components/discussion_filter_spec.js
+++ b/spec/frontend/notes/components/discussion_filter_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import createEventHub from '~/helpers/event_hub_factory';
import Vuex from 'vuex';
import { createLocalVue, mount } from '@vue/test-utils';
@@ -132,7 +132,7 @@ describe('DiscussionFilter component', () => {
});
describe('Merge request tabs', () => {
- eventHub = new Vue();
+ eventHub = createEventHub();
beforeEach(() => {
window.mrTabs = {
diff --git a/spec/frontend/notes/mixins/discussion_navigation_spec.js b/spec/frontend/notes/mixins/discussion_navigation_spec.js
index 4e5325b8bc3..120de023099 100644
--- a/spec/frontend/notes/mixins/discussion_navigation_spec.js
+++ b/spec/frontend/notes/mixins/discussion_navigation_spec.js
@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import * as utils from '~/lib/utils/common_utils';
import discussionNavigation from '~/notes/mixins/discussion_navigation';
import eventHub from '~/notes/event_hub';
+import createEventHub from '~/helpers/event_hub_factory';
import notesModule from '~/notes/stores/modules';
import { setHTMLFixture } from 'helpers/fixtures';
@@ -67,8 +68,7 @@ describe('Discussion navigation mixin', () => {
describe('cycle through discussions', () => {
beforeEach(() => {
- // eslint-disable-next-line new-cap
- window.mrTabs = { eventHub: new localVue(), tabShown: jest.fn() };
+ window.mrTabs = { eventHub: createEventHub(), tabShown: jest.fn() };
});
describe.each`
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb
index c82e1617f7d..97bffa23b31 100644
--- a/spec/models/alert_management/alert_spec.rb
+++ b/spec/models/alert_management/alert_spec.rb
@@ -162,7 +162,50 @@ describe AlertManagement::Alert do
it { is_expected.to contain_exactly(alert_1) }
end
- describe '.details' do
+ describe '.search' do
+ let_it_be(:alert) do
+ create(:alert_management_alert,
+ title: 'Title',
+ description: 'Desc',
+ service: 'Service',
+ monitoring_tool: 'Monitor'
+ )
+ end
+
+ subject { AlertManagement::Alert.search(query) }
+
+ context 'does not contain search string' do
+ let(:query) { 'something else' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'title includes query' do
+ let(:query) { alert.title.upcase }
+
+ it { is_expected.to contain_exactly(alert) }
+ end
+
+ context 'description includes query' do
+ let(:query) { alert.description.upcase }
+
+ it { is_expected.to contain_exactly(alert) }
+ end
+
+ context 'service includes query' do
+ let(:query) { alert.service.upcase }
+
+ it { is_expected.to contain_exactly(alert) }
+ end
+
+ context 'monitoring tool includes query' do
+ let(:query) { alert.monitoring_tool.upcase }
+
+ it { is_expected.to contain_exactly(alert) }
+ end
+ end
+
+ describe '#details' do
let(:payload) do
{
'title' => 'Details title',
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index ea7ce8cadc4..6605866d9c0 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -3117,11 +3117,7 @@ describe Ci::Build do
end
end
- describe '#secret_group_variables' do
- subject { build.secret_group_variables }
-
- let!(:variable) { create(:ci_group_variable, protected: true, group: group) }
-
+ shared_examples "secret CI variables" do
context 'when ref is branch' do
let(:build) { create(:ci_build, ref: 'master', tag: false, project: project) }
@@ -3175,62 +3171,28 @@ describe Ci::Build do
end
end
- describe '#secret_project_variables' do
- subject { build.secret_project_variables }
-
- let!(:variable) { create(:ci_variable, protected: true, project: project) }
+ describe '#secret_instance_variables' do
+ subject { build.secret_instance_variables }
- context 'when ref is branch' do
- let(:build) { create(:ci_build, ref: 'master', tag: false, project: project) }
+ let_it_be(:variable) { create(:ci_instance_variable, protected: true) }
- context 'when ref is protected' do
- before do
- create(:protected_branch, :developers_can_merge, name: 'master', project: project)
- end
-
- it { is_expected.to include(variable) }
- end
-
- context 'when ref is not protected' do
- it { is_expected.not_to include(variable) }
- end
- end
-
- context 'when ref is tag' do
- let(:build) { create(:ci_build, ref: 'v1.1.0', tag: true, project: project) }
+ include_examples "secret CI variables"
+ end
- context 'when ref is protected' do
- before do
- create(:protected_tag, project: project, name: 'v*')
- end
+ describe '#secret_group_variables' do
+ subject { build.secret_group_variables }
- it { is_expected.to include(variable) }
- end
+ let_it_be(:variable) { create(:ci_group_variable, protected: true, group: group) }
- context 'when ref is not protected' do
- it { is_expected.not_to include(variable) }
- end
- end
-
- context 'when ref is merge request' do
- let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
- let(:pipeline) { merge_request.pipelines_for_merge_request.first }
- let(:build) { create(:ci_build, ref: merge_request.source_branch, tag: false, pipeline: pipeline, project: project) }
+ include_examples "secret CI variables"
+ end
- context 'when ref is protected' do
- before do
- create(:protected_branch, :developers_can_merge, name: merge_request.source_branch, project: project)
- end
+ describe '#secret_project_variables' do
+ subject { build.secret_project_variables }
- it 'does not return protected variables as it is not supported for merge request pipelines' do
- is_expected.not_to include(variable)
- end
- end
+ let_it_be(:variable) { create(:ci_variable, protected: true, project: project) }
- context 'when ref is not protected' do
- it { is_expected.not_to include(variable) }
- end
- end
+ include_examples "secret CI variables"
end
describe '#deployment_variables' do
@@ -3283,6 +3245,29 @@ describe Ci::Build do
expect(build.scoped_variables_hash).not_to include('MY_VAR': 'myvar')
end
end
+
+ context 'when overriding CI instance variables' do
+ before do
+ create(:ci_instance_variable, key: 'MY_VAR', value: 'my value 1')
+ group.variables.create!(key: 'MY_VAR', value: 'my value 2')
+ end
+
+ it 'returns a regular hash created using valid ordering' do
+ expect(build.scoped_variables_hash).to include('MY_VAR': 'my value 2')
+ expect(build.scoped_variables_hash).not_to include('MY_VAR': 'my value 1')
+ end
+ end
+
+ context 'when CI instance variables are disabled' do
+ before do
+ create(:ci_instance_variable, key: 'MY_VAR', value: 'my value 1')
+ stub_feature_flags(ci_instance_level_variables: false)
+ end
+
+ it 'does not include instance level variables' do
+ expect(build.scoped_variables_hash).not_to include('MY_VAR': 'my value 1')
+ end
+ end
end
describe '#any_unmet_prerequisites?' do
diff --git a/spec/models/ci/instance_variable_spec.rb b/spec/models/ci/instance_variable_spec.rb
index b879965a261..ff8676e1424 100644
--- a/spec/models/ci/instance_variable_spec.rb
+++ b/spec/models/ci/instance_variable_spec.rb
@@ -31,4 +31,63 @@ describe Ci::InstanceVariable do
end
end
end
+
+ describe '.all_cached', :use_clean_rails_memory_store_caching do
+ let_it_be(:unprotected_variable) { create(:ci_instance_variable, protected: false) }
+ let_it_be(:protected_variable) { create(:ci_instance_variable, protected: true) }
+
+ it { expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable) }
+
+ it 'memoizes the result' do
+ expect(described_class).to receive(:store_cache).with(:ci_instance_variable_data).once.and_call_original
+
+ 2.times do
+ expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable)
+ end
+ end
+
+ it 'removes scopes' do
+ expect(described_class.unprotected.all_cached).to contain_exactly(protected_variable, unprotected_variable)
+ end
+
+ it 'resets the cache when records are deleted' do
+ expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable)
+
+ protected_variable.destroy
+
+ expect(described_class.all_cached).to contain_exactly(unprotected_variable)
+ end
+
+ it 'resets the cache when records are inserted' do
+ expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable)
+
+ variable = create(:ci_instance_variable, protected: true)
+
+ expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable, variable)
+ end
+
+ it 'resets the cache when the shared key is missing' do
+ expect(Rails.cache).to receive(:read).with(:ci_instance_variable_changed_at).twice.and_return(nil)
+ expect(described_class).to receive(:store_cache).with(:ci_instance_variable_data).thrice.and_call_original
+
+ 3.times do
+ expect(described_class.all_cached).to contain_exactly(protected_variable, unprotected_variable)
+ end
+ end
+ end
+
+ describe '.unprotected_cached', :use_clean_rails_memory_store_caching do
+ let_it_be(:unprotected_variable) { create(:ci_instance_variable, protected: false) }
+ let_it_be(:protected_variable) { create(:ci_instance_variable, protected: true) }
+
+ it { expect(described_class.unprotected_cached).to contain_exactly(unprotected_variable) }
+
+ it 'memoizes the result' do
+ expect(described_class).to receive(:store_cache).with(:ci_instance_variable_data).once.and_call_original
+
+ 2.times do
+ expect(described_class.unprotected_cached).to contain_exactly(unprotected_variable)
+ end
+ end
+ end
end
diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb
index dabf2bb80b5..f7b194abcee 100644
--- a/spec/models/email_spec.rb
+++ b/spec/models/email_spec.rb
@@ -3,6 +3,12 @@
require 'spec_helper'
describe Email do
+ describe 'modules' do
+ subject { described_class }
+
+ it { is_expected.to include_module(AsyncDeviseEmail) }
+ end
+
describe 'validations' do
it_behaves_like 'an object with RFC3696 compliant email-formated attributes', :email do
subject { build(:email) }
@@ -45,4 +51,16 @@ describe Email do
expect(build(:email, user: user).username).to eq user.username
end
end
+
+ describe 'Devise emails' do
+ let!(:user) { create(:user) }
+
+ describe 'behaviour' do
+ it 'sends emails asynchronously' do
+ expect do
+ user.emails.create!(email: 'hello@hello.com')
+ end.to have_enqueued_job.on_queue('mailers')
+ end
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 40536f96ff4..1c7e47f8114 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3138,6 +3138,45 @@ describe Project do
end
end
+ describe '#ci_instance_variables_for' do
+ let(:project) { create(:project) }
+
+ let!(:instance_variable) do
+ create(:ci_instance_variable, value: 'secret')
+ end
+
+ let!(:protected_instance_variable) do
+ create(:ci_instance_variable, :protected, value: 'protected')
+ end
+
+ subject { project.ci_instance_variables_for(ref: 'ref') }
+
+ before do
+ stub_application_setting(
+ default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ end
+
+ context 'when the ref is not protected' do
+ before do
+ allow(project).to receive(:protected_for?).with('ref').and_return(false)
+ end
+
+ it 'contains only the CI variables' do
+ is_expected.to contain_exactly(instance_variable)
+ end
+ end
+
+ context 'when the ref is protected' do
+ before do
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
+ end
+
+ it 'contains all the variables' do
+ is_expected.to contain_exactly(instance_variable, protected_instance_variable)
+ end
+ end
+ end
+
describe '#any_lfs_file_locks?', :request_store do
let_it_be(:project) { create(:project) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index c1e49d4b0a7..94a3f6bafea 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -17,6 +17,7 @@ describe User do
it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(TokenAuthenticatable) }
it { is_expected.to include_module(BlocksJsonSerialization) }
+ it { is_expected.to include_module(AsyncDeviseEmail) }
end
describe 'delegations' do
@@ -165,6 +166,18 @@ describe User do
end
end
+ describe 'Devise emails' do
+ let!(:user) { create(:user) }
+
+ describe 'behaviour' do
+ it 'sends emails asynchronously' do
+ expect do
+ user.update!(email: 'hello@hello.com')
+ end.to have_enqueued_job.on_queue('mailers').exactly(:twice)
+ end
+ end
+ end
+
describe 'validations' do
describe 'password' do
let!(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
index cafa7366411..a751d8ce63a 100644
--- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
@@ -10,6 +10,7 @@ describe 'getting Alert Management Alerts' do
let_it_be(:alert_1) { create(:alert_management_alert, :all_fields, :resolved, project: project, issue: nil, severity: :low) }
let_it_be(:alert_2) { create(:alert_management_alert, :all_fields, project: project, severity: :critical, payload: payload) }
let_it_be(:other_project_alert) { create(:alert_management_alert, :all_fields) }
+ let(:params) { {} }
let(:fields) do
<<~QUERY
@@ -23,7 +24,7 @@ describe 'getting Alert Management Alerts' do
graphql_query_for(
'project',
{ 'fullPath' => project.full_path },
- query_graphql_field('alertManagementAlerts', {}, fields)
+ query_graphql_field('alertManagementAlerts', params, fields)
)
end
@@ -83,13 +84,7 @@ describe 'getting Alert Management Alerts' do
end
context 'with iid given' do
- let(:query) do
- graphql_query_for(
- 'project',
- { 'fullPath' => project.full_path },
- query_graphql_field('alertManagementAlerts', { iid: alert_1.iid.to_s }, fields)
- )
- end
+ let(:params) { { iid: alert_1.iid.to_s } }
it_behaves_like 'a working graphql query'
@@ -98,14 +93,6 @@ describe 'getting Alert Management Alerts' do
end
context 'sorting data given' do
- let(:query) do
- graphql_query_for(
- 'project',
- { 'fullPath' => project.full_path },
- query_graphql_field('alertManagementAlerts', params, fields)
- )
- end
-
let(:params) { 'sort: SEVERITY_DESC' }
let(:iids) { alerts.map { |a| a['iid'] } }
@@ -123,6 +110,21 @@ describe 'getting Alert Management Alerts' do
end
end
end
+
+ context 'searching' do
+ let(:params) { { search: alert_1.title } }
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(alerts.size).to eq(1) }
+ it { expect(first_alert['iid']).to eq(alert_1.iid.to_s) }
+
+ context 'unknown criteria' do
+ let(:params) { { search: 'something random' } }
+
+ it { expect(alerts.size).to eq(0) }
+ end
+ end
end
end
end
diff --git a/spec/services/emails/confirm_service_spec.rb b/spec/services/emails/confirm_service_spec.rb
index 6a274ca9dfe..973d2731b2f 100644
--- a/spec/services/emails/confirm_service_spec.rb
+++ b/spec/services/emails/confirm_service_spec.rb
@@ -8,10 +8,10 @@ describe Emails::ConfirmService do
subject(:service) { described_class.new(user) }
describe '#execute' do
- it 'sends a confirmation email again' do
+ it 'enqueues a background job to send confirmation email again' do
email = user.emails.create(email: 'new@email.com')
- mail = service.execute(email)
- expect(mail.subject).to eq('Confirmation instructions')
+
+ expect { service.execute(email) }.to have_enqueued_job.on_queue('mailers')
end
end
end