merge_requests_finder_spec.rb 14.8 KB
Newer Older
1 2 3
require 'spec_helper'

describe MergeRequestsFinder do
B
Bob Van Landuyt 已提交
4 5
  include ProjectForksHelper

6 7 8 9 10 11 12 13 14 15
  # We need to explicitly permit Gitaly N+1s because of the specs that use
  # :request_store. Gitaly N+1 detection is only enabled when :request_store is,
  # but we don't care about potential N+1s when we're just creating several
  # projects in the setup phase.
  def create_project_without_n_plus_1(*args)
    Gitlab::GitalyClient.allow_n_plus_1_calls do
      create(:project, :public, *args)
    end
  end

16 17 18 19 20 21 22 23 24 25 26
  context "multiple projects with merge requests" do
    let(:user)  { create :user }
    let(:user2) { create :user }

    let(:group) { create(:group) }
    let(:subgroup) { create(:group, parent: group) }
    let(:project1) { create_project_without_n_plus_1(group: group) }
    let(:project2) do
      Gitlab::GitalyClient.allow_n_plus_1_calls do
        fork_project(project1, user)
      end
27
    end
28 29 30 31 32 33
    let(:project3) do
      Gitlab::GitalyClient.allow_n_plus_1_calls do
        p = fork_project(project1, user)
        p.update!(archived: true)
        p
      end
34
    end
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    let(:project4) { create_project_without_n_plus_1(:repository, group: subgroup) }
    let(:project5) { create_project_without_n_plus_1(group: subgroup) }
    let(:project6) { create_project_without_n_plus_1(group: subgroup) }

    let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
    let!(:merge_request2) { create(:merge_request, :conflict, author: user, source_project: project2, target_project: project1, state: 'closed') }
    let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2, state: 'locked', title: 'thing WIP thing') }
    let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3, title: 'WIP thing') }
    let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4, title: '[WIP]') }
    let!(:merge_request6) { create(:merge_request, :simple, author: user, source_project: project5, target_project: project5, title: 'WIP: thing') }
    let!(:merge_request7) { create(:merge_request, :simple, author: user, source_project: project6, target_project: project6, title: 'wip thing') }
    let!(:merge_request8) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project1, title: '[wip] thing') }
    let!(:merge_request9) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project2, title: 'wip: thing') }

    before do
      project1.add_maintainer(user)
      project2.add_developer(user)
      project3.add_developer(user)
      project2.add_developer(user2)
      project4.add_developer(user)
      project5.add_developer(user)
      project6.add_developer(user)
57 58
    end

59 60 61 62 63 64
    describe '#execute' do
      it 'filters by scope' do
        params = { scope: 'authored', state: 'opened' }
        merge_requests = described_class.new(user, params).execute
        expect(merge_requests.size).to eq(7)
      end
65

66 67 68 69 70
      it 'filters by project' do
        params = { project_id: project1.id, scope: 'authored', state: 'opened' }
        merge_requests = described_class.new(user, params).execute
        expect(merge_requests.size).to eq(2)
      end
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85
      it 'filters by commit sha' do
        merge_requests = described_class.new(
          user,
          commit_sha: merge_request5.merge_request_diff.last_commit_sha
        ).execute

        expect(merge_requests).to contain_exactly(merge_request5)
      end

      context 'filtering by group' do
        it 'includes all merge requests when user has access' do
          params = { group_id: group.id }

          merge_requests = described_class.new(user, params).execute
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
          expect(merge_requests.size).to eq(3)
        end

        it 'excludes merge requests from projects the user does not have access to' do
          private_project = create_project_without_n_plus_1(:private, group: group)
          private_mr = create(:merge_request, :simple, author: user, source_project: private_project, target_project: private_project)
          params = { group_id: group.id }

          private_project.add_guest(user)
          merge_requests = described_class.new(user, params).execute

          expect(merge_requests.size).to eq(3)
          expect(merge_requests).not_to include(private_mr)
        end

        it 'filters by group including subgroups', :nested_groups do
          params = { group_id: group.id, include_subgroups: true }

          merge_requests = described_class.new(user, params).execute

          expect(merge_requests.size).to eq(6)
        end
      end

      it 'filters by non_archived' do
        params = { non_archived: true }
        merge_requests = described_class.new(user, params).execute
        expect(merge_requests.size).to eq(8)
      end

      it 'filters by iid' do
        params = { project_id: project1.id, iids: merge_request1.iid }
119

120
        merge_requests = described_class.new(user, params).execute
121

122
        expect(merge_requests).to contain_exactly(merge_request1)
123
      end
124

125 126
      it 'filters by source branch' do
        params = { source_branch: merge_request2.source_branch }
127

128 129
        merge_requests = described_class.new(user, params).execute

130
        expect(merge_requests).to contain_exactly(merge_request2)
131 132
      end

133 134
      it 'filters by target branch' do
        params = { target_branch: merge_request2.target_branch }
135 136

        merge_requests = described_class.new(user, params).execute
137

138
        expect(merge_requests).to contain_exactly(merge_request2)
139
      end
140

141 142
      it 'filters by state' do
        params = { state: 'locked' }
M
mhasbini 已提交
143

144
        merge_requests = described_class.new(user, params).execute
M
mhasbini 已提交
145

146 147
        expect(merge_requests).to contain_exactly(merge_request3)
      end
M
mhasbini 已提交
148

149 150
      it 'filters by wip' do
        params = { wip: 'yes' }
151

152
        merge_requests = described_class.new(user, params).execute
153

154 155
        expect(merge_requests).to contain_exactly(merge_request4, merge_request5, merge_request6, merge_request7, merge_request8, merge_request9)
      end
156

157 158
      it 'filters by not wip' do
        params = { wip: 'no' }
159

160
        merge_requests = described_class.new(user, params).execute
161

162 163
        expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3)
      end
164

165 166
      it 'returns all items if no valid wip param exists' do
        params = { wip: '' }
167

168
        merge_requests = described_class.new(user, params).execute
169

170 171
        expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request4, merge_request5, merge_request6, merge_request7, merge_request8, merge_request9)
      end
172

173 174
      it 'adds wip to scalar params' do
        scalar_params = described_class.scalar_params
175

176 177
        expect(scalar_params).to include(:wip, :assignee_id)
      end
178

179 180 181 182 183
      context 'filtering by group milestone' do
        let!(:group) { create(:group, :public) }
        let(:group_milestone) { create(:milestone, group: group) }
        let!(:group_member) { create(:group_member, group: group, user: user) }
        let(:params) { { milestone_title: group_milestone.title } }
184

185 186 187 188 189
        before do
          project2.update(namespace: group)
          merge_request2.update(milestone: group_milestone)
          merge_request3.update(milestone: group_milestone)
        end
190

191 192
        it 'returns issues assigned to that group milestone' do
          merge_requests = described_class.new(user, params).execute
193

194 195 196
          expect(merge_requests).to contain_exactly(merge_request2, merge_request3)
        end
      end
197

198 199
      context 'filtering by created_at/updated_at' do
        let(:new_project) { create(:project, forked_from_project: project1) }
200

201 202 203 204 205 206 207 208 209
        let!(:new_merge_request) do
          create(:merge_request,
                :simple,
                author: user,
                created_at: 1.week.from_now,
                updated_at: 1.week.from_now,
                source_project: new_project,
                target_project: new_project)
        end
210

211 212 213 214 215 216 217 218 219 220
        let!(:old_merge_request) do
          create(:merge_request,
                :simple,
                author: user,
                source_branch: 'feature_1',
                created_at: 1.week.ago,
                updated_at: 1.week.ago,
                source_project: new_project,
                target_project: new_project)
        end
221

222 223 224
        before do
          new_project.add_maintainer(user)
        end
225

226 227
        it 'filters by created_after' do
          params = { project_id: new_project.id, created_after: new_merge_request.created_at }
228

229
          merge_requests = described_class.new(user, params).execute
230

231 232
          expect(merge_requests).to contain_exactly(new_merge_request)
        end
F
Felipe Artur 已提交
233

234 235
        it 'filters by created_before' do
          params = { project_id: new_project.id, created_before: old_merge_request.created_at }
F
Felipe Artur 已提交
236

237
          merge_requests = described_class.new(user, params).execute
F
Felipe Artur 已提交
238

239 240
          expect(merge_requests).to contain_exactly(old_merge_request)
        end
F
Felipe Artur 已提交
241

242 243 244 245 246 247
        it 'filters by created_after and created_before' do
          params = {
            project_id: new_project.id,
            created_after: old_merge_request.created_at,
            created_before: new_merge_request.created_at
          }
248

249
          merge_requests = described_class.new(user, params).execute
250

251 252
          expect(merge_requests).to contain_exactly(old_merge_request, new_merge_request)
        end
253

254 255
        it 'filters by updated_after' do
          params = { project_id: new_project.id, updated_after: new_merge_request.updated_at }
256

257
          merge_requests = described_class.new(user, params).execute
258

259 260
          expect(merge_requests).to contain_exactly(new_merge_request)
        end
261

262 263
        it 'filters by updated_before' do
          params = { project_id: new_project.id, updated_before: old_merge_request.updated_at }
264

265
          merge_requests = described_class.new(user, params).execute
266

267 268
          expect(merge_requests).to contain_exactly(old_merge_request)
        end
269

270 271 272 273 274 275
        it 'filters by updated_after and updated_before' do
          params = {
            project_id: new_project.id,
            updated_after: old_merge_request.updated_at,
            updated_before: new_merge_request.updated_at
          }
276

277
          merge_requests = described_class.new(user, params).execute
278

279 280
          expect(merge_requests).to contain_exactly(old_merge_request, new_merge_request)
        end
281
      end
282
    end
283

284 285 286
    describe '#row_count', :request_store do
      it 'returns the number of rows for the default state' do
        finder = described_class.new(user)
287

288 289 290 291 292
        expect(finder.row_count).to eq(7)
      end

      it 'returns the number of rows for a given state' do
        finder = described_class.new(user, state: 'closed')
293

294
        expect(finder.row_count).to eq(1)
295
      end
296 297
    end
  end
298

299 300
  context 'when projects require different access levels for merge requests' do
    let(:user) { create(:user) }
301

302 303 304 305 306
    let(:public_project) { create(:project, :public) }
    let(:internal) { create(:project, :internal) }
    let(:private_project) { create(:project, :private) }
    let(:public_with_private_repo) { create(:project, :public, :repository, :repository_private) }
    let(:internal_with_private_repo) { create(:project, :internal, :repository, :repository_private) }
307

308
    let(:merge_requests) { described_class.new(user, {}).execute }
309

310 311 312 313 314
    let!(:mr_public) { create(:merge_request, source_project: public_project) }
    let!(:mr_private) { create(:merge_request, source_project: private_project) }
    let!(:mr_internal) { create(:merge_request, source_project: internal) }
    let!(:mr_private_repo_access) { create(:merge_request, source_project: public_with_private_repo) }
    let!(:mr_internal_private_repo_access) { create(:merge_request, source_project: internal_with_private_repo) }
315

316 317
    context 'with admin user' do
      let(:user) { create(:user, :admin) }
318

319 320 321 322
      it 'returns all merge requests' do
        expect(merge_requests).to eq(
          [mr_internal_private_repo_access, mr_private_repo_access, mr_internal, mr_private, mr_public]
        )
323
      end
324
    end
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

    context 'when project restricts merge requests' do
      let(:non_member) { create(:user) }
      let(:project) { create(:project, :repository, :public, :merge_requests_private) }
      let!(:merge_request) { create(:merge_request, source_project: project) }

      it "returns nothing to to non members" do
        merge_requests = described_class.new(
          non_member,
          project_id: project.id
        ).execute

        expect(merge_requests).to be_empty
      end
    end
340

341 342
    context 'with external user' do
      let(:user) { create(:user, :external) }
343

344 345 346
      it 'returns only public merge requests' do
        expect(merge_requests).to eq([mr_public])
      end
347 348
    end

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    context 'with authenticated user' do
      it 'returns public and internal merge requests' do
        expect(merge_requests).to eq([mr_internal, mr_public])
      end

      context 'being added to the private project' do
        context 'as a guest' do
          before do
            private_project.add_guest(user)
          end

          it 'does not return merge requests from the private project' do
            expect(merge_requests).to eq([mr_internal, mr_public])
          end
        end

        context 'as a developer' do
          before do
            private_project.add_developer(user)
          end

          it 'returns merge requests from the private project' do
            expect(merge_requests).to eq([mr_internal, mr_private, mr_public])
          end
        end
      end
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
      context 'being added to the public project with private repo access' do
        context 'as a guest' do
          before do
            public_with_private_repo.add_guest(user)
          end

          it 'returns merge requests from the project' do
            expect(merge_requests).to eq([mr_internal, mr_public])
          end
        end

        context 'as a reporter' do
          before do
            public_with_private_repo.add_reporter(user)
          end

          it 'returns merge requests from the project' do
            expect(merge_requests).to eq([mr_private_repo_access, mr_internal, mr_public])
          end
        end
      end

      context 'being added to the internal project with private repo access' do
        context 'as a guest' do
          before do
            internal_with_private_repo.add_guest(user)
          end

          it 'returns merge requests from the project' do
            expect(merge_requests).to eq([mr_internal, mr_public])
          end
        end

        context 'as a reporter' do
          before do
            internal_with_private_repo.add_reporter(user)
          end

          it 'returns merge requests from the project' do
            expect(merge_requests).to eq([mr_internal_private_repo_access, mr_internal, mr_public])
          end
        end
      end
419 420
    end
  end
421
end