projects_controller_spec.rb 30.3 KB
Newer Older
1 2 3
require('spec_helper')

describe ProjectsController do
4 5
  include ProjectForksHelper

6 7
  let(:project) { create(:project) }
  let(:public_project) { create(:project, :public) }
8
  let(:user) { create(:user) }
9 10
  let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
  let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
11

12 13 14 15 16 17 18 19 20 21 22 23 24
  describe 'GET new' do
    context 'with an authenticated user' do
      let(:group) { create(:group) }

      before do
        sign_in(user)
      end

      context 'when namespace_id param is present' do
        context 'when user has access to the namespace' do
          it 'renders the template' do
            group.add_owner(user)

blackst0ne's avatar
blackst0ne committed
25
            get :new, params: { namespace_id: group.id }
26

27
            expect(response).to have_gitlab_http_status(200)
28 29 30 31 32 33
            expect(response).to render_template('new')
          end
        end

        context 'when user does not have access to the namespace' do
          it 'responds with status 404' do
blackst0ne's avatar
blackst0ne committed
34
            get :new, params: { namespace_id: group.id }
35

36
            expect(response).to have_gitlab_http_status(404)
37 38 39 40 41 42 43
            expect(response).not_to render_template('new')
          end
        end
      end
    end
  end

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  describe 'GET index' do
    context 'as a user' do
      it 'redirects to root page' do
        sign_in(user)

        get :index

        expect(response).to redirect_to(root_path)
      end
    end

    context 'as a guest' do
      it 'redirects to Explore page' do
        get :index

        expect(response).to redirect_to(explore_root_path)
      end
    end
  end

64
  describe "GET show" do
65
    context "user not project member" do
66 67 68
      before do
        sign_in(user)
      end
69 70

      context "user does not have access to project" do
71
        let(:private_project) { create(:project, :private) }
72 73

        it "does not initialize notification setting" do
blackst0ne's avatar
blackst0ne committed
74
          get :show, params: { namespace_id: private_project.namespace, id: private_project }
75 76 77 78 79 80 81
          expect(assigns(:notification_setting)).to be_nil
        end
      end

      context "user has access to project" do
        context "and does not have notification setting" do
          it "initializes notification as disabled" do
blackst0ne's avatar
blackst0ne committed
82
            get :show, params: { namespace_id: public_project.namespace, id: public_project }
83
            expect(assigns(:notification_setting).level).to eq("global")
84 85 86 87 88 89
          end
        end

        context "and has notification setting" do
          before do
            setting = user.notification_settings_for(public_project)
90
            setting.level = :watch
91 92 93 94
            setting.save
          end

          it "shows current notification setting" do
blackst0ne's avatar
blackst0ne committed
95
            get :show, params: { namespace_id: public_project.namespace, id: public_project }
96
            expect(assigns(:notification_setting).level).to eq("watch")
97 98 99
          end
        end
      end
100 101 102 103 104

      describe "when project repository is disabled" do
        render_views

        before do
105
          project.add_developer(user)
106 107 108 109
          project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED)
        end

        it 'shows wiki homepage' do
blackst0ne's avatar
blackst0ne committed
110
          get :show, params: { namespace_id: project.namespace, id: project }
111 112 113 114 115 116

          expect(response).to render_template('projects/_wiki')
        end

        it 'shows issues list page if wiki is disabled' do
          project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
117
          create(:issue, project: project)
118

blackst0ne's avatar
blackst0ne committed
119
          get :show, params: { namespace_id: project.namespace, id: project }
120 121

          expect(response).to render_template('projects/issues/_issues')
122
          expect(assigns(:issuable_meta_data)).not_to be_nil
123 124 125 126 127 128
        end

        it 'shows customize workflow page if wiki and issues are disabled' do
          project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
          project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)

blackst0ne's avatar
blackst0ne committed
129
          get :show, params: { namespace_id: project.namespace, id: project }
130 131 132 133 134 135 136

          expect(response).to render_template("projects/_customize_workflow")
        end

        it 'shows activity if enabled by user' do
          user.update_attribute(:project_view, 'activity')

blackst0ne's avatar
blackst0ne committed
137
          get :show, params: { namespace_id: project.namespace, id: project }
138 139 140 141

          expect(response).to render_template("projects/_activity")
        end
      end
142
    end
143

144
    context 'when the storage is not available', :broken_storage do
145 146
      set(:project) { create(:project, :broken_storage) }

147 148 149 150 151 152
      before do
        project.add_developer(user)
        sign_in(user)
      end

      it 'renders a 503' do
blackst0ne's avatar
blackst0ne committed
153
        get :show, params: { namespace_id: project.namespace, id: project }
154

155
        expect(response).to have_gitlab_http_status(503)
156 157 158
      end
    end

159 160 161
    context "project with empty repo" do
      let(:empty_project) { create(:project_empty_repo, :public) }

162 163 164
      before do
        sign_in(user)
      end
165 166 167 168

      User.project_views.keys.each do |project_view|
        context "with #{project_view} view set" do
          before do
Lin Jen-Shin's avatar
Lin Jen-Shin committed
169
            user.update(project_view: project_view)
170

blackst0ne's avatar
blackst0ne committed
171
            get :show, params: { namespace_id: empty_project.namespace, id: empty_project }
172 173 174 175 176 177 178 179 180
          end

          it "renders the empty project view" do
            expect(response).to render_template('empty')
          end
        end
      end
    end

181 182 183
    context "project with broken repo" do
      let(:empty_project) { create(:project_broken_repo, :public) }

184 185 186
      before do
        sign_in(user)
      end
187 188 189 190

      User.project_views.keys.each do |project_view|
        context "with #{project_view} view set" do
          before do
Lin Jen-Shin's avatar
Lin Jen-Shin committed
191
            user.update(project_view: project_view)
192

blackst0ne's avatar
blackst0ne committed
193
            get :show, params: { namespace_id: empty_project.namespace, id: empty_project }
194 195 196 197 198 199 200 201 202 203 204
          end

          it "renders the empty project view" do
            allow(Project).to receive(:repo).and_raise(Gitlab::Git::Repository::NoRepository)

            expect(response).to render_template('projects/no_repo')
          end
        end
      end
    end

205
    context "rendering default project view" do
206 207
      let(:public_project) { create(:project, :public, :repository) }

208
      render_views
209

Douwe Maan's avatar
Douwe Maan committed
210
      it "renders the activity view" do
211 212
        allow(controller).to receive(:current_user).and_return(user)
        allow(user).to receive(:project_view).and_return('activity')
Douwe Maan's avatar
Douwe Maan committed
213

blackst0ne's avatar
blackst0ne committed
214
        get :show, params: { namespace_id: public_project.namespace, id: public_project }
215 216 217
        expect(response).to render_template('_activity')
      end

Douwe Maan's avatar
Douwe Maan committed
218
      it "renders the files view" do
219 220
        allow(controller).to receive(:current_user).and_return(user)
        allow(user).to receive(:project_view).and_return('files')
Douwe Maan's avatar
Douwe Maan committed
221

blackst0ne's avatar
blackst0ne committed
222
        get :show, params: { namespace_id: public_project.namespace, id: public_project }
223 224
        expect(response).to render_template('_files')
      end
225 226 227 228 229

      it "renders the readme view" do
        allow(controller).to receive(:current_user).and_return(user)
        allow(user).to receive(:project_view).and_return('readme')

blackst0ne's avatar
blackst0ne committed
230
        get :show, params: { namespace_id: public_project.namespace, id: public_project }
231 232
        expect(response).to render_template('_readme')
      end
233
    end
234

235
    context "when the url contains .atom" do
236
      let(:public_project_with_dot_atom) { build(:project, :public, name: 'my.atom', path: 'my.atom') }
237

238
      it 'expects an error creating the project' do
239
        expect(public_project_with_dot_atom).not_to be_valid
240 241
      end
    end
242 243 244

    context 'when the project is pending deletions' do
      it 'renders a 404 error' do
245
        project = create(:project, pending_delete: true)
246 247
        sign_in(user)

blackst0ne's avatar
blackst0ne committed
248
        get :show, params: { namespace_id: project.namespace, id: project }
249 250 251 252

        expect(response.status).to eq 404
      end
    end
253 254 255

    context "redirection from http://someproject.git" do
      it 'redirects to project page (format.html)' do
256
        project = create(:project, :public)
257

blackst0ne's avatar
blackst0ne committed
258
        get :show, params: { namespace_id: project.namespace, id: project }, format: :git
259

260
        expect(response).to have_gitlab_http_status(302)
261 262 263
        expect(response).to redirect_to(namespace_project_path)
      end
    end
264 265 266

    context 'when the project is forked and has a repository', :request_store do
      let(:public_project) { create(:project, :public, :repository) }
267
      let(:other_user) { create(:user) }
268 269 270 271 272

      render_views

      before do
        # View the project as a user that does not have any rights
273
        sign_in(other_user)
274 275 276 277 278

        fork_project(public_project)
      end

      it 'does not increase the number of queries when the project is forked' do
279
        expected_query = /#{public_project.fork_network.find_forks_in(other_user.namespace).to_sql}/
280

blackst0ne's avatar
blackst0ne committed
281
        expect { get(:show, params: { namespace_id: public_project.namespace, id: public_project }) }
282
          .not_to exceed_query_limit(2).for_query(expected_query)
283 284
      end
    end
285
  end
Stan Hu's avatar
Stan Hu committed
286

287 288 289 290 291 292
  describe 'GET edit' do
    it 'sets the badge API endpoint' do
      sign_in(user)
      project.add_maintainer(user)

      get :edit,
blackst0ne's avatar
blackst0ne committed
293 294 295 296
          params: {
            namespace_id: project.namespace.path,
            id: project.path
          }
297 298 299 300 301

      expect(assigns(:badge_api_endpoint)).not_to be_nil
    end
  end

302 303 304 305
  describe "#update" do
    render_views

    let(:admin) { create(:admin) }
306 307 308 309

    before do
      sign_in(admin)
    end
310

Nick Thomas's avatar
Nick Thomas committed
311 312 313
    shared_examples_for 'updating a project' do
      context 'when only renaming a project path' do
        it "sets the repository to the right path after a rename" do
314 315 316
          original_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
            project.repository.path
          end
317

Nick Thomas's avatar
Nick Thomas committed
318 319 320
          expect { update_project path: 'renamed_path' }
            .to change { project.reload.path }
          expect(project.path).to include 'renamed_path'
321

322 323 324 325
          assign_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
            assigns(:repository).path
          end

Nick Thomas's avatar
Nick Thomas committed
326
          if project.hashed_storage?(:repository)
327
            expect(assign_repository_path).to eq(original_repository_path)
Nick Thomas's avatar
Nick Thomas committed
328
          else
329
            expect(assign_repository_path).to include(project.path)
Nick Thomas's avatar
Nick Thomas committed
330 331 332 333
          end

          expect(response).to have_gitlab_http_status(302)
        end
334
      end
335

Nick Thomas's avatar
Nick Thomas committed
336 337 338 339 340 341 342 343 344 345
      context 'when project has container repositories with tags' do
        before do
          stub_container_registry_config(enabled: true)
          stub_container_registry_tags(repository: /image/, tags: %w[rc1])
          create(:container_repository, project: project, name: :image)
        end

        it 'does not allow to rename the project' do
          expect { update_project path: 'renamed_path' }
            .not_to change { project.reload.path }
346

347
          expect(controller).to set_flash.now[:alert].to(/container registry tags/)
Nick Thomas's avatar
Nick Thomas committed
348 349
          expect(response).to have_gitlab_http_status(200)
        end
350 351
      end

Nick Thomas's avatar
Nick Thomas committed
352 353 354 355 356 357
      it 'updates Fast Forward Merge attributes' do
        controller.instance_variable_set(:@project, project)

        params = {
          merge_method: :ff
        }
358

Nick Thomas's avatar
Nick Thomas committed
359
        put :update,
blackst0ne's avatar
blackst0ne committed
360 361 362 363 364
            params: {
              namespace_id: project.namespace,
              id: project.id,
              project: params
            }
365

Nick Thomas's avatar
Nick Thomas committed
366 367 368 369 370
        expect(response).to have_gitlab_http_status(302)
        params.each do |param, value|
          expect(project.public_send(param)).to eq(value)
        end
      end
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385
      it 'does not update namespace' do
        controller.instance_variable_set(:@project, project)

        params = {
          namespace_id: 'test'
        }

        expect do
          put :update,
            params: {
              namespace_id: project.namespace,
              id: project.id,
              project: params
            }
386
        end.not_to change { project.namespace.reload }
387 388
      end

Nick Thomas's avatar
Nick Thomas committed
389 390
      def update_project(**parameters)
        put :update,
blackst0ne's avatar
blackst0ne committed
391 392 393 394 395
            params: {
              namespace_id: project.namespace.path,
              id: project.path,
              project: parameters
            }
396 397 398
      end
    end

Nick Thomas's avatar
Nick Thomas committed
399 400 401 402 403 404 405 406 407 408
    context 'hashed storage' do
      let(:project) { create(:project, :repository) }

      it_behaves_like 'updating a project'
    end

    context 'legacy storage' do
      let(:project) { create(:project, :repository, :legacy_storage) }

      it_behaves_like 'updating a project'
409 410 411
    end
  end

412 413 414
  describe '#transfer' do
    render_views

415
    let(:project) { create(:project, :repository) }
416 417 418 419 420 421 422
    let(:admin) { create(:admin) }
    let(:new_namespace) { create(:namespace) }

    it 'updates namespace' do
      sign_in(admin)

      put :transfer,
blackst0ne's avatar
blackst0ne committed
423 424 425 426 427
          params: {
            namespace_id: project.namespace.path,
            new_namespace_id: new_namespace.id,
            id: project.path
          },
428 429 430 431
          format: :js

      project.reload

432
      expect(project.namespace).to eq(new_namespace)
433
      expect(response).to have_gitlab_http_status(200)
434 435 436 437 438 439 440
    end

    context 'when new namespace is empty' do
      it 'project namespace is not changed' do
        controller.instance_variable_set(:@project, project)
        sign_in(admin)

441
        old_namespace = project.namespace
442 443

        put :transfer,
blackst0ne's avatar
blackst0ne committed
444 445 446 447 448
            params: {
              namespace_id: old_namespace.path,
              new_namespace_id: nil,
              id: project.path
            },
449 450 451 452
            format: :js

        project.reload

453
        expect(project.namespace).to eq(old_namespace)
454
        expect(response).to have_gitlab_http_status(200)
455
        expect(flash[:alert]).to eq 'Please select a new namespace for your project.'
456 457 458 459
      end
    end
  end

460 461 462 463 464 465 466 467
  describe "#destroy" do
    let(:admin) { create(:admin) }

    it "redirects to the dashboard" do
      controller.instance_variable_set(:@project, project)
      sign_in(admin)

      orig_id = project.id
blackst0ne's avatar
blackst0ne committed
468
      delete :destroy, params: { namespace_id: project.namespace, id: project }
469 470

      expect { Project.find(orig_id) }.to raise_error(ActiveRecord::RecordNotFound)
471
      expect(response).to have_gitlab_http_status(302)
472 473
      expect(response).to redirect_to(dashboard_projects_path)
    end
474

Katarzyna Kobierska's avatar
Katarzyna Kobierska committed
475
    context "when the project is forked" do
476
      let(:project) { create(:project, :repository) }
477
      let(:forked_project) { fork_project(project, nil, repository: true) }
478
      let(:merge_request) do
479
        create(:merge_request,
480
          source_project: forked_project,
481
          target_project: project)
482 483 484
      end

      it "closes all related merge requests" do
485 486
        project.merge_requests << merge_request
        sign_in(admin)
487

blackst0ne's avatar
blackst0ne committed
488
        delete :destroy, params: { namespace_id: forked_project.namespace, id: forked_project }
489 490

        expect(merge_request.reload.state).to eq('closed')
491 492
      end
    end
493 494
  end

495
  describe 'PUT #new_issuable_address for issue' do
496
    subject do
497
      put :new_issuable_address,
blackst0ne's avatar
blackst0ne committed
498 499 500 501 502
        params: {
          namespace_id: project.namespace,
          id: project,
          issuable_type: 'issue'
        }
503 504 505 506 507
      user.reload
    end

    before do
      sign_in(user)
508
      project.add_developer(user)
509 510 511 512
      allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true)
    end

    it 'has http status 200' do
513
      expect(response).to have_gitlab_http_status(200)
514 515 516 517 518 519 520
    end

    it 'changes the user incoming email token' do
      expect { subject }.to change { user.incoming_email_token }
    end

    it 'changes projects new issue address' do
521 522 523 524 525 526 527
      expect { subject }.to change { project.new_issuable_address(user, 'issue') }
    end
  end

  describe 'PUT #new_issuable_address for merge request' do
    subject do
      put :new_issuable_address,
blackst0ne's avatar
blackst0ne committed
528 529 530 531 532
        params: {
          namespace_id: project.namespace,
          id: project,
          issuable_type: 'merge_request'
        }
533 534 535 536 537
      user.reload
    end

    before do
      sign_in(user)
538
      project.add_developer(user)
539 540 541 542 543 544 545 546 547 548 549 550 551
      allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true)
    end

    it 'has http status 200' do
      expect(response).to have_http_status(200)
    end

    it 'changes the user incoming email token' do
      expect { subject }.to change { user.incoming_email_token }
    end

    it 'changes projects new merge request address' do
      expect { subject }.to change { project.new_issuable_address(user, 'merge_request') }
552 553 554
    end
  end

Ciro Santilli's avatar
Ciro Santilli committed
555
  describe "POST #toggle_star" do
556
    it "toggles star if user is signed in" do
Ciro Santilli's avatar
Ciro Santilli committed
557
      sign_in(user)
558
      expect(user.starred?(public_project)).to be_falsey
Stan Hu's avatar
Stan Hu committed
559
      post(:toggle_star,
blackst0ne's avatar
blackst0ne committed
560 561 562 563
           params: {
             namespace_id: public_project.namespace,
             id: public_project
           })
564
      expect(user.starred?(public_project)).to be_truthy
Stan Hu's avatar
Stan Hu committed
565
      post(:toggle_star,
blackst0ne's avatar
blackst0ne committed
566 567 568 569
           params: {
             namespace_id: public_project.namespace,
             id: public_project
           })
570
      expect(user.starred?(public_project)).to be_falsey
Ciro Santilli's avatar
Ciro Santilli committed
571 572 573
    end

    it "does nothing if user is not signed in" do
Stan Hu's avatar
Stan Hu committed
574
      post(:toggle_star,
blackst0ne's avatar
blackst0ne committed
575 576 577 578
           params: {
             namespace_id: project.namespace,
             id: public_project
           })
579
      expect(user.starred?(public_project)).to be_falsey
Stan Hu's avatar
Stan Hu committed
580
      post(:toggle_star,
blackst0ne's avatar
blackst0ne committed
581 582 583 584
           params: {
             namespace_id: project.namespace,
             id: public_project
           })
585
      expect(user.starred?(public_project)).to be_falsey
Ciro Santilli's avatar
Ciro Santilli committed
586 587
    end
  end
588

Douwe Maan's avatar
Douwe Maan committed
589
  describe "DELETE remove_fork" do
590 591 592 593 594 595
    context 'when signed in' do
      before do
        sign_in(user)
      end

      context 'with forked project' do
596
        let(:forked_project) { fork_project(create(:project, :public), user) }
597

598
        it 'removes fork from project' do
599
          delete(:remove_fork,
blackst0ne's avatar
blackst0ne committed
600 601 602 603 604
              params: {
                namespace_id: forked_project.namespace.to_param,
                id: forked_project.to_param
              },
              format: :js)
605

606
          expect(forked_project.reload.forked?).to be_falsey
Douwe Maan's avatar
Douwe Maan committed
607
          expect(flash[:notice]).to eq('The fork relationship has been removed.')
608 609 610 611
          expect(response).to render_template(:remove_fork)
        end
      end

612
      context 'when project not forked' do
613
        let(:unforked_project) { create(:project, namespace: user.namespace) }
614

615
        it 'does nothing if project was not forked' do
616
          delete(:remove_fork,
blackst0ne's avatar
blackst0ne committed
617 618 619 620 621
              params: {
                namespace_id: unforked_project.namespace,
                id: unforked_project
              },
              format: :js)
622 623 624 625

          expect(flash[:notice]).to be_nil
          expect(response).to render_template(:remove_fork)
        end
626 627 628 629
      end
    end

    it "does nothing if user is not signed in" do
630
      delete(:remove_fork,
blackst0ne's avatar
blackst0ne committed
631 632 633 634 635
          params: {
            namespace_id: project.namespace,
            id: project
          },
          format: :js)
636
      expect(response).to have_gitlab_http_status(401)
637 638
    end
  end
639 640

  describe "GET refs" do
641
    let(:project) { create(:project, :public, :repository) }
642

643
    it 'gets a list of branches and tags' do
644
      get :refs, params: { namespace_id: project.namespace, id: project, sort: 'updated_desc' }
645 646

      parsed_body = JSON.parse(response.body)
647 648 649 650
      expect(parsed_body['Branches']).to include('master')
      expect(parsed_body['Tags'].first).to eq('v1.1.0')
      expect(parsed_body['Tags'].last).to eq('v1.0.0')
      expect(parsed_body['Commits']).to be_nil
651 652
    end

653
    it "gets a list of branches, tags and commits" do
654
      get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
655 656 657 658 659 660

      parsed_body = JSON.parse(response.body)
      expect(parsed_body["Branches"]).to include("master")
      expect(parsed_body["Tags"]).to include("v1.0.0")
      expect(parsed_body["Commits"]).to include("123456")
    end
661 662 663 664 665 666 667 668

    context "when preferred language is Japanese" do
      before do
        user.update!(preferred_language: 'ja')
        sign_in(user)
      end

      it "gets a list of branches, tags and commits" do
669
        get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
670 671 672 673 674 675 676

        parsed_body = JSON.parse(response.body)
        expect(parsed_body["Branches"]).to include("master")
        expect(parsed_body["Tags"]).to include("v1.0.0")
        expect(parsed_body["Commits"]).to include("123456")
      end
    end
677 678 679 680 681 682 683 684 685 686

    context 'when private project' do
      let(:project) { create(:project, :repository) }

      context 'as a guest' do
        it 'renders forbidden' do
          user = create(:user)
          project.add_guest(user)

          sign_in(user)
687
          get :refs, params: { namespace_id: project.namespace, id: project }
688 689 690 691 692

          expect(response).to have_gitlab_http_status(404)
        end
      end
    end
693
  end
694 695

  describe 'POST #preview_markdown' do
696
    before do
697
      sign_in(user)
698
    end
699

700
    it 'renders json in a correct format' do
blackst0ne's avatar
blackst0ne committed
701
      post :preview_markdown, params: { namespace_id: public_project.namespace, id: public_project, text: '*Markdown* text' }
702 703 704

      expect(JSON.parse(response.body).keys).to match_array(%w(body references))
    end
705 706 707 708 709 710

    context 'state filter on references' do
      let(:issue) { create(:issue, :closed, project: public_project) }
      let(:merge_request) { create(:merge_request, :closed, target_project: public_project) }

      it 'renders JSON body with state filter for issues' do
blackst0ne's avatar
blackst0ne committed
711 712 713 714 715
        post :preview_markdown, params: {
                                  namespace_id: public_project.namespace,
                                  id: public_project,
                                  text: issue.to_reference
                                }
716 717 718 719 720 721 722

        json_response = JSON.parse(response.body)

        expect(json_response['body']).to match(/\##{issue.iid} \(closed\)/)
      end

      it 'renders JSON body with state filter for MRs' do
blackst0ne's avatar
blackst0ne committed
723 724 725 726 727
        post :preview_markdown, params: {
                                  namespace_id: public_project.namespace,
                                  id: public_project,
                                  text: merge_request.to_reference
                                }
728 729 730 731 732 733

        json_response = JSON.parse(response.body)

        expect(json_response['body']).to match(/\!#{merge_request.iid} \(closed\)/)
      end
    end
734
  end
735

736 737 738 739 740 741 742 743 744
  describe '#ensure_canonical_path' do
    before do
      sign_in(user)
    end

    context 'for a GET request' do
      context 'when requesting the canonical path' do
        context "with exactly matching casing" do
          it "loads the project" do
blackst0ne's avatar
blackst0ne committed
745
            get :show, params: { namespace_id: public_project.namespace, id: public_project }
746 747

            expect(assigns(:project)).to eq(public_project)
748
            expect(response).to have_gitlab_http_status(200)
749 750 751 752 753
          end
        end

        context "with different casing" do
          it "redirects to the normalized path" do
blackst0ne's avatar
blackst0ne committed
754
            get :show, params: { namespace_id: public_project.namespace, id: public_project.path.upcase }
755 756 757 758 759 760 761 762 763 764 765 766

            expect(assigns(:project)).to eq(public_project)
            expect(response).to redirect_to("/#{public_project.full_path}")
            expect(controller).not_to set_flash[:notice]
          end
        end
      end

      context 'when requesting a redirected path' do
        let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }

        it 'redirects to the canonical path' do
blackst0ne's avatar
blackst0ne committed
767
          get :show, params: { namespace_id: 'foo', id: 'bar' }
768 769 770 771 772 773

          expect(response).to redirect_to(public_project)
          expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
        end

        it 'redirects to the canonical path (testing non-show action)' do
blackst0ne's avatar
blackst0ne committed
774
          get :refs, params: { namespace_id: 'foo', id: 'bar' }
775

776
          expect(response).to redirect_to(refs_project_path(public_project))
777 778 779 780 781 782 783 784
          expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
        end
      end
    end

    context 'for a POST request' do
      context 'when requesting the canonical path with different casing' do
        it 'does not 404' do
blackst0ne's avatar
blackst0ne committed
785
          post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project.path.upcase }
786

787
          expect(response).not_to have_gitlab_http_status(404)
788 789 790
        end

        it 'does not redirect to the correct casing' do
blackst0ne's avatar
blackst0ne committed
791
          post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project.path.upcase }
792

793
          expect(response).not_to have_gitlab_http_status(301)
794 795 796 797 798 799 800
        end
      end

      context 'when requesting a redirected path' do
        let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }

        it 'returns not found' do
blackst0ne's avatar
blackst0ne committed
801
          post :toggle_star, params: { namespace_id: 'foo', id: 'bar' }
802

803
          expect(response).to have_gitlab_http_status(404)
804 805 806 807 808 809 810 811 812 813 814
        end
      end
    end

    context 'for a DELETE request' do
      before do
        sign_in(create(:admin))
      end

      context 'when requesting the canonical path with different casing' do
        it 'does not 404' do
blackst0ne's avatar
blackst0ne committed
815
          delete :destroy, params: { namespace_id: project.namespace, id: project.path.upcase }
816

817
          expect(response).not_to have_gitlab_http_status(404)
818 819 820
        end

        it 'does not redirect to the correct casing' do
blackst0ne's avatar
blackst0ne committed
821
          delete :destroy, params: { namespace_id: project.namespace, id: project.path.upcase }
822

823
          expect(response).not_to have_gitlab_http_status(301)
824 825 826 827 828 829 830
        end
      end

      context 'when requesting a redirected path' do
        let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }

        it 'returns not found' do
blackst0ne's avatar
blackst0ne committed
831
          delete :destroy, params: { namespace_id: 'foo', id: 'bar' }
832

833
          expect(response).to have_gitlab_http_status(404)
834 835 836 837 838
        end
      end
    end
  end

839 840 841 842
  describe '#export' do
    before do
      sign_in(user)

843
      project.add_maintainer(user)
844 845 846 847
    end

    context 'when project export is enabled' do
      it 'returns 302' do
blackst0ne's avatar
blackst0ne committed
848
        get :export, params: { namespace_id: project.namespace, id: project }
849

850
        expect(response).to have_gitlab_http_status(302)
851 852 853 854 855 856 857 858 859
      end
    end

    context 'when project export is disabled' do
      before do
        stub_application_setting(project_export_enabled?: false)
      end

      it 'returns 404' do
blackst0ne's avatar
blackst0ne committed
860
        get :export, params: { namespace_id: project.namespace, id: project }
861

862
        expect(response).to have_gitlab_http_status(404)
863 864 865 866 867 868 869 870
      end
    end
  end

  describe '#download_export' do
    before do
      sign_in(user)

871
      project.add_maintainer(user)
872 873
    end

874 875 876
    context 'object storage enabled' do
      context 'when project export is enabled' do
        it 'returns 302' do
blackst0ne's avatar
blackst0ne committed
877
          get :download_export, params: { namespace_id: project.namespace, id: project }
878

879 880 881 882 883 884 885 886 887 888
          expect(response).to have_gitlab_http_status(302)
        end
      end

      context 'when project export is disabled' do
        before do
          stub_application_setting(project_export_enabled?: false)
        end

        it 'returns 404' do
blackst0ne's avatar
blackst0ne committed
889
          get :download_export, params: { namespace_id: project.namespace, id: project }
890 891 892

          expect(response).to have_gitlab_http_status(404)
        end
893 894 895 896 897 898 899 900
      end
    end
  end

  describe '#remove_export' do
    before do
      sign_in(user)

901
      project.add_maintainer(user)
902 903 904 905
    end

    context 'when project export is enabled' do
      it 'returns 302' do
blackst0ne's avatar
blackst0ne committed
906
        post :remove_export, params: { namespace_id: project.namespace, id: project }
907

908
        expect(response).to have_gitlab_http_status(302)
909 910 911 912 913 914 915 916 917
      end
    end

    context 'when project export is disabled' do
      before do
        stub_application_setting(project_export_enabled?: false)
      end

      it 'returns 404' do
blackst0ne's avatar
blackst0ne committed
918
        post :remove_export, params: { namespace_id: project.namespace, id: project }
919

920
        expect(response).to have_gitlab_http_status(404)
921 922 923 924 925 926 927 928
      end
    end
  end

  describe '#generate_new_export' do
    before do
      sign_in(user)

929
      project.add_maintainer(user)
930 931 932 933
    end

    context 'when project export is enabled' do
      it 'returns 302' do
blackst0ne's avatar
blackst0ne committed
934
        post :generate_new_export, params: { namespace_id: project.namespace, id: project }
935

936
        expect(response).to have_gitlab_http_status(302)
937 938 939 940 941 942 943 944 945
      end
    end

    context 'when project export is disabled' do
      before do
        stub_application_setting(project_export_enabled?: false)
      end

      it 'returns 404' do
blackst0ne's avatar
blackst0ne committed
946
        post :generate_new_export, params: { namespace_id: project.namespace, id: project }
947

948
        expect(response).to have_gitlab_http_status(404)
949 950 951 952
      end
    end
  end

953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
  context 'private project with token authentication' do
    let(:private_project) { create(:project, :private) }

    it_behaves_like 'authenticates sessionless user', :show, :atom do
      before do
        default_params.merge!(id: private_project, namespace_id: private_project.namespace)

        private_project.add_maintainer(user)
      end
    end
  end

  context 'public project with token authentication' do
    let(:public_project) { create(:project, :public) }

    it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do
      before do
        default_params.merge!(id: public_project, namespace_id: public_project.namespace)
      end
    end
  end

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
  describe 'GET resolve' do
    shared_examples 'resolvable endpoint' do
      it 'redirects to the project page' do
        get :resolve, params: { id: project.id }

        expect(response).to have_gitlab_http_status(302)
        expect(response).to redirect_to(project_path(project))
      end
    end

    context 'with an authenticated user' do
      before do
        sign_in(user)
      end

      context 'when user has access to the project' do
        before do
          project.add_developer(user)
        end

        it_behaves_like 'resolvable endpoint'
      end

      context 'when user has no access to the project' do
        it 'gives 404 for existing project' do
          get :resolve, params: { id: project.id }

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

      it 'gives 404 for non-existing project' do
        get :resolve, params: { id: '0' }

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

    context 'non authenticated user' do
      context 'with a public project' do
        let(:project) { public_project }

        it_behaves_like 'resolvable endpoint'
      end

      it 'gives 404 for private project' do
        get :resolve, params: { id: project.id }

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

1028 1029 1030
  def project_moved_message(redirect_route, project)
    "Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path."
  end
1031
end