blob_controller_spec.rb 12.0 KB
Newer Older
1 2 3
require 'rails_helper'

describe Projects::BlobController do
B
Bob Van Landuyt 已提交
4 5
  include ProjectForksHelper

6
  let(:project) { create(:project, :public, :repository) }
7

S
Sean McGivern 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
  describe "GET show" do
    render_views

    context 'with file path' do
      before do
        get(:show,
            namespace_id: project.namespace,
            project_id: project,
            id: id)
      end

      context "valid branch, valid file" do
        let(:id) { 'master/README.md' }
        it { is_expected.to respond_with(:success) }
      end

      context "valid branch, invalid file" do
        let(:id) { 'master/invalid-path.rb' }
        it { is_expected.to respond_with(:not_found) }
      end

      context "invalid branch, valid file" do
        let(:id) { 'invalid-branch/README.md' }
        it { is_expected.to respond_with(:not_found) }
      end

      context "binary file" do
        let(:id) { 'binary-encoding/encoding/binary-1.bin' }
        it { is_expected.to respond_with(:success) }
      end
    end

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    context 'with file path and JSON format' do
      context "valid branch, valid file" do
        let(:id) { 'master/README.md' }

        before do
          get(:show,
              namespace_id: project.namespace,
              project_id: project,
              id: id,
              format: :json)
        end

        it do
          expect(response).to be_ok
          expect(json_response).to have_key 'html'
55
          expect(json_response).to have_key 'raw_path'
56 57
        end
      end
58

59
      context "with viewer=none" do
60 61 62 63 64 65 66 67
        let(:id) { 'master/README.md' }

        before do
          get(:show,
              namespace_id: project.namespace,
              project_id: project,
              id: id,
              format: :json,
68
              viewer: 'none')
69 70 71 72
        end

        it do
          expect(response).to be_ok
73
          expect(json_response).not_to have_key 'html'
74
          expect(json_response).to have_key 'raw_path'
75 76
        end
      end
77 78
    end

S
Sean McGivern 已提交
79 80 81 82 83 84 85 86 87 88 89 90
    context 'with tree path' do
      before do
        get(:show,
            namespace_id: project.namespace,
            project_id: project,
            id: id)
        controller.instance_variable_set(:@blob, nil)
      end

      context 'redirect to tree' do
        let(:id) { 'markdown/doc' }
        it 'redirects' do
91
          expect(subject)
92
            .to redirect_to("/#{project.full_path}/tree/markdown/doc")
S
Sean McGivern 已提交
93 94 95 96 97
        end
      end
    end
  end

98
  describe 'GET diff' do
E
Eric Eastwood 已提交
99 100
    let(:user) { create(:user) }

101 102 103
    render_views

    def do_get(opts = {})
104 105
      params = { namespace_id: project.namespace,
                 project_id: project,
106 107 108 109
                 id: 'master/CHANGELOG' }
      get :diff, params.merge(opts)
    end

E
Eric Eastwood 已提交
110
    before do
111
      project.add_maintainer(user)
E
Eric Eastwood 已提交
112 113 114 115

      sign_in(user)
    end

116 117 118 119 120 121 122 123 124
    context 'when essential params are missing' do
      it 'renders nothing' do
        do_get

        expect(response.body).to be_blank
      end
    end

    context 'when essential params are present' do
F
Felipe Artur 已提交
125 126 127
      context 'when rendering for commit' do
        it 'renders the diff content' do
          do_get(since: 1, to: 5, offset: 10)
128

F
Felipe Artur 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
          expect(response.body).to be_present
        end
      end

      context 'when rendering for merge request' do
        it 'renders diff context lines Gitlab::Diff::Line array' do
          do_get(since: 1, to: 5, offset: 10, from_merge_request: true)

          lines = JSON.parse(response.body)

          expect(lines.first).to have_key('type')
          expect(lines.first).to have_key('rich_text')
          expect(lines.first).to have_key('rich_text')
        end

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        context 'comment in any diff line feature flag' do
          it 'renders context lines when feature disabled' do
            stub_feature_flags(comment_in_any_diff_line: false)

            do_get(since: 1, to: 5, offset: 10, from_merge_request: true)
            lines = JSON.parse(response.body)
            all_context = lines.all? { |line| line['type'] == 'context' }

            expect(all_context).to be(true)
          end

          it 'renders unchanged lines when feature enabled' do
            stub_feature_flags(comment_in_any_diff_line: true)

            do_get(since: 1, to: 5, offset: 10, from_merge_request: true)
            lines = JSON.parse(response.body)
            all_unchanged = lines.all? { |line| line['type'].nil? }

            expect(all_unchanged).to be(true)
          end
        end

F
Felipe Artur 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        context 'when rendering match lines' do
          it 'adds top match line when "since" is less than 1' do
            do_get(since: 5, to: 10, offset: 10, from_merge_request: true)

            match_line = JSON.parse(response.body).first

            expect(match_line['type']).to eq('match')
            expect(match_line['meta_data']).to have_key('old_pos')
            expect(match_line['meta_data']).to have_key('new_pos')
          end

          it 'does not add top match line when when "since" is equal 1' do
            do_get(since: 1, to: 10, offset: 10, from_merge_request: true)

            match_line = JSON.parse(response.body).first

182
            expect(match_line['type']).to be_nil
F
Felipe Artur 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
          end

          it 'adds bottom match line when "t"o is less than blob size' do
            do_get(since: 1, to: 5, offset: 10, from_merge_request: true, bottom: true)

            match_line = JSON.parse(response.body).last

            expect(match_line['type']).to eq('match')
            expect(match_line['meta_data']).to have_key('old_pos')
            expect(match_line['meta_data']).to have_key('new_pos')
          end

          it 'does not add bottom match line when "to" is less than blob size' do
            commit_id = project.repository.commit('master').id
            blob = project.repository.blob_at(commit_id, 'CHANGELOG')
            do_get(since: 1, to: blob.lines.count, offset: 10, from_merge_request: true, bottom: true)

            match_line = JSON.parse(response.body).last

202
            expect(match_line['type']).to be_nil
F
Felipe Artur 已提交
203 204
          end
        end
205 206 207
      end
    end
  end
208

E
Eric Eastwood 已提交
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
  describe 'GET edit' do
    let(:default_params) do
      {
        namespace_id: project.namespace,
        project_id: project,
        id: 'master/CHANGELOG'
      }
    end

    context 'anonymous' do
      before do
        get :edit, default_params
      end

      it 'redirects to sign in and returns' do
        expect(response).to redirect_to(new_user_session_path)
      end
    end

    context 'as guest' do
      let(:guest) { create(:user) }

      before do
        sign_in(guest)
        get :edit, default_params
      end

      it 'redirects to blob show' do
237
        expect(response).to redirect_to(project_blob_path(project, 'master/CHANGELOG'))
E
Eric Eastwood 已提交
238 239 240 241 242 243 244
      end
    end

    context 'as developer' do
      let(:developer) { create(:user) }

      before do
245
        project.add_developer(developer)
E
Eric Eastwood 已提交
246 247 248 249 250
        sign_in(developer)
        get :edit, default_params
      end

      it 'redirects to blob show' do
251
        expect(response).to have_gitlab_http_status(200)
E
Eric Eastwood 已提交
252 253 254
      end
    end

255 256
    context 'as maintainer' do
      let(:maintainer) { create(:user) }
E
Eric Eastwood 已提交
257 258

      before do
259 260
        project.add_maintainer(maintainer)
        sign_in(maintainer)
E
Eric Eastwood 已提交
261 262 263 264
        get :edit, default_params
      end

      it 'redirects to blob show' do
265
        expect(response).to have_gitlab_http_status(200)
E
Eric Eastwood 已提交
266 267 268 269
      end
    end
  end

270
  describe 'PUT update' do
E
Eric Eastwood 已提交
271
    let(:user) { create(:user) }
272 273
    let(:default_params) do
      {
274 275
        namespace_id: project.namespace,
        project_id: project,
276
        id: 'master/CHANGELOG',
D
Douwe Maan 已提交
277
        branch_name: 'master',
278 279 280 281 282 283
        content: 'Added changes',
        commit_message: 'Update CHANGELOG'
      }
    end

    def blob_after_edit_path
284
      project_blob_path(project, 'master/CHANGELOG')
285 286
    end

E
Eric Eastwood 已提交
287
    before do
288
      project.add_maintainer(user)
E
Eric Eastwood 已提交
289 290 291 292

      sign_in(user)
    end

293 294 295 296 297 298 299 300 301 302 303 304 305
    it 'redirects to blob' do
      put :update, default_params

      expect(response).to redirect_to(blob_after_edit_path)
    end

    context '?from_merge_request_iid' do
      let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
      let(:mr_params) { default_params.merge(from_merge_request_iid: merge_request.iid) }

      it 'redirects to MR diff' do
        put :update, mr_params

306
        after_edit_path = diffs_project_merge_request_path(project, merge_request)
307
        file_anchor = "##{Digest::SHA1.hexdigest('CHANGELOG')}"
308 309 310 311 312
        expect(response).to redirect_to(after_edit_path + file_anchor)
      end

      context "when user doesn't have access" do
        before do
313
          other_project = create(:project, :repository)
314 315 316 317 318 319 320 321 322 323
          merge_request.update!(source_project: other_project, target_project: other_project)
        end

        it "it redirect to blob" do
          put :update, mr_params

          expect(response).to redirect_to(blob_after_edit_path)
        end
      end
    end
324 325

    context 'when user has forked project' do
B
Bob Van Landuyt 已提交
326 327
      let!(:forked_project) { fork_project(project, guest, namespace: guest.namespace, repository: true) }
      let(:guest) { create(:user) }
328

329 330 331
      before do
        sign_in(guest)
      end
332

333 334
      context 'when editing on the fork' do
        before do
335 336
          default_params[:namespace_id] = forked_project.namespace
          default_params[:project_id] = forked_project
337 338 339 340 341
        end

        it 'redirects to blob' do
          put :update, default_params

342
          expect(response).to redirect_to(project_blob_path(forked_project, 'master/CHANGELOG'))
343 344 345 346 347
        end
      end

      context 'when editing on the original repository' do
        it "redirects to forked project new merge request" do
D
Douwe Maan 已提交
348
          default_params[:branch_name] = "fork-test-1"
349 350 351 352 353
          default_params[:create_merge_request] = 1

          put :update, default_params

          expect(response).to redirect_to(
354
            project_new_merge_request_path(
355 356 357 358
              forked_project,
              merge_request: {
                source_project_id: forked_project.id,
                target_project_id: project.id,
359
                source_branch: "fork-test-1",
360 361 362
                target_branch: "master"
              }
            )
363
          )
364
        end
365 366
      end
    end
367
  end
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

  describe 'DELETE destroy' do
    let(:user) { create(:user) }
    let(:project_root_path) { project_tree_path(project, 'master') }

    before do
      project.add_maintainer(user)

      sign_in(user)
    end

    context 'for a file in a subdirectory' do
      let(:default_params) do
        {
          namespace_id: project.namespace,
          project_id: project,
          id: 'master/files/whitespace',
          original_branch: 'master',
          branch_name: 'master',
          commit_message: 'Delete whitespace'
        }
      end

      let(:after_delete_path) { project_tree_path(project, 'master/files') }

      it 'redirects to the sub directory' do
        delete :destroy, default_params

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

    context 'if deleted file is the last one in a subdirectory' do
      let(:default_params) do
        {
          namespace_id: project.namespace,
          project_id: project,
          id: 'master/bar/branch-test.txt',
          original_branch: 'master',
          branch_name: 'master',
          commit_message: 'Delete whitespace'
        }
      end

      it 'redirects to the project root' do
        delete :destroy, default_params

        expect(response).to redirect_to(project_root_path)
      end

      context 'when deleting a file in a branch other than master' do
        let(:default_params) do
          {
            namespace_id: project.namespace,
            project_id: project,
            id: 'binary-encoding/foo/bar/.gitkeep',
            original_branch: 'binary-encoding',
            branch_name: 'binary-encoding',
            commit_message: 'Delete whitespace'
          }
        end

        let(:after_delete_path) { project_tree_path(project, 'binary-encoding') }

        it 'redirects to the project root of the branch' do
          delete :destroy, default_params

          expect(response).to redirect_to(after_delete_path)
        end
      end
    end
  end
440
end