diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-16 21:08:01 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-16 21:08:01 +0300 |
commit | 8e45d25f7dde6508839ffee719c0ddc2cf6b12d3 (patch) | |
tree | 9839e7fe63b36904d40995ebf519124c9a8f7681 /spec/lib | |
parent | 00c78fb814d7ce00989ac04edd6cdaa3239da284 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/lib')
-rw-r--r-- | spec/lib/gitlab/ci/ansi2json/line_spec.rb | 168 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/ansi2json/parser_spec.rb | 30 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/ansi2json/style_spec.rb | 166 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/ansi2json_spec.rb | 544 | ||||
-rw-r--r-- | spec/lib/gitlab/diff/position_collection_spec.rb | 13 | ||||
-rw-r--r-- | spec/lib/gitlab/health_checks/probes/collection_spec.rb | 62 | ||||
-rw-r--r-- | spec/lib/gitlab/health_checks/probes/liveness_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/health_checks/probes/readiness_spec.rb | 39 | ||||
-rw-r--r-- | spec/lib/gitlab_spec.rb | 78 |
9 files changed, 1032 insertions, 85 deletions
diff --git a/spec/lib/gitlab/ci/ansi2json/line_spec.rb b/spec/lib/gitlab/ci/ansi2json/line_spec.rb new file mode 100644 index 00000000000..4b5c3f9489e --- /dev/null +++ b/spec/lib/gitlab/ci/ansi2json/line_spec.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Ansi2json::Line do + let(:offset) { 0 } + let(:style) { Gitlab::Ci::Ansi2json::Style.new } + + subject { described_class.new(offset: offset, style: style) } + + describe '#<<' do + it 'appends new data to the current segment' do + expect { subject << 'test 1' }.to change { subject.current_segment.text } + expect(subject.current_segment.text).to eq('test 1') + + expect { subject << ', test 2' }.to change { subject.current_segment.text } + expect(subject.current_segment.text).to eq('test 1, test 2') + end + end + + describe '#style' do + context 'when style is passed to the initializer' do + let(:style) { double } + + it 'returns the same style' do + expect(subject.style).to eq(style) + end + end + + context 'when style is not passed to the initializer' do + it 'returns the default style' do + expect(subject.style.set?).to be_falsey + end + end + end + + describe '#update_style' do + let(:expected_style) do + Gitlab::Ci::Ansi2json::Style.new( + fg: 'term-fg-l-yellow', + bg: 'term-bg-blue', + mask: 1) + end + + it 'sets the style' do + subject.update_style(%w[1 33 44]) + + expect(subject.style).to eq(expected_style) + end + end + + describe '#add_section' do + it 'appends a new section to the list' do + subject.add_section('section_1') + subject.add_section('section_2') + + expect(subject.sections).to eq(%w[section_1 section_2]) + end + end + + describe '#set_as_section_header' do + it 'change the section_header to true' do + expect { subject.set_as_section_header } + .to change { subject.section_header } + .to be_truthy + end + end + + describe '#set_section_duration' do + it 'sets and formats the section_duration' do + subject.set_section_duration(75) + + expect(subject.section_duration).to eq('01:15') + end + end + + describe '#flush_current_segment!' do + context 'when current segment is not empty' do + before do + subject << 'some data' + end + + it 'adds the segment to the list' do + expect { subject.flush_current_segment! }.to change { subject.segments.count }.by(1) + + expect(subject.segments.map { |s| s[:text] }).to eq(['some data']) + end + + it 'updates the current segment pointer propagating the style' do + previous_segment = subject.current_segment + + subject.flush_current_segment! + + expect(subject.current_segment).not_to eq(previous_segment) + expect(subject.current_segment.style).to eq(previous_segment.style) + end + end + + context 'when current segment is empty' do + it 'does not add any segments to the list' do + expect { subject.flush_current_segment! }.not_to change { subject.segments.count } + end + + it 'does not change the current segment' do + expect { subject.flush_current_segment! }.not_to change { subject.current_segment } + end + end + end + + describe '#to_h' do + before do + subject << 'some data' + subject.update_style(['1']) + end + + context 'when sections are present' do + before do + subject.add_section('section_1') + subject.add_section('section_2') + end + + context 'when section header is set' do + before do + subject.set_as_section_header + end + + it 'serializes the attributes set' do + result = { + offset: 0, + content: [{ text: 'some data', style: 'term-bold' }], + section: 'section_2', + section_header: true + } + + expect(subject.to_h).to eq(result) + end + end + + context 'when section duration is set' do + before do + subject.set_section_duration(75) + end + + it 'serializes the attributes set' do + result = { + offset: 0, + content: [{ text: 'some data', style: 'term-bold' }], + section: 'section_2', + section_duration: '01:15' + } + + expect(subject.to_h).to eq(result) + end + end + end + + context 'when there are no sections' do + it 'serializes the attributes set' do + result = { + offset: 0, + content: [{ text: 'some data', style: 'term-bold' }] + } + + expect(subject.to_h).to eq(result) + end + end + end +end diff --git a/spec/lib/gitlab/ci/ansi2json/parser_spec.rb b/spec/lib/gitlab/ci/ansi2json/parser_spec.rb new file mode 100644 index 00000000000..e161e74c1ff --- /dev/null +++ b/spec/lib/gitlab/ci/ansi2json/parser_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# The rest of the specs for this class are covered in style_spec.rb +describe Gitlab::Ci::Ansi2json::Parser do + subject { described_class } + + describe 'bold?' do + it 'returns true if style mask matches bold format' do + expect(subject.bold?(0x01)).to be_truthy + end + + it 'returns false if style mask does not match bold format' do + expect(subject.bold?(0x02)).to be_falsey + end + end + + describe 'matching_formats' do + it 'returns matching formats given a style mask' do + expect(subject.matching_formats(0x01)).to eq(%w[term-bold]) + expect(subject.matching_formats(0x03)).to eq(%w[term-bold term-italic]) + expect(subject.matching_formats(0x07)).to eq(%w[term-bold term-italic term-underline]) + end + + it 'returns an empty array if no formats match the style mask' do + expect(subject.matching_formats(0)).to eq([]) + end + end +end diff --git a/spec/lib/gitlab/ci/ansi2json/style_spec.rb b/spec/lib/gitlab/ci/ansi2json/style_spec.rb new file mode 100644 index 00000000000..88a0ca35859 --- /dev/null +++ b/spec/lib/gitlab/ci/ansi2json/style_spec.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Ansi2json::Style do + describe '#set?' do + subject { described_class.new(params).set? } + + context 'when fg color is set' do + let(:params) { { fg: 'term-fg-black' } } + + it { is_expected.to be_truthy } + end + + context 'when bg color is set' do + let(:params) { { bg: 'term-bg-black' } } + + it { is_expected.to be_truthy } + end + + context 'when mask is set' do + let(:params) { { mask: 0x01 } } + + it { is_expected.to be_truthy } + end + + context 'nothing is set' do + let(:params) { {} } + + it { is_expected.to be_falsey } + end + end + + describe '#reset!' do + let(:style) { described_class.new(fg: 'term-fg-black', bg: 'term-bg-yellow', mask: 0x01) } + + it 'set the style params to default' do + style.reset! + + expect(style.fg).to be_nil + expect(style.bg).to be_nil + expect(style.mask).to be_zero + end + end + + describe 'update formats to mimic terminals' do + subject { described_class.new(params) } + + context 'when fg color present' do + let(:params) { { fg: 'term-fg-black', mask: mask } } + + context 'when mask is set to bold' do + let(:mask) { 0x01 } + + it 'changes the fg color to a lighter version' do + expect(subject.fg).to eq('term-fg-l-black') + end + end + + context 'when mask set to another format' do + let(:mask) { 0x02 } + + it 'does not change the fg color' do + expect(subject.fg).to eq('term-fg-black') + end + end + + context 'when mask is not set' do + let(:mask) { 0 } + + it 'does not change the fg color' do + expect(subject.fg).to eq('term-fg-black') + end + end + end + end + + describe '#update' do + where(:initial_state, :ansi_commands, :result, :description) do + [ + # add format + [[], %w[0], '', 'does not set any style'], + [[], %w[1], 'term-bold', 'enables format bold'], + [[], %w[3], 'term-italic', 'enables format italic'], + [[], %w[4], 'term-underline', 'enables format underline'], + [[], %w[8], 'term-conceal', 'enables format conceal'], + [[], %w[9], 'term-cross', 'enables format cross'], + # remove format + [%w[1], %w[21], '', 'disables format bold'], + [%w[1 3], %w[21], 'term-italic', 'disables format bold and leaves italic'], + [%w[1], %w[22], '', 'disables format bold using command 22'], + [%w[1 3], %w[22], 'term-italic', 'disables format bold and leaves italic using command 22'], + [%w[3], %w[23], '', 'disables format italic'], + [%w[1 3], %w[23], 'term-bold', 'disables format italic and leaves bold'], + [%w[4], %w[24], '', 'disables format underline'], + [%w[1 4], %w[24], 'term-bold', 'disables format underline and leaves bold'], + [%w[8], %w[28], '', 'disables format conceal'], + [%w[1 8], %w[28], 'term-bold', 'disables format conceal and leaves bold'], + [%w[9], %w[29], '', 'disables format cross'], + [%w[1 9], %w[29], 'term-bold', 'disables format cross and leaves bold'], + # set fg color + [[], %w[30], 'term-fg-black', 'sets fg color black'], + [[], %w[31], 'term-fg-red', 'sets fg color red'], + [[], %w[32], 'term-fg-green', 'sets fg color green'], + [[], %w[33], 'term-fg-yellow', 'sets fg color yellow'], + [[], %w[34], 'term-fg-blue', 'sets fg color blue'], + [[], %w[35], 'term-fg-magenta', 'sets fg color magenta'], + [[], %w[36], 'term-fg-cyan', 'sets fg color cyan'], + [[], %w[37], 'term-fg-white', 'sets fg color white'], + # sets xterm fg color + [[], %w[38 5 1], 'xterm-fg-1', 'sets xterm fg color 1'], + [[], %w[38 5 2], 'xterm-fg-2', 'sets xterm fg color 2'], + [[], %w[38 1], 'term-bold', 'ignores 38 command if not followed by 5 and sets format bold'], + # set bg color + [[], %w[40], 'term-bg-black', 'sets bg color black'], + [[], %w[41], 'term-bg-red', 'sets bg color red'], + [[], %w[42], 'term-bg-green', 'sets bg color green'], + [[], %w[43], 'term-bg-yellow', 'sets bg color yellow'], + [[], %w[44], 'term-bg-blue', 'sets bg color blue'], + [[], %w[45], 'term-bg-magenta', 'sets bg color magenta'], + [[], %w[46], 'term-bg-cyan', 'sets bg color cyan'], + [[], %w[47], 'term-bg-white', 'sets bg color white'], + # set xterm bg color + [[], %w[48 5 1], 'xterm-bg-1', 'sets xterm bg color 1'], + [[], %w[48 5 2], 'xterm-bg-2', 'sets xterm bg color 2'], + [[], %w[48 1], 'term-bold', 'ignores 48 command if not followed by 5 and sets format bold'], + # set light fg color + [[], %w[90], 'term-fg-l-black', 'sets fg color light black'], + [[], %w[91], 'term-fg-l-red', 'sets fg color light red'], + [[], %w[92], 'term-fg-l-green', 'sets fg color light green'], + [[], %w[93], 'term-fg-l-yellow', 'sets fg color light yellow'], + [[], %w[94], 'term-fg-l-blue', 'sets fg color light blue'], + [[], %w[95], 'term-fg-l-magenta', 'sets fg color light magenta'], + [[], %w[96], 'term-fg-l-cyan', 'sets fg color light cyan'], + [[], %w[97], 'term-fg-l-white', 'sets fg color light white'], + # set light bg color + [[], %w[100], 'term-bg-l-black', 'sets bg color light black'], + [[], %w[101], 'term-bg-l-red', 'sets bg color light red'], + [[], %w[102], 'term-bg-l-green', 'sets bg color light green'], + [[], %w[103], 'term-bg-l-yellow', 'sets bg color light yellow'], + [[], %w[104], 'term-bg-l-blue', 'sets bg color light blue'], + [[], %w[105], 'term-bg-l-magenta', 'sets bg color light magenta'], + [[], %w[106], 'term-bg-l-cyan', 'sets bg color light cyan'], + [[], %w[107], 'term-bg-l-white', 'sets bg color light white'], + # reset + [%w[1], %w[0], '', 'resets style from format bold'], + [%w[1 3], %w[0], '', 'resets style from format bold and italic'], + [%w[1 3 term-fg-l-red term-bg-yellow], %w[0], '', 'resets all formats and colors'], + # misc + [[], %w[1 30 42 3], 'term-fg-l-black term-bg-green term-bold term-italic', 'adds fg color, bg color and formats from no style'], + [%w[3 31], %w[23 1 43], 'term-fg-l-red term-bg-yellow term-bold', 'replaces format italic with bold and adds a yellow background'] + ] + end + + with_them do + it 'change the style' do + style = described_class.new + style.update(initial_state) + + style.update(ansi_commands) + + expect(style.to_s).to eq(result) + end + end + end +end diff --git a/spec/lib/gitlab/ci/ansi2json_spec.rb b/spec/lib/gitlab/ci/ansi2json_spec.rb new file mode 100644 index 00000000000..3c6bc46436b --- /dev/null +++ b/spec/lib/gitlab/ci/ansi2json_spec.rb @@ -0,0 +1,544 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Ansi2json do + subject { described_class } + + describe 'lines' do + it 'prints non-ansi as-is' do + expect(convert_json('Hello')).to eq([ + { offset: 0, content: [{ text: 'Hello' }] } + ]) + end + + it 'adds new line in a separate element' do + expect(convert_json("Hello\nworld")).to eq([ + { offset: 0, content: [{ text: 'Hello' }] }, + { offset: 6, content: [{ text: 'world' }] } + ]) + end + + it 'recognizes color changing ANSI sequences' do + expect(convert_json("\e[31mHello\e[0m")).to eq([ + { offset: 0, content: [{ text: 'Hello', style: 'term-fg-red' }] } + ]) + end + + it 'recognizes color changing ANSI sequences across multiple lines' do + expect(convert_json("\e[31mHello\nWorld\e[0m")).to eq([ + { offset: 0, content: [{ text: 'Hello', style: 'term-fg-red' }] }, + { offset: 11, content: [{ text: 'World', style: 'term-fg-red' }] } + ]) + end + + it 'recognizes background and foreground colors' do + expect(convert_json("\e[31;44mHello")).to eq([ + { offset: 0, content: [{ text: 'Hello', style: 'term-fg-red term-bg-blue' }] } + ]) + end + + it 'recognizes style changes within the same line' do + expect(convert_json("\e[31;44mHello\e[0m world")).to eq([ + { offset: 0, content: [ + { text: 'Hello', style: 'term-fg-red term-bg-blue' }, + { text: ' world' } + ] } + ]) + end + + context 'with section markers' do + let(:section_name) { 'prepare-script' } + let(:section_duration) { 63.seconds } + let(:section_start_time) { Time.new(2019, 9, 17).utc } + let(:section_end_time) { section_start_time + section_duration } + let(:section_start) { "section_start:#{section_start_time.to_i}:#{section_name}\r\033[0K"} + let(:section_end) { "section_end:#{section_end_time.to_i}:#{section_name}\r\033[0K"} + + it 'marks the first line of the section as header' do + expect(convert_json("Hello#{section_start}world!")).to eq([ + { + offset: 0, + content: [{ text: 'Hello' }] + }, + { + offset: 5, + content: [{ text: 'world!' }], + section: 'prepare-script', + section_header: true + } + ]) + end + + it 'does not marks the other lines of the section as header' do + expect(convert_json("outside section#{section_start}Hello\nworld!")).to eq([ + { + offset: 0, + content: [{ text: 'outside section' }] + }, + { + offset: 15, + content: [{ text: 'Hello' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 65, + content: [{ text: 'world!' }], + section: 'prepare-script' + } + ]) + end + + it 'marks the last line of the section as footer' do + expect(convert_json("#{section_start}Good\nmorning\nworld!#{section_end}")).to eq([ + { + offset: 0, + content: [{ text: 'Good' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 49, + content: [{ text: 'morning' }], + section: 'prepare-script' + }, + { + offset: 57, + content: [{ text: 'world!' }], + section: 'prepare-script' + }, + { + offset: 63, + content: [], + section_duration: '01:03', + section: 'prepare-script' + }, + { + offset: 63, + content: [] + } + ]) + end + + it 'marks the first line as header and footer if is the only line in the section' do + expect(convert_json("#{section_start}Hello world!#{section_end}")).to eq([ + { + offset: 0, + content: [{ text: 'Hello world!' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 56, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 56, + content: [] + } + ]) + end + + it 'does not add sections attribute to lines after the section is closed' do + expect(convert_json("#{section_start}Hello#{section_end}world")).to eq([ + { + offset: 0, + content: [{ text: 'Hello' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 49, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 49, + content: [{ text: 'world' }] + } + ]) + end + + it 'ignores section_end marker if no section_start exists' do + expect(convert_json("Hello #{section_end}world")).to eq([ + { + offset: 0, + content: [{ text: 'Hello world' }] + } + ]) + end + + context 'when section name contains .-_ and capital letters' do + let(:section_name) { 'a.Legit-SeCtIoN_namE' } + + it 'sanitizes the section name' do + expect(convert_json("Hello#{section_start}world!")).to eq([ + { + offset: 0, + content: [{ text: 'Hello' }] + }, + { + offset: 5, + content: [{ text: 'world!' }], + section: 'a-legit-section-name', + section_header: true + } + ]) + end + end + + context 'when section name includes $' do + let(:section_name) { 'my_$ection' } + + it 'ignores the section' do + expect(convert_json("#{section_start}hello")).to eq([ + { + offset: 0, + content: [{ text: "#{section_start.gsub("\033[0K", '')}hello" }] + } + ]) + end + end + + context 'when section name includes <' do + let(:section_name) { '<a_tag>' } + + it 'ignores the section' do + expect(convert_json("#{section_start}hello")).to eq([ + { + offset: 0, + content: [{ text: "#{section_start.gsub("\033[0K", '').gsub('<', '<')}hello" }] + } + ]) + end + end + + it 'prevents XSS injection' do + trace = "#{section_start}section_end:1:2<script>alert('XSS Hack!');</script>#{section_end}" + expect(convert_json(trace)).to eq([ + { + offset: 0, + content: [{ text: "section_end:1:2<script>alert('XSS Hack!');</script>" }], + section: 'prepare-script', + section_header: true + }, + { + offset: 95, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 95, + content: [] + } + ]) + end + + context 'with nested section' do + let(:nested_section_name) { 'prepare-script-nested' } + let(:nested_section_duration) { 2.seconds } + let(:nested_section_start_time) { Time.new(2019, 9, 17).utc } + let(:nested_section_end_time) { nested_section_start_time + nested_section_duration } + let(:nested_section_start) { "section_start:#{nested_section_start_time.to_i}:#{nested_section_name}\r\033[0K"} + let(:nested_section_end) { "section_end:#{nested_section_end_time.to_i}:#{nested_section_name}\r\033[0K"} + + it 'adds multiple sections to the lines inside the nested section' do + trace = "Hello#{section_start}foo#{nested_section_start}bar#{nested_section_end}baz#{section_end}world" + + expect(convert_json(trace)).to eq([ + { + offset: 0, + content: [{ text: 'Hello' }] + }, + { + offset: 5, + content: [{ text: 'foo' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 52, + content: [{ text: 'bar' }], + section: 'prepare-script-nested', + section_header: true + }, + { + offset: 106, + content: [], + section: 'prepare-script-nested', + section_duration: '00:02' + }, + { + offset: 106, + content: [{ text: 'baz' }], + section: 'prepare-script' + }, + { + offset: 158, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 158, + content: [{ text: 'world' }] + } + ]) + end + + it 'adds multiple sections to the lines inside the nested section and closes all sections together' do + trace = "Hello#{section_start}\e[91mfoo\e[0m#{nested_section_start}bar#{nested_section_end}#{section_end}" + + expect(convert_json(trace)).to eq([ + { + offset: 0, + content: [{ text: 'Hello' }] + }, + { + offset: 5, + content: [{ text: 'foo', style: 'term-fg-l-red' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 61, + content: [{ text: 'bar' }], + section: 'prepare-script-nested', + section_header: true + }, + { + offset: 115, + content: [], + section: 'prepare-script-nested', + section_duration: '00:02' + }, + { + offset: 115, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 164, + content: [] + } + ]) + end + end + end + + describe 'incremental updates' do + let(:pass1_stream) { StringIO.new(pre_text) } + let(:pass2_stream) { StringIO.new(pre_text + text) } + let(:pass1) { subject.convert(pass1_stream) } + let(:pass2) { subject.convert(pass2_stream, pass1.state) } + + context 'with split word' do + let(:pre_text) { "\e[1mHello " } + let(:text) { "World" } + + let(:lines) do + [ + { offset: 0, content: [{ text: 'Hello World', style: 'term-bold' }] } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_falsey + end + end + + context 'with split word on second line' do + let(:pre_text) { "Good\nmorning " } + let(:text) { "World" } + + let(:lines) do + [ + { offset: 5, content: [{ text: 'morning World' }] } + ] + end + + it 'returns all lines since last partially processed line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_truthy + end + end + + context 'with split sequence across multiple lines' do + let(:pre_text) { "\e[1mgood\nmorning\n" } + let(:text) { "\e[3mworld" } + + let(:lines) do + [ + { offset: 17, content: [{ text: 'world', style: 'term-bold term-italic' }] } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_truthy + end + end + + context 'with split partial sequence' do + let(:pre_text) { "hello\e" } + let(:text) { "[1m world" } + + let(:lines) do + [ + { offset: 0, content: [ + { text: 'hello' }, + { text: ' world', style: 'term-bold' } + ] } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_falsey + end + end + + context 'with split new line' do + let(:pre_text) { "hello\r" } + let(:text) { "\nworld" } + + let(:lines) do + [ + { offset: 0, content: [{ text: 'hello' }] }, + { offset: 7, content: [{ text: 'world' }] } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_falsey + end + end + + context 'with split section' do + let(:section_name) { 'prepare-script' } + let(:section_duration) { 63.seconds } + let(:section_start_time) { Time.new(2019, 9, 17).utc } + let(:section_end_time) { section_start_time + section_duration } + let(:section_start) { "section_start:#{section_start_time.to_i}:#{section_name}\r\033[0K"} + let(:section_end) { "section_end:#{section_end_time.to_i}:#{section_name}\r\033[0K"} + + context 'with split section body' do + let(:pre_text) { "#{section_start}this is a header\nand " } + let(:text) { "this\n is a body" } + + let(:lines) do + [ + { + offset: 61, + content: [{ text: 'and this' }], + section: 'prepare-script' + }, + { + offset: 70, + content: [{ text: ' is a body' }], + section: 'prepare-script' + } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_truthy + end + end + + context 'with split section where header is also split' do + let(:pre_text) { "#{section_start}this is " } + let(:text) { "a header\nand body" } + + let(:lines) do + [ + { + offset: 0, + content: [{ text: 'this is a header' }], + section: 'prepare-script', + section_header: true + }, + { + offset: 61, + content: [{ text: 'and body' }], + section: 'prepare-script' + } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_falsey + end + end + + context 'with split section end' do + let(:pre_text) { "#{section_start}this is a header\nthe" } + let(:text) { " body\nthe end#{section_end}" } + + let(:lines) do + [ + { + offset: 61, + content: [{ text: 'the body' }], + section: 'prepare-script' + }, + { + offset: 70, + content: [{ text: 'the end' }], + section: 'prepare-script' + }, + { + offset: 77, + content: [], + section: 'prepare-script', + section_duration: '01:03' + }, + { + offset: 77, + content: [] + } + ] + end + + it 'returns the full line' do + expect(pass2.lines).to eq(lines) + expect(pass2.append).to be_truthy + end + end + end + end + + describe 'trucates' do + let(:text) { "Hello World" } + let(:stream) { StringIO.new(text) } + let(:subject) { described_class.convert(stream) } + + before do + stream.seek(3, IO::SEEK_SET) + end + + it "returns truncated output" do + expect(subject.truncated).to be_truthy + end + + it "does not append output" do + expect(subject.append).to be_falsey + end + end + + def convert_json(data) + stream = StringIO.new(data) + subject.convert(stream).lines + end + end +end diff --git a/spec/lib/gitlab/diff/position_collection_spec.rb b/spec/lib/gitlab/diff/position_collection_spec.rb index de0e631ab03..f2a8312587c 100644 --- a/spec/lib/gitlab/diff/position_collection_spec.rb +++ b/spec/lib/gitlab/diff/position_collection_spec.rb @@ -35,14 +35,15 @@ describe Gitlab::Diff::PositionCollection do let(:text_position) { build_text_position } let(:folded_text_position) { build_text_position(old_line: 1, new_line: 1) } let(:image_position) { build_image_position } + let(:invalid_position) { 'a position' } let(:head_sha) { merge_request.diff_head_sha } let(:collection) do - described_class.new([text_position, folded_text_position, image_position], head_sha) + described_class.new([text_position, folded_text_position, image_position, invalid_position], head_sha) end describe '#to_a' do - it 'returns all positions' do + it 'returns all positions that are Gitlab::Diff::Position' do expect(collection.to_a).to eq([text_position, folded_text_position, image_position]) end end @@ -59,6 +60,14 @@ describe Gitlab::Diff::PositionCollection do expect(collection.unfoldable).to be_empty end end + + context 'when given head_sha is nil' do + let(:head_sha) { nil } + + it 'returns unfoldable diff positions unfiltered by head_sha' do + expect(collection.unfoldable).to eq([folded_text_position]) + end + end end describe '#concat' do diff --git a/spec/lib/gitlab/health_checks/probes/collection_spec.rb b/spec/lib/gitlab/health_checks/probes/collection_spec.rb new file mode 100644 index 00000000000..33efc640257 --- /dev/null +++ b/spec/lib/gitlab/health_checks/probes/collection_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::HealthChecks::Probes::Collection do + let(:readiness) { described_class.new(*checks) } + + describe '#call' do + subject { readiness.execute } + + context 'with all checks' do + let(:checks) do + [ + Gitlab::HealthChecks::DbCheck, + Gitlab::HealthChecks::Redis::RedisCheck, + Gitlab::HealthChecks::Redis::CacheCheck, + Gitlab::HealthChecks::Redis::QueuesCheck, + Gitlab::HealthChecks::Redis::SharedStateCheck, + Gitlab::HealthChecks::GitalyCheck + ] + end + + it 'responds with readiness checks data' do + expect(subject.http_status).to eq(200) + + expect(subject.json[:status]).to eq('ok') + expect(subject.json['db_check']).to contain_exactly(status: 'ok') + expect(subject.json['cache_check']).to contain_exactly(status: 'ok') + expect(subject.json['queues_check']).to contain_exactly(status: 'ok') + expect(subject.json['shared_state_check']).to contain_exactly(status: 'ok') + expect(subject.json['gitaly_check']).to contain_exactly( + status: 'ok', labels: { shard: 'default' }) + end + + context 'when Redis fails' do + before do + allow(Gitlab::HealthChecks::Redis::RedisCheck).to receive(:readiness).and_return( + Gitlab::HealthChecks::Result.new('redis_check', false, "check error")) + end + + it 'responds with failure' do + expect(subject.http_status).to eq(503) + + expect(subject.json[:status]).to eq('failed') + expect(subject.json['cache_check']).to contain_exactly(status: 'ok') + expect(subject.json['redis_check']).to contain_exactly( + status: 'failed', message: 'check error') + end + end + end + + context 'without checks' do + let(:checks) { [] } + + it 'responds with success' do + expect(subject.http_status).to eq(200) + + expect(subject.json).to eq(status: 'ok') + end + end + end +end diff --git a/spec/lib/gitlab/health_checks/probes/liveness_spec.rb b/spec/lib/gitlab/health_checks/probes/liveness_spec.rb deleted file mode 100644 index 91066cb8ba0..00000000000 --- a/spec/lib/gitlab/health_checks/probes/liveness_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::HealthChecks::Probes::Liveness do - let(:liveness) { described_class.new } - - describe '#call' do - subject { liveness.execute } - - it 'responds with liveness checks data' do - expect(subject.http_status).to eq(200) - - expect(subject.json[:status]).to eq('ok') - end - end -end diff --git a/spec/lib/gitlab/health_checks/probes/readiness_spec.rb b/spec/lib/gitlab/health_checks/probes/readiness_spec.rb deleted file mode 100644 index d88ffd984c2..00000000000 --- a/spec/lib/gitlab/health_checks/probes/readiness_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::HealthChecks::Probes::Readiness do - let(:readiness) { described_class.new } - - describe '#call' do - subject { readiness.execute } - - it 'responds with readiness checks data' do - expect(subject.http_status).to eq(200) - - expect(subject.json[:status]).to eq('ok') - expect(subject.json['db_check']).to contain_exactly(status: 'ok') - expect(subject.json['cache_check']).to contain_exactly(status: 'ok') - expect(subject.json['queues_check']).to contain_exactly(status: 'ok') - expect(subject.json['shared_state_check']).to contain_exactly(status: 'ok') - expect(subject.json['gitaly_check']).to contain_exactly( - status: 'ok', labels: { shard: 'default' }) - end - - context 'when Redis fails' do - before do - allow(Gitlab::HealthChecks::Redis::RedisCheck).to receive(:readiness).and_return( - Gitlab::HealthChecks::Result.new('redis_check', false, "check error")) - end - - it 'responds with failure' do - expect(subject.http_status).to eq(503) - - expect(subject.json[:status]).to eq('failed') - expect(subject.json['cache_check']).to contain_exactly(status: 'ok') - expect(subject.json['redis_check']).to contain_exactly( - status: 'failed', message: 'check error') - end - end - end -end diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index c1d171815ba..6bf837f1d3f 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -146,7 +146,7 @@ describe Gitlab do describe '.ee?' do before do - stub_env('IS_GITLAB_EE', nil) # Make sure the ENV is clean + stub_env('FOSS_ONLY', nil) # Make sure the ENV is clean described_class.instance_variable_set(:@is_ee, nil) end @@ -154,42 +154,66 @@ describe Gitlab do described_class.instance_variable_set(:@is_ee, nil) end - it 'returns true when using Enterprise Edition' do - root = Pathname.new('dummy') - license_path = double(:path, exist?: true) + context 'for EE' do + before do + root = Pathname.new('dummy') + license_path = double(:path, exist?: true) - allow(described_class) - .to receive(:root) - .and_return(root) + allow(described_class) + .to receive(:root) + .and_return(root) - allow(root) - .to receive(:join) - .with('ee/app/models/license.rb') - .and_return(license_path) + allow(root) + .to receive(:join) + .with('ee/app/models/license.rb') + .and_return(license_path) + end - expect(described_class.ee?).to eq(true) - end + context 'when using FOSS_ONLY=1' do + before do + stub_env('FOSS_ONLY', '1') + end - it 'returns false when using Community Edition' do - root = double(:path) - license_path = double(:path, exists?: false) + it 'returns not to be EE' do + expect(described_class).not_to be_ee + end + end - allow(described_class) - .to receive(:root) - .and_return(Pathname.new('dummy')) + context 'when using FOSS_ONLY=0' do + before do + stub_env('FOSS_ONLY', '0') + end - allow(root) - .to receive(:join) - .with('ee/app/models/license.rb') - .and_return(license_path) + it 'returns to be EE' do + expect(described_class).to be_ee + end + end - expect(described_class.ee?).to eq(false) + context 'when using default FOSS_ONLY' do + it 'returns to be EE' do + expect(described_class).to be_ee + end + end end - it 'returns true when the IS_GITLAB_EE variable is not empty' do - stub_env('IS_GITLAB_EE', '1') + context 'for CE' do + before do + root = double(:path) + license_path = double(:path, exists?: false) - expect(described_class.ee?).to eq(true) + allow(described_class) + .to receive(:root) + .and_return(Pathname.new('dummy')) + + allow(root) + .to receive(:join) + .with('ee/app/models/license.rb') + .and_return(license_path) + end + + it 'returns not to be EE' do + expect(described_class).not_to be_ee + end end end |