diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-16 18:08:32 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-16 18:08:32 +0300 |
commit | 10fd79745df7b572fc79fd84b58e818e64bf2571 (patch) | |
tree | a89151d08c7a13334843b3a6f9010c00acabcb2b /spec | |
parent | 9bfdb5cf67ca45ac6d354e18168f5df12b60ccd2 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/projects/tags_controller_spec.rb | 66 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/charts/time_series_spec.js | 6 | ||||
-rw-r--r-- | spec/frontend/monitoring/pages/dashboard_page_spec.js | 36 | ||||
-rw-r--r-- | spec/helpers/gitlab_routing_helper_spec.rb | 10 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/auth_finders_spec.rb | 24 | ||||
-rw-r--r-- | spec/lib/gitlab/repo_path_spec.rb | 18 | ||||
-rw-r--r-- | spec/models/concerns/route_model_query_spec.rb | 28 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 6 | ||||
-rw-r--r-- | spec/models/snippet_spec.rb | 26 | ||||
-rw-r--r-- | spec/requests/api/oauth_tokens_spec.rb | 15 | ||||
-rw-r--r-- | spec/requests/api/terraform/state_spec.rb | 73 | ||||
-rw-r--r-- | spec/services/releases/create_service_spec.rb | 74 | ||||
-rw-r--r-- | spec/support/helpers/api_helpers.rb | 11 | ||||
-rw-r--r-- | spec/support/helpers/http_basic_auth_helpers.rb | 26 | ||||
-rw-r--r-- | spec/workers/create_evidence_worker_spec.rb | 15 |
15 files changed, 380 insertions, 54 deletions
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb index 9ca56f58055..122d1b072d0 100644 --- a/spec/controllers/projects/tags_controller_spec.rb +++ b/spec/controllers/projects/tags_controller_spec.rb @@ -6,6 +6,7 @@ RSpec.describe Projects::TagsController do let(:project) { create(:project, :public, :repository) } let!(:release) { create(:release, project: project) } let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') } + let(:user) { create(:user) } describe 'GET index' do before do @@ -61,4 +62,69 @@ RSpec.describe Projects::TagsController do end end end + + describe 'POST #create' do + before do + project.add_developer(user) + sign_in(user) + end + + let(:release_description) { nil } + let(:request) do + post(:create, params: { + namespace_id: project.namespace.to_param, + project_id: project, + tag_name: '1.0', + ref: 'master', + release_description: release_description + }) + end + + it 'creates tag' do + request + + expect(response).to have_gitlab_http_status(:found) + expect(project.repository.find_tag('1.0')).to be_present + end + + # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245 + context 'when release description is set' do + let(:release_description) { 'some release description' } + + it 'creates tag and release' do + request + + expect(response).to have_gitlab_http_status(:found) + expect(project.repository.find_tag('1.0')).to be_present + + release = project.releases.find_by_tag!('1.0') + + expect(release).to be_present + expect(release.description).to eq(release_description) + end + + it 'passes the last pipeline for evidence creation', :sidekiq_inline do + sha = project.repository.commit('master').sha + create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline + pipeline = create(:ci_empty_pipeline, sha: sha, project: project) + + # simulating pipeline creation by new tag + expect_any_instance_of(Repository).to receive(:add_tag).and_wrap_original do |m, *args| + create(:ci_empty_pipeline, sha: sha, project: project) + m.call(*args) + end + + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + request + + release = project.releases.find_by_tag!('1.0') + + expect(release).to be_present + expect(release.description).to eq(release_description) + end + end + end end diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index d1afcf7da0d..271b65748ea 100644 --- a/spec/frontend/monitoring/components/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -411,6 +411,12 @@ describe('Time series component', () => { }); }); + describe('xAxis pointer', () => { + it('snap is set to false by default', () => { + expect(getChartOptions().xAxis.axisPointer.snap).toBe(false); + }); + }); + describe('are extended by `option`', () => { const mockSeriesName = 'Extra series 1'; const mockOption = { diff --git a/spec/frontend/monitoring/pages/dashboard_page_spec.js b/spec/frontend/monitoring/pages/dashboard_page_spec.js new file mode 100644 index 00000000000..e3c56ef4cbf --- /dev/null +++ b/spec/frontend/monitoring/pages/dashboard_page_spec.js @@ -0,0 +1,36 @@ +import { shallowMount } from '@vue/test-utils'; +import DashboardPage from '~/monitoring/pages/dashboard_page.vue'; +import Dashboard from '~/monitoring/components/dashboard.vue'; +import { propsData } from '../mock_data'; + +describe('monitoring/pages/dashboard_page', () => { + let wrapper; + + const buildWrapper = (props = {}) => { + wrapper = shallowMount(DashboardPage, { + propsData: { + ...props, + }, + }); + }; + + const findDashboardComponent = () => wrapper.find(Dashboard); + + afterEach(() => { + if (wrapper) { + wrapper.destroy(); + wrapper = null; + } + }); + + it('throws errors if dashboard props are not passed', () => { + expect(() => buildWrapper()).toThrow('Missing required prop: "dashboardProps"'); + }); + + it('renders the dashboard page with dashboard component', () => { + buildWrapper({ dashboardProps: propsData }); + + expect(findDashboardComponent().props()).toMatchObject(propsData); + expect(findDashboardComponent()).toExist(); + }); +}); diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb index 64b23043dac..4def04f4284 100644 --- a/spec/helpers/gitlab_routing_helper_spec.rb +++ b/spec/helpers/gitlab_routing_helper_spec.rb @@ -238,6 +238,16 @@ describe GitlabRoutingHelper do expect(gitlab_toggle_award_emoji_snippet_url(personal_snippet)).to eq("http://test.host/snippets/#{personal_snippet.id}/toggle_award_emoji") end end + + describe '#gitlab_dashboard_snippets_path' do + it 'returns the personal snippets dashboard path' do + expect(gitlab_dashboard_snippets_path(personal_snippet)).to eq("/dashboard/snippets") + end + + it 'returns the project snippets dashboard path' do + expect(gitlab_dashboard_snippets_path(project_snippet)).to eq("/#{project_snippet.project.full_path}/snippets") + end + end end context 'wikis' do diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb index 774a87752b9..2aef206c7fd 100644 --- a/spec/lib/gitlab/auth/auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/auth_finders_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe Gitlab::Auth::AuthFinders do include described_class + include HttpBasicAuthHelpers let(:user) { create(:user) } let(:env) do @@ -22,10 +23,7 @@ describe Gitlab::Auth::AuthFinders do end def set_basic_auth_header(username, password) - set_header( - 'HTTP_AUTHORIZATION', - ActionController::HttpAuthentication::Basic.encode_credentials(username, password) - ) + env.merge!(basic_auth_header(username, password)) end describe '#find_user_from_warden' do @@ -653,6 +651,24 @@ describe Gitlab::Auth::AuthFinders do it_behaves_like 'job token params', described_class::JOB_TOKEN_PARAM it_behaves_like 'job token params', described_class::RUNNER_JOB_TOKEN_PARAM end + + context 'when the job token is provided via basic auth' do + let(:route_authentication_setting) { { job_token_allowed: :basic_auth } } + let(:username) { Ci::Build::CI_REGISTRY_USER } + let(:token) { job.token } + + before do + set_basic_auth_header(username, token) + end + + it { is_expected.to eq(user) } + + context 'credentials are provided but route setting is incorrect' do + let(:route_authentication_setting) { { job_token_allowed: :unknown } } + + it { is_expected.to be_nil } + end + end end describe '#find_runner_from_token' do diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb index 68571b9de20..6d54342ac46 100644 --- a/spec/lib/gitlab/repo_path_spec.rb +++ b/spec/lib/gitlab/repo_path_spec.rb @@ -67,11 +67,11 @@ describe ::Gitlab::RepoPath do end end - describe '.find_project' do + describe '.find_routes_source' do context 'when finding a project by its canonical path' do context 'when the cases match' do it 'returns the project and nil' do - expect(described_class.find_project(project.full_path)).to eq([project, nil]) + expect(described_class.find_routes_source(project.full_path)).to eq([project, nil]) end end @@ -81,14 +81,14 @@ describe ::Gitlab::RepoPath do # requests, we should accept wrongly-cased URLs because it is a pain to # block people's git operations and force them to update remote URLs. it 'returns the project and nil' do - expect(described_class.find_project(project.full_path.upcase)).to eq([project, nil]) + expect(described_class.find_routes_source(project.full_path.upcase)).to eq([project, nil]) end end end context 'when finding a project via a redirect' do it 'returns the project and nil' do - expect(described_class.find_project(redirect.path)).to eq([project, redirect.path]) + expect(described_class.find_routes_source(redirect.path)).to eq([project, redirect.path]) end end end @@ -110,6 +110,16 @@ describe ::Gitlab::RepoPath do end end + context 'when path is namespace path, but has same id as project' do + let(:namespace) { build_stubbed(:namespace, id: project.id) } + + it 'returns nil if path is referring to namespace' do + allow(described_class).to receive(:find_route_source).and_return(namespace) + + expect(described_class.find_snippet("#{namespace.full_path}/snippets/#{project_snippet.id}")).to eq([nil, nil]) + end + end + it 'returns nil for snippets not associated with the project' do snippet = create(:project_snippet) diff --git a/spec/models/concerns/route_model_query_spec.rb b/spec/models/concerns/route_model_query_spec.rb new file mode 100644 index 00000000000..ac58c8d44fa --- /dev/null +++ b/spec/models/concerns/route_model_query_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Route, 'RouteModelQuery', :aggregate_failures do + let_it_be(:group1) { create(:group, path: 'Group1') } + let_it_be(:group2) { create(:group, path: 'Group2') } + let_it_be(:project1) { create(:project, path: 'Project1', group: group1) } + let_it_be(:project2) { create(:project, path: 'Project2', group: group2) } + + describe '.find_source_of_path' do + it 'finds exact match' do + expect(described_class.find_source_of_path('Group1')).to eq(group1) + expect(described_class.find_source_of_path('Group2/Project2')).to eq(project2) + + expect(described_class.find_source_of_path('GROUP1')).to be_nil + expect(described_class.find_source_of_path('GROUP2/PROJECT2')).to be_nil + end + + it 'finds case insensitive match' do + expect(described_class.find_source_of_path('Group1', case_sensitive: false)).to eq(group1) + expect(described_class.find_source_of_path('Group2/Project2', case_sensitive: false)).to eq(project2) + + expect(described_class.find_source_of_path('GROUP1', case_sensitive: false)).to eq(group1) + expect(described_class.find_source_of_path('GROUP2/PROJECT2', case_sensitive: false)).to eq(project2) + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1a223b6c5bd..9ec306d297e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -5227,13 +5227,13 @@ describe Project do describe '#find_or_initialize_services' do it 'returns only enabled services' do - allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover]) + allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover teamcity]) allow(subject).to receive(:disabled_services).and_return(%w[prometheus]) services = subject.find_or_initialize_services - expect(services.count).to eq 1 - expect(services).to include(PushoverService) + expect(services.count).to eq(2) + expect(services.map(&:title)).to eq(['JetBrains TeamCity CI', 'Pushover']) end end diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 4d6586c1df4..22e78c49ce5 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -206,6 +206,32 @@ describe Snippet do end end + describe '.find_by_id_and_project' do + let_it_be(:project) { create(:project) } + let_it_be(:project_snippet) { create(:project_snippet, project: project) } + let_it_be(:personal_snippet) { create(:personal_snippet) } + + context 'when project is provided' do + it 'returns ProjectSnippet' do + expect(described_class.find_by_id_and_project(id: project_snippet.id, project: project)).to eq(project_snippet) + end + end + + context 'when project is nil' do + it 'returns PersonalSnippet' do + expect(described_class.find_by_id_and_project(id: personal_snippet.id, project: nil)).to eq(personal_snippet) + end + end + + context 'when project variable is not a Project' do + let(:namespace) { build_stubbed(:namespace, id: project.id) } + + it 'returns nil' do + expect(described_class.find_by_id_and_project(id: project_snippet.id, project: namespace)).to be_nil + end + end + end + describe '.with_optional_visibility' do context 'when a visibility level is provided' do it 'returns snippets with the given visibility' do diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb index 3266fed1741..5e775841f12 100644 --- a/spec/requests/api/oauth_tokens_spec.rb +++ b/spec/requests/api/oauth_tokens_spec.rb @@ -3,20 +3,9 @@ require 'spec_helper' describe 'OAuth tokens' do - context 'Resource Owner Password Credentials' do - def basic_auth_header(username, password) - { - 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials( - username, - password - ) - } - end - - def client_basic_auth_header(client) - basic_auth_header(client.uid, client.secret) - end + include HttpBasicAuthHelpers + context 'Resource Owner Password Credentials' do def request_oauth_token(user, headers = {}) post '/oauth/token', params: { username: user.username, password: user.password, grant_type: 'password' }, diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb index 844cd948411..ec9db5566e3 100644 --- a/spec/requests/api/terraform/state_spec.rb +++ b/spec/requests/api/terraform/state_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe API::Terraform::State do + include HttpBasicAuthHelpers + let_it_be(:project) { create(:project) } let_it_be(:developer) { create(:user, developer_projects: [project]) } let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) } @@ -10,7 +12,7 @@ describe API::Terraform::State do let!(:state) { create(:terraform_state, :with_file, project: project) } let(:current_user) { maintainer } - let(:auth_header) { basic_auth_header(current_user) } + let(:auth_header) { user_basic_auth_header(current_user) } let(:project_id) { project.id } let(:state_name) { state.name } let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}" } @@ -23,7 +25,7 @@ describe API::Terraform::State do subject(:request) { get api(state_path), headers: auth_header } context 'without authentication' do - let(:auth_header) { basic_auth_header('failing_token') } + let(:auth_header) { basic_auth_header('bad', 'token') } it 'returns 401 if user is not authenticated' do request @@ -32,34 +34,71 @@ describe API::Terraform::State do end end - context 'with maintainer permissions' do - let(:current_user) { maintainer } + context 'personal acceess token authentication' do + context 'with maintainer permissions' do + let(:current_user) { maintainer } - it 'returns terraform state belonging to a project of given state name' do - request + it 'returns terraform state belonging to a project of given state name' do + request - expect(response).to have_gitlab_http_status(:ok) - expect(response.body).to eq(state.file.read) + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to eq(state.file.read) + end + + context 'for a project that does not exist' do + let(:project_id) { '0000' } + + it 'returns not found' do + request + + expect(response).to have_gitlab_http_status(:not_found) + end + end end - context 'for a project that does not exist' do - let(:project_id) { '0000' } + context 'with developer permissions' do + let(:current_user) { developer } - it 'returns not found' do + it 'returns forbidden if the user cannot access the state' do request - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to have_gitlab_http_status(:forbidden) end end end - context 'with developer permissions' do - let(:current_user) { developer } + context 'job token authentication' do + let(:auth_header) { job_basic_auth_header(job) } - it 'returns forbidden if the user cannot access the state' do - request + context 'with maintainer permissions' do + let(:job) { create(:ci_build, project: project, user: maintainer) } - expect(response).to have_gitlab_http_status(:forbidden) + it 'returns terraform state belonging to a project of given state name' do + request + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to eq(state.file.read) + end + + context 'for a project that does not exist' do + let(:project_id) { '0000' } + + it 'returns not found' do + request + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'with developer permissions' do + let(:job) { create(:ci_build, project: project, user: developer) } + + it 'returns forbidden if the user cannot access the state' do + request + + expect(response).to have_gitlab_http_status(:forbidden) + end end end end diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb index ece145dcc4b..4e3d9d5f108 100644 --- a/spec/services/releases/create_service_spec.rb +++ b/spec/services/releases/create_service_spec.rb @@ -188,6 +188,7 @@ describe Releases::CreateService do end context 'Evidence collection' do + let(:sha) { project.repository.commit('master').sha } let(:params) do { name: 'New release', @@ -229,6 +230,75 @@ describe Releases::CreateService do end end + shared_examples 'uses the right pipeline for evidence' do + it 'creates evidence without pipeline if it does not exist', :sidekiq_inline do + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: nil) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { subject }.to change(Releases::Evidence, :count).by(1) + end + + it 'uses the last pipeline for evidence', :sidekiq_inline do + create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline + pipeline = create(:ci_empty_pipeline, sha: sha, project: project) + + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { subject }.to change(Releases::Evidence, :count).by(1) + end + + context 'when old evidence_pipeline is passed to service' do + let!(:old_pipeline) { create(:ci_empty_pipeline, sha: sha, project: project) } + let!(:new_pipeline) { create(:ci_empty_pipeline, sha: sha, project: project) } + let(:params) do + super().merge( + evidence_pipeline: old_pipeline + ) + end + + it 'uses the old pipeline for evidence', :sidekiq_inline do + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: old_pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { subject }.to change(Releases::Evidence, :count).by(1) + end + end + + it 'pipeline is still being used for evidence if new pipeline is being created for tag', :sidekiq_inline do + pipeline = create(:ci_empty_pipeline, sha: sha, project: project) + + expect(project.repository).to receive(:add_tag).and_wrap_original do |m, *args| + create(:ci_empty_pipeline, sha: sha, project: project) + m.call(*args) + end + + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { subject }.to change(Releases::Evidence, :count).by(1) + end + + it 'uses the last pipeline for evidence when tag is already created', :sidekiq_inline do + Tags::CreateService.new(project, user).execute('v0.1', 'master', nil) + + expect(project.repository.find_tag('v0.1')).to be_present + + create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline + pipeline = create(:ci_empty_pipeline, sha: sha, project: project) + + expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { subject }.to change(Releases::Evidence, :count).by(1) + end + end + context 'immediate release' do let(:released_at) { nil } @@ -257,6 +327,8 @@ describe Releases::CreateService do expect(last_release.upcoming_release?).to be_falsy end + + include_examples 'uses the right pipeline for evidence' end context 'upcoming release' do @@ -287,6 +359,8 @@ describe Releases::CreateService do expect(last_release.upcoming_release?).to be_truthy end + + include_examples 'uses the right pipeline for evidence' end end end diff --git a/spec/support/helpers/api_helpers.rb b/spec/support/helpers/api_helpers.rb index eb9594a4fb6..b1e6078c4f2 100644 --- a/spec/support/helpers/api_helpers.rb +++ b/spec/support/helpers/api_helpers.rb @@ -40,17 +40,6 @@ module ApiHelpers end end - def basic_auth_header(user = nil) - return { 'HTTP_AUTHORIZATION' => user } unless user.respond_to?(:username) - - { - 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials( - user.username, - create(:personal_access_token, user: user).token - ) - } - end - def expect_empty_array_response expect_successful_response_with_paginated_array expect(json_response.length).to eq(0) diff --git a/spec/support/helpers/http_basic_auth_helpers.rb b/spec/support/helpers/http_basic_auth_helpers.rb new file mode 100644 index 00000000000..c0b24b3dfa4 --- /dev/null +++ b/spec/support/helpers/http_basic_auth_helpers.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module HttpBasicAuthHelpers + def user_basic_auth_header(user) + access_token = create(:personal_access_token, user: user) + + basic_auth_header(user.username, access_token.token) + end + + def job_basic_auth_header(job) + basic_auth_header(Ci::Build::CI_REGISTRY_USER, job.token) + end + + def client_basic_auth_header(client) + basic_auth_header(client.uid, client.secret) + end + + def basic_auth_header(username, password) + { + 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials( + username, + password + ) + } + end +end diff --git a/spec/workers/create_evidence_worker_spec.rb b/spec/workers/create_evidence_worker_spec.rb index 8cba0777793..b8c622f7d1d 100644 --- a/spec/workers/create_evidence_worker_spec.rb +++ b/spec/workers/create_evidence_worker_spec.rb @@ -3,13 +3,24 @@ require 'spec_helper' describe CreateEvidenceWorker do - let(:release) { create(:release) } + let(:project) { create(:project, :repository) } + let(:release) { create(:release, project: project) } + let(:pipeline) { create(:ci_empty_pipeline, sha: release.sha, project: project) } + # support old scheduled workers without pipeline it 'creates a new Evidence record' do - expect_next_instance_of(::Releases::CreateEvidenceService, release) do |service| + expect_next_instance_of(::Releases::CreateEvidenceService, release, pipeline: nil) do |service| expect(service).to receive(:execute).and_call_original end expect { described_class.new.perform(release.id) }.to change(Releases::Evidence, :count).by(1) end + + it 'creates a new Evidence record with pipeline' do + expect_next_instance_of(::Releases::CreateEvidenceService, release, pipeline: pipeline) do |service| + expect(service).to receive(:execute).and_call_original + end + + expect { described_class.new.perform(release.id, pipeline.id) }.to change(Releases::Evidence, :count).by(1) + end end |