diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /spec/services/dependency_proxy | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'spec/services/dependency_proxy')
4 files changed, 204 insertions, 11 deletions
diff --git a/spec/services/dependency_proxy/auth_token_service_spec.rb b/spec/services/dependency_proxy/auth_token_service_spec.rb new file mode 100644 index 00000000000..4b96f9d75a9 --- /dev/null +++ b/spec/services/dependency_proxy/auth_token_service_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe DependencyProxy::AuthTokenService do + include DependencyProxyHelpers + + describe '.decoded_token_payload' do + let_it_be(:user) { create(:user) } + let_it_be(:token) { build_jwt(user) } + + subject { described_class.decoded_token_payload(token.encoded) } + + it 'returns the user' do + result = subject + + expect(result['user_id']).to eq(user.id) + end + + it 'raises an error if the token is expired' do + travel_to(Time.zone.now + Auth::DependencyProxyAuthenticationService.token_expire_at + 1.minute) do + expect { subject }.to raise_error(JWT::ExpiredSignature) + end + end + + it 'raises an error if decoding fails' do + allow(JWT).to receive(:decode).and_raise(JWT::DecodeError) + + expect { subject }.to raise_error(JWT::DecodeError) + end + + it 'raises an error if signature is immature' do + allow(JWT).to receive(:decode).and_raise(JWT::ImmatureSignature) + + expect { subject }.to raise_error(JWT::ImmatureSignature) + end + end +end diff --git a/spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb b/spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb new file mode 100644 index 00000000000..c375e5a2fa3 --- /dev/null +++ b/spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe DependencyProxy::FindOrCreateManifestService do + include DependencyProxyHelpers + + let_it_be(:image) { 'alpine' } + let_it_be(:tag) { 'latest' } + let_it_be(:dependency_proxy_manifest) { create(:dependency_proxy_manifest, file_name: "#{image}:#{tag}.json") } + let(:manifest) { dependency_proxy_manifest.file.read } + let(:group) { dependency_proxy_manifest.group } + let(:token) { Digest::SHA256.hexdigest('123') } + let(:headers) { { 'docker-content-digest' => dependency_proxy_manifest.digest } } + + describe '#execute' do + subject { described_class.new(group, image, tag, token).execute } + + context 'when no manifest exists' do + let_it_be(:image) { 'new-image' } + + before do + stub_manifest_head(image, tag, digest: dependency_proxy_manifest.digest) + stub_manifest_download(image, tag, headers: headers) + end + + it 'downloads manifest from remote registry if there is no cached one', :aggregate_failures do + expect { subject }.to change { group.dependency_proxy_manifests.count }.by(1) + expect(subject[:status]).to eq(:success) + expect(subject[:manifest]).to be_a(DependencyProxy::Manifest) + expect(subject[:manifest]).to be_persisted + end + end + + context 'when manifest exists' do + before do + stub_manifest_head(image, tag, digest: dependency_proxy_manifest.digest) + end + + shared_examples 'using the cached manifest' do + it 'uses cached manifest instead of downloading one', :aggregate_failures do + expect(subject[:status]).to eq(:success) + expect(subject[:manifest]).to be_a(DependencyProxy::Manifest) + expect(subject[:manifest]).to eq(dependency_proxy_manifest) + end + end + + it_behaves_like 'using the cached manifest' + + context 'when digest is stale' do + let(:digest) { 'new-digest' } + + before do + stub_manifest_head(image, tag, digest: digest) + stub_manifest_download(image, tag, headers: { 'docker-content-digest' => digest }) + end + + it 'downloads the new manifest and updates the existing record', :aggregate_failures do + expect(subject[:status]).to eq(:success) + expect(subject[:manifest]).to eq(dependency_proxy_manifest) + expect(subject[:manifest].digest).to eq(digest) + end + end + + context 'failed connection' do + before do + expect(DependencyProxy::HeadManifestService).to receive(:new).and_raise(Net::OpenTimeout) + end + + it_behaves_like 'using the cached manifest' + + context 'and no manifest is cached' do + let_it_be(:image) { 'new-image' } + + it 'returns an error', :aggregate_failures do + expect(subject[:status]).to eq(:error) + expect(subject[:http_status]).to eq(503) + expect(subject[:message]).to eq('Failed to download the manifest from the external registry') + end + end + end + end + end +end diff --git a/spec/services/dependency_proxy/head_manifest_service_spec.rb b/spec/services/dependency_proxy/head_manifest_service_spec.rb new file mode 100644 index 00000000000..7c7ebe4d181 --- /dev/null +++ b/spec/services/dependency_proxy/head_manifest_service_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe DependencyProxy::HeadManifestService do + include DependencyProxyHelpers + + let(:image) { 'alpine' } + let(:tag) { 'latest' } + let(:token) { Digest::SHA256.hexdigest('123') } + let(:digest) { '12345' } + + subject { described_class.new(image, tag, token).execute } + + context 'remote request is successful' do + before do + stub_manifest_head(image, tag, digest: digest) + end + + it { expect(subject[:status]).to eq(:success) } + it { expect(subject[:digest]).to eq(digest) } + end + + context 'remote request is not found' do + before do + stub_manifest_head(image, tag, status: 404, body: 'Not found') + end + + it { expect(subject[:status]).to eq(:error) } + it { expect(subject[:http_status]).to eq(404) } + it { expect(subject[:message]).to eq('Not found') } + end + + context 'net timeout exception' do + before do + manifest_link = DependencyProxy::Registry.manifest_url(image, tag) + + stub_full_request(manifest_link, method: :head).to_timeout + end + + it { expect(subject[:status]).to eq(:error) } + it { expect(subject[:http_status]).to eq(599) } + it { expect(subject[:message]).to eq('execution expired') } + end +end diff --git a/spec/services/dependency_proxy/pull_manifest_service_spec.rb b/spec/services/dependency_proxy/pull_manifest_service_spec.rb index 030ed9c001b..b760839d1fb 100644 --- a/spec/services/dependency_proxy/pull_manifest_service_spec.rb +++ b/spec/services/dependency_proxy/pull_manifest_service_spec.rb @@ -8,26 +8,43 @@ RSpec.describe DependencyProxy::PullManifestService do let(:tag) { '3.9' } let(:token) { Digest::SHA256.hexdigest('123') } let(:manifest) { { foo: 'bar' }.to_json } + let(:digest) { '12345' } + let(:headers) { { 'docker-content-digest' => digest } } - subject { described_class.new(image, tag, token).execute } + subject { described_class.new(image, tag, token).execute_with_manifest(&method(:check_response)) } context 'remote request is successful' do before do - stub_manifest_download(image, tag) + stub_manifest_download(image, tag, headers: headers) end - it { expect(subject[:status]).to eq(:success) } - it { expect(subject[:manifest]).to eq(manifest) } + it 'successfully returns the manifest' do + def check_response(response) + response[:file].rewind + + expect(response[:status]).to eq(:success) + expect(response[:file].read).to eq(manifest) + expect(response[:digest]).to eq(digest) + end + + subject + end end context 'remote request is not found' do before do - stub_manifest_download(image, tag, 404, 'Not found') + stub_manifest_download(image, tag, status: 404, body: 'Not found') end - it { expect(subject[:status]).to eq(:error) } - it { expect(subject[:http_status]).to eq(404) } - it { expect(subject[:message]).to eq('Not found') } + it 'returns a 404 not found error' do + def check_response(response) + expect(response[:status]).to eq(:error) + expect(response[:http_status]).to eq(404) + expect(response[:message]).to eq('Not found') + end + + subject + end end context 'net timeout exception' do @@ -37,8 +54,20 @@ RSpec.describe DependencyProxy::PullManifestService do stub_full_request(manifest_link).to_timeout end - it { expect(subject[:status]).to eq(:error) } - it { expect(subject[:http_status]).to eq(599) } - it { expect(subject[:message]).to eq('execution expired') } + it 'returns a 599 error' do + def check_response(response) + expect(response[:status]).to eq(:error) + expect(response[:http_status]).to eq(599) + expect(response[:message]).to eq('execution expired') + end + + subject + end + end + + context 'no block is given' do + subject { described_class.new(image, tag, token).execute_with_manifest } + + it { expect { subject }.to raise_error(ArgumentError, 'Block must be provided') } end end |