diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-03 21:08:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-03 21:08:19 +0300 |
commit | d83bbccfcd07ddab93be73959e3b149b75831e28 (patch) | |
tree | d8156497696dd1951f6556307cb3689952933eed /spec | |
parent | a99d0fa6922be88307b1c80330a257c55c5d8270 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
19 files changed, 484 insertions, 92 deletions
diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index 77c62c0d930..1da868c6c4b 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -8,9 +8,11 @@ RSpec.describe Groups::RunnersController do let_it_be(:project) { create(:project, group: group) } let!(:runner) { create(:ci_runner, :group, groups: [group]) } - let!(:runner_project) { create(:ci_runner, :project, projects: [project]) } + let!(:project_runner) { create(:ci_runner, :project, projects: [project]) } + let!(:instance_runner) { create(:ci_runner, :instance) } - let(:params_runner_project) { { group_id: group, id: runner_project } } + let(:params_runner_project) { { group_id: group, id: project_runner } } + let(:params_runner_instance) { { group_id: group, id: instance_runner } } let(:params) { { group_id: group, id: runner } } before do @@ -70,8 +72,33 @@ RSpec.describe Groups::RunnersController do expect(response).to render_template(:show) end + context 'when runners_finder_all_available is enabled' do + before do + stub_feature_flags(runners_finder_all_available: true) + end + + it 'renders show with 200 status code instance runner' do + get :show, params: { group_id: group, id: instance_runner } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:show) + end + end + + context 'when runners_finder_all_available is disabled' do + before do + stub_feature_flags(runners_finder_all_available: false) + end + + it 'renders show with a 404 instance runner' do + get :show, params: { group_id: group, id: instance_runner } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + it 'renders show with 200 status code project runner' do - get :show, params: { group_id: group, id: runner_project } + get :show, params: { group_id: group, id: project_runner } expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:show) @@ -89,8 +116,14 @@ RSpec.describe Groups::RunnersController do expect(response).to have_gitlab_http_status(:not_found) end + it 'renders a 404 instance runner' do + get :show, params: { group_id: group, id: instance_runner } + + expect(response).to have_gitlab_http_status(:not_found) + end + it 'renders a 404 project runner' do - get :show, params: { group_id: group, id: runner_project } + get :show, params: { group_id: group, id: project_runner } expect(response).to have_gitlab_http_status(:not_found) end @@ -103,15 +136,21 @@ RSpec.describe Groups::RunnersController do group.add_owner(user) end - it 'renders show with 200 status code' do + it 'renders edit with 200 status code' do get :edit, params: { group_id: group, id: runner } expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:edit) end - it 'renders show with 200 status code project runner' do - get :edit, params: { group_id: group, id: runner_project } + it 'renders a 404 instance runner' do + get :edit, params: { group_id: group, id: instance_runner } + + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'renders edit with 200 status code project runner' do + get :edit, params: { group_id: group, id: project_runner } expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:edit) @@ -130,7 +169,7 @@ RSpec.describe Groups::RunnersController do end it 'renders a 404 project runner' do - get :edit, params: { group_id: group, id: runner_project } + get :edit, params: { group_id: group, id: project_runner } expect(response).to have_gitlab_http_status(:not_found) end @@ -154,15 +193,26 @@ RSpec.describe Groups::RunnersController do expect(runner.reload.description).to eq(new_desc) end + it 'does not update the instance runner' do + new_desc = instance_runner.description.swapcase + + expect do + post :update, params: params_runner_instance.merge(runner: { description: new_desc } ) + end.to not_change { instance_runner.ensure_runner_queue_value } + .and not_change { instance_runner.description } + + expect(response).to have_gitlab_http_status(:not_found) + end + it 'updates the project runner, ticks the queue, and redirects project runner' do - new_desc = runner_project.description.swapcase + new_desc = project_runner.description.swapcase expect do post :update, params: params_runner_project.merge(runner: { description: new_desc } ) - end.to change { runner_project.ensure_runner_queue_value } + end.to change { project_runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:found) - expect(runner_project.reload.description).to eq(new_desc) + expect(project_runner.reload.description).to eq(new_desc) end end @@ -182,15 +232,26 @@ RSpec.describe Groups::RunnersController do expect(runner.reload.description).to eq(old_desc) end + it 'rejects the update and responds 404 instance runner' do + old_desc = instance_runner.description + + expect do + post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase } ) + end.not_to change { instance_runner.ensure_runner_queue_value } + + expect(response).to have_gitlab_http_status(:not_found) + expect(instance_runner.reload.description).to eq(old_desc) + end + it 'rejects the update and responds 404 project runner' do - old_desc = runner_project.description + old_desc = project_runner.description expect do post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase } ) - end.not_to change { runner_project.ensure_runner_queue_value } + end.not_to change { project_runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:not_found) - expect(runner_project.reload.description).to eq(old_desc) + expect(project_runner.reload.description).to eq(old_desc) end end end diff --git a/spec/factories/ci/build_metadata.rb b/spec/factories/ci/build_metadata.rb index cfc86c4ef4b..a0a5305ef39 100644 --- a/spec/factories/ci/build_metadata.rb +++ b/spec/factories/ci/build_metadata.rb @@ -3,5 +3,9 @@ FactoryBot.define do factory :ci_build_metadata, class: 'Ci::BuildMetadata' do build { association(:ci_build, strategy: :build, metadata: instance) } + + after(:build) do |metadata| + metadata.build&.valid? + end end end diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 8c2edc8cd9f..9a3b2837ab8 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -424,79 +424,79 @@ FactoryBot.define do trait :codequality_report do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :codequality, job: build) + build.job_artifacts << build(:ci_job_artifact, :codequality, job: build) end end trait :sast_report do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :sast, job: build) + build.job_artifacts << build(:ci_job_artifact, :sast, job: build) end end trait :secret_detection_report do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :secret_detection, job: build) + build.job_artifacts << build(:ci_job_artifact, :secret_detection, job: build) end end trait :test_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :junit, job: build) + build.job_artifacts << build(:ci_job_artifact, :junit, job: build) end end trait :test_reports_with_attachment do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :junit_with_attachment, job: build) + build.job_artifacts << build(:ci_job_artifact, :junit_with_attachment, job: build) end end trait :broken_test_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :junit_with_corrupted_data, job: build) + build.job_artifacts << build(:ci_job_artifact, :junit_with_corrupted_data, job: build) end end trait :test_reports_with_duplicate_failed_test_names do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :junit_with_duplicate_failed_test_names, job: build) + build.job_artifacts << build(:ci_job_artifact, :junit_with_duplicate_failed_test_names, job: build) end end trait :test_reports_with_three_failures do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :junit_with_three_failures, job: build) + build.job_artifacts << build(:ci_job_artifact, :junit_with_three_failures, job: build) end end trait :accessibility_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :accessibility, job: build) + build.job_artifacts << build(:ci_job_artifact, :accessibility, job: build) end end trait :coverage_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :cobertura, job: build) + build.job_artifacts << build(:ci_job_artifact, :cobertura, job: build) end end trait :codequality_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :codequality, job: build) + build.job_artifacts << build(:ci_job_artifact, :codequality, job: build) end end trait :codequality_reports_without_degradation do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :codequality_without_errors, job: build) + build.job_artifacts << build(:ci_job_artifact, :codequality_without_errors, job: build) end end trait :terraform_reports do after(:build) do |build| - build.job_artifacts << create(:ci_job_artifact, :terraform, job: build) + build.job_artifacts << build(:ci_job_artifact, :terraform, job: build) end end diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index 5b20010ef7e..650b8647237 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -8,6 +8,7 @@ FactoryBot.define do sha { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' } status { 'pending' } add_attribute(:protected) { false } + partition_id { 1234 } project @@ -53,6 +54,7 @@ FactoryBot.define do end factory :ci_pipeline do + partition_id { 1234 } transient { ci_ref_presence { true } } before(:create) do |pipeline, evaluator| diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb index dd377aa4a26..1ab231632fb 100644 --- a/spec/features/milestones/user_creates_milestone_spec.rb +++ b/spec/features/milestones/user_creates_milestone_spec.rb @@ -3,29 +3,100 @@ require 'spec_helper' RSpec.describe "User creates milestone", :js do - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user) } + let_it_be(:inherited_guest) { create(:user) } + let_it_be(:inherited_developer) { create(:user) } + let_it_be(:group) { create(:group, :public) } + + shared_examples 'creates milestone' do + specify do + title = "v2.3" + + fill_in("Title", with: title) + fill_in("Description", with: "# Description header") + click_button("Create milestone") + + expect(page).to have_content(title) + .and have_content("Issues") + .and have_header_with_correct_id_and_link(1, "Description header", "description-header") + + visit(activity_project_path(project)) + + expect(page).to have_content("#{user.name} #{user.to_reference} opened milestone") + end + end + + shared_examples 'renders not found' do + specify do + expect(page).to have_title('Not Found') + expect(page).to have_content('Page Not Found') + end + end + + before_all do + group.add_guest(inherited_guest) + group.add_developer(inherited_developer) + end before do - project.add_developer(user) sign_in(user) - visit(new_project_milestone_path(project)) end - it "creates milestone" do - title = "v2.3" + context 'when project is public' do + let_it_be(:project) { create(:project, :public, group: group) } + + context 'and issues and merge requests are private' do + before_all do + project.project_feature.update!( + issues_access_level: ProjectFeature::PRIVATE, + merge_requests_access_level: ProjectFeature::PRIVATE + ) + end + + context 'when user is an inherited member from the group' do + context 'and user is a guest' do + let(:user) { inherited_guest } + + it_behaves_like 'renders not found' + end + + context 'and user is a developer' do + let(:user) { inherited_developer } + + it_behaves_like 'creates milestone' + end + end + end + end + + context 'when project is private' do + let_it_be(:project) { create(:project, :private, group: group) } + + context 'and user is a direct project member' do + before_all do + project.add_developer(developer) + end + + context 'when user is a developer' do + let(:user) { developer } + + it_behaves_like 'creates milestone' + end + end - fill_in("Title", with: title) - fill_in("Description", with: "# Description header") - click_button("Create milestone") + context 'and user is an inherited member from the group' do + context 'when user is a guest' do + let(:user) { inherited_guest } - expect(page).to have_content(title) - .and have_content("Issues") - .and have_header_with_correct_id_and_link(1, "Description header", "description-header") + it_behaves_like 'renders not found' + end - visit(activity_project_path(project)) + context 'when user is a developer' do + let(:user) { inherited_developer } - expect(page).to have_content("#{user.name} #{user.to_reference} opened milestone") + it_behaves_like 'creates milestone' + end + end end end diff --git a/spec/frontend/flash_spec.js b/spec/frontend/flash_spec.js index e26c52f0bf7..a809bf248bf 100644 --- a/spec/frontend/flash_spec.js +++ b/spec/frontend/flash_spec.js @@ -285,6 +285,13 @@ describe('Flash', () => { expect(document.querySelector('.gl-alert')).toBeNull(); }); + it('does not crash if calling .dismiss() twice', () => { + alert = createAlert({ message: mockMessage }); + + alert.dismiss(); + expect(() => alert.dismiss()).not.toThrow(); + }); + it('calls onDismiss when dismissed', () => { const dismissHandler = jest.fn(); diff --git a/spec/graphql/types/branch_rule_type_spec.rb b/spec/graphql/types/branch_rule_type_spec.rb index 277901f00bf..12a2c8dfe12 100644 --- a/spec/graphql/types/branch_rule_type_spec.rb +++ b/spec/graphql/types/branch_rule_type_spec.rb @@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['BranchRule'] do let(:fields) do %i[ name + isDefault branch_protection created_at updated_at diff --git a/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb b/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb new file mode 100644 index 00000000000..98939e15952 --- /dev/null +++ b/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::UpdateCiPipelineArtifactsUnknownLockedStatus do + describe '#perform' do + let(:batch_table) { :ci_pipeline_artifacts } + let(:batch_column) { :id } + + let(:sub_batch_size) { 1 } + let(:pause_ms) { 0 } + let(:connection) { Ci::ApplicationRecord.connection } + + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:pipelines) { table(:ci_pipelines, database: :ci) } + let(:pipeline_artifacts) { table(:ci_pipeline_artifacts, database: :ci) } + + let(:namespace) { namespaces.create!(name: 'name', path: 'path') } + let(:project) do + projects + .create!(name: "project", path: "project", namespace_id: namespace.id, project_namespace_id: namespace.id) + end + + let(:unlocked) { 0 } + let(:locked) { 1 } + let(:unknown) { 2 } + + let(:unlocked_pipeline) { pipelines.create!(locked: unlocked) } + let(:locked_pipeline) { pipelines.create!(locked: locked) } + + # rubocop:disable Layout/LineLength + let!(:locked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: locked_pipeline.id, size: 1024, file_type: 0, file_format: 'gzip', file: 'a.gz', locked: unknown) } + let!(:unlocked_artifact_1) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 2048, file_type: 1, file_format: 'raw', file: 'b', locked: unknown) } + let!(:unlocked_artifact_2) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 4096, file_type: 2, file_format: 'gzip', file: 'c.gz', locked: unknown) } + let!(:already_unlocked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 8192, file_type: 3, file_format: 'raw', file: 'd', locked: unlocked) } + let!(:already_locked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: locked_pipeline.id, size: 8192, file_type: 3, file_format: 'raw', file: 'd', locked: locked) } + # rubocop:enable Layout/LineLength + + subject do + described_class.new( + start_id: locked_artifact.id, + end_id: already_locked_artifact.id, + batch_table: batch_table, + batch_column: batch_column, + sub_batch_size: sub_batch_size, + pause_ms: pause_ms, + connection: connection + ).perform + end + + it 'updates ci_pipeline_artifacts with unknown lock status' do + subject + + expect(locked_artifact.reload.locked).to eq(locked) + expect(unlocked_artifact_1.reload.locked).to eq(unlocked) + expect(unlocked_artifact_2.reload.locked).to eq(unlocked) + expect(already_unlocked_artifact.reload.locked).to eq(unlocked) + expect(already_locked_artifact.reload.locked).to eq(locked) + end + end +end diff --git a/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb b/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb new file mode 100644 index 00000000000..7e3f8caa966 --- /dev/null +++ b/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleUpdateCiPipelineArtifactsLockedStatus, migration: :gitlab_ci do + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background jobs for each batch of ci_pipeline_artifacts' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + gitlab_schema: :gitlab_ci, + table_name: :ci_pipeline_artifacts, + column_name: :id, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb index e904463a5ca..16cff72db64 100644 --- a/spec/models/ci/build_metadata_spec.rb +++ b/spec/models/ci/build_metadata_spec.rb @@ -14,8 +14,8 @@ RSpec.describe Ci::BuildMetadata do status: 'success') end - let(:build) { create(:ci_build, pipeline: pipeline) } - let(:metadata) { build.metadata } + let(:job) { create(:ci_build, pipeline: pipeline) } + let(:metadata) { job.metadata } it_behaves_like 'having unique enum values' @@ -35,7 +35,7 @@ RSpec.describe Ci::BuildMetadata do context 'when project timeout is set' do context 'when runner is assigned to the job' do before do - build.update!(runner: runner) + job.update!(runner: runner) end context 'when runner timeout is not set' do @@ -59,13 +59,13 @@ RSpec.describe Ci::BuildMetadata do context 'when job timeout is set' do context 'when job timeout is higher than project timeout' do - let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) } + let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) } it_behaves_like 'sets timeout', 'job_timeout_source', 3000 end context 'when job timeout is lower than project timeout' do - let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1000 }) } + let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1000 }) } it_behaves_like 'sets timeout', 'job_timeout_source', 1000 end @@ -73,18 +73,18 @@ RSpec.describe Ci::BuildMetadata do context 'when both runner and job timeouts are set' do before do - build.update!(runner: runner) + job.update!(runner: runner) end context 'when job timeout is higher than runner timeout' do - let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) } + let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) } let(:runner) { create(:ci_runner, maximum_timeout: 2100) } it_behaves_like 'sets timeout', 'runner_timeout_source', 2100 end context 'when job timeout is lower than runner timeout' do - let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1900 }) } + let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1900 }) } let(:runner) { create(:ci_runner, maximum_timeout: 2100) } it_behaves_like 'sets timeout', 'job_timeout_source', 1900 @@ -135,20 +135,51 @@ RSpec.describe Ci::BuildMetadata do describe 'set_cancel_gracefully' do it 'sets cancel_gracefully' do - build.set_cancel_gracefully + job.set_cancel_gracefully - expect(build.cancel_gracefully?).to be true + expect(job.cancel_gracefully?).to be true end it 'returns false' do - expect(build.cancel_gracefully?).to be false + expect(job.cancel_gracefully?).to be false end end context 'loose foreign key on ci_builds_metadata.project_id' do it_behaves_like 'cleanup by a loose foreign key' do - let!(:parent) { create(:project) } - let!(:model) { create(:ci_build_metadata, project: parent) } + let!(:parent) { project } + let!(:model) { metadata } + end + end + + describe 'partitioning' do + context 'with job' do + let(:status) { build(:commit_status, partition_id: 123) } + let(:metadata) { build(:ci_build_metadata, build: status) } + + it 'copies the partition_id from job' do + expect { metadata.valid? }.to change(metadata, :partition_id).to(123) + end + + context 'when it is already set' do + let(:metadata) { build(:ci_build_metadata, build: status, partition_id: 125) } + + it 'does not change the partition_id value' do + expect { metadata.valid? }.not_to change(metadata, :partition_id) + end + end + end + + context 'without job' do + subject(:metadata) do + build(:ci_build_metadata, build: nil) + end + + it { is_expected.to validate_presence_of(:partition_id) } + + it 'does not change the partition_id value' do + expect { metadata.valid? }.not_to change(metadata, :partition_id) + end end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 41b817f231b..52142278c15 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -320,10 +320,10 @@ RSpec.describe Ci::Build do let(:artifact_scope) { Ci::JobArtifact.where(file_type: 'archive') } - let!(:build_1) { create(:ci_build, :artifacts) } - let!(:build_2) { create(:ci_build, :codequality_reports) } - let!(:build_3) { create(:ci_build, :test_reports) } - let!(:build_4) { create(:ci_build, :artifacts) } + let!(:build_1) { create(:ci_build, :artifacts, pipeline: pipeline) } + let!(:build_2) { create(:ci_build, :codequality_reports, pipeline: pipeline) } + let!(:build_3) { create(:ci_build, :test_reports, pipeline: pipeline) } + let!(:build_4) { create(:ci_build, :artifacts, pipeline: pipeline) } it 'returns artifacts matching the given scope' do expect(builds).to contain_exactly(build_1, build_4) diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 3fc1883c1e6..8bf32527342 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -5488,7 +5488,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do end describe 'partitioning' do - let(:pipeline) { build(:ci_pipeline) } + let(:pipeline) { build(:ci_pipeline, partition_id: nil) } before do allow(described_class).to receive(:current_partition_value) { 123 } diff --git a/spec/models/concerns/ci/partitionable_spec.rb b/spec/models/concerns/ci/partitionable_spec.rb new file mode 100644 index 00000000000..d53501ccc3d --- /dev/null +++ b/spec/models/concerns/ci/partitionable_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Partitionable do + describe 'partitionable models inclusion' do + let(:ci_model) { Class.new(Ci::ApplicationRecord) } + + subject { ci_model.include(described_class) } + + it 'raises an exception' do + expect { subject } + .to raise_error(/must be included in PARTITIONABLE_MODELS/) + end + + context 'when is included in the models list' do + before do + stub_const("#{described_class}::Testing::PARTITIONABLE_MODELS", [ci_model.name]) + end + + it 'does not raise exceptions' do + expect { subject }.not_to raise_error + end + end + end +end diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index 54a90ca6049..b88367b9ca2 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -435,4 +435,28 @@ RSpec.describe ProtectedBranch do expect(described_class.downcase_humanized_name).to eq 'protected branch' end end + + describe '.default_branch?' do + before do + allow(subject.project).to receive(:default_branch).and_return(branch) + end + + context 'when the name matches the default branch' do + let(:branch) { subject.name } + + it { is_expected.to be_default_branch } + end + + context 'when the name does not match the default branch' do + let(:branch) { "#{subject.name}qwerty" } + + it { is_expected.not_to be_default_branch } + end + + context 'when a wildcard name matches the default branch' do + let(:branch) { "#{subject.name}*" } + + it { is_expected.not_to be_default_branch } + end + end end diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb index 70fb37941e2..1aaf0e9edc7 100644 --- a/spec/requests/api/graphql/project/branch_rules_spec.rb +++ b/spec/requests/api/graphql/project/branch_rules_spec.rb @@ -21,27 +21,24 @@ RSpec.describe 'getting list of branch rules for a project' do let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') } let(:variables) { { path: project.full_path } } - - let(:fields) do - <<~QUERY - pageInfo { - hasNextPage - hasPreviousPage - } - edges { - cursor - node { - #{all_graphql_fields_for('branch_rules'.classify)} - } - } - QUERY - end - + # fields must use let as the all_graphql_fields_for also configures some spies + let(:fields) { all_graphql_fields_for('BranchRule') } let(:query) do <<~GQL query($path: ID!, $n: Int, $cursor: String) { project(fullPath: $path) { - branchRules(first: $n, after: $cursor) { #{fields} } + branchRules(first: $n, after: $cursor) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + cursor + node { + #{fields} + } + } + } } } GQL @@ -55,7 +52,9 @@ RSpec.describe 'getting list of branch rules for a project' do it_behaves_like 'a working graphql query' - it { expect(branch_rules_data).to be_empty } + it 'hides branch rules data' do + expect(branch_rules_data).to be_empty + end end context 'when the user does have read_protected_branch abilities' do @@ -66,12 +65,17 @@ RSpec.describe 'getting list of branch rules for a project' do it_behaves_like 'a working graphql query' - it 'includes a name' do + it 'returns branch rules data' do expect(branch_rules_data.dig(0, 'node', 'name')).to be_present - end - - it 'includes created_at and updated_at' do + expect(branch_rules_data.dig(0, 'node', 'isDefault')).to be(true).or be(false) + expect(branch_rules_data.dig(0, 'node', 'branchProtection')).to be_present expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present + expect(branch_rules_data.dig(0, 'node', 'updatedAt')).to be_present + + expect(branch_rules_data.dig(1, 'node', 'name')).to be_present + expect(branch_rules_data.dig(1, 'node', 'isDefault')).to be(true).or be(false) + expect(branch_rules_data.dig(1, 'node', 'branchProtection')).to be_present + expect(branch_rules_data.dig(1, 'node', 'createdAt')).to be_present expect(branch_rules_data.dig(1, 'node', 'updatedAt')).to be_present end @@ -82,16 +86,16 @@ RSpec.describe 'getting list of branch rules for a project' do { path: project.full_path, n: branch_rule_limit, cursor: last_cursor } end - it_behaves_like 'a working graphql query' do - it 'only returns N branch_rules' do - expect(branch_rules_data.size).to eq(branch_rule_limit) - expect(has_next_page).to be_truthy - expect(has_prev_page).to be_falsey - post_graphql(query, current_user: current_user, variables: next_variables) - expect(branch_rules_data.size).to eq(branch_rule_limit) - expect(has_next_page).to be_falsey - expect(has_prev_page).to be_truthy - end + it_behaves_like 'a working graphql query' + + it 'returns pagination information' do + expect(branch_rules_data.size).to eq(branch_rule_limit) + expect(has_next_page).to be_truthy + expect(has_prev_page).to be_falsey + post_graphql(query, current_user: current_user, variables: next_variables) + expect(branch_rules_data.size).to eq(branch_rule_limit) + expect(has_next_page).to be_falsey + expect(has_prev_page).to be_truthy end context 'when no limit is provided' do diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb index a2259f9813b..030ba84951e 100644 --- a/spec/services/ci/job_artifacts/create_service_spec.rb +++ b/spec/services/ci/job_artifacts/create_service_spec.rb @@ -182,7 +182,8 @@ RSpec.describe Ci::JobArtifacts::CreateService do end context 'with job partitioning' do - let(:job) { create(:ci_build, project: project, partition_id: 123) } + let(:pipeline) { create(:ci_pipeline, project: project, partition_id: 123) } + let(:job) { create(:ci_build, pipeline: pipeline) } it 'sets partition_id on artifacts' do expect { subject }.to change { Ci::JobArtifact.count } diff --git a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb index 29b0f73e3c1..0843a983b7e 100644 --- a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb +++ b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb @@ -62,5 +62,25 @@ RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXml do end end end + + context 'when data values has unexpected keys' do + let(:data) do + { + filelists: described_class::ALLOWED_DATA_VALUE_KEYS.each_with_object({}) do |key, result| + result[:"#{key}-wrong"] = { value: 'value' } + end + } + end + + it 'ignores wrong keys' do + result = Nokogiri::XML::Document.parse(subject).remove_namespaces! + + data.each do |tag_name, tag_attributes| + tag_attributes.each_key do |key| + expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).to be_nil + end + end + end + end end end diff --git a/spec/support/models/partitionable_check.rb b/spec/support/models/partitionable_check.rb new file mode 100644 index 00000000000..2c09c1b3408 --- /dev/null +++ b/spec/support/models/partitionable_check.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module PartitioningTesting + module CascadeCheck + extend ActiveSupport::Concern + + included do + after_create :check_partition_cascade_value + end + + def check_partition_cascade_value + raise 'Partition value not found' unless partition_scope_value + raise 'Default value detected' if partition_id == 100 + + return if partition_id == partition_scope_value + + raise "partition_id was expected to equal #{partition_scope_value} but it was #{partition_id}." + end + end + + module DefaultPartitionValue + extend ActiveSupport::Concern + + class_methods do + def current_partition_value + current = super + + if current == 100 + 54321 + else + current + end + end + end + end +end + +Ci::Partitionable::Testing::PARTITIONABLE_MODELS.each do |klass| + model = klass.safe_constantize + + if klass == 'Ci::Pipeline' + model.prepend(PartitioningTesting::DefaultPartitionValue) + else + model.include(PartitioningTesting::CascadeCheck) + end +end diff --git a/spec/views/registrations/welcome/show.html.haml_spec.rb b/spec/views/registrations/welcome/show.html.haml_spec.rb index d9c5d348e15..99d87ac449b 100644 --- a/spec/views/registrations/welcome/show.html.haml_spec.rb +++ b/spec/views/registrations/welcome/show.html.haml_spec.rb @@ -11,6 +11,7 @@ RSpec.describe 'registrations/welcome/show' do allow(view).to receive(:in_trial_flow?).and_return(false) allow(view).to receive(:user_has_memberships?).and_return(false) allow(view).to receive(:in_oauth_flow?).and_return(false) + allow(view).to receive(:glm_tracking_params).and_return({}) render end |