BigW Consortium Gitlab

issues_controller_spec.rb 11.8 KB
Newer Older
1 2 3
require('spec_helper')

describe Projects::IssuesController do
4
  let(:project) { create(:project_empty_repo) }
5 6
  let(:user)    { create(:user) }
  let(:issue)   { create(:issue, project: project) }
7

8
  describe "GET #index" do
9 10
    context 'external issue tracker' do
      it 'redirects to the external issue tracker' do
11
        external = double(project_path: 'https://example.com/project')
12 13
        allow(project).to receive(:external_issue_tracker).and_return(external)
        controller.instance_variable_set(:@project, project)
14

15
        get :index, namespace_id: project.namespace.path, project_id: project
16

17
        expect(response).to redirect_to('https://example.com/project')
18
      end
19 20
    end

21 22 23 24 25
    context 'internal issue tracker' do
      before do
        sign_in(user)
        project.team << [user, :developer]
      end
26

27 28
      it "returns index" do
        get :index, namespace_id: project.namespace.path, project_id: project.path
29

30 31
        expect(response).to have_http_status(200)
      end
32

33
      it "returns 301 if request path doesn't match project path" do
34 35 36 37
        get :index, namespace_id: project.namespace.path, project_id: project.path.upcase

        expect(response).to redirect_to(namespace_project_issues_path(project.namespace, project))
      end
38

39 40 41
      it "returns 404 when issues are disabled" do
        project.issues_enabled = false
        project.save
42

43 44 45 46 47 48 49 50 51 52
        get :index, namespace_id: project.namespace.path, project_id: project.path
        expect(response).to have_http_status(404)
      end

      it "returns 404 when external issue tracker is enabled" do
        controller.instance_variable_set(:@project, project)
        allow(project).to receive(:default_issues_tracker?).and_return(false)

        get :index, namespace_id: project.namespace.path, project_id: project.path
        expect(response).to have_http_status(404)
53 54 55 56 57 58 59 60 61 62 63 64 65 66
      end
    end
  end

  describe 'GET #new' do
    context 'external issue tracker' do
      it 'redirects to the external issue tracker' do
        external = double(new_issue_path: 'https://example.com/issues/new')
        allow(project).to receive(:external_issue_tracker).and_return(external)
        controller.instance_variable_set(:@project, project)

        get :new, namespace_id: project.namespace.path, project_id: project

        expect(response).to redirect_to('https://example.com/issues/new')
67
      end
68
    end
69 70
  end

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
  describe 'PUT #update' do
    context 'when moving issue to another private project' do
      let(:another_project) { create(:project, :private) }

      before do
        sign_in(user)
        project.team << [user, :developer]
      end

      context 'when user has access to move issue' do
        before { another_project.team << [user, :reporter] }

        it 'moves issue to another project' do
          move_issue

          expect(response).to have_http_status :found
87
          expect(another_project.issues).not_to be_empty
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
        end
      end

      context 'when user does not have access to move issue' do
        it 'responds with 404' do
          move_issue

          expect(response).to have_http_status :not_found
        end
      end

      def move_issue
        put :update,
          namespace_id: project.namespace.to_param,
          project_id: project.to_param,
          id: issue.iid,
          issue: { title: 'New title' },
          move_to_project_id: another_project.id
      end
    end
  end

110
  describe 'Confidential Issues' do
111
    let(:project) { create(:project_empty_repo, :public) }
112 113 114 115 116 117 118 119 120 121
    let(:assignee) { create(:assignee) }
    let(:author) { create(:user) }
    let(:non_member) { create(:user) }
    let(:member) { create(:user) }
    let(:admin) { create(:admin) }
    let!(:issue) { create(:issue, project: project) }
    let!(:unescaped_parameter_value) { create(:issue, :confidential, project: project, author: author) }
    let!(:request_forgery_timing_attack) { create(:issue, :confidential, project: project, assignee: assignee) }

    describe 'GET #index' do
122
      it 'does not list confidential issues for guests' do
123 124 125 126 127 128
        sign_out(:user)
        get_issues

        expect(assigns(:issues)).to eq [issue]
      end

129
      it 'does not list confidential issues for non project members' do
130 131 132 133 134 135
        sign_in(non_member)
        get_issues

        expect(assigns(:issues)).to eq [issue]
      end

136
      it 'does not list confidential issues for project members with guest role' do
137 138 139 140 141 142 143 144
        sign_in(member)
        project.team << [member, :guest]

        get_issues

        expect(assigns(:issues)).to eq [issue]
      end

145
      it 'lists confidential issues for author' do
146 147 148 149 150 151 152
        sign_in(author)
        get_issues

        expect(assigns(:issues)).to include unescaped_parameter_value
        expect(assigns(:issues)).not_to include request_forgery_timing_attack
      end

153
      it 'lists confidential issues for assignee' do
154 155 156 157 158 159 160
        sign_in(assignee)
        get_issues

        expect(assigns(:issues)).not_to include unescaped_parameter_value
        expect(assigns(:issues)).to include request_forgery_timing_attack
      end

161
      it 'lists confidential issues for project members' do
162 163 164 165 166 167 168 169 170
        sign_in(member)
        project.team << [member, :developer]

        get_issues

        expect(assigns(:issues)).to include unescaped_parameter_value
        expect(assigns(:issues)).to include request_forgery_timing_attack
      end

171
      it 'lists confidential issues for admin' do
172 173 174 175 176 177 178 179 180 181 182 183 184
        sign_in(admin)
        get_issues

        expect(assigns(:issues)).to include unescaped_parameter_value
        expect(assigns(:issues)).to include request_forgery_timing_attack
      end

      def get_issues
        get :index,
          namespace_id: project.namespace.to_param,
          project_id: project.to_param
      end
    end
185

186 187
    shared_examples_for 'restricted action' do |http_status|
      it 'returns 404 for guests' do
188
        sign_out(:user)
189 190 191 192 193 194 195 196 197
        go(id: unescaped_parameter_value.to_param)

        expect(response).to have_http_status :not_found
      end

      it 'returns 404 for non project members' do
        sign_in(non_member)
        go(id: unescaped_parameter_value.to_param)

198 199 200 201 202 203 204 205
        expect(response).to have_http_status :not_found
      end

      it 'returns 404 for project members with guest role' do
        sign_in(member)
        project.team << [member, :guest]
        go(id: unescaped_parameter_value.to_param)

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
        expect(response).to have_http_status :not_found
      end

      it "returns #{http_status[:success]} for author" do
        sign_in(author)
        go(id: unescaped_parameter_value.to_param)

        expect(response).to have_http_status http_status[:success]
      end

      it "returns #{http_status[:success]} for assignee" do
        sign_in(assignee)
        go(id: request_forgery_timing_attack.to_param)

        expect(response).to have_http_status http_status[:success]
      end

      it "returns #{http_status[:success]} for project members" do
        sign_in(member)
        project.team << [member, :developer]
        go(id: unescaped_parameter_value.to_param)

        expect(response).to have_http_status http_status[:success]
      end

      it "returns #{http_status[:success]} for admin" do
        sign_in(admin)
        go(id: unescaped_parameter_value.to_param)

        expect(response).to have_http_status http_status[:success]
      end
    end

    describe 'GET #show' do
      it_behaves_like 'restricted action', success: 200

      def go(id:)
        get :show,
          namespace_id: project.namespace.to_param,
          project_id: project.to_param,
          id: id
      end
    end

    describe 'GET #edit' do
      it_behaves_like 'restricted action', success: 200

      def go(id:)
        get :edit,
          namespace_id: project.namespace.to_param,
          project_id: project.to_param,
          id: id
      end
    end

    describe 'PUT #update' do
      it_behaves_like 'restricted action', success: 302

      def go(id:)
        put :update,
          namespace_id: project.namespace.to_param,
          project_id: project.to_param,
          id: id,
          issue: { title: 'New title' }
      end
    end
272
  end
273

274 275 276
  describe 'POST #create' do
    context 'Akismet is enabled' do
      before do
277
        allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
278
        allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
      end

      def post_spam_issue
        sign_in(user)
        spam_project = create(:empty_project, :public)
        post :create, {
          namespace_id: spam_project.namespace.to_param,
          project_id: spam_project.to_param,
          issue: { title: 'Spam Title', description: 'Spam lives here' }
        }
      end

      it 'rejects an issue recognized as spam' do
        expect{ post_spam_issue }.not_to change(Issue, :count)
        expect(response).to render_template(:new)
      end

      it 'creates a spam log' do
        post_spam_issue
        spam_logs = SpamLog.all
        expect(spam_logs.count).to eq(1)
        expect(spam_logs[0].title).to eq('Spam Title')
      end
    end
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

    context 'user agent details are saved' do
      before do
        request.env['action_dispatch.remote_ip'] = '127.0.0.1'
      end

      def post_new_issue
        sign_in(user)
        project = create(:empty_project, :public)
        post :create, {
          namespace_id: project.namespace.to_param,
          project_id: project.to_param,
          issue: { title: 'Title', description: 'Description' }
        }
      end

      it 'creates a user agent detail' do
320
        expect{ post_new_issue }.to change(UserAgentDetail, :count).by(1)
321 322
      end
    end
323 324
  end

325 326 327
  describe 'POST #mark_as_spam' do
    context 'properly submits to Akismet' do
      before do
328
        allow_any_instance_of(AkismetService).to receive_messages(submit_spam: true)
329
        allow_any_instance_of(ApplicationSetting).to receive_messages(akismet_enabled: true)
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
      end

      def post_spam
        admin = create(:admin)
        create(:user_agent_detail, subject: issue)
        project.team << [admin, :master]
        sign_in(admin)
        post :mark_as_spam, {
          namespace_id: project.namespace.path,
          project_id: project.path,
          id: issue.iid
        }
      end

      it 'updates issue' do
        post_spam
346
        expect(issue.submittable_as_spam?).to be_falsey
347 348 349 350
      end
    end
  end

351
  describe "DELETE #destroy" do
352 353 354 355
    context "when the user is a developer" do
      before { sign_in(user) }
      it "rejects a developer to destroy an issue" do
        delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid
356
        expect(response).to have_http_status(404)
357
      end
358 359
    end

360 361 362 363 364
    context "when the user is owner" do
      let(:owner)     { create(:user) }
      let(:namespace) { create(:namespace, owner: owner) }
      let(:project)   { create(:project, namespace: namespace) }

365
      before { sign_in(owner) }
366

367
      it "deletes the issue" do
368 369
        delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid

370
        expect(response).to have_http_status(302)
371
        expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./).now
372
      end
373 374 375 376 377 378

      it 'delegates the update of the todos count cache to TodoService' do
        expect_any_instance_of(TodoService).to receive(:destroy_issue).with(issue, owner).once

        delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid
      end
379 380
    end
  end
381 382 383 384 385 386 387

  describe 'POST #toggle_award_emoji' do
    before do
      sign_in(user)
      project.team << [user, :developer]
    end

388
    it "toggles the award emoji" do
389
      expect do
390
        post(:toggle_award_emoji, namespace_id: project.namespace.path,
391 392
                                  project_id: project.path, id: issue.iid, name: "thumbsup")
      end.to change { issue.award_emoji.count }.by(1)
393

394
      expect(response).to have_http_status(200)
395 396
    end
  end
397
end