Skip to content
Snippets Groups Projects
Commit e0fa0638 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent f8d15ca6
No related branches found
No related tags found
No related merge requests found
Showing
with 552 additions and 30 deletions
# frozen_string_literal: true
module Gitlab
module SidekiqMiddleware
module DuplicateJobs
module Strategies
# This strategy takes a lock before scheduling the job in a queue and
# removes the lock before the job starts allowing a new job to be queued
# while a job is still executing.
class UntilExecuting
def initialize(duplicate_job)
@duplicate_job = duplicate_job
end
def schedule(job)
if duplicate_job.check! && duplicate_job.duplicate?
job['duplicate-of'] = duplicate_job.existing_jid
end
yield
end
def perform(_job)
duplicate_job.delete!
yield
end
private
attr_reader :duplicate_job
end
end
end
end
end
Loading
Loading
@@ -196,6 +196,11 @@ msgid_plural "%d unstaged changes"
msgstr[0] ""
msgstr[1] ""
 
msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
Loading
Loading
@@ -3930,6 +3935,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
 
msgid "Cluster does not exist"
msgstr ""
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr ""
 
Loading
Loading
@@ -6700,6 +6708,9 @@ msgstr ""
msgid "Difference between start date and now"
msgstr ""
 
msgid "DiffsCompareBaseBranch|(HEAD)"
msgstr ""
msgid "DiffsCompareBaseBranch|(base)"
msgstr ""
 
Loading
Loading
@@ -6823,12 +6834,20 @@ msgstr ""
msgid "Dismiss"
msgstr ""
 
msgid "Dismiss %d selected vulnerability as"
msgid_plural "Dismiss %d selected vulnerabilities as"
msgstr[0] ""
msgstr[1] ""
msgid "Dismiss DevOps Score introduction"
msgstr ""
 
msgid "Dismiss Merge Request promotion"
msgstr ""
 
msgid "Dismiss Selected"
msgstr ""
msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
 
Loading
Loading
@@ -7396,6 +7415,9 @@ msgstr ""
msgid "Environment"
msgstr ""
 
msgid "Environment does not have deployments"
msgstr ""
msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. Additionally, they can be masked so they are hidden in job logs, though they must match certain regexp requirements to do so. You can use environment variables for passwords, secret keys, or whatever you want."
msgstr ""
 
Loading
Loading
@@ -8293,6 +8315,9 @@ msgstr ""
msgid "Failure"
msgstr ""
 
msgid "False positive"
msgstr ""
msgid "Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged."
msgstr ""
 
Loading
Loading
@@ -12640,6 +12665,9 @@ msgstr ""
msgid "Name:"
msgstr ""
 
msgid "Namespace is empty"
msgstr ""
msgid "Namespace: %{namespace}"
msgstr ""
 
Loading
Loading
@@ -12897,9 +12925,6 @@ msgstr ""
msgid "No data to display"
msgstr ""
 
msgid "No deployment platform available"
msgstr ""
msgid "No deployments found"
msgstr ""
 
Loading
Loading
@@ -13149,6 +13174,9 @@ msgstr ""
msgid "NotificationEvent|Failed pipeline"
msgstr ""
 
msgid "NotificationEvent|Fixed pipeline"
msgstr ""
msgid "NotificationEvent|Merge merge request"
msgstr ""
 
Loading
Loading
@@ -17056,6 +17084,9 @@ msgstr ""
msgid "Security Reports|There was an error deleting the comment."
msgstr ""
 
msgid "Security Reports|There was an error dismissing the vulnerabilities."
msgstr ""
msgid "Security Reports|There was an error dismissing the vulnerability."
msgstr ""
 
Loading
Loading
@@ -17212,6 +17243,9 @@ msgstr ""
msgid "Select a project to read Insights configuration file"
msgstr ""
 
msgid "Select a reason"
msgstr ""
msgid "Select a repository"
msgstr ""
 
Loading
Loading
@@ -22173,6 +22207,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
 
msgid "Won't fix / Accept risk"
msgstr ""
msgid "Work in progress Limit"
msgstr ""
 
Loading
Loading
@@ -22761,6 +22798,9 @@ msgstr ""
msgid "Zoom meeting removed"
msgstr ""
 
msgid "[No reason]"
msgstr ""
msgid "a deleted user"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -14,4 +14,5 @@ N_('NotificationEvent|Close merge request')
N_('NotificationEvent|Reassign merge request')
N_('NotificationEvent|Merge merge request')
N_('NotificationEvent|Failed pipeline')
N_('NotificationEvent|Fixed pipeline')
N_('NotificationEvent|New release')
# frozen_string_literal: true
FactoryBot.define do
factory :ci_ref, class: 'Ci::Ref' do
ref { 'master' }
status { :success }
tag { false }
project
before(:create) do |ref, evaluator|
next if ref.pipelines.exists?
ref.update!(last_updated_by_pipeline: create(:ci_pipeline, project: evaluator.project, ref: evaluator.ref, tag: evaluator.tag, status: evaluator.status))
end
end
end
Loading
Loading
@@ -356,7 +356,7 @@ describe 'Pipeline', :js do
end
end
 
context 'test tabs' do
describe 'test tabs' do
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
 
before do
Loading
Loading
@@ -364,21 +364,31 @@ describe 'Pipeline', :js do
wait_for_requests
end
 
it 'shows badge counter in Tests tab' do
expect(pipeline.test_reports.total_count).to eq(4)
expect(page.find('.js-test-report-badge-counter').text).to eq(pipeline.test_reports.total_count.to_s)
end
context 'with test reports' do
it 'shows badge counter in Tests tab' do
expect(pipeline.test_reports.total_count).to eq(4)
expect(page.find('.js-test-report-badge-counter').text).to eq(pipeline.test_reports.total_count.to_s)
end
it 'does not call test_report.json endpoint by default', :js do
expect(page).to have_selector('.js-no-tests-to-show', visible: :all)
end
 
it 'does not call test_report.json endpoint by default', :js do
expect(page).to have_selector('.js-no-tests-to-show', visible: :all)
it 'does call test_report.json endpoint when tab is selected', :js do
find('.js-tests-tab-link').click
wait_for_requests
expect(page).to have_content('Test suites')
expect(page).to have_selector('.js-tests-detail', visible: :all)
end
end
 
it 'does call test_report.json endpoint when tab is selected', :js do
find('.js-tests-tab-link').click
wait_for_requests
context 'without test reports' do
let(:pipeline) { create(:ci_pipeline, project: project) }
 
expect(page).to have_content('Test suites')
expect(page).to have_selector('.js-tests-detail', visible: :all)
it 'shows nothing' do
expect(page.find('.js-test-report-badge-counter', visible: :all).text).to eq("")
end
end
end
 
Loading
Loading
Loading
Loading
@@ -2,6 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import CompareVersionsDropdown from '~/diffs/components/compare_versions_dropdown.vue';
import diffsMockData from '../mock_data/merge_request_diffs';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { TEST_HOST } from 'helpers/test_constants';
 
const localVue = createLocalVue();
const targetBranch = { branchName: 'tmp-wine-dev', versionIndex: -1 };
Loading
Loading
@@ -109,6 +110,24 @@ describe('CompareVersionsDropdown', () => {
 
expect(findLastLink().attributes('href')).toEqual(baseVersionPath);
expect(findLastLink().text()).toContain('(base)');
expect(findLastLink().text()).not.toContain('(HEAD)');
});
it('should render a correct head version link', () => {
Object.defineProperty(window, 'location', {
writable: true,
value: { href: `${TEST_HOST}?diff_head=true` },
});
createComponent({
baseVersionPath,
otherVersions: diffsMockData.slice(1),
targetBranch,
});
expect(findLastLink().attributes('href')).toEqual(baseVersionPath);
expect(findLastLink().text()).not.toContain('(base)');
expect(findLastLink().text()).toContain('(HEAD)');
});
 
it('should not render commits count if no showCommitsCount is passed', () => {
Loading
Loading
Loading
Loading
@@ -21,6 +21,7 @@ describe NotificationsHelper do
describe '#notification_event_name' do
it { expect(notification_event_name(:success_pipeline)).to match('Successful pipeline') }
it { expect(notification_event_name(:failed_pipeline)).to match('Failed pipeline') }
it { expect(notification_event_name(:fixed_pipeline)).to match('Fixed pipeline') }
end
 
describe '#notification_icon_level' do
Loading
Loading
Loading
Loading
@@ -19,7 +19,7 @@ describe Gitlab::Checks::SnippetCheck do
let(:newrev) { '0000000000000000000000000000000000000000' }
 
it 'raises an error' do
expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can not create or delete branches.')
expect { subject.exec }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.')
end
end
 
Loading
Loading
@@ -27,7 +27,7 @@ describe Gitlab::Checks::SnippetCheck do
let(:oldrev) { '0000000000000000000000000000000000000000' }
 
it 'raises an error' do
expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can not create or delete branches.')
expect { subject.exec }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.')
end
end
end
Loading
Loading
Loading
Loading
@@ -26,7 +26,7 @@ describe Gitlab::GitAccessSnippet do
let(:actor) { build(:deploy_key) }
 
it 'does not allow push and pull access' do
expect { pull_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:authentication_mechanism])
expect { pull_access_check }.to raise_forbidden(described_class::ERROR_MESSAGES[:authentication_mechanism])
end
end
 
Loading
Loading
@@ -76,8 +76,8 @@ describe Gitlab::GitAccessSnippet do
it 'blocks access when the user did not accept terms' do
message = /must accept the Terms of Service in order to perform this action/
 
expect { push_access_check }.to raise_unauthorized(message)
expect { pull_access_check }.to raise_unauthorized(message)
expect { push_access_check }.to raise_forbidden(message)
expect { pull_access_check }.to raise_forbidden(message)
end
 
it 'allows access when the user accepted the terms' do
Loading
Loading
@@ -101,13 +101,13 @@ describe Gitlab::GitAccessSnippet do
if Ability.allowed?(user, :update_snippet, snippet)
expect { push_access_check }.not_to raise_error
else
expect { push_access_check }.to raise_error(described_class::UnauthorizedError)
expect { push_access_check }.to raise_error(described_class::ForbiddenError)
end
 
if Ability.allowed?(user, :read_snippet, snippet)
expect { pull_access_check }.not_to raise_error
else
expect { pull_access_check }.to raise_error(described_class::UnauthorizedError)
expect { pull_access_check }.to raise_error(described_class::ForbiddenError)
end
end
end
Loading
Loading
@@ -154,7 +154,7 @@ describe Gitlab::GitAccessSnippet do
 
with_them do
it "respects accessibility" do
error_class = described_class::UnauthorizedError
error_class = described_class::ForbiddenError
 
if Ability.allowed?(user, :update_snippet, snippet)
expect { push_access_check }.not_to raise_error
Loading
Loading
@@ -180,7 +180,7 @@ describe Gitlab::GitAccessSnippet do
allow(::Gitlab::Database).to receive(:read_only?).and_return(true)
allow(::Gitlab::Geo).to receive(:secondary_with_primary?).and_return(true)
 
expect { push_access_check }.to raise_unauthorized(/You can't push code to a read-only GitLab instance/)
expect { push_access_check }.to raise_forbidden(/You can't push code to a read-only GitLab instance/)
end
end
 
Loading
Loading
@@ -198,10 +198,10 @@ describe Gitlab::GitAccessSnippet do
 
it 'raises error if SnippetCheck raises error' do
expect_next_instance_of(Gitlab::Checks::SnippetCheck) do |check|
allow(check).to receive(:exec).and_raise(Gitlab::GitAccess::UnauthorizedError, 'foo')
allow(check).to receive(:exec).and_raise(Gitlab::GitAccess::ForbiddenError, 'foo')
end
 
expect { push_access_check }.to raise_unauthorized('foo')
expect { push_access_check }.to raise_forbidden('foo')
end
end
 
Loading
Loading
@@ -215,7 +215,7 @@ describe Gitlab::GitAccessSnippet do
raise_error(Gitlab::GitAccess::NotFoundError, Gitlab::GitAccess::ERROR_MESSAGES[:project_not_found])
end
 
def raise_unauthorized(message)
raise_error(Gitlab::GitAccess::UnauthorizedError, message)
def raise_forbidden(message)
raise_error(Gitlab::GitAccess::ForbiddenError, message)
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Graphql::Docs::Renderer do
describe '#contents' do
# Returns a Schema that uses the given `type`
def mock_schema(type)
query_type = Class.new(GraphQL::Schema::Object) do
graphql_name 'QueryType'
field :foo, type, null: true
end
GraphQL::Schema.define(query: query_type)
end
let_it_be(:template) { Rails.root.join('lib/gitlab/graphql/docs/templates/', 'default.md.haml') }
subject(:contents) do
described_class.new(
mock_schema(type).graphql_definition,
output_dir: nil,
template: template
).contents
end
context 'A type with a field with a [Array] return type' do
let(:type) do
Class.new(GraphQL::Schema::Object) do
graphql_name 'ArrayTest'
field :foo, [GraphQL::STRING_TYPE], null: false, description: 'A description'
end
end
specify do
expectation = <<~DOC
## ArrayTest
| Name | Type | Description |
| --- | ---- | ---------- |
| `foo` | String! => Array | A description |
DOC
is_expected.to include(expectation)
end
end
context 'A type with fields defined in reverse alphabetical order' do
let(:type) do
Class.new(GraphQL::Schema::Object) do
graphql_name 'OrderingTest'
field :foo, GraphQL::STRING_TYPE, null: false, description: 'A description of foo field'
field :bar, GraphQL::STRING_TYPE, null: false, description: 'A description of bar field'
end
end
specify do
expectation = <<~DOC
## OrderingTest
| Name | Type | Description |
| --- | ---- | ---------- |
| `bar` | String! | A description of bar field |
| `foo` | String! | A description of foo field |
DOC
is_expected.to include(expectation)
end
end
context 'A type with a deprecated field' do
let(:type) do
Class.new(GraphQL::Schema::Object) do
graphql_name 'DeprecatedTest'
field :foo, GraphQL::STRING_TYPE, null: false, deprecation_reason: 'This is deprecated', description: 'A description'
end
end
specify do
expectation = <<~DOC
## DeprecatedTest
| Name | Type | Description |
| --- | ---- | ---------- |
| `foo` **{warning-solid}** | String! | **Deprecated:** This is deprecated |
DOC
is_expected.to include(expectation)
end
end
end
end
Loading
Loading
@@ -192,6 +192,7 @@ ci_pipelines:
- environments
- chat_data
- source_pipeline
- ref_status
- source_bridge
- source_job
- sourced_pipelines
Loading
Loading
@@ -359,6 +360,7 @@ project:
- ci_pipelines
- all_pipelines
- stages
- ci_refs
- builds
- runner_projects
- runners
Loading
Loading
Loading
Loading
@@ -89,6 +89,17 @@ describe Gitlab::IncomingEmail do
it 'does not match emails with extra bits' do
expect(described_class.key_from_address('somereplies+somekey@example.com.someotherdomain.com')).to be nil
end
context 'when a custom wildcard address is used' do
let(:wildcard_address) { 'custom.address+%{key}@example.com' }
it 'finds key if email matches address pattern' do
key = described_class.key_from_address(
'custom.address+foo@example.com', wildcard_address: wildcard_address
)
expect(key).to eq('foo')
end
end
end
 
context 'self.key_from_fallback_message_id' do
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::Client, :clean_gitlab_redis_queues do
let(:worker_class) do
Class.new do
def self.name
'TestDeduplicationWorker'
end
include ApplicationWorker
def perform(*args)
end
end
end
before do
stub_const('TestDeduplicationWorker', worker_class)
end
describe '#call' do
it 'adds a correct duplicate tag to the jobs', :aggregate_failures do
TestDeduplicationWorker.bulk_perform_async([['args1'], ['args2'], ['args1']])
job1, job2, job3 = TestDeduplicationWorker.jobs
expect(job1['duplicate-of']).to be_nil
expect(job2['duplicate-of']).to be_nil
expect(job3['duplicate-of']).to eq(job1['jid'])
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_redis_queues do
subject(:duplicate_job) do
described_class.new(job, queue)
end
let(:job) { { 'class' => 'AuthorizedProjectsWorker', 'args' => [1], 'jid' => '123' } }
let(:queue) { 'authorized_projects' }
let(:idempotency_key) do
hash = Digest::SHA256.hexdigest("#{job['class']}:#{job['args'].join('-')}")
"#{Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE}:duplicate:#{queue}:#{hash}"
end
describe '#schedule' do
it 'calls schedule on the strategy' do
expect do |block|
expect_next_instance_of(Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting) do |strategy|
expect(strategy).to receive(:schedule).with(job, &block)
end
duplicate_job.schedule(&block)
end.to yield_control
end
end
describe '#perform' do
it 'calls perform on the strategy' do
expect do |block|
expect_next_instance_of(Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting) do |strategy|
expect(strategy).to receive(:perform).with(job, &block)
end
duplicate_job.perform(&block)
end.to yield_control
end
end
describe '#check!' do
context 'when there was no job in the queue yet' do
it { expect(duplicate_job.check!).to eq('123') }
it "adds a key with ttl set to #{described_class::DUPLICATE_KEY_TTL}" do
expect { duplicate_job.check! }
.to change { read_idempotency_key_with_ttl(idempotency_key) }
.from([nil, -2])
.to(['123', be_within(1).of(described_class::DUPLICATE_KEY_TTL)])
end
end
context 'when there was already a job with same arguments in the same queue' do
before do
set_idempotency_key(idempotency_key, 'existing-key')
end
it { expect(duplicate_job.check!).to eq('existing-key') }
it "does not change the existing key's TTL" do
expect { duplicate_job.check! }
.not_to change { read_idempotency_key_with_ttl(idempotency_key) }
.from(['existing-key', -1])
end
it 'sets the existing jid' do
duplicate_job.check!
expect(duplicate_job.existing_jid).to eq('existing-key')
end
end
end
describe '#delete!' do
context "when we didn't track the definition" do
it { expect { duplicate_job.delete! }.not_to raise_error }
end
context 'when the key exists in redis' do
before do
set_idempotency_key(idempotency_key, 'existing-key')
end
it 'removes the key from redis' do
expect { duplicate_job.delete! }
.to change { read_idempotency_key_with_ttl(idempotency_key) }
.from(['existing-key', -1])
.to([nil, -2])
end
end
end
describe '#duplicate?' do
it "raises an error if the check wasn't performed" do
expect { duplicate_job.duplicate? }.to raise_error /Call `#check!` first/
end
it 'returns false if the existing jid equals the job jid' do
duplicate_job.check!
expect(duplicate_job.duplicate?).to be(false)
end
it 'returns false if the existing jid is different from the job jid' do
set_idempotency_key(idempotency_key, 'a different jid')
duplicate_job.check!
expect(duplicate_job.duplicate?).to be(true)
end
end
def set_idempotency_key(key, value = '1')
Sidekiq.redis { |r| r.set(key, value) }
end
def read_idempotency_key_with_ttl(key)
Sidekiq.redis do |redis|
redis.pipelined do |p|
p.get(key)
p.ttl(key)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::Server, :clean_gitlab_redis_queues do
let(:worker_class) do
Class.new do
def self.name
'TestDeduplicationWorker'
end
include ApplicationWorker
def perform(*args)
end
end
end
before do
stub_const('TestDeduplicationWorker', worker_class)
end
around do |example|
Sidekiq::Testing.inline! { example.run }
end
before(:context) do
Sidekiq::Testing.server_middleware do |chain|
chain.add described_class
end
end
after(:context) do
Sidekiq::Testing.server_middleware do |chain|
chain.remove described_class
end
end
describe '#call' do
it 'removes the stored job from redis' do
bare_job = { 'class' => 'TestDeduplicationWorker', 'args' => ['hello'] }
job_definition = Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob.new(bare_job.dup, 'test_deduplication')
expect(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob)
.to receive(:new).with(a_hash_including(bare_job), 'test_deduplication')
.and_return(job_definition).twice # once in client middleware
expect(job_definition).to receive(:delete!).and_call_original
TestDeduplicationWorker.perform_async('hello')
end
end
end
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting do
let(:fake_duplicate_job) do
instance_double(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob)
end
subject(:strategy) { described_class.new(fake_duplicate_job) }
describe '#schedule' do
it 'checks for duplicates before yielding' do
expect(fake_duplicate_job).to receive(:check!).ordered.and_return('a jid')
expect(fake_duplicate_job).to receive(:duplicate?).ordered.and_return(false)
expect { |b| strategy.schedule({}, &b) }.to yield_control
end
it 'adds the jid of the existing job to the job hash' do
allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
job_hash = {}
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
expect(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
strategy.schedule(job_hash) {}
expect(job_hash).to include('duplicate-of' => 'the jid')
end
end
describe '#perform' do
it 'deletes the lock before executing' do
expect(fake_duplicate_job).to receive(:delete!).ordered
expect { |b| strategy.perform({}, &b) }.to yield_control
end
end
end
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies do
describe '.for' do
it 'returns the right class for `until_executing`' do
expect(described_class.for(:until_executing)).to eq(described_class::UntilExecuting)
end
it 'raises an UnknownStrategyError when passing an unknown key' do
expect { described_class.for(:unknown) }.to raise_error(described_class::UnknownStrategyError)
end
end
end
Loading
Loading
@@ -46,7 +46,8 @@ describe Gitlab::SidekiqMiddleware do
Gitlab::SidekiqMiddleware::MemoryKiller,
Gitlab::SidekiqMiddleware::RequestStoreMiddleware,
Gitlab::SidekiqMiddleware::WorkerContext::Server,
Gitlab::SidekiqMiddleware::AdminMode::Server
Gitlab::SidekiqMiddleware::AdminMode::Server,
Gitlab::SidekiqMiddleware::DuplicateJobs::Server
]
end
let(:enabled_sidekiq_middlewares) { all_sidekiq_middlewares - disabled_sidekiq_middlewares }
Loading
Loading
@@ -117,7 +118,8 @@ describe Gitlab::SidekiqMiddleware do
Gitlab::SidekiqMiddleware::ClientMetrics,
Gitlab::SidekiqMiddleware::WorkerContext::Client,
Labkit::Middleware::Sidekiq::Client,
Gitlab::SidekiqMiddleware::AdminMode::Client
Gitlab::SidekiqMiddleware::AdminMode::Client,
Gitlab::SidekiqMiddleware::DuplicateJobs::Client
]
end
 
Loading
Loading
Loading
Loading
@@ -106,4 +106,17 @@ describe Emails::Pipelines do
let(:status_text) { 'Your pipeline has failed.' }
end
end
describe '#pipeline_fixed_email' do
subject { Notify.pipeline_fixed_email(pipeline, pipeline.user.try(:email)) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: ref, sha: sha) }
let(:ref) { 'master' }
let(:sha) { project.commit(ref).sha }
it_behaves_like 'correct pipeline information' do
let(:status) { 'been fixed' }
let(:status_text) { 'Your pipeline has been fixed!' }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Ci::Ref do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:last_updated_by_pipeline) }
it { is_expected.to validate_inclusion_of(:status).in_array(%w[success failed fixed]) }
it { is_expected.to validate_presence_of(:last_updated_by_pipeline) }
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment