summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
blob: 2f3d44f6f8ff9f8b4c1557f2c49536db0a3f4692 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freeze_time do
  include Gitlab::Database::MigrationHelpers
  include Database::MigrationTestingHelpers

  let(:result_dir) { Dir.mktmpdir }

  after do
    FileUtils.rm_rf(result_dir)
  end

  let(:migration) do
    ActiveRecord::Migration.new.extend(Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers)
  end

  let(:connection) { ApplicationRecord.connection }

  let(:table_name) { "_test_column_copying"}

  before do
    connection.execute(<<~SQL)
      CREATE TABLE #{table_name} (
        id bigint primary key not null,
        data bigint
      );

      insert into #{table_name} (id) select i from generate_series(1, 1000) g(i);
    SQL

    allow(migration).to receive(:transaction_open?).and_return(false)
  end

  context 'running a real background migration' do
    it 'runs sampled jobs from the batched background migration' do
      migration.queue_batched_background_migration('CopyColumnUsingBackgroundMigrationJob',
                                         table_name, :id,
                                         :id, :data,
                                         batch_size: 100,
                                         job_interval: 5.minutes) # job_interval is skipped when testing
      described_class.new(result_dir: result_dir, connection: connection).run_jobs(for_duration: 1.minute)
      unmigrated_row_count = define_batchable_model(table_name).where('id != data').count

      expect(unmigrated_row_count).to eq(0)
    end
  end

  context 'with jobs to run' do
    let(:migration_name) { 'TestBackgroundMigration' }

    before do
      migration.queue_batched_background_migration(
        migration_name, table_name, :id, job_interval: 5.minutes, batch_size: 100
      )
    end

    it 'samples jobs' do
      calls = []
      define_background_migration(migration_name) do |*args|
        calls << args
      end

      described_class.new(result_dir: result_dir, connection: connection).run_jobs(for_duration: 3.minutes)

      expect(calls.count).to eq(10) # 1000 rows / batch size 100 = 10
    end

    context 'with multiple jobs to run' do
      it 'runs all jobs created within the last 48 hours' do
        old_migration = define_background_migration(migration_name)

        travel 3.days

        new_migration = define_background_migration('NewMigration') { travel 1.second }
        migration.queue_batched_background_migration('NewMigration', table_name, :id,
                                           job_interval: 5.minutes,
                                           batch_size: 10,
                                           sub_batch_size: 5)

        other_new_migration = define_background_migration('NewMigration2') { travel 2.seconds }
        migration.queue_batched_background_migration('NewMigration2', table_name, :id,
                                           job_interval: 5.minutes,
                                           batch_size: 10,
                                           sub_batch_size: 5)

        expect_migration_runs(new_migration => 3, other_new_migration => 2, old_migration => 0) do
          described_class.new(result_dir: result_dir, connection: connection).run_jobs(for_duration: 5.seconds)
        end
      end
    end
  end
end