Commit b6f0eddc authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'lfs-batch-download-to-stable' into '8-2-stable'

Lfs batch download to stable

!1842 for stable

See merge request !1853
parents ea279432 89dec03c
...@@ -10,23 +10,9 @@ module Gitlab ...@@ -10,23 +10,9 @@ module Gitlab
@request = request @request = request
end end
# Return a response for a download request
# Can be a response to:
# Request from a user to get the file
# Request from gitlab-workhorse which file to serve to the user
def render_download_hypermedia_response(oid)
render_response_to_download do
if check_download_accept_header?
render_lfs_download_hypermedia(oid)
else
render_not_found
end
end
end
def render_download_object_response(oid) def render_download_object_response(oid)
render_response_to_download do render_response_to_download do
if check_download_sendfile_header? && check_download_accept_header? if check_download_sendfile_header?
render_lfs_sendfile(oid) render_lfs_sendfile(oid)
else else
render_not_found render_not_found
...@@ -34,20 +20,15 @@ module Gitlab ...@@ -34,20 +20,15 @@ module Gitlab
end end
end end
def render_lfs_api_auth def render_batch_operation_response
render_response_to_push do request_body = JSON.parse(@request.body.read)
request_body = JSON.parse(@request.body.read) case request_body["operation"]
return render_not_found if request_body.empty? || request_body['objects'].empty? when "download"
render_batch_download(request_body)
response = build_response(request_body['objects']) when "upload"
[ render_batch_upload(request_body)
200, else
{ render_not_found
"Content-Type" => "application/json; charset=utf-8",
"Cache-Control" => "private",
},
[JSON.dump(response)]
]
end end
end end
...@@ -71,13 +52,24 @@ module Gitlab ...@@ -71,13 +52,24 @@ module Gitlab
end end
end end
def render_unsupported_deprecated_api
[
501,
{ "Content-Type" => "application/json; charset=utf-8" },
[JSON.dump({
'message' => 'Server supports batch API only, please update your Git LFS client to version 0.6.0 and up.',
'documentation_url' => "#{Gitlab.config.gitlab.url}/help",
})]
]
end
private private
def render_not_enabled def render_not_enabled
[ [
501, 501,
{ {
"Content-Type" => "application/vnd.git-lfs+json", "Content-Type" => "application/json; charset=utf-8",
}, },
[JSON.dump({ [JSON.dump({
'message' => 'Git LFS is not enabled on this GitLab server, contact your admin.', 'message' => 'Git LFS is not enabled on this GitLab server, contact your admin.',
...@@ -142,18 +134,35 @@ module Gitlab ...@@ -142,18 +134,35 @@ module Gitlab
end end
end end
def render_lfs_download_hypermedia(oid) def render_batch_upload(body)
return render_not_found unless oid.present? return render_not_found if body.empty? || body['objects'].nil?
lfs_object = object_for_download(oid) render_response_to_push do
if lfs_object response = build_upload_batch_response(body['objects'])
[ [
200, 200,
{ "Content-Type" => "application/vnd.git-lfs+json" }, {
[JSON.dump(download_hypermedia(oid))] "Content-Type" => "application/json; charset=utf-8",
"Cache-Control" => "private",
},
[JSON.dump(response)]
]
end
end
def render_batch_download(body)
return render_not_found if body.empty? || body['objects'].nil?
render_response_to_download do
response = build_download_batch_response(body['objects'])
[
200,
{
"Content-Type" => "application/json; charset=utf-8",
"Cache-Control" => "private",
},
[JSON.dump(response)]
] ]
else
render_not_found
end end
end end
...@@ -199,10 +208,6 @@ module Gitlab ...@@ -199,10 +208,6 @@ module Gitlab
@env['HTTP_X_SENDFILE_TYPE'].to_s == "X-Sendfile" @env['HTTP_X_SENDFILE_TYPE'].to_s == "X-Sendfile"
end end
def check_download_accept_header?
@env['HTTP_ACCEPT'].to_s == "application/vnd.git-lfs+json; charset=utf-8"
end
def user_can_fetch? def user_can_fetch?
# Check user access against the project they used to initiate the pull # Check user access against the project they used to initiate the pull
@user.can?(:download_code, @origin_project) @user.can?(:download_code, @origin_project)
...@@ -266,42 +271,56 @@ module Gitlab ...@@ -266,42 +271,56 @@ module Gitlab
@project.lfs_objects.where(oid: objects_oids).pluck(:oid).to_set @project.lfs_objects.where(oid: objects_oids).pluck(:oid).to_set
end end
def build_response(objects) def build_upload_batch_response(objects)
selected_objects = select_existing_objects(objects) selected_objects = select_existing_objects(objects)
upload_hypermedia(objects, selected_objects) upload_hypermedia_links(objects, selected_objects)
end end
def download_hypermedia(oid) def build_download_batch_response(objects)
{ selected_objects = select_existing_objects(objects)
'_links' => {
'download' => download_hypermedia_links(objects, selected_objects)
{
'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{oid}",
'header' => {
'Accept' => "application/vnd.git-lfs+json; charset=utf-8",
'Authorization' => @env['HTTP_AUTHORIZATION']
}.compact
}
}
}
end end
def upload_hypermedia(all_objects, existing_objects) def download_hypermedia_links(all_objects, existing_objects)
all_objects.each do |object| all_objects.each do |object|
object['_links'] = hypermedia_links(object) unless existing_objects.include?(object['oid']) if existing_objects.include?(object['oid'])
object['actions'] = {
'download' => {
'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}",
'header' => {
'Authorization' => @env['HTTP_AUTHORIZATION']
}.compact
}
}
else
object['error'] = {
'code' => 404,
'message' => "Object does not exist on the server or you don't have permissions to access it",
}
end
end end
{ 'objects' => all_objects } { 'objects' => all_objects }
end end
def hypermedia_links(object) def upload_hypermedia_links(all_objects, existing_objects)
{ all_objects.each do |object|
"upload" => { # generate actions only for non-existing objects
'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}/#{object['size']}", next if existing_objects.include?(object['oid'])
'header' => { 'Authorization' => @env['HTTP_AUTHORIZATION'] }
}.compact object['actions'] = {
} 'upload' => {
'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}/#{object['size']}",
'header' => {
'Authorization' => @env['HTTP_AUTHORIZATION']
}.compact
}
}
end
{ 'objects' => all_objects }
end end
end end
end end
......
...@@ -34,7 +34,7 @@ module Gitlab ...@@ -34,7 +34,7 @@ module Gitlab
case path_match[1] case path_match[1]
when "info/lfs" when "info/lfs"
lfs.render_download_hypermedia_response(oid) lfs.render_unsupported_deprecated_api
when "gitlab-lfs" when "gitlab-lfs"
lfs.render_download_object_response(oid) lfs.render_download_object_response(oid)
else else
...@@ -48,7 +48,9 @@ module Gitlab ...@@ -48,7 +48,9 @@ module Gitlab
# Check for Batch API # Check for Batch API
if post_path[0].ends_with?("/info/lfs/objects/batch") if post_path[0].ends_with?("/info/lfs/objects/batch")
lfs.render_lfs_api_auth lfs.render_batch_operation_response
elsif post_path[0].ends_with?("/info/lfs/objects")
lfs.render_unsupported_deprecated_api
else else
nil nil
end end
......
...@@ -26,113 +26,52 @@ describe Gitlab::Lfs::Router do ...@@ -26,113 +26,52 @@ describe Gitlab::Lfs::Router do
let(:sample_oid) { "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80" } let(:sample_oid) { "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80" }
let(:sample_size) { 499013 } let(:sample_size) { 499013 }
let(:respond_with_deprecated) {[ 501, { "Content-Type"=>"application/json; charset=utf-8" }, ["{\"message\":\"Server supports batch API only, please update your Git LFS client to version 0.6.0 and up.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
let(:respond_with_disabled) {[ 501, { "Content-Type"=>"application/json; charset=utf-8" }, ["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
describe 'when lfs is disabled' do describe 'when lfs is disabled' do
before do before do
allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}" env['REQUEST_METHOD'] = 'POST'
body = {
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
},
{ 'oid' => sample_oid,
'size' => sample_size
}
],
'operation' => 'upload'
}.to_json
env['rack.input'] = StringIO.new(body)
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
end end
it 'responds with 501' do it 'responds with 501' do
respond_with_disabled = [ 501,
{ "Content-Type"=>"application/vnd.git-lfs+json" },
["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]
]
expect(lfs_router_auth.try_call).to match_array(respond_with_disabled) expect(lfs_router_auth.try_call).to match_array(respond_with_disabled)
end end
end end
describe 'when fetching lfs object' do describe 'when fetching lfs object using deprecated API' do
before do before do
enable_lfs enable_lfs
env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}" env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}"
end end
describe 'when user is authenticated' do it 'responds with 501' do
context 'and user has project download access' do expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
before do
@auth = authorize(user)
env["HTTP_AUTHORIZATION"] = @auth
project.lfs_objects << lfs_object
project.team << [user, :master]
end
it "responds with status 200" do
expect(lfs_router_auth.try_call.first).to eq(200)
end
it "responds with download hypermedia" do
json_response = ActiveSupport::JSON.decode(lfs_router_auth.try_call.last.first)
expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
expect(json_response['_links']['download']['header']).to eq("Authorization" => @auth, "Accept" => "application/vnd.git-lfs+json; charset=utf-8")
end
end
context 'and user does not have project access' do
it "responds with status 403" do
expect(lfs_router_auth.try_call.first).to eq(403)
end
end
end
describe 'when user is unauthenticated' do
context 'and user does not have download access' do
it "responds with status 401" do
expect(lfs_router_noauth.try_call.first).to eq(401)
end
end
context 'and user has download access' do
before do
project.team << [user, :master]
end
it "responds with status 401" do
expect(lfs_router_noauth.try_call.first).to eq(401)
end
end
end end
end
describe 'and project is public' do describe 'when fetching lfs object' do
context 'and project has access to the lfs object' do before do
before do enable_lfs
public_project.lfs_objects << lfs_object env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
end env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}"
context 'and user is authenticated' do
it "responds with status 200 and sends download hypermedia" do
expect(lfs_router_public_auth.try_call.first).to eq(200)
json_response = ActiveSupport::JSON.decode(lfs_router_public_auth.try_call.last.first)
expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{public_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8")
end
end
context 'and user is unauthenticated' do
it "responds with status 200 and sends download hypermedia" do
expect(lfs_router_public_noauth.try_call.first).to eq(200)
json_response = ActiveSupport::JSON.decode(lfs_router_public_noauth.try_call.last.first)
expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{public_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8")
end
end
end
context 'and project does not have access to the lfs object' do
it "responds with status 404" do
expect(lfs_router_public_auth.try_call.first).to eq(404)
end
end
end end
describe 'and request comes from gitlab-workhorse' do describe 'and request comes from gitlab-workhorse' do
before do
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}"
end
context 'without user being authorized' do context 'without user being authorized' do
it "responds with status 401" do it "responds with status 401" do
expect(lfs_router_noauth.try_call.first).to eq(401) expect(lfs_router_noauth.try_call.first).to eq(401)
...@@ -173,200 +112,376 @@ describe Gitlab::Lfs::Router do ...@@ -173,200 +112,376 @@ describe Gitlab::Lfs::Router do
end end
end end
end end
end
describe 'from a forked public project' do describe 'when handling lfs request using deprecated API' do
before do before do
env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8" enable_lfs
env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}" env['REQUEST_METHOD'] = 'POST'
end env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects"
end
it 'responds with 501' do
expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
end
end
describe 'when handling lfs batch request' do
before do
enable_lfs
env['REQUEST_METHOD'] = 'POST'
env['PATH_INFO'] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
end
describe 'download' do
describe 'when user is authenticated' do
before do
body = { 'operation' => 'download',
'objects' => [
{ 'oid' => sample_oid,
'size' => sample_size
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
context "when fetching a lfs object" do describe 'when user has download access' do
context "and user has project download access" do
before do before do
public_project.lfs_objects << lfs_object @auth = authorize(user)
env["HTTP_AUTHORIZATION"] = @auth
project.team << [user, :reporter]
end end
it "can download the lfs object" do context 'when downloading an lfs object that is assigned to our project' do
expect(lfs_router_forked_auth.try_call.first).to eq(200) before do
json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first) project.lfs_objects << lfs_object
end
it 'responds with status 200 and href to download' do
response = lfs_router_auth.try_call
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{forked_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}") expect(response_body).to eq('objects' => [
expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8") { 'oid' => sample_oid,
'size' => sample_size,
'actions' => {
'download' => {
'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
'header' => { 'Authorization' => @auth }
}
}
}])
end
end end
end
context "and user is not authenticated but project is public" do context 'when downloading an lfs object that is assigned to other project' do
before do before do
public_project.lfs_objects << lfs_object public_project.lfs_objects << lfs_object
end
it 'responds with status 200 and error message' do
response = lfs_router_auth.try_call
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body).to eq('objects' => [
{ 'oid' => sample_oid,
'size' => sample_size,
'error' => {
'code' => 404,
'message' => "Object does not exist on the server or you don't have permissions to access it",
}
}])
end
end end
it "can download the lfs object" do context 'when downloading a lfs object that does not exist' do
expect(lfs_router_forked_auth.try_call.first).to eq(200) before do
body = { 'operation' => 'download',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
it "responds with status 200 and error message" do
response = lfs_router_auth.try_call
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body).to eq('objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078,
'error' => {
'code' => 404,
'message' => "Object does not exist on the server or you don't have permissions to access it",
}
}])
end
end
context 'when downloading one new and one existing lfs object' do
before do
body = { 'operation' => 'download',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
},
{ 'oid' => sample_oid,
'size' => sample_size
}
]
}.to_json
env['rack.input'] = StringIO.new(body)
project.lfs_objects << lfs_object
end
it "responds with status 200 with upload hypermedia link for the new object" do
response = lfs_router_auth.try_call
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body).to eq('objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078,
'error' => {
'code' => 404,
'message' => "Object does not exist on the server or you don't have permissions to access it",
}
},
{ 'oid' => sample_oid,
'size' => sample_size,
'actions' => {
'download' => {
'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
'header' => { 'Authorization' => @auth }
}
}
}])
end
end end
end end
context "and user has project download access" do context 'when user does is not member of the project' do
before do before do
env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897" @auth = authorize(user)
@auth = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
env["HTTP_AUTHORIZATION"] = @auth env["HTTP_AUTHORIZATION"] = @auth
lfs_object_two = create(:lfs_object, :with_file, oid: "91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897", size: 1575078) project.team << [user, :guest]
public_project.lfs_objects << lfs_object_two
end end
it "can get a lfs object that is not in the forked project" do it 'responds with 403' do
expect(lfs_router_forked_auth.try_call.first).to eq(200) expect(lfs_router_auth.try_call.first).to eq(403)
json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first)
expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{forked_project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8", "Authorization" => @auth)
end end
end end
context "and user has project download access" do context 'when user does not have download access' do
before do before do
env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/267c8b1d876743971e3a9978405818ff5ca731c4c870b06507619cd9b1847b6b" @auth = authorize(user)
lfs_object_three = create(:lfs_object, :with_file, oid: "267c8b1d876743971e3a9978405818ff5ca731c4c870b06507619cd9b1847b6b", size: 127192524) env["HTTP_AUTHORIZATION"] = @auth
project.lfs_objects << lfs_object_three project.team << [user, :guest]
end end
it "cannot get a lfs object that is not in the project" do it 'responds with 403' do
expect(lfs_router_forked_auth.try_call.first).to eq(404) expect(lfs_router_auth.try_call.first).to eq(403)
end end
end end
end end
end
end
describe 'when initiating pushing of the lfs object' do
before do
enable_lfs
env['REQUEST_METHOD'] = 'POST'
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
end
describe 'when user is authenticated' do
before do
body = { 'objects' => [{
'oid' => sample_oid,
'size' => sample_size
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
describe 'when user has project push access' do context 'when user is not authenticated' do
before do before do
@auth = authorize(user) body = { 'operation' => 'download',
env["HTTP_AUTHORIZATION"] = @auth 'objects' => [
project.team << [user, :master] { 'oid' => sample_oid,
'size' => sample_size
}],
}.to_json
env['rack.input'] = StringIO.new(body)
end end
context 'when pushing an lfs object that already exists' do describe 'is accessing public project' do
before do before do
public_project.lfs_objects << lfs_object public_project.lfs_objects << lfs_object
end end
it "responds with status 200 and links the object to the project" do it 'responds with status 200 and href to download' do
response_body = lfs_router_auth.try_call.last response = lfs_router_public_noauth.try_call
response = ActiveSupport::JSON.decode(response_body.first) expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response['objects']).to be_kind_of(Array) expect(response_body).to eq('objects' => [
expect(response['objects'].first['oid']).to eq(sample_oid) { 'oid' => sample_oid,
expect(response['objects'].first['size']).to eq(sample_size) 'size' => sample_size,
expect(lfs_object.projects.pluck(:id)).to_not include(project.id) 'actions' => {
expect(lfs_object.projects.pluck(:id)).to include(public_project.id) 'download' => {
expect(response['objects'].first).to have_key('_links') 'href' => "#{public_project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
'header' => {}
}
}
}])
end end
end end
context 'when pushing a lfs object that does not exist' do describe 'is accessing non-public project' do
before do before do
body = { project.lfs_objects << lfs_object
'objects' => [{
'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end end
it "responds with status 200 and upload hypermedia link" do it 'responds with authorization required' do
response = lfs_router_auth.try_call expect(lfs_router_noauth.try_call.first).to eq(401)
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body['objects']).to be_kind_of(Array)
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(response_body['objects'].first['size']).to eq(1575078)
expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
expect(response_body['objects'].first['_links']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(response_body['objects'].first['_links']['upload']['header']).to eq("Authorization" => @auth)
end end
end end
end
end
context 'when pushing one new and one existing lfs object' do describe 'upload' do
describe 'when user is authenticated' do
before do
body = { 'operation' => 'upload',
'objects' => [
{ 'oid' => sample_oid,
'size' => sample_size
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
describe 'when user has project push access' do
before do before do
body = { @auth = authorize(user)
'objects' => [ env["HTTP_AUTHORIZATION"] = @auth
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', project.team << [user, :developer]
'size' => 1575078
},
{ 'oid' => sample_oid,
'size' => sample_size
}
]
}.to_json
env['rack.input'] = StringIO.new(body)
public_project.lfs_objects << lfs_object
end end
it "responds with status 200 with upload hypermedia link for the new object" do context 'when pushing an lfs object that already exists' do
response = lfs_router_auth.try_call before do
expect(response.first).to eq(200) public_project.lfs_objects << lfs_object
end
response_body = ActiveSupport::JSON.decode(response.last.first) it "responds with status 200 and links the object to the project" do
expect(response_body['objects']).to be_kind_of(Array) response_body = lfs_router_auth.try_call.last
response = ActiveSupport::JSON.decode(response_body.first)
expect(response['objects']).to be_kind_of(Array)
expect(response['objects'].first['oid']).to eq(sample_oid)
expect(response['objects'].first['size']).to eq(sample_size)
expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
end
end
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") context 'when pushing a lfs object that does not exist' do
expect(response_body['objects'].first['size']).to eq(1575078) before do
expect(response_body['objects'].first['_links']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") body = { 'operation' => 'upload',
expect(response_body['objects'].first['_links']['upload']['header']).to eq("Authorization" => @auth) 'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
expect(response_body['objects'].last['oid']).to eq(sample_oid) it "responds with status 200 and upload hypermedia link" do
expect(response_body['objects'].last['size']).to eq(sample_size) response = lfs_router_auth.try_call
expect(lfs_object.projects.pluck(:id)).to_not include(project.id) expect(response.first).to eq(200)
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
expect(response_body['objects'].last).to have_key('_links') response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body['objects']).to be_kind_of(Array)
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(response_body['objects'].first['size']).to eq(1575078)
expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(response_body['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
end
end
context 'when pushing one new and one existing lfs object' do
before do
body = { 'operation' => 'upload',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
},
{ 'oid' => sample_oid,
'size' => sample_size
}
]
}.to_json
env['rack.input'] = StringIO.new(body)
project.lfs_objects << lfs_object
end
it "responds with status 200 with upload hypermedia link for the new object" do
response = lfs_router_auth.try_call
expect(response.first).to eq(200)
response_body = ActiveSupport::JSON.decode(response.last.first)
expect(response_body['objects']).to be_kind_of(Array)
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(response_body['objects'].first['size']).to eq(1575078)
expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(response_body['objects'].first['actions']['upload']['header']).to eq("Authorization" => @auth)
expect(response_body['objects'].last['oid']).to eq(sample_oid)
expect(response_body['objects'].last['size']).to eq(sample_size)
expect(response_body['objects'].last).to_not have_key('actions')
end
end end
end end
end
context 'when user does not have push access' do context 'when user does not have push access' do
it 'responds with 403' do it 'responds with 403' do
expect(lfs_router_auth.try_call.first).to eq(403) expect(lfs_router_auth.try_call.first).to eq(403)
end
end end
end end
end
context 'when user is not authenticated' do context 'when user is not authenticated' do
context 'when user has push access' do
before do before do
project.team << [user, :master] env['rack.input'] = StringIO.new(
{ 'objects' => [], 'operation' => 'upload' }.to_json
)
end end
it "responds with status 401" do context 'when user has push access' do
expect(lfs_router_public_noauth.try_call.first).to eq(401) before do
project.team << [user, :master]
end
it "responds with status 401" do
expect(lfs_router_public_noauth.try_call.first).to eq(401)
end
end end
end
context 'when user does not have push access' do context 'when user does not have push access' do
it "responds with status 401" do it "responds with status 401" do
expect(lfs_router_public_noauth.try_call.first).to eq(401) expect(lfs_router_public_noauth.try_call.first).to eq(401)
end
end end
end end
end end
describe 'unsupported' do
before do
body = { 'operation' => 'other',
'objects' => [
{ 'oid' => sample_oid,
'size' => sample_size
}]
}.to_json
env['rack.input'] = StringIO.new(body)
end
it 'responds with status 404' do
expect(lfs_router_public_noauth.try_call.first).to eq(404)
end
end
end end
describe 'when pushing a lfs object' do describe 'when pushing a lfs object' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment