summaryrefslogtreecommitdiff
path: root/spec/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/api')
-rw-r--r--spec/lib/api/entities/snippet_repository_storage_move_spec.rb25
-rw-r--r--spec/lib/api/helpers/authentication_spec.rb207
-rw-r--r--spec/lib/api/helpers_spec.rb47
3 files changed, 278 insertions, 1 deletions
diff --git a/spec/lib/api/entities/snippet_repository_storage_move_spec.rb b/spec/lib/api/entities/snippet_repository_storage_move_spec.rb
new file mode 100644
index 00000000000..8086be3ffa7
--- /dev/null
+++ b/spec/lib/api/entities/snippet_repository_storage_move_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::SnippetRepositoryStorageMove do
+ describe '#as_json' do
+ subject { entity.as_json }
+
+ let(:default_storage) { 'default' }
+ let(:second_storage) { 'test_second_storage' }
+ let(:storage_move) { create(:snippet_repository_storage_move, :scheduled, destination_storage_name: second_storage) }
+ let(:entity) { described_class.new(storage_move) }
+
+ it 'includes basic fields' do
+ allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(%W[#{default_storage} #{second_storage}])
+
+ is_expected.to include(
+ state: 'scheduled',
+ source_storage_name: default_storage,
+ destination_storage_name: second_storage,
+ snippet: a_kind_of(Hash)
+ )
+ end
+ end
+end
diff --git a/spec/lib/api/helpers/authentication_spec.rb b/spec/lib/api/helpers/authentication_spec.rb
new file mode 100644
index 00000000000..461b0d2f6f9
--- /dev/null
+++ b/spec/lib/api/helpers/authentication_spec.rb
@@ -0,0 +1,207 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Helpers::Authentication do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project, :public) }
+ let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
+ let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
+
+ describe 'class methods' do
+ subject { Class.new.include(described_class::ClassMethods).new }
+
+ describe '.authenticate_with' do
+ it 'sets namespace_inheritable :authentication to correctly when body is empty' do
+ expect(subject).to receive(:namespace_inheritable).with(:authentication, {})
+
+ subject.authenticate_with { |allow| }
+ end
+
+ it 'sets namespace_inheritable :authentication to correctly when body is not empty' do
+ expect(subject).to receive(:namespace_inheritable).with(:authentication, { basic: [:pat, :job], oauth: [:pat, :job] })
+
+ subject.authenticate_with { |allow| allow.token_type(:pat, :job).sent_through(:basic, :oauth) }
+ end
+ end
+ end
+
+ describe 'helper methods' do
+ let(:object) do
+ cls = Class.new
+
+ class << cls
+ def helpers(*modules, &block)
+ modules.each { |m| include m }
+ include Module.new.tap { |m| m.class_eval(&block) } if block_given?
+ end
+ end
+
+ cls.define_method(:unauthorized!) { raise '401' }
+ cls.define_method(:bad_request!) { |m| raise "400 - #{m}" }
+
+ # Include the helper class methods, as instance methods
+ cls.include described_class::ClassMethods
+
+ # Include the methods under test
+ cls.include described_class
+
+ cls.new
+ end
+
+ describe '#token_from_namespace_inheritable' do
+ let(:object) do
+ o = super()
+
+ o.instance_eval do
+ # It doesn't matter what this returns as long as the method is defined
+ def current_request
+ nil
+ end
+
+ # Spoof Grape's namespace inheritable system
+ def namespace_inheritable(key, value = nil)
+ return unless key == :authentication
+
+ if value
+ @authentication = value
+ else
+ @authentication
+ end
+ end
+ end
+
+ o
+ end
+
+ let(:authentication) do
+ object.authenticate_with { |allow| allow.token_types(*resolvers).sent_through(*locators) }
+ end
+
+ subject { object.token_from_namespace_inheritable }
+
+ before do
+ # Skip validation of token transports and types to simplify testing
+ allow(Gitlab::APIAuthentication::TokenLocator).to receive(:new) { |type| type }
+ allow(Gitlab::APIAuthentication::TokenResolver).to receive(:new) { |type| type }
+
+ authentication
+ end
+
+ shared_examples 'stops early' do |response_method|
+ it "calls ##{response_method}" do
+ errcls = Class.new(StandardError)
+ expect(object).to receive(response_method).and_raise(errcls)
+ expect { subject }.to raise_error(errcls)
+ end
+ end
+
+ shared_examples 'an anonymous request' do
+ it 'returns nil' do
+ expect(subject).to be(nil)
+ end
+ end
+
+ shared_examples 'an authenticated request' do
+ it 'returns the token' do
+ expect(subject).to be(token)
+ end
+ end
+
+ shared_examples 'an unauthorized request' do
+ it_behaves_like 'stops early', :unauthorized!
+ end
+
+ context 'with no allowed authentication strategies' do
+ let(:authentication) { nil }
+
+ it_behaves_like 'an anonymous request'
+ end
+
+ context 'with no located credentials' do
+ let(:locators) { [double(extract: nil)] }
+ let(:resolvers) { [] }
+
+ it_behaves_like 'an anonymous request'
+ end
+
+ context 'with one set of located credentials' do
+ let(:locators) { [double(extract: true)] }
+
+ context 'when the credentials contain a valid token' do
+ let(:token) { double }
+ let(:resolvers) { [double(resolve: token)] }
+
+ it_behaves_like 'an authenticated request'
+ end
+
+ context 'when the credentials do not contain a valid token' do
+ let(:resolvers) { [double(resolve: nil)] }
+
+ it_behaves_like 'an unauthorized request'
+ end
+ end
+
+ context 'with multiple located credentials' do
+ let(:locators) { [double(extract: true), double(extract: true)] }
+ let(:resolvers) { [] }
+
+ it_behaves_like 'stops early', :bad_request!
+ end
+
+ context 'when a resolver raises UnauthorizedError' do
+ let(:locators) { [double(extract: true)] }
+ let(:resolvers) do
+ r = double
+ expect(r).to receive(:resolve).and_raise(Gitlab::Auth::UnauthorizedError)
+ r
+ end
+
+ it_behaves_like 'an unauthorized request'
+ end
+ end
+
+ describe '#access_token_from_namespace_inheritable' do
+ subject { object.access_token_from_namespace_inheritable }
+
+ it 'returns #token_from_namespace_inheritable if it is a personal access token' do
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(personal_access_token)
+ expect(subject).to be(personal_access_token)
+ end
+
+ it 'returns nil if #token_from_namespace_inheritable is not a personal access token' do
+ token = double
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(token)
+ expect(subject).to be(nil)
+ end
+ end
+
+ describe '#user_from_namespace_inheritable' do
+ subject { object.user_from_namespace_inheritable }
+
+ it 'returns #token_from_namespace_inheritable if it is a deploy token' do
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(deploy_token)
+ expect(subject).to be(deploy_token)
+ end
+
+ it 'returns #token_from_namespace_inheritable.user if the token is not a deploy token' do
+ user = double
+ token = double(user: user)
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(token)
+
+ expect(subject).to be(user)
+ end
+
+ it 'falls back to #find_user_from_warden if #token_from_namespace_inheritable.user is nil' do
+ token = double(user: nil)
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(token)
+ subject
+ end
+
+ it 'falls back to #find_user_from_warden if #token_from_namespace_inheritable is nil' do
+ expect(object).to receive(:token_from_namespace_inheritable).and_return(nil)
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index be5f0cc9f9a..bdf04fafaae 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -205,7 +205,7 @@ RSpec.describe API::Helpers do
end
it 'tracks redis hll event' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(value, event_name)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(event_name, values: value)
subject.increment_unique_values(event_name, value)
end
@@ -363,4 +363,49 @@ RSpec.describe API::Helpers do
end
end
end
+
+ describe '#present_disk_file!' do
+ let_it_be(:dummy_class) do
+ Class.new do
+ attr_reader :headers
+ alias_method :header, :headers
+
+ def initialize
+ @headers = {}
+ end
+ end
+ end
+
+ let(:dummy_instance) { dummy_class.include(described_class).new }
+ let(:path) { '/tmp/file.txt' }
+ let(:filename) { 'file.txt' }
+
+ subject { dummy_instance.present_disk_file!(path, filename) }
+
+ before do
+ expect(dummy_instance).to receive(:content_type).with('application/octet-stream')
+ end
+
+ context 'with X-Sendfile supported' do
+ before do
+ dummy_instance.headers['X-Sendfile-Type'] = 'X-Sendfile'
+ end
+
+ it 'sends the file using X-Sendfile' do
+ expect(dummy_instance).to receive(:body).with('')
+
+ subject
+
+ expect(dummy_instance.headers['X-Sendfile']).to eq(path)
+ end
+ end
+
+ context 'without X-Sendfile supported' do
+ it 'sends the file' do
+ expect(dummy_instance).to receive(:sendfile).with(path)
+
+ subject
+ end
+ end
+ end
end