issues_spec.rb 65.8 KB
Newer Older
Nihad Abbasov's avatar
Nihad Abbasov committed
1 2
require 'spec_helper'

3
describe API::Issues do
4 5
  set(:user) { create(:user) }
  set(:project) do
6
    create(:project, :public, creator_id: user.id, namespace: user.namespace)
7 8
  end

9
  let(:user2)       { create(:user) }
10
  let(:non_member)  { create(:user) }
11 12 13
  set(:guest)       { create(:user) }
  set(:author)      { create(:author) }
  set(:assignee)    { create(:assignee) }
14
  let(:admin)       { create(:user, :admin) }
15 16
  let(:issue_title)       { 'foo' }
  let(:issue_description) { 'closed' }
17 18 19
  let!(:closed_issue) do
    create :closed_issue,
           author: user,
20
           assignees: [user],
21 22
           project: project,
           state: :closed,
Sean McGivern's avatar
Sean McGivern committed
23
           milestone: milestone,
24
           created_at: generate(:past_time),
25 26
           updated_at: 3.hours.ago,
           closed_at: 1.hour.ago
27
  end
28 29 30 31 32
  let!(:confidential_issue) do
    create :issue,
           :confidential,
           project: project,
           author: author,
33
           assignees: [assignee],
34
           created_at: generate(:past_time),
Sean McGivern's avatar
Sean McGivern committed
35
           updated_at: 2.hours.ago
36
  end
37 38 39
  let!(:issue) do
    create :issue,
           author: user,
40
           assignees: [user],
41
           project: project,
Sean McGivern's avatar
Sean McGivern committed
42
           milestone: milestone,
43
           created_at: generate(:past_time),
44 45 46
           updated_at: 1.hour.ago,
           title: issue_title,
           description: issue_description
47
  end
48
  set(:label) do
49 50
    create(:label, title: 'label', color: '#FFAABB', project: project)
  end
jubianchi's avatar
jubianchi committed
51
  let!(:label_link) { create(:label_link, label: label, target: issue) }
52
  let(:milestone) { create(:milestone, title: '1.0.0', project: project) }
53
  set(:empty_milestone) do
54 55
    create(:milestone, title: '2.0.0', project: project)
  end
56
  let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) }
57

58 59
  let(:no_milestone_title) { "None" }
  let(:any_milestone_title) { "Any" }
60

61
  before(:all) do
62 63
    project.add_reporter(user)
    project.add_guest(guest)
64
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
65 66

  describe "GET /issues" do
67
    context "when unauthenticated" do
68
      it "returns an array of all issues" do
blackst0ne's avatar
blackst0ne committed
69
        get api("/issues"), params: { scope: 'all' }
70 71 72 73 74 75

        expect(response).to have_http_status(200)
        expect(json_response).to be_an Array
      end

      it "returns authentication error without any scope" do
76
        get api("/issues")
77

78 79 80 81
        expect(response).to have_http_status(401)
      end

      it "returns authentication error when scope is assigned-to-me" do
blackst0ne's avatar
blackst0ne committed
82
        get api("/issues"), params: { scope: 'assigned-to-me' }
83 84 85 86 87

        expect(response).to have_http_status(401)
      end

      it "returns authentication error when scope is created-by-me" do
blackst0ne's avatar
blackst0ne committed
88
        get api("/issues"), params: { scope: 'created-by-me' }
89 90

        expect(response).to have_http_status(401)
91
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
92
    end
93

94
    context "when authenticated" do
95
      it "returns an array of issues" do
Robert Speicher's avatar
Robert Speicher committed
96
        get api("/issues", user)
97

98
        expect_paginated_array_response([issue.id, closed_issue.id])
99
        expect(json_response.first['title']).to eq(issue.title)
100
        expect(json_response.last).to have_key('web_url')
Nihad Abbasov's avatar
Nihad Abbasov committed
101
      end
102

103
      it 'returns an array of closed issues' do
blackst0ne's avatar
blackst0ne committed
104
        get api('/issues', user), params: { state: :closed }
105

106
        expect_paginated_array_response(closed_issue.id)
jubianchi's avatar
jubianchi committed
107 108
      end

109
      it 'returns an array of opened issues' do
blackst0ne's avatar
blackst0ne committed
110
        get api('/issues', user), params: { state: :opened }
111

112
        expect_paginated_array_response(issue.id)
jubianchi's avatar
jubianchi committed
113 114
      end

115
      it 'returns an array of all issues' do
blackst0ne's avatar
blackst0ne committed
116
        get api('/issues', user), params: { state: :all }
117

118
        expect_paginated_array_response([issue.id, closed_issue.id])
jubianchi's avatar
jubianchi committed
119
      end
jubianchi's avatar
jubianchi committed
120

121 122 123
      it 'returns issues assigned to me' do
        issue2 = create(:issue, assignees: [user2], project: project)

blackst0ne's avatar
blackst0ne committed
124
        get api('/issues', user2), params: { scope: 'assigned_to_me' }
125

126
        expect_paginated_array_response(issue2.id)
127 128 129 130 131
      end

      it 'returns issues assigned to me (kebab-case)' do
        issue2 = create(:issue, assignees: [user2], project: project)

blackst0ne's avatar
blackst0ne committed
132
        get api('/issues', user2), params: { scope: 'assigned-to-me' }
133

134
        expect_paginated_array_response(issue2.id)
135 136
      end

137 138 139
      it 'returns issues authored by the given author id' do
        issue2 = create(:issue, author: user2, project: project)

blackst0ne's avatar
blackst0ne committed
140
        get api('/issues', user), params: { author_id: user2.id, scope: 'all' }
141

142
        expect_paginated_array_response(issue2.id)
143 144 145 146 147
      end

      it 'returns issues assigned to the given assignee id' do
        issue2 = create(:issue, assignees: [user2], project: project)

blackst0ne's avatar
blackst0ne committed
148
        get api('/issues', user), params: { assignee_id: user2.id, scope: 'all' }
149

150
        expect_paginated_array_response(issue2.id)
151 152 153 154 155
      end

      it 'returns issues authored by the given author id and assigned to the given assignee id' do
        issue2 = create(:issue, author: user2, assignees: [user2], project: project)

blackst0ne's avatar
blackst0ne committed
156
        get api('/issues', user), params: { author_id: user2.id, assignee_id: user2.id, scope: 'all' }
157

158
        expect_paginated_array_response(issue2.id)
159 160
      end

161 162 163
      it 'returns issues with no assignee' do
        issue2 = create(:issue, author: user2, project: project)

blackst0ne's avatar
blackst0ne committed
164
        get api('/issues', user), params: { assignee_id: 0, scope: 'all' }
165

166
        expect_paginated_array_response(issue2.id)
167 168
      end

169 170 171
      it 'returns issues with no assignee' do
        issue2 = create(:issue, author: user2, project: project)

blackst0ne's avatar
blackst0ne committed
172
        get api('/issues', user), params: { assignee_id: 'None', scope: 'all' }
173

174
        expect_paginated_array_response(issue2.id)
175 176 177
      end

      it 'returns issues with any assignee' do
178 179 180
        # This issue without assignee should not be returned
        create(:issue, author: user2, project: project)

blackst0ne's avatar
blackst0ne committed
181
        get api('/issues', user), params: { assignee_id: 'Any', scope: 'all' }
182

183
        expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
184 185
      end

Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
186
      it 'returns issues reacted by the authenticated user' do
187
        issue2 = create(:issue, project: project, author: user, assignees: [user])
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
188
        create(:award_emoji, awardable: issue2, user: user2, name: 'star')
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
189
        create(:award_emoji, awardable: issue, user: user2, name: 'thumbsup')
190

blackst0ne's avatar
blackst0ne committed
191
        get api('/issues', user2), params: { my_reaction_emoji: 'Any', scope: 'all' }
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
192

193
        expect_paginated_array_response([issue2.id, issue.id])
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
194 195 196 197 198 199
      end

      it 'returns issues not reacted by the authenticated user' do
        issue2 = create(:issue, project: project, author: user, assignees: [user])
        create(:award_emoji, awardable: issue2, user: user2, name: 'star')

blackst0ne's avatar
blackst0ne committed
200
        get api('/issues', user2), params: { my_reaction_emoji: 'None', scope: 'all' }
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
201

202
        expect_paginated_array_response([issue.id, closed_issue.id])
203 204
      end

205
      it 'returns issues matching given search string for title' do
blackst0ne's avatar
blackst0ne committed
206
        get api("/issues", user), params: { search: issue.title }
207

208
        expect_paginated_array_response(issue.id)
209 210
      end

211 212 213 214 215 216 217 218 219 220 221 222
      it 'returns issues matching given search string for title and scoped in title' do
        get api("/issues", user), params: { search: issue.title, in: 'title' }

        expect_paginated_array_response(issue.id)
      end

      it 'returns an empty array if no issue matches given search string for title and scoped in description' do
        get api("/issues", user), params: { search: issue.title, in: 'description' }

        expect_paginated_array_response([])
      end

223
      it 'returns issues matching given search string for description' do
blackst0ne's avatar
blackst0ne committed
224
        get api("/issues", user), params: { search: issue.description }
225

226
        expect_paginated_array_response(issue.id)
227 228
      end

229 230 231 232 233 234
      context 'filtering before a specific date' do
        let!(:issue2) { create(:issue, project: project, author: user, created_at: Date.new(2000, 1, 1), updated_at: Date.new(2000, 1, 1)) }

        it 'returns issues created before a specific date' do
          get api('/issues?created_before=2000-01-02T00:00:00.060Z', user)

235
          expect_paginated_array_response(issue2.id)
236 237 238 239 240
        end

        it 'returns issues updated before a specific date' do
          get api('/issues?updated_before=2000-01-02T00:00:00.060Z', user)

241
          expect_paginated_array_response(issue2.id)
242 243 244 245 246 247 248 249 250
        end
      end

      context 'filtering after a specific date' do
        let!(:issue2) { create(:issue, project: project, author: user, created_at: 1.week.from_now, updated_at: 1.week.from_now) }

        it 'returns issues created after a specific date' do
          get api("/issues?created_after=#{issue2.created_at}", user)

251
          expect_paginated_array_response(issue2.id)
252 253 254 255 256
        end

        it 'returns issues updated after a specific date' do
          get api("/issues?updated_after=#{issue2.updated_at}", user)

257
          expect_paginated_array_response(issue2.id)
258 259 260
        end
      end

261
      it 'returns an array of labeled issues' do
blackst0ne's avatar
blackst0ne committed
262
        get api("/issues", user), params: { labels: label.title }
263

264 265
        expect_paginated_array_response(issue.id)
        expect(json_response.first['labels']).to eq([label.title])
jubianchi's avatar
jubianchi committed
266 267
      end

268 269 270 271 272 273 274
      it 'returns an array of labeled issues when all labels matches' do
        label_b = create(:label, title: 'foo', project: project)
        label_c = create(:label, title: 'bar', project: project)

        create(:label_link, label: label_b, target: issue)
        create(:label_link, label: label_c, target: issue)

blackst0ne's avatar
blackst0ne committed
275
        get api("/issues", user), params: { labels: "#{label.title},#{label_b.title},#{label_c.title}" }
276

277
        expect_paginated_array_response(issue.id)
278
        expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title])
jubianchi's avatar
jubianchi committed
279 280
      end

281
      it 'returns an empty array if no issue matches labels' do
blackst0ne's avatar
blackst0ne committed
282
        get api('/issues', user), params: { labels: 'foo,bar' }
283

284
        expect_paginated_array_response([])
jubianchi's avatar
jubianchi committed
285 286
      end

287
      it 'returns an array of labeled issues matching given state' do
blackst0ne's avatar
blackst0ne committed
288
        get api("/issues", user), params: { labels: label.title, state: :opened }
289

290
        expect_paginated_array_response(issue.id)
291 292
        expect(json_response.first['labels']).to eq([label.title])
        expect(json_response.first['state']).to eq('opened')
jubianchi's avatar
jubianchi committed
293 294
      end

295
      it 'returns an empty array if no issue matches labels and state filters' do
blackst0ne's avatar
blackst0ne committed
296
        get api("/issues", user), params: { labels: label.title, state: :closed }
297

298
        expect_paginated_array_response([])
299 300 301
      end

      it 'returns an array of issues with any label' do
blackst0ne's avatar
blackst0ne committed
302
        get api("/issues", user), params: { labels: IssuesFinder::FILTER_ANY }
303

304
        expect_paginated_array_response(issue.id)
305 306
      end

307
      it 'returns an array of issues with no label' do
blackst0ne's avatar
blackst0ne committed
308
        get api("/issues", user), params: { labels: IssuesFinder::FILTER_NONE }
309

310
        expect_paginated_array_response(closed_issue.id)
311 312 313
      end

      it 'returns an array of issues with no label when using the legacy No+Label filter' do
blackst0ne's avatar
blackst0ne committed
314
        get api("/issues", user), params: { labels: "No Label" }
315

316
        expect_paginated_array_response(closed_issue.id)
jubianchi's avatar
jubianchi committed
317
      end
Sean McGivern's avatar
Sean McGivern committed
318

319 320 321
      it 'returns an empty array if no issue matches milestone' do
        get api("/issues?milestone=#{empty_milestone.title}", user)

322
        expect_paginated_array_response([])
323 324 325 326 327
      end

      it 'returns an empty array if milestone does not exist' do
        get api("/issues?milestone=foo", user)

328
        expect_paginated_array_response([])
329 330 331 332 333
      end

      it 'returns an array of issues in given milestone' do
        get api("/issues?milestone=#{milestone.title}", user)

334
        expect_paginated_array_response([issue.id, closed_issue.id])
335 336 337 338 339 340
      end

      it 'returns an array of issues matching state in milestone' do
        get api("/issues?milestone=#{milestone.title}"\
                '&state=closed', user)

341
        expect_paginated_array_response(closed_issue.id)
342 343 344
      end

      it 'returns an array of issues with no milestone' do
345
        get api("/issues?milestone=#{no_milestone_title}", author)
346

347
        expect_paginated_array_response(confidential_issue.id)
348 349
      end

350
      it 'returns an array of issues found by iids' do
blackst0ne's avatar
blackst0ne committed
351
        get api('/issues', user), params: { iids: [closed_issue.iid] }
352

353
        expect_paginated_array_response(closed_issue.id)
354 355 356
      end

      it 'returns an empty array if iid does not exist' do
blackst0ne's avatar
blackst0ne committed
357
        get api("/issues", user), params: { iids: [99999] }
358

359
        expect_paginated_array_response([])
360 361
      end

Sean McGivern's avatar
Sean McGivern committed
362 363 364
      it 'sorts by created_at descending by default' do
        get api('/issues', user)

365
        expect_paginated_array_response([issue.id, closed_issue.id])
Sean McGivern's avatar
Sean McGivern committed
366 367 368 369 370
      end

      it 'sorts ascending when requested' do
        get api('/issues?sort=asc', user)

371
        expect_paginated_array_response([closed_issue.id, issue.id])
Sean McGivern's avatar
Sean McGivern committed
372 373 374 375 376
      end

      it 'sorts by updated_at descending when requested' do
        get api('/issues?order_by=updated_at', user)

377
        issue.touch(:updated_at)
378

379
        expect_paginated_array_response([issue.id, closed_issue.id])
Sean McGivern's avatar
Sean McGivern committed
380 381 382 383 384
      end

      it 'sorts by updated_at ascending when requested' do
        get api('/issues?order_by=updated_at&sort=asc', user)

385
        issue.touch(:updated_at)
386

387
        expect_paginated_array_response([closed_issue.id, issue.id])
Sean McGivern's avatar
Sean McGivern committed
388
      end
389 390 391 392

      it 'matches V4 response schema' do
        get api('/issues', user)

393
        expect(response).to have_gitlab_http_status(200)
394 395
        expect(response).to match_response_schema('public_api/v4/issues')
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
396 397 398
    end
  end

399 400
  describe "GET /groups/:id/issues" do
    let!(:group)            { create(:group) }
401
    let!(:group_project)    { create(:project, :public, creator_id: user.id, namespace: group) }
402 403 404
    let!(:group_closed_issue) do
      create :closed_issue,
             author: user,
405
             assignees: [user],
406 407
             project: group_project,
             state: :closed,
Sean McGivern's avatar
Sean McGivern committed
408
             milestone: group_milestone,
409 410
             updated_at: 3.hours.ago,
             created_at: 1.day.ago
411 412 413 414 415 416
    end
    let!(:group_confidential_issue) do
      create :issue,
             :confidential,
             project: group_project,
             author: author,
417
             assignees: [assignee],
418 419
             updated_at: 2.hours.ago,
             created_at: 2.days.ago
420 421 422 423
    end
    let!(:group_issue) do
      create :issue,
             author: user,
424
             assignees: [user],
425
             project: group_project,
Sean McGivern's avatar
Sean McGivern committed
426
             milestone: group_milestone,
427 428
             updated_at: 1.hour.ago,
             title: issue_title,
429 430
             description: issue_description,
             created_at: 5.days.ago
431 432 433 434 435 436 437 438 439 440 441 442 443
    end
    let!(:group_label) do
      create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project)
    end
    let!(:group_label_link) { create(:label_link, label: group_label, target: group_issue) }
    let!(:group_milestone) { create(:milestone, title: '3.0.0', project: group_project) }
    let!(:group_empty_milestone) do
      create(:milestone, title: '4.0.0', project: group_project)
    end
    let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) }

    let(:base_url) { "/groups/#{group.id}/issues" }

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
    context 'when group has subgroups', :nested_groups do
      let(:subgroup_1) { create(:group, parent: group) }
      let(:subgroup_2) { create(:group, parent: subgroup_1) }

      let(:subgroup_1_project) { create(:project, namespace: subgroup_1) }
      let(:subgroup_2_project) { create(:project, namespace: subgroup_2) }

      let!(:issue_1) { create(:issue, project: subgroup_1_project) }
      let!(:issue_2) { create(:issue, project: subgroup_2_project) }

      before do
        group.add_developer(user)
      end

      it 'also returns subgroups projects issues' do
        get api(base_url, user)

461
        expect_paginated_array_response([issue_2.id, issue_1.id, group_closed_issue.id, group_confidential_issue.id, group_issue.id])
462 463 464
      end
    end

465 466 467
    context 'when user is unauthenticated' do
      it 'lists all issues in public projects' do
        get api(base_url)
468

469
        expect_paginated_array_response([group_closed_issue.id, group_issue.id])
470
      end
471 472
    end

473 474 475 476
    context 'when user is a group member' do
      before do
        group_project.add_reporter(user)
      end
477

478 479
      it 'returns all group issues (including opened and closed)' do
        get api(base_url, admin)
480

481
        expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id, group_issue.id])
482
      end
483

484
      it 'returns group issues without confidential issues for non project members' do
blackst0ne's avatar
blackst0ne committed
485
        get api(base_url, non_member), params: { state: :opened }
486

487
        expect_paginated_array_response(group_issue.id)
488
      end
489

490
      it 'returns group confidential issues for author' do
blackst0ne's avatar
blackst0ne committed
491
        get api(base_url, author), params: { state: :opened }
492

493
        expect_paginated_array_response([group_confidential_issue.id, group_issue.id])
494
      end
495

496
      it 'returns group confidential issues for assignee' do
blackst0ne's avatar
blackst0ne committed
497
        get api(base_url, assignee), params: { state: :opened }
498

499
        expect_paginated_array_response([group_confidential_issue.id, group_issue.id])
500
      end
501

502
      it 'returns group issues with confidential issues for project members' do
blackst0ne's avatar
blackst0ne committed
503
        get api(base_url, user), params: { state: :opened }
504

505
        expect_paginated_array_response([group_confidential_issue.id, group_issue.id])
506
      end
507

508
      it 'returns group confidential issues for admin' do
blackst0ne's avatar
blackst0ne committed
509
        get api(base_url, admin), params: { state: :opened }
510

511
        expect_paginated_array_response([group_confidential_issue.id, group_issue.id])
512
      end
513

514
      it 'returns an array of labeled group issues' do
blackst0ne's avatar
blackst0ne committed
515
        get api(base_url, user), params: { labels: group_label.title }
516

517
        expect_paginated_array_response(group_issue.id)
518 519
        expect(json_response.first['labels']).to eq([group_label.title])
      end
520

521
      it 'returns an array of labeled group issues where all labels match' do
blackst0ne's avatar
blackst0ne committed
522
        get api(base_url, user), params: { labels: "#{group_label.title},foo,bar" }
523

524
        expect_paginated_array_response([])
525
      end
526

527
      it 'returns issues matching given search string for title' do
blackst0ne's avatar
blackst0ne committed
528
        get api(base_url, user), params: { search: group_issue.title }
529

530
        expect_paginated_array_response(group_issue.id)
531
      end
532

533
      it 'returns issues matching given search string for description' do
blackst0ne's avatar
blackst0ne committed
534
        get api(base_url, user), params: { search: group_issue.description }
535

536
        expect_paginated_array_response(group_issue.id)
537
      end
538

539 540 541
      it 'returns an array of labeled issues when all labels matches' do
        label_b = create(:label, title: 'foo', project: group_project)
        label_c = create(:label, title: 'bar', project: group_project)
542

543 544
        create(:label_link, label: label_b, target: group_issue)
        create(:label_link, label: label_c, target: group_issue)
545

blackst0ne's avatar
blackst0ne committed
546
        get api(base_url, user), params: { labels: "#{group_label.title},#{label_b.title},#{label_c.title}" }
547

548
        expect_paginated_array_response(group_issue.id)
549 550
        expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
      end
551

552
      it 'returns an array of issues found by iids' do
blackst0ne's avatar
blackst0ne committed
553
        get api(base_url, user), params: { iids: [group_issue.iid] }
554

555
        expect_paginated_array_response(group_issue.id)
556 557
        expect(json_response.first['id']).to eq(group_issue.id)
      end
558

559
      it 'returns an empty array if iid does not exist' do
blackst0ne's avatar
blackst0ne committed
560
        get api(base_url, user), params: { iids: [99999] }
561

562
        expect_paginated_array_response([])
563
      end
564

565
      it 'returns an empty array if no group issue matches labels' do
blackst0ne's avatar
blackst0ne committed
566
        get api(base_url, user), params: { labels: 'foo,bar' }
567

568
        expect_paginated_array_response([])
569
      end
570

571
      it 'returns an array of group issues with any label' do
blackst0ne's avatar
blackst0ne committed
572
        get api(base_url, user), params: { labels: IssuesFinder::FILTER_ANY }
573

574
        expect_paginated_array_response(group_issue.id)
575 576 577 578
        expect(json_response.first['id']).to eq(group_issue.id)
      end

      it 'returns an array of group issues with no label' do
blackst0ne's avatar
blackst0ne committed
579
        get api(base_url, user), params: { labels: IssuesFinder::FILTER_NONE }
580

581
        expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
582 583
      end

584
      it 'returns an empty array if no issue matches milestone' do
blackst0ne's avatar
blackst0ne committed
585
        get api(base_url, user), params: { milestone: group_empty_milestone.title }
586

587
        expect_paginated_array_response([])
588
      end
589

590
      it 'returns an empty array if milestone does not exist' do
blackst0ne's avatar
blackst0ne committed
591
        get api(base_url, user), params: { milestone: 'foo' }
592

593
        expect_paginated_array_response([])
594
      end
595

596
      it 'returns an array of issues in given milestone' do
blackst0ne's avatar
blackst0ne committed
597
        get api(base_url, user), params: { state: :opened, milestone: group_milestone.title }
Sean McGivern's avatar
Sean McGivern committed
598

599
        expect_paginated_array_response(group_issue.id)
600
      end
601

602
      it 'returns an array of issues matching state in milestone' do
blackst0ne's avatar
blackst0ne committed
603
        get api(base_url, user), params: { milestone: group_milestone.title, state: :closed }
604

605
        expect_paginated_array_response(group_closed_issue.id)
606
      end
607

608
      it 'returns an array of issues with no milestone' do
blackst0ne's avatar
blackst0ne committed
609
        get api(base_url, user), params: { milestone: no_milestone_title }
Sean McGivern's avatar
Sean McGivern committed
610

611
        expect(response).to have_gitlab_http_status(200)
612

613
        expect_paginated_array_response(group_confidential_issue.id)
614
      end
Sean McGivern's avatar
Sean McGivern committed
615

616 617
      it 'sorts by created_at descending by default' do
        get api(base_url, user)
Sean McGivern's avatar
Sean McGivern committed
618

619
        expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id, group_issue.id])
620
      end
Sean McGivern's avatar
Sean McGivern committed
621

622 623
      it 'sorts ascending when requested' do
        get api("#{base_url}?sort=asc", user)
Sean McGivern's avatar
Sean McGivern committed
624

625
        expect_paginated_array_response([group_issue.id, group_confidential_issue.id, group_closed_issue.id])
626
      end
Sean McGivern's avatar
Sean McGivern committed
627

628 629
      it 'sorts by updated_at descending when requested' do
        get api("#{base_url}?order_by=updated_at", user)
Sean McGivern's avatar
Sean McGivern committed
630

631
        group_issue.touch(:updated_at)
632

633
        expect_paginated_array_response([group_issue.id, group_confidential_issue.id, group_closed_issue.id])
634 635 636
      end

      it 'sorts by updated_at ascending when requested' do
blackst0ne's avatar
blackst0ne committed
637
        get api(base_url, user), params: { order_by: :updated_at, sort: :asc }
638

639
        expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id, group_issue.id])
640
      end
Sean McGivern's avatar
Sean McGivern committed
641
    end
642 643
  end

Nihad Abbasov's avatar
Nihad Abbasov committed
644
  describe "GET /projects/:id/issues" do
645 646
    let(:base_url) { "/projects/#{project.id}" }

647 648 649 650
    context 'when unauthenticated' do
      it 'returns public project issues' do
        get api("/projects/#{project.id}/issues")

651
        expect_paginated_array_response([issue.id, closed_issue.id])
652 653 654
      end
    end

655
    it 'avoids N+1 queries' do
656 657 658
      get api("/projects/#{project.id}/issues", user)

      control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
659 660 661
        get api("/projects/#{project.id}/issues", user)
      end.count

662
      create_list(:issue, 3, project: project)
663 664 665

      expect do
        get api("/projects/#{project.id}/issues", user)
666
      end.not_to exceed_all_query_limit(control_count)
667 668
    end

669 670 671
    it 'returns 404 when project does not exist' do
      get api('/projects/1000/issues', non_member)

672
      expect(response).to have_gitlab_http_status(404)
673 674
    end

675
    it "returns 404 on private projects for other users" do
676
      private_project = create(:project, :private)
677 678 679 680
      create(:issue, project: private_project)

      get api("/projects/#{private_project.id}/issues", non_member)

681
      expect(response).to have_gitlab_http_status(404)
682 683 684
    end

    it 'returns no issues when user has access to project but not issues' do
685
      restricted_project = create(:project, :public, :issues_private)
686 687 688 689
      create(:issue, project: restricted_project)

      get api("/projects/#{restricted_project.id}/issues", non_member)

690
      expect_paginated_array_response([])
691 692
    end

693
    it 'returns project issues without confidential issues for non project members' do
694
      get api("#{base_url}/issues", non_member)
695

696
      expect_paginated_array_response([issue.id, closed_issue.id])
697 698
    end

699
    it 'returns project issues without confidential issues for project members with guest role' do
700
      get api("#{base_url}/issues", guest)
701

702
      expect_paginated_array_response([issue.id, closed_issue.id])
703 704
    end

705
    it 'returns project confidential issues for author' do
706
      get api("#{base_url}/issues", author)
707

708
      expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
709 710
    end

711
    it 'returns project confidential issues for assignee' do
712
      get api("#{base_url}/issues", assignee)
713

714
      expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
715 716
    end

717
    it 'returns project issues with confidential issues for project members' do
718
      get api("#{base_url}/issues", user)
719

720
      expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
721 722
    end

723
    it 'returns project confidential issues for admin' do
724
      get api("#{base_url}/issues", admin)
725

726
      expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
Nihad Abbasov's avatar
Nihad Abbasov committed
727
    end
jubianchi's avatar
jubianchi committed
728

729
    it 'returns an array of labeled project issues' do
blackst0ne's avatar
blackst0ne committed
730
      get api("#{base_url}/issues", user), params: { labels: label.title }
731

732
      expect_paginated_array_response(issue.id)
jubianchi's avatar
jubianchi committed
733 734
    end

735 736 737 738 739 740 741
    it 'returns an array of labeled issues when all labels matches' do
      label_b = create(:label, title: 'foo', project: project)
      label_c = create(:label, title: 'bar', project: project)

      create(:label_link, label: label_b, target: issue)
      create(:label_link, label: label_c, target: issue)

blackst0ne's avatar
blackst0ne committed
742
      get api("#{base_url}/issues", user), params: { labels: "#{label.title},#{label_b.title},#{label_c.title}" }
743

744
      expect_paginated_array_response(issue.id)
745 746
    end

747 748 749
    it 'returns issues matching given search string for title' do
      get api("#{base_url}/issues?search=#{issue.title}", user)

750
      expect_paginated_array_response(issue.id)
751 752 753 754 755
    end

    it 'returns issues matching given search string for description' do
      get api("#{base_url}/issues?search=#{issue.description}", user)

756
      expect_paginated_array_response(issue.id)
757 758
    end

759
    it 'returns an array of issues found by iids' do
blackst0ne's avatar
blackst0ne committed
760
      get api("#{base_url}/issues", user), params: { iids: [issue.iid] }
761

762
      expect_paginated_array_response(issue.id)
763 764 765
    end

    it 'returns an empty array if iid does not exist' do
blackst0ne's avatar
blackst0ne committed
766
      get api("#{base_url}/issues", user), params: { iids: [99999] }
767

768
      expect_paginated_array_response([])
769 770
    end

771 772 773
    it 'returns an empty array if not all labels matches' do
      get api("#{base_url}/issues?labels=#{label.title},foo", user)

774
      expect_paginated_array_response([])
jubianchi's avatar
jubianchi committed
775 776
    end

777
    it 'returns an array of project issues with any label' do
blackst0ne's avatar
blackst0ne committed
778
      get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_ANY }
779

780
      expect_paginated_array_response(issue.id)
781 782 783
    end

    it 'returns an array of project issues with no label' do
blackst0ne's avatar
blackst0ne committed
784
      get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_NONE }
785

786
      expect_paginated_array_response([confidential_issue.id, closed_issue.id])
787 788
    end

789
    it 'returns an empty array if no project issue matches labels' do
blackst0ne's avatar
blackst0ne committed
790
      get api("#{base_url}/issues", user), params: { labels: 'foo,bar' }
791

792
      expect_paginated_array_response([])
793 794
    end