diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-09 15:09:29 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-09 15:09:29 +0000 |
commit | 209bd8cf1f542f6ba2a069b368a9187faa871e96 (patch) | |
tree | 6b77dc8183135b8316cc70c8dbc9c4e7c18cf05a /spec | |
parent | a9ced7da447785c57477b3d8dbccc73a78cface1 (diff) | |
download | gitlab-ce-209bd8cf1f542f6ba2a069b368a9187faa871e96.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
21 files changed, 554 insertions, 219 deletions
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index ad05f27b325..c44feaf4b63 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -796,11 +796,13 @@ describe('DiffsStoreMutations', () => { it('sets showWhitespace', () => { const state = { showWhitespace: true, + diffFiles: ['test'], }; mutations[types.SET_SHOW_WHITESPACE](state, false); expect(state.showWhitespace).toBe(false); + expect(state.diffFiles).toEqual([]); }); }); diff --git a/spec/frontend/header_spec.js b/spec/frontend/header_spec.js index 00b5b306d66..0a74799283a 100644 --- a/spec/frontend/header_spec.js +++ b/spec/frontend/header_spec.js @@ -1,53 +1,87 @@ import $ from 'jquery'; -import initTodoToggle from '~/header'; +import initTodoToggle, { initNavUserDropdownTracking } from '~/header'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; describe('Header', () => { - const todosPendingCount = '.todos-count'; - const fixtureTemplate = 'issues/open-issue.html'; + describe('Todos notification', () => { + const todosPendingCount = '.todos-count'; + const fixtureTemplate = 'issues/open-issue.html'; - function isTodosCountHidden() { - return $(todosPendingCount).hasClass('hidden'); - } + function isTodosCountHidden() { + return $(todosPendingCount).hasClass('hidden'); + } - function triggerToggle(newCount) { - $(document).trigger('todo:toggle', newCount); - } + function triggerToggle(newCount) { + $(document).trigger('todo:toggle', newCount); + } - preloadFixtures(fixtureTemplate); - beforeEach(() => { - initTodoToggle(); - loadFixtures(fixtureTemplate); - }); + preloadFixtures(fixtureTemplate); + beforeEach(() => { + initTodoToggle(); + loadFixtures(fixtureTemplate); + }); - it('should update todos-count after receiving the todo:toggle event', () => { - triggerToggle(5); + it('should update todos-count after receiving the todo:toggle event', () => { + triggerToggle(5); - expect($(todosPendingCount).text()).toEqual('5'); - }); + expect($(todosPendingCount).text()).toEqual('5'); + }); - it('should hide todos-count when it is 0', () => { - triggerToggle(0); + it('should hide todos-count when it is 0', () => { + triggerToggle(0); - expect(isTodosCountHidden()).toEqual(true); - }); + expect(isTodosCountHidden()).toEqual(true); + }); + + it('should show todos-count when it is more than 0', () => { + triggerToggle(10); + + expect(isTodosCountHidden()).toEqual(false); + }); + + describe('when todos-count is 1000', () => { + beforeEach(() => { + triggerToggle(1000); + }); - it('should show todos-count when it is more than 0', () => { - triggerToggle(10); + it('should show todos-count', () => { + expect(isTodosCountHidden()).toEqual(false); + }); - expect(isTodosCountHidden()).toEqual(false); + it('should show 99+ for todos-count', () => { + expect($(todosPendingCount).text()).toEqual('99+'); + }); + }); }); - describe('when todos-count is 1000', () => { + describe('Track user dropdown open', () => { + let trackingSpy; + beforeEach(() => { - triggerToggle(1000); + setFixtures(` + <li class="js-nav-user-dropdown"> + <a class="js-buy-ci-minutes-link" data-track-event="click_buy_ci_minutes" data-track-label="free" data-track-property="user_dropdown">Buy CI minutes + </a> + </li>`); + + trackingSpy = mockTracking('_category_', $('.js-nav-user-dropdown').element, jest.spyOn); + document.body.dataset.page = 'some:page'; + + initNavUserDropdownTracking(); }); - it('should show todos-count', () => { - expect(isTodosCountHidden()).toEqual(false); + afterEach(() => { + unmockTracking(); }); - it('should show 99+ for todos-count', () => { - expect($(todosPendingCount).text()).toEqual('99+'); + it('sends a tracking event when the dropdown is opened and contains Buy CI minutes link', () => { + $('.js-nav-user-dropdown').trigger('shown.bs.dropdown'); + + expect(trackingSpy).toHaveBeenCalledTimes(1); + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'show_buy_ci_minutes', { + label: 'free', + property: 'user_dropdown', + }); }); }); }); diff --git a/spec/frontend/helpers/monitor_helper_spec.js b/spec/frontend/helpers/monitor_helper_spec.js index 0798ca580e2..f7163d496d2 100644 --- a/spec/frontend/helpers/monitor_helper_spec.js +++ b/spec/frontend/helpers/monitor_helper_spec.js @@ -56,6 +56,32 @@ describe('monitor helper', () => { expect(result.name).toEqual('brpop'); }); + it('supports a multi metric label template expression', () => { + const config = { + ...defaultConfig, + name: '', + }; + + const [result] = monitorHelper.makeDataSeries( + [ + { + metric: { + backend: 'HA Server', + frontend: 'BA Server', + app: 'prometheus', + instance: 'k8 cluster 1', + }, + values: series, + }, + ], + config, + ); + + expect(result.name).toBe( + 'backend: HA Server, frontend: BA Server, app: prometheus, instance: k8 cluster 1', + ); + }); + it('supports space-padded template expressions', () => { const config = { ...defaultConfig, diff --git a/spec/frontend/monitoring/store/utils_spec.js b/spec/frontend/monitoring/store/utils_spec.js index e1c8e694122..fcc5614850b 100644 --- a/spec/frontend/monitoring/store/utils_spec.js +++ b/spec/frontend/monitoring/store/utils_spec.js @@ -251,7 +251,7 @@ describe('mapToDashboardViewModel', () => { }; it('creates a metric', () => { - const dashboard = dashboardWithMetric({}); + const dashboard = dashboardWithMetric({ label: 'Panel Label' }); expect(getMappedMetric(dashboard)).toEqual({ label: expect.any(String), @@ -268,11 +268,11 @@ describe('mapToDashboardViewModel', () => { expect(getMappedMetric(dashboard).metricId).toEqual('1_http_responses'); }); - it('creates a metric with a default label', () => { + it('creates a metric without a default label', () => { const dashboard = dashboardWithMetric({}); expect(getMappedMetric(dashboard)).toMatchObject({ - label: defaultLabel, + label: undefined, }); }); diff --git a/spec/frontend/repository/router_spec.js b/spec/frontend/repository/router_spec.js index 8f3ac53c37a..6944b23558a 100644 --- a/spec/frontend/repository/router_spec.js +++ b/spec/frontend/repository/router_spec.js @@ -4,14 +4,15 @@ import createRouter from '~/repository/router'; describe('Repository router spec', () => { it.each` - path | component | componentName - ${'/'} | ${IndexPage} | ${'IndexPage'} - ${'/tree/master'} | ${TreePage} | ${'TreePage'} - ${'/-/tree/master'} | ${TreePage} | ${'TreePage'} - ${'/-/tree/master/app/assets'} | ${TreePage} | ${'TreePage'} - ${'/-/tree/123/app/assets'} | ${null} | ${'null'} - `('sets component as $componentName for path "$path"', ({ path, component }) => { - const router = createRouter('', 'master'); + path | branch | component | componentName + ${'/'} | ${'master'} | ${IndexPage} | ${'IndexPage'} + ${'/tree/master'} | ${'master'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/master'} | ${'master'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/master/app/assets'} | ${'master'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/feature/test-%23/app/assets'} | ${'feature/test-#'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/123/app/assets'} | ${'master'} | ${null} | ${'null'} + `('sets component as $componentName for path "$path"', ({ path, component, branch }) => { + const router = createRouter('', branch); const componentsForRoute = router.getMatchedComponents(path); diff --git a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js new file mode 100644 index 00000000000..55e30825621 --- /dev/null +++ b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js @@ -0,0 +1,43 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlNewButton } from '@gitlab/ui'; + +import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; + +describe('Static Site Editor Toolbar', () => { + let wrapper; + + const buildWrapper = (propsData = {}) => { + wrapper = shallowMount(PublishToolbar, { + propsData: { + saveable: false, + ...propsData, + }, + }); + }; + + const findSaveChangesButton = () => wrapper.find(GlNewButton); + + beforeEach(() => { + buildWrapper(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders Submit Changes button', () => { + expect(findSaveChangesButton().exists()).toBe(true); + }); + + it('disables Submit Changes button', () => { + expect(findSaveChangesButton().attributes('disabled')).toBe('true'); + }); + + describe('when saveable', () => { + it('enables Submit Changes button', () => { + buildWrapper({ saveable: true }); + + expect(findSaveChangesButton().attributes('disabled')).toBeFalsy(); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/components/static_site_editor_spec.js index cde95d0a21e..ec984102250 100644 --- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js +++ b/spec/frontend/static_site_editor/components/static_site_editor_spec.js @@ -7,6 +7,7 @@ import createState from '~/static_site_editor/store/state'; import StaticSiteEditor from '~/static_site_editor/components/static_site_editor.vue'; import EditArea from '~/static_site_editor/components/edit_area.vue'; +import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; const localVue = createLocalVue(); @@ -16,18 +17,31 @@ describe('StaticSiteEditor', () => { let wrapper; let store; let loadContentActionMock; + let setContentActionMock; const buildStore = ({ initialState, getters } = {}) => { loadContentActionMock = jest.fn(); + setContentActionMock = jest.fn(); store = new Vuex.Store({ state: createState(initialState), getters: { isContentLoaded: () => false, + contentChanged: () => false, ...getters, }, actions: { loadContent: loadContentActionMock, + setContent: setContentActionMock, + }, + }); + }; + const buildContentLoadedStore = ({ initialState, getters } = {}) => { + buildStore({ + initialState, + getters: { + isContentLoaded: () => true, + ...getters, }, }); }; @@ -40,6 +54,8 @@ describe('StaticSiteEditor', () => { }; const findEditArea = () => wrapper.find(EditArea); + const findPublishToolbar = () => wrapper.find(PublishToolbar); + const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); beforeEach(() => { buildStore(); @@ -54,6 +70,10 @@ describe('StaticSiteEditor', () => { it('does not render edit area', () => { expect(findEditArea().exists()).toBe(false); }); + + it('does not render toolbar', () => { + expect(findPublishToolbar().exists()).toBe(false); + }); }); describe('when content is loaded', () => { @@ -68,19 +88,49 @@ describe('StaticSiteEditor', () => { expect(findEditArea().exists()).toBe(true); }); + it('does not render skeleton loader', () => { + expect(findSkeletonLoader().exists()).toBe(false); + }); + it('passes page content to edit area', () => { expect(findEditArea().props('value')).toBe(content); }); + + it('renders toolbar', () => { + expect(findPublishToolbar().exists()).toBe(true); + }); + }); + + it('sets toolbar as saveable when content changes', () => { + buildContentLoadedStore({ + getters: { + contentChanged: () => true, + }, + }); + buildWrapper(); + + expect(findPublishToolbar().props('saveable')).toBe(true); }); - it('displays skeleton loader while loading content', () => { + it('displays skeleton loader when loading content', () => { buildStore({ initialState: { isLoadingContent: true } }); buildWrapper(); - expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true); + expect(findSkeletonLoader().exists()).toBe(true); }); it('dispatches load content action', () => { expect(loadContentActionMock).toHaveBeenCalled(); }); + + it('dispatches setContent action when edit area emits input event', () => { + const content = 'new content'; + + buildContentLoadedStore(); + buildWrapper(); + + findEditArea().vm.$emit('input', content); + + expect(setContentActionMock).toHaveBeenCalledWith(expect.anything(), content, undefined); + }); }); diff --git a/spec/frontend/static_site_editor/store/actions_spec.js b/spec/frontend/static_site_editor/store/actions_spec.js index 98d7d0d2c2d..4ad1e798ccd 100644 --- a/spec/frontend/static_site_editor/store/actions_spec.js +++ b/spec/frontend/static_site_editor/store/actions_spec.js @@ -73,4 +73,15 @@ describe('Static Site Editor Store actions', () => { }); }); }); + + describe('setContent', () => { + it('commits setContent mutation', () => { + testAction(actions.setContent, content, state, [ + { + type: mutationTypes.SET_CONTENT, + payload: content, + }, + ]); + }); + }); }); diff --git a/spec/frontend/static_site_editor/store/getters_spec.js b/spec/frontend/static_site_editor/store/getters_spec.js index 8800216f3b0..1b482db9366 100644 --- a/spec/frontend/static_site_editor/store/getters_spec.js +++ b/spec/frontend/static_site_editor/store/getters_spec.js @@ -1,15 +1,29 @@ import createState from '~/static_site_editor/store/state'; -import { isContentLoaded } from '~/static_site_editor/store/getters'; +import { isContentLoaded, contentChanged } from '~/static_site_editor/store/getters'; import { sourceContent as content } from '../mock_data'; describe('Static Site Editor Store getters', () => { describe('isContentLoaded', () => { - it('returns true when content is not empty', () => { - expect(isContentLoaded(createState({ content }))).toBe(true); + it('returns true when originalContent is not empty', () => { + expect(isContentLoaded(createState({ originalContent: content }))).toBe(true); }); - it('returns false when content is empty', () => { - expect(isContentLoaded(createState({ content: '' }))).toBe(false); + it('returns false when originalContent is empty', () => { + expect(isContentLoaded(createState({ originalContent: '' }))).toBe(false); + }); + }); + + describe('contentChanged', () => { + it('returns true when content and originalContent are different', () => { + const state = createState({ content, originalContent: 'something else' }); + + expect(contentChanged(state)).toBe(true); + }); + + it('returns false when content and originalContent are the same', () => { + const state = createState({ content, originalContent: content }); + + expect(contentChanged(state)).toBe(false); }); }); }); diff --git a/spec/frontend/static_site_editor/store/mutations_spec.js b/spec/frontend/static_site_editor/store/mutations_spec.js index c7055fbb2f0..db3a1081af5 100644 --- a/spec/frontend/static_site_editor/store/mutations_spec.js +++ b/spec/frontend/static_site_editor/store/mutations_spec.js @@ -35,8 +35,9 @@ describe('Static Site Editor Store mutations', () => { expect(state.title).toBe(payload.title); }); - it('sets content', () => { + it('sets originalContent and content', () => { expect(state.content).toBe(payload.content); + expect(state.originalContent).toBe(payload.content); }); }); @@ -49,4 +50,12 @@ describe('Static Site Editor Store mutations', () => { expect(state.isLoadingContent).toBe(false); }); }); + + describe('setContent', () => { + it('sets content', () => { + mutations[types.SET_CONTENT](state, content); + + expect(state.content).toBe(content); + }); + }); }); diff --git a/spec/lib/gitlab/ci/config/entry/include_spec.rb b/spec/lib/gitlab/ci/config/entry/include_spec.rb new file mode 100644 index 00000000000..bab11f26fa1 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/include_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ::Gitlab::Ci::Config::Entry::Include do + subject(:include_entry) { described_class.new(config) } + + describe 'validations' do + before do + include_entry.compose! + end + + context 'when value is a string' do + let(:config) { 'test.yml' } + + it { is_expected.to be_valid } + end + + context 'when value is hash' do + context 'when using not allowed keys' do + let(:config) do + { not_allowed: 'key' } + end + + it { is_expected.not_to be_valid } + end + + context 'when using "local"' do + let(:config) { { local: 'test.yml' } } + + it { is_expected.to be_valid } + end + + context 'when using "file"' do + let(:config) { { file: 'test.yml' } } + + it { is_expected.to be_valid } + end + + context 'when using "template"' do + let(:config) { { template: 'test.yml' } } + + it { is_expected.to be_valid } + end + + context 'when using "artifact"' do + context 'and specifying "job"' do + let(:config) { { artifact: 'test.yml', job: 'generator' } } + + it { is_expected.to be_valid } + end + + context 'without "job"' do + let(:config) { { artifact: 'test.yml' } } + + it { is_expected.not_to be_valid } + + it 'has specific error' do + expect(include_entry.errors) + .to include('include config must specify the job where to fetch the artifact from') + end + end + end + end + + context 'when value is something else' do + let(:config) { 123 } + + it { is_expected.not_to be_valid } + end + end +end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 62adba4319e..70c3c5ab339 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -2052,6 +2052,54 @@ module Gitlab end end + describe 'with parent-child pipeline' do + context 'when artifact and job are specified' do + let(:config) do + YAML.dump({ + build1: { stage: 'build', script: 'test' }, + test1: { stage: 'test', trigger: { + include: [{ artifact: 'generated.yml', job: 'build1' }] + } } + }) + end + + it { expect { subject }.not_to raise_error } + end + + context 'when job is not specified specified while artifact is' do + let(:config) do + YAML.dump({ + build1: { stage: 'build', script: 'test' }, + test1: { stage: 'test', trigger: { + include: [{ artifact: 'generated.yml' }] + } } + }) + end + + it do + expect { subject }.to raise_error( + described_class::ValidationError, + /include config must specify the job where to fetch the artifact from/) + end + end + + context 'when include is a string' do + let(:config) do + YAML.dump({ + build1: { stage: 'build', script: 'test' }, + test1: { + stage: 'test', + trigger: { + include: 'generated.yml' + } + } + }) + end + + it { expect { subject }.not_to raise_error } + end + end + describe "Error handling" do it "fails to parse YAML" do expect do diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index f25383ef416..06f9767d58b 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -301,26 +301,12 @@ describe Gitlab::Git::Blob, :seed_helper do stub_const('Gitlab::Git::Blob::BATCH_SIZE', 2) end - context 'blobs_fetch_in_batches is enabled' do - it 'fetches the blobs in batches' do - expect(client).to receive(:get_blobs).with(first_batch, limit).ordered - expect(client).to receive(:get_blobs).with(second_batch, limit).ordered - expect(client).to receive(:get_blobs).with(third_batch, limit).ordered + it 'fetches the blobs in batches' do + expect(client).to receive(:get_blobs).with(first_batch, limit).ordered + expect(client).to receive(:get_blobs).with(second_batch, limit).ordered + expect(client).to receive(:get_blobs).with(third_batch, limit).ordered - subject - end - end - - context 'blobs_fetch_in_batches is disabled' do - before do - stub_feature_flags(blobs_fetch_in_batches: false) - end - - it 'fetches the blobs in a single batch' do - expect(client).to receive(:get_blobs).with(blob_references, limit) - - subject - end + subject end end end diff --git a/spec/lib/gitlab/git/diff_stats_collection_spec.rb b/spec/lib/gitlab/git/diff_stats_collection_spec.rb index b07690ef39c..82d15a49062 100644 --- a/spec/lib/gitlab/git/diff_stats_collection_spec.rb +++ b/spec/lib/gitlab/git/diff_stats_collection_spec.rb @@ -29,4 +29,16 @@ describe Gitlab::Git::DiffStatsCollection do expect(collection.paths).to eq %w[foo bar] end end + + describe '#real_size' do + it 'returns the number of modified files' do + expect(collection.real_size).to eq('2') + end + + it 'returns capped number when it is bigger than max_files' do + allow(::Commit).to receive(:max_diff_options).and_return(max_files: 1) + + expect(collection.real_size).to eq('1+') + end + end end diff --git a/spec/models/ci/build_dependencies_spec.rb b/spec/models/ci/build_dependencies_spec.rb index 6db69d0f34c..8f2199ac360 100644 --- a/spec/models/ci/build_dependencies_spec.rb +++ b/spec/models/ci/build_dependencies_spec.rb @@ -96,14 +96,6 @@ describe Ci::BuildDependencies do end it { is_expected.to contain_exactly(build, rspec_test, staging) } - - context 'when ci_dag_support is disabled' do - before do - stub_feature_flags(ci_dag_support: false) - end - - it { is_expected.to contain_exactly(build, rspec_test, rubocop_test, staging) } - end end context 'when need artifacts are defined' do diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb index e03f54aa728..e8ef7b29681 100644 --- a/spec/models/ci/processable_spec.rb +++ b/spec/models/ci/processable_spec.rb @@ -25,20 +25,6 @@ describe Ci::Processable do it 'returns all needs' do expect(with_aggregated_needs.first.aggregated_needs_names).to contain_exactly('test1', 'test2') end - - context 'with ci_dag_support disabled' do - before do - stub_feature_flags(ci_dag_support: false) - end - - it 'returns all processables' do - expect(with_aggregated_needs).to contain_exactly(processable) - end - - it 'returns empty needs' do - expect(with_aggregated_needs.first.aggregated_needs_names).to be_nil - end - end end context 'without needs' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index bfad1da1e21..50bb194ef71 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -874,7 +874,7 @@ describe MergeRequest do subject(:merge_request) { build(:merge_request) } before do - expect(diff).to receive(:modified_paths).and_return(paths) + allow(diff).to receive(:modified_paths).and_return(paths) end context 'when past_merge_request_diff is specified' do @@ -890,10 +890,29 @@ describe MergeRequest do let(:compare) { double(:compare) } let(:diff) { compare } - it 'returns affected file paths from compare' do + before do merge_request.compare = compare - expect(merge_request.modified_paths).to eq(paths) + expect(merge_request).to receive(:diff_stats).and_return(diff_stats) + end + + context 'and diff_stats are not present' do + let(:diff_stats) { nil } + + it 'returns affected file paths from compare' do + expect(merge_request.modified_paths).to eq(paths) + end + end + + context 'and diff_stats are present' do + let(:diff_stats) { double(:diff_stats) } + + it 'returns affected file paths from compare' do + diff_stats_path = double(:diff_stats_paths) + expect(diff_stats).to receive(:paths).and_return(diff_stats_path) + + expect(merge_request.modified_paths).to eq(diff_stats_path) + end end end diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 8c4d1951697..2061084d5ea 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -703,7 +703,7 @@ describe Snippet do let(:current_size) { 60 } before do - allow(subject.repository).to receive(:_uncached_size).and_return(current_size) + allow(subject.repository).to receive(:size).and_return(current_size) end it 'sets up size checker', :aggregate_failures do diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb index b4071d1b0fe..a76e83f2d60 100644 --- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb +++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb @@ -18,25 +18,10 @@ describe Ci::CreatePipelineService, '#execute' do before do project.add_developer(user) - stub_ci_pipeline_to_return_yaml_file + stub_ci_pipeline_yaml_file(config) end - describe 'child pipeline triggers' do - before do - stub_ci_pipeline_yaml_file <<~YAML - test: - script: rspec - - deploy: - variables: - CROSS: downstream - stage: deploy - trigger: - include: - - local: path/to/child.yml - YAML - end - + shared_examples 'successful creation' do it 'creates bridge jobs correctly' do pipeline = create_pipeline! @@ -48,58 +33,140 @@ describe Ci::CreatePipelineService, '#execute' do expect(bridge).to be_a Ci::Bridge expect(bridge.stage).to eq 'deploy' expect(pipeline.statuses).to match_array [test, bridge] - expect(bridge.options).to eq( - 'trigger' => { 'include' => [{ 'local' => 'path/to/child.yml' }] } - ) + expect(bridge.options).to eq(expected_bridge_options) expect(bridge.yaml_variables) .to include(key: 'CROSS', value: 'downstream', public: true) end end + shared_examples 'creation failure' do + it 'returns errors' do + pipeline = create_pipeline! + + expect(pipeline.errors.full_messages.first).to match(expected_error) + expect(pipeline.failure_reason).to eq 'config_error' + expect(pipeline).to be_persisted + expect(pipeline.status).to eq 'failed' + end + end + + describe 'child pipeline triggers' do + let(:config) do + <<~YAML + test: + script: rspec + deploy: + variables: + CROSS: downstream + stage: deploy + trigger: + include: + - local: path/to/child.yml + YAML + end + + it_behaves_like 'successful creation' do + let(:expected_bridge_options) do + { + 'trigger' => { + 'include' => [ + { 'local' => 'path/to/child.yml' } + ] + } + } + end + end + end + describe 'child pipeline triggers' do context 'when YAML is valid' do - before do - stub_ci_pipeline_yaml_file <<~YAML + let(:config) do + <<~YAML + test: + script: rspec + deploy: + variables: + CROSS: downstream + stage: deploy + trigger: + include: + - local: path/to/child.yml + YAML + end + + it_behaves_like 'successful creation' do + let(:expected_bridge_options) do + { + 'trigger' => { + 'include' => [ + { 'local' => 'path/to/child.yml' } + ] + } + } + end + end + + context 'when trigger:include is specified as a string' do + let(:config) do + <<~YAML test: script: rspec + deploy: + variables: + CROSS: downstream + stage: deploy + trigger: + include: path/to/child.yml + YAML + end + + it_behaves_like 'successful creation' do + let(:expected_bridge_options) do + { + 'trigger' => { + 'include' => 'path/to/child.yml' + } + } + end + end + end + context 'when trigger:include is specified as array of strings' do + let(:config) do + <<~YAML + test: + script: rspec deploy: variables: CROSS: downstream stage: deploy trigger: include: - - local: path/to/child.yml - YAML - end + - path/to/child.yml + - path/to/child2.yml + YAML + end - it 'creates bridge jobs correctly' do - pipeline = create_pipeline! - - test = pipeline.statuses.find_by(name: 'test') - bridge = pipeline.statuses.find_by(name: 'deploy') - - expect(pipeline).to be_persisted - expect(test).to be_a Ci::Build - expect(bridge).to be_a Ci::Bridge - expect(bridge.stage).to eq 'deploy' - expect(pipeline.statuses).to match_array [test, bridge] - expect(bridge.options).to eq( - 'trigger' => { 'include' => [{ 'local' => 'path/to/child.yml' }] } - ) - expect(bridge.yaml_variables) - .to include(key: 'CROSS', value: 'downstream', public: true) + it_behaves_like 'successful creation' do + let(:expected_bridge_options) do + { + 'trigger' => { + 'include' => ['path/to/child.yml', 'path/to/child2.yml'] + } + } + end + end end end - context 'when YAML is invalid' do + context 'when limit of includes is reached' do let(:config) do - { + YAML.dump({ test: { script: 'rspec' }, deploy: { trigger: { include: included_files } } - } + }) end let(:included_files) do @@ -112,17 +179,46 @@ describe Ci::CreatePipelineService, '#execute' do Gitlab::Ci::Config::Entry::Trigger::ComplexTrigger::SameProjectTrigger::INCLUDE_MAX_SIZE end - before do - stub_ci_pipeline_yaml_file(YAML.dump(config)) + it_behaves_like 'creation failure' do + let(:expected_error) { /trigger:include config is too long/ } end + end - it 'returns errors' do - pipeline = create_pipeline! + context 'when including configs from artifact' do + context 'when specified dependency is in the wrong order' do + let(:config) do + <<~YAML + test: + trigger: + include: + - job: generator + artifact: 'generated.yml' + generator: + stage: 'deploy' + script: 'generator' + YAML + end - expect(pipeline.errors.full_messages.first).to match(/trigger:include config is too long/) - expect(pipeline.failure_reason).to eq 'config_error' - expect(pipeline).to be_persisted - expect(pipeline.status).to eq 'failed' + it_behaves_like 'creation failure' do + let(:expected_error) { /test job: dependency generator is not defined in prior stages/ } + end + end + + context 'when specified dependency is missing :job key' do + let(:config) do + <<~YAML + test: + trigger: + include: + - artifact: 'generated.yml' + YAML + end + + it_behaves_like 'creation failure' do + let(:expected_error) do + /include config must specify the job where to fetch the artifact from/ + end + end end end end diff --git a/spec/services/ci/pipeline_processing/shared_processing_service.rb b/spec/services/ci/pipeline_processing/shared_processing_service.rb index ca003299535..ffe5eacfc48 100644 --- a/spec/services/ci/pipeline_processing/shared_processing_service.rb +++ b/spec/services/ci/pipeline_processing/shared_processing_service.rb @@ -757,73 +757,19 @@ shared_examples 'Pipeline Processing Service' do expect(builds.pending).to contain_exactly(deploy) end - context 'when feature ci_dag_support is disabled' do - before do - stub_feature_flags(ci_dag_support: false) - end - - it 'when linux:build finishes first it follows stages' do - expect(process_pipeline).to be_truthy - - expect(stages).to eq(%w(pending created created)) - expect(builds.pending).to contain_exactly(linux_build, mac_build) - - # we follow the single path of linux - linux_build.reset.success! - - expect(stages).to eq(%w(running created created)) - expect(builds.success).to contain_exactly(linux_build) - expect(builds.pending).to contain_exactly(mac_build) - - mac_build.reset.success! - - expect(stages).to eq(%w(success pending created)) - expect(builds.success).to contain_exactly(linux_build, mac_build) - expect(builds.pending).to contain_exactly( - linux_rspec, linux_rubocop, mac_rspec, mac_rubocop) - - linux_rspec.reset.success! - linux_rubocop.reset.success! - mac_rspec.reset.success! - mac_rubocop.reset.success! - - expect(stages).to eq(%w(success success pending)) - expect(builds.success).to contain_exactly( - linux_build, linux_rspec, linux_rubocop, mac_build, mac_rspec, mac_rubocop) - expect(builds.pending).to contain_exactly(deploy) - end - end - context 'when one of the jobs is run on a failure' do let!(:linux_notify) { create_build('linux:notify', stage: 'deploy', stage_idx: 2, when: 'on_failure', scheduling_type: :dag) } let!(:linux_notify_on_build) { create(:ci_build_need, build: linux_notify, name: 'linux:build') } context 'when another job in build phase fails first' do - context 'when ci_dag_support is enabled' do - it 'does skip linux:notify' do - expect(process_pipeline).to be_truthy - - mac_build.reset.drop! - linux_build.reset.success! - - expect(linux_notify.reset).to be_skipped - end - end - - context 'when ci_dag_support is disabled' do - before do - stub_feature_flags(ci_dag_support: false) - end - - it 'does run linux:notify' do - expect(process_pipeline).to be_truthy + it 'does skip linux:notify' do + expect(process_pipeline).to be_truthy - mac_build.reset.drop! - linux_build.reset.success! + mac_build.reset.drop! + linux_build.reset.success! - expect(linux_notify.reset).to be_pending - end + expect(linux_notify.reset).to be_skipped end end @@ -864,19 +810,6 @@ shared_examples 'Pipeline Processing Service' do expect(stages).to eq(%w(success success running)) expect(builds.pending).to contain_exactly(deploy) end - - context 'when ci_dag_support is disabled' do - before do - stub_feature_flags(ci_dag_support: false) - end - - it 'does run deploy_pages at the start' do - expect(process_pipeline).to be_truthy - - expect(stages).to eq(%w(pending created created)) - expect(builds.pending).to contain_exactly(linux_build, mac_build) - end - end end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index ac17919d7f0..a51e0b79075 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -394,6 +394,7 @@ describe PostReceive do it 'expires the status cache' do expect(snippet.repository).to receive(:empty?).and_return(true) expect(snippet.repository).to receive(:expire_status_cache) + expect(snippet.repository).to receive(:expire_statistics_caches) perform end |