Read about our upcoming Code of Conduct on this issue

search_results_spec.rb 10.9 KB
Newer Older
1
2
3
require 'spec_helper'

describe Gitlab::SearchResults do
4
5
  include ProjectForksHelper

6
  let(:user) { create(:user) }
7
  let!(:project) { create(:project, name: 'foo') }
8
9
10
11
12
13
14
  let!(:issue) { create(:issue, project: project, title: 'foo') }

  let!(:merge_request) do
    create(:merge_request, source_project: project, title: 'foo')
  end

  let!(:milestone) { create(:milestone, project: project, title: 'foo') }
15
  let(:results) { described_class.new(user, Project.all, 'foo') }
16

17
18
  context 'as a user with access' do
    before do
19
      project.add_developer(user)
20
21
    end

22
    describe '#objects' do
Jarka Kadlecová's avatar
Jarka Kadlecová committed
23
      it 'returns without_counts collection by default' do
24
25
        expect(results.objects('projects')).to be_kind_of(Kaminari::PaginatableWithoutCount)
      end
Jarka Kadlecová's avatar
Jarka Kadlecová committed
26
27
28
29

      it 'returns with counts collection when requested' do
        expect(results.objects('projects', 1, false)).not_to be_kind_of(Kaminari::PaginatableWithoutCount)
      end
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
    end

    context "when count_limit is lower than total amount" do
      before do
        allow(results).to receive(:count_limit).and_return(1)
      end

      describe '#limited_projects_count' do
        it 'returns the limited amount of projects' do
          create(:project, name: 'foo2')

          expect(results.limited_projects_count).to eq(1)
        end
      end

      describe '#limited_merge_requests_count' do
        it 'returns the limited amount of merge requests' do
          create(:merge_request, :simple, source_project: project, title: 'foo2')

          expect(results.limited_merge_requests_count).to eq(1)
        end
      end

      describe '#limited_milestones_count' do
        it 'returns the limited amount of milestones' do
          create(:milestone, project: project, title: 'foo2')

          expect(results.limited_milestones_count).to eq(1)
        end
      end

      describe '#limited_issues_count' do
        it 'runs single SQL query to get the limited amount of issues' do
          create(:milestone, project: project, title: 'foo2')

          expect(results).to receive(:issues).with(public_only: true).and_call_original
          expect(results).not_to receive(:issues).with(no_args).and_call_original

          expect(results.limited_issues_count).to eq(1)
        end
      end
    end

    context "when count_limit is higher than total amount" do
      describe '#limited_issues_count' do
        it 'runs multiple queries to get the limited amount of issues' do
          expect(results).to receive(:issues).with(public_only: true).and_call_original
          expect(results).to receive(:issues).with(no_args).and_call_original

          expect(results.limited_issues_count).to eq(1)
        end
      end
    end

84
    it 'includes merge requests from source and target projects' do
85
      forked_project = fork_project(project, user)
86
87
88
89
90
91
      merge_request_2 = create(:merge_request, target_project: project, source_project: forked_project, title: 'foo')

      results = described_class.new(user, Project.where(id: forked_project.id), 'foo')

      expect(results.objects('merge_requests')).to include merge_request_2
    end
92

93
94
95
96
97
98
99
    describe '#merge_requests' do
      it 'includes project filter by default' do
        expect(results).to receive(:project_ids_relation).and_call_original

        results.objects('merge_requests')
      end

100
      it 'skips project filter if default project context is used' do
101
102
103
104
105
106
        allow(results).to receive(:default_project_filter).and_return(true)

        expect(results).not_to receive(:project_ids_relation)

        results.objects('merge_requests')
      end
107
108
    end

109
110
111
112
113
114
115
    describe '#issues' do
      it 'includes project filter by default' do
        expect(results).to receive(:project_ids_relation).and_call_original

        results.objects('issues')
      end

116
      it 'skips project filter if default project context is used' do
117
118
119
120
121
122
        allow(results).to receive(:default_project_filter).and_return(true)

        expect(results).not_to receive(:project_ids_relation)

        results.objects('issues')
      end
123
    end
124
125

    describe '#users' do
126
127
128
129
130
131
132
133
      it 'does not call the UsersFinder when the current_user is not allowed to read users list' do
        allow(Ability).to receive(:allowed?).and_return(false)

        expect(UsersFinder).not_to receive(:new).with(user, search: 'foo').and_call_original

        results.objects('users')
      end

134
135
136
137
138
139
      it 'calls the UsersFinder' do
        expect(UsersFinder).to receive(:new).with(user, search: 'foo').and_call_original

        results.objects('users')
      end
    end
140
141
  end

142
  it 'does not list issues on private projects' do
143
    private_project = create(:project, :private)
144
145
146
147
148
    issue = create(:issue, project: private_project, title: 'foo')

    expect(results.objects('issues')).not_to include issue
  end

149
  describe 'confidential issues' do
150
151
152
153
    let(:project_1) { create(:project, :internal) }
    let(:project_2) { create(:project, :internal) }
    let(:project_3) { create(:project, :internal) }
    let(:project_4) { create(:project, :internal) }
154
155
156
157
158
159
160
161
162
    let(:query) { 'issue' }
    let(:limit_projects) { Project.where(id: [project_1.id, project_2.id, project_3.id]) }
    let(:author) { create(:user) }
    let(:assignee) { create(:user) }
    let(:non_member) { create(:user) }
    let(:member) { create(:user) }
    let(:admin) { create(:admin) }
    let!(:issue) { create(:issue, project: project_1, title: 'Issue 1') }
    let!(:security_issue_1) { create(:issue, :confidential, project: project_1, title: 'Security issue 1', author: author) }
163
    let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project_1, assignees: [assignee]) }
164
    let!(:security_issue_3) { create(:issue, :confidential, project: project_2, title: 'Security issue 3', author: author) }
165
    let!(:security_issue_4) { create(:issue, :confidential, project: project_3, title: 'Security issue 4', assignees: [assignee]) }
166
167
    let!(:security_issue_5) { create(:issue, :confidential, project: project_4, title: 'Security issue 5') }

168
    it 'does not list confidential issues for non project members' do
169
170
171
172
173
174
175
176
177
      results = described_class.new(non_member, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).not_to include security_issue_1
      expect(issues).not_to include security_issue_2
      expect(issues).not_to include security_issue_3
      expect(issues).not_to include security_issue_4
      expect(issues).not_to include security_issue_5
178
      expect(results.limited_issues_count).to eq 1
179
180
    end

181
    it 'does not list confidential issues for project members with guest role' do
182
183
      project_1.add_guest(member)
      project_2.add_guest(member)
184
185
186
187
188
189
190
191
192
193

      results = described_class.new(member, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).not_to include security_issue_1
      expect(issues).not_to include security_issue_2
      expect(issues).not_to include security_issue_3
      expect(issues).not_to include security_issue_4
      expect(issues).not_to include security_issue_5
194
      expect(results.limited_issues_count).to eq 1
195
196
    end

197
    it 'lists confidential issues for author' do
198
199
200
201
202
203
204
205
206
      results = described_class.new(author, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).to include security_issue_1
      expect(issues).not_to include security_issue_2
      expect(issues).to include security_issue_3
      expect(issues).not_to include security_issue_4
      expect(issues).not_to include security_issue_5
207
      expect(results.limited_issues_count).to eq 3
208
209
    end

210
    it 'lists confidential issues for assignee' do
211
212
213
214
215
216
217
218
219
      results = described_class.new(assignee, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).not_to include security_issue_1
      expect(issues).to include security_issue_2
      expect(issues).not_to include security_issue_3
      expect(issues).to include security_issue_4
      expect(issues).not_to include security_issue_5
220
      expect(results.limited_issues_count).to eq 3
221
222
    end

223
    it 'lists confidential issues for project members' do
224
225
      project_1.add_developer(member)
      project_2.add_developer(member)
226
227
228
229
230
231
232
233
234
235

      results = described_class.new(member, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).to include security_issue_1
      expect(issues).to include security_issue_2
      expect(issues).to include security_issue_3
      expect(issues).not_to include security_issue_4
      expect(issues).not_to include security_issue_5
236
      expect(results.limited_issues_count).to eq 4
237
238
    end

239
    it 'lists all issues for admin' do
240
241
242
243
244
245
246
247
248
      results = described_class.new(admin, limit_projects, query)
      issues = results.objects('issues')

      expect(issues).to include issue
      expect(issues).to include security_issue_1
      expect(issues).to include security_issue_2
      expect(issues).to include security_issue_3
      expect(issues).to include security_issue_4
      expect(issues).not_to include security_issue_5
249
      expect(results.limited_issues_count).to eq 5
250
251
    end
  end
252
253
254
255
256
257
258

  it 'does not list merge requests on projects with limited access' do
    project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
    project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE)

    expect(results.objects('merge_requests')).not_to include merge_request
  end
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

  context 'milestones' do
    it 'returns correct set of milestones' do
      private_project_1 = create(:project, :private)
      private_project_2 = create(:project, :private)
      internal_project = create(:project, :internal)
      public_project_1 = create(:project, :public)
      public_project_2 = create(:project, :public, :issues_disabled, :merge_requests_disabled)
      private_project_1.add_developer(user)
      # milestones that should not be visible
      create(:milestone, project: private_project_2, title: 'Private project without access milestone')
      create(:milestone, project: public_project_2, title: 'Public project with milestones disabled milestone')
      # milestones that should be visible
      milestone_1 = create(:milestone, project: private_project_1, title: 'Private project with access milestone', state: 'closed')
      milestone_2 = create(:milestone, project: internal_project, title: 'Internal project milestone')
      milestone_3 = create(:milestone, project: public_project_1, title: 'Public project with milestones enabled milestone')
      # Global search scope takes user authorized projects, internal projects and public projects.
      limit_projects = ProjectsFinder.new(current_user: user).execute

      milestones = described_class.new(user, limit_projects, 'milestone').objects('milestones')

      expect(milestones).to match_array([milestone_1, milestone_2, milestone_3])
    end
  end
283
end