summaryrefslogtreecommitdiff
path: root/spec/requests/api/project_container_repositories_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests/api/project_container_repositories_spec.rb')
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb228
1 files changed, 228 insertions, 0 deletions
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
new file mode 100644
index 00000000000..f1dc4e6f0b2
--- /dev/null
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -0,0 +1,228 @@
+require 'spec_helper'
+
+describe API::ProjectContainerRepositories do
+ include ExclusiveLeaseHelpers
+
+ set(:project) { create(:project, :private) }
+ set(:maintainer) { create(:user) }
+ set(:developer) { create(:user) }
+ set(:reporter) { create(:user) }
+ set(:guest) { create(:user) }
+
+ let(:root_repository) { create(:container_repository, :root, project: project) }
+ let(:test_repository) { create(:container_repository, project: project) }
+
+ let(:users) do
+ {
+ anonymous: nil,
+ developer: developer,
+ guest: guest,
+ maintainer: maintainer,
+ reporter: reporter
+ }
+ end
+
+ let(:api_user) { maintainer }
+
+ before do
+ project.add_maintainer(maintainer)
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+
+ stub_feature_flags(container_registry_api: true)
+ stub_container_registry_config(enabled: true)
+
+ root_repository
+ test_repository
+ end
+
+ describe 'GET /projects/:id/registry/repositories' do
+ let(:url) { "/projects/#{project.id}/registry/repositories" }
+
+ subject { get api(url, api_user) }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
+ let(:object) { project }
+ end
+ end
+
+ describe 'DELETE /projects/:id/registry/repositories/:repository_id' do
+ subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}", api_user) }
+
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ context 'for maintainer' do
+ let(:api_user) { maintainer }
+
+ it 'schedules removal of repository' do
+ expect(DeleteContainerRepositoryWorker).to receive(:perform_async)
+ .with(maintainer.id, root_repository.id)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:accepted)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/registry/repositories/:repository_id/tags' do
+ subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user) }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ context 'for reporter' do
+ let(:api_user) { reporter }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest))
+ end
+
+ it 'returns a list of tags' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['name'] }).to eq %w(latest rootA)
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/tags')
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags' do
+ subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user), params: params }
+
+ context 'disallowed' do
+ let(:params) do
+ { name_regex: 'v10.*' }
+ end
+
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+ end
+
+ context 'for maintainer' do
+ let(:api_user) { maintainer }
+
+ context 'without required parameters' do
+ let(:params) { }
+
+ it 'returns bad request' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'passes all declared parameters' do
+ let(:params) do
+ { name_regex: 'v10.*',
+ keep_n: 100,
+ older_than: '1 day',
+ other: 'some value' }
+ end
+
+ let(:worker_params) do
+ { name_regex: 'v10.*',
+ keep_n: 100,
+ older_than: '1 day' }
+ end
+
+ let(:lease_key) { "container_repository:cleanup_tags:#{root_repository.id}" }
+
+ it 'schedules cleanup of tags repository' do
+ stub_exclusive_lease(lease_key, timeout: 1.hour)
+ expect(CleanupContainerRepositoryWorker).to receive(:perform_async)
+ .with(maintainer.id, root_repository.id, worker_params)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:accepted)
+ end
+
+ context 'called multiple times in one hour' do
+ it 'returns 400 with an error message' do
+ stub_exclusive_lease_taken(lease_key, timeout: 1.hour)
+ subject
+
+ expect(response).to have_gitlab_http_status(400)
+ expect(response.body).to include('This request has already been made.')
+ end
+
+ it 'executes service only for the first time' do
+ expect(CleanupContainerRepositoryWorker).to receive(:perform_async).once
+
+ 2.times { subject }
+ end
+ end
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
+ subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ context 'for reporter' do
+ let(:api_user) { reporter }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA), with_manifest: true)
+ end
+
+ it 'returns a details of tag' do
+ subject
+
+ expect(json_response).to include(
+ 'name' => 'rootA',
+ 'digest' => 'sha256:4c8e63ca4cb663ce6c688cb06f1c372b088dac5b6d7ad7d49cd620d85cf72a15',
+ 'revision' => 'd7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac',
+ 'total_size' => 2319870)
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/tag')
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
+ subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
+
+ it_behaves_like 'rejected container repository access', :reporter, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ context 'for developer' do
+ let(:api_user) { developer }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA), with_manifest: true)
+ end
+
+ it 'properly removes tag' do
+ expect_any_instance_of(ContainerRegistry::Client)
+ .to receive(:delete_repository_tag).with(root_repository.path,
+ 'sha256:4c8e63ca4cb663ce6c688cb06f1c372b088dac5b6d7ad7d49cd620d85cf72a15')
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+end