issues_controller_spec.rb 11.2 KB
Newer Older
1 2
# frozen_string_literal: true

3 4
require 'spec_helper'

Felipe Artur's avatar
Felipe Artur committed
5
describe Boards::IssuesController do
6 7
  include ExternalAuthorizationServiceHelpers

8
  let(:project) { create(:project, :private) }
9
  let(:board)   { create(:board, project: project) }
10
  let(:user)    { create(:user) }
11
  let(:guest)   { create(:user) }
12

13 14 15
  let(:planning)    { create(:label, project: project, name: 'Planning') }
  let(:development) { create(:label, project: project, name: 'Development') }

16 17
  let!(:list1) { create(:list, board: board, label: planning, position: 0) }
  let!(:list2) { create(:list, board: board, label: development, position: 1) }
18

19
  before do
20
    project.add_maintainer(user)
21
    project.add_guest(guest)
22 23
  end

24
  describe 'GET index', :request_store do
25
    let(:johndoe) { create(:user, avatar: fixture_file_upload(File.join('spec/fixtures/dk.png'))) }
26

27 28 29 30
    context 'with invalid board id' do
      it 'returns a not found 404 response' do
        list_issues user: user, board: 999, list: list2

31
        expect(response).to have_gitlab_http_status(404)
32 33 34
      end
    end

35 36
    context 'when list id is present' do
      context 'with valid list id' do
37 38 39 40 41 42 43 44 45
        let(:group) { create(:group, :private, projects: [project]) }
        let(:group_board) { create(:board, group: group) }
        let!(:list3) { create(:list, board: group_board, label: development, position: 2) }
        let(:sub_group_1) { create(:group, :private, parent: group) }

        before do
          group.add_maintainer(user)
        end

46 47 48 49
        it 'returns issues that have the list label applied' do
          issue = create(:labeled_issue, project: project, labels: [planning])
          create(:labeled_issue, project: project, labels: [planning])
          create(:labeled_issue, project: project, labels: [development], due_date: Date.tomorrow)
50
          create(:labeled_issue, project: project, labels: [development], assignees: [johndoe])
51
          issue.subscribe(johndoe, project)
52

53 54 55 56
          list_issues user: user, board: board, list: list2

          parsed_response = JSON.parse(response.body)

57
          expect(response).to match_response_schema('entities/issue_boards')
58
          expect(parsed_response['issues'].length).to eq 2
Valery Sizov's avatar
Valery Sizov committed
59
          expect(development.issues.map(&:relative_position)).not_to include(nil)
60
        end
61 62 63 64 65 66 67 68 69 70 71

        it 'avoids N+1 database queries' do
          create(:labeled_issue, project: project, labels: [development])
          control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: board, list: list2) }.count

          # 25 issues is bigger than the page size
          # the relative position will ignore the `#make_sure_position_set` queries
          create_list(:labeled_issue, 25, project: project, labels: [development], assignees: [johndoe], relative_position: 1)

          expect { list_issues(user: user, board: board, list: list2) }.not_to exceed_query_limit(control_count)
        end
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

        it 'avoids N+1 database queries when adding a project', :request_store do
          create(:labeled_issue, project: project, labels: [development])
          control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: group_board, list: list3) }.count

          2.times do
            p = create(:project, group: group)
            create(:labeled_issue, project: p, labels: [development])
          end

          project_2 = create(:project, group: group)
          create(:labeled_issue, project: project_2, labels: [development], assignees: [johndoe])

          # because each issue without relative_position must be updated with
          # a different value, we have 8 extra queries per issue
          expect { list_issues(user: user, board: group_board, list: list3) }.not_to exceed_query_limit(control_count + (2 * 8 - 1))
        end

        it 'avoids N+1 database queries when adding a subgroup, project, and issue', :nested_groups do
          create(:project, group: sub_group_1)
          create(:labeled_issue, project: project, labels: [development])
          control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: group_board, list: list3) }.count
          project_2 = create(:project, group: group)

          2.times do
            p = create(:project, group: sub_group_1)
            create(:labeled_issue, project: p, labels: [development])
          end

          create(:labeled_issue, project: project_2, labels: [development], assignees: [johndoe])

          expect { list_issues(user: user, board: group_board, list: list3) }.not_to exceed_query_limit(control_count + (2 * 8 - 1))
        end
105 106 107 108 109 110
      end

      context 'with invalid list id' do
        it 'returns a not found 404 response' do
          list_issues user: user, board: board, list: 999

111
          expect(response).to have_gitlab_http_status(404)
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        end
      end
    end

    context 'when list id is missing' do
      it 'returns opened issues without board labels applied' do
        bug = create(:label, project: project, name: 'Bug')
        create(:issue, project: project)
        create(:labeled_issue, project: project, labels: [planning])
        create(:labeled_issue, project: project, labels: [development])
        create(:labeled_issue, project: project, labels: [bug])

        list_issues user: user, board: board

        parsed_response = JSON.parse(response.body)

128
        expect(response).to match_response_schema('entities/issue_boards')
129
        expect(parsed_response['issues'].length).to eq 2
130 131
      end
    end
132

133
    context 'with unauthorized user' do
134
      let(:unauth_user) { create(:user) }
135

136
      it 'returns a forbidden 403 response' do
137
        list_issues user: unauth_user, board: board, list: list2
138

139
        expect(response).to have_gitlab_http_status(403)
140 141 142
      end
    end

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    context 'with external authorization' do
      before do
        sign_in(user)
        enable_external_authorization_service_check
      end

      it 'returns a 403 for group boards' do
        group = create(:group)
        group_board = create(:board, group: group)

        list_issues(user: user, board: group_board)

        expect(response).to have_gitlab_http_status(403)
      end

      it 'is successful for project boards' do
        project_board = create(:board, project: project)

        list_issues(user: user, board: project_board)

        expect(response).to have_gitlab_http_status(200)
      end
    end

167
    def list_issues(user:, board:, list: nil)
168 169
      sign_in(user)

170 171 172 173 174
      params = {
        board_id: board.to_param,
        list_id: list.try(:to_param)
      }

175 176 177 178 179
      unless board.try(:parent)&.is_a?(Group)
        params[:namespace_id] = project.namespace.to_param
        params[:project_id] = project
      end

blackst0ne's avatar
blackst0ne committed
180
      get :index, params: params.compact
181
    end
182
  end
183

184 185 186
  describe 'POST create' do
    context 'with valid params' do
      it 'returns a successful 200 response' do
187
        create_issue user: user, board: board, list: list1, title: 'New issue'
188

189
        expect(response).to have_gitlab_http_status(200)
190 191 192
      end

      it 'returns the created issue' do
193
        create_issue user: user, board: board, list: list1, title: 'New issue'
194

195
        expect(response).to match_response_schema('entities/issue_board')
196 197 198 199 200 201
      end
    end

    context 'with invalid params' do
      context 'when title is nil' do
        it 'returns an unprocessable entity 422 response' do
202
          create_issue user: user, board: board, list: list1, title: nil
203

204
          expect(response).to have_gitlab_http_status(422)
205 206 207 208 209 210 211
        end
      end

      context 'when list does not belongs to project board' do
        it 'returns a not found 404 response' do
          list = create(:list)

212
          create_issue user: user, board: board, list: list, title: 'New issue'
213

214
          expect(response).to have_gitlab_http_status(404)
215 216
        end
      end
Felipe Artur's avatar
Felipe Artur committed
217 218 219 220 221

      context 'with invalid board id' do
        it 'returns a not found 404 response' do
          create_issue user: user, board: 999, list: list1, title: 'New issue'

222
          expect(response).to have_gitlab_http_status(404)
Felipe Artur's avatar
Felipe Artur committed
223 224 225 226 227 228 229
        end
      end

      context 'with invalid list id' do
        it 'returns a not found 404 response' do
          create_issue user: user, board: board, list: 999, title: 'New issue'

230
          expect(response).to have_gitlab_http_status(404)
Felipe Artur's avatar
Felipe Artur committed
231 232
        end
      end
233 234
    end

235 236 237 238 239
    context 'with guest user' do
      context 'in open list' do
        it 'returns a successful 200 response' do
          open_list = board.lists.create(list_type: :backlog)
          create_issue user: guest, board: board, list: open_list, title: 'New issue'
240

241 242 243 244 245 246 247 248 249 250
          expect(response).to have_gitlab_http_status(200)
        end
      end

      context 'in label list' do
        it 'returns a forbidden 403 response' do
          create_issue user: guest, board: board, list: list1, title: 'New issue'

          expect(response).to have_gitlab_http_status(403)
        end
251 252 253
      end
    end

254
    def create_issue(user:, board:, list:, title:)
255 256
      sign_in(user)

blackst0ne's avatar
blackst0ne committed
257 258 259
      post :create, params: {
                      board_id: board.to_param,
                      list_id: list.to_param,
260
                      issue: { title: title, project_id: project.id }
blackst0ne's avatar
blackst0ne committed
261
                    },
262 263 264 265
                    format: :json
    end
  end

266
  describe 'PATCH update' do
Felipe Artur's avatar
Felipe Artur committed
267
    let!(:issue) { create(:labeled_issue, project: project, labels: [planning]) }
268 269 270

    context 'with valid params' do
      it 'returns a successful 200 response' do
271
        move user: user, board: board, issue: issue, from_list_id: list1.id, to_list_id: list2.id
272

273
        expect(response).to have_gitlab_http_status(200)
274 275 276
      end

      it 'moves issue to the desired list' do
277
        move user: user, board: board, issue: issue, from_list_id: list1.id, to_list_id: list2.id
278 279 280 281 282 283 284

        expect(issue.reload.labels).to contain_exactly(development)
      end
    end

    context 'with invalid params' do
      it 'returns a unprocessable entity 422 response for invalid lists' do
285
        move user: user, board: board, issue: issue, from_list_id: nil, to_list_id: nil
286

287
        expect(response).to have_gitlab_http_status(422)
288 289
      end

290 291 292
      it 'returns a not found 404 response for invalid board id' do
        move user: user, board: 999, issue: issue, from_list_id: list1.id, to_list_id: list2.id

293
        expect(response).to have_gitlab_http_status(404)
294 295
      end

296
      it 'returns a not found 404 response for invalid issue id' do
Felipe Artur's avatar
Felipe Artur committed
297
        move user: user, board: board, issue: double(id: 999), from_list_id: list1.id, to_list_id: list2.id
298

299
        expect(response).to have_gitlab_http_status(404)
300 301 302
      end
    end

303
    context 'with unauthorized user' do
304 305 306
      let(:guest) { create(:user) }

      before do
307
        project.add_guest(guest)
308 309
      end

310
      it 'returns a forbidden 403 response' do
311
        move user: guest, board: board, issue: issue, from_list_id: list1.id, to_list_id: list2.id
312

313
        expect(response).to have_gitlab_http_status(403)
314 315 316
      end
    end

317
    def move(user:, board:, issue:, from_list_id:, to_list_id:)
318 319
      sign_in(user)

blackst0ne's avatar
blackst0ne committed
320 321 322 323 324 325 326 327
      patch :update, params: {
                       namespace_id: project.namespace.to_param,
                       project_id: project.id,
                       board_id: board.to_param,
                       id: issue.id,
                       from_list_id: from_list_id,
                       to_list_id: to_list_id
                     },
328 329 330
                     format: :json
    end
  end
331
end