diff options
Diffstat (limited to 'spec')
-rw-r--r-- | spec/finders/fork_targets_finder_spec.rb | 4 | ||||
-rw-r--r-- | spec/fixtures/api/schemas/public_api/v4/commit/basic.json | 6 | ||||
-rw-r--r-- | spec/lib/gitlab/url_builder_spec.rb | 14 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 36 | ||||
-rw-r--r-- | spec/requests/api/groups_spec.rb | 60 | ||||
-rw-r--r-- | spec/requests/api/merge_requests_spec.rb | 20 | ||||
-rw-r--r-- | spec/requests/api/project_snippets_spec.rb | 54 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 20 | ||||
-rw-r--r-- | spec/requests/api/remote_mirrors_spec.rb | 48 | ||||
-rw-r--r-- | spec/services/ci/create_cross_project_pipeline_service_spec.rb | 72 | ||||
-rw-r--r-- | spec/services/git/branch_push_service_spec.rb | 15 | ||||
-rw-r--r-- | spec/services/merge_requests/create_service_spec.rb | 23 | ||||
-rw-r--r-- | spec/services/merge_requests/refresh_service_spec.rb | 56 |
13 files changed, 399 insertions, 29 deletions
diff --git a/spec/finders/fork_targets_finder_spec.rb b/spec/finders/fork_targets_finder_spec.rb index e7110c33071..f8c03cdf9b3 100644 --- a/spec/finders/fork_targets_finder_spec.rb +++ b/spec/finders/fork_targets_finder_spec.rb @@ -28,8 +28,8 @@ describe ForkTargetsFinder do end describe '#execute' do - it 'returns all user manageable namespaces except project namespace' do - expect(finder.execute).to match_array([user.namespace, maintained_group, owned_group]) + it 'returns all user manageable namespaces' do + expect(finder.execute).to match_array([user.namespace, maintained_group, owned_group, project.namespace]) end end end diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/basic.json b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json index 9d99628a286..da99e99c692 100644 --- a/spec/fixtures/api/schemas/public_api/v4/commit/basic.json +++ b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json @@ -12,7 +12,8 @@ "authored_date", "committer_name", "committer_email", - "committed_date" + "committed_date", + "web_url" ], "properties" : { "id": { "type": ["string", "null"] }, @@ -32,6 +33,7 @@ "authored_date": { "type": "date" }, "committer_name": { "type": "string" }, "committer_email": { "type": "string" }, - "committed_date": { "type": "date" } + "committed_date": { "type": "date" }, + "web_url": { "type": "string" } } } diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 11bbf444b1d..c2eb1b4c25d 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -14,6 +14,18 @@ describe Gitlab::UrlBuilder do end end + context 'when passing a batch loaded Commit' do + it 'returns a proper URL' do + commit = BatchLoader.for(:commit).batch do |batch, loader| + batch.each { |commit| loader.call(:commit, build_stubbed(:commit)) } + end + + url = described_class.build(commit) + + expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.full_path}/-/commit/#{commit.id}" + end + end + context 'when passing an Issue' do it 'returns a proper URL' do issue = build_stubbed(:issue, iid: 42) @@ -160,7 +172,7 @@ describe Gitlab::UrlBuilder do project = build_stubbed(:project) expect { described_class.build(project) } - .to raise_error(NotImplementedError, 'No URL builder defined for Project') + .to raise_error(NotImplementedError, "No URL builder defined for #{project.inspect}") end end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index cf1690df9ba..76051ecb177 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2813,6 +2813,30 @@ describe Ci::Pipeline, :mailer do end end + describe '#created_successfully?' do + subject { pipeline.created_successfully? } + + context 'when pipeline is not persisted' do + let(:pipeline) { build(:ci_pipeline) } + + it { is_expected.to be_falsey } + end + + context 'when pipeline is persisted' do + context 'when pipeline has failure reasons' do + let(:pipeline) { create(:ci_pipeline, failure_reason: :config_error) } + + it { is_expected.to be_falsey } + end + + context 'when pipeline has no failure reasons' do + let(:pipeline) { create(:ci_pipeline, failure_reason: nil) } + + it { is_expected.to be_truthy } + end + end + end + describe '#parent_pipeline' do let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } @@ -2960,8 +2984,7 @@ describe Ci::Pipeline, :mailer do it 'can not update bridge status if is not active' do bridge.success! - expect { pipeline.update_bridge_status! } - .to raise_error Ci::Pipeline::BridgeStatusError + expect { pipeline.update_bridge_status! }.not_to change { bridge.status } end end end @@ -2992,9 +3015,12 @@ describe Ci::Pipeline, :mailer do end describe '#update_bridge_status!' do - it 'can not update upstream job status' do - expect { pipeline.update_bridge_status! } - .to raise_error ArgumentError + it 'tracks an ArgumentError and does not update upstream job status' do + expect(Gitlab::ErrorTracking) + .to receive(:track_exception) + .with(instance_of(ArgumentError), pipeline_id: pipeline.id) + + pipeline.update_bridge_status! end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index fb564bb398b..7dfa239cd1e 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -21,6 +21,47 @@ describe API::Groups do group2.add_owner(user2) end + shared_examples 'group avatar upload' do + context 'when valid' do + let(:file_path) { 'spec/fixtures/banana_sample.gif' } + + it 'returns avatar url in response' do + make_upload_request + + group_id = json_response['id'] + expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\ + '-/system/group/avatar/'\ + "#{group_id}/banana_sample.gif") + end + end + + context 'when invalid' do + shared_examples 'invalid file upload request' do + it 'returns 400' do + make_upload_request + + expect(response).to have_gitlab_http_status(:bad_request) + expect(response.message).to eq('Bad Request') + expect(json_response['message'].to_s).to match(/#{message}/) + end + end + + context 'when file format is not supported' do + let(:file_path) { 'spec/fixtures/doc_sample.txt' } + let(:message) { 'file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico' } + + it_behaves_like 'invalid file upload request' + end + + context 'when file format is not supported' do + let(:file_path) { 'spec/fixtures/big-image.png' } + let(:message) { 'is too big' } + + it_behaves_like 'invalid file upload request' + end + end + end + describe "GET /groups" do context "when unauthenticated" do it "returns public groups" do @@ -539,6 +580,15 @@ describe API::Groups do describe 'PUT /groups/:id' do let(:new_group_name) { 'New Group'} + it_behaves_like 'group avatar upload' do + def make_upload_request + group_param = { + avatar: fixture_file_upload(file_path) + } + put api("/groups/#{group1.id}", user1), params: group_param + end + end + context 'when authenticated as the group owner' do it 'updates the group' do put api("/groups/#{group1.id}", user1), params: { @@ -940,6 +990,16 @@ describe API::Groups do end describe "POST /groups" do + it_behaves_like 'group avatar upload' do + def make_upload_request + params = attributes_for_group_api(request_access_enabled: false).tap do |attrs| + attrs[:avatar] = fixture_file_upload(file_path) + end + + post api("/groups", user3), params: params + end + end + context "when authenticated as user without group permissions" do it "does not create group" do group = attributes_for_group_api diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f0ab2f26900..d8fac47d6f6 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -1150,12 +1150,16 @@ describe API::MergeRequests do describe 'POST /projects/:id/merge_requests/:merge_request_iid/pipelines' do before do - stub_ci_pipeline_yaml_file(YAML.dump({ + stub_ci_pipeline_yaml_file(ci_yaml) + end + + let(:ci_yaml) do + YAML.dump({ rspec: { script: 'ls', only: ['merge_requests'] } - })) + }) end let(:project) do @@ -1208,6 +1212,18 @@ describe API::MergeRequests do expect(response).to have_gitlab_http_status(:not_found) end end + + context 'when the .gitlab-ci.yml file is invalid' do + let(:ci_yaml) { 'invalid yaml file' } + + it 'creates a failed pipeline' do + expect { request }.to change(Ci::Pipeline, :count).by(1) + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_a Hash + expect(merge_request.pipelines_for_merge_request.last).to be_failed + expect(merge_request.pipelines_for_merge_request.last).to be_config_error + end + end end describe 'POST /projects/:id/merge_requests' do diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 16903d9d6d0..ba5de430f7d 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -6,6 +6,12 @@ describe API::ProjectSnippets do let_it_be(:project) { create(:project, :public) } let_it_be(:user) { create(:user) } let_it_be(:admin) { create(:admin) } + let_it_be(:project_no_snippets) { create(:project, :snippets_disabled) } + + before do + project_no_snippets.add_developer(admin) + project_no_snippets.add_developer(user) + end describe "GET /projects/:project_id/snippets/:id/user_agent_detail" do let(:snippet) { create(:project_snippet, :public, project: project) } @@ -32,6 +38,12 @@ describe API::ProjectSnippets do expect(response).to have_gitlab_http_status(:forbidden) end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123/user_agent_detail", admin) } + end + end end describe 'GET /projects/:project_id/snippets/' do @@ -63,6 +75,12 @@ describe API::ProjectSnippets do expect(json_response).to be_an Array expect(json_response.size).to eq(0) end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { get api("/projects/#{project_no_snippets.id}/snippets", user) } + end + end end describe 'GET /projects/:project_id/snippets/:id' do @@ -85,6 +103,12 @@ describe API::ProjectSnippets do expect(response).to have_gitlab_http_status(:not_found) expect(json_response['message']).to eq('404 Not found') end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123", user) } + end + end end describe 'POST /projects/:project_id/snippets/' do @@ -244,11 +268,17 @@ describe API::ProjectSnippets do end end end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { post api("/projects/#{project_no_snippets.id}/snippets", user), params: params } + end + end end describe 'PUT /projects/:project_id/snippets/:id/' do let(:visibility_level) { Snippet::PUBLIC } - let(:snippet) { create(:project_snippet, author: admin, visibility_level: visibility_level) } + let(:snippet) { create(:project_snippet, author: admin, visibility_level: visibility_level, project: project) } it 'updates snippet' do new_content = 'New content' @@ -354,10 +384,16 @@ describe API::ProjectSnippets do end end end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { put api("/projects/#{project_no_snippets.id}/snippets/123", admin), params: { description: 'foo' } } + end + end end describe 'DELETE /projects/:project_id/snippets/:id/' do - let(:snippet) { create(:project_snippet, author: admin) } + let(:snippet) { create(:project_snippet, author: admin, project: project) } it 'deletes snippet' do delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) @@ -375,10 +411,16 @@ describe API::ProjectSnippets do it_behaves_like '412 response' do let(:request) { api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) } end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { delete api("/projects/#{project_no_snippets.id}/snippets/123", admin) } + end + end end describe 'GET /projects/:project_id/snippets/:id/raw' do - let(:snippet) { create(:project_snippet, author: admin) } + let(:snippet) { create(:project_snippet, author: admin, project: project) } it 'returns raw text' do get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/raw", admin) @@ -394,5 +436,11 @@ describe API::ProjectSnippets do expect(response).to have_gitlab_http_status(:not_found) expect(json_response['message']).to eq('404 Snippet Not Found') end + + context 'with snippets disabled' do + it_behaves_like '403 response' do + let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123/raw", admin) } + end + end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 59c394d8d8d..858fdc783ee 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -2935,6 +2935,26 @@ describe API::Projects do expect(response).to have_gitlab_http_status(:conflict) expect(json_response['message']['name']).to eq(['has already been taken']) end + + it 'forks to the same namespace with alternative path and name' do + post api("/projects/#{project.id}/fork", user), params: { path: 'path_2', name: 'name_2' } + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['name']).to eq('name_2') + expect(json_response['path']).to eq('path_2') + expect(json_response['owner']['id']).to eq(user.id) + expect(json_response['namespace']['id']).to eq(user.namespace.id) + expect(json_response['forked_from_project']['id']).to eq(project.id) + expect(json_response['import_status']).to eq('scheduled') + end + + it 'fails to fork to the same namespace without alternative path and name' do + post api("/projects/#{project.id}/fork", user) + + expect(response).to have_gitlab_http_status(:conflict) + expect(json_response['message']['path']).to eq(['has already been taken']) + expect(json_response['message']['name']).to eq(['has already been taken']) + end end context 'when unauthenticated' do diff --git a/spec/requests/api/remote_mirrors_spec.rb b/spec/requests/api/remote_mirrors_spec.rb index 065d9c7ca5b..2186fe375ac 100644 --- a/spec/requests/api/remote_mirrors_spec.rb +++ b/spec/requests/api/remote_mirrors_spec.rb @@ -39,6 +39,54 @@ describe API::RemoteMirrors do end end + describe 'POST /projects/:id/remote_mirrors' do + let(:route) { "/projects/#{project.id}/remote_mirrors" } + + shared_examples 'creates a remote mirror' do + it 'creates a remote mirror and returns reponse' do + project.add_maintainer(user) + + post api(route, user), params: params + + enabled = params.fetch(:enabled, false) + expect(response).to have_gitlab_http_status(:success) + expect(response).to match_response_schema('remote_mirror') + expect(json_response['enabled']).to eq(enabled) + end + end + + it 'requires `admin_remote_mirror` permission' do + post api(route, developer) + + expect(response).to have_gitlab_http_status(:unauthorized) + end + + context 'creates a remote mirror' do + context 'disabled by default' do + let(:params) { { url: 'https://foo:bar@test.com' } } + + it_behaves_like 'creates a remote mirror' + end + + context 'enabled' do + let(:params) { { url: 'https://foo:bar@test.com', enabled: true } } + + it_behaves_like 'creates a remote mirror' + end + end + + it 'returns error if url is invalid' do + project.add_maintainer(user) + + post api(route, user), params: { + url: 'ftp://foo:bar@test.com' + } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']['url']).to eq(["is blocked: Only allowed schemes are ssh, git, http, https"]) + end + end + describe 'PUT /projects/:id/remote_mirrors/:mirror_id' do let(:route) { ->(id) { "/projects/#{project.id}/remote_mirrors/#{id}" } } let(:mirror) { project.remote_mirrors.first } diff --git a/spec/services/ci/create_cross_project_pipeline_service_spec.rb b/spec/services/ci/create_cross_project_pipeline_service_spec.rb index 09d44bcea0a..667ad532fb0 100644 --- a/spec/services/ci/create_cross_project_pipeline_service_spec.rb +++ b/spec/services/ci/create_cross_project_pipeline_service_spec.rb @@ -116,6 +116,28 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do expect(bridge.reload).to be_success end + context 'when bridge job has already any downstream pipelines' do + before do + bridge.sourced_pipelines.create!( + source_pipeline: bridge.pipeline, + source_project: bridge.project, + project: bridge.project, + pipeline: create(:ci_pipeline, project: bridge.project) + ) + end + + it 'logs an error and exits' do + expect(Gitlab::ErrorTracking) + .to receive(:track_exception) + .with( + instance_of(Ci::CreateCrossProjectPipelineService::DuplicateDownstreamPipelineError), + bridge_id: bridge.id, project_id: bridge.project.id) + .and_call_original + expect(Ci::CreatePipelineService).not_to receive(:new) + expect(service.execute(bridge)).to be_nil + end + end + context 'when target ref is not specified' do let(:trigger) do { trigger: { project: downstream_project.full_path } } @@ -149,13 +171,11 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do expect(pipeline.source_bridge).to be_a ::Ci::Bridge end - it 'does not update bridge status when downstream pipeline gets processed' do + it 'updates the bridge status when downstream pipeline gets processed' do pipeline = service.execute(bridge) expect(pipeline.reload).to be_failed - # TODO: This should change to failed once #198354 gets fixed. - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25706 - expect(bridge.reload).to be_pending + expect(bridge.reload).to be_failed end end @@ -242,6 +262,22 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do it_behaves_like 'creates a child pipeline' + it 'updates the bridge job to success' do + expect { service.execute(bridge) }.to change { bridge.status }.to 'success' + end + + context 'when bridge uses "depend" strategy' do + let(:trigger) do + { + trigger: { include: 'child-pipeline.yml', strategy: 'depend' } + } + end + + it 'does not update the bridge job status' do + expect { service.execute(bridge) }.not_to change { bridge.status } + end + end + context 'when latest sha for the ref changed in the meantime' do before do upstream_project.repository.create_file( @@ -298,6 +334,34 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do end end + context 'when downstream pipeline creation errors out' do + let(:stub_config) { false } + + before do + stub_ci_pipeline_yaml_file(YAML.dump(invalid: { yaml: 'error' })) + end + + it 'creates only one new pipeline' do + expect { service.execute(bridge) } + .to change { Ci::Pipeline.count }.by(1) + end + + it 'creates a new pipeline in the downstream project' do + pipeline = service.execute(bridge) + + expect(pipeline.user).to eq bridge.user + expect(pipeline.project).to eq downstream_project + end + + it 'drops the bridge' do + pipeline = service.execute(bridge) + + expect(pipeline.reload).to be_failed + expect(bridge.reload).to be_failed + expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed') + end + end + context 'when bridge job has YAML variables defined' do before do bridge.yaml_variables = [{ key: 'BRIDGE', value: 'var', public: true }] diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb index d7357cf4d0b..acd14005c69 100644 --- a/spec/services/git/branch_push_service_spec.rb +++ b/spec/services/git/branch_push_service_spec.rb @@ -129,6 +129,21 @@ describe Git::BranchPushService, services: true do end end end + + context 'when .gitlab-ci.yml file is invalid' do + before do + stub_ci_pipeline_yaml_file('invalid yaml file') + end + + it 'persists an error pipeline' do + expect { subject }.to change { Ci::Pipeline.count } + + pipeline = Ci::Pipeline.last + expect(pipeline).to be_push + expect(pipeline).to be_failed + expect(pipeline).to be_config_error + end + end end describe "Updates merge requests" do diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index aebead481ce..c34f81901ef 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -177,18 +177,18 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do describe 'Pipelines for merge requests' do before do - stub_ci_pipeline_yaml_file(YAML.dump(config)) + stub_ci_pipeline_yaml_file(config) end context "when .gitlab-ci.yml has merge_requests keywords" do let(:config) do - { + YAML.dump({ test: { stage: 'test', script: 'echo', only: ['merge_requests'] } - } + }) end it 'creates a detached merge request pipeline and sets it as a head pipeline' do @@ -269,12 +269,12 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do context "when .gitlab-ci.yml does not have merge_requests keywords" do let(:config) do - { + YAML.dump({ test: { stage: 'test', script: 'echo' } - } + }) end it 'does not create a detached merge request pipeline' do @@ -284,6 +284,19 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do expect(merge_request.pipelines_for_merge_request.count).to eq(0) end end + + context 'when .gitlab-ci.yml is invalid' do + let(:config) { 'invalid yaml file' } + + it 'persists a pipeline with config error' do + expect(merge_request).to be_persisted + + merge_request.reload + expect(merge_request.pipelines_for_merge_request.count).to eq(1) + expect(merge_request.pipelines_for_merge_request.last).to be_failed + expect(merge_request.pipelines_for_merge_request.last).to be_config_error + end + end end it 'increments the usage data counter of create event' do diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index b67779a912d..4f052fa3edb 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -148,7 +148,7 @@ describe MergeRequests::RefreshService do describe 'Pipelines for merge requests' do before do - stub_ci_pipeline_yaml_file(YAML.dump(config)) + stub_ci_pipeline_yaml_file(config) end subject { service.new(project, @user).execute(@oldrev, @newrev, ref) } @@ -158,13 +158,13 @@ describe MergeRequests::RefreshService do context "when .gitlab-ci.yml has merge_requests keywords" do let(:config) do - { + YAML.dump({ test: { stage: 'test', script: 'echo', only: ['merge_requests'] } - } + }) end it 'create detached merge request pipeline with commits' do @@ -255,16 +255,28 @@ describe MergeRequests::RefreshService do end.not_to change { @merge_request.pipelines_for_merge_request.count } end end + + context 'when the pipeline should be skipped' do + it 'saves a skipped detached merge request pipeline' do + project.repository.create_file(@user, 'new-file.txt', 'A new file', + message: '[skip ci] This is a test', + branch_name: 'master') + + expect { subject } + .to change { @merge_request.pipelines_for_merge_request.count }.by(1) + expect(@merge_request.pipelines_for_merge_request.last).to be_skipped + end + end end context "when .gitlab-ci.yml does not have merge_requests keywords" do let(:config) do - { + YAML.dump({ test: { stage: 'test', script: 'echo' } - } + }) end it 'does not create a detached merge request pipeline' do @@ -272,6 +284,40 @@ describe MergeRequests::RefreshService do .not_to change { @merge_request.pipelines_for_merge_request.count } end end + + context 'when .gitlab-ci.yml is invalid' do + let(:config) { 'invalid yaml file' } + + it 'persists a pipeline with config error' do + expect { subject } + .to change { @merge_request.pipelines_for_merge_request.count }.by(1) + expect(@merge_request.pipelines_for_merge_request.last).to be_failed + expect(@merge_request.pipelines_for_merge_request.last).to be_config_error + end + end + + context 'when .gitlab-ci.yml file is valid but has a logical error' do + let(:config) do + YAML.dump({ + build: { + script: 'echo "Valid yaml syntax, but..."', + only: ['master'] + }, + test: { + script: 'echo "... I depend on build, which does not run."', + only: ['merge_request'], + needs: ['build'] + } + }) + end + + it 'persists a pipeline with config error' do + expect { subject } + .to change { @merge_request.pipelines_for_merge_request.count }.by(1) + expect(@merge_request.pipelines_for_merge_request.last).to be_failed + expect(@merge_request.pipelines_for_merge_request.last).to be_config_error + end + end end context 'push to origin repo source branch' do |