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
e1ad8ca6
Commit
e1ad8ca6
authored
May 04, 2018
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Test trace_spec on both conditions - ci_enable_live_trace is on/off
parent
28284c14
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
747 additions
and
660 deletions
+747
-660
spec/lib/gitlab/ci/trace_spec.rb
spec/lib/gitlab/ci/trace_spec.rb
+6
-660
spec/support/shared_examples/ci_trace_shared_exmaples.rb
spec/support/shared_examples/ci_trace_shared_exmaples.rb
+741
-0
No files found.
spec/lib/gitlab/ci/trace_spec.rb
View file @
e1ad8ca6
...
@@ -4,678 +4,24 @@ describe Gitlab::Ci::Trace, :clean_gitlab_redis_cache do
...
@@ -4,678 +4,24 @@ describe Gitlab::Ci::Trace, :clean_gitlab_redis_cache do
let
(
:build
)
{
create
(
:ci_build
)
}
let
(
:build
)
{
create
(
:ci_build
)
}
let
(
:trace
)
{
described_class
.
new
(
build
)
}
let
(
:trace
)
{
described_class
.
new
(
build
)
}
before
do
stub_feature_flags
(
ci_enable_live_trace:
true
)
end
describe
"associations"
do
describe
"associations"
do
it
{
expect
(
trace
).
to
respond_to
(
:job
)
}
it
{
expect
(
trace
).
to
respond_to
(
:job
)
}
it
{
expect
(
trace
).
to
delegate_method
(
:old_trace
).
to
(
:job
)
}
it
{
expect
(
trace
).
to
delegate_method
(
:old_trace
).
to
(
:job
)
}
end
end
describe
'#html'
do
context
'when live trace feature is disabled'
do
before
do
trace
.
set
(
"12
\n
34"
)
end
it
"returns formatted html"
do
expect
(
trace
.
html
).
to
eq
(
"12<br>34"
)
end
it
"returns last line of formatted html"
do
expect
(
trace
.
html
(
last_lines:
1
)).
to
eq
(
"34"
)
end
end
describe
'#raw'
do
before
do
trace
.
set
(
"12
\n
34"
)
end
it
"returns raw output"
do
expect
(
trace
.
raw
).
to
eq
(
"12
\n
34"
)
end
it
"returns last line of raw output"
do
expect
(
trace
.
raw
(
last_lines:
1
)).
to
eq
(
"34"
)
end
end
describe
'#extract_coverage'
do
let
(
:regex
)
{
'\(\d+.\d+\%\) covered'
}
context
'matching coverage'
do
before
do
trace
.
set
(
'Coverage 1033 / 1051 LOC (98.29%) covered'
)
end
it
"returns valid coverage"
do
expect
(
trace
.
extract_coverage
(
regex
)).
to
eq
(
"98.29"
)
end
end
context
'no coverage'
do
before
do
trace
.
set
(
'No coverage'
)
end
it
'returs nil'
do
expect
(
trace
.
extract_coverage
(
regex
)).
to
be_nil
end
end
end
describe
'#extract_sections'
do
let
(
:log
)
{
'No sections'
}
let
(
:sections
)
{
trace
.
extract_sections
}
before
do
trace
.
set
(
log
)
end
context
'no sections'
do
it
'returs []'
do
expect
(
trace
.
extract_sections
).
to
eq
([])
end
end
context
'multiple sections available'
do
let
(
:log
)
{
File
.
read
(
expand_fixture_path
(
'trace/trace_with_sections'
))
}
let
(
:sections_data
)
do
[
{
name:
'prepare_script'
,
lines:
2
,
duration:
3
.
seconds
},
{
name:
'get_sources'
,
lines:
4
,
duration:
1
.
second
},
{
name:
'restore_cache'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'download_artifacts'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'build_script'
,
lines:
2
,
duration:
1
.
second
},
{
name:
'after_script'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'archive_cache'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'upload_artifacts'
,
lines:
0
,
duration:
0
.
seconds
}
]
end
it
"returns valid sections"
do
expect
(
sections
).
not_to
be_empty
expect
(
sections
.
size
).
to
eq
(
sections_data
.
size
),
"expected
#{
sections_data
.
size
}
sections, got
#{
sections
.
size
}
"
buff
=
StringIO
.
new
(
log
)
sections
.
each_with_index
do
|
s
,
i
|
expected
=
sections_data
[
i
]
expect
(
s
[
:name
]).
to
eq
(
expected
[
:name
])
expect
(
s
[
:date_end
]
-
s
[
:date_start
]).
to
eq
(
expected
[
:duration
])
buff
.
seek
(
s
[
:byte_start
],
IO
::
SEEK_SET
)
length
=
s
[
:byte_end
]
-
s
[
:byte_start
]
lines
=
buff
.
read
(
length
).
count
(
"
\n
"
)
expect
(
lines
).
to
eq
(
expected
[
:lines
])
end
end
end
context
'logs contains "section_start"'
do
let
(
:log
)
{
"section_start:1506417476:a_section
\r\033
[0Klooks like a section_start:invalid
\n
section_end:1506417477:a_section
\r\033
[0K"
}
it
"returns only one section"
do
expect
(
sections
).
not_to
be_empty
expect
(
sections
.
size
).
to
eq
(
1
)
section
=
sections
[
0
]
expect
(
section
[
:name
]).
to
eq
(
'a_section'
)
expect
(
section
[
:byte_start
]).
not_to
eq
(
section
[
:byte_end
]),
"got an empty section"
end
end
context
'missing section_end'
do
let
(
:log
)
{
"section_start:1506417476:a_section
\r\033
[0KSome logs
\n
No section_end
\n
"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
context
'missing section_start'
do
let
(
:log
)
{
"Some logs
\n
No section_start
\n
section_end:1506417476:a_section
\r\033
[0K"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
context
'inverted section_start section_end'
do
let
(
:log
)
{
"section_end:1506417476:a_section
\r\033
[0Klooks like a section_start:invalid
\n
section_start:1506417477:a_section
\r\033
[0K"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
end
describe
'#set'
do
before
do
trace
.
set
(
"12"
)
end
it
"returns trace"
do
expect
(
trace
.
raw
).
to
eq
(
"12"
)
end
context
'overwrite trace'
do
before
do
trace
.
set
(
"34"
)
end
it
"returns new trace"
do
expect
(
trace
.
raw
).
to
eq
(
"34"
)
end
end
context
'runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
trace
.
set
(
token
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
context
'hides build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
trace
.
set
(
token
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
end
describe
'#append'
do
before
do
trace
.
set
(
"1234"
)
end
it
"returns correct trace"
do
expect
(
trace
.
append
(
"56"
,
4
)).
to
eq
(
6
)
expect
(
trace
.
raw
).
to
eq
(
"123456"
)
end
context
'tries to append trace at different offset'
do
it
"fails with append"
do
expect
(
trace
.
append
(
"56"
,
2
)).
to
eq
(
-
4
)
expect
(
trace
.
raw
).
to
eq
(
"1234"
)
end
end
context
'runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
trace
.
append
(
token
,
0
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
context
'build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
trace
.
append
(
token
,
0
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
end
describe
'#read'
do
shared_examples
'read successfully with IO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
IO
)
end
end
end
shared_examples
'read successfully with StringIO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
StringIO
)
end
end
end
shared_examples
'read successfully with ChunkedIO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
ChunkedIO
)
end
end
end
shared_examples
'failed to read'
do
it
'yields without source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_nil
end
end
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it_behaves_like
'read successfully with IO'
end
context
'when current_path (with project_id) exists'
do
before
do
expect
(
trace
).
to
receive
(
:default_path
)
{
expand_fixture_path
(
'trace/sample_trace'
)
}
end
it_behaves_like
'read successfully with IO'
end
context
'when current_path (with project_ci_id) exists'
do
before
do
expect
(
trace
).
to
receive
(
:deprecated_path
)
{
expand_fixture_path
(
'trace/sample_trace'
)
}
end
it_behaves_like
'read successfully with IO'
end
context
'when db trace exists'
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
"data"
)
end
it_behaves_like
'read successfully with StringIO'
end
context
'when live trace exists'
do
before
do
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
stream
.
write
(
'abc'
)
end
end
it_behaves_like
'read successfully with ChunkedIO'
end
context
'when no sources exist'
do
it_behaves_like
'failed to read'
end
end
describe
'trace handling'
do
subject
{
trace
.
exist?
}
context
'trace does not exist'
do
it
{
expect
(
trace
.
exist?
).
to
be
(
false
)
}
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
{
is_expected
.
to
be_truthy
}
context
'when the trace artifact has been erased'
do
before
do
trace
.
erase!
end
it
{
is_expected
.
to
be_falsy
}
it
'removes associations'
do
expect
(
Ci
::
JobArtifact
.
exists?
(
job_id:
build
.
id
,
file_type: :trace
)).
to
be_falsy
end
end
end
context
'new trace path is used'
do
before
do
trace
.
send
(
:ensure_directory
)
File
.
open
(
trace
.
send
(
:default_path
),
"w"
)
do
|
file
|
file
.
write
(
"data"
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
end
context
'deprecated path'
do
let
(
:path
)
{
trace
.
send
(
:deprecated_path
)
}
context
'with valid ci_id'
do
before
do
build
.
project
.
update
(
ci_id:
1000
)
FileUtils
.
mkdir_p
(
File
.
dirname
(
path
))
File
.
open
(
path
,
"w"
)
do
|
file
|
file
.
write
(
"data"
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
end
context
'without valid ci_id'
do
it
"does not return deprecated path"
do
expect
(
path
).
to
be_nil
end
end
end
context
'stored in database'
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
"data"
)
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
it
"returns database data"
do
expect
(
trace
.
raw
).
to
eq
(
"data"
)
end
end
context
'stored in database'
do
before
do
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
stream
.
write
(
'abc'
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
expect
(
Ci
::
BuildTraceChunk
.
where
(
build:
build
)).
not_to
be_exist
end
it
"returns live trace data"
do
expect
(
trace
.
raw
).
to
eq
(
"abc"
)
end
end
end
describe
'#archive!'
do
subject
{
trace
.
archive!
}
before
do
stub_feature_flags
(
ci_enable_live_trace:
false
)
end
shared_examples
'archive trace file'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
File
.
exist?
(
src_path
)).
to
be_falsy
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace file stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
expect
(
File
.
exist?
(
src_path
)).
to
be_truthy
end
end
shared_examples
'archive trace in database'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
build
.
old_trace
).
to
be_nil
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace in database stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
expect
(
build
.
old_trace
).
to
eq
(
trace_content
)
end
end
shared_examples
'archive trace file in ChunkedIO'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
Ci
::
BuildTraceChunk
.
where
(
build:
build
)).
not_to
be_exist
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace in ChunkedIO stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
expect
(
stream
.
read
).
to
eq
(
trace_raw
)
end
end
end
context
'when job does not have trace artifact'
do
context
'when trace file stored in default path'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
)
}
let
(
:src_path
)
{
trace
.
read
{
|
s
|
s
.
path
}
}
let
(
:src_checksum
)
{
Digest
::
SHA256
.
file
(
src_path
).
hexdigest
}
before
do
stub_feature_flags
(
ci_enable_live_trace:
false
)
build
# Initialize after set feature flag
src_path
src_checksum
end
it_behaves_like
'archive trace file'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
it_behaves_like
'source trace file stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace file stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
end
context
'when trace is stored in database'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
)
}
let
(
:trace_content
)
{
'Sample trace'
}
let
(
:src_checksum
)
{
Digest
::
SHA256
.
hexdigest
(
trace_content
)
}
before
do
before
do
stub_feature_flags
(
ci_enable_live_trace:
false
)
stub_feature_flags
(
ci_enable_live_trace:
false
)
build
# Initialize after set feature flag
trace_content
src_checksum
build
.
update_column
(
:trace
,
trace_content
)
end
end
it_behaves_like
'archive trace in database'
it_behaves_like
'trace with disabled live trace feature'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
end
it_behaves_like
'source trace in database stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
context
'when live trace feature is enabled'
do
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace in database stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
context
'when there is a validation error on Ci::Build'
do
before
do
allow_any_instance_of
(
Ci
::
Build
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
Build
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
context
"when erase old trace with 'save'"
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
nil
)
build
.
save
end
it
'old trace is not deleted'
do
build
.
reload
expect
(
build
.
trace
.
raw
).
to
eq
(
trace_content
)
end
end
it_behaves_like
'archive trace in database'
end
end
context
'when trace is stored in ChunkedIO'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
)
}
let
(
:trace_raw
)
{
build
.
trace
.
raw
}
let
(
:src_checksum
)
{
Digest
::
SHA256
.
hexdigest
(
trace_raw
)
}
before
do
before
do
stub_feature_flags
(
ci_enable_live_trace:
true
)
stub_feature_flags
(
ci_enable_live_trace:
true
)
build
# Initialize after set feature flag
trace_raw
src_checksum
end
end
it_behaves_like
'archive trace file in ChunkedIO'
it_behaves_like
'trace with enabled live trace feature'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
it_behaves_like
'source trace in ChunkedIO stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace in ChunkedIO stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
end
end
context
'when job has trace artifact'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Already archived'
)
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
end
end
context
'when job is not finished yet'
do
let!
(
:build
)
{
create
(
:ci_build
,
:running
,
:trace_live
)
}
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Job is not finished yet'
)
expect
(
build
.
trace
.
exist?
).
to
be_truthy
end
end
end
end
end
end
spec/support/shared_examples/ci_trace_shared_exmaples.rb
0 → 100644
View file @
e1ad8ca6
shared_examples_for
'common trace features'
do
describe
'#html'
do
before
do
trace
.
set
(
"12
\n
34"
)
end
it
"returns formatted html"
do
expect
(
trace
.
html
).
to
eq
(
"12<br>34"
)
end
it
"returns last line of formatted html"
do
expect
(
trace
.
html
(
last_lines:
1
)).
to
eq
(
"34"
)
end
end
describe
'#raw'
do
before
do
trace
.
set
(
"12
\n
34"
)
end
it
"returns raw output"
do
expect
(
trace
.
raw
).
to
eq
(
"12
\n
34"
)
end
it
"returns last line of raw output"
do
expect
(
trace
.
raw
(
last_lines:
1
)).
to
eq
(
"34"
)
end
end
describe
'#extract_coverage'
do
let
(
:regex
)
{
'\(\d+.\d+\%\) covered'
}
context
'matching coverage'
do
before
do
trace
.
set
(
'Coverage 1033 / 1051 LOC (98.29%) covered'
)
end
it
"returns valid coverage"
do
expect
(
trace
.
extract_coverage
(
regex
)).
to
eq
(
"98.29"
)
end
end
context
'no coverage'
do
before
do
trace
.
set
(
'No coverage'
)
end
it
'returs nil'
do
expect
(
trace
.
extract_coverage
(
regex
)).
to
be_nil
end
end
end
describe
'#extract_sections'
do
let
(
:log
)
{
'No sections'
}
let
(
:sections
)
{
trace
.
extract_sections
}
before
do
trace
.
set
(
log
)
end
context
'no sections'
do
it
'returs []'
do
expect
(
trace
.
extract_sections
).
to
eq
([])
end
end
context
'multiple sections available'
do
let
(
:log
)
{
File
.
read
(
expand_fixture_path
(
'trace/trace_with_sections'
))
}
let
(
:sections_data
)
do
[
{
name:
'prepare_script'
,
lines:
2
,
duration:
3
.
seconds
},
{
name:
'get_sources'
,
lines:
4
,
duration:
1
.
second
},
{
name:
'restore_cache'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'download_artifacts'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'build_script'
,
lines:
2
,
duration:
1
.
second
},
{
name:
'after_script'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'archive_cache'
,
lines:
0
,
duration:
0
.
seconds
},
{
name:
'upload_artifacts'
,
lines:
0
,
duration:
0
.
seconds
}
]
end
it
"returns valid sections"
do
expect
(
sections
).
not_to
be_empty
expect
(
sections
.
size
).
to
eq
(
sections_data
.
size
),
"expected
#{
sections_data
.
size
}
sections, got
#{
sections
.
size
}
"
buff
=
StringIO
.
new
(
log
)
sections
.
each_with_index
do
|
s
,
i
|
expected
=
sections_data
[
i
]
expect
(
s
[
:name
]).
to
eq
(
expected
[
:name
])
expect
(
s
[
:date_end
]
-
s
[
:date_start
]).
to
eq
(
expected
[
:duration
])
buff
.
seek
(
s
[
:byte_start
],
IO
::
SEEK_SET
)
length
=
s
[
:byte_end
]
-
s
[
:byte_start
]
lines
=
buff
.
read
(
length
).
count
(
"
\n
"
)
expect
(
lines
).
to
eq
(
expected
[
:lines
])
end
end
end
context
'logs contains "section_start"'
do
let
(
:log
)
{
"section_start:1506417476:a_section
\r\033
[0Klooks like a section_start:invalid
\n
section_end:1506417477:a_section
\r\033
[0K"
}
it
"returns only one section"
do
expect
(
sections
).
not_to
be_empty
expect
(
sections
.
size
).
to
eq
(
1
)
section
=
sections
[
0
]
expect
(
section
[
:name
]).
to
eq
(
'a_section'
)
expect
(
section
[
:byte_start
]).
not_to
eq
(
section
[
:byte_end
]),
"got an empty section"
end
end
context
'missing section_end'
do
let
(
:log
)
{
"section_start:1506417476:a_section
\r\033
[0KSome logs
\n
No section_end
\n
"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
context
'missing section_start'
do
let
(
:log
)
{
"Some logs
\n
No section_start
\n
section_end:1506417476:a_section
\r\033
[0K"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
context
'inverted section_start section_end'
do
let
(
:log
)
{
"section_end:1506417476:a_section
\r\033
[0Klooks like a section_start:invalid
\n
section_start:1506417477:a_section
\r\033
[0K"
}
it
"returns no sections"
do
expect
(
sections
).
to
be_empty
end
end
end
describe
'#set'
do
before
do
trace
.
set
(
"12"
)
end
it
"returns trace"
do
expect
(
trace
.
raw
).
to
eq
(
"12"
)
end
context
'overwrite trace'
do
before
do
trace
.
set
(
"34"
)
end
it
"returns new trace"
do
expect
(
trace
.
raw
).
to
eq
(
"34"
)
end
end
context
'runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
trace
.
set
(
token
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
context
'hides build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
trace
.
set
(
token
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
end
describe
'#append'
do
before
do
trace
.
set
(
"1234"
)
end
it
"returns correct trace"
do
expect
(
trace
.
append
(
"56"
,
4
)).
to
eq
(
6
)
expect
(
trace
.
raw
).
to
eq
(
"123456"
)
end
context
'tries to append trace at different offset'
do
it
"fails with append"
do
expect
(
trace
.
append
(
"56"
,
2
)).
to
eq
(
-
4
)
expect
(
trace
.
raw
).
to
eq
(
"1234"
)
end
end
context
'runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
trace
.
append
(
token
,
0
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
context
'build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
trace
.
append
(
token
,
0
)
end
it
"hides token"
do
expect
(
trace
.
raw
).
not_to
include
(
token
)
end
end
end
end
shared_examples_for
'trace with disabled live trace feature'
do
it_behaves_like
'common trace features'
describe
'#read'
do
shared_examples
'read successfully with IO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
IO
)
end
end
end
shared_examples
'read successfully with StringIO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
StringIO
)
end
end
end
shared_examples
'failed to read'
do
it
'yields without source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_nil
end
end
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it_behaves_like
'read successfully with IO'
end
context
'when current_path (with project_id) exists'
do
before
do
expect
(
trace
).
to
receive
(
:default_path
)
{
expand_fixture_path
(
'trace/sample_trace'
)
}
end
it_behaves_like
'read successfully with IO'
end
context
'when current_path (with project_ci_id) exists'
do
before
do
expect
(
trace
).
to
receive
(
:deprecated_path
)
{
expand_fixture_path
(
'trace/sample_trace'
)
}
end
it_behaves_like
'read successfully with IO'
end
context
'when db trace exists'
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
"data"
)
end
it_behaves_like
'read successfully with StringIO'
end
context
'when no sources exist'
do
it_behaves_like
'failed to read'
end
end
describe
'trace handling'
do
subject
{
trace
.
exist?
}
context
'trace does not exist'
do
it
{
expect
(
trace
.
exist?
).
to
be
(
false
)
}
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
{
is_expected
.
to
be_truthy
}
context
'when the trace artifact has been erased'
do
before
do
trace
.
erase!
end
it
{
is_expected
.
to
be_falsy
}
it
'removes associations'
do
expect
(
Ci
::
JobArtifact
.
exists?
(
job_id:
build
.
id
,
file_type: :trace
)).
to
be_falsy
end
end
end
context
'new trace path is used'
do
before
do
trace
.
send
(
:ensure_directory
)
File
.
open
(
trace
.
send
(
:default_path
),
"w"
)
do
|
file
|
file
.
write
(
"data"
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
end
context
'deprecated path'
do
let
(
:path
)
{
trace
.
send
(
:deprecated_path
)
}
context
'with valid ci_id'
do
before
do
build
.
project
.
update
(
ci_id:
1000
)
FileUtils
.
mkdir_p
(
File
.
dirname
(
path
))
File
.
open
(
path
,
"w"
)
do
|
file
|
file
.
write
(
"data"
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
end
context
'without valid ci_id'
do
it
"does not return deprecated path"
do
expect
(
path
).
to
be_nil
end
end
end
context
'stored in database'
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
"data"
)
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
end
it
"returns database data"
do
expect
(
trace
.
raw
).
to
eq
(
"data"
)
end
end
end
describe
'#archive!'
do
subject
{
trace
.
archive!
}
shared_examples
'archive trace file'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
File
.
exist?
(
src_path
)).
to
be_falsy
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace file stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
expect
(
File
.
exist?
(
src_path
)).
to
be_truthy
end
end
shared_examples
'archive trace in database'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
build
.
old_trace
).
to
be_nil
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace in database stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
expect
(
build
.
old_trace
).
to
eq
(
trace_content
)
end
end
context
'when job does not have trace artifact'
do
context
'when trace file stored in default path'
do
let!
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
)
}
let!
(
:src_path
)
{
trace
.
read
{
|
s
|
s
.
path
}
}
let!
(
:src_checksum
)
{
Digest
::
SHA256
.
file
(
src_path
).
hexdigest
}
it_behaves_like
'archive trace file'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
it_behaves_like
'source trace file stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace file stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
end
context
'when trace is stored in database'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
)
}
let
(
:trace_content
)
{
'Sample trace'
}
let
(
:src_checksum
)
{
Digest
::
SHA256
.
hexdigest
(
trace_content
)
}
before
do
build
.
update_column
(
:trace
,
trace_content
)
end
it_behaves_like
'archive trace in database'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
it_behaves_like
'source trace in database stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace in database stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
context
'when there is a validation error on Ci::Build'
do
before
do
allow_any_instance_of
(
Ci
::
Build
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
Build
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
context
"when erase old trace with 'save'"
do
before
do
build
.
send
(
:write_attribute
,
:trace
,
nil
)
build
.
save
end
it
'old trace is not deleted'
do
build
.
reload
expect
(
build
.
trace
.
raw
).
to
eq
(
trace_content
)
end
end
it_behaves_like
'archive trace in database'
end
end
end
context
'when job has trace artifact'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Already archived'
)
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
end
end
context
'when job is not finished yet'
do
let!
(
:build
)
{
create
(
:ci_build
,
:running
,
:trace_live
)
}
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Job is not finished yet'
)
expect
(
build
.
trace
.
exist?
).
to
be_truthy
end
end
end
end
shared_examples_for
'trace with enabled live trace feature'
do
it_behaves_like
'common trace features'
describe
'#read'
do
shared_examples
'read successfully with IO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
IO
)
end
end
end
shared_examples
'read successfully with ChunkedIO'
do
it
'yields with source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
ChunkedIO
)
end
end
end
shared_examples
'failed to read'
do
it
'yields without source'
do
trace
.
read
do
|
stream
|
expect
(
stream
).
to
be_a
(
Gitlab
::
Ci
::
Trace
::
Stream
)
expect
(
stream
.
stream
).
to
be_nil
end
end
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it_behaves_like
'read successfully with IO'
end
context
'when live trace exists'
do
before
do
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
stream
.
write
(
'abc'
)
end
end
it_behaves_like
'read successfully with ChunkedIO'
end
context
'when no sources exist'
do
it_behaves_like
'failed to read'
end
end
describe
'trace handling'
do
subject
{
trace
.
exist?
}
context
'trace does not exist'
do
it
{
expect
(
trace
.
exist?
).
to
be
(
false
)
}
end
context
'when trace artifact exists'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
{
is_expected
.
to
be_truthy
}
context
'when the trace artifact has been erased'
do
before
do
trace
.
erase!
end
it
{
is_expected
.
to
be_falsy
}
it
'removes associations'
do
expect
(
Ci
::
JobArtifact
.
exists?
(
job_id:
build
.
id
,
file_type: :trace
)).
to
be_falsy
end
end
end
context
'stored in live trace'
do
before
do
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
stream
.
write
(
'abc'
)
end
end
it
"trace exist"
do
expect
(
trace
.
exist?
).
to
be
(
true
)
end
it
"can be erased"
do
trace
.
erase!
expect
(
trace
.
exist?
).
to
be
(
false
)
expect
(
Ci
::
BuildTraceChunk
.
where
(
build:
build
)).
not_to
be_exist
end
it
"returns live trace data"
do
expect
(
trace
.
raw
).
to
eq
(
"abc"
)
end
end
end
describe
'#archive!'
do
subject
{
trace
.
archive!
}
shared_examples
'archive trace file in ChunkedIO'
do
it
do
expect
{
subject
}.
to
change
{
Ci
::
JobArtifact
.
count
}.
by
(
1
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
.
file
.
filename
).
to
eq
(
'job.log'
)
expect
(
Ci
::
BuildTraceChunk
.
where
(
build:
build
)).
not_to
be_exist
expect
(
src_checksum
)
.
to
eq
(
Digest
::
SHA256
.
file
(
build
.
job_artifacts_trace
.
file
.
path
).
hexdigest
)
expect
(
build
.
job_artifacts_trace
.
file_sha256
).
to
eq
(
src_checksum
)
end
end
shared_examples
'source trace in ChunkedIO stays intact'
do
|
error
:|
it
do
expect
{
subject
}.
to
raise_error
(
error
)
build
.
reload
expect
(
build
.
trace
.
exist?
).
to
be_truthy
expect
(
build
.
job_artifacts_trace
).
to
be_nil
Gitlab
::
Ci
::
Trace
::
ChunkedIO
.
new
(
build
)
do
|
stream
|
expect
(
stream
.
read
).
to
eq
(
trace_raw
)
end
end
end
context
'when job does not have trace artifact'
do
context
'when trace is stored in ChunkedIO'
do
let!
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
)
}
let!
(
:trace_raw
)
{
build
.
trace
.
raw
}
let!
(
:src_checksum
)
{
Digest
::
SHA256
.
hexdigest
(
trace_raw
)
}
it_behaves_like
'archive trace file in ChunkedIO'
context
'when failed to create clone file'
do
before
do
allow
(
IO
).
to
receive
(
:copy_stream
).
and_return
(
0
)
end
it_behaves_like
'source trace in ChunkedIO stays intact'
,
error:
Gitlab
::
Ci
::
Trace
::
ArchiveError
end
context
'when failed to create job artifact record'
do
before
do
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive
(
:save
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
JobArtifact
).
to
receive_message_chain
(
:errors
,
:full_messages
)
.
and_return
(
%w[Error Error]
)
end
it_behaves_like
'source trace in ChunkedIO stays intact'
,
error:
ActiveRecord
::
RecordInvalid
end
end
end
context
'when job has trace artifact'
do
before
do
create
(
:ci_job_artifact
,
:trace
,
job:
build
)
end
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Already archived'
)
expect
(
build
.
job_artifacts_trace
.
file
.
exists?
).
to
be_truthy
end
end
context
'when job is not finished yet'
do
let!
(
:build
)
{
create
(
:ci_build
,
:running
,
:trace_live
)
}
it
'does not archive'
do
expect_any_instance_of
(
described_class
).
not_to
receive
(
:archive_stream!
)
expect
{
subject
}.
to
raise_error
(
'Job is not finished yet'
)
expect
(
build
.
trace
.
exist?
).
to
be_truthy
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