summaryrefslogtreecommitdiff
path: root/spec/finders/concerns/finder_with_cross_project_access_spec.rb
blob: 0798528c20077354ef292511b9e0ae044370eca4 (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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe FinderWithCrossProjectAccess do
  let(:finder_class) do
    Class.new do
      prepend FinderWithCrossProjectAccess
      include FinderMethods

      requires_cross_project_access if: -> { requires_access? }

      attr_reader :current_user

      def initialize(user)
        @current_user = user
      end

      def execute
        Issue.all
      end
    end
  end

  let(:user) { create(:user) }
  subject(:finder) { finder_class.new(user) }

  let!(:result) { create(:issue) }

  before do
    result.project.add_maintainer(user)
  end

  def expect_access_check_on_result
    expect(finder).not_to receive(:requires_access?)
    expect(Ability).to receive(:allowed?).with(user, :read_issue, result).and_call_original
  end

  context 'when the user cannot read cross project' do
    before do
      allow(Ability).to receive(:allowed?).and_call_original
      allow(Ability).to receive(:allowed?).with(user, :read_cross_project)
                          .and_return(false)
    end

    describe '#execute' do
      it 'returns a issue if the check is disabled' do
        expect(finder).to receive(:requires_access?).and_return(false)

        expect(finder.execute).to include(result)
      end

      it 'returns an empty relation when the check is enabled' do
        expect(finder).to receive(:requires_access?).and_return(true)

        expect(finder.execute).to be_empty
      end

      it 'only queries once when check is enabled' do
        expect(finder).to receive(:requires_access?).and_return(true)

        expect { finder.execute }.not_to exceed_query_limit(1)
      end

      it 'only queries once when check is disabled' do
        expect(finder).to receive(:requires_access?).and_return(false)

        expect { finder.execute }.not_to exceed_query_limit(1)
      end
    end

    describe '#find' do
      it 'checks the accessibility of the subject directly' do
        expect_access_check_on_result

        finder.find(result.id)
      end

      it 'returns the issue' do
        expect(finder.find(result.id)).to eq(result)
      end
    end

    describe '#find_by' do
      it 'checks the accessibility of the subject directly' do
        expect_access_check_on_result

        finder.find_by(id: result.id)
      end
    end

    describe '#find_by!' do
      it 'checks the accessibility of the subject directly' do
        expect_access_check_on_result

        finder.find(result.id)
      end

      it 're-enables the check after the find failed' do
        finder.find(non_existing_record_id) rescue ActiveRecord::RecordNotFound

        expect(finder.instance_variable_get(:@should_skip_cross_project_check))
          .to eq(false)
      end
    end
  end

  context 'when the user can read cross project' do
    before do
      allow(Ability).to receive(:allowed?).and_call_original
      allow(Ability).to receive(:allowed?).with(user, :read_cross_project)
                          .and_return(true)
    end

    it 'returns the result' do
      expect(finder).not_to receive(:requires_access?)

      expect(finder.execute).to include(result)
    end
  end

  context 'when specifying a model' do
    let(:finder_class) do
      Class.new do
        prepend FinderWithCrossProjectAccess

        requires_cross_project_access model: Project
      end
    end

    describe '.finder_model' do
      it 'is set correctly' do
        expect(finder_class.finder_model).to eq(Project)
      end
    end
  end
end