diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 21:08:32 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 21:08:32 +0300 |
commit | 995bcca3fc5544e5d2d8ee274dc9275d5b4ce375 (patch) | |
tree | 370881ef6e9de8f93ce5546b725b2f91b4072a5f /spec | |
parent | a5d7e614fe1d038a7f9e2af76106773b98e2b5e8 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js | 94 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/file/base_spec.rb | 40 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/file/component_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/processor_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb | 144 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml/loader_spec.rb | 165 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml_spec.rb | 172 | ||||
-rw-r--r-- | spec/models/plan_limits_spec.rb | 28 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 7 | ||||
-rw-r--r-- | spec/rubocop/cop_todo_spec.rb | 15 | ||||
-rw-r--r-- | spec/rubocop/formatter/todo_formatter_spec.rb | 37 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service_spec.rb | 4 |
12 files changed, 195 insertions, 515 deletions
diff --git a/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js index cda3876f9b2..ad20d7682ed 100644 --- a/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js +++ b/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js @@ -1,5 +1,6 @@ +import { GlSprintf } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; -import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import RunnerSummaryCell from '~/ci/runner/components/cells/runner_summary_cell.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; @@ -31,8 +32,8 @@ describe('RunnerTypeCell', () => { wrapper.findAllComponents(RunnerSummaryField).filter((w) => w.props('icon') === icon) .wrappers[0]; - const createComponent = (runner, options) => { - wrapper = mountExtended(RunnerSummaryCell, { + const createComponent = ({ runner, mountFn = shallowMountExtended, ...options } = {}) => { + wrapper = mountFn(RunnerSummaryCell, { propsData: { runner: { ...mockRunner, @@ -40,7 +41,7 @@ describe('RunnerTypeCell', () => { }, }, stubs: { - RunnerSummaryField, + GlSprintf, }, ...options, }); @@ -51,6 +52,8 @@ describe('RunnerTypeCell', () => { }); it('Displays the runner name as id and short token', () => { + createComponent({ mountFn: mountExtended }); + expect(wrapper.text()).toContain( `#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`, ); @@ -58,13 +61,16 @@ describe('RunnerTypeCell', () => { it('Displays no runner manager count', () => { createComponent({ - managers: { count: 0 }, + runner: { managers: { nodes: { count: 0 } } }, + mountFn: mountExtended, }); expect(findRunnerManagersBadge().html()).toBe(''); }); it('Displays runner manager count', () => { + createComponent({ mountFn: mountExtended }); + expect(findRunnerManagersBadge().text()).toBe('2'); }); @@ -74,8 +80,8 @@ describe('RunnerTypeCell', () => { it('Displays the locked icon for locked runners', () => { createComponent({ - runnerType: PROJECT_TYPE, - locked: true, + runner: { runnerType: PROJECT_TYPE, locked: true }, + mountFn: mountExtended, }); expect(findLockIcon().exists()).toBe(true); @@ -83,8 +89,8 @@ describe('RunnerTypeCell', () => { it('Displays the runner type', () => { createComponent({ - runnerType: INSTANCE_TYPE, - locked: true, + runner: { runnerType: INSTANCE_TYPE, locked: true }, + mountFn: mountExtended, }); expect(wrapper.text()).toContain(I18N_INSTANCE_TYPE); @@ -101,7 +107,7 @@ describe('RunnerTypeCell', () => { it('Displays "No description" for missing runner description', () => { createComponent({ - description: null, + runner: { description: null }, }); expect(wrapper.findByText(I18N_NO_DESCRIPTION).classes()).toContain('gl-text-secondary'); @@ -109,7 +115,7 @@ describe('RunnerTypeCell', () => { it('Displays last contact', () => { createComponent({ - contactedAt: '2022-01-02', + runner: { contactedAt: '2022-01-02' }, }); expect(findRunnerSummaryField('clock').findComponent(TimeAgo).props('time')).toBe('2022-01-02'); @@ -124,20 +130,46 @@ describe('RunnerTypeCell', () => { expect(findRunnerSummaryField('clock').text()).toContain(__('Never')); }); - it('Displays ip address', () => { - createComponent({ - ipAddress: '127.0.0.1', + describe('IP address', () => { + it('with no managers', () => { + createComponent({ + runner: { + managers: { count: 0, nodes: [] }, + }, + }); + + expect(findRunnerSummaryField('disk')).toBeUndefined(); }); - expect(findRunnerSummaryField('disk').text()).toContain('127.0.0.1'); - }); + it('with no ip', () => { + createComponent({ + runner: { + managers: { count: 1, nodes: [{ ipAddress: null }] }, + }, + }); - it('Displays no ip address', () => { - createComponent({ - ipAddress: null, + expect(findRunnerSummaryField('disk')).toBeUndefined(); }); - expect(findRunnerSummaryField('disk')).toBeUndefined(); + it.each` + count | ipAddress | expected + ${1} | ${'127.0.0.1'} | ${'127.0.0.1'} + ${2} | ${'127.0.0.2'} | ${'127.0.0.2 (+1)'} + ${11} | ${'127.0.0.3'} | ${'127.0.0.3 (+10)'} + ${1001} | ${'127.0.0.4'} | ${'127.0.0.4 (+1,000)'} + `( + 'with $count managers, ip $ipAddress displays $expected', + ({ count, ipAddress, expected }) => { + createComponent({ + runner: { + // `first: 1` is requested, `count` varies when there are more managers + managers: { count, nodes: [{ ipAddress }] }, + }, + }); + + expect(findRunnerSummaryField('disk').text()).toMatchInterpolatedText(expected); + }, + ); }); it('Displays job count', () => { @@ -146,7 +178,7 @@ describe('RunnerTypeCell', () => { it('Formats large job counts', () => { createComponent({ - jobCount: 1000, + runner: { jobCount: 1000 }, }); expect(findRunnerSummaryField('pipeline').text()).toContain('1,000'); @@ -154,7 +186,7 @@ describe('RunnerTypeCell', () => { it('Formats large job counts with a plus symbol', () => { createComponent({ - jobCount: 1001, + runner: { jobCount: 1001 }, }); expect(findRunnerSummaryField('pipeline').text()).toContain('1,000+'); @@ -165,7 +197,7 @@ describe('RunnerTypeCell', () => { it('Displays created at ...', () => { createComponent({ - createdBy: null, + runner: { createdBy: null }, }); expect(findRunnerSummaryField('calendar').text()).toMatchInterpolatedText( @@ -177,12 +209,15 @@ describe('RunnerTypeCell', () => { }); it('Displays created at ... by ...', () => { + createComponent({ mountFn: mountExtended }); + expect(findRunnerSummaryField('calendar').text()).toMatchInterpolatedText( sprintf(I18N_CREATED_AT_BY_LABEL, { timeAgo: findCreatedTime().text(), avatar: mockRunner.createdBy.username, }), ); + expect(findCreatedTime().props('time')).toBe(mockRunner.createdAt); }); @@ -200,7 +235,7 @@ describe('RunnerTypeCell', () => { it('Displays tag list', () => { createComponent({ - tagList: ['shell', 'linux'], + runner: { tagList: ['shell', 'linux'] }, }); expect(findRunnerTags().props('tagList')).toEqual(['shell', 'linux']); @@ -209,14 +244,11 @@ describe('RunnerTypeCell', () => { it('Displays a custom runner-name slot', () => { const slotContent = 'My custom runner name'; - createComponent( - {}, - { - slots: { - 'runner-name': slotContent, - }, + createComponent({ + slots: { + 'runner-name': slotContent, }, - ); + }); expect(wrapper.text()).toContain(slotContent); }); diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb index 1c5918f77ca..d6dd75f4b10 100644 --- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb @@ -106,7 +106,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe it 'is not a valid file' do expect(valid?).to be_falsy expect(file.error_message) - .to eq('`some/file/xxxxxxxxxxxxxxxx.yml`: content does not have a valid YAML syntax') + .to eq('`some/file/xxxxxxxxxxxxxxxx.yml`: Invalid configuration format') end end @@ -128,31 +128,6 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe end end - context 'when interpolation is disabled but there is a spec header' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - let(:location) { 'some-location.yml' } - - let(:content) do - <<~YAML - spec: - include: - website: - --- - run: - script: deploy $[[ inputs.website ]] - YAML - end - - it 'returns an error saying that interpolation is disabled' do - expect(valid?).to be_falsy - expect(file.errors) - .to include('`some-location.yml`: can not evaluate included file because interpolation is disabled') - end - end - context 'when interpolation was unsuccessful' do let(:location) { 'some-location.yml' } @@ -275,4 +250,17 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe it { is_expected.to eq([{ location: location, content: content }, nil, 'HEAD'].hash) } end end + + describe '#load_and_validate_expanded_hash!' do + let(:location) { 'some/file/config.yml' } + let(:logger) { instance_double(::Gitlab::Ci::Pipeline::Logger, :instrument) } + let(:context_params) { { sha: 'HEAD', variables: variables, project: project, logger: logger } } + + it 'includes instrumentation for loading and expanding the content' do + expect(logger).to receive(:instrument).once.ordered.with(:config_file_fetch_content_hash).and_yield + expect(logger).to receive(:instrument).once.ordered.with(:config_file_expand_content_includes).and_yield + + file.load_and_validate_expanded_hash! + end + end end diff --git a/spec/lib/gitlab/ci/config/external/file/component_spec.rb b/spec/lib/gitlab/ci/config/external/file/component_spec.rb index fe811bce9fe..7e3406413d0 100644 --- a/spec/lib/gitlab/ci/config/external/file/component_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/component_spec.rb @@ -121,7 +121,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category: it 'is invalid' do expect(subject).to be_falsy - expect(external_resource.error_message).to match(/does not have a valid YAML syntax/) + expect(external_resource.error_message).to match(/Invalid configuration format/) end end end diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb index 74afb3b1e97..935b6989dd7 100644 --- a/spec/lib/gitlab/ci/config/external/processor_spec.rb +++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb @@ -221,7 +221,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor, feature_category: :pipel it 'raises an error' do expect { processor.perform }.to raise_error( described_class::IncludeError, - '`lib/gitlab/ci/templates/template.yml`: content does not have a valid YAML syntax' + '`lib/gitlab/ci/templates/template.yml`: Invalid configuration format' ) end end diff --git a/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb index 726ed6d95a0..888756a3eb1 100644 --- a/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb @@ -5,10 +5,10 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeline_composition do let_it_be(:project) { create(:project) } - let(:ctx) { instance_double(Gitlab::Ci::Config::External::Context, project: project, user: build(:user, id: 1234)) } + let(:current_user) { build(:user, id: 1234) } let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(config: [header, content]) } - subject { described_class.new(result, arguments, ctx) } + subject { described_class.new(result, arguments, current_user: current_user) } context 'when input data is valid' do let(:header) do @@ -39,7 +39,7 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end context 'when config has a syntax error' do - let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) } + let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(error: 'Invalid configuration format') } let(:arguments) do { website: 'gitlab.com' } @@ -50,7 +50,7 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli expect(subject).not_to be_valid expect(subject.error_message).to eq subject.errors.first - expect(subject.errors).to include 'content does not have a valid YAML syntax' + expect(subject.errors).to include 'Invalid configuration format' end end @@ -142,28 +142,6 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end describe '#to_hash' do - context 'when interpolation is disabled' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.website ]]' } - end - - let(:arguments) { {} } - - it 'returns an empty hash' do - subject.interpolate! - - expect(subject.to_hash).to be_empty - end - end - context 'when interpolation is not used' do let(:result) do ::Gitlab::Ci::Config::Yaml::Result.new(config: content) @@ -202,118 +180,4 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end end end - - describe '#ready?' do - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.website ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - it 'returns false if interpolation has not been done yet' do - expect(subject).not_to be_ready - end - - it 'returns true if interpolation has been performed' do - subject.interpolate! - - expect(subject).to be_ready - end - - context 'when interpolation can not be performed' do - let(:result) do - ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) - end - - it 'returns true if interpolator has preliminary errors' do - expect(subject).to be_ready - end - - it 'returns true if interpolation has been attempted' do - subject.interpolate! - - expect(subject).to be_ready - end - end - end - - describe '#interpolate?' do - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.something.abc ]] $[[ inputs.cde ]] $[[ efg ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - context 'when interpolation can be performed' do - it 'will perform interpolation' do - expect(subject.interpolate?).to eq true - end - end - - context 'when interpolation is disabled' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - - context 'when an interpolation header is missing' do - let(:header) { nil } - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - - context 'when interpolator has preliminary errors' do - let(:result) do - ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) - end - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - end - - describe '#has_header?' do - let(:content) do - { test: 'deploy $[[ inputs.something.abc ]] $[[ inputs.cde ]] $[[ efg ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - context 'when header is an empty hash' do - let(:header) { {} } - - it 'does not have a header available' do - expect(subject).not_to have_header - end - end - - context 'when header is not specified' do - let(:header) { nil } - - it 'does not have a header available' do - expect(subject).not_to have_header - end - end - end end diff --git a/spec/lib/gitlab/ci/config/yaml/loader_spec.rb b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb index 1e417bcd8af..4e6151677e6 100644 --- a/spec/lib/gitlab/ci/config/yaml/loader_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb @@ -2,151 +2,58 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Yaml::Loader, feature_category: :pipeline_composition do - describe '#to_result' do +RSpec.describe ::Gitlab::Ci::Config::Yaml::Loader, feature_category: :pipeline_composition do + describe '#load' do let_it_be(:project) { create(:project) } - subject(:result) { described_class.new(yaml, project: project).to_result } - - context 'when syntax is invalid' do - let(:yaml) { 'some: invalid: syntax' } - - it 'returns an invalid result object' do - expect(result).not_to be_valid - expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError - end + let(:inputs) { { test_input: 'hello test' } } + + let(:yaml) do + <<~YAML + --- + spec: + inputs: + test_input: + --- + test_job: + script: + - echo "$[[ inputs.test_input ]]" + YAML end - context 'when the first document is a header' do - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - spec: - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result.header).to eq({ spec: nil }) - expect(result.content).to eq({ b: 2 }) - end - end - end + subject(:result) { described_class.new(yaml, inputs: inputs, current_user: project.creator).load } - context 'when first document is empty' do - let(:yaml) do - <<~YAML - --- - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when first document is an empty hash' do - let(:yaml) do - <<~YAML - {} - --- - b: 2 - YAML - end + it 'loads and interpolates CI config YAML' do + expected_config = { test_job: { script: ['echo "hello test"'] } } - it 'returns second document as a content' do - expect(result).not_to have_header - expect(result.content).to eq({ b: 2 }) - end + expect(result).to be_valid + expect(result.content).to eq(expected_config) end - context 'when first an array' do - let(:yaml) do - <<~YAML - --- - - a - - b - --- - b: 2 - YAML - end + it 'allows the use of YAML reference tags' do + expect(Psych).to receive(:add_tag).once.with( + ::Gitlab::Ci::Config::Yaml::Tags::Reference.tag, + ::Gitlab::Ci::Config::Yaml::Tags::Reference + ) - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end + result end - context 'when the first document is not a header' do - let(:yaml) do - <<~YAML - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - b: 2 - YAML - end + context 'when there is an error loading the YAML' do + let(:yaml) { 'invalid...yaml' } - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + it 'returns an error result' do + expect(result).not_to be_valid + expect(result.error).to eq('Invalid configuration format') end end - context 'when the first document is not a header and second document is empty' do - let(:yaml) do - <<~YAML - a: 1 - --- - YAML - end - - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - YAML - end + context 'when there is an error interpolating the YAML' do + let(:inputs) { {} } - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + it 'returns an error result' do + expect(result).not_to be_valid + expect(result.error).to eq('`test_input` input: required value has not been provided') end end end diff --git a/spec/lib/gitlab/ci/config/yaml_spec.rb b/spec/lib/gitlab/ci/config/yaml_spec.rb index 3576dd481c6..27d93d555f1 100644 --- a/spec/lib/gitlab/ci/config/yaml_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml_spec.rb @@ -3,18 +3,20 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_composition do - describe '.load!' do - it 'loads a YAML file' do - yaml = <<~YAML - image: 'image:1.0' - texts: - nested_key: 'value1' - more_text: - more_nested_key: 'value2' - YAML + let(:yaml) do + <<~YAML + image: 'image:1.0' + texts: + nested_key: 'value1' + more_text: + more_nested_key: 'value2' + YAML + end - config = described_class.load!(yaml) + describe '.load!' do + subject(:config) { described_class.load!(yaml) } + it 'loads a YAML file' do expect(config).to eq({ image: 'image:1.0', texts: { @@ -30,156 +32,20 @@ RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_composition let(:yaml) { 'some: invalid: syntax' } it 'raises an error' do - expect { described_class.load!(yaml) } + expect { config } .to raise_error ::Gitlab::Config::Loader::FormatError, /mapping values are not allowed in this context/ end end - end - - describe '.load_result!' do - let_it_be(:project) { create(:project) } - - subject(:result) { described_class.load_result!(yaml, project: project) } - - context 'when syntax is invalid' do - let(:yaml) { 'some: invalid: syntax' } - - it 'returns an invalid result object' do - expect(result).not_to be_valid - expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError - end - end - - context 'when the first document is a header' do - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - spec: - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result.header).to eq({ spec: nil }) - expect(result.content).to eq({ b: 2 }) - end - end - end - - context 'when first document is empty' do - let(:yaml) do - <<~YAML - --- - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when first document is an empty hash' do - let(:yaml) do - <<~YAML - {} - --- - b: 2 - YAML - end - it 'returns second document as a content' do - expect(result).not_to have_header - expect(result.content).to eq({ b: 2 }) - end - end + context 'when given a user' do + let(:user) { instance_double(User) } - context 'when first an array' do - let(:yaml) do - <<~YAML - --- - - a - - b - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when the first document is not a header' do - let(:yaml) do - <<~YAML - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - end - end - - context 'when the first document is not a header and second document is empty' do - let(:yaml) do - <<~YAML - a: 1 - --- - YAML - end - - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + subject(:config) { described_class.load!(yaml, current_user: user) } - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - YAML - end + it 'passes it to Loader' do + expect(::Gitlab::Ci::Config::Yaml::Loader).to receive(:new).with(yaml, current_user: user).and_call_original - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + config end end end diff --git a/spec/models/plan_limits_spec.rb b/spec/models/plan_limits_spec.rb index d211499e9e9..265f781d61d 100644 --- a/spec/models/plan_limits_spec.rb +++ b/spec/models/plan_limits_spec.rb @@ -364,32 +364,4 @@ RSpec.describe PlanLimits do end end end - - describe '#limit_attribute_changes', :freeze_time do - let(:user) { create(:user) } - let(:current_timestamp) { Time.current.utc.to_i } - let(:plan_limits) do - create(:plan_limits, - limits_history: { 'enforcement_limit' => [ - { user_id: user.id, username: user.username, timestamp: current_timestamp, - value: 20_000 }, { user_id: user.id, username: user.username, timestamp: current_timestamp, - value: 50_000 } - ] }) - end - - it 'returns an empty array for attribute with no changes' do - changes = plan_limits.limit_attribute_changes(:notification_limit) - - expect(changes).to eq([]) - end - - it 'returns the changes for a specific attribute' do - changes = plan_limits.limit_attribute_changes(:enforcement_limit) - - expect(changes).to eq( - [{ timestamp: current_timestamp, value: 20_000, username: user.username, user_id: user.id }, - { timestamp: current_timestamp, value: 50_000, username: user.username, user_id: user.id }] - ) - end - end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f44331521e9..b5c47d9fc40 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -6576,7 +6576,8 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr it 'does not allow access to branches for which the merge request was closed' do create( - :merge_request, :closed, + :merge_request, + :closed, target_project: target_project, target_branch: 'target-branch', source_project: project, @@ -9081,7 +9082,9 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr def create_build(new_pipeline = pipeline, name = 'test') create( - :ci_build, :success, :artifacts, + :ci_build, + :success, + :artifacts, pipeline: new_pipeline, status: new_pipeline.status, name: name diff --git a/spec/rubocop/cop_todo_spec.rb b/spec/rubocop/cop_todo_spec.rb index c641001789f..49206d76d5a 100644 --- a/spec/rubocop/cop_todo_spec.rb +++ b/spec/rubocop/cop_todo_spec.rb @@ -3,7 +3,7 @@ require 'rubocop_spec_helper' require_relative '../../rubocop/cop_todo' -RSpec.describe RuboCop::CopTodo do +RSpec.describe RuboCop::CopTodo, feature_category: :tooling do let(:cop_name) { 'Cop/Rule' } subject(:cop_todo) { described_class.new(cop_name) } @@ -32,6 +32,19 @@ RSpec.describe RuboCop::CopTodo do end end + describe '#add_files' do + it 'adds files' do + cop_todo.add_files(%w[a.rb b.rb]) + cop_todo.add_files(%w[a.rb]) + cop_todo.add_files(%w[]) + + expect(cop_todo).to have_attributes( + files: contain_exactly('a.rb', 'b.rb'), + offense_count: 0 + ) + end + end + describe '#autocorrectable?' do subject { cop_todo.autocorrectable? } diff --git a/spec/rubocop/formatter/todo_formatter_spec.rb b/spec/rubocop/formatter/todo_formatter_spec.rb index 5494d518605..fdd6117d0e6 100644 --- a/spec/rubocop/formatter/todo_formatter_spec.rb +++ b/spec/rubocop/formatter/todo_formatter_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # rubocop:disable RSpec/VerifiedDoubles require 'fast_spec_helper' @@ -10,7 +11,7 @@ require 'tmpdir' require_relative '../../../rubocop/formatter/todo_formatter' require_relative '../../../rubocop/todo_dir' -RSpec.describe RuboCop::Formatter::TodoFormatter do +RSpec.describe RuboCop::Formatter::TodoFormatter, feature_category: :tooling do let(:stdout) { StringIO.new } let(:tmp_dir) { Dir.mktmpdir } let(:real_tmp_dir) { File.join(tmp_dir, 'real') } @@ -97,6 +98,36 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do YAML end + context 'with existing HAML exclusions' do + before do + todo_dir.write('B/TooManyOffenses', <<~YAML) + --- + B/TooManyOffenses: + Exclude: + - 'd.rb' + - 'app/views/project.html.haml.rb' + - 'app/views/unrelated.html.haml.rb.ext' + - 'app/views/unrelated.html.haml.ext' + - 'app/views/unrelated.html.haml' + YAML + + todo_dir.inspect_all + end + + it 'does not remove them' do + run_formatter + + expect(todo_yml('B/TooManyOffenses')).to eq(<<~YAML) + --- + B/TooManyOffenses: + Exclude: + - 'a.rb' + - 'app/views/project.html.haml.rb' + - 'c.rb' + YAML + end + end + context 'when cop previously not explicitly disabled' do before do todo_dir.write('B/TooManyOffenses', <<~YAML) @@ -105,6 +136,8 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do Exclude: - 'x.rb' YAML + + todo_dir.inspect_all end it 'does not disable cop' do @@ -158,6 +191,8 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do Exclude: - 'x.rb' YAML + + todo_dir.inspect_all end it 'keeps cop disabled' do diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index f75c95c66f9..a28ede89cee 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -2035,7 +2035,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes expect(pipeline).to be_persisted expect(pipeline.yaml_errors) - .to include 'content does not have a valid YAML syntax' + .to include 'mapping values are not allowed' end end end @@ -2172,7 +2172,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes expect(pipeline).to be_persisted expect(pipeline.yaml_errors) - .to include 'content does not have a valid YAML syntax' + .to include 'mapping values are not allowed' end end end |