Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-27 15:11:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-27 15:11:21 +0300
commit5471fef2360f9bcf604a026d5807a554dae243e9 (patch)
tree8b9c82036dc5da7fdf30ba3c2c5f85997ad41eaa /spec
parentb6f32e82a08a171debbb57236e8995b8d741e6a5 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb6
-rw-r--r--spec/features/issues/form_spec.rb398
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb53
-rw-r--r--spec/features/labels_hierarchy_spec.rb76
-rw-r--r--spec/features/merge_request/user_creates_mr_spec.rb75
-rw-r--r--spec/features/merge_request/user_edits_mr_spec.rb38
-rw-r--r--spec/features/projects/container_registry_spec.rb3
-rw-r--r--spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js11
-rw-r--r--spec/graphql/mutations/container_repositories/destroy_spec.rb6
-rw-r--r--spec/lib/extracts_path_spec.rb4
-rw-r--r--spec/lib/extracts_ref/ref_extractor_spec.rb125
-rw-r--r--spec/lib/extracts_ref_spec.rb22
-rw-r--r--spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb48
-rw-r--r--spec/lib/gitlab/database/migrations/version_spec.rb120
-rw-r--r--spec/requests/api/composer_packages_spec.rb613
-rw-r--r--spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb20
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb3
-rw-r--r--spec/support/shared_examples/ref_extraction_shared_examples.rb165
-rw-r--r--spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb102
-rw-r--r--spec/views/projects/merge_requests/edit.html.haml_spec.rb65
-rw-r--r--spec/workers/delete_container_repository_worker_spec.rb19
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
23 files changed, 1126 insertions, 852 deletions
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 834fdddd583..a07a3641edf 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Registry::RepositoriesController do
+RSpec.describe Projects::Registry::RepositoriesController, feature_category: :container_registry do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :private) }
@@ -103,8 +103,6 @@ RSpec.describe Projects::Registry::RepositoriesController do
end
it 'marks the repository as delete_scheduled' do
- expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async).with(user.id, repository.id)
-
expect { delete_repository(repository) }
.to change { repository.reload.status }.from(nil).to('delete_scheduled')
@@ -113,8 +111,6 @@ RSpec.describe Projects::Registry::RepositoriesController do
end
it 'tracks the event', :snowplow do
- allow(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id)
-
delete_repository(repository)
expect_snowplow_event(category: anything, action: 'delete_repository')
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index ed2c712feb1..6e3a5ecaac7 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -18,7 +18,6 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
let_it_be(:confidential_issue) { create(:issue, project: project, assignees: [user], milestone: milestone, confidential: true) }
let(:current_user) { user }
- let(:visible_label_selection_on_metadata) { false }
before_all do
project.add_maintainer(user)
@@ -28,7 +27,6 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
before do
stub_licensed_features(multiple_issue_assignees: false, issue_weights: false)
- stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata)
sign_in(current_user)
end
@@ -117,232 +115,125 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- let(:visible_label_selection_on_metadata) { true }
-
- it 'allows user to create new issue' do
- fill_in 'issue_title', with: 'title'
- fill_in 'issue_description', with: 'title'
-
- expect(find('a', text: 'Assign to me')).to be_visible
- click_button 'Unassigned'
-
- wait_for_requests
-
- page.within '.dropdown-menu-user' do
- click_link user2.name
- end
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
- page.within '.js-assignee-search' do
- expect(page).to have_content user2.name
- end
- expect(find('a', text: 'Assign to me')).to be_visible
-
- click_link 'Assign to me'
- assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
-
- expect(assignee_ids[0].value).to match(user.id.to_s)
-
- page.within '.js-assignee-search' do
- expect(page).to have_content user.name
- end
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
+ it 'allows user to create new issue' do
+ fill_in 'issue_title', with: 'title'
+ fill_in 'issue_description', with: 'title'
- click_button 'Select milestone'
- click_button milestone.title
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(page).to have_button milestone.title
+ expect(find('a', text: 'Assign to me')).to be_visible
+ click_button 'Unassigned'
- click_button _('Select label')
- wait_for_all_requests
- page.within '[data-testid="sidebar-labels"]' do
- click_button label.title
- click_button label2.title
- click_button _('Close')
- wait_for_requests
- page.within('[data-testid="embedded-labels-list"]') do
- expect(page).to have_content(label.title)
- expect(page).to have_content(label2.title)
- end
- end
+ wait_for_requests
- click_button 'Create issue'
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
+ end
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user2.name
+ end
+ expect(find('a', text: 'Assign to me')).to be_visible
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content "Assignee"
- end
+ click_link 'Assign to me'
+ assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
+ expect(assignee_ids[0].value).to match(user.id.to_s)
- page.within '.labels' do
- expect(page).to have_content label.title
- expect(page).to have_content label2.title
- end
- end
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user.name
+ end
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- page.within '.breadcrumbs' do
- issue = Issue.find_by(title: 'title')
+ click_button 'Select milestone'
+ click_button milestone.title
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(page).to have_button milestone.title
- expect(page).to have_text("Issues #{issue.to_reference}")
+ click_button _('Select label')
+ wait_for_all_requests
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
+ wait_for_requests
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
end
end
- it 'correctly updates the dropdown toggle when removing a label' do
- click_button _('Select label')
-
- wait_for_all_requests
-
- page.within '[data-testid="sidebar-labels"]' do
- click_button label.title
- click_button _('Close')
-
- wait_for_requests
-
- page.within('[data-testid="embedded-labels-list"]') do
- expect(page).to have_content(label.title)
- end
+ click_button 'Create issue'
- expect(page.find('.gl-dropdown-button-text')).to have_content(label.title)
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content "Assignee"
end
- click_button label.title, class: 'gl-dropdown-toggle'
-
- wait_for_all_requests
-
- page.within '[data-testid="sidebar-labels"]' do
- click_button label.title, class: 'dropdown-item'
- click_button _('Close')
-
- wait_for_requests
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
- expect(page).not_to have_selector('[data-testid="embedded-labels-list"]')
- expect(page.find('.gl-dropdown-button-text')).to have_content(_('Select label'))
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
end
end
- it 'clears label search input field when a label is selected', :js do
- click_button _('Select label')
+ page.within '.breadcrumbs' do
+ issue = Issue.find_by(title: 'title')
- wait_for_all_requests
-
- page.within '[data-testid="sidebar-labels"]' do
- search_field = find('input[type="search"]')
-
- search_field.native.send_keys(label.title)
-
- expect(page).to have_css('.gl-search-box-by-type-clear')
-
- click_button label.title, class: 'dropdown-item'
-
- expect(page).not_to have_css('.gl-search-box-by-type-clear')
- expect(search_field.value).to eq ''
- end
+ expect(page).to have_text("Issues #{issue.to_reference}")
end
end
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- let(:visible_label_selection_on_metadata) { false }
+ it 'correctly updates the dropdown toggle when removing a label' do
+ click_button _('Select label')
- it 'allows user to create new issue' do
- fill_in 'issue_title', with: 'title'
- fill_in 'issue_description', with: 'title'
+ wait_for_all_requests
- expect(find('a', text: 'Assign to me')).to be_visible
- click_button 'Unassigned'
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button _('Close')
wait_for_requests
- page.within '.dropdown-menu-user' do
- click_link user2.name
- end
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
- page.within '.js-assignee-search' do
- expect(page).to have_content user2.name
- end
- expect(find('a', text: 'Assign to me')).to be_visible
-
- click_link 'Assign to me'
- assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
-
- expect(assignee_ids[0].value).to match(user.id.to_s)
-
- page.within '.js-assignee-search' do
- expect(page).to have_content user.name
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
end
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
-
- click_button 'Select milestone'
- click_button milestone.title
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(page).to have_button milestone.title
-
- click_button 'Labels'
- page.within '.dropdown-menu-labels' do
- click_link label.title
- click_link label2.title
- end
-
- find('.js-issuable-form-dropdown.js-label-select').click
- page.within '.js-label-select' do
- expect(page).to have_content label.title
- end
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
-
- click_button 'Create issue'
+ expect(page.find('.gl-dropdown-button-text')).to have_content(label.title)
+ end
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content "Assignee"
- end
+ click_button label.title, class: 'gl-dropdown-toggle'
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
+ wait_for_all_requests
- page.within '.labels' do
- expect(page).to have_content label.title
- expect(page).to have_content label2.title
- end
- end
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title, class: 'dropdown-item'
+ click_button _('Close')
- page.within '.breadcrumbs' do
- issue = Issue.find_by(title: 'title')
+ wait_for_requests
- expect(page).to have_text("Issues #{issue.to_reference}")
- end
+ expect(page).not_to have_selector('[data-testid="embedded-labels-list"]')
+ expect(page.find('.gl-dropdown-button-text')).to have_content(_('Select label'))
end
+ end
- it 'correctly updates the dropdown toggle when removing a label' do
- click_button 'Labels'
-
- page.within '.dropdown-menu-labels' do
- click_link label.title
- end
+ it 'clears label search input field when a label is selected', :js do
+ click_button _('Select label')
- expect(find('.js-label-select')).to have_content(label.title)
+ wait_for_all_requests
- page.within '.dropdown-menu-labels' do
- click_link label.title
- end
+ page.within '[data-testid="sidebar-labels"]' do
+ search_field = find('input[type="search"]')
- expect(find('.js-label-select')).to have_content('Labels')
- end
+ search_field.native.send_keys(label.title)
- it 'clears label search input field when a label is selected' do
- click_button 'Labels'
+ expect(page).to have_css('.gl-search-box-by-type-clear')
- page.within '.dropdown-menu-labels' do
- search_field = find('input[type="search"]')
+ click_button label.title, class: 'dropdown-item'
- search_field.set(label2.title)
- click_link label2.title
- expect(search_field.value).to eq ''
- end
+ expect(page).not_to have_css('.gl-search-box-by-type-clear')
+ expect(search_field.value).to eq ''
end
end
@@ -559,100 +450,52 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
visit edit_project_issue_path(project, issue)
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- let(:visible_label_selection_on_metadata) { true }
-
- it 'allows user to update issue' do
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
-
- page.within '.js-user-search' do
- expect(page).to have_content user.name
- end
-
- expect(page).to have_button milestone.title
-
- click_button _('Select label')
-
- wait_for_all_requests
-
- page.within '[data-testid="sidebar-labels"]' do
- click_button label.title
- click_button label2.title
- click_button _('Close')
+ it 'allows user to update issue' do
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- wait_for_requests
+ page.within '.js-user-search' do
+ expect(page).to have_content user.name
+ end
- page.within('[data-testid="embedded-labels-list"]') do
- expect(page).to have_content(label.title)
- expect(page).to have_content(label2.title)
- end
- end
+ expect(page).to have_button milestone.title
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)
- .map(&:value))
- .to contain_exactly(label.id.to_s, label2.id.to_s)
+ click_button _('Select label')
- click_button 'Save changes'
+ wait_for_all_requests
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content user.name
- end
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
+ wait_for_requests
- page.within '.labels' do
- expect(page).to have_content label.title
- expect(page).to have_content label2.title
- end
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
end
end
- end
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- let(:visible_label_selection_on_metadata) { false }
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)
+ .map(&:value))
+ .to contain_exactly(label.id.to_s, label2.id.to_s)
- it 'allows user to update issue' do
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
+ click_button 'Save changes'
- page.within '.js-user-search' do
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
expect(page).to have_content user.name
end
- expect(page).to have_button milestone.title
-
- click_button 'Labels'
- page.within '.dropdown-menu-labels' do
- click_link label.title
- click_link label2.title
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
end
- page.within '.js-label-select' do
- expect(page).to have_content label.title
- end
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
-
- click_button 'Save changes'
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content user.name
- end
-
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
-
- page.within '.labels' do
- expect(page).to have_content label.title
- expect(page).to have_content label2.title
- end
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
end
end
end
@@ -733,10 +576,8 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
visit new_project_issue_path(sub_group_project)
end
- context 'with the visible_label_selection_on_metadata feature flag enabled', :js do
- let(:visible_label_selection_on_metadata) { true }
-
- it 'creates project label from dropdown', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/416585' do
+ context 'labels', :js do
+ it 'creates project label from dropdown' do
find('[data-testid="labels-select-dropdown-contents"] button').click
wait_for_all_requests
@@ -761,29 +602,6 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
end
end
-
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- let(:visible_label_selection_on_metadata) { false }
-
- it 'creates project label from dropdown' do
- click_button 'Labels'
-
- click_link 'Create project label'
-
- page.within '.dropdown-new-label' do
- fill_in 'new_label_name', with: 'test label'
- first('.suggest-colors-dropdown a').click
-
- click_button 'Create'
-
- wait_for_requests
- end
-
- page.within '.dropdown-menu-labels' do
- expect(page).to have_link 'test label'
- end
- end
- end
end
def before_for_selector(selector)
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 857cb1f39a2..c4aff4ca04b 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -9,8 +9,6 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:user) { create(:user) }
- let(:visible_label_selection_on_metadata) { false }
-
context "when unauthenticated" do
before do
sign_out(:user)
@@ -37,7 +35,6 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
context "when signed in as guest", :js do
before do
- stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata)
project.add_guest(user)
sign_in(user)
@@ -97,50 +94,28 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- let(:visible_label_selection_on_metadata) { true }
-
- it "creates issue" do
- issue_title = "500 error on profile"
-
- fill_in("Title", with: issue_title)
-
- click_button _('Select label')
+ it "creates issue" do
+ issue_title = "500 error on profile"
- wait_for_all_requests
+ fill_in("Title", with: issue_title)
- page.within '[data-testid="sidebar-labels"]' do
- click_button label_titles.first
- click_button _('Close')
+ click_button _('Select label')
- wait_for_requests
- end
+ wait_for_all_requests
- click_button("Create issue")
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label_titles.first
+ click_button _('Close')
- expect(page).to have_content(issue_title)
- .and have_content(user.name)
- .and have_content(project.name)
- .and have_content(label_titles.first)
+ wait_for_requests
end
- end
-
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- let(:visible_label_selection_on_metadata) { false }
- it "creates issue" do
- issue_title = "500 error on profile"
+ click_button("Create issue")
- fill_in("Title", with: issue_title)
- click_button("Label")
- click_link(label_titles.first)
- click_button("Create issue")
-
- expect(page).to have_content(issue_title)
- .and have_content(user.name)
- .and have_content(project.name)
- .and have_content(label_titles.first)
- end
+ expect(page).to have_content(issue_title)
+ .and have_content(user.name)
+ .and have_content(project.name)
+ .and have_content(label_titles.first)
end
end
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index 0cb712622f2..edc7b570933 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -158,73 +158,35 @@ RSpec.describe 'Labels Hierarchy', :js, feature_category: :team_planning do
end
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ context 'when creating new issuable' do
before do
- stub_feature_flags(visible_label_selection_on_metadata: true)
+ visit new_project_issue_path(project_1)
+ close_rich_text_promo_popover_if_present
end
- context 'when creating new issuable' do
- before do
- visit new_project_issue_path(project_1)
- close_rich_text_promo_popover_if_present
- end
-
- it 'is able to assign ancestor group labels' do
- fill_in 'issue_title', with: 'new created issue'
- fill_in 'issue_description', with: 'new issue description'
-
- click_button _('Select label')
-
- wait_for_all_requests
+ it 'is able to assign ancestor group labels' do
+ fill_in 'issue_title', with: 'new created issue'
+ fill_in 'issue_description', with: 'new issue description'
- page.within '[data-testid="sidebar-labels"]' do
- click_button grandparent_group_label.title
- click_button parent_group_label.title
- click_button project_label_1.title
- click_button _('Close')
+ click_button _('Select label')
- wait_for_requests
- end
-
- find('.btn-confirm').click
+ wait_for_all_requests
- expect(page.find('.issue-details h1.title')).to have_content('new created issue')
- expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
- end
- end
- end
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button grandparent_group_label.title
+ click_button parent_group_label.title
+ click_button project_label_1.title
+ click_button _('Close')
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: false)
- end
-
- context 'when creating new issuable' do
- before do
- visit new_project_issue_path(project_1)
- close_rich_text_promo_popover_if_present
- end
-
- it 'is able to assign ancestor group labels' do
- fill_in 'issue_title', with: 'new created issue'
- fill_in 'issue_description', with: 'new issue description'
-
- find(".js-label-select").click
wait_for_requests
+ end
- find('a.label-item', text: grandparent_group_label.title).click
- find('a.label-item', text: parent_group_label.title).click
- find('a.label-item', text: project_label_1.title).click
-
- find('.btn-confirm').click
+ find('.btn-confirm').click
- expect(page.find('.issue-details h1.title')).to have_content('new created issue')
- expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
- end
+ expect(page.find('.issue-details h1.title')).to have_content('new created issue')
+ expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
end
end
diff --git a/spec/features/merge_request/user_creates_mr_spec.rb b/spec/features/merge_request/user_creates_mr_spec.rb
index f48315a1636..950b64bb395 100644
--- a/spec/features/merge_request/user_creates_mr_spec.rb
+++ b/spec/features/merge_request/user_creates_mr_spec.rb
@@ -89,77 +89,34 @@ RSpec.describe 'Merge request > User creates MR', feature_category: :code_review
end
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: true)
- end
-
- context 'non-fork merge request' do
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request with visible selected labels'
- end
-
- context 'from a forked project' do
- let(:canonical_project) { create(:project, :public, :repository) }
-
- let(:source_project) do
- fork_project(canonical_project, user,
- repository: true,
- namespace: user.namespace)
- end
-
- context 'to canonical project' do
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request with visible selected labels'
- end
-
- context 'to another forked project' do
- let(:target_project) do
- fork_project(canonical_project, user,
- repository: true,
- namespace: user.namespace)
- end
-
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request with visible selected labels'
- end
- end
+ context 'non-fork merge request' do
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request with visible selected labels'
end
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: false)
+ context 'from a forked project' do
+ let(:canonical_project) { create(:project, :public, :repository) }
+
+ let(:source_project) do
+ fork_project(canonical_project, user,
+ repository: true,
+ namespace: user.namespace)
end
- context 'non-fork merge request' do
+ context 'to canonical project' do
include_context 'merge request create context'
- it_behaves_like 'a creatable merge request'
+ it_behaves_like 'a creatable merge request with visible selected labels'
end
- context 'from a forked project' do
- let(:canonical_project) { create(:project, :public, :repository) }
-
- let(:source_project) do
+ context 'to another forked project' do
+ let(:target_project) do
fork_project(canonical_project, user,
repository: true,
namespace: user.namespace)
end
- context 'to canonical project' do
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request'
- end
-
- context 'to another forked project' do
- let(:target_project) do
- fork_project(canonical_project, user,
- repository: true,
- namespace: user.namespace)
- end
-
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request'
- end
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request with visible selected labels'
end
end
diff --git a/spec/features/merge_request/user_edits_mr_spec.rb b/spec/features/merge_request/user_edits_mr_spec.rb
index bf237e07ac8..fca3a76949a 100644
--- a/spec/features/merge_request/user_edits_mr_spec.rb
+++ b/spec/features/merge_request/user_edits_mr_spec.rb
@@ -198,39 +198,15 @@ RSpec.describe 'Merge request > User edits MR', feature_category: :code_review_w
stub_licensed_features(multiple_merge_request_assignees: false)
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: true)
- end
-
- context 'non-fork merge request' do
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request with visible selected labels'
- end
-
- context 'for a forked project' do
- let(:source_project) { fork_project(target_project, nil, repository: true) }
-
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request with visible selected labels'
- end
+ context 'non-fork merge request' do
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request with visible selected labels'
end
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: false)
- end
-
- context 'non-fork merge request' do
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request'
- end
+ context 'for a forked project' do
+ let(:source_project) { fork_project(target_project, nil, repository: true) }
- context 'for a forked project' do
- let(:source_project) { fork_project(target_project, nil, repository: true) }
-
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request'
- end
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request with visible selected labels'
end
end
diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb
index 0a77c671fce..c285d039d08 100644
--- a/spec/features/projects/container_registry_spec.rb
+++ b/spec/features/projects/container_registry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Container Registry', :js, feature_category: :groups_and_projects do
+RSpec.describe 'Container Registry', :js, feature_category: :container_registry do
include_context 'container registry tags'
let(:user) { create(:user) }
@@ -75,7 +75,6 @@ RSpec.describe 'Container Registry', :js, feature_category: :groups_and_projects
visit_container_registry
expect_any_instance_of(ContainerRepository).to receive(:delete_scheduled!).and_call_original
- expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
find('[title="Remove repository"]').click
expect(find('.modal .modal-title')).to have_content _('Delete image repository?')
diff --git a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
index 7d65dddc3f9..be50858bc88 100644
--- a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
+++ b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
@@ -29,6 +29,7 @@ describe('BulkImportsHistoryApp', () => {
source_full_path: 'top-level-group-12',
destination_full_path: 'h5bp/top-level-group-12',
destination_name: 'top-level-group-12',
+ destination_slug: 'top-level-group-12',
destination_namespace: 'h5bp',
created_at: '2021-07-08T10:03:44.743Z',
failures: [],
@@ -40,6 +41,7 @@ describe('BulkImportsHistoryApp', () => {
entity_type: 'project',
source_full_path: 'autodevops-demo',
destination_name: 'autodevops-demo',
+ destination_slug: 'autodevops-demo',
destination_full_path: 'some-group/autodevops-demo',
destination_namespace: 'flightjs',
parent_id: null,
@@ -173,7 +175,7 @@ describe('BulkImportsHistoryApp', () => {
expect(findLocalStorageSync().props('value')).toBe(NEW_PAGE_SIZE);
});
- it('renders correct url for destination group when relative_url is empty', async () => {
+ it('renders link to destination_full_path for destination group', async () => {
createComponent({ shallow: false });
await axios.waitForAll();
@@ -182,14 +184,17 @@ describe('BulkImportsHistoryApp', () => {
);
});
- it('renders loading icon when destination namespace is not defined', async () => {
+ it('renders destination as text when destination_full_path is not defined', async () => {
const RESPONSE = [{ ...DUMMY_RESPONSE[0], destination_full_path: null }];
mock.onGet(API_URL).reply(HTTP_STATUS_OK, RESPONSE, DEFAULT_HEADERS);
createComponent({ shallow: false });
await axios.waitForAll();
- expect(wrapper.find('tbody tr').findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.find('tbody tr a').exists()).toBe(false);
+ expect(wrapper.find('tbody tr span').text()).toBe(
+ `${DUMMY_RESPONSE[0].destination_namespace}/${DUMMY_RESPONSE[0].destination_slug}/`,
+ );
});
it('adds slash to group urls', async () => {
diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb
index 85e0ac96e55..b49751985ec 100644
--- a/spec/graphql/mutations/container_repositories/destroy_spec.rb
+++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::ContainerRepositories::Destroy do
+RSpec.describe Mutations::ContainerRepositories::Destroy, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:container_repository) { create(:container_repository) }
@@ -23,7 +23,6 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
it 'marks the repository as delete_scheduled' do
expect(::Packages::CreateEventService)
.to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
- expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
subject
expect(container_repository.reload.delete_scheduled?).to be true
@@ -32,9 +31,6 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
shared_examples 'denying access to container respository' do
it 'raises an error' do
- expect(DeleteContainerRepositoryWorker)
- .not_to receive(:perform_async).with(user.id, container_repository.id)
-
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 5db2fbd923e..a10ff60a249 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ExtractsPath do
+RSpec.describe ExtractsPath, feature_category: :source_code_management do
include described_class
include RepoHelpers
include Gitlab::Routing
@@ -215,7 +215,7 @@ RSpec.describe ExtractsPath do
end
it 'raises an error if there are no matching refs' do
- expect { extract_ref_without_atom('foo.atom') }.to raise_error(ExtractsRef::InvalidPathError)
+ expect { extract_ref_without_atom('foo.atom') }.to raise_error(ExtractsPath::InvalidPathError)
end
end
end
diff --git a/spec/lib/extracts_ref/ref_extractor_spec.rb b/spec/lib/extracts_ref/ref_extractor_spec.rb
new file mode 100644
index 00000000000..23b283967ca
--- /dev/null
+++ b/spec/lib/extracts_ref/ref_extractor_spec.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ExtractsRef::RefExtractor, feature_category: :source_code_management do
+ include RepoHelpers
+
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:container) { create(:snippet, :repository, author: owner) }
+
+ let(:ref) { sample_commit[:id] }
+ let(:path) { sample_commit[:line_code_path] }
+ let(:params) { { path: path, ref: ref } }
+
+ let(:ref_extractor) { described_class.new(container, params) }
+
+ before do
+ ref_names = ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0', 'release/app', 'release/app/v1.0.0']
+
+ allow(container.repository).to receive(:ref_names).and_return(ref_names)
+ end
+
+ describe '#extract_vars!' do
+ it_behaves_like 'extracts ref vars'
+
+ context 'when ref contains trailing space' do
+ let(:ref) { 'master ' }
+
+ it 'strips surrounding space' do
+ ref_extractor.extract!
+
+ expect(ref_extractor.ref).to eq('master')
+ end
+ end
+
+ context 'when ref and path are nil' do
+ let(:ref) { nil }
+ let(:path) { nil }
+
+ it 'does not set commit' do
+ expect(container.repository).not_to receive(:commit).with('')
+
+ ref_extractor.extract!
+
+ expect(ref_extractor.commit).to be_nil
+ end
+ end
+
+ context 'when a ref_type parameter is provided' do
+ let(:params) { { path: path, ref: ref, ref_type: 'tags' } }
+
+ it 'sets a fully_qualified_ref variable' do
+ fully_qualified_ref = "refs/tags/#{ref}"
+
+ expect(container.repository).to receive(:commit).with(fully_qualified_ref)
+
+ ref_extractor.extract!
+
+ expect(ref_extractor.fully_qualified_ref).to eq(fully_qualified_ref)
+ end
+ end
+ end
+
+ describe '#ref_type' do
+ let(:params) { { ref_type: 'heads' } }
+
+ it 'delegates to .ref_type' do
+ expect(described_class).to receive(:ref_type).with('heads')
+
+ ref_extractor.ref_type
+ end
+ end
+
+ describe '.ref_type' do
+ subject { described_class.ref_type(ref_type) }
+
+ context 'when ref_type is nil' do
+ let(:ref_type) { nil }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when ref_type is heads' do
+ let(:ref_type) { 'heads' }
+
+ it { is_expected.to eq('heads') }
+ end
+
+ context 'when ref_type is tags' do
+ let(:ref_type) { 'tags' }
+
+ it { is_expected.to eq('tags') }
+ end
+
+ context 'when ref_type is invalid' do
+ let(:ref_type) { 'invalid' }
+
+ it { is_expected.to eq(nil) }
+ end
+ end
+
+ describe '.qualify_ref' do
+ subject { described_class.qualify_ref(ref, ref_type) }
+
+ context 'when ref_type is nil' do
+ let(:ref_type) { nil }
+
+ it { is_expected.to eq(ref) }
+ end
+
+ context 'when ref_type valid' do
+ let(:ref_type) { 'heads' }
+
+ it { is_expected.to eq("refs/#{ref_type}/#{ref}") }
+ end
+
+ context 'when ref_type is invalid' do
+ let(:ref_type) { 'invalid' }
+
+ it { is_expected.to eq(ref) }
+ end
+ end
+
+ it_behaves_like 'extracts ref method'
+end
diff --git a/spec/lib/extracts_ref_spec.rb b/spec/lib/extracts_ref_spec.rb
index bf33c8b95f1..9ff11899e89 100644
--- a/spec/lib/extracts_ref_spec.rb
+++ b/spec/lib/extracts_ref_spec.rb
@@ -100,27 +100,5 @@ RSpec.describe ExtractsRef do
end
end
- describe '.qualify_ref' do
- subject { described_class.qualify_ref(ref, ref_type) }
-
- context 'when ref_type is nil' do
- let(:ref_type) { nil }
-
- it { is_expected.to eq(ref) }
- end
-
- context 'when ref_type valid' do
- let(:ref_type) { 'heads' }
-
- it { is_expected.to eq("refs/#{ref_type}/#{ref}") }
- end
-
- context 'when ref_type is invalid' do
- let(:ref_type) { 'invalid' }
-
- it { is_expected.to eq(ref) }
- end
- end
-
it_behaves_like 'extracts refs'
end
diff --git a/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb b/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb
new file mode 100644
index 00000000000..e375af494a2
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::MilestoneMixin, feature_category: :database do
+ let(:migration_no_mixin) do
+ Class.new(Gitlab::Database::Migration[2.1]) do
+ def change
+ # no-op here to make rubocop happy
+ end
+ end
+ end
+
+ let(:migration_mixin) do
+ Class.new(Gitlab::Database::Migration[2.1]) do
+ include Gitlab::Database::Migrations::MilestoneMixin
+ end
+ end
+
+ let(:migration_mixin_version) do
+ Class.new(Gitlab::Database::Migration[2.1]) do
+ include Gitlab::Database::Migrations::MilestoneMixin
+ milestone '16.4'
+ end
+ end
+
+ context 'when the mixin is not included' do
+ it 'does not raise an error' do
+ expect { migration_no_mixin.new(4, 4) }.not_to raise_error
+ end
+ end
+
+ context 'when the mixin is included' do
+ context 'when a milestone is not specified' do
+ it "raises MilestoneNotSetError" do
+ expect { migration_mixin.new(4, 4, :regular) }.to raise_error(
+ "#{described_class}::MilestoneNotSetError".constantize
+ )
+ end
+ end
+
+ context 'when a milestone is specified' do
+ it "does not raise an error" do
+ expect { migration_mixin_version.new(4, 4, :regular) }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migrations/version_spec.rb b/spec/lib/gitlab/database/migrations/version_spec.rb
new file mode 100644
index 00000000000..821a2156539
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/version_spec.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::Version, feature_category: :database do
+ let(:test_versions) do
+ [
+ 4,
+ 5,
+ described_class.new(6, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ 7,
+ described_class.new(8, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ described_class.new(9, Gitlab::VersionInfo.parse_from_milestone('10.4'), :regular),
+ described_class.new(10, Gitlab::VersionInfo.parse_from_milestone('10.3'), :post),
+ described_class.new(11, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular)
+ ]
+ end
+
+ describe "#<=>" do
+ it 'sorts by existence of milestone, then by milestone, then by type, then by timestamp when sorted by version' do
+ expect(test_versions.sort.map(&:to_i)).to eq [4, 5, 7, 6, 8, 11, 10, 9]
+ end
+ end
+
+ describe 'initialize' do
+ context 'when the type is :post or :regular' do
+ it 'does not raise an error' do
+ expect { described_class.new(4, 4, :regular) }.not_to raise_error
+ expect { described_class.new(4, 4, :post) }.not_to raise_error
+ end
+ end
+
+ context 'when the type is anything else' do
+ it 'does not raise an error' do
+ expect { described_class.new(4, 4, 'foo') }.to raise_error("#{described_class}::InvalidTypeError".constantize)
+ end
+ end
+ end
+
+ describe 'eql?' do
+ where(:version1, :version2, :expected_equality) do
+ [
+ [
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ true
+ ],
+ [
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.4'), :regular),
+ false
+ ],
+ [
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :post),
+ false
+ ],
+ [
+ described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ described_class.new(5, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular),
+ false
+ ]
+ ]
+ end
+
+ with_them do
+ it 'correctly evaluates deep equality' do
+ expect(version1.eql?(version2)).to eq(expected_equality)
+ end
+
+ it 'correctly evaluates deep equality using ==' do
+ expect(version1 == version2).to eq(expected_equality)
+ end
+ end
+ end
+
+ describe 'type' do
+ subject { described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), migration_type) }
+
+ context 'when the migration is regular' do
+ let(:migration_type) { :regular }
+
+ it 'correctly identifies the migration type' do
+ expect(subject.type).to eq(:regular)
+ expect(subject.regular?).to eq(true)
+ expect(subject.post_deployment?).to eq(false)
+ end
+ end
+
+ context 'when the migration is post_deployment' do
+ let(:migration_type) { :post }
+
+ it 'correctly identifies the migration type' do
+ expect(subject.type).to eq(:post)
+ expect(subject.regular?).to eq(false)
+ expect(subject.post_deployment?).to eq(true)
+ end
+ end
+ end
+
+ describe 'to_s' do
+ subject { described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular) }
+
+ it 'returns the given timestamp value as a string' do
+ expect(subject.to_s).to eql('4')
+ end
+ end
+
+ describe 'hash' do
+ subject { described_class.new(4, Gitlab::VersionInfo.parse_from_milestone('10.3'), :regular) }
+
+ let(:expected_hash) { subject.hash }
+
+ it 'deterministically returns a hash of the timestamp, milestone, and type value' do
+ 3.times do
+ expect(subject.hash).to eq(expected_hash)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb
index 3652bee5e44..6d1d6a7c4e0 100644
--- a/spec/requests/api/composer_packages_spec.rb
+++ b/spec/requests/api/composer_packages_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token_for_project, project: project) }
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
+ let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
let(:snowplow_gitlab_standard_context) do
{ project: project, namespace: project.namespace, user: user, property: 'i_package_composer_user' }
@@ -28,7 +29,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
subject { get api(url), headers: headers }
context 'with valid project' do
- let!(:package) { create(:composer_package, :with_metadatum, project: project) }
+ let_it_be(:package) { create(:composer_package, :with_metadatum, project: project) }
context 'with a public group' do
before do
@@ -36,59 +37,62 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
end
context 'with basic auth' do
- where(:project_visibility_level, :user_role, :member, :user_token, :include_package) do
- 'PUBLIC' | :developer | true | true | :include_package
- 'PUBLIC' | :developer | false | true | :include_package
- 'PUBLIC' | :guest | true | true | :include_package
- 'PUBLIC' | :guest | false | true | :include_package
- 'PUBLIC' | :anonymous | false | true | :include_package
- 'PRIVATE' | :developer | true | true | :include_package
- 'PRIVATE' | :developer | false | true | :does_not_include_package
- 'PRIVATE' | :guest | true | true | :does_not_include_package
- 'PRIVATE' | :guest | false | true | :does_not_include_package
- 'PRIVATE' | :anonymous | false | true | :does_not_include_package
- 'PRIVATE' | :guest | false | false | :does_not_include_package
- 'PRIVATE' | :guest | true | false | :does_not_include_package
- 'PRIVATE' | :developer | false | false | :does_not_include_package
- 'PRIVATE' | :developer | true | false | :does_not_include_package
- 'PUBLIC' | :developer | true | false | :include_package
- 'PUBLIC' | :guest | true | false | :include_package
- 'PUBLIC' | :developer | false | false | :include_package
- 'PUBLIC' | :guest | false | false | :include_package
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :package_returned) do
+ 'PUBLIC' | :developer | :user | true | true
+ 'PUBLIC' | :developer | :user | false | true # Anonymous User - fallback
+ 'PUBLIC' | :developer | :job | true | true
+ 'PUBLIC' | :guest | :user | true | true
+ 'PUBLIC' | :guest | :user | false | true # Anonymous User - fallback
+ 'PUBLIC' | :guest | :job | true | true
+ 'PUBLIC' | nil | :user | true | true
+ 'PUBLIC' | nil | :user | false | true # Anonymous User - fallback
+ 'PUBLIC' | nil | :job | true | true
+ 'PUBLIC' | nil | nil | nil | true # Anonymous User
+ 'PRIVATE' | :developer | :user | true | true
+ 'PRIVATE' | :developer | :user | false | false # Anonymous User - fallback
+ 'PRIVATE' | :developer | :job | true | true
+ 'PRIVATE' | :guest | :user | true | false
+ 'PRIVATE' | :guest | :user | false | false # Anonymous User - fallback
+ 'PRIVATE' | :guest | :job | true | false
+ 'PRIVATE' | nil | :user | true | false
+ 'PRIVATE' | nil | :user | false | false # Anonymous User - fallback
+ 'PRIVATE' | nil | :job | true | false
+ 'PRIVATE' | nil | nil | nil | false # Anonymous User
end
with_them do
- include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token], :basic do
- it_behaves_like 'Composer package index', params[:user_role], :success, params[:member], params[:include_package]
+ include_context 'Composer api project access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like 'Composer package index', member_role: params[:member_role], expected_status: :success, package_returned: params[:package_returned]
end
end
end
- context 'with private token header auth' do
- where(:project_visibility_level, :user_role, :member, :user_token, :expected_status, :include_package) do
- 'PUBLIC' | :developer | true | true | :success | :include_package
- 'PUBLIC' | :developer | false | true | :success | :include_package
- 'PUBLIC' | :guest | true | true | :success | :include_package
- 'PUBLIC' | :guest | false | true | :success | :include_package
- 'PUBLIC' | :anonymous | false | true | :success | :include_package
- 'PRIVATE' | :developer | true | true | :success | :include_package
- 'PRIVATE' | :developer | false | true | :success | :does_not_include_package
- 'PRIVATE' | :guest | true | true | :success | :does_not_include_package
- 'PRIVATE' | :guest | false | true | :success | :does_not_include_package
- 'PRIVATE' | :anonymous | false | true | :success | :does_not_include_package
- 'PRIVATE' | :guest | false | false | :unauthorized | nil
- 'PRIVATE' | :guest | true | false | :unauthorized | nil
- 'PRIVATE' | :developer | false | false | :unauthorized | nil
- 'PRIVATE' | :developer | true | false | :unauthorized | nil
- 'PUBLIC' | :developer | true | false | :unauthorized | nil
- 'PUBLIC' | :guest | true | false | :unauthorized | nil
- 'PUBLIC' | :developer | false | false | :unauthorized | nil
- 'PUBLIC' | :guest | false | false | :unauthorized | nil
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :expected_status, :package_returned) do
+ :PUBLIC | :developer | :user | true | :success | true
+ :PUBLIC | :developer | :user | false | :unauthorized | false
+ :PUBLIC | :developer | :job | true | :success | true # Anonymous User - fallback
+ :PUBLIC | :guest | :user | true | :success | true
+ :PUBLIC | :guest | :user | false | :unauthorized | false
+ :PUBLIC | :guest | :job | true | :success | true # Anonymous User - fallback
+ :PUBLIC | nil | :user | true | :success | true
+ :PUBLIC | nil | :user | false | :unauthorized | false
+ :PUBLIC | nil | :job | true | :success | true # Anonymous User - fallback
+ :PUBLIC | nil | nil | nil | :success | true # Anonymous User
+ :PRIVATE | :developer | :user | true | :success | true
+ :PRIVATE | :developer | :user | false | :unauthorized | false
+ :PRIVATE | :developer | :job | true | :success | false # Anonymous User - fallback
+ :PRIVATE | :guest | :user | true | :success | false
+ :PRIVATE | :guest | :user | false | :unauthorized | false
+ :PRIVATE | :guest | :job | true | :success | false # Anonymous User - fallback
+ :PRIVATE | nil | :user | true | :success | false
+ :PRIVATE | nil | :user | false | :unauthorized | false
+ :PRIVATE | nil | nil | nil | :success | false # Anonymous User
end
with_them do
- include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token], :token do
- it_behaves_like 'Composer package index', params[:user_role], params[:expected_status], params[:member], params[:include_package]
+ include_context 'Composer api project access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like 'Composer package index', member_role: params[:member_role], expected_status: params[:expected_status], package_returned: params[:package_returned]
end
end
end
@@ -101,33 +105,44 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
it_behaves_like 'Composer access with deploy tokens'
- context 'with access to the api' do
- where(:project_visibility_level, :user_role, :member, :user_token, :include_package) do
- 'PRIVATE' | :developer | true | true | :include_package
- 'PRIVATE' | :guest | true | true | :does_not_include_package
+ context 'with basic auth' do
+ where(:member_role, :token_type, :valid_token, :shared_examples_name, :expected_status, :package_returned) do
+ :developer | :user | true | 'Composer package index' | :success | true
+ :developer | :user | false | 'process Composer api request' | :unauthorized | false
+ :developer | :job | true | 'Composer package index' | :success | true
+ :guest | :user | true | 'Composer package index' | :success | false
+ :guest | :user | false | 'process Composer api request' | :unauthorized | false
+ :guest | :job | true | 'Composer package index' | :success | false
+ nil | :user | true | 'Composer package index' | :not_found | false
+ nil | :user | false | 'process Composer api request' | :unauthorized | false
+ nil | :job | true | 'Composer package index' | :not_found | false
+ nil | nil | nil | 'process Composer api request' | :unauthorized | false # Anonymous User
end
with_them do
- include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like 'Composer package index', params[:user_role], :success, params[:member], params[:include_package]
+ include_context 'Composer api project access', auth_method: :basic, project_visibility_level: :PRIVATE, token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status], package_returned: params[:package_returned]
end
end
end
- context 'without access to the api' do
- where(:project_visibility_level, :user_role, :member, :user_token) do
- 'PRIVATE' | :developer | true | false
- 'PRIVATE' | :developer | false | true
- 'PRIVATE' | :developer | false | false
- 'PRIVATE' | :guest | true | false
- 'PRIVATE' | :guest | false | true
- 'PRIVATE' | :guest | false | false
- 'PRIVATE' | :anonymous | false | true
+ context 'with token auth' do
+ where(:member_role, :token_type, :valid_token, :shared_examples_name, :expected_status, :package_returned) do
+ :developer | :user | true | 'Composer package index' | :success | true
+ :developer | :user | false | 'process Composer api request' | :unauthorized | false
+ :developer | :job | true | 'process Composer api request' | :unauthorized | false
+ :guest | :user | true | 'Composer package index' | :success | false
+ :guest | :user | false | 'process Composer api request' | :unauthorized | false
+ :guest | :job | true | 'process Composer api request' | :unauthorized | false
+ nil | :user | true | 'Composer package index' | :not_found | false
+ nil | :user | false | 'Composer package index' | :unauthorized | false
+ nil | :job | true | 'process Composer api request' | :unauthorized | false
+ nil | nil | nil | 'process Composer api request' | :unauthorized | false # Anonymous User
end
with_them do
- include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like 'process Composer api request', params[:user_role], :not_found, params[:member]
+ include_context 'Composer api project access', auth_method: :token, project_visibility_level: :PRIVATE, token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status], package_returned: params[:package_returned]
end
end
end
@@ -145,30 +160,65 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
subject { get api(url), headers: headers }
context 'with valid project' do
- where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'Composer provider index' | :success
- 'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'Composer provider index' | :success
- 'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | true | true | 'Composer provider index' | :success
- 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | false | true | 'Composer provider index' | :success
- 'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'Composer provider index' | :success
- 'PRIVATE' | :developer | true | true | 'Composer provider index' | :success
- 'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | true | true | 'Composer empty provider index' | :success
- 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found
+ context 'with basic auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | :developer | :user | false | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | :developer | :job | true | 'Composer provider index' | :success
+ 'PUBLIC' | :guest | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | :guest | :user | false | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :job | true | 'Composer provider index' | :success
+ 'PUBLIC' | nil | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | nil | :user | false | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :job | true | 'Composer provider index' | :success
+ 'PUBLIC' | nil | nil | nil | 'Composer provider index' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer provider index' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'Composer provider index' | :success
+ 'PRIVATE' | :guest | :user | true | 'Composer empty provider index' | :success
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'Composer empty provider index' | :success
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
+ end
end
- with_them do
- include_context 'Composer api group access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :developer | :job | true | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :guest | :job | true | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :user | true | 'Composer provider index' | :success
+ 'PUBLIC' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | nil | :job | true | 'Composer provider index' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | nil | nil | 'Composer provider index' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer provider index' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :user | true | 'Composer empty provider index' | :success
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
end
end
@@ -186,7 +236,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
subject { get api(url), headers: headers }
context 'with no packages' do
- include_context 'Composer user type', :developer, true do
+ include_context 'Composer user type', member_role: :developer do
it_behaves_like 'returning response status', :not_found
end
end
@@ -194,40 +244,73 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'with valid project' do
let!(:package) { create(:composer_package, :with_metadatum, name: package_name, project: project) }
- where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'Composer package api request' | :success
- 'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'Composer package api request' | :success
- 'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | true | true | 'Composer package api request' | :success
- 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | false | true | 'Composer package api request' | :success
- 'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'Composer package api request' | :success
- 'PRIVATE' | :developer | true | true | 'Composer package api request' | :success
- 'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | true | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found
+ context 'with basic auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :developer | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :developer | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | nil | nil | 'Composer package api request' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package api request' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'Composer package api request' | :success
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
+ end
end
- with_them do
- include_context 'Composer api group access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :developer | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :guest | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | nil | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | nil | nil | 'Composer package api request' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package api request' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
end
end
context 'without a sha' do
let(:sha) { '' }
- include_context 'Composer api group access', 'PRIVATE', :developer, true do
- include_context 'Composer user type', :developer, true do
- it_behaves_like 'process Composer api request', :developer, :not_found, true
- end
+ include_context 'Composer api group access', project_visibility_level: 'PRIVATE', token_type: :user, auth_method: :token do
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :not_found
end
end
@@ -244,7 +327,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
subject { get api(url), headers: headers }
context 'with no packages' do
- include_context 'Composer user type', :developer, true do
+ include_context 'Composer user type', member_role: :developer do
it_behaves_like 'returning response status', :not_found
end
end
@@ -252,30 +335,65 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'with valid project' do
let!(:package) { create(:composer_package, :with_metadatum, name: package_name, project: project) }
- where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'Composer package api request' | :success
- 'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'Composer package api request' | :success
- 'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | true | true | 'Composer package api request' | :success
- 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | false | true | 'Composer package api request' | :success
- 'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'Composer package api request' | :success
- 'PRIVATE' | :developer | true | true | 'Composer package api request' | :success
- 'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | true | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found
+ context 'with basic auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :developer | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :developer | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | false | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :job | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | nil | nil | 'Composer package api request' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package api request' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'Composer package api request' | :success
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
+ end
end
- with_them do
- include_context 'Composer api group access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :developer | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :guest | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :user | true | 'Composer package api request' | :success
+ 'PUBLIC' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | nil | :job | true | 'Composer package api request' | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | nil | nil | 'Composer package api request' | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package api request' | :success
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api group access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
end
end
@@ -297,30 +415,65 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
shared_examples 'composer package publish' do
context 'with valid project' do
- where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'Composer package creation' | :created
- 'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'process Composer api request' | :forbidden
- 'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | true | true | 'process Composer api request' | :forbidden
- 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :guest | false | true | 'process Composer api request' | :forbidden
- 'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'Composer package creation' | :created
- 'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | true | true | 'process Composer api request' | :forbidden
- 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
- 'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :unauthorized
+ context 'with basic auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package creation' | :created
+ 'PUBLIC' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :developer | :job | true | 'Composer package creation' | :created
+ 'PUBLIC' | :guest | :user | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :guest | :job | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | nil | :user | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | nil | :job | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package creation' | :created
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'Composer package creation' | :created
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :forbidden
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :forbidden
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api project access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
+ end
end
- with_them do
- include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | 'Composer package creation' | :created
+ 'PUBLIC' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :developer | :job | true | 'process Composer api request' | :unauthorized # Anonymous User - fallback
+ 'PUBLIC' | :guest | :user | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | :guest | :job | true | 'process Composer api request' | :unauthorized # Anonymous User - fallback
+ 'PUBLIC' | nil | :user | true | 'process Composer api request' | :forbidden
+ 'PUBLIC' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PUBLIC' | nil | :job | true | 'process Composer api request' | :unauthorized # Anonymous User - fallback
+ 'PUBLIC' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ 'PRIVATE' | :developer | :user | true | 'Composer package creation' | :created
+ 'PRIVATE' | :developer | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :developer | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :user | true | 'process Composer api request' | :forbidden
+ 'PRIVATE' | :guest | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | :guest | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :user | true | 'process Composer api request' | :not_found
+ 'PRIVATE' | nil | :user | false | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | :job | true | 'process Composer api request' | :unauthorized
+ 'PRIVATE' | nil | nil | nil | 'process Composer api request' | :unauthorized # Anonymous User
+ end
+
+ with_them do
+ include_context 'Composer api project access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like params[:shared_examples_name], member_role: params[:member_role], expected_status: params[:expected_status]
+ end
end
end
@@ -331,7 +484,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
end
context 'with existing package' do
- include_context 'Composer api project access', 'PRIVATE', :developer, true, true
+ include_context 'Composer api project access', auth_method: :token, project_visibility_level: 'PRIVATE', token_type: :user
let_it_be_with_reload(:existing_package) { create(:composer_package, name: package_name, version: '1.2.99', project: project) }
@@ -362,7 +515,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'with no tag or branch params' do
let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process Composer api request', :developer, :bad_request
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :bad_request
end
context 'with a tag' do
@@ -376,7 +529,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
let(:params) { { tag: 'non-existing-tag' } }
let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process Composer api request', :developer, :not_found
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :not_found
end
end
@@ -391,7 +544,7 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
let(:params) { { branch: 'non-existing-branch' } }
let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process Composer api request', :developer, :not_found
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :not_found
end
end
@@ -407,19 +560,19 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'with a missing composer.json file' do
let(:files) { { 'some_other_file' => '' } }
- it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :unprocessable_entity
end
context 'with an empty composer.json file' do
let(:files) { { 'composer.json' => '' } }
- it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :unprocessable_entity
end
context 'with a malformed composer.json file' do
let(:files) { { 'composer.json' => 'not_valid_JSON' } }
- it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :unprocessable_entity
end
end
end
@@ -446,10 +599,10 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'anonymous' do
let(:headers) { {} }
- it_behaves_like 'process Composer api request', :anonymous, :unauthorized
+ it_behaves_like 'process Composer api request', expected_status: :unauthorized
end
- it_behaves_like 'process Composer api request', :developer, :not_found
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :not_found
end
context 'when the package name does not match the sha' do
@@ -460,60 +613,116 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
context 'anonymous' do
let(:headers) { {} }
- it_behaves_like 'process Composer api request', :anonymous, :unauthorized
+ it_behaves_like 'process Composer api request', expected_status: :unauthorized
end
- it_behaves_like 'process Composer api request', :developer, :not_found
+ it_behaves_like 'process Composer api request', member_role: :developer, expected_status: :not_found
end
context 'with a match package name and sha' do
let(:branch) { project.repository.find_branch('master') }
let(:sha) { branch.target }
- where(:project_visibility_level, :user_role, :member, :user_token, :expected_status) do
- 'PUBLIC' | :developer | true | true | :success
- 'PUBLIC' | :developer | true | false | :success
- 'PUBLIC' | :developer | false | true | :success
- 'PUBLIC' | :developer | false | false | :success
- 'PUBLIC' | :guest | true | true | :success
- 'PUBLIC' | :guest | true | false | :success
- 'PUBLIC' | :guest | false | true | :success
- 'PUBLIC' | :guest | false | false | :success
- 'PUBLIC' | :anonymous | false | true | :success
- 'PRIVATE' | :developer | true | true | :success
- 'PRIVATE' | :developer | true | false | :unauthorized
- 'PRIVATE' | :developer | false | true | :not_found
- 'PRIVATE' | :developer | false | false | :unauthorized
- 'PRIVATE' | :guest | true | true | :forbidden
- 'PRIVATE' | :guest | true | false | :unauthorized
- 'PRIVATE' | :guest | false | true | :not_found
- 'PRIVATE' | :guest | false | false | :unauthorized
- 'PRIVATE' | :anonymous | false | true | :unauthorized
- end
+ context 'with basic auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | :success
+ 'PUBLIC' | :developer | :user | false | :success # Anonymous User - fallback
+ 'PUBLIC' | :developer | :job | true | :success
+ 'PUBLIC' | :guest | :user | true | :success
+ 'PUBLIC' | :guest | :user | false | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :job | true | :success
+ 'PUBLIC' | nil | :user | true | :success
+ 'PUBLIC' | nil | :user | false | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :job | true | :success
+ 'PUBLIC' | nil | nil | nil | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | :success
+ 'PRIVATE' | :developer | :user | false | :unauthorized
+ 'PRIVATE' | :developer | :job | true | :success
+ 'PRIVATE' | :guest | :user | true | :forbidden
+ 'PRIVATE' | :guest | :user | false | :unauthorized
+ 'PRIVATE' | :guest | :job | true | :forbidden
+ 'PRIVATE' | nil | :user | true | :not_found
+ 'PRIVATE' | nil | :user | false | :unauthorized
+ 'PRIVATE' | nil | :job | true | :not_found
+ 'PRIVATE' | nil | nil | nil | :unauthorized # Anonymous User
+ end
- with_them do
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
- let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ with_them do
+ include_context 'Composer api project access', auth_method: :basic, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like 'process Composer api request', member_role: params[:member_role], expected_status: params[:expected_status] do
+ if params[:expected_status] == :success
+ let(:snowplow_gitlab_standard_context) do
+ if valid_token && (member_role || project_visibility_level == 'PUBLIC')
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user', user: user }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ end
+ end
+
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
+ else
+ it_behaves_like 'not a package tracking event'
+ end
+ end
- before do
- project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
+ context 'with another project' do
+ include Ci::JobTokenScopeHelpers
+
+ let_it_be(:project_two) { create(:project, group: group) }
+ let_it_be(:job) { create(:ci_build, :running, user: user, project: project_two) }
+
+ before do
+ add_inbound_accessible_linkage(project_two, project)
+ end
+
+ it_behaves_like 'process Composer api request', member_role: params[:member_role], expected_status: params[:expected_status]
+ end
+ end
end
+ end
- it_behaves_like 'process Composer api request', params[:user_role], params[:expected_status], params[:member]
+ context 'with token auth' do
+ where(:project_visibility_level, :member_role, :token_type, :valid_token, :expected_status) do
+ 'PUBLIC' | :developer | :user | true | :success
+ 'PUBLIC' | :developer | :user | false | :unauthorized
+ 'PUBLIC' | :developer | :job | true | :success # Anonymous User - fallback
+ 'PUBLIC' | :guest | :user | true | :success
+ 'PUBLIC' | :guest | :user | false | :unauthorized
+ 'PUBLIC' | :guest | :job | true | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | :user | true | :success
+ 'PUBLIC' | nil | :user | false | :unauthorized
+ 'PUBLIC' | nil | :job | true | :success # Anonymous User - fallback
+ 'PUBLIC' | nil | nil | nil | :success # Anonymous User
+ 'PRIVATE' | :developer | :user | true | :success
+ 'PRIVATE' | :developer | :user | false | :unauthorized
+ 'PRIVATE' | :developer | :job | true | :unauthorized
+ 'PRIVATE' | :guest | :user | true | :forbidden
+ 'PRIVATE' | :guest | :user | false | :unauthorized
+ 'PRIVATE' | :guest | :job | true | :unauthorized
+ 'PRIVATE' | nil | :user | true | :not_found
+ 'PRIVATE' | nil | :user | false | :unauthorized
+ 'PRIVATE' | nil | :job | true | :unauthorized
+ 'PRIVATE' | nil | nil | nil | :unauthorized # Anonymous User
+ end
- include_context 'Composer user type', params[:user_role], params[:member] do
- if params[:expected_status] == :success
- let(:snowplow_gitlab_standard_context) do
- if user_role == :anonymous || (project_visibility_level == 'PUBLIC' && user_token == false)
- { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ with_them do
+ include_context 'Composer api project access', auth_method: :token, project_visibility_level: params[:project_visibility_level], token_type: params[:token_type], valid_token: params[:valid_token] do
+ it_behaves_like 'process Composer api request', member_role: params[:member_role], expected_status: params[:expected_status] do
+ if params[:expected_status] == :success
+ let(:snowplow_gitlab_standard_context) do
+ # Job tokens sent over token auth means current_user is nil
+ if valid_token && token_type != :job && (member_role || project_visibility_level == 'PUBLIC')
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user', user: user }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ end
+ end
+
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
else
- { project: project, namespace: project.namespace, property: 'i_package_composer_user', user: user }
+ it_behaves_like 'not a package tracking event'
end
end
-
- it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
- else
- it_behaves_like 'not a package tracking event'
end
end
end
diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
index ef159e41d3d..8d980a9e8ea 100644
--- a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
@@ -36,8 +36,6 @@ RSpec.describe 'Destroying a container repository', feature_category: :container
it 'marks the container repository as delete_scheduled' do
expect(::Packages::CreateEventService)
.to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
- expect(DeleteContainerRepositoryWorker)
- .not_to receive(:perform_async)
subject
@@ -50,9 +48,6 @@ RSpec.describe 'Destroying a container repository', feature_category: :container
shared_examples 'denying the mutation request' do
it 'does not destroy the container repository' do
- expect(DeleteContainerRepositoryWorker)
- .not_to receive(:perform_async).with(user.id, container_repository.id)
-
subject
expect(mutation_response).to be_nil
diff --git a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
index f30b7d0ea73..5040ee39712 100644
--- a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
@@ -5,15 +5,17 @@ require 'spec_helper'
RSpec.describe "Add linked items to a work item", feature_category: :portfolio_management do
include GraphqlHelpers
- let_it_be(:project) { create(:project, :private) }
- let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
- let_it_be(:work_item) { create(:work_item, project: project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :private, group: group) }
+ let_it_be(:reporter) { create(:user).tap { |user| group.add_reporter(user) } }
+ let_it_be(:project_work_item) { create(:work_item, project: project) }
let_it_be(:related1) { create(:work_item, project: project) }
let_it_be(:related2) { create(:work_item, project: project) }
let(:mutation_response) { graphql_mutation_response(:work_item_add_linked_items) }
let(:mutation) { graphql_mutation(:workItemAddLinkedItems, input, fields) }
+ let(:work_item) { project_work_item }
let(:ids_to_link) { [related1.to_global_id.to_s, related2.to_global_id.to_s] }
let(:input) { { 'id' => work_item.to_global_id.to_s, 'workItemsIds' => ids_to_link } }
@@ -70,6 +72,18 @@ RSpec.describe "Add linked items to a work item", feature_category: :portfolio_m
)
end
+ context 'when work item is created at the group level' do
+ let(:work_item) { create(:work_item, :group_level, namespace: group) }
+
+ it 'links the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { WorkItems::RelatedWorkItemLink.count }.by(2)
+
+ expect(mutation_response['message']).to eq("Successfully linked ID(s): #{related1.id} and #{related2.id}.")
+ end
+ end
+
context 'when linking a work item fails' do
let_it_be(:private_project) { create(:project, :private) }
let_it_be(:related2) { create(:work_item, project: private_project) }
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index a2e1a1c1721..f51b94bb78e 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectContainerRepositories, feature_category: :package_registry do
+RSpec.describe API::ProjectContainerRepositories, feature_category: :container_registry do
include ExclusiveLeaseHelpers
let_it_be(:project) { create(:project, :private) }
@@ -142,7 +142,6 @@ RSpec.describe API::ProjectContainerRepositories, feature_category: :package_reg
let(:api_user) { maintainer }
it 'marks the repository as delete_scheduled' do
- expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
expect { subject }.to change { root_repository.reload.status }.from(nil).to('delete_scheduled')
expect(response).to have_gitlab_http_status(:accepted)
diff --git a/spec/support/shared_examples/ref_extraction_shared_examples.rb b/spec/support/shared_examples/ref_extraction_shared_examples.rb
new file mode 100644
index 00000000000..f51c3a16406
--- /dev/null
+++ b/spec/support/shared_examples/ref_extraction_shared_examples.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'extracts ref vars' do
+ describe '#extract!' do
+ context 'when ref contains %20' do
+ let(:ref) { 'foo%20bar' }
+
+ it 'is not converted to a space in @id' do
+ container.repository.add_branch(owner, 'foo%20bar', 'master')
+
+ ref_extractor.extract!
+
+ expect(ref_extractor.id).to start_with('foo%20bar/')
+ end
+ end
+
+ context 'when ref contains trailing space' do
+ let(:ref) { 'master ' }
+
+ it 'strips surrounding space' do
+ ref_extractor.extract!
+
+ expect(ref_extractor.ref).to eq('master')
+ end
+ end
+
+ context 'when ref contains leading space' do
+ let(:ref) { ' master ' }
+
+ it 'strips surrounding space' do
+ ref_extractor.extract!
+
+ expect(ref_extractor.ref).to eq('master')
+ end
+ end
+
+ context 'when path contains space' do
+ let(:ref) { '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' }
+ let(:path) { 'with space' }
+
+ it 'is not converted to %20 in @path' do
+ ref_extractor.extract!
+
+ expect(ref_extractor.path).to eq(path)
+ end
+ end
+
+ context 'when override_id is given' do
+ let(:ref_extractor) do
+ described_class.new(container, params, override_id: '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e')
+ end
+
+ it 'uses override_id' do
+ ref_extractor.extract!
+
+ expect(ref_extractor.id).to eq('38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e')
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'extracts ref method' do
+ describe '#extract_ref' do
+ it 'returns an empty pair when no repository_container is set' do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:repository_container).and_return(nil)
+ end
+ expect(ref_extractor.extract_ref('master/CHANGELOG')).to eq(['', ''])
+ end
+
+ context 'without a path' do
+ it 'extracts a valid branch' do
+ expect(ref_extractor.extract_ref('master')).to eq(['master', ''])
+ end
+
+ it 'extracts a valid tag' do
+ expect(ref_extractor.extract_ref('v2.0.0')).to eq(['v2.0.0', ''])
+ end
+
+ it 'extracts a valid commit ref' do
+ expect(ref_extractor.extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062')).to eq(
+ ['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
+ )
+ end
+
+ it 'falls back to a primitive split for an invalid ref' do
+ expect(ref_extractor.extract_ref('stable')).to eq(['stable', ''])
+ end
+
+ it 'does not fetch ref names when there is no slash' do
+ expect(ref_extractor).not_to receive(:ref_names)
+
+ ref_extractor.extract_ref('master')
+ end
+
+ it 'fetches ref names when there is a slash' do
+ expect(ref_extractor).to receive(:ref_names).and_call_original
+
+ ref_extractor.extract_ref('release/app/v1.0.0')
+ end
+ end
+
+ context 'with a path' do
+ it 'extracts a valid branch' do
+ expect(ref_extractor.extract_ref('foo/bar/baz/CHANGELOG')).to eq(
+ ['foo/bar/baz', 'CHANGELOG'])
+ end
+
+ it 'extracts a valid tag' do
+ expect(ref_extractor.extract_ref('v2.0.0/CHANGELOG')).to eq(['v2.0.0', 'CHANGELOG'])
+ end
+
+ it 'extracts a valid commit SHA' do
+ expect(ref_extractor.extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG')).to eq(
+ %w[f4b14494ef6abf3d144c28e4af0c20143383e062 CHANGELOG]
+ )
+ end
+
+ it 'falls back to a primitive split for an invalid ref' do
+ expect(ref_extractor.extract_ref('stable/CHANGELOG')).to eq(%w[stable CHANGELOG])
+ end
+
+ it 'extracts the longest matching ref' do
+ expect(ref_extractor.extract_ref('release/app/v1.0.0/README.md')).to eq(
+ ['release/app/v1.0.0', 'README.md'])
+ end
+
+ context 'when the repository does not have ambiguous refs' do
+ before do
+ allow(container.repository).to receive(:has_ambiguous_refs?).and_return(false)
+ end
+
+ it 'does not fetch all ref names when the first path component is a ref' do
+ expect(ref_extractor).not_to receive(:ref_names)
+ expect(container.repository).to receive(:branch_names_include?).with('v1.0.0').and_return(false)
+ expect(container.repository).to receive(:tag_names_include?).with('v1.0.0').and_return(true)
+
+ expect(ref_extractor.extract_ref('v1.0.0/doc/README.md')).to eq(['v1.0.0', 'doc/README.md'])
+ end
+
+ it 'fetches all ref names when the first path component is not a ref' do
+ expect(ref_extractor).to receive(:ref_names).and_call_original
+ expect(container.repository).to receive(:branch_names_include?).with('release').and_return(false)
+ expect(container.repository).to receive(:tag_names_include?).with('release').and_return(false)
+
+ expect(ref_extractor.extract_ref('release/app/doc/README.md')).to eq(['release/app', 'doc/README.md'])
+ end
+ end
+
+ context 'when the repository has ambiguous refs' do
+ before do
+ allow(container.repository).to receive(:has_ambiguous_refs?).and_return(true)
+ end
+
+ it 'always fetches all ref names' do
+ expect(ref_extractor).to receive(:ref_names).and_call_original
+ expect(container.repository).not_to receive(:branch_names_include?)
+ expect(container.repository).not_to receive(:tag_names_include?)
+
+ expect(ref_extractor.extract_ref('v1.0.0/doc/README.md')).to eq(['v1.0.0', 'doc/README.md'])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
index 6a77de4266f..7e0efd05dd7 100644
--- a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
@@ -1,42 +1,45 @@
# frozen_string_literal: true
-RSpec.shared_context 'Composer user type' do |user_type, add_member|
+RSpec.shared_context 'Composer user type' do |member_role: nil|
before do
- group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
- project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
+ if member_role
+ group.send("add_#{member_role}", user)
+ project.send("add_#{member_role}", user)
+ end
end
end
-RSpec.shared_examples 'Composer package index with version' do |schema_path|
+RSpec.shared_examples 'Composer package index with version' do |schema_path, expected_status|
it 'returns the package index' do
subject
- expect(response).to have_gitlab_http_status(status)
+ expect(response).to have_gitlab_http_status(expected_status)
- if status == :success
+ if expected_status == :success
expect(response).to match_response_schema(schema_path)
expect(json_response).to eq presenter.root
end
end
end
-RSpec.shared_examples 'Composer package index' do |user_type, status, add_member, include_package|
- include_context 'Composer user type', user_type, add_member do
- let(:expected_packages) { include_package == :include_package ? [package] : [] }
- let(:presenter) { ::Packages::Composer::PackagesPresenter.new(group, expected_packages ) }
+RSpec.shared_examples 'Composer package index' do |member_role:, expected_status:, package_returned:|
+ include_context 'Composer user type', member_role: member_role do
+ let_it_be(:expected_packages) { package_returned ? [package] : [] }
+ let_it_be(:presenter) { ::Packages::Composer::PackagesPresenter.new(group, expected_packages ) }
- it_behaves_like 'Composer package index with version', 'public_api/v4/packages/composer/index'
+ it_behaves_like 'Composer package index with version', 'public_api/v4/packages/composer/index', expected_status
context 'with version 2' do
+ let_it_be(:presenter) { ::Packages::Composer::PackagesPresenter.new(group, expected_packages, true ) }
let(:headers) { super().merge('User-Agent' => 'Composer/2.0.9 (Darwin; 19.6.0; PHP 7.4.8; cURL 7.71.1)') }
- it_behaves_like 'Composer package index with version', 'public_api/v4/packages/composer/index_v2'
+ it_behaves_like 'Composer package index with version', 'public_api/v4/packages/composer/index_v2', expected_status
end
end
end
-RSpec.shared_examples 'Composer empty provider index' do |user_type, status, add_member = true|
- include_context 'Composer user type', user_type, add_member do
+RSpec.shared_examples 'Composer empty provider index' do |member_role:, expected_status:|
+ include_context 'Composer user type', member_role: member_role do
it 'returns the package index' do
subject
@@ -47,24 +50,24 @@ RSpec.shared_examples 'Composer empty provider index' do |user_type, status, add
end
end
-RSpec.shared_examples 'Composer provider index' do |user_type, status, add_member = true|
- include_context 'Composer user type', user_type, add_member do
+RSpec.shared_examples 'Composer provider index' do |member_role:, expected_status:|
+ include_context 'Composer user type', member_role: member_role do
it 'returns the package index' do
subject
- expect(response).to have_gitlab_http_status(status)
+ expect(response).to have_gitlab_http_status(expected_status)
expect(response).to match_response_schema('public_api/v4/packages/composer/provider')
expect(json_response['providers']).to include(package.name)
end
end
end
-RSpec.shared_examples 'Composer package api request' do |user_type, status, add_member = true|
- include_context 'Composer user type', user_type, add_member do
+RSpec.shared_examples 'Composer package api request' do |member_role:, expected_status:|
+ include_context 'Composer user type', member_role: member_role do
it 'returns the package index' do
subject
- expect(response).to have_gitlab_http_status(status)
+ expect(response).to have_gitlab_http_status(expected_status)
expect(response).to match_response_schema('public_api/v4/packages/composer/package')
expect(json_response['packages']).to include(package.name)
expect(json_response['packages'][package.name]).to include(package.version)
@@ -72,18 +75,13 @@ RSpec.shared_examples 'Composer package api request' do |user_type, status, add_
end
end
-RSpec.shared_examples 'Composer package creation' do |user_type, status, add_member = true|
- context "for user type #{user_type}" do
- before do
- group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
- project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
- end
-
+RSpec.shared_examples 'Composer package creation' do |expected_status:, member_role: nil|
+ include_context 'Composer user type', member_role: member_role do
it 'creates package files' do
expect { subject }
.to change { project.packages.composer.count }.by(1)
- expect(response).to have_gitlab_http_status(status)
+ expect(response).to have_gitlab_http_status(expected_status)
end
it_behaves_like 'a package tracking event', described_class.name, 'push_package'
@@ -100,42 +98,38 @@ RSpec.shared_examples 'Composer package creation' do |user_type, status, add_mem
end
end
-RSpec.shared_examples 'process Composer api request' do |user_type, status, add_member = true|
- context "for user type #{user_type}" do
- before do
- group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
- project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
- end
-
- it_behaves_like 'returning response status', status
- it_behaves_like 'bumping the package last downloaded at field' if status == :success
+RSpec.shared_examples 'process Composer api request' do |expected_status:, member_role: nil, **extra|
+ include_context 'Composer user type', member_role: member_role do
+ it_behaves_like 'returning response status', expected_status
+ it_behaves_like 'bumping the package last downloaded at field' if expected_status == :success
end
end
-RSpec.shared_context 'Composer auth headers' do |user_role, user_token, auth_method = :token|
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
-
+RSpec.shared_context 'Composer auth headers' do |token_type:, valid_token:, auth_method: :token|
let(:headers) do
- if user_role == :anonymous
- {}
- elsif auth_method == :token
- { 'Private-Token' => token }
+ if token_type == :user
+ token = valid_token ? personal_access_token.token : 'wrong'
+ auth_method == :token ? { 'Private-Token' => token } : basic_auth_header(user.username, token)
+ elsif token_type == :job && valid_token
+ auth_method == :token ? { 'Job-Token' => job.token } : job_basic_auth_header(job)
else
- basic_auth_header(user.username, token)
+ {} # Anonymous user
end
end
end
-RSpec.shared_context 'Composer api project access' do |project_visibility_level, user_role, user_token, auth_method|
- include_context 'Composer auth headers', user_role, user_token, auth_method do
+RSpec.shared_context 'Composer api project access' do |auth_method:, project_visibility_level:, token_type:,
+ valid_token: true|
+ include_context 'Composer auth headers', auth_method: auth_method, token_type: token_type, valid_token: valid_token do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
end
end
end
-RSpec.shared_context 'Composer api group access' do |project_visibility_level, user_role, user_token|
- include_context 'Composer auth headers', user_role, user_token do
+RSpec.shared_context 'Composer api group access' do |auth_method:, project_visibility_level:, token_type:,
+ valid_token: true|
+ include_context 'Composer auth headers', auth_method: auth_method, token_type: token_type, valid_token: valid_token do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
@@ -148,13 +142,13 @@ RSpec.shared_examples 'rejects Composer access with unknown group id' do
let(:group) { double(id: non_existing_record_id) }
context 'as anonymous' do
- it_behaves_like 'process Composer api request', :anonymous, :not_found
+ it_behaves_like 'process Composer api request', expected_status: :unauthorized
end
context 'as authenticated user' do
subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process Composer api request', :anonymous, :not_found
+ it_behaves_like 'process Composer api request', expected_status: :not_found
end
end
end
@@ -164,13 +158,13 @@ RSpec.shared_examples 'rejects Composer access with unknown project id' do
let(:project) { double(id: non_existing_record_id) }
context 'as anonymous' do
- it_behaves_like 'process Composer api request', :anonymous, :unauthorized
+ it_behaves_like 'process Composer api request', expected_status: :unauthorized
end
context 'as authenticated user' do
subject { get api(url), params: params, headers: basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process Composer api request', :anonymous, :not_found
+ it_behaves_like 'process Composer api request', expected_status: :not_found
end
end
end
@@ -191,7 +185,7 @@ RSpec.shared_examples 'Composer access with deploy tokens' do
context 'invalid token' do
let(:headers) { basic_auth_header(deploy_token.username, 'bar') }
- it_behaves_like 'returning response status', :not_found
+ it_behaves_like 'returning response status', :unauthorized
end
end
end
diff --git a/spec/views/projects/merge_requests/edit.html.haml_spec.rb b/spec/views/projects/merge_requests/edit.html.haml_spec.rb
index bb8a4455775..5affe2dd9b4 100644
--- a/spec/views/projects/merge_requests/edit.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/edit.html.haml_spec.rb
@@ -46,65 +46,28 @@ RSpec.describe 'projects/merge_requests/edit.html.haml' do
end
end
- context 'with the visible_label_selection_on_metadata feature flag enabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: true)
- end
-
- context 'when a merge request without fork' do
- it_behaves_like 'merge request shows editable fields'
-
- it "shows editable fields" do
- unlink_project.execute
- closed_merge_request.reload
-
- render
+ context 'when a merge request without fork' do
+ it_behaves_like 'merge request shows editable fields'
- expect(rendered).not_to have_selector('#merge_request_target_branch', visible: false)
- expect(rendered).to have_selector('.js-issuable-form-label-selector')
- end
- end
-
- context 'when a merge request with an existing source project is closed' do
- it_behaves_like 'merge request shows editable fields'
+ it "shows editable fields" do
+ unlink_project.execute
+ closed_merge_request.reload
- it "shows editable fields" do
- render
+ render
- expect(rendered).to have_selector('#merge_request_target_branch', visible: false)
- expect(rendered).to have_selector('.js-issuable-form-label-selector')
- end
+ expect(rendered).not_to have_selector('#merge_request_target_branch', visible: false)
+ expect(rendered).to have_selector('.js-issuable-form-label-selector')
end
end
- context 'with the visible_label_selection_on_metadata feature flag disabled' do
- before do
- stub_feature_flags(visible_label_selection_on_metadata: false)
- end
-
- context 'when a merge request without fork' do
- it_behaves_like 'merge request shows editable fields'
-
- it "shows editable fields" do
- unlink_project.execute
- closed_merge_request.reload
-
- render
-
- expect(rendered).not_to have_selector('#merge_request_target_branch', visible: false)
- expect(rendered).not_to have_selector('.js-issuable-form-label-selector')
- end
- end
-
- context 'when a merge request with an existing source project is closed' do
- it_behaves_like 'merge request shows editable fields'
+ context 'when a merge request with an existing source project is closed' do
+ it_behaves_like 'merge request shows editable fields'
- it "shows editable fields" do
- render
+ it "shows editable fields" do
+ render
- expect(rendered).to have_selector('#merge_request_target_branch', visible: false)
- expect(rendered).not_to have_selector('.js-issuable-form-label-selector')
- end
+ expect(rendered).to have_selector('#merge_request_target_branch', visible: false)
+ expect(rendered).to have_selector('.js-issuable-form-label-selector')
end
end
end
diff --git a/spec/workers/delete_container_repository_worker_spec.rb b/spec/workers/delete_container_repository_worker_spec.rb
deleted file mode 100644
index 6260bea6949..00000000000
--- a/spec/workers/delete_container_repository_worker_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe DeleteContainerRepositoryWorker, feature_category: :container_registry do
- let_it_be(:repository) { create(:container_repository) }
-
- let(:project) { repository.project }
- let(:user) { project.first_owner }
- let(:worker) { described_class.new }
-
- describe '#perform' do
- subject(:perform) { worker.perform(user.id, repository.id) }
-
- it 'is a no op' do
- expect { subject }.to not_change { ContainerRepository.count }
- end
- end
-end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index c5964d3460f..453d64e94fa 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -198,7 +198,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Database::LockTablesWorker' => false,
'Database::BatchedBackgroundMigration::CiExecutionWorker' => 0,
'Database::BatchedBackgroundMigration::MainExecutionWorker' => 0,
- 'DeleteContainerRepositoryWorker' => 3,
'DeleteDiffFilesWorker' => 3,
'DeleteMergedBranchesWorker' => 3,
'DeleteStoredFilesWorker' => 3,