Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
051f0c95
Commit
051f0c95
authored
Apr 23, 2020
by
Mehmet Emin INAC
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement ExportService class to encapsulate export logic
parent
0e32b4aa
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
204 additions
and
3 deletions
+204
-3
ee/app/services/vulnerability_exports/export_service.rb
ee/app/services/vulnerability_exports/export_service.rb
+76
-0
ee/app/services/vulnerability_exports/exporters/csv_service.rb
...p/services/vulnerability_exports/exporters/csv_service.rb
+3
-3
ee/spec/services/vulnerability_exports/export_service_spec.rb
...pec/services/vulnerability_exports/export_service_spec.rb
+125
-0
No files found.
ee/app/services/vulnerability_exports/export_service.rb
0 → 100644
View file @
051f0c95
# frozen_string_literal: true
module
VulnerabilityExports
class
ExportService
include
::
Gitlab
::
ExclusiveLeaseHelpers
LEASE_TTL
=
1
.
hour
LEASE_NAMESPACE
=
"vulnerability_exports_export"
EXPORTERS
=
{
'csv'
=>
VulnerabilityExports
::
Exporters
::
CsvService
}.
freeze
def
self
.
export
(
vulnerability_export
)
new
(
vulnerability_export
).
export
end
def
initialize
(
vulnerability_export
)
self
.
vulnerability_export
=
vulnerability_export
end
def
export
in_lock
(
lease_key
,
ttl:
LEASE_TTL
)
do
generate_export
if
vulnerability_export
.
created?
end
end
private
attr_accessor
:vulnerability_export
delegate
:exportable
,
to: :vulnerability_export
,
private:
true
delegate
:format
,
to: :vulnerability_export
,
private:
true
def
lease_key
"
#{
LEASE_NAMESPACE
}
:
#{
vulnerability_export
.
id
}
"
end
def
generate_export
vulnerability_export
.
start!
generate_export_file
vulnerability_export
.
finish!
rescue
=>
error
vulnerability_export
.
failed!
raise
(
error
)
ensure
schedule_export_deletion
end
def
generate_export_file
exporter
.
generate
{
|
f
|
vulnerability_export
.
file
=
f
}
vulnerability_export
.
file
.
filename
=
filename
end
def
exporter
EXPORTERS
[
format
].
new
(
vulnerabilities
)
end
def
vulnerabilities
Security
::
VulnerabilitiesFinder
.
new
(
exportable
).
execute
.
with_findings_and_scanner
end
def
schedule_export_deletion
VulnerabilityExports
::
ExportDeletionWorker
.
perform_in
(
1
.
hour
,
vulnerability_export
.
id
)
end
def
filename
[
exportable
.
full_path
.
parameterize
,
'_vulnerabilities_'
,
Time
.
now
.
utc
.
strftime
(
'%FT%H%M'
),
'.'
,
format
].
join
end
end
end
ee/app/services/vulnerability_exports/exporters/csv_service.rb
View file @
051f0c95
...
...
@@ -5,8 +5,8 @@ module VulnerabilityExports
class
CsvService
attr_reader
:vulnerabilities
def
initialize
(
vulnerabilities
_relation
)
@vulnerabilities
=
vulnerabilities
_relation
def
initialize
(
vulnerabilities
)
@vulnerabilities
=
vulnerabilities
end
def
generate
(
&
block
)
...
...
@@ -16,7 +16,7 @@ module VulnerabilityExports
private
def
csv_builder
@csv_builder
||=
CsvBuilder
.
new
(
vulnerabilities
.
with_findings_and_scanner
,
header_to_value_hash
)
@csv_builder
||=
CsvBuilder
.
new
(
vulnerabilities
,
header_to_value_hash
)
end
def
header_to_value_hash
...
...
ee/spec/services/vulnerability_exports/export_service_spec.rb
0 → 100644
View file @
051f0c95
# frozen_string_literal: true
require
'spec_helper'
describe
VulnerabilityExports
::
ExportService
do
describe
'::export'
do
let
(
:vulnerability_export
)
{
create
(
:vulnerability_export
)
}
let
(
:mock_service_object
)
{
instance_double
(
described_class
,
export:
true
)
}
subject
(
:export
)
{
described_class
.
export
(
vulnerability_export
)
}
before
do
allow
(
described_class
).
to
receive
(
:new
).
and_return
(
mock_service_object
)
end
it
'instantiates a new instance of the service class and sends export message to it'
do
export
expect
(
described_class
).
to
have_received
(
:new
).
with
(
vulnerability_export
)
expect
(
mock_service_object
).
to
have_received
(
:export
)
end
end
describe
'#export'
do
let
(
:vulnerability_export
)
{
create
(
:vulnerability_export
,
:created
)
}
let
(
:service_object
)
{
described_class
.
new
(
vulnerability_export
)
}
subject
(
:export
)
{
service_object
.
export
}
context
'generating the export file'
do
let
(
:lease_name
)
{
"vulnerability_exports_export:
#{
vulnerability_export
.
id
}
"
}
before
do
allow
(
service_object
).
to
receive
(
:in_lock
)
end
it
'runs synchronized with distributed semaphore'
do
export
expect
(
service_object
).
to
have_received
(
:in_lock
).
with
(
lease_name
,
ttl:
1
.
hour
)
end
end
context
'when the vulnerability_export is not in `created` state'
do
before
do
allow
(
vulnerability_export
).
to
receive
(
:created?
).
and_return
(
false
)
allow
(
service_object
).
to
receive
(
:generate_export
)
end
it
'does not execute export file generation logic'
do
export
expect
(
service_object
).
not_to
have_received
(
:generate_export
)
end
end
context
'when the vulnerability_export is in `created` state'
do
before
do
allow
(
VulnerabilityExports
::
ExportDeletionWorker
).
to
receive
(
:perform_in
)
end
context
'when the export generation fails'
do
let
(
:error
)
{
RuntimeError
.
new
(
'foo'
)
}
before
do
allow
(
service_object
).
to
receive
(
:generate_export_file
).
and_raise
(
error
)
end
it
'marks the export object as `failed` and propagates the error to the caller'
do
expect
{
export
}.
to
raise_error
(
error
)
expect
(
vulnerability_export
.
failed?
).
to
be_truthy
end
it
'schedules the export deletion background job'
do
expect
{
export
}.
to
raise_error
(
error
)
expect
(
VulnerabilityExports
::
ExportDeletionWorker
).
to
have_received
(
:perform_in
).
with
(
1
.
hour
,
vulnerability_export
.
id
)
end
end
context
'when the export generation succeeds'
do
before
do
allow
(
service_object
).
to
receive
(
:generate_export_file
)
allow
(
vulnerability_export
).
to
receive
(
:start!
)
allow
(
vulnerability_export
).
to
receive
(
:finish!
)
end
it
'marks the state of export object as `started` and then `finished`'
do
export
expect
(
vulnerability_export
).
to
have_received
(
:start!
).
ordered
expect
(
vulnerability_export
).
to
have_received
(
:finish!
).
ordered
end
it
'schedules the export deletion background job'
do
export
expect
(
VulnerabilityExports
::
ExportDeletionWorker
).
to
have_received
(
:perform_in
).
with
(
1
.
hour
,
vulnerability_export
.
id
)
end
end
context
'when the export format is csv'
do
let
(
:vulnerabilities
)
{
Vulnerability
.
none
}
let
(
:mock_relation
)
{
double
(
:relation
,
with_findings_and_scanner:
vulnerabilities
)
}
let
(
:mock_vulnerability_finder_service_object
)
{
instance_double
(
Security
::
VulnerabilitiesFinder
,
execute:
mock_relation
)
}
let
(
:exportable_full_path
)
{
'foo'
}
let
(
:time_suffix
)
{
Time
.
now
.
utc
.
strftime
(
'%FT%H%M'
)
}
let
(
:expected_file_name
)
{
"
#{
exportable_full_path
}
_vulnerabilities_
#{
time_suffix
}
.csv"
}
before
do
allow
(
Security
::
VulnerabilitiesFinder
).
to
receive
(
:new
).
and_return
(
mock_vulnerability_finder_service_object
)
allow
(
vulnerability_export
.
exportable
).
to
receive
(
:full_path
).
and_return
(
exportable_full_path
)
end
around
do
|
example
|
Timecop
.
freeze
{
example
.
run
}
end
it
'calls the VulnerabilityExports::Exporters::CsvService which sets the file and filename'
do
expect
{
export
}.
to
change
{
vulnerability_export
.
file
}
.
and
change
{
vulnerability_export
.
file
&
.
filename
}.
from
(
nil
).
to
(
expected_file_name
)
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment