spec/lib/release_tools/security/merge_train_service_spec.rb (208 lines of code) (raw):

# frozen_string_literal: true require 'spec_helper' RSpec.describe ReleaseTools::Security::MergeTrainService do let(:client) { ReleaseTools::GitlabOpsClient } let(:project) { ReleaseTools::Project::GitlabEe } subject(:service) { described_class.new } def mirror_stub(overrides = {}) defaults = { enabled: true, last_error: nil, update_status: 'finished', url: 'https://*****:*****@gitlab.com/gitlab-org/security/gitlab' } double(defaults.merge(overrides)) end before do enable_feature(:internal_release_merge_train_stable_branches) end describe '#execute' do context 'when all branches need to be synced using merge-train' do before do # Stub the methods that are called within execute allow(service).to receive(:run_merge_train_default_branch) allow(service).to receive(:run_merge_train_stable_branches) end it 'calls run_merge_train_default_branch for each project with correct schedule_id' do without_dry_run do service.execute end described_class::PROJECTS.each do |project, schedule_id| expect(service).to have_received(:run_merge_train_default_branch) .with(project, schedule_id) end end it 'calls run_merge_train_stable_branches for each project' do without_dry_run do service.execute end described_class::PROJECTS_STABLE_BRANCHES.each_key do |project| expect(service).to have_received(:run_merge_train_stable_branches) .with(project, described_class::PROJECTS_STABLE_BRANCHES[project]) end end it 'processes all projects in PROJECTS' do without_dry_run do service.execute end expect(service).to have_received(:run_merge_train_default_branch) .exactly(described_class::PROJECTS.count).times expect(service).to have_received(:run_merge_train_stable_branches) .exactly(described_class::PROJECTS_STABLE_BRANCHES.count).times end context 'when required and inactive' do before do allow(service).to receive(:run_merge_train_default_branch).and_call_original allow(service).to receive_messages( merge_train_required?: true, merge_train_active?: false ) end it 'toggles on the merge-train pipeline schedule and notifies' do described_class::PROJECTS.each_value do |schedule_id| new_schedule = double expect(client).to receive(:pipeline_schedule_take_ownership).with( ReleaseTools::Project::MergeTrain, schedule_id ) expect(client).to receive(:edit_pipeline_schedule).with( ReleaseTools::Project::MergeTrain.ops_path, schedule_id, active: true, cron: described_class::CRON ).and_return(new_schedule) expect(ReleaseTools::Slack::MergeTrainNotification) .to receive(:toggled) .with(new_schedule) end without_dry_run do service.execute end end end context 'when not required and active' do before do allow(service).to receive(:run_merge_train_default_branch).and_call_original allow(service).to receive_messages( merge_train_required?: false, merge_train_active?: true ) end it 'toggles off the merge-train pipeline schedule and notifies' do described_class::PROJECTS.each_value do |schedule_id| new_schedule = double expect(client).to receive(:pipeline_schedule_take_ownership).with( ReleaseTools::Project::MergeTrain, schedule_id ) expect(client).to receive(:edit_pipeline_schedule).with( ReleaseTools::Project::MergeTrain.ops_path, schedule_id, active: false, cron: described_class::CRON ).and_return(new_schedule) expect(ReleaseTools::Slack::MergeTrainNotification) .to receive(:toggled) .with(new_schedule) end without_dry_run do service.execute end end end context 'when required and active' do before do allow(service).to receive(:run_merge_train_default_branch).and_call_original allow(service).to receive_messages( merge_train_required?: true, merge_train_active?: true ) end it 'does nothing' do expect(client).not_to receive(:pipeline_schedule_take_ownership) expect(client).not_to receive(:edit_pipeline_schedule) expect(ReleaseTools::Slack::MergeTrainNotification).not_to receive(:toggled) without_dry_run do service.execute end end end context 'when not required and inactive' do before do allow(service).to receive(:run_merge_train_default_branch).and_call_original allow(service).to receive_messages( merge_train_required?: false, merge_train_active?: false ) end it 'does nothing' do expect(client).not_to receive(:pipeline_schedule_take_ownership) expect(client).not_to receive(:edit_pipeline_schedule) expect(ReleaseTools::Slack::MergeTrainNotification).not_to receive(:toggled) without_dry_run do service.execute end end end context 'when the feature flag is disabled' do before do disable_feature(:internal_release_merge_train_stable_branches) end it 'does not call run_merge_train_stable_branches for each project' do without_dry_run do service.execute end expect(service).to have_received(:run_merge_train_default_branch).exactly(3).times expect(service).not_to have_received(:run_merge_train_stable_branches) end end end context 'when the default branches do not need to be synced using merge-train' do before do # Ignore the implementation of run_merge_train_stable_branches allow(service).to receive(:run_merge_train_stable_branches) described_class::PROJECTS.each_key do |project| allow(service).to receive(:merge_train_required?).with(project).and_return(false) end allow(service).to receive(:merge_train_active?).and_return(false) end it 'does not enable any merge-train schedule' do expect(service).not_to receive(:toggle_merge_train).with(anything, true) without_dry_run do service.execute end end end context 'when the stable branches do not need to be synced using merge-train' do let(:branches) { ['15-6-stable-ee', '15-5-stable-ee'] } let(:project) { ReleaseTools::Project::GitlabEe } before do # Ignore the implementation of run_merge_train_default_branch allow(service).to receive(:run_merge_train_default_branch) allow(service).to receive(:internal_release_stable_branches).and_return(branches) branches.each do |branch| allow(service).to receive(:merge_train_required?).with(project, branch: branch).and_return(false) allow(service).to receive(:merge_train_active?).and_return(false) end end it 'does not enable any merge-train schedule' do expect(service).not_to receive(:toggle_merge_train).with(anything, true) without_dry_run do service.execute end end end context 'when an error happens with getting remote mirrors' do let(:project) { ReleaseTools::Project::GitlabEe } before do allow(service).to receive(:run_merge_train_stable_branches) described_class::PROJECTS.each_key do |project| allow(service).to receive(:get_remote_mirrors).with(project).and_raise(Gitlab::Error::Error) end allow(service).to receive(:merge_train_active?).and_return(false) end it 'does not enable any merge-train schedule' do expect(service).not_to receive(:toggle_merge_train).with(anything, true) without_dry_run do service.execute end end end end end