Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-14 15:13:32 +00:00
parent 2896c7471a
commit 1123408ec8
28 changed files with 245 additions and 157 deletions

View File

@ -12,7 +12,6 @@ Style/OpenStructUse:
- lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
- lib/gitlab/testing/request_inspector_middleware.rb
- lib/mattermost/session.rb
- spec/controllers/projects/clusters_controller_spec.rb
- spec/factories/go_module_versions.rb
- spec/factories/wiki_pages.rb
- spec/graphql/mutations/branches/create_spec.rb

View File

@ -77,6 +77,7 @@ export default class IssuableForm {
this.initAutosave();
this.form.on('submit', this.handleSubmit);
this.form.on('click', '.btn-cancel', this.resetAutosave);
this.form.find('.js-unwrap-on-load').unwrap();
this.initWip();
const $issuableDueDate = $('#issuable-due-date');

View File

@ -150,6 +150,10 @@ label {
margin-bottom: 0;
margin-top: #{$grid-size / 2};
font-size: $gl-font-size;
.invisible {
visibility: hidden;
}
}
.gl-field-error,

View File

@ -42,8 +42,6 @@
}
:first-child {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
line-height: $gl-line-height;
}
@ -52,7 +50,6 @@
}
:last-child {
border-bottom-right-radius: $border-radius-default;
border-top-right-radius: $border-radius-default;
border-radius: $border-radius-default;
}
}

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Groups
class UpdateStatisticsService
attr_reader :group, :statistics
def initialize(group, statistics: [])
@group = group
@statistics = statistics
end
def execute
unless group
return ServiceResponse.error(message: 'Invalid group', http_status: 400)
end
namespace_statistics.refresh!(only: statistics.map(&:to_sym))
ServiceResponse.success(message: 'Group statistics successfully updated.')
end
private
def namespace_statistics
@namespace_statistics ||= group.namespace_statistics || group.build_namespace_statistics
end
end
end

View File

@ -20,10 +20,9 @@
= _("Verification status")
.col-sm-10
.status-badge
- text, status = domain_presenter.unverified? ? [_('Unverified'), 'badge-danger'] : [_('Verified'), 'badge-success']
.badge{ class: status }
= text
= link_to sprite_icon("redo"), verify_project_pages_domain_path(@project, domain_presenter), method: :post, class: "gl-button btn btn-default has-tooltip", title: _("Retry verification")
- text, status = domain_presenter.unverified? ? [_('Unverified'), :danger] : [_('Verified'), :success]
= gl_badge_tag text, variant: status
= link_to sprite_icon("redo"), verify_project_pages_domain_path(@project, domain_presenter), method: :post, class: "gl-ml-2 gl-button btn btn-default has-tooltip", title: _("Retry verification")
.input-group
= text_field_tag :domain_verification, verification_record, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append

View File

@ -14,13 +14,15 @@
- if issuable.respond_to?(:work_in_progress?)
.form-text.text-muted
.js-wip-explanation
.js-wip-explanation{ style: "display: none;" }
= remove_wip_text
.js-no-wip-explanation
- if has_wip_commits
= _('It looks like you have some draft commits in this branch.')
%br
= add_wip_text
.invisible
.js-unwrap-on-load
= add_wip_text
- if no_issuable_templates && can?(current_user, :push_code, issuable.project)
= render 'shared/issuable/form/default_templates'

View File

@ -2335,6 +2335,15 @@
:weight: 1
:idempotent:
:tags: []
- :name: groups_update_statistics
:worker_name: Groups::UpdateStatisticsWorker
:feature_category: :source_code_management
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
:idempotent: true
:tags: []
- :name: import_issues_csv
:worker_name: ImportIssuesCsvWorker
:feature_category: :team_planning

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
# Worker for updating group statistics.
module Groups
class UpdateStatisticsWorker
include ApplicationWorker
data_consistency :always
sidekiq_options retry: 3
worker_resource_boundary :cpu
feature_category :source_code_management
idempotent!
loggable_arguments 0, 1
# group_id - The ID of the group for which to flush the cache.
# statistics - An Array containing columns from NamespaceStatistics to
# refresh, if empty all columns will be refreshed
def perform(group_id, statistics = [])
group = Group.find_by_id(group_id)
return unless group
Groups::UpdateStatisticsService.new(group, statistics: statistics).execute
end
end
end

View File

@ -1,8 +0,0 @@
---
name: ci_skip_require_credit_card_for_addon_ci_minutes
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77829
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349841
milestone: '14.7'
type: development
group: group::fulfillment
default_enabled: true

View File

@ -387,6 +387,7 @@ Therefore, document new uploads here by slotting them into the following tables:
| Container image cache (?) | `direct upload` | `workhorse` | `/dependency-proxy/<group_id_hash>/dependency_proxy/<group_id>/files/<proxy_id>/<blob_id or manifest_id>` |
| Terraform state files | `carrierwave` | `rails controller` | `/terraform/<proj_id_hash>/<terraform_state_id>` |
| Pages content archives | `carrierwave` | `sidekiq` | `/gitlab-gprd-pages/<proj_id_hash>/pages_deployments/<deployment_id>/` |
| Secure Files | `carrierwave` | `sidekiq` | `/ci-secure-files/<proj_id_hash>/secure_files/<secure_file_id>/` |
#### CarrierWave integration
@ -426,3 +427,4 @@ Therefore, document new uploads here by slotting them into the following tables:
| `app/models/concerns/packages/debian/distribution.rb` | `mount_uploader :signed_file, Packages::Debian::DistributionReleaseFileUploader` | :white_check_mark: |
| `app/models/bulk_imports/export_upload.rb` | `mount_uploader :export_file, ExportUploader` | :white_check_mark: |
| `ee/app/models/user_permission_export_upload.rb` | `mount_uploader :file, AttachmentUploader` | |
| `app/models/ci/secure_file.rb` | `include FileStoreMounter` | |

View File

@ -16,17 +16,13 @@ Advanced Search provides faster search response times and [improved search featu
> Support for Elasticsearch 6.8 was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/350275) in GitLab 14.8 and is scheduled for removal in GitLab 15.0.
<!-- Remember to update ee/lib/system_check/app/elasticsearch_check.rb if this changes -->
| GitLab version | Elasticsearch version |
|------------------------------------------------|--------------------------------|
| GitLab Enterprise Edition 14.8 or later | Elasticsearch 7.x through 7.17 |
| GitLab Enterprise Edition 13.9 through 14.7 | Elasticsearch 6.8 through 7.17 |
| GitLab Enterprise Edition 13.3 through 13.8 | Elasticsearch 6.4 through 7.x |
| GitLab Enterprise Edition 12.7 through 13.2 | Elasticsearch 6.x through 7.x |
| GitLab Enterprise Edition 11.5 through 12.6 | Elasticsearch 5.6 through 6.x |
| GitLab Enterprise Edition 9.0 through 11.4 | Elasticsearch 5.1 through 5.5 |
| GitLab Enterprise Edition 8.4 through 8.17 | Elasticsearch 2.4 with [Delete By Query Plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/2.4/plugins-delete-by-query.html) installed |
| GitLab version | Elasticsearch version |
|----------------------|--------------------------|
| GitLab 14.8 or later | Elasticsearch 7.x - 7.17 |
| GitLab 13.9 - 14.7 | Elasticsearch 6.8 - 7.x |
| GitLab 13.3 - 13.8 | Elasticsearch 6.4 - 7.x |
| GitLab 12.7 - 13.2 | Elasticsearch 6.x - 7.x |
| GitLab 11.5 - 12.6 | Elasticsearch 5.6 - 6.x |
The Elasticsearch Integration works with supported versions of
Elasticsearch and follows Elasticsearch's [End of Life Policy](https://www.elastic.co/support/eol).

View File

@ -1,8 +1,7 @@
---
stage: Create
group: Source Code
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
type: concepts, howto
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Sign commits and tags with X.509 certificates **(FREE)**
@ -335,7 +334,7 @@ step of the previous [main verification checks](#main-verification-checks).
signature.__send__(:p7).verify([], signature.__send__(:cert_store), signature.__send__(:signed_text))
```
1. If this fails, add the missing certificate(s) required to establish trust
1. If this fails, add the missing certificates required to establish trust
[to the GitLab certificate store](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
1. After adding more certificates, (if these troubleshooting steps then pass)
@ -347,7 +346,7 @@ step of the previous [main verification checks](#main-verification-checks).
pp signature.__send__(:p7).certificates ; nil
```
Ensure any additional intermediate certificate(s) and the root certificate are added
Ensure any additional intermediate certificates and the root certificate are added
to the certificate store. For consistency with how certificate chains are built on
web servers:

View File

@ -126,7 +126,7 @@ module Gitlab
location_fingerprints.map do |location_fingerprint|
FindingKey.new(location_fingerprint: location_fingerprint, identifier_fingerprint: identifier.fingerprint)
end
end
end.push(uuid)
end
def primary_identifier_fingerprint

View File

@ -11,6 +11,8 @@ module Gitlab
end
def ==(other)
return false unless other.is_a?(self.class)
has_fingerprints? && other.has_fingerprints? &&
location_fingerprint == other.location_fingerprint &&
identifier_fingerprint == other.identifier_fingerprint

View File

@ -11,6 +11,7 @@ kaniko-build:
# Additional options for Kaniko executor.
# For more details see https://github.com/GoogleContainerTools/kaniko/blob/master/README.md#additional-flags
KANIKO_ARGS: ""
KANIKO_BUILD_CONTEXT: $CI_PROJECT_DIR
stage: build
image:
# For latest releases see https://github.com/GoogleContainerTools/kaniko/releases
@ -40,8 +41,13 @@ kaniko-build:
# Write credentials to access Gitlab Container Registry within the runner/ci
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
# Build and push the container. To disable push add --no-push
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$VERSION $KANIKO_ARGS
- DOCKERFILE_PATH=${DOCKERFILE_PATH:-"$KANIKO_BUILD_CONTEXT/Dockerfile"}
- /kaniko/executor --context $KANIKO_BUILD_CONTEXT --dockerfile $DOCKERFILE_PATH --destination $CI_REGISTRY_IMAGE:$VERSION $KANIKO_ARGS
# Run this job in a branch/tag where a Dockerfile exists
rules:
- exists:
- Dockerfile
# custom Dockerfile path
- if: $DOCKERFILE_PATH
# custom build context without an explicit Dockerfile path
- if: $KANIKO_BUILD_CONTEXT != $CI_PROJECT_DIR

View File

@ -972,18 +972,6 @@ module Gitlab
@praefect_info_client ||= Gitlab::GitalyClient::PraefectInfoService.new(self)
end
def clean_stale_repository_files
wrapped_gitaly_errors do
gitaly_repository_client.cleanup if exists?
end
rescue Gitlab::Git::CommandError => e # Don't fail if we can't cleanup
Gitlab::AppLogger.error("Unable to clean repository on storage #{storage} with relative path #{relative_path}: #{e.message}")
Gitlab::Metrics.counter(
:failed_repository_cleanup_total,
'Number of failed repository cleanup events'
).increment
end
def branch_names_contains_sha(sha)
gitaly_ref_client.branch_names_contains_sha(sha)
end

View File

@ -328,11 +328,6 @@ module Gitlab
raise ForbiddenError, error_message(:push_code)
end
else
# If there are worktrees with a HEAD pointing to a non-existent object,
# calls to `git rev-list --all` will fail in git 2.15+. This should also
# clear stale lock files.
project.repository.clean_stale_repository_files if project.present?
check_access!
end
end
@ -467,11 +462,6 @@ module Gitlab
def check_push_size!
return unless check_size_limit?
# If there are worktrees with a HEAD pointing to a non-existent object,
# calls to `git rev-list --all` will fail in git 2.15+. This should also
# clear stale lock files.
repository.clean_stale_repository_files
# Use #check_repository_disk_size to get correct push size whenever a lot of changes
# gets pushed at the same time containing the same blobs. This is only
# doable if GIT_OBJECT_DIRECTORY_RELATIVE env var is set and happens

View File

@ -21,11 +21,6 @@ module Gitlab
response.exists
end
def cleanup
request = Gitaly::CleanupRequest.new(repository: @gitaly_repo)
GitalyClient.call(@storage, :repository_service, :cleanup, request, timeout: GitalyClient.fast_timeout)
end
def garbage_collect(create_bitmap, prune:)
request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap, prune: prune)
GitalyClient.call(@storage, :repository_service, :garbage_collect, request, timeout: GitalyClient.long_timeout)

View File

@ -18,7 +18,11 @@ module GitlabEdition
end
def self.ee?
@is_ee ||=
# To reduce dependencies in QA image we are not using
# `Gitlab::Utils::StrongMemoize` but reimplementing its functionality.
return @is_ee if defined?(@is_ee)
@is_ee =
# We use this method when the Rails environment is not loaded. This
# means that checking the presence of the License class could result in
# this method returning `false`, even for an EE installation.
@ -34,7 +38,9 @@ module GitlabEdition
end
def self.jh?
@is_jh ||=
return @is_jh if defined?(@is_jh)
@is_jh =
ee? &&
root.join('jh').exist? &&
!%w[true 1].include?(ENV['EE_ONLY'].to_s)

View File

@ -315,7 +315,8 @@ RSpec.describe Projects::ClustersController do
.to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s)
allow_any_instance_of(GoogleApi::CloudPlatform::Client)
.to receive(:projects_zones_clusters_create) do
OpenStruct.new(
double(
'secure',
self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123',
status: 'RUNNING'
)

View File

@ -6,36 +6,47 @@ RSpec.describe Gitlab::Ci::Reports::Security::FindingKey do
using RSpec::Parameterized::TableSyntax
describe '#==' do
where(:location_fp_1, :location_fp_2, :identifier_fp_1, :identifier_fp_2, :equals?) do
nil | 'different location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | nil | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'different location fp' | nil | 'different identifier fp' | false
'location fp' | 'different location fp' | 'identifier fp' | nil | false
nil | nil | 'identifier fp' | 'identifier fp' | false
'location fp' | 'location fp' | nil | nil | false
nil | nil | nil | nil | false
'location fp' | 'different location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'different location fp' | 'identifier fp' | 'identifier fp' | false
'location fp' | 'location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'location fp' | 'identifier fp' | 'identifier fp' | true
context 'when the comparison is done between FindingKey instances' do
where(:location_fp_1, :location_fp_2, :identifier_fp_1, :identifier_fp_2, :equals?) do
nil | 'different location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | nil | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'different location fp' | nil | 'different identifier fp' | false
'location fp' | 'different location fp' | 'identifier fp' | nil | false
nil | nil | 'identifier fp' | 'identifier fp' | false
'location fp' | 'location fp' | nil | nil | false
nil | nil | nil | nil | false
'location fp' | 'different location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'different location fp' | 'identifier fp' | 'identifier fp' | false
'location fp' | 'location fp' | 'identifier fp' | 'different identifier fp' | false
'location fp' | 'location fp' | 'identifier fp' | 'identifier fp' | true
end
with_them do
let(:finding_key_1) do
build(:ci_reports_security_finding_key,
location_fingerprint: location_fp_1,
identifier_fingerprint: identifier_fp_1)
end
let(:finding_key_2) do
build(:ci_reports_security_finding_key,
location_fingerprint: location_fp_2,
identifier_fingerprint: identifier_fp_2)
end
subject { finding_key_1 == finding_key_2 }
it { is_expected.to be(equals?) }
end
end
with_them do
let(:finding_key_1) do
build(:ci_reports_security_finding_key,
location_fingerprint: location_fp_1,
identifier_fingerprint: identifier_fp_1)
end
context 'when the comparison is not done between FindingKey instances' do
let(:finding_key) { build(:ci_reports_security_finding_key) }
let(:uuid) { SecureRandom.uuid }
let(:finding_key_2) do
build(:ci_reports_security_finding_key,
location_fingerprint: location_fp_2,
identifier_fingerprint: identifier_fp_2)
end
subject { finding_key == uuid }
subject { finding_key_1 == finding_key_2 }
it { is_expected.to be(equals?) }
it { is_expected.to be_falsey }
end
end
end

View File

@ -2252,44 +2252,6 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end
end
describe '#clean_stale_repository_files' do
let(:worktree_id) { 'rebase-1' }
let(:gitlab_worktree_path) { File.join(repository_path, 'gitlab-worktree', worktree_id) }
let(:admin_dir) { File.join(repository_path, 'worktrees') }
it 'cleans up the files' do
create_worktree = %W[git -C #{repository_path} worktree add --detach #{gitlab_worktree_path} master]
raise 'preparation failed' unless system(*create_worktree, err: '/dev/null')
FileUtils.touch(gitlab_worktree_path, mtime: Time.now - 8.hours)
# git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object,
# but the HEAD must be 40 characters long or git will ignore it.
File.write(File.join(admin_dir, worktree_id, 'HEAD'), Gitlab::Git::BLANK_SHA)
expect(rev_list_all).to be(false)
repository.clean_stale_repository_files
expect(rev_list_all).to be(true)
expect(File.exist?(gitlab_worktree_path)).to be_falsey
end
def rev_list_all
system(*%W[git -C #{repository_path} rev-list --all], out: '/dev/null', err: '/dev/null')
end
it 'increments a counter upon an error' do
expect(repository.gitaly_repository_client).to receive(:cleanup).and_raise(Gitlab::Git::CommandError)
counter = double(:counter)
expect(counter).to receive(:increment)
expect(Gitlab::Metrics).to receive(:counter).with(:failed_repository_cleanup_total,
'Number of failed repository cleanup events').and_return(counter)
repository.clean_stale_repository_files
end
end
describe '#squash' do
let(:branch_name) { 'fix' }
let(:start_sha) { '4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6' }

View File

@ -1008,11 +1008,6 @@ RSpec.describe Gitlab::GitAccess do
end
end
it 'cleans up the files' do
expect(project.repository).to receive(:clean_stale_repository_files).and_call_original
expect { push_access_check }.not_to raise_error
end
it 'avoids N+1 queries', :request_store do
# Run this once to establish a baseline. Cached queries should get
# cached, so that when we introduce another change we shouldn't see

View File

@ -21,16 +21,6 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
end
end
describe '#cleanup' do
it 'sends a cleanup message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:cleanup)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
client.cleanup
end
end
describe '#garbage_collect' do
it 'sends a garbage_collect message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)

View File

@ -3,18 +3,22 @@
require 'spec_helper'
RSpec.describe GitlabEdition do
def remove_instance_variable(ivar)
described_class.remove_instance_variable(ivar) if described_class.instance_variable_defined?(ivar)
end
before do
# Make sure the ENV is clean
stub_env('FOSS_ONLY', nil)
stub_env('EE_ONLY', nil)
described_class.instance_variable_set(:@is_ee, nil)
described_class.instance_variable_set(:@is_jh, nil)
remove_instance_variable(:@is_ee)
remove_instance_variable(:@is_jh)
end
after do
described_class.instance_variable_set(:@is_ee, nil)
described_class.instance_variable_set(:@is_jh, nil)
remove_instance_variable(:@is_ee)
remove_instance_variable(:@is_jh)
end
describe '.root' do
@ -51,7 +55,7 @@ RSpec.describe GitlabEdition do
allow(described_class).to receive(:ee?).and_return(false)
end
it 'returns the exyensions according to the current edition' do
it 'returns the extensions according to the current edition' do
expect(described_class.extensions).to be_empty
end
end
@ -77,7 +81,7 @@ RSpec.describe GitlabEdition do
end
describe '.ee?' do
context 'for EE' do
context 'when EE' do
before do
stub_path('ee/app/models/license.rb', exist?: true)
end
@ -109,7 +113,7 @@ RSpec.describe GitlabEdition do
end
end
context 'for CE' do
context 'when CE' do
before do
stub_path('ee/app/models/license.rb', exist?: false)
end
@ -121,12 +125,9 @@ RSpec.describe GitlabEdition do
end
describe '.jh?' do
context 'for JH' do
context 'when JH' do
before do
stub_path(
'ee/app/models/license.rb',
'jh',
exist?: true)
stub_path('ee/app/models/license.rb', 'jh', exist?: true)
end
context 'when using default FOSS_ONLY and EE_ONLY' do

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::UpdateStatisticsService do
let_it_be(:group, reload: true) { create(:group) }
let(:statistics) { %w(wiki_size) }
subject(:service) { described_class.new(group, statistics: statistics)}
describe '#execute', :aggregate_failures do
context 'when group is nil' do
let(:group) { nil }
it 'does nothing' do
expect(NamespaceStatistics).not_to receive(:new)
result = service.execute
expect(result).to be_error
end
end
context 'with an existing group' do
context 'when namespace statistics exists for the group' do
it 'uses the existing statistics and refreshes them' do
namespace_statistics = create(:namespace_statistics, namespace: group)
expect(namespace_statistics).to receive(:refresh!).with(only: statistics.map(&:to_sym)).and_call_original
result = service.execute
expect(result).to be_success
end
end
context 'when namespace statistics does not exist for the group' do
it 'creates the statistics and refreshes them' do
expect_next_instance_of(NamespaceStatistics) do |instance|
expect(instance).to receive(:refresh!).with(only: statistics.map(&:to_sym)).and_call_original
end
result = nil
expect do
result = service.execute
end.to change { NamespaceStatistics.count }.by(1)
expect(result).to be_success
end
end
end
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::UpdateStatisticsWorker do
let_it_be(:group) { create(:group) }
let(:statistics) { %w(wiki_size) }
subject(:worker) { described_class.new }
describe '#perform' do
it 'updates the group statistics' do
expect(Groups::UpdateStatisticsService).to receive(:new)
.with(group, statistics: statistics)
.and_call_original
worker.perform(group.id, statistics)
end
context 'when group id does not exist' do
it 'ends gracefully' do
expect(Groups::UpdateStatisticsService).not_to receive(:new)
expect { worker.perform(non_existing_record_id, statistics) }.not_to raise_error
end
end
end
end