BigW Consortium Gitlab

files_spec.rb 11.2 KB
Newer Older
1 2
require 'spec_helper'

3
describe API::Files, api: true  do
4 5
  include ApiHelpers
  let(:user) { create(:user) }
6 7
  let!(:project) { create(:project, :repository, namespace: user.namespace ) }
  let(:guest) { create(:user) { |u| project.add_guest(u) } }
8
  let(:file_path) { "files%2Fruby%2Fpopen%2Erb" }
9 10 11 12 13
  let(:params) do
    {
      ref: 'master'
    }
  end
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  let(:author_email) { FFaker::Internet.email }

  # I have to remove periods from the end of the name
  # This happened when the user's name had a suffix (i.e. "Sr.")
  # This seems to be what git does under the hood. For example, this commit:
  #
  # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?'
  #
  # results in this:
  #
  # $ git show --pretty
  # ...
  # Author: Foo Sr <foo@example.com>
  # ...
  let(:author_name) { FFaker::Name.name.chomp("\.") }
29

30
  before { project.team << [user, :developer] }
31

32 33 34
  def route(file_path = nil)
    "/projects/#{project.id}/repository/files/#{file_path}"
  end
35

36
  describe "GET /projects/:id/repository/files/:file_path" do
37
    shared_examples_for 'repository files' do
38 39
      it 'returns file attributes as json' do
        get api(route(file_path), current_user), params
40 41

        expect(response).to have_http_status(200)
42
        expect(json_response['file_path']).to eq(CGI.unescape(file_path))
43 44 45 46
        expect(json_response['file_name']).to eq('popen.rb')
        expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
        expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
      end
47

48 49 50 51 52 53 54 55 56 57 58 59
      it 'returns file by commit sha' do
        # This file is deleted on HEAD
        file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee"
        params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"

        get api(route(file_path), current_user), params

        expect(response).to have_http_status(200)
        expect(json_response['file_name']).to eq('commit.js.coffee')
        expect(Base64.decode64(json_response['content']).lines.first).to eq("class Commit\n")
      end

60 61 62 63 64 65 66 67 68 69
      it 'returns raw file info' do
        url = route(file_path) + "/raw"
        expect(Gitlab::Workhorse).to receive(:send_git_blob)

        get api(url, current_user), params

        expect(response).to have_http_status(200)
      end

      context 'when mandatory params are not given' do
70
        it_behaves_like '400 response' do
71
          let(:request) { get api(route("any%2Ffile"), current_user) }
72 73 74 75
        end
      end

      context 'when file_path does not exist' do
76
        let(:params) { { ref: 'master' } }
77 78

        it_behaves_like '404 response' do
79
          let(:request) { get api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params }
80 81 82 83 84 85 86 87
          let(:message) { '404 File Not Found' }
        end
      end

      context 'when repository is disabled' do
        include_context 'disabled repository'

        it_behaves_like '403 response' do
88
          let(:request) { get api(route(file_path), current_user), params }
89 90
        end
      end
91 92
    end

93
    context 'when unauthenticated', 'and project is public' do
94 95 96 97 98
      it_behaves_like 'repository files' do
        let(:project) { create(:project, :public) }
        let(:current_user) { nil }
      end
    end
99

100 101
    context 'when unauthenticated', 'and project is private' do
      it_behaves_like '404 response' do
102
        let(:request) { get api(route(file_path)), params }
103
        let(:message) { '404 Project Not Found' }
104
      end
105 106
    end

107 108 109 110
    context 'when authenticated', 'as a developer' do
      it_behaves_like 'repository files' do
        let(:current_user) { user }
      end
111 112
    end

113 114
    context 'when authenticated', 'as a guest' do
      it_behaves_like '403 response' do
115
        let(:request) { get api(route(file_path), guest), params }
116
      end
117 118
    end
  end
119

120 121 122 123 124 125 126 127 128 129 130
  describe "GET /projects/:id/repository/files/:file_path/raw" do
    shared_examples_for 'repository raw files' do
      it 'returns raw file info' do
        url = route(file_path) + "/raw"
        expect(Gitlab::Workhorse).to receive(:send_git_blob)

        get api(url, current_user), params

        expect(response).to have_http_status(200)
      end

131 132 133 134 135 136 137 138 139 140 141
      it 'returns file by commit sha' do
        # This file is deleted on HEAD
        file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee"
        params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"
        expect(Gitlab::Workhorse).to receive(:send_git_blob)

        get api(route(file_path) + "/raw", current_user), params

        expect(response).to have_http_status(200)
      end

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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
      context 'when mandatory params are not given' do
        it_behaves_like '400 response' do
          let(:request) { get api(route("any%2Ffile"), current_user) }
        end
      end

      context 'when file_path does not exist' do
        let(:params) { { ref: 'master' } }

        it_behaves_like '404 response' do
          let(:request) { get api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params }
          let(:message) { '404 File Not Found' }
        end
      end

      context 'when repository is disabled' do
        include_context 'disabled repository'

        it_behaves_like '403 response' do
          let(:request) { get api(route(file_path), current_user), params }
        end
      end
    end

    context 'when unauthenticated', 'and project is public' do
      it_behaves_like 'repository raw files' do
        let(:project) { create(:project, :public) }
        let(:current_user) { nil }
      end
    end

    context 'when unauthenticated', 'and project is private' do
      it_behaves_like '404 response' do
        let(:request) { get api(route(file_path)), params }
        let(:message) { '404 Project Not Found' }
      end
    end

    context 'when authenticated', 'as a developer' do
      it_behaves_like 'repository raw files' do
        let(:current_user) { user }
      end
    end

    context 'when authenticated', 'as a guest' do
      it_behaves_like '403 response' do
        let(:request) { get api(route(file_path), guest), params }
      end
    end
  end

  describe "POST /projects/:id/repository/files/:file_path" do
    let!(:file_path) { "new_subfolder%2Fnewfile%2Erb" }
195
    let(:valid_params) do
196
      {
197 198 199
        branch: "master",
        content: "puts 8",
        commit_message: "Added newfile"
200
      }
201
    end
202

203
    it "creates a new file in project repo" do
204
      post api(route(file_path), user), valid_params
205

206
      expect(response).to have_http_status(201)
207
      expect(json_response["file_path"]).to eq(CGI.unescape(file_path))
208 209 210
      last_commit = project.repository.commit.raw
      expect(last_commit.author_email).to eq(user.email)
      expect(last_commit.author_name).to eq(user.name)
211 212
    end

213 214
    it "returns a 400 bad request if no mandatory params given" do
      post api(route("any%2Etxt"), user)
215

216
      expect(response).to have_http_status(400)
217 218
    end

219
    it "returns a 400 if editor fails to create file" do
Douwe Maan committed
220
      allow_any_instance_of(Repository).to receive(:create_file).
221
        and_return(false)
222

223
      post api(route("any%2Etxt"), user), valid_params
224

225
      expect(response).to have_http_status(400)
226
    end
227 228 229 230 231

    context "when specifying an author" do
      it "creates a new file with the specified author" do
        valid_params.merge!(author_email: author_email, author_name: author_name)

232
        post api(route("new_file_with_author%2Etxt"), user), valid_params
233 234 235 236 237 238 239

        expect(response).to have_http_status(201)
        last_commit = project.repository.commit.raw
        expect(last_commit.author_email).to eq(author_email)
        expect(last_commit.author_name).to eq(author_name)
      end
    end
240 241 242 243 244

    context 'when the repo is empty' do
      let!(:project) { create(:project_empty_repo, namespace: user.namespace ) }

      it "creates a new file in project repo" do
245
        post api(route("newfile%2Erb"), user), valid_params
246 247 248 249 250 251 252 253

        expect(response).to have_http_status(201)
        expect(json_response['file_path']).to eq('newfile.rb')
        last_commit = project.repository.commit.raw
        expect(last_commit.author_email).to eq(user.email)
        expect(last_commit.author_name).to eq(user.name)
      end
    end
254 255
  end

256
  describe "PUT /projects/:id/repository/files" do
257
    let(:valid_params) do
258
      {
259
        branch: 'master',
260 261 262
        content: 'puts 8',
        commit_message: 'Changed file'
      }
263
    end
264

265
    it "updates existing file in project repo" do
266
      put api(route(file_path), user), valid_params
267

268
      expect(response).to have_http_status(200)
269
      expect(json_response['file_path']).to eq(CGI.unescape(file_path))
270 271 272
      last_commit = project.repository.commit.raw
      expect(last_commit.author_email).to eq(user.email)
      expect(last_commit.author_name).to eq(user.name)
273 274
    end

275
    it "returns a 400 bad request if no params given" do
276
      put api(route(file_path), user)
277

278
      expect(response).to have_http_status(400)
279
    end
280 281 282 283 284

    context "when specifying an author" do
      it "updates a file with the specified author" do
        valid_params.merge!(author_email: author_email, author_name: author_name, content: "New content")

285
        put api(route(file_path), user), valid_params
286 287 288 289 290 291 292

        expect(response).to have_http_status(200)
        last_commit = project.repository.commit.raw
        expect(last_commit.author_email).to eq(author_email)
        expect(last_commit.author_name).to eq(author_name)
      end
    end
293
  end
294 295

  describe "DELETE /projects/:id/repository/files" do
296
    let(:valid_params) do
297
      {
298
        branch: 'master',
299 300
        commit_message: 'Changed file'
      }
301
    end
302

303
    it "deletes existing file in project repo" do
304
      delete api(route(file_path), user), valid_params
305

306
      expect(response).to have_http_status(204)
307 308
    end

309
    it "returns a 400 bad request if no params given" do
310
      delete api(route(file_path), user)
311

312
      expect(response).to have_http_status(400)
313 314
    end

315
    it "returns a 400 if fails to create file" do
Douwe Maan committed
316
      allow_any_instance_of(Repository).to receive(:delete_file).and_return(false)
317

318
      delete api(route(file_path), user), valid_params
319

320
      expect(response).to have_http_status(400)
321
    end
322 323 324 325 326

    context "when specifying an author" do
      it "removes a file with the specified author" do
        valid_params.merge!(author_email: author_email, author_name: author_name)

327
        delete api(route(file_path), user), valid_params
328

329
        expect(response).to have_http_status(204)
330 331
      end
    end
332
  end
333 334

  describe "POST /projects/:id/repository/files with binary file" do
335
    let(:file_path) { 'test%2Ebin' }
336 337
    let(:put_params) do
      {
338
        branch: 'master',
339 340 341 342 343 344 345 346 347 348 349 350
        content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
        commit_message: 'Binary file with a \n should not be touched',
        encoding: 'base64'
      }
    end
    let(:get_params) do
      {
        ref: 'master',
      }
    end

    before do
351
      post api(route(file_path), user), put_params
352 353 354
    end

    it "remains unchanged" do
355
      get api(route(file_path), user), get_params
356

357
      expect(response).to have_http_status(200)
358 359
      expect(json_response['file_path']).to eq(CGI.unescape(file_path))
      expect(json_response['file_name']).to eq(CGI.unescape(file_path))
360 361 362
      expect(json_response['content']).to eq(put_params[:content])
    end
  end
363
end