1# frozen_string_literal: true 2 3require 'spec_helper' 4 5RSpec.describe Gitlab::Database::BackgroundMigrationJob do 6 it_behaves_like 'having unique enum values' 7 8 describe '.for_migration_execution' do 9 let!(:job1) { create(:background_migration_job) } 10 let!(:job2) { create(:background_migration_job, arguments: ['hi', 2]) } 11 let!(:job3) { create(:background_migration_job, class_name: 'OtherJob', arguments: ['hi', 2]) } 12 13 it 'returns jobs matching class_name and arguments' do 14 relation = described_class.for_migration_execution('TestJob', ['hi', 2]) 15 16 expect(relation.count).to eq(1) 17 expect(relation.first).to have_attributes(class_name: 'TestJob', arguments: ['hi', 2]) 18 end 19 20 it 'normalizes class names by removing leading ::' do 21 relation = described_class.for_migration_execution('::TestJob', ['hi', 2]) 22 23 expect(relation.count).to eq(1) 24 expect(relation.first).to have_attributes(class_name: 'TestJob', arguments: ['hi', 2]) 25 end 26 end 27 28 describe '.for_partitioning_migration' do 29 let!(:job1) { create(:background_migration_job, arguments: [1, 100, 'other_table']) } 30 let!(:job2) { create(:background_migration_job, arguments: [1, 100, 'audit_events']) } 31 let!(:job3) { create(:background_migration_job, class_name: 'OtherJob', arguments: [1, 100, 'audit_events']) } 32 33 it 'returns jobs matching class_name and the table_name job argument' do 34 relation = described_class.for_partitioning_migration('TestJob', 'audit_events') 35 36 expect(relation.count).to eq(1) 37 expect(relation.first).to have_attributes(class_name: 'TestJob', arguments: [1, 100, 'audit_events']) 38 end 39 40 it 'normalizes class names by removing leading ::' do 41 relation = described_class.for_partitioning_migration('::TestJob', 'audit_events') 42 43 expect(relation.count).to eq(1) 44 expect(relation.first).to have_attributes(class_name: 'TestJob', arguments: [1, 100, 'audit_events']) 45 end 46 end 47 48 describe '.mark_all_as_succeeded' do 49 let!(:job1) { create(:background_migration_job, arguments: [1, 100]) } 50 let!(:job2) { create(:background_migration_job, arguments: [1, 100]) } 51 let!(:job3) { create(:background_migration_job, arguments: [101, 200]) } 52 let!(:job4) { create(:background_migration_job, class_name: 'OtherJob', arguments: [1, 100]) } 53 54 it 'marks all matching jobs as succeeded' do 55 expect { described_class.mark_all_as_succeeded('TestJob', [1, 100]) } 56 .to change { described_class.succeeded.count }.from(0).to(2) 57 58 expect(job1.reload).to be_succeeded 59 expect(job2.reload).to be_succeeded 60 expect(job3.reload).to be_pending 61 expect(job4.reload).to be_pending 62 end 63 64 it 'normalizes class_names by removing leading ::' do 65 expect { described_class.mark_all_as_succeeded('::TestJob', [1, 100]) } 66 .to change { described_class.succeeded.count }.from(0).to(2) 67 68 expect(job1.reload).to be_succeeded 69 expect(job2.reload).to be_succeeded 70 expect(job3.reload).to be_pending 71 expect(job4.reload).to be_pending 72 end 73 74 it 'returns the number of jobs updated' do 75 expect(described_class.succeeded.count).to eq(0) 76 77 jobs_updated = described_class.mark_all_as_succeeded('::TestJob', [1, 100]) 78 79 expect(jobs_updated).to eq(2) 80 expect(described_class.succeeded.count).to eq(2) 81 end 82 83 context 'when previous matching jobs have already succeeded' do 84 let(:initial_time) { Time.now.round } 85 let!(:job1) { create(:background_migration_job, :succeeded, created_at: initial_time, updated_at: initial_time) } 86 87 it 'does not update non-pending jobs' do 88 travel_to(initial_time + 1.day) do 89 expect { described_class.mark_all_as_succeeded('TestJob', [1, 100]) } 90 .to change { described_class.succeeded.count }.from(1).to(2) 91 end 92 93 expect(job1.reload.updated_at).to eq(initial_time) 94 expect(job2.reload).to be_succeeded 95 expect(job3.reload).to be_pending 96 expect(job4.reload).to be_pending 97 end 98 end 99 end 100 101 describe '#class_name=' do 102 context 'when the class_name is given without the leading ::' do 103 it 'sets the class_name to the given value' do 104 job = described_class.new(class_name: 'TestJob') 105 106 expect(job.class_name).to eq('TestJob') 107 end 108 end 109 110 context 'when the class_name is given with the leading ::' do 111 it 'removes the leading :: when setting the class_name' do 112 job = described_class.new(class_name: '::TestJob') 113 114 expect(job.class_name).to eq('TestJob') 115 end 116 end 117 118 context 'when the value is nil' do 119 it 'sets the class_name to nil' do 120 job = described_class.new(class_name: nil) 121 122 expect(job.class_name).to be_nil 123 end 124 end 125 126 context 'when the values is blank' do 127 it 'sets the class_name to the given value' do 128 job = described_class.new(class_name: '') 129 130 expect(job.class_name).to eq('') 131 end 132 end 133 end 134end 135