Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/features/projects/files/user_find_file_spec.rb39
-rw-r--r--spec/frontend/pages/projects/find_file/ref_switcher/ref_switcher_utils_spec.js39
-rw-r--r--spec/graphql/types/ci/runner_type_spec.rb1
-rw-r--r--spec/lib/gitlab/metrics/rails_slis_spec.rb10
-rw-r--r--spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb23
-rw-r--r--spec/models/ci/build_spec.rb290
-rw-r--r--spec/models/ci/runner_spec.rb18
-rw-r--r--spec/policies/ci/runner_policy_spec.rb23
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb103
-rw-r--r--spec/scripts/failed_tests_spec.rb200
-rw-r--r--spec/scripts/pipeline_test_report_builder_spec.rb191
-rw-r--r--spec/tooling/lib/tooling/mappings/base_spec.rb44
-rw-r--r--spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb169
-rw-r--r--spec/tooling/lib/tooling/mappings/view_to_js_mappings_spec.rb (renamed from spec/tooling/lib/tooling/view_to_js_mappings_spec.rb)49
15 files changed, 778 insertions, 425 deletions
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 67186282c95..f113ca2425f 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -466,7 +466,9 @@ FactoryBot.define do
trait :with_jira_integration do
has_external_issue_tracker { true }
- jira_integration
+ after :create do |project|
+ create(:jira_integration, project: project)
+ end
end
trait :with_prometheus_integration do
diff --git a/spec/features/projects/files/user_find_file_spec.rb b/spec/features/projects/files/user_find_file_spec.rb
index 1b53189da83..0a3b8c19cc4 100644
--- a/spec/features/projects/files/user_find_file_spec.rb
+++ b/spec/features/projects/files/user_find_file_spec.rb
@@ -21,6 +21,10 @@ RSpec.describe 'User find project file', feature_category: :projects do
fill_in 'file_find', with: text
end
+ def ref_selector_dropdown
+ find('.gl-dropdown-toggle > .gl-dropdown-button-text')
+ end
+
it 'navigates to find file by shortcut', :js do
find('body').native.send_key('t')
@@ -65,4 +69,39 @@ RSpec.describe 'User find project file', feature_category: :projects do
expect(page).not_to have_content('CHANGELOG')
expect(page).not_to have_content('VERSION')
end
+
+ context 'when refs are switched', :js do
+ before do
+ click_link 'Find file'
+ end
+
+ specify 'the ref switcher lists all the branches and tags' do
+ ref = 'add-ipython-files'
+ expect(ref_selector_dropdown).not_to have_text(ref)
+
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ expect(page).to have_selector('li', text: ref)
+ expect(page).to have_selector('li', text: 'v1.0.0')
+ end
+ end
+
+ specify 'the search result changes when refs switched' do
+ ref = 'add-ipython-files'
+ expect(ref_selector_dropdown).not_to have_text(ref)
+
+ find('.ref-selector button').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in _('Switch branch/tag'), with: ref
+ wait_for_requests
+
+ find('.gl-dropdown-item', text: ref).click
+ end
+ expect(ref_selector_dropdown).to have_text(ref)
+ end
+ end
end
diff --git a/spec/frontend/pages/projects/find_file/ref_switcher/ref_switcher_utils_spec.js b/spec/frontend/pages/projects/find_file/ref_switcher/ref_switcher_utils_spec.js
new file mode 100644
index 00000000000..ef2e5d779d8
--- /dev/null
+++ b/spec/frontend/pages/projects/find_file/ref_switcher/ref_switcher_utils_spec.js
@@ -0,0 +1,39 @@
+import { generateRefDestinationPath } from '~/pages/projects/find_file/ref_switcher/ref_switcher_utils';
+import setWindowLocation from 'helpers/set_window_location_helper';
+
+const projectRootPath = 'root/Project1';
+const selectedRef = 'feature/test';
+
+describe('generateRefDestinationPath', () => {
+ it.each`
+ currentPath | result
+ ${`${projectRootPath}/-/find_file/flightjs/Flight`} | ${`http://test.host/${projectRootPath}/-/find_file/${selectedRef}`}
+ ${`${projectRootPath}/-/find_file/test/test1?test=something`} | ${`http://test.host/${projectRootPath}/-/find_file/${selectedRef}?test=something`}
+ ${`${projectRootPath}/-/find_file/simpletest?test=something&test=it`} | ${`http://test.host/${projectRootPath}/-/find_file/${selectedRef}?test=something&test=it`}
+ ${`${projectRootPath}/-/find_file/some_random_char?test=something&test[]=it&test[]=is`} | ${`http://test.host/${projectRootPath}/-/find_file/${selectedRef}?test=something&test[]=it&test[]=is`}
+ `('generates the correct destination path for $currentPath', ({ currentPath, result }) => {
+ setWindowLocation(currentPath);
+ expect(generateRefDestinationPath(selectedRef, '/-/find_file')).toBe(result);
+ });
+
+ it("returns original url if it's missing selectedRef param", () => {
+ setWindowLocation(`${projectRootPath}/-/find_file/flightjs/Flight`);
+ expect(generateRefDestinationPath(undefined, '/-/find_file')).toBe(
+ `http://test.host/${projectRootPath}/-/find_file/flightjs/Flight`,
+ );
+ });
+
+ it("returns original url if it's missing namespace param", () => {
+ setWindowLocation(`${projectRootPath}/-/find_file/flightjs/Flight`);
+ expect(generateRefDestinationPath(selectedRef, undefined)).toBe(
+ `http://test.host/${projectRootPath}/-/find_file/flightjs/Flight`,
+ );
+ });
+
+ it("returns original url if it's missing namespace and selectedRef param", () => {
+ setWindowLocation(`${projectRootPath}/-/find_file/flightjs/Flight`);
+ expect(generateRefDestinationPath(undefined, undefined)).toBe(
+ `http://test.host/${projectRootPath}/-/find_file/flightjs/Flight`,
+ );
+ });
+});
diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb
index 2296d1bea30..a2d107ae295 100644
--- a/spec/graphql/types/ci/runner_type_spec.rb
+++ b/spec/graphql/types/ci/runner_type_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do
version short_sha revision locked run_untagged ip_address runner_type tag_list
project_count job_count admin_url edit_admin_url user_permissions executor_name architecture_name platform_name
maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project job_execution_status
+ ephemeral_authentication_token
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/lib/gitlab/metrics/rails_slis_spec.rb b/spec/lib/gitlab/metrics/rails_slis_spec.rb
index 9da102fb8b8..af4df00b7da 100644
--- a/spec/lib/gitlab/metrics/rails_slis_spec.rb
+++ b/spec/lib/gitlab/metrics/rails_slis_spec.rb
@@ -46,16 +46,6 @@ RSpec.describe Gitlab::Metrics::RailsSlis do
described_class.initialize_request_slis!
end
-
- it "initializes the SLI for all possible endpoints if they weren't given error rate feature flag is disabled", :aggregate_failures do
- stub_feature_flags(gitlab_metrics_error_rate_sli: false)
-
- expect(Gitlab::Metrics::Sli::Apdex).to receive(:initialize_sli).with(:rails_request, array_including(*possible_labels)).and_call_original
- expect(Gitlab::Metrics::Sli::Apdex).to receive(:initialize_sli).with(:graphql_query, array_including(*possible_graphql_labels)).and_call_original
- expect(Gitlab::Metrics::Sli::ErrorRate).not_to receive(:initialize_sli)
-
- described_class.initialize_request_slis!
- end
end
describe '.request_apdex' do
diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
index d6644bc12d2..97b70b5a7fc 100644
--- a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
@@ -53,18 +53,6 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware, :aggregate_failures, fea
subject.call(env)
end
- it 'does not track error rate when feature flag is disabled' do
- stub_feature_flags(gitlab_metrics_error_rate_sli: false)
-
- expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'unknown')
- expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ method: 'get' }, a_positive_execution_time)
- expect(Gitlab::Metrics::RailsSlis.request_apdex).to receive(:increment)
- .with(labels: { feature_category: 'unknown', endpoint_id: 'unknown', request_urgency: :default }, success: true)
- expect(Gitlab::Metrics::RailsSlis.request_error_rate).not_to receive(:increment)
-
- subject.call(env)
- end
-
context 'request is a health check endpoint' do
['/-/liveness', '/-/liveness/', '/-/%6D%65%74%72%69%63%73'].each do |path|
context "when path is #{path}" do
@@ -116,17 +104,6 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware, :aggregate_failures, fea
subject.call(env)
end
-
- it 'does not track error rate when feature flag is disabled' do
- stub_feature_flags(gitlab_metrics_error_rate_sli: false)
-
- expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '500', feature_category: 'unknown')
- expect(described_class).not_to receive(:http_request_duration_seconds)
- expect(Gitlab::Metrics::RailsSlis).not_to receive(:request_apdex)
- expect(Gitlab::Metrics::RailsSlis.request_error_rate).not_to receive(:increment)
-
- subject.call(env)
- end
end
context '@app.call throws exception' do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index e941fccada1..a3982263de8 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
it 'executes hooks' do
expect_next(described_class).to receive(:execute_hooks)
- create(:ci_build)
+ create(:ci_build, pipeline: pipeline)
end
end
end
@@ -108,19 +108,19 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { described_class.ref_protected }
context 'when protected is true' do
- let!(:job) { create(:ci_build, :protected) }
+ let!(:job) { create(:ci_build, :protected, pipeline: pipeline) }
it { is_expected.to include(job) }
end
context 'when protected is false' do
- let!(:job) { create(:ci_build) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
it { is_expected.not_to include(job) }
end
context 'when protected is nil' do
- let!(:job) { create(:ci_build) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
before do
job.update_attribute(:protected, nil)
@@ -134,7 +134,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { described_class.with_downloadable_artifacts }
context 'when job does not have a downloadable artifact' do
- let!(:job) { create(:ci_build) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
it 'does not return the job' do
is_expected.not_to include(job)
@@ -144,7 +144,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
::Ci::JobArtifact::DOWNLOADABLE_TYPES.each do |type|
context "when job has a #{type} artifact" do
it 'returns the job' do
- job = create(:ci_build)
+ job = create(:ci_build, pipeline: pipeline)
create(
:ci_job_artifact,
file_format: ::Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS[type.to_sym],
@@ -158,7 +158,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when job has a non-downloadable artifact' do
- let!(:job) { create(:ci_build, :trace_artifact) }
+ let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
it 'does not return the job' do
is_expected.not_to include(job)
@@ -170,7 +170,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { described_class.with_erasable_artifacts }
context 'when job does not have any artifacts' do
- let!(:job) { create(:ci_build) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
it 'does not return the job' do
is_expected.not_to include(job)
@@ -180,7 +180,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
::Ci::JobArtifact.erasable_file_types.each do |type|
context "when job has a #{type} artifact" do
it 'returns the job' do
- job = create(:ci_build)
+ job = create(:ci_build, pipeline: pipeline)
create(
:ci_job_artifact,
file_format: ::Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS[type.to_sym],
@@ -194,7 +194,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when job has a non-erasable artifact' do
- let!(:job) { create(:ci_build, :trace_artifact) }
+ let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
it 'does not return the job' do
is_expected.not_to include(job)
@@ -206,7 +206,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { described_class.with_live_trace }
context 'when build has live trace' do
- let!(:build) { create(:ci_build, :success, :trace_live) }
+ let!(:build) { create(:ci_build, :success, :trace_live, pipeline: pipeline) }
it 'selects the build' do
is_expected.to eq([build])
@@ -214,7 +214,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build does not have live trace' do
- let!(:build) { create(:ci_build, :success, :trace_artifact) }
+ let!(:build) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) }
it 'does not select the build' do
is_expected.to be_empty
@@ -226,7 +226,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { described_class.with_stale_live_trace }
context 'when build has a stale live trace' do
- let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 1.day.ago) }
+ let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 1.day.ago, pipeline: pipeline) }
it 'selects the build' do
is_expected.to eq([build])
@@ -234,7 +234,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build does not have a stale live trace' do
- let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 1.hour.ago) }
+ let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 1.hour.ago, pipeline: pipeline) }
it 'does not select the build' do
is_expected.to be_empty
@@ -245,9 +245,9 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '.license_management_jobs' do
subject { described_class.license_management_jobs }
- let!(:management_build) { create(:ci_build, :success, name: :license_management) }
- let!(:scanning_build) { create(:ci_build, :success, name: :license_scanning) }
- let!(:another_build) { create(:ci_build, :success, name: :another_type) }
+ let!(:management_build) { create(:ci_build, :success, name: :license_management, pipeline: pipeline) }
+ let!(:scanning_build) { create(:ci_build, :success, name: :license_scanning, pipeline: pipeline) }
+ let!(:another_build) { create(:ci_build, :success, name: :another_type, pipeline: pipeline) }
it 'returns license_scanning jobs' do
is_expected.to include(scanning_build)
@@ -268,7 +268,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
let(:date) { 1.hour.ago }
context 'when build has finished one day ago' do
- let!(:build) { create(:ci_build, :success, finished_at: 1.day.ago) }
+ let!(:build) { create(:ci_build, :success, finished_at: 1.day.ago, pipeline: pipeline) }
it 'selects the build' do
is_expected.to eq([build])
@@ -276,7 +276,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build has finished 30 minutes ago' do
- let!(:build) { create(:ci_build, :success, finished_at: 30.minutes.ago) }
+ let!(:build) { create(:ci_build, :success, finished_at: 30.minutes.ago, pipeline: pipeline) }
it 'returns an empty array' do
is_expected.to be_empty
@@ -284,7 +284,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is still running' do
- let!(:build) { create(:ci_build, :running) }
+ let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
it 'returns an empty array' do
is_expected.to be_empty
@@ -295,9 +295,9 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '.with_exposed_artifacts' do
subject { described_class.with_exposed_artifacts }
- let!(:job1) { create(:ci_build) }
- let!(:job2) { create(:ci_build, options: options) }
- let!(:job3) { create(:ci_build) }
+ let!(:job1) { create(:ci_build, pipeline: pipeline) }
+ let!(:job2) { create(:ci_build, options: options, pipeline: pipeline) }
+ let!(:job3) { create(:ci_build, pipeline: pipeline) }
context 'when some jobs have exposed artifacs and some not' do
let(:options) { { artifacts: { expose_as: 'test', paths: ['test'] } } }
@@ -337,7 +337,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when there are multiple builds containing artifacts' do
before do
- create_list(:ci_build, 5, :success, :test_reports)
+ create_list(:ci_build, 5, :success, :test_reports, pipeline: pipeline)
end
it 'does not execute a query for selecting job artifact one by one' do
@@ -353,8 +353,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '.with_needs' do
- let!(:build) { create(:ci_build) }
- let!(:build_b) { create(:ci_build) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:build_b) { create(:ci_build, pipeline: pipeline) }
let!(:build_need_a) { create(:ci_build_need, build: build) }
let!(:build_need_b) { create(:ci_build_need, build: build_b) }
@@ -393,7 +393,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#stick_build_if_status_changed' do
it 'sticks the build if the status changed' do
- job = create(:ci_build, :pending)
+ job = create(:ci_build, :pending, pipeline: pipeline)
expect(described_class.sticking).to receive(:stick)
.with(:build, job.id)
@@ -403,7 +403,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#enqueue' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
before do
allow(build).to receive(:any_unmet_prerequisites?).and_return(has_prerequisites)
@@ -480,7 +480,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#enqueue_preparing' do
- let(:build) { create(:ci_build, :preparing) }
+ let(:build) { create(:ci_build, :preparing, pipeline: pipeline) }
before do
allow(build).to receive(:any_unmet_prerequisites?).and_return(has_unmet_prerequisites)
@@ -535,7 +535,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#run' do
context 'when build has been just created' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
it 'creates queuing entry and then removes it' do
build.enqueue!
@@ -547,7 +547,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build status transition fails' do
- let(:build) { create(:ci_build, :pending) }
+ let(:build) { create(:ci_build, :pending, pipeline: pipeline) }
before do
create(:ci_pending_build, build: build, project: build.project)
@@ -563,7 +563,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build has been picked by a shared runner' do
- let(:build) { create(:ci_build, :pending) }
+ let(:build) { create(:ci_build, :pending, pipeline: pipeline) }
it 'creates runtime metadata entry' do
build.runner = create(:ci_runner, :instance_type)
@@ -577,7 +577,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#drop' do
context 'when has a runtime tracking entry' do
- let(:build) { create(:ci_build, :pending) }
+ let(:build) { create(:ci_build, :pending, pipeline: pipeline) }
it 'removes runtime tracking entry' do
build.runner = create(:ci_runner, :instance_type)
@@ -614,10 +614,10 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#outdated_deployment?' do
subject { build.outdated_deployment? }
- let(:build) { create(:ci_build, :created, :with_deployment, project: project, environment: 'production') }
+ let(:build) { create(:ci_build, :created, :with_deployment, pipeline: pipeline, environment: 'production') }
context 'when build has no environment' do
- let(:build) { create(:ci_build, :created, project: project, environment: nil) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline, environment: nil) }
it { expect(subject).to be_falsey }
end
@@ -647,7 +647,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is older than the latest deployment but succeeded once' do
- let(:build) { create(:ci_build, :success, :with_deployment, project: project, environment: 'production') }
+ let(:build) { create(:ci_build, :success, :with_deployment, pipeline: pipeline, environment: 'production') }
before do
allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
@@ -663,13 +663,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.schedulable? }
context 'when build is schedulable' do
- let(:build) { create(:ci_build, :created, :schedulable, project: project) }
+ let(:build) { create(:ci_build, :created, :schedulable, pipeline: pipeline) }
it { expect(subject).to be_truthy }
end
context 'when build is not schedulable' do
- let(:build) { create(:ci_build, :created, project: project) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
it { expect(subject).to be_falsy }
end
@@ -682,7 +682,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
project.add_developer(user)
end
- let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) }
+ let(:build) { create(:ci_build, :created, :schedulable, user: user, pipeline: pipeline) }
it 'transits to scheduled' do
allow(Ci::BuildScheduleWorker).to receive(:perform_at)
@@ -743,7 +743,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#options_scheduled_at' do
subject { build.options_scheduled_at }
- let(:build) { build_stubbed(:ci_build, options: option) }
+ let(:build) { build_stubbed(:ci_build, options: option, pipeline: pipeline) }
context 'when start_in is 1 day' do
let(:option) { { start_in: '1 day' } }
@@ -881,18 +881,18 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when new artifacts are used' do
context 'artifacts archive does not exist' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
context 'artifacts archive exists' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
context 'is expired' do
- let(:build) { create(:ci_build, :artifacts, :expired) }
+ let(:build) { create(:ci_build, :artifacts, :expired, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
@@ -909,13 +909,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'artifacts archive does not exist' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
context 'artifacts archive exists' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
@@ -927,13 +927,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'artifacts archive does not exist' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
context 'artifacts archive exists' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
@@ -941,7 +941,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#available_artifacts?' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
subject { build.available_artifacts? }
@@ -1000,7 +1000,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.browsable_artifacts? }
context 'artifacts metadata does exists' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
@@ -1010,13 +1010,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.artifacts_public? }
context 'artifacts with defaults' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
context 'non public artifacts' do
- let(:build) { create(:ci_build, :artifacts, :non_public_artifacts) }
+ let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
it { is_expected.to be_falsey }
end
@@ -1050,7 +1050,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'artifacts archive is a zip file and metadata exists' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
@@ -1277,12 +1277,12 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#has_live_trace?' do
subject { build.has_live_trace? }
- let(:build) { create(:ci_build, :trace_live) }
+ let(:build) { create(:ci_build, :trace_live, pipeline: pipeline) }
it { is_expected.to be_truthy }
context 'when build does not have live trace' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
@@ -1291,12 +1291,12 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#has_archived_trace?' do
subject { build.has_archived_trace? }
- let(:build) { create(:ci_build, :trace_artifact) }
+ let(:build) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
it { is_expected.to be_truthy }
context 'when build does not have archived trace' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsy }
end
@@ -1306,7 +1306,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.has_job_artifacts? }
context 'when build has a job artifact' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
@@ -1316,13 +1316,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.has_test_reports? }
context 'when build has a test report' do
- let(:build) { create(:ci_build, :test_reports) }
+ let(:build) { create(:ci_build, :test_reports, pipeline: pipeline) }
it { is_expected.to be_truthy }
end
context 'when build does not have a test report' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_falsey }
end
@@ -1395,7 +1395,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
with_them do
- let(:build) { create(:ci_build, trait, project: project, pipeline: pipeline) }
+ let(:build) { create(:ci_build, trait, pipeline: pipeline) }
let(:event) { state }
context "when transitioning to #{params[:state]}" do
@@ -1419,7 +1419,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe 'state transition as a deployable' do
subject { build.send(event) }
- let!(:build) { create(:ci_build, :with_deployment, :start_review_app, project: project, pipeline: pipeline) }
+ let!(:build) { create(:ci_build, :with_deployment, :start_review_app, pipeline: pipeline) }
let(:deployment) { build.deployment }
let(:environment) { deployment.environment }
@@ -1583,7 +1583,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.on_stop }
context 'when a job has a specification that it can be stopped from the other job' do
- let(:build) { create(:ci_build, :start_review_app) }
+ let(:build) { create(:ci_build, :start_review_app, pipeline: pipeline) }
it 'returns the other job name' do
is_expected.to eq('stop_review_app')
@@ -1591,7 +1591,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when a job does not have environment information' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it 'returns nil' do
is_expected.to be_nil
@@ -1666,7 +1666,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
let(:build) do
create(:ci_build,
ref: 'master',
- environment: 'review/$CI_COMMIT_REF_NAME')
+ environment: 'review/$CI_COMMIT_REF_NAME',
+ pipeline: pipeline)
end
it { is_expected.to eq('review/master') }
@@ -1676,7 +1677,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
let(:build) do
create(:ci_build,
yaml_variables: [{ key: :APP_HOST, value: 'host' }],
- environment: 'review/$APP_HOST')
+ environment: 'review/$APP_HOST',
+ pipeline: pipeline)
end
it 'returns an expanded environment name with a list of variables' do
@@ -1698,7 +1700,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when using persisted variables' do
let(:build) do
- create(:ci_build, environment: 'review/x$CI_BUILD_ID')
+ create(:ci_build, environment: 'review/x$CI_BUILD_ID', pipeline: pipeline)
end
it { is_expected.to eq('review/x') }
@@ -1715,7 +1717,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
create(:ci_build,
ref: 'master',
yaml_variables: yaml_variables,
- environment: 'review/$ENVIRONMENT_NAME')
+ environment: 'review/$ENVIRONMENT_NAME',
+ pipeline: pipeline)
end
it { is_expected.to eq('review/master') }
@@ -1723,7 +1726,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#expanded_kubernetes_namespace' do
- let(:build) { create(:ci_build, environment: environment, options: options) }
+ let(:build) { create(:ci_build, environment: environment, options: options, pipeline: pipeline) }
subject { build.expanded_kubernetes_namespace }
@@ -1859,7 +1862,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'build is not erasable' do
- let!(:build) { create(:ci_build) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
describe '#erasable?' do
subject { build.erasable? }
@@ -1870,7 +1873,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'build is erasable' do
context 'new artifacts' do
- let!(:build) { create(:ci_build, :test_reports, :trace_artifact, :success, :artifacts) }
+ let!(:build) { create(:ci_build, :test_reports, :trace_artifact, :success, :artifacts, pipeline: pipeline) }
describe '#erasable?' do
subject { build.erasable? }
@@ -1879,7 +1882,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#erased?' do
- let!(:build) { create(:ci_build, :trace_artifact, :success, :artifacts) }
+ let!(:build) { create(:ci_build, :trace_artifact, :success, :artifacts, pipeline: pipeline) }
subject { build.erased? }
@@ -1973,13 +1976,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is created' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
it { is_expected.to be_cancelable }
end
context 'when build is waiting for resource' do
- let(:build) { create(:ci_build, :waiting_for_resource) }
+ let(:build) { create(:ci_build, :waiting_for_resource, pipeline: pipeline) }
it { is_expected.to be_cancelable }
end
@@ -2042,7 +2045,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#tag_list' do
- let_it_be(:build) { create(:ci_build, tag_list: ['tag']) }
+ let_it_be(:build) { create(:ci_build, tag_list: ['tag'], pipeline: pipeline) }
context 'when tags are preloaded' do
it 'does not trigger queries' do
@@ -2059,7 +2062,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#save_tags' do
- let(:build) { create(:ci_build, tag_list: ['tag']) }
+ let(:build) { create(:ci_build, tag_list: ['tag'], pipeline: pipeline) }
it 'saves tags' do
build.save!
@@ -2088,13 +2091,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#has_tags?' do
context 'when build has tags' do
- subject { create(:ci_build, tag_list: ['tag']) }
+ subject { create(:ci_build, tag_list: ['tag'], pipeline: pipeline) }
it { is_expected.to have_tags }
end
context 'when build does not have tags' do
- subject { create(:ci_build, tag_list: []) }
+ subject { create(:ci_build, tag_list: [], pipeline: pipeline) }
it { is_expected.not_to have_tags }
end
@@ -2149,9 +2152,9 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '.keep_artifacts!' do
- let!(:build) { create(:ci_build, artifacts_expire_at: Time.current + 7.days) }
+ let!(:build) { create(:ci_build, artifacts_expire_at: Time.current + 7.days, pipeline: pipeline) }
let!(:builds_for_update) do
- Ci::Build.where(id: create_list(:ci_build, 3, artifacts_expire_at: Time.current + 7.days).map(&:id))
+ Ci::Build.where(id: create_list(:ci_build, 3, artifacts_expire_at: Time.current + 7.days, pipeline: pipeline).map(&:id))
end
it 'resets expire_at' do
@@ -2193,7 +2196,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#keep_artifacts!' do
- let(:build) { create(:ci_build, artifacts_expire_at: Time.current + 7.days) }
+ let(:build) { create(:ci_build, artifacts_expire_at: Time.current + 7.days, pipeline: pipeline) }
subject { build.keep_artifacts! }
@@ -2215,7 +2218,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#auto_retry_expected?' do
- subject { create(:ci_build, :failed) }
+ subject { create(:ci_build, :failed, pipeline: pipeline) }
context 'when build is failed and auto retry is configured' do
before do
@@ -2237,7 +2240,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#artifacts_file_for_type' do
- let(:build) { create(:ci_build, :artifacts) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
let(:file_type) { :archive }
subject { build.artifacts_file_for_type(file_type) }
@@ -2250,6 +2253,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#merge_request' do
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+
subject { pipeline.builds.take.merge_request }
context 'on a branch pipeline' do
@@ -2294,19 +2299,23 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'on a detached merged request pipeline' do
- let(:pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline, :with_job) }
+ let(:pipeline) do
+ create(:ci_pipeline, :detached_merge_request_pipeline, :with_job, merge_request: merge_request)
+ end
it { is_expected.to eq(pipeline.merge_request) }
end
context 'on a legacy detached merged request pipeline' do
- let(:pipeline) { create(:ci_pipeline, :legacy_detached_merge_request_pipeline, :with_job) }
+ let(:pipeline) do
+ create(:ci_pipeline, :legacy_detached_merge_request_pipeline, :with_job, merge_request: merge_request)
+ end
it { is_expected.to eq(pipeline.merge_request) }
end
context 'on a pipeline for merged results' do
- let(:pipeline) { create(:ci_pipeline, :merged_result_pipeline, :with_job) }
+ let(:pipeline) { create(:ci_pipeline, :merged_result_pipeline, :with_job, merge_request: merge_request) }
it { is_expected.to eq(pipeline.merge_request) }
end
@@ -2342,7 +2351,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when options include artifacts:expose_as' do
- let(:build) { create(:ci_build, options: { artifacts: { expose_as: 'test' } }) }
+ let(:build) { create(:ci_build, options: { artifacts: { expose_as: 'test' } }, pipeline: pipeline) }
it 'saves the presence of expose_as into build metadata' do
expect(build.metadata).to have_exposed_artifacts
@@ -2468,56 +2477,56 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#playable?' do
context 'when build is a manual action' do
context 'when build has been skipped' do
- subject { build_stubbed(:ci_build, :manual, status: :skipped) }
+ subject { build_stubbed(:ci_build, :manual, status: :skipped, pipeline: pipeline) }
it { is_expected.not_to be_playable }
end
context 'when build has been canceled' do
- subject { build_stubbed(:ci_build, :manual, status: :canceled) }
+ subject { build_stubbed(:ci_build, :manual, status: :canceled, pipeline: pipeline) }
it { is_expected.to be_playable }
end
context 'when build is successful' do
- subject { build_stubbed(:ci_build, :manual, status: :success) }
+ subject { build_stubbed(:ci_build, :manual, status: :success, pipeline: pipeline) }
it { is_expected.to be_playable }
end
context 'when build has failed' do
- subject { build_stubbed(:ci_build, :manual, status: :failed) }
+ subject { build_stubbed(:ci_build, :manual, status: :failed, pipeline: pipeline) }
it { is_expected.to be_playable }
end
context 'when build is a manual untriggered action' do
- subject { build_stubbed(:ci_build, :manual, status: :manual) }
+ subject { build_stubbed(:ci_build, :manual, status: :manual, pipeline: pipeline) }
it { is_expected.to be_playable }
end
context 'when build is a manual and degenerated' do
- subject { build_stubbed(:ci_build, :manual, :degenerated, status: :manual) }
+ subject { build_stubbed(:ci_build, :manual, :degenerated, status: :manual, pipeline: pipeline) }
it { is_expected.not_to be_playable }
end
end
context 'when build is scheduled' do
- subject { build_stubbed(:ci_build, :scheduled) }
+ subject { build_stubbed(:ci_build, :scheduled, pipeline: pipeline) }
it { is_expected.to be_playable }
end
context 'when build is not a manual action' do
- subject { build_stubbed(:ci_build, :success) }
+ subject { build_stubbed(:ci_build, :success, pipeline: pipeline) }
it { is_expected.not_to be_playable }
end
context 'when build is waiting for deployment approval' do
- subject { build_stubbed(:ci_build, :manual, environment: 'production') }
+ subject { build_stubbed(:ci_build, :manual, environment: 'production', pipeline: pipeline) }
before do
create(:deployment, :blocked, deployable: subject)
@@ -3767,7 +3776,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#any_unmet_prerequisites?' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
subject { build.any_unmet_prerequisites? }
@@ -3854,7 +3863,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'state transition: any => [:preparing]' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
before do
allow(build).to receive(:prerequisites).and_return([double])
@@ -3868,7 +3877,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'when the build is waiting for deployment approval' do
- let(:build) { create(:ci_build, :manual, environment: 'production') }
+ let(:build) { create(:ci_build, :manual, environment: 'production', pipeline: pipeline) }
before do
create(:deployment, :blocked, deployable: build)
@@ -3880,7 +3889,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'state transition: any => [:pending]' do
- let(:build) { create(:ci_build, :created) }
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
it 'queues BuildQueueWorker' do
expect(BuildQueueWorker).to receive(:perform_async).with(build.id)
@@ -3900,8 +3909,10 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'state transition: pending: :running' do
- let(:runner) { create(:ci_runner) }
- let(:job) { create(:ci_build, :pending, runner: runner) }
+ let_it_be_with_reload(:runner) { create(:ci_runner) }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:job) { create(:ci_build, :pending, runner: runner, pipeline: pipeline) }
before do
job.project.update_attribute(:build_timeout, 1800)
@@ -4005,7 +4016,9 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when artifacts of depended job has been erased' do
- let!(:pre_stage_job) { create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago) }
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago)
+ end
it { expect(job).not_to have_valid_build_dependencies }
end
@@ -4062,7 +4075,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is configured to be retried' do
- subject { create(:ci_build, :running, options: { script: ["ls -al"], retry: 3 }, project: project, user: user) }
+ subject { create(:ci_build, :running, options: { script: ["ls -al"], retry: 3 }, pipeline: pipeline, user: user) }
it 'retries build and assigns the same user to it' do
expect_next_instance_of(::Ci::RetryJobService) do |service|
@@ -4111,7 +4124,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is not configured to be retried' do
- subject { create(:ci_build, :running, project: project, user: user, pipeline: pipeline) }
+ subject { create(:ci_build, :running, pipeline: pipeline, user: user) }
let(:pipeline) do
create(:ci_pipeline,
@@ -4175,7 +4188,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '.matches_tag_ids' do
- let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, pipeline: pipeline, user: user) }
let(:tag_ids) { ::ActsAsTaggableOn::Tag.named_any(tag_list).ids }
@@ -4223,7 +4236,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '.matches_tags' do
- let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, pipeline: pipeline, user: user) }
subject { described_class.where(id: build).with_any_tags }
@@ -4249,7 +4262,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'pages deployments' do
- let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, pipeline: pipeline, user: user) }
context 'when job is "pages"' do
before do
@@ -4575,7 +4588,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#artifacts_metadata_entry' do
- let_it_be(:build) { create(:ci_build, project: project) }
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
let(:path) { 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' }
@@ -4635,7 +4648,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#publishes_artifacts_reports?' do
- let(:build) { create(:ci_build, options: options) }
+ let(:build) { create(:ci_build, options: options, pipeline: pipeline) }
subject { build.publishes_artifacts_reports? }
@@ -4663,7 +4676,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#runner_required_feature_names' do
- let(:build) { create(:ci_build, options: options) }
+ let(:build) { create(:ci_build, options: options, pipeline: pipeline) }
subject { build.runner_required_feature_names }
@@ -4685,7 +4698,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#supported_runner?' do
- let_it_be_with_refind(:build) { create(:ci_build) }
+ let_it_be_with_refind(:build) { create(:ci_build, pipeline: pipeline) }
subject { build.supported_runner?(runner_features) }
@@ -4793,7 +4806,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is a last deployment' do
- let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline, project: project) }
+ let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
@@ -4801,7 +4814,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when there is a newer build with deployment' do
- let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline, project: project) }
+ let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
let!(:last_deployment) { create(:deployment, :success, environment: environment, project: environment.project) }
@@ -4810,7 +4823,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build with deployment has failed' do
- let(:build) { create(:ci_build, :failed, environment: 'production', pipeline: pipeline, project: project) }
+ let(:build) { create(:ci_build, :failed, environment: 'production', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
@@ -4818,7 +4831,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build with deployment is running' do
- let(:build) { create(:ci_build, environment: 'production', pipeline: pipeline, project: project) }
+ let(:build) { create(:ci_build, environment: 'production', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
@@ -4828,13 +4841,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#degenerated?' do
context 'when build is degenerated' do
- subject { create(:ci_build, :degenerated) }
+ subject { create(:ci_build, :degenerated, pipeline: pipeline) }
it { is_expected.to be_degenerated }
end
context 'when build is valid' do
- subject { create(:ci_build) }
+ subject { create(:ci_build, pipeline: pipeline) }
it { is_expected.not_to be_degenerated }
@@ -4849,7 +4862,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe 'degenerate!' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
subject { build.degenerate! }
@@ -4869,13 +4882,13 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#archived?' do
context 'when build is degenerated' do
- subject { create(:ci_build, :degenerated) }
+ subject { create(:ci_build, :degenerated, pipeline: pipeline) }
it { is_expected.to be_archived }
end
context 'for old build' do
- subject { create(:ci_build, created_at: 1.day.ago) }
+ subject { create(:ci_build, created_at: 1.day.ago, pipeline: pipeline) }
context 'when archive_builds_in is set' do
before do
@@ -4896,7 +4909,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#read_metadata_attribute' do
- let(:build) { create(:ci_build, :degenerated) }
+ let(:build) { create(:ci_build, :degenerated, pipeline: pipeline) }
let(:build_options) { { key: "build" } }
let(:metadata_options) { { key: "metadata" } }
let(:default_options) { { key: "default" } }
@@ -4933,7 +4946,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#write_metadata_attribute' do
- let(:build) { create(:ci_build, :degenerated) }
+ let(:build) { create(:ci_build, :degenerated, pipeline: pipeline) }
let(:options) { { key: "new options" } }
let(:existing_options) { { key: "existing options" } }
@@ -5059,13 +5072,15 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
subject { build.environment_auto_stop_in }
context 'when build option has environment auto_stop_in' do
- let(:build) { create(:ci_build, options: { environment: { name: 'test', auto_stop_in: '1 day' } }) }
+ let(:build) do
+ create(:ci_build, options: { environment: { name: 'test', auto_stop_in: '1 day' } }, pipeline: pipeline)
+ end
it { is_expected.to eq('1 day') }
end
context 'when build option does not have environment auto_stop_in' do
- let(:build) { create(:ci_build) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
it { is_expected.to be_nil }
end
@@ -5385,7 +5400,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '.build_matchers' do
- let_it_be(:pipeline) { create(:ci_pipeline, :protected) }
+ let_it_be(:pipeline) { create(:ci_pipeline, :protected, project: project) }
subject(:matchers) { pipeline.builds.build_matchers(pipeline.project) }
@@ -5434,7 +5449,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#build_matcher' do
let_it_be(:build) do
- build_stubbed(:ci_build, tag_list: %w[tag1 tag2])
+ build_stubbed(:ci_build, tag_list: %w[tag1 tag2], pipeline: pipeline)
end
subject(:matcher) { build.build_matcher }
@@ -5570,7 +5585,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
it 'does not generate cross DB queries when a record is created via FactoryBot' do
with_cross_database_modification_prevented do
- create(:ci_build)
+ create(:ci_build, pipeline: pipeline)
end
end
@@ -5598,7 +5613,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
it_behaves_like 'cleanup by a loose foreign key' do
- let!(:model) { create(:ci_build, user: create(:user)) }
+ let!(:model) { create(:ci_build, user: create(:user), pipeline: pipeline) }
let!(:parent) { model.user }
end
@@ -5608,7 +5623,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when given new job variables' do
context 'when the cloned build has an action' do
it 'applies the new job variables' do
- build = create(:ci_build, :actionable)
+ build = create(:ci_build, :actionable, pipeline: pipeline)
create(:ci_job_variable, job: build, key: 'TEST_KEY', value: 'old value')
create(:ci_job_variable, job: build, key: 'OLD_KEY', value: 'i will not live for long')
@@ -5627,7 +5642,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when the cloned build does not have an action' do
it 'applies the old job variables' do
- build = create(:ci_build)
+ build = create(:ci_build, pipeline: pipeline)
create(:ci_job_variable, job: build, key: 'TEST_KEY', value: 'old value')
new_build = build.clone(
@@ -5645,7 +5660,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
context 'when not given new job variables' do
it 'applies the old job variables' do
- build = create(:ci_build)
+ build = create(:ci_build, pipeline: pipeline)
create(:ci_job_variable, job: build, key: 'TEST_KEY', value: 'old value')
new_build = build.clone(current_user: user)
@@ -5659,14 +5674,14 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
describe '#test_suite_name' do
- let(:build) { create(:ci_build, name: 'test') }
+ let(:build) { create(:ci_build, name: 'test', pipeline: pipeline) }
it 'uses the group name for test suite name' do
expect(build.test_suite_name).to eq('test')
end
context 'when build is part of parallel build' do
- let(:build) { create(:ci_build, name: 'build 1/2') }
+ let(:build) { create(:ci_build, name: 'build 1/2', pipeline: pipeline) }
it 'uses the group name for test suite name' do
expect(build.test_suite_name).to eq('build')
@@ -5674,7 +5689,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
end
context 'when build is part of matrix build' do
- let!(:matrix_build) { create(:ci_build, :matrix) }
+ let!(:matrix_build) { create(:ci_build, :matrix, pipeline: pipeline) }
it 'uses the job name for the test suite' do
expect(matrix_build.test_suite_name).to eq(matrix_build.name)
@@ -5685,7 +5700,8 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe '#runtime_hooks' do
let(:build1) do
FactoryBot.build(:ci_build,
- options: { hooks: { pre_get_sources_script: ["echo 'hello pre_get_sources_script'"] } })
+ options: { hooks: { pre_get_sources_script: ["echo 'hello pre_get_sources_script'"] } },
+ pipeline: pipeline)
end
subject(:runtime_hooks) { build1.runtime_hooks }
@@ -5700,7 +5716,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe 'partitioning', :ci_partitionable do
include Ci::PartitioningHelpers
- let(:new_pipeline) { create(:ci_pipeline) }
+ let(:new_pipeline) { create(:ci_pipeline, project: project) }
let(:ci_build) { FactoryBot.build(:ci_build, pipeline: new_pipeline) }
before do
@@ -5724,7 +5740,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
describe 'assigning token', :ci_partitionable do
include Ci::PartitioningHelpers
- let(:new_pipeline) { create(:ci_pipeline) }
+ let(:new_pipeline) { create(:ci_pipeline, project: project) }
let(:ci_build) { create(:ci_build, pipeline: new_pipeline) }
before do
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 681f1b57a1a..65dc1a71829 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1931,7 +1931,7 @@ RSpec.describe Ci::Runner, feature_category: :runner do
end
end
- describe '#with_upgrade_status' do
+ describe '.with_upgrade_status' do
subject { described_class.with_upgrade_status(upgrade_status) }
let_it_be(:runner_14_0_0) { create(:ci_runner, version: '14.0.0') }
@@ -1975,4 +1975,20 @@ RSpec.describe Ci::Runner, feature_category: :runner do
end
end
end
+
+ describe '#created_via_ui?' do
+ subject(:created_via_ui) { runner.created_via_ui? }
+
+ context 'when runner registered from command line' do
+ let(:runner) { create(:ci_runner) }
+
+ it { is_expected.to eq false }
+ end
+
+ context 'when runner created via UI' do
+ let(:runner) { create(:ci_runner, :created_in_ui) }
+
+ it { is_expected.to eq true }
+ end
+ end
end
diff --git a/spec/policies/ci/runner_policy_spec.rb b/spec/policies/ci/runner_policy_spec.rb
index 6039d60ec2f..e0a9e3c2870 100644
--- a/spec/policies/ci/runner_policy_spec.rb
+++ b/spec/policies/ci/runner_policy_spec.rb
@@ -3,11 +3,12 @@
require 'spec_helper'
RSpec.describe Ci::RunnerPolicy, feature_category: :runner do
+ let_it_be(:owner) { create(:user) }
+
describe 'ability :read_runner' do
let_it_be(:guest) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
- let_it_be(:owner) { create(:user) }
let_it_be_with_reload(:group) { create(:group, name: 'top-level', path: 'top-level') }
let_it_be_with_reload(:subgroup) { create(:group, name: 'subgroup', path: 'subgroup', parent: group) }
@@ -170,4 +171,24 @@ RSpec.describe Ci::RunnerPolicy, feature_category: :runner do
end
end
end
+
+ describe 'ability :read_ephemeral_token' do
+ subject(:policy) { described_class.new(user, runner) }
+
+ let_it_be(:runner) { create(:ci_runner, creator: owner) }
+
+ let(:creator) { owner }
+
+ context 'with request made by creator' do
+ let(:user) { creator }
+
+ it { expect_allowed :read_ephemeral_token }
+ end
+
+ context 'with request made by another user' do
+ let(:user) { create(:admin) }
+
+ it { expect_disallowed :read_ephemeral_token }
+ end
+ end
end
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 1d40d8291b5..6c5d6b0010d 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -92,6 +92,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
run_untagged: runner.run_untagged,
ip_address: runner.ip_address,
runner_type: runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE',
+ ephemeral_authentication_token: nil,
executor_name: runner.executor_type&.dasherize,
architecture_name: runner.architecture,
platform_name: runner.platform,
@@ -518,6 +519,108 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
end
+ describe 'ephemeralAuthenticationToken', :freeze_time do
+ subject(:request) { post_graphql(query, current_user: user) }
+
+ let_it_be(:creator) { create(:user) }
+
+ let(:created_at) { Time.current }
+ let(:token_prefix) { '' }
+ let(:query) do
+ %(
+ query {
+ runner(id: "#{runner.to_global_id}") {
+ id
+ ephemeralAuthenticationToken
+ }
+ }
+ )
+ end
+
+ let(:runner) do
+ create(:ci_runner, :group,
+ groups: [group], creator: creator, created_at: created_at, token: "#{token_prefix}abc123")
+ end
+
+ before_all do
+ group.add_owner(creator) # Allow creating runners in the group
+ end
+
+ shared_examples 'an ephemeral_authentication_token' do
+ it 'returns token in ephemeral_authentication_token field' do
+ request
+
+ runner_data = graphql_data_at(:runner)
+ expect(runner_data).not_to be_nil
+ expect(runner_data).to match a_graphql_entity_for(runner, ephemeral_authentication_token: runner.token)
+ end
+ end
+
+ shared_examples 'a protected ephemeral_authentication_token' do
+ it 'returns nil ephemeral_authentication_token' do
+ request
+
+ runner_data = graphql_data_at(:runner)
+ expect(runner_data).not_to be_nil
+ expect(runner_data).to match a_graphql_entity_for(runner, ephemeral_authentication_token: nil)
+ end
+ end
+
+ context 'with request made by creator' do
+ let(:user) { creator }
+
+ context 'with runner created in UI' do
+ let(:token_prefix) { ::Ci::Runner::CREATED_RUNNER_TOKEN_PREFIX }
+
+ context 'with runner created in last 3 hours' do
+ let(:created_at) { (3.hours - 1.second).ago }
+
+ context 'with no runner machine registed yet' do
+ it_behaves_like 'an ephemeral_authentication_token'
+ end
+
+ context 'with first runner machine already registed' do
+ let!(:runner_machine) { create(:ci_runner_machine, runner: runner) }
+
+ it_behaves_like 'a protected ephemeral_authentication_token'
+ end
+ end
+
+ context 'with runner created almost too long ago' do
+ let(:created_at) { (3.hours - 1.second).ago }
+
+ it_behaves_like 'an ephemeral_authentication_token'
+ end
+
+ context 'with runner created too long ago' do
+ let(:created_at) { 3.hours.ago }
+
+ it_behaves_like 'a protected ephemeral_authentication_token'
+ end
+ end
+
+ context 'with runner registered from command line' do
+ let(:token_prefix) { '' }
+
+ context 'with runner created in last 3 hours' do
+ let(:created_at) { (3.hours - 1.second).ago }
+
+ it_behaves_like 'a protected ephemeral_authentication_token'
+ end
+ end
+ end
+
+ context 'when request is made by non-creator of the runner' do
+ let(:user) { create(:admin) }
+
+ context 'with runner created in UI' do
+ let(:token_prefix) { ::Ci::Runner::CREATED_RUNNER_TOKEN_PREFIX }
+
+ it_behaves_like 'a protected ephemeral_authentication_token'
+ end
+ end
+ end
+
describe 'Query limits' do
def runner_query(runner)
<<~SINGLE
diff --git a/spec/scripts/failed_tests_spec.rb b/spec/scripts/failed_tests_spec.rb
index b99fd991c55..ce0ec66cdb6 100644
--- a/spec/scripts/failed_tests_spec.rb
+++ b/spec/scripts/failed_tests_spec.rb
@@ -5,121 +5,113 @@ require_relative '../../scripts/failed_tests'
RSpec.describe FailedTests do
let(:report_file) { 'spec/fixtures/scripts/test_report.json' }
- let(:output_directory) { 'tmp/previous_test_results' }
- let(:rspec_pg_regex) { /rspec .+ pg12( .+)?/ }
- let(:rspec_ee_pg_regex) { /rspec-ee .+ pg12( .+)?/ }
-
- subject { described_class.new(previous_tests_report_path: report_file, output_directory: output_directory, rspec_pg_regex: rspec_pg_regex, rspec_ee_pg_regex: rspec_ee_pg_regex) }
-
- describe '#output_failed_test_files' do
- it 'writes the file for the suite' do
- expect(File).to receive(:open).with(File.join(output_directory, "rspec_failed_files.txt"), 'w').once
-
- subject.output_failed_test_files
- end
- end
-
- describe '#failed_files_for_suite_collection' do
- let(:failure_path) { 'path/to/fail_file_spec.rb' }
- let(:other_failure_path) { 'path/to/fail_file_spec_2.rb' }
- let(:file_contents_as_json) do
- {
- 'suites' => [
- {
- 'failed_count' => 1,
- 'name' => 'rspec unit pg12 10/12',
- 'test_cases' => [
- {
- 'status' => 'failed',
- 'file' => failure_path
- }
- ]
- },
- {
- 'failed_count' => 1,
- 'name' => 'rspec-ee unit pg12',
- 'test_cases' => [
- {
- 'status' => 'failed',
- 'file' => failure_path
- }
- ]
- },
- {
- 'failed_count' => 1,
- 'name' => 'rspec unit pg13 10/12',
- 'test_cases' => [
- {
- 'status' => 'failed',
- 'file' => other_failure_path
- }
- ]
- }
- ]
- }
- end
-
- before do
- allow(subject).to receive(:file_contents_as_json).and_return(file_contents_as_json)
- end
-
- it 'returns a list of failed file paths for suite collection' do
- result = subject.failed_files_for_suite_collection
-
- expect(result[:rspec].to_a).to match_array(failure_path)
- expect(result[:rspec_ee].to_a).to match_array(failure_path)
- end
+ let(:options) { described_class::DEFAULT_OPTIONS.merge(previous_tests_report_path: report_file) }
+ let(:failure_path) { 'path/to/fail_file_spec.rb' }
+ let(:other_failure_path) { 'path/to/fail_file_spec_2.rb' }
+ let(:file_contents_as_json) do
+ {
+ 'suites' => [
+ {
+ 'failed_count' => 1,
+ 'name' => 'rspec unit pg12 10/12',
+ 'test_cases' => [
+ {
+ 'status' => 'failed',
+ 'file' => failure_path
+ }
+ ]
+ },
+ {
+ 'failed_count' => 1,
+ 'name' => 'rspec-ee unit pg12',
+ 'test_cases' => [
+ {
+ 'status' => 'failed',
+ 'file' => failure_path
+ }
+ ]
+ },
+ {
+ 'failed_count' => 1,
+ 'name' => 'rspec unit pg13 10/12',
+ 'test_cases' => [
+ {
+ 'status' => 'failed',
+ 'file' => other_failure_path
+ }
+ ]
+ }
+ ]
+ }
end
- describe 'empty report' do
- let(:file_content) do
- '{}'
- end
-
- before do
- allow(subject).to receive(:file_contents).and_return(file_content)
- end
-
- it 'does not fail for output files' do
- subject.output_failed_test_files
- end
-
- it 'returns empty results for suite failures' do
- result = subject.failed_files_for_suite_collection
-
- expect(result.values.flatten).to be_empty
- end
- end
-
- describe 'invalid report' do
- let(:file_content) do
- ''
- end
-
- before do
- allow(subject).to receive(:file_contents).and_return(file_content)
- end
-
- it 'does not fail for output files' do
- subject.output_failed_test_files
- end
-
- it 'returns empty results for suite failures' do
- result = subject.failed_files_for_suite_collection
-
- expect(result.values.flatten).to be_empty
+ subject { described_class.new(options) }
+
+ describe '#output_failed_tests' do
+ context 'with a valid report file' do
+ before do
+ allow(subject).to receive(:file_contents_as_json).and_return(file_contents_as_json)
+ end
+
+ it 'writes the file for the suite' do
+ expect(File).to receive(:open)
+ .with(File.join(described_class::DEFAULT_OPTIONS[:output_directory], "rspec_failed_tests.txt"), 'w').once
+ expect(File).to receive(:open)
+ .with(File.join(described_class::DEFAULT_OPTIONS[:output_directory], "rspec_ee_failed_tests.txt"), 'w').once
+
+ subject.output_failed_tests
+ end
+
+ context 'when given a valid format' do
+ subject { described_class.new(options.merge(format: :json)) }
+
+ it 'writes the file for the suite' do
+ expect(File).to receive(:open)
+ .with(File.join(described_class::DEFAULT_OPTIONS[:output_directory], "rspec_failed_tests.json"), 'w').once
+ expect(File).to receive(:open)
+ .with(File.join(described_class::DEFAULT_OPTIONS[:output_directory], "rspec_ee_failed_tests.json"), 'w')
+ .once
+
+ subject.output_failed_tests
+ end
+ end
+
+ context 'when given an invalid format' do
+ subject { described_class.new(options.merge(format: :foo)) }
+
+ it 'raises an exception' do
+ expect { subject.output_failed_tests }
+ .to raise_error '[FailedTests] Unsupported format `foo` (allowed formats: `oneline` and `json`)!'
+ end
+ end
+
+ describe 'empty report' do
+ let(:file_contents_as_json) do
+ {}
+ end
+
+ it 'does not fail for output files' do
+ subject.output_failed_tests
+ end
+
+ it 'returns empty results for suite failures' do
+ result = subject.failed_cases_for_suite_collection
+
+ expect(result.values.flatten).to be_empty
+ end
+ end
end
end
describe 'missing report file' do
- let(:report_file) { 'unknownfile.json' }
+ subject { described_class.new(options.merge(previous_tests_report_path: 'unknownfile.json')) }
it 'does not fail for output files' do
- subject.output_failed_test_files
+ subject.output_failed_tests
end
it 'returns empty results for suite failures' do
- result = subject.failed_files_for_suite_collection
+ result = subject.failed_cases_for_suite_collection
expect(result.values.flatten).to be_empty
end
diff --git a/spec/scripts/pipeline_test_report_builder_spec.rb b/spec/scripts/pipeline_test_report_builder_spec.rb
index b51b4dc4887..e7529eb0d41 100644
--- a/spec/scripts/pipeline_test_report_builder_spec.rb
+++ b/spec/scripts/pipeline_test_report_builder_spec.rb
@@ -3,12 +3,11 @@
require 'fast_spec_helper'
require_relative '../../scripts/pipeline_test_report_builder'
-RSpec.describe PipelineTestReportBuilder do
+RSpec.describe PipelineTestReportBuilder, feature_category: :tooling do
let(:report_file) { 'spec/fixtures/scripts/test_report.json' }
let(:output_file_path) { 'tmp/previous_test_results/output_file.json' }
-
- subject do
- described_class.new(
+ let(:options) do
+ described_class::DEFAULT_OPTIONS.merge(
target_project: 'gitlab-org/gitlab',
mr_id: '999',
instance_base_url: 'https://gitlab.com',
@@ -16,25 +15,27 @@ RSpec.describe PipelineTestReportBuilder do
)
end
- let(:failed_pipeline_url) { 'pipeline2_url' }
+ let(:previous_pipeline_url) { '/pipelines/previous' }
- let(:failed_pipeline) do
+ let(:previous_pipeline) do
{
'status' => 'failed',
- 'created_at' => (DateTime.now - 5).to_s,
- 'web_url' => failed_pipeline_url
+ 'id' => 1,
+ 'web_url' => previous_pipeline_url
}
end
- let(:current_pipeline) do
+ let(:latest_pipeline_url) { '/pipelines/latest' }
+
+ let(:latest_pipeline) do
{
'status' => 'running',
- 'created_at' => DateTime.now.to_s,
- 'web_url' => 'pipeline1_url'
+ 'id' => 3,
+ 'web_url' => latest_pipeline_url
}
end
- let(:mr_pipelines) { [current_pipeline, failed_pipeline] }
+ let(:mr_pipelines) { [latest_pipeline, previous_pipeline] }
let(:failed_build_id) { 9999 }
@@ -68,6 +69,8 @@ RSpec.describe PipelineTestReportBuilder do
}
end
+ subject { described_class.new(options) }
+
before do
allow(subject).to receive(:pipelines_for_mr).and_return(mr_pipelines)
allow(subject).to receive(:failed_builds_for_pipeline).and_return(failed_builds_for_pipeline)
@@ -78,7 +81,7 @@ RSpec.describe PipelineTestReportBuilder do
let(:fork_pipeline) do
{
'status' => 'failed',
- 'created_at' => (DateTime.now - 5).to_s,
+ 'id' => 2,
'web_url' => fork_pipeline_url
}
end
@@ -88,7 +91,7 @@ RSpec.describe PipelineTestReportBuilder do
end
context 'pipeline in a fork project' do
- let(:mr_pipelines) { [current_pipeline, fork_pipeline] }
+ let(:mr_pipelines) { [latest_pipeline, fork_pipeline] }
it 'returns fork pipeline' do
expect(subject.previous_pipeline).to eq(fork_pipeline)
@@ -97,125 +100,105 @@ RSpec.describe PipelineTestReportBuilder do
context 'pipeline in target project' do
it 'returns failed pipeline' do
- expect(subject.previous_pipeline).to eq(failed_pipeline)
+ expect(subject.previous_pipeline).to eq(previous_pipeline)
end
end
end
- describe '#test_report_for_latest_pipeline' do
- let(:failed_build_uri) { "#{failed_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}" }
-
- before do
- allow(subject).to receive(:fetch).with(failed_build_uri).and_return(failed_builds_for_pipeline)
- end
-
- it 'fetches builds from pipeline related to MR' do
- expected = { "suites" => [failed_builds_for_pipeline] }.to_json
- expect(subject.test_report_for_latest_pipeline).to eq(expected)
- end
-
- context 'canonical pipeline' do
- context 'no previous pipeline' do
- let(:mr_pipelines) { [] }
+ describe '#test_report_for_pipeline' do
+ context 'for previous pipeline' do
+ let(:failed_build_uri) { "#{previous_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}" }
- it 'returns empty hash' do
- expect(subject.test_report_for_latest_pipeline).to eq("{}")
- end
+ before do
+ allow(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
end
- context 'first pipeline scenario' do
- let(:mr_pipelines) do
- [
- {
- 'status' => 'running',
- 'created_at' => DateTime.now.to_s
- }
- ]
- end
-
- it 'returns empty hash' do
- expect(subject.test_report_for_latest_pipeline).to eq("{}")
- end
+ it 'fetches builds from pipeline related to MR' do
+ expected = { "suites" => [test_report_for_build.merge('job_url' => "/jobs/#{failed_build_id}")] }.to_json
+ expect(subject.test_report_for_pipeline).to eq(expected)
end
- context 'no previous failed pipeline' do
- let(:mr_pipelines) do
- [
- {
- 'status' => 'running',
- 'created_at' => DateTime.now.to_s
- },
- {
- 'status' => 'success',
- 'created_at' => (DateTime.now - 5).to_s
- }
- ]
- end
+ context 'canonical pipeline' do
+ context 'no previous pipeline' do
+ let(:mr_pipelines) { [] }
- it 'returns empty hash' do
- expect(subject.test_report_for_latest_pipeline).to eq("{}")
+ it 'returns empty hash' do
+ expect(subject.test_report_for_pipeline).to eq("{}")
+ end
end
- end
- context 'no failed test builds' do
- let(:failed_builds_for_pipeline) do
- [
- {
- 'id' => 9999,
- 'stage' => 'prepare'
- }
- ]
- end
+ context 'no failed test builds' do
+ let(:failed_builds_for_pipeline) do
+ [
+ {
+ 'id' => 9999,
+ 'stage' => 'prepare'
+ }
+ ]
+ end
- it 'returns empty hash' do
- expect(subject.test_report_for_latest_pipeline).to eq("{}")
+ it 'returns a hash with an empty "suites" array' do
+ expect(subject.test_report_for_pipeline).to eq({ suites: [] }.to_json)
+ end
end
- end
- context 'failed pipeline and failed test builds' do
- before do
- allow(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
- end
+ context 'failed pipeline and failed test builds' do
+ before do
+ allow(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
+ end
- it 'returns populated test list for suites' do
- actual = subject.test_report_for_latest_pipeline
- expected = {
- 'suites' => [test_report_for_build]
- }.to_json
+ it 'returns populated test list for suites' do
+ actual = subject.test_report_for_pipeline
+ expected = {
+ 'suites' => [test_report_for_build]
+ }.to_json
- expect(actual).to eq(expected)
+ expect(actual).to eq(expected)
+ end
end
- end
- context 'when receiving a server error' do
- let(:response) { instance_double('Net::HTTPResponse') }
- let(:error) { Net::HTTPServerException.new('server error', response) }
- let(:test_report_for_latest_pipeline) { subject.test_report_for_latest_pipeline }
+ context 'when receiving a server error' do
+ let(:response) { instance_double('Net::HTTPResponse') }
+ let(:error) { Net::HTTPServerException.new('server error', response) }
+ let(:test_report_for_pipeline) { subject.test_report_for_pipeline }
- before do
- allow(response).to receive(:code).and_return(response_code)
- allow(subject).to receive(:fetch).with(failed_build_uri).and_raise(error)
- end
+ before do
+ allow(response).to receive(:code).and_return(response_code)
+ allow(subject).to receive(:fetch).with(failed_build_uri).and_raise(error)
+ end
- context 'when response code is 404' do
- let(:response_code) { 404 }
+ context 'when response code is 404' do
+ let(:response_code) { 404 }
- it 'continues without the missing reports' do
- expected = { 'suites' => [] }.to_json
+ it 'continues without the missing reports' do
+ expected = { suites: [] }.to_json
- expect { test_report_for_latest_pipeline }.not_to raise_error
- expect(test_report_for_latest_pipeline).to eq(expected)
+ expect { test_report_for_pipeline }.not_to raise_error
+ expect(test_report_for_pipeline).to eq(expected)
+ end
end
- end
- context 'when response code is unexpected' do
- let(:response_code) { 500 }
+ context 'when response code is unexpected' do
+ let(:response_code) { 500 }
- it 'raises HTTPServerException' do
- expect { test_report_for_latest_pipeline }.to raise_error(error)
+ it 'raises HTTPServerException' do
+ expect { test_report_for_pipeline }.to raise_error(error)
+ end
end
end
end
end
+
+ context 'for latest pipeline' do
+ let(:failed_build_uri) { "#{latest_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}" }
+
+ subject { described_class.new(options.merge(pipeline_index: :latest)) }
+
+ it 'fetches builds from pipeline related to MR' do
+ expect(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
+
+ subject.test_report_for_pipeline
+ end
+ end
end
end
diff --git a/spec/tooling/lib/tooling/mappings/base_spec.rb b/spec/tooling/lib/tooling/mappings/base_spec.rb
new file mode 100644
index 00000000000..935f833fa8b
--- /dev/null
+++ b/spec/tooling/lib/tooling/mappings/base_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require_relative '../../../../../tooling/lib/tooling/mappings/view_to_js_mappings'
+
+RSpec.describe Tooling::Mappings::Base, feature_category: :tooling do
+ describe '#folders_for_available_editions' do
+ let(:base_folder_path) { 'app/views' }
+
+ subject { described_class.new.folders_for_available_editions(base_folder_path) }
+
+ context 'when FOSS' do
+ before do
+ allow(GitlabEdition).to receive(:ee?).and_return(false)
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
+ end
+
+ it 'returns the correct paths' do
+ expect(subject).to match_array([base_folder_path])
+ end
+ end
+
+ context 'when EE' do
+ before do
+ allow(GitlabEdition).to receive(:ee?).and_return(true)
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
+ end
+
+ it 'returns the correct paths' do
+ expect(subject).to match_array([base_folder_path, "ee/#{base_folder_path}"])
+ end
+ end
+
+ context 'when JiHu' do
+ before do
+ allow(GitlabEdition).to receive(:ee?).and_return(true)
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ end
+
+ it 'returns the correct paths' do
+ expect(subject).to match_array([base_folder_path, "ee/#{base_folder_path}", "jh/#{base_folder_path}"])
+ end
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb b/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb
new file mode 100644
index 00000000000..72e02547938
--- /dev/null
+++ b/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb
@@ -0,0 +1,169 @@
+# frozen_string_literal: true
+
+require 'tempfile'
+require_relative '../../../../../tooling/lib/tooling/mappings/js_to_system_specs_mappings'
+
+RSpec.describe Tooling::Mappings::JsToSystemSpecsMappings, feature_category: :tooling do
+ # We set temporary folders, and those readers give access to those folder paths
+ attr_accessor :js_base_folder, :system_specs_base_folder
+
+ around do |example|
+ Dir.mktmpdir do |tmp_js_base_folder|
+ Dir.mktmpdir do |tmp_system_specs_base_folder|
+ self.system_specs_base_folder = tmp_system_specs_base_folder
+ self.js_base_folder = tmp_js_base_folder
+
+ example.run
+ end
+ end
+ end
+
+ describe '#execute' do
+ let(:instance) do
+ described_class.new(
+ system_specs_base_folder: system_specs_base_folder,
+ js_base_folder: js_base_folder
+ )
+ end
+
+ subject { instance.execute(changed_files) }
+
+ context 'when no JS files were changed' do
+ let(:changed_files) { [] }
+
+ it 'returns nothing' do
+ expect(subject).to match_array([])
+ end
+ end
+
+ context 'when some JS files were changed' do
+ let(:changed_files) { ["#{js_base_folder}/issues/secret_values.js"] }
+
+ context 'when the JS files are not present on disk' do
+ it 'returns nothing' do
+ expect(subject).to match_array([])
+ end
+ end
+
+ context 'when the JS files are present on disk' do
+ before do
+ FileUtils.mkdir_p("#{js_base_folder}/issues")
+ File.write("#{js_base_folder}/issues/secret_values.js", "hello")
+ end
+
+ context 'when no system specs match the JS keyword' do
+ it 'returns nothing' do
+ expect(subject).to match_array([])
+ end
+ end
+
+ context 'when a system spec matches the JS keyword' do
+ before do
+ FileUtils.mkdir_p("#{system_specs_base_folder}/confidential_issues")
+ File.write("#{system_specs_base_folder}/confidential_issues/issues_spec.rb", "a test")
+ end
+
+ it 'returns something' do
+ expect(subject).to match_array(["#{system_specs_base_folder}/confidential_issues/issues_spec.rb"])
+ end
+ end
+ end
+ end
+ end
+
+ describe '#filter_files' do
+ subject { described_class.new(js_base_folder: js_base_folder).filter_files(changed_files) }
+
+ before do
+ File.write("#{js_base_folder}/index.js", "index.js")
+ File.write("#{js_base_folder}/index-with-ee-in-it.js", "index-with-ee-in-it.js")
+ File.write("#{js_base_folder}/index-with-jh-in-it.js", "index-with-jh-in-it.js")
+ end
+
+ context 'when no files were changed' do
+ let(:changed_files) { [] }
+
+ it 'returns an empty array' do
+ expect(subject).to match_array([])
+ end
+ end
+
+ context 'when JS files were changed' do
+ let(:changed_files) do
+ [
+ "#{js_base_folder}/index.js",
+ "#{js_base_folder}/index-with-ee-in-it.js",
+ "#{js_base_folder}/index-with-jh-in-it.js"
+ ]
+ end
+
+ it 'returns the path to the JS files' do
+ # "nil" group represents FOSS JS files in app/assets/javascripts
+ expect(subject).to match(nil => [
+ "#{js_base_folder}/index.js",
+ "#{js_base_folder}/index-with-ee-in-it.js",
+ "#{js_base_folder}/index-with-jh-in-it.js"
+ ])
+ end
+ end
+
+ context 'when JS files are deleted' do
+ let(:changed_files) { ["#{system_specs_base_folder}/deleted.html"] }
+
+ it 'returns an empty array' do
+ expect(subject).to match_array([])
+ end
+ end
+ end
+
+ describe '#construct_js_keywords' do
+ subject { described_class.new.construct_js_keywords(js_files) }
+
+ let(:js_files) do
+ %w[
+ app/assets/javascripts/boards/issue_board_filters.js
+ ee/app/assets/javascripts/queries/epic_due_date.query.graphql
+ ]
+ end
+
+ it 'returns a singularized keyword based on the first folder the file is in' do
+ expect(subject).to eq(%w[board query])
+ end
+ end
+
+ describe '#system_specs_for_edition' do
+ subject do
+ described_class.new(system_specs_base_folder: system_specs_base_folder).system_specs_for_edition(edition)
+ end
+
+ context 'when FOSS' do
+ let(:edition) { nil }
+
+ it 'checks the correct folder' do
+ expect(Dir).to receive(:[]).with("#{system_specs_base_folder}/**/*").and_call_original
+
+ subject
+ end
+ end
+
+ context 'when EE' do
+ let(:edition) { 'ee' }
+
+ it 'checks the correct folder' do
+ expect(Dir).to receive(:[]).with("ee#{system_specs_base_folder}/**/*").and_call_original
+
+ subject
+ end
+ end
+
+ context 'when JiHu' do
+ let(:edition) { 'jh' }
+
+ it 'checks the correct folder' do
+ expect(Dir).to receive(:[]).with("jh#{system_specs_base_folder}/**/*").and_call_original
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/view_to_js_mappings_spec.rb b/spec/tooling/lib/tooling/mappings/view_to_js_mappings_spec.rb
index b09df2a9200..eaa0124370d 100644
--- a/spec/tooling/lib/tooling/view_to_js_mappings_spec.rb
+++ b/spec/tooling/lib/tooling/mappings/view_to_js_mappings_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'tempfile'
-require_relative '../../../../tooling/lib/tooling/view_to_js_mappings'
+require_relative '../../../../../tooling/lib/tooling/mappings/view_to_js_mappings'
-RSpec.describe Tooling::ViewToJsMappings, feature_category: :tooling do
+RSpec.describe Tooling::Mappings::ViewToJsMappings, feature_category: :tooling do
# We set temporary folders, and those readers give access to those folder paths
attr_accessor :view_base_folder, :js_base_folder
@@ -32,7 +32,7 @@ RSpec.describe Tooling::ViewToJsMappings, feature_category: :tooling do
context 'when no view files have been changed' do
before do
- allow(instance).to receive(:view_files).and_return([])
+ allow(instance).to receive(:filter_files).and_return([])
end
it 'returns nothing' do
@@ -140,8 +140,8 @@ RSpec.describe Tooling::ViewToJsMappings, feature_category: :tooling do
end
end
- describe '#view_files' do
- subject { described_class.new(view_base_folder: view_base_folder).view_files(changed_files) }
+ describe '#filter_files' do
+ subject { described_class.new(view_base_folder: view_base_folder).filter_files(changed_files) }
before do
File.write("#{js_base_folder}/index.js", "index.js")
@@ -181,45 +181,6 @@ RSpec.describe Tooling::ViewToJsMappings, feature_category: :tooling do
end
end
- describe '#folders_for_available_editions' do
- let(:base_folder_path) { 'app/views' }
-
- subject { described_class.new.folders_for_available_editions(base_folder_path) }
-
- context 'when FOSS' do
- before do
- allow(GitlabEdition).to receive(:ee?).and_return(false)
- allow(GitlabEdition).to receive(:jh?).and_return(false)
- end
-
- it 'returns the correct paths' do
- expect(subject).to match_array([base_folder_path])
- end
- end
-
- context 'when EE' do
- before do
- allow(GitlabEdition).to receive(:ee?).and_return(true)
- allow(GitlabEdition).to receive(:jh?).and_return(false)
- end
-
- it 'returns the correct paths' do
- expect(subject).to eq([base_folder_path, "ee/#{base_folder_path}"])
- end
- end
-
- context 'when JiHu' do
- before do
- allow(GitlabEdition).to receive(:ee?).and_return(true)
- allow(GitlabEdition).to receive(:jh?).and_return(true)
- end
-
- it 'returns the correct paths' do
- expect(subject).to eq([base_folder_path, "ee/#{base_folder_path}", "jh/#{base_folder_path}"])
- end
- end
- end
-
describe '#find_partials' do
subject { described_class.new(view_base_folder: view_base_folder).find_partials(file_path) }