File: lfs_objects_project_spec.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (136 lines) | stat: -rw-r--r-- 4,332 bytes parent folder | download
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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe LfsObjectsProject do
  let_it_be(:project) { create(:project) }

  subject(:lfs_objects_project) do
    create(:lfs_objects_project, project: project)
  end

  describe 'associations' do
    it { is_expected.to belong_to(:project) }
    it { is_expected.to belong_to(:lfs_object) }
  end

  describe 'validations' do
    it { is_expected.to validate_presence_of(:lfs_object_id) }
    it { is_expected.to validate_presence_of(:project_id) }

    it 'validates object id' do
      is_expected.to validate_uniqueness_of(:lfs_object_id)
        .scoped_to(:project_id, :repository_type)
        .with_message("already exists in repository")
    end
  end

  describe '#ensure_uniqueness' do
    let(:lfs_object) { create(:lfs_object) }

    subject(:lfs_objects_project) do
      build(:lfs_objects_project, project: project, lfs_object: lfs_object)
    end

    context 'when project_id is nil' do
      before do
        lfs_objects_project.project_id = nil
      end

      it 'does not execute advisory lock' do
        expect(lfs_objects_project.connection).not_to receive(:execute)
        lfs_objects_project.send(:ensure_uniqueness)
      end
    end

    context 'when lfs_object_id is nil' do
      before do
        lfs_objects_project.lfs_object_id = nil
      end

      it 'does not execute advisory lock' do
        expect(lfs_objects_project.connection).not_to receive(:execute)
        lfs_objects_project.send(:ensure_uniqueness)
      end
    end

    context 'when repository_type is nil' do
      before do
        lfs_objects_project.repository_type = nil
      end

      it 'executes advisory lock' do
        expect(lfs_objects_project.connection).to receive(:execute).with(/SELECT pg_advisory_xact_lock/)
        lfs_objects_project.send(:ensure_uniqueness)
      end

      it 'uses correct lock key' do
        lock_key = <<~LOCK_KEY.chomp
          #{lfs_objects_project.project_id}-#{lfs_objects_project.lfs_object_id}-null
        LOCK_KEY

        expect(lfs_objects_project.connection).to receive(:execute).with(/hashtext\('#{lock_key}'\)/)
        lfs_objects_project.send(:ensure_uniqueness)
      end
    end

    context 'when all conditions are met' do
      it 'executes advisory lock' do
        expect(lfs_objects_project.connection).to receive(:execute).with(/SELECT pg_advisory_xact_lock/)
        lfs_objects_project.send(:ensure_uniqueness)
      end

      it 'uses correct lock key' do
        lock_key = <<~LOCK_KEY.chomp
          #{lfs_objects_project.project_id}-#{lfs_objects_project.lfs_object_id}-#{lfs_objects_project.repository_type}
        LOCK_KEY

        expect(lfs_objects_project.connection).to receive(:execute).with(/hashtext\('#{lock_key}'\)/)
        lfs_objects_project.send(:ensure_uniqueness)
      end
    end
  end

  describe '#link_to_project!' do
    it 'does not throw error when duplicate exists' do
      lfs_objects_project

      expect do
        result = described_class.link_to_project!(lfs_objects_project.lfs_object, lfs_objects_project.project)
        expect(result).to be_a(described_class)
      end.not_to change { described_class.count }
    end

    it 'upserts a new entry and updates the project cache' do
      new_project = create(:project)

      allow(ProjectCacheWorker).to receive(:perform_async).and_call_original
      expect(ProjectCacheWorker).to receive(:perform_async).with(new_project.id, [], [:lfs_objects_size])
      expect { described_class.link_to_project!(lfs_objects_project.lfs_object, new_project) }
        .to change { described_class.count }

      expect(described_class.find_by(
        lfs_object_id: lfs_objects_project.lfs_object.id,
        project_id: new_project.id
      )).to be_present
    end
  end

  describe '#update_project_statistics' do
    it 'updates project statistics when the object is added' do
      expect(ProjectCacheWorker).to receive(:perform_async)
        .with(project.id, [], [:lfs_objects_size])

      lfs_objects_project.save!
    end

    it 'lfs_objects_project project statistics when the object is removed' do
      lfs_objects_project.save!

      expect(ProjectCacheWorker).to receive(:perform_async)
        .with(project.id, [], [:lfs_objects_size])

      lfs_objects_project.destroy!
    end
  end
end