summaryrefslogtreecommitdiff
path: root/spec/requests/lfs_locks_api_spec.rb
blob: 363a16f014b299b38c242d54a06700acbc1219fe (plain)
1
2
3
4
5
6
7
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Git LFS File Locking API', feature_category: :source_code_management do
  include LfsHttpHelpers
  include WorkhorseHelpers

  let_it_be(:project) { create(:project) }
  let_it_be(:maintainer) { create(:user) }
  let_it_be(:developer) { create(:user) }
  let_it_be(:reporter) { create(:user) }
  let_it_be(:guest) { create(:user) }
  let_it_be(:path) { 'README.md' }

  let(:user) { developer }
  let(:headers) do
    {
      'Authorization' => authorize_user
    }.compact
  end

  shared_examples 'unauthorized request' do
    context 'when user does not have download permission' do
      let(:user) { guest }

      it 'returns a 404 response' do
        post_lfs_json url, body, headers

        expect(response).to have_gitlab_http_status(:not_found)
      end
    end

    context 'when user does not have upload permission' do
      let(:user) { reporter }

      it 'returns a 403 response' do
        post_lfs_json url, body, headers

        expect(response).to have_gitlab_http_status(:forbidden)
      end
    end
  end

  before do
    allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)

    project.add_maintainer(maintainer)
    project.add_developer(developer)
    project.add_reporter(reporter)
    project.add_guest(guest)
  end

  describe 'Create File Lock endpoint' do
    let(:url) { "#{project.http_url_to_repo}/info/lfs/locks" }
    let(:body) { { path: path } }

    include_examples 'unauthorized request'

    context 'with an existent lock' do
      before do
        lock_file('README.md', developer)
      end

      it 'return an error message' do
        post_lfs_json url, body, headers

        expect(response).to have_gitlab_http_status(:conflict)

        expect(json_response.keys).to match_array(%w(lock message documentation_url))
        expect(json_response['message']).to match(/already locked/)
      end

      it 'returns the existen lock' do
        post_lfs_json url, body, headers

        expect(json_response['lock']['path']).to eq('README.md')
      end
    end

    context 'without an existent lock' do
      it 'creates the lock' do
        post_lfs_json url, body, headers

        expect(response).to have_gitlab_http_status(:created)

        expect(json_response['lock'].keys).to match_array(%w(id path locked_at owner))
      end
    end
  end

  describe 'Listing File Locks endpoint' do
    let(:url) { "#{project.http_url_to_repo}/info/lfs/locks" }

    include_examples 'unauthorized request'

    it 'returns the list of locked files' do
      lock_file('README.md', developer)
      lock_file('README', developer)

      do_get url, nil, headers

      expect(response).to have_gitlab_http_status(:ok)

      expect(json_response['locks'].size).to eq(2)
      expect(json_response['locks'].first.keys).to match_array(%w(id path locked_at owner))
    end
  end

  describe 'List File Locks for verification endpoint' do
    let(:url) { "#{project.http_url_to_repo}/info/lfs/locks/verify" }

    include_examples 'unauthorized request'

    it 'returns the list of locked files grouped by owner' do
      lock_file('README.md', maintainer)
      lock_file('README', developer)

      post_lfs_json url, nil, headers

      expect(response).to have_gitlab_http_status(:ok)

      expect(json_response['ours'].size).to eq(1)
      expect(json_response['ours'].first['path']).to eq('README')
      expect(json_response['theirs'].size).to eq(1)
      expect(json_response['theirs'].first['path']).to eq('README.md')
    end
  end

  describe 'Delete File Lock endpoint' do
    let!(:lock) { lock_file('README.md', developer) }
    let(:url) { "#{project.http_url_to_repo}/info/lfs/locks/#{lock[:id]}/unlock" }

    include_examples 'unauthorized request'

    context 'with an existent lock' do
      it 'deletes the lock' do
        post_lfs_json url, nil, headers

        expect(response).to have_gitlab_http_status(:ok)
      end

      it 'returns the deleted lock' do
        post_lfs_json url, nil, headers

        expect(json_response['lock'].keys).to match_array(%w(id path locked_at owner))
      end

      context 'when a maintainer uses force' do
        let(:user) { maintainer }

        it 'deletes the lock' do
          project.add_maintainer(maintainer)
          post_lfs_json url, { force: true }, headers

          expect(response).to have_gitlab_http_status(:ok)
        end
      end
    end
  end

  def lock_file(path, author)
    result = Lfs::LockFileService.new(project, author, { path: path }).execute

    result[:lock]
  end

  def do_get(url, params = nil, headers = nil)
    get(url, params: (params || {}), headers: (headers || {}).merge('Content-Type' => LfsRequest::CONTENT_TYPE))
  end
end