gitlab-ce/spec/requests/api/markdown_uploads_spec.rb

363 lines
12 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::MarkdownUploads, feature_category: :team_planning do
let_it_be(:group) { create(:group, :private) }
let_it_be(:group_maintainer) { create(:user, maintainer_of: group) }
let_it_be(:project) { create(:project, :private) }
let_it_be(:project_maintainer) { create(:user, maintainer_of: project) }
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:user) { create(:user, guest_of: [project, group]) }
describe "POST /projects/:id/uploads/authorize" do
include WorkhorseHelpers
let(:headers) { workhorse_internal_api_request_header.merge({ 'HTTP_GITLAB_WORKHORSE' => 1 }) }
let(:path) { "/projects/#{project.id}/uploads/authorize" }
context 'with authorized user' do
it "returns 200" do
post api(path, user), headers: headers
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['MaximumSize']).to eq(project.max_attachment_size)
end
end
context 'with unauthorized user' do
it "returns 404" do
post api(path, create(:user)), headers: headers
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with anonymous user on public project' do
let(:project) { public_project }
it "returns 401" do
post api(path), headers: headers
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'with no Workhorse headers' do
it "returns 403" do
post api(path, user)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
describe "POST /projects/:id/uploads" do
let(:file) { fixture_file_upload("spec/fixtures/dk.png", "image/png") }
let(:path) { "/projects/#{project.id}/uploads" }
it "uploads the file through the upload service and returns its info" do
expect(UploadService).to receive(:new).with(project, anything, uploaded_by_user_id: user.id).and_call_original
post api(path, user), params: { file: file }
expect(response).to have_gitlab_http_status(:created)
expect(json_response['id']).to eq(Upload.last.id)
expect(json_response['alt']).to eq("dk")
expect(json_response['url']).to start_with("/uploads/")
expect(json_response['url']).to end_with("/dk.png")
expect(json_response['full_path']).to start_with("/-/project/#{project.id}/uploads")
end
it "does not leave the temporary file in place after uploading, even when the tempfile reaper does not run" do
tempfile = Tempfile.new('foo')
path = tempfile.path
# rubocop: disable RSpec/AnyInstanceOf -- allow_next_instance_of does not work here because TempfileReaper is a middleware that is initialized early
allow_any_instance_of(Rack::TempfileReaper).to receive(:call) do |instance, env|
instance.instance_variable_get(:@app).call(env)
end
# rubocop: enable RSpec/AnyInstanceOf
expect(path).not_to be_nil
expect(Rack::Multipart::Parser::TEMPFILE_FACTORY).to receive(:call).and_return(tempfile)
post api(path, user), params: { file: fixture_file_upload("spec/fixtures/dk.png", "image/png") }
expect(tempfile.path).to be_nil
expect(File.exist?(path)).to be(false)
end
context 'with anonymous user on public project' do
let(:project) { public_project }
it "returns 401" do
post api(path), params: { file: file }
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
shared_examples 'an unauthorized request' do
it 'returns 403' do
make_request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
describe "GET /projects/:id/uploads" do
let_it_be(:uploads) { create_list(:upload, 3, :issuable_upload, model: project) }
let_it_be(:other_upload) { create(:upload, :issuable_upload, model: create(:project)) }
let(:path) { "/projects/#{project.id}/uploads" }
it 'returns uploads ordered by created_at' do
get api(path, project_maintainer)
expect_paginated_array_response(uploads.reverse.map(&:id))
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { get api(path, user) }
end
end
describe "GET /projects/:id/uploads/:upload_id" do
let_it_be(:upload) { create(:upload, :issuable_upload, :with_file, model: project, filename: 'test.jpg') }
let(:path) { "/projects/#{project.id}/uploads/#{upload.id}" }
it 'returns the uploaded file' do
get api(path, project_maintainer)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition'])
.to eq(%(attachment; filename="test.jpg"; filename*=UTF-8''test.jpg))
end
context 'when the upload does not exist' do
let(:path) { "/projects/#{project.id}/uploads/#{non_existing_record_id}" }
it 'returns a 404' do
get api(path, project_maintainer)
expect(response).to have_gitlab_http_status(:not_found)
end
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { get api(path, user) }
end
end
describe "GET /projects/:id/uploads/:secret/:filename" do
let_it_be(:upload) { create(:upload, :issuable_upload, :with_file, model: project, filename: 'test.jpg') }
let(:path) { "/projects/#{project.id}/uploads/#{upload.secret}/#{upload.filename}" }
it 'returns the uploaded file' do
get api(path, project_maintainer)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition'])
.to eq(%(attachment; filename="test.jpg"; filename*=UTF-8''test.jpg))
end
context 'when the secret does not match' do
let(:path) { "/projects/#{project.id}/uploads/invalid_secret/#{upload.filename}" }
it 'returns a 404' do
get api(path, project_maintainer)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with a user that does not have access to the project' do
it 'returns 404' do
get api(path, create(:user))
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe "DELETE /projects/:id/uploads/:upload_id" do
let_it_be(:upload) { create(:upload, :issuable_upload, model: project) }
let(:path) { "/projects/#{project.id}/uploads/#{upload.id}" }
it 'deletes the given upload' do
expect do
delete api(path, project_maintainer)
end.to change { Upload.count }.by(-1)
expect(response).to have_gitlab_http_status(:no_content)
end
it 'returns an error when deletion fails' do
expect_next_instance_of(Banzai::UploadsFinder) do |finder|
expect(finder).to receive(:find).with(upload.id).and_return(upload)
end
expect(upload).to receive(:destroy).and_return(false)
delete api(path, project_maintainer)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to include(_('Upload could not be deleted.'))
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { delete api(path, user) }
end
end
describe "DELETE /projects/:id/uploads/:secret/:filename" do
let_it_be(:upload) { create(:upload, :issuable_upload, model: project) }
let(:path) { "/projects/#{project.id}/uploads/#{upload.secret}/#{upload.filename}" }
it 'deletes the given upload' do
expect do
delete api(path, project_maintainer)
end.to change { Upload.count }.by(-1)
expect(response).to have_gitlab_http_status(:no_content)
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { delete api(path, user) }
end
end
describe "GET /groups/:id/uploads" do
let_it_be(:uploads) { create_list(:upload, 3, :namespace_upload, model: group) }
let_it_be(:other_upload) { create(:upload, :namespace_upload, model: create(:group)) }
let(:path) { "/groups/#{group.id}/uploads" }
it 'returns uploads ordered by created_at' do
get api(path, group_maintainer)
expect_paginated_array_response(uploads.reverse.map(&:id))
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { get api(path, user) }
end
end
describe "GET /groups/:id/uploads/:upload_id" do
let_it_be(:upload) { create(:upload, :namespace_upload, :with_file, model: group, filename: 'test.jpg') }
let(:path) { "/groups/#{group.id}/uploads/#{upload.id}" }
it 'returns the uploaded file' do
get api(path, group_maintainer)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition'])
.to eq(%(attachment; filename="test.jpg"; filename*=UTF-8''test.jpg))
end
context 'when the upload does not exist' do
let(:path) { "/groups/#{group.id}/uploads/#{non_existing_record_id}" }
it 'returns a 404' do
get api(path, group_maintainer)
expect(response).to have_gitlab_http_status(:not_found)
end
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { get api(path, user) }
end
end
describe "GET /groups/:id/uploads/:secret/:filename" do
let_it_be(:upload) { create(:upload, :namespace_upload, :with_file, model: group, filename: 'test.jpg') }
let(:path) { "/groups/#{group.id}/uploads/#{upload.secret}/#{upload.filename}" }
it 'returns the uploaded file' do
get api(path, group_maintainer)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition'])
.to eq(%(attachment; filename="test.jpg"; filename*=UTF-8''test.jpg))
end
context 'when the secret does not match' do
let(:path) { "/groups/#{group.id}/uploads/invalid_secret/#{upload.filename}" }
it 'returns a 404' do
get api(path, group_maintainer)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with a user that does not have access to the group' do
it 'returns 404' do
get api(path, create(:user))
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe "DELETE /groups/:id/uploads/:upload_id" do
let_it_be(:upload) { create(:upload, :namespace_upload, model: group) }
let(:path) { "/groups/#{group.id}/uploads/#{upload.id}" }
it 'deletes the given upload' do
expect do
delete api(path, group_maintainer)
end.to change { Upload.count }.by(-1)
expect(response).to have_gitlab_http_status(:no_content)
end
it 'returns an error when deletion fails' do
expect_next_instance_of(Banzai::UploadsFinder) do |finder|
expect(finder).to receive(:find).with(upload.id).and_return(upload)
end
expect(upload).to receive(:destroy).and_return(false)
delete api(path, group_maintainer)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to include(_('Upload could not be deleted.'))
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { delete api(path, user) }
end
end
describe "DELETE /groups/:id/uploads/:secret/:filename" do
let_it_be(:upload) { create(:upload, :namespace_upload, model: group) }
let(:path) { "/groups/#{group.id}/uploads/#{upload.secret}/#{upload.filename}" }
it 'deletes the given upload' do
expect do
delete api(path, group_maintainer)
end.to change { Upload.count }.by(-1)
expect(response).to have_gitlab_http_status(:no_content)
end
it_behaves_like 'an unauthorized request' do
subject(:make_request) { delete api(path, user) }
end
end
end