221 lines
6.8 KiB
Ruby
221 lines
6.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe Repositories::GitHttpController do
|
|
include GitHttpHelpers
|
|
|
|
let_it_be(:project) { create(:project, :public, :repository) }
|
|
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) }
|
|
let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) }
|
|
|
|
let(:namespace_id) { project.namespace.to_param }
|
|
let(:repository_id) { project.path + '.git' }
|
|
let(:container_params) do
|
|
{
|
|
namespace_id: namespace_id,
|
|
repository_id: repository_id
|
|
}
|
|
end
|
|
|
|
let(:params) { container_params }
|
|
|
|
describe 'HEAD #info_refs' do
|
|
it 'returns 403' do
|
|
head :info_refs, params: params
|
|
|
|
expect(response).to have_gitlab_http_status(:forbidden)
|
|
end
|
|
end
|
|
|
|
shared_examples 'info_refs behavior' do
|
|
describe 'GET #info_refs' do
|
|
let(:params) { container_params.merge(service: 'git-upload-pack') }
|
|
|
|
it 'returns 401 for unauthenticated requests to public repositories when http protocol is disabled' do
|
|
stub_application_setting(enabled_git_access_protocol: 'ssh')
|
|
allow(controller).to receive(:basic_auth_provided?).and_call_original
|
|
|
|
expect(controller).to receive(:http_download_allowed?).and_call_original
|
|
|
|
get :info_refs, params: params
|
|
|
|
expect(response).to have_gitlab_http_status(:unauthorized)
|
|
end
|
|
|
|
context 'with authorized user' do
|
|
before do
|
|
request.headers.merge! auth_env(user.username, user.password, nil)
|
|
end
|
|
|
|
it 'returns 200' do
|
|
get :info_refs, params: params
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
end
|
|
|
|
it 'updates the user activity' do
|
|
expect_next_instance_of(Users::ActivityService) do |activity_service|
|
|
expect(activity_service).to receive(:execute)
|
|
end
|
|
|
|
get :info_refs, params: params
|
|
end
|
|
|
|
include_context 'parsed logs' do
|
|
it 'adds user info to the logs' do
|
|
get :info_refs, params: params
|
|
|
|
expect(log_data).to include('username' => user.username,
|
|
'user_id' => user.id,
|
|
'meta.user' => user.username)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with exceptions' do
|
|
before do
|
|
allow(controller).to receive(:authenticate_user).and_return(true)
|
|
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
|
|
end
|
|
|
|
it 'returns 503 with GRPC Unavailable' do
|
|
allow(controller).to receive(:access_check).and_raise(GRPC::Unavailable)
|
|
|
|
get :info_refs, params: params
|
|
|
|
expect(response).to have_gitlab_http_status(:service_unavailable)
|
|
end
|
|
|
|
it 'returns 503 with timeout error' do
|
|
allow(controller).to receive(:access_check).and_raise(Gitlab::GitAccess::TimeoutError)
|
|
|
|
get :info_refs, params: params
|
|
|
|
expect(response).to have_gitlab_http_status(:service_unavailable)
|
|
expect(response.body).to eq 'Gitlab::GitAccess::TimeoutError'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'git_upload_pack behavior' do |expected|
|
|
describe 'POST #git_upload_pack' do
|
|
before do
|
|
allow(controller).to receive(:authenticate_user).and_return(true)
|
|
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
|
|
allow(controller).to receive(:access_check).and_return(nil)
|
|
end
|
|
|
|
def send_request
|
|
post :git_upload_pack, params: params
|
|
end
|
|
|
|
context 'on a read-only instance' do
|
|
before do
|
|
allow(Gitlab::Database).to receive(:read_only?).and_return(true)
|
|
end
|
|
|
|
it 'does not update project statistics' do
|
|
expect(ProjectDailyStatisticsWorker).not_to receive(:perform_async)
|
|
|
|
send_request
|
|
end
|
|
end
|
|
|
|
if expected
|
|
context 'when project_statistics_sync feature flag is disabled' do
|
|
before do
|
|
stub_feature_flags(project_statistics_sync: false)
|
|
end
|
|
|
|
it 'updates project statistics async' do
|
|
expect(ProjectDailyStatisticsWorker).to receive(:perform_async)
|
|
|
|
send_request
|
|
end
|
|
end
|
|
|
|
it 'updates project statistics sync' do
|
|
expect { send_request }.to change {
|
|
Projects::DailyStatisticsFinder.new(project).total_fetch_count
|
|
}.from(0).to(1)
|
|
end
|
|
else
|
|
context 'when project_statistics_sync feature flag is disabled' do
|
|
before do
|
|
stub_feature_flags(project_statistics_sync: false)
|
|
end
|
|
|
|
it 'does not update project statistics' do
|
|
expect(ProjectDailyStatisticsWorker).not_to receive(:perform_async)
|
|
|
|
send_request
|
|
end
|
|
end
|
|
|
|
it 'does not update project statistics' do
|
|
expect { send_request }.not_to change {
|
|
Projects::DailyStatisticsFinder.new(project).total_fetch_count
|
|
}.from(0)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'access checker class' do
|
|
let(:params) { container_params.merge(service: 'git-upload-pack') }
|
|
|
|
it 'calls the right access class checker with the right object' do
|
|
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
|
|
|
|
access_double = double
|
|
expect(expected_class).to receive(:new).with(anything, expected_object, 'http', anything).and_return(access_double)
|
|
allow(access_double).to receive(:check).and_return(false)
|
|
|
|
get :info_refs, params: params
|
|
end
|
|
end
|
|
|
|
context 'when repository container is a project' do
|
|
it_behaves_like 'info_refs behavior' do
|
|
let(:user) { project.owner }
|
|
end
|
|
|
|
it_behaves_like 'git_upload_pack behavior', true
|
|
it_behaves_like 'access checker class' do
|
|
let(:expected_class) { Gitlab::GitAccess }
|
|
let(:expected_object) { project }
|
|
end
|
|
end
|
|
|
|
context 'when repository container is a personal snippet' do
|
|
let(:namespace_id) { 'snippets' }
|
|
let(:repository_id) { personal_snippet.to_param + '.git' }
|
|
|
|
it_behaves_like 'info_refs behavior' do
|
|
let(:user) { personal_snippet.author }
|
|
end
|
|
|
|
it_behaves_like 'git_upload_pack behavior', false
|
|
it_behaves_like 'access checker class' do
|
|
let(:expected_class) { Gitlab::GitAccessSnippet }
|
|
let(:expected_object) { personal_snippet }
|
|
end
|
|
end
|
|
|
|
context 'when repository container is a project snippet' do
|
|
let(:namespace_id) { project.full_path + '/snippets' }
|
|
let(:repository_id) { project_snippet.to_param + '.git' }
|
|
|
|
it_behaves_like 'info_refs behavior' do
|
|
let(:user) { project_snippet.author }
|
|
end
|
|
|
|
it_behaves_like 'git_upload_pack behavior', false
|
|
it_behaves_like 'access checker class' do
|
|
let(:expected_class) { Gitlab::GitAccessSnippet }
|
|
let(:expected_object) { project_snippet }
|
|
end
|
|
end
|
|
end
|