Commit a0f60907 authored by Mehmet Emin INAC's avatar Mehmet Emin INAC

Strip out logic from Sidekiq worker

parent 4c9cae15
......@@ -12,52 +12,13 @@ module VulnerabilityExports
idempotent!
def perform(project_id, vulnerability_export_id)
project = Project.find_by_id(project_id)
return unless project
def perform(_exportable_id = nil, vulnerability_export_id) # rubocop:disable Style/OptionalArguments
vulnerability_export = Vulnerabilities::Export.find_by_id(vulnerability_export_id)
return unless vulnerability_export
vulnerability_export = project.vulnerability_exports.find_by_id(vulnerability_export_id)
return unless vulnerability_export&.created?
return unless try_obtain_lease_for(project_id, vulnerability_export_id)
schedule_export_deletion(project_id, vulnerability_export_id)
vulnerability_export.start!
vulnerabilities = Security::VulnerabilitiesFinder.new(project).execute
generate_file_data(vulnerability_export.format, vulnerabilities) do |file|
vulnerability_export.file = file
vulnerability_export.file.filename = generate_filename(project, vulnerability_export.format)
vulnerability_export.finish!
end
ExportService.export(vulnerability_export)
rescue => error
logger.error class: self.class.name, message: error.message
vulnerability_export&.failed!
end
private
def try_obtain_lease_for(project_id, vulnerability_export_id)
Gitlab::ExclusiveLease
.new("vulnerability_exports_export:#{project_id}/#{vulnerability_export_id}", timeout: LEASE_TIMEOUT)
.try_obtain
end
def generate_file_data(format, vulnerabilities, &block)
case format
when 'csv'
VulnerabilityExports::ExportCsvService.new(vulnerabilities).csv_data(&block)
end
end
def schedule_export_deletion(project_id, vulnerability_export_id)
VulnerabilityExports::ExportDeletionWorker.perform_in(1.hour, project_id, vulnerability_export_id)
end
def generate_filename(project, format)
"#{project.full_path.parameterize}_vulnerabilities_#{Time.now.utc.strftime('%FT%H%M')}.#{format}"
end
end
end
......@@ -4,67 +4,54 @@ require 'spec_helper'
RSpec.describe VulnerabilityExports::ExportWorker, type: :worker do
describe '#perform' do
let_it_be(:project) { create(:project, :with_vulnerability) }
let!(:vulnerability_export) { create(:vulnerability_export, :created, :csv, project: project) }
let(:worker) { described_class.new }
subject(:export_vulnerabilities) { worker.perform(vulnerability_export_id) }
before do
allow(VulnerabilityExports::ExportDeletionWorker).to receive(:perform_in)
allow(VulnerabilityExports::ExportService).to receive(:export)
allow(Sidekiq.logger).to receive(:error)
end
context 'when vulnerability export does not exist' do
subject { worker.perform(project.id, 9999) }
let(:vulnerability_export_id) { nil }
it 'does not raise any error' do
expect { subject }.not_to raise_error
expect { export_vulnerabilities }.not_to raise_error
end
it 'does not call VulnerabilityExports::ExportService::export' do
export_vulnerabilities
expect(VulnerabilityExports::ExportService).not_to have_received(:export)
end
end
context 'when vulnerability export exists' do
include_examples 'an idempotent worker' do
let(:job_args) { [project.id, vulnerability_export.id] }
context 'when export can be performed successfully' do
it 'creates new export file' do
subject
vulnerability_export.reload
expect(vulnerability_export).to be_finished
expect(vulnerability_export.file.read).to include('Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE')
end
it 'schedules job to delete export in 1 hour' do
expect(VulnerabilityExports::ExportDeletionWorker).to receive(:perform_in).with(1.hour, project.id, vulnerability_export.id)
subject
end
end
let(:vulnerability_export) { create(:vulnerability_export, :created, :csv) }
let(:vulnerability_export_id) { vulnerability_export.id }
it 'calls VulnerabilityExports::ExportService::export with the vulnerability_export object' do
export_vulnerabilities
expect(VulnerabilityExports::ExportService).to have_received(:export).with(vulnerability_export)
end
context 'when export fails' do
subject { worker.perform(project.id, vulnerability_export.id) }
let(:error_message) { 'Foo' }
before do
allow_any_instance_of(Vulnerabilities::Export).to receive(:finish!).and_raise(ActiveRecord::RecordInvalid)
allow(VulnerabilityExports::ExportService).to receive(:export).and_raise(error_message)
end
it 'does not raise exception' do
expect { subject }.not_to raise_error
expect { export_vulnerabilities }.not_to raise_error
end
it 'logs error' do
expect(Sidekiq.logger).to receive(:error).with(class: described_class.name, message: anything)
subject
end
it 'sets status of the export to failed' do
expect_any_instance_of(Vulnerabilities::Export).to receive(:failed!)
subject
end
export_vulnerabilities
it 'schedules job to delete export in 1 hour' do
expect(VulnerabilityExports::ExportDeletionWorker).to receive(:perform_in).with(1.hour, project.id, vulnerability_export.id)
subject
expect(Sidekiq.logger).to have_received(:error).with(class: described_class.name, message: error_message)
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment