summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/services/repositories/housekeeping_shared_examples.rb
blob: 8a9373037119ba3b34eacd6a5f1809988159c74e (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# frozen_string_literal: true

RSpec.shared_examples 'housekeeps repository' do
  subject { described_class.new(resource) }

  context 'with a clean redis state', :clean_gitlab_redis_shared_state, :aggregate_failures do
    describe '#execute' do
      it 'enqueues a sidekiq job' do
        expect(subject).to receive(:try_obtain_lease).and_return(:the_uuid)
        expect(subject).to receive(:lease_key).and_return(:the_lease_key)
        expect(subject).to receive(:task).and_return(:incremental_repack)
        expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :incremental_repack, :the_lease_key, :the_uuid).and_call_original

        Sidekiq::Testing.fake! do
          expect { subject.execute }.to change { resource.git_garbage_collect_worker_klass.jobs.size }.by(1)
        end
      end

      it 'yields the block if given' do
        expect do |block|
          subject.execute(&block)
        end.to yield_with_no_args
      end

      it 'resets counter after execution' do
        expect(subject).to receive(:try_obtain_lease).and_return(:the_uuid)
        allow(subject).to receive(:gc_period).and_return(1)
        resource.increment_pushes_since_gc

        perform_enqueued_jobs do
          expect { subject.execute }.to change { resource.pushes_since_gc }.to(0)
        end
      end

      context 'when no lease can be obtained' do
        before do
          expect(subject).to receive(:try_obtain_lease).and_return(false)
        end

        it 'does not enqueue a job' do
          expect(resource.git_garbage_collect_worker_klass).not_to receive(:perform_async)

          expect { subject.execute }.to raise_error(Repositories::HousekeepingService::LeaseTaken)
        end

        it 'does not reset pushes_since_gc' do
          expect do
            expect { subject.execute }.to raise_error(Repositories::HousekeepingService::LeaseTaken)
          end.not_to change { resource.pushes_since_gc }
        end

        it 'does not yield' do
          expect do |block|
            expect { subject.execute(&block) }
              .to raise_error(Repositories::HousekeepingService::LeaseTaken)
          end.not_to yield_with_no_args
        end
      end

      context 'task type' do
        it 'goes through all three housekeeping tasks, executing only the highest task when there is overlap' do
          allow(subject).to receive(:try_obtain_lease).and_return(:the_uuid)
          allow(subject).to receive(:lease_key).and_return(:the_lease_key)

          # At push 200
          expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :gc, :the_lease_key, :the_uuid)
            .once
          # At push 50, 100, 150
          expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :full_repack, :the_lease_key, :the_uuid)
            .exactly(3).times
          # At push 10, 20, ... (except those above)
          expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :incremental_repack, :the_lease_key, :the_uuid)
            .exactly(16).times

          201.times do
            subject.increment!
            subject.execute if subject.needed?
          end

          expect(resource.pushes_since_gc).to eq(1)
        end

        context 'when optimized_repository feature flag is disabled' do
          before do
            stub_feature_flags(optimized_housekeeping: false)
          end

          it 'calls also the garbage collect worker with pack_refs every 6 commits' do
            allow(subject).to receive(:try_obtain_lease).and_return(:the_uuid)
            allow(subject).to receive(:lease_key).and_return(:the_lease_key)

            # At push 200
            expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :gc, :the_lease_key, :the_uuid)
              .once
            # At push 50, 100, 150
            expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :full_repack, :the_lease_key, :the_uuid)
              .exactly(3).times
            # At push 10, 20, ... (except those above)
            expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :incremental_repack, :the_lease_key, :the_uuid)
              .exactly(16).times
            # At push 6, 12, 18, ... (except those above)
            expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :pack_refs, :the_lease_key, :the_uuid)
              .exactly(27).times

            201.times do
              subject.increment!
              subject.execute if subject.needed?
            end

            expect(resource.pushes_since_gc).to eq(1)
          end
        end
      end

      it 'runs the task specifically requested' do
        housekeeping = described_class.new(resource, :gc)

        allow(housekeeping).to receive(:try_obtain_lease).and_return(:gc_uuid)
        allow(housekeeping).to receive(:lease_key).and_return(:gc_lease_key)

        expect(resource.git_garbage_collect_worker_klass).to receive(:perform_async).with(resource.id, :gc, :gc_lease_key, :gc_uuid).twice

        2.times do
          housekeeping.execute
        end
      end
    end

    describe '#needed?' do
      it 'when the count is low enough' do
        expect(subject.needed?).to eq(false)
      end

      it 'when the count is high enough' do
        allow(resource).to receive(:pushes_since_gc).and_return(10)
        expect(subject.needed?).to eq(true)
      end

      context 'when optimized_housekeeping is disabled' do
        before do
          stub_feature_flags(optimized_housekeeping: false)
        end

        it 'returns true pack refs is needed' do
          allow(resource).to receive(:pushes_since_gc).and_return(described_class::PACK_REFS_PERIOD)
          expect(subject.needed?).to eq(true)
        end
      end
    end

    describe '#increment!' do
      it 'increments the pushes_since_gc counter' do
        expect { subject.increment! }.to change { resource.pushes_since_gc }.by(1)
      end
    end
  end
end