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
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/shared_examples/requests')
-rw-r--r--spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb119
-rw-r--r--spec/support/shared_examples/requests/api/discussions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb170
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb77
-rw-r--r--spec/support/shared_examples/requests/api/issues_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/members_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb4
12 files changed, 378 insertions, 43 deletions
diff --git a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
index 59e641e2af6..2170025824f 100644
--- a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
@@ -1,21 +1,98 @@
# frozen_string_literal: true
RSpec.shared_examples 'GET resource access tokens available' do
- let_it_be(:active_resource_access_token) { create(:personal_access_token, user: bot_user) }
+ let_it_be(:active_resource_access_token) { create(:personal_access_token, user: access_token_user) }
- it 'retrieves active resource access tokens' do
- subject
+ it 'retrieves active access tokens' do
+ get_access_tokens
- token_entities = assigns(:active_resource_access_tokens)
+ token_entities = assigns(:active_access_tokens)
expect(token_entities.length).to eq(1)
expect(token_entities[0][:name]).to eq(active_resource_access_token.name)
end
it 'lists all available scopes' do
- subject
+ get_access_tokens
expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes)
end
+
+ it 'returns for json response' do
+ get_access_tokens_json
+
+ expect(json_response.count).to eq(1)
+ end
+end
+
+RSpec.shared_examples 'GET access tokens are paginated and ordered' do
+ before do
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ context "when multiple access tokens are returned" do
+ before do
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ it "returns paginated response", :aggregate_failures do
+ get_access_tokens_with_page
+ expect(assigns(:active_access_tokens).count).to eq(1)
+
+ expect_header('X-Per-Page', '1')
+ expect_header('X-Page', '1')
+ expect_header('X-Next-Page', '2')
+ expect_header('X-Total', '2')
+ end
+ end
+
+ context "when access_token_pagination feature flag is disabled" do
+ before do
+ stub_feature_flags(access_token_pagination: false)
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ it "returns all tokens in system" do
+ get_access_tokens_with_page
+ expect(assigns(:active_access_tokens).count).to eq(2)
+ end
+ end
+
+ context "when tokens returned are ordered" do
+ let(:expires_1_day_from_now) { 1.day.from_now.to_date }
+ let(:expires_2_day_from_now) { 2.days.from_now.to_date }
+
+ before do
+ create(:personal_access_token, user: access_token_user, name: "Token1", expires_at: expires_1_day_from_now)
+ create(:personal_access_token, user: access_token_user, name: "Token2", expires_at: expires_2_day_from_now)
+ end
+
+ it "orders token list ascending on expires_at" do
+ get_access_tokens
+
+ first_token = assigns(:active_access_tokens).first.as_json
+ expect(first_token['name']).to eq("Token1")
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ end
+
+ it "orders tokens on id in case token has same expires_at" do
+ create(:personal_access_token, user: access_token_user, name: "Token3", expires_at: expires_1_day_from_now)
+
+ get_access_tokens
+
+ first_token = assigns(:active_access_tokens).first.as_json
+ expect(first_token['name']).to eq("Token3")
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+
+ second_token = assigns(:active_access_tokens).second.as_json
+ expect(second_token['name']).to eq("Token1")
+ expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ end
+ end
+
+ def expect_header(header_name, header_val)
+ expect(response.headers[header_name]).to eq(header_val)
+ end
end
RSpec.shared_examples 'POST resource access tokens available' do
@@ -83,7 +160,7 @@ end
RSpec.shared_examples 'PUT resource access tokens available' do
it 'calls delete user worker' do
- expect(DeleteUserWorker).to receive(:perform_async).with(user.id, bot_user.id, skip_authorization: true)
+ expect(DeleteUserWorker).to receive(:perform_async).with(user.id, access_token_user.id, skip_authorization: true)
subject
end
@@ -91,34 +168,12 @@ RSpec.shared_examples 'PUT resource access tokens available' do
it 'removes membership of bot user' do
subject
- expect(resource.reload.bots).not_to include(bot_user)
+ expect(resource.reload.bots).not_to include(access_token_user)
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'creates GhostUserMigration records to handle migration in a worker' do
- expect { subject }.to(
- change { Users::GhostUserMigration.count }.from(0).to(1))
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'converts issuables of the bot user to ghost user' do
- issue = create(:issue, author: bot_user)
-
- subject
-
- expect(issue.reload.author.ghost?).to be true
- end
-
- it 'deletes project bot user' do
- subject
-
- expect(User.exists?(bot_user.id)).to be_falsy
- end
+ it 'creates GhostUserMigration records to handle migration in a worker' do
+ expect { subject }.to(
+ change { Users::GhostUserMigration.count }.from(0).to(1))
end
context 'when unsuccessful' do
diff --git a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
index 32562aef8d2..f577e2ad323 100644
--- a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
@@ -15,7 +15,7 @@ RSpec.shared_examples 'with cross-reference system notes' do
new_merge_request.project.add_developer(user)
hidden_merge_request = create(:merge_request)
- new_cross_reference = "test commit #{hidden_merge_request.project.commit}"
+ new_cross_reference = "test commit #{hidden_merge_request.project.commit.to_reference(project)}"
new_note = create(:system_note, noteable: merge_request, project: project, note: new_cross_reference)
create(:system_note_metadata, note: new_note, action: 'cross_reference')
end
diff --git a/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
index 22805cf7aed..bb492425fd7 100644
--- a/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
@@ -1,13 +1,15 @@
# frozen_string_literal: true
# Requires `query(params)` , `user`, `issuable_data` and `issuable` bindings
-RSpec.shared_examples 'query with a search term' do
+RSpec.shared_examples 'query with a search term' do |fields = [:DESCRIPTION]|
+ let(:search_term) { 'bar' }
+ let(:ids) { graphql_dig_at(issuable_data, :node, :id) }
+
it 'returns only matching issuables' do
- filter_params = { search: 'bar', in: [:DESCRIPTION] }
+ filter_params = { search: search_term, in: fields }
graphql_query = query(filter_params)
post_graphql(graphql_query, current_user: user)
- ids = graphql_dig_at(issuable_data, :node, :id)
expect(ids).to contain_exactly(issuable.to_global_id.to_s)
end
diff --git a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
new file mode 100644
index 00000000000..5469fd80a4f
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
@@ -0,0 +1,170 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'graphql issue list request spec' do
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_query
+ end
+ end
+
+ describe 'filters' do
+ context 'when filtering by assignees' do
+ context 'when both assignee_username filters are provided' do
+ let(:issue_filter_params) do
+ { assignee_username: current_user.username, assignee_usernames: [current_user.username] }
+ end
+
+ it 'returns a mutually exclusive param error' do
+ post_query
+
+ expect_graphql_errors_to_include(
+ 'only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.'
+ )
+ end
+ end
+
+ context 'when filtering by a negated argument' do
+ let(:issue_filter_params) { { not: { assignee_usernames: [current_user.username] } } }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(expected_negated_assignee_issues.map { |i| i.to_gid.to_s })
+ end
+ end
+ end
+
+ context 'when filtering by unioned arguments' do
+ let(:issue_filter_params) { { or: { assignee_usernames: [current_user.username, another_user.username] } } }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(expected_unioned_assignee_issues.map { |i| i.to_gid.to_s })
+ end
+
+ context 'when argument is blank' do
+ let(:issue_filter_params) { { or: {} } }
+
+ it 'does not raise an error' do
+ post_query
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ it 'returns an error' do
+ stub_feature_flags(or_issuable_queries: false)
+
+ post_query
+
+ expect_graphql_errors_to_include(
+ "'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled."
+ )
+ end
+ end
+ end
+
+ context 'when filtering by a blank negated argument' do
+ let(:issue_filter_params) { { not: {} } }
+
+ it 'does not raise an error' do
+ post_query
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when filtering by reaction emoji' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:value, :issue_list) do
+ 'thumbsup' | lazy { voted_issues }
+ 'ANY' | lazy { voted_issues }
+ 'any' | lazy { voted_issues }
+ 'AnY' | lazy { voted_issues }
+ 'NONE' | lazy { no_award_issues }
+ 'thumbsdown' | lazy { [] }
+ end
+
+ with_them do
+ let(:issue_filter_params) { { my_reaction_emoji: value } }
+ let(:gids) { to_gid_list(issue_list) }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(gids)
+ end
+ end
+ end
+
+ context 'when filtering by search' do
+ it_behaves_like 'query with a search term', [:TITLE] do
+ let(:search_term) { search_title_term }
+ let(:issuable_data) { issues_data }
+ let(:user) { current_user }
+ let(:issuable) { title_search_issue }
+ let(:ids) { issue_ids }
+ end
+ end
+ end
+
+ describe 'sorting and pagination' do
+ context 'when sorting by severity' do
+ context 'when ascending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :SEVERITY_ASC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_severity_sorted_asc) }
+ end
+ end
+
+ context 'when descending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :SEVERITY_DESC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_severity_sorted_asc.reverse) }
+ end
+ end
+ end
+
+ context 'when sorting by priority' do
+ context 'when ascending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :PRIORITY_ASC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_priority_sorted_asc) }
+ end
+ end
+
+ context 'when descending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :PRIORITY_DESC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_priority_sorted_desc) }
+ end
+ end
+ end
+ end
+
+ it 'includes a web_url' do
+ post_query
+
+ expect(issues_data[0]['webUrl']).to be_present
+ end
+
+ it 'includes discussion locked' do
+ post_query
+
+ expect(issues_data).to contain_exactly(
+ *locked_discussion_issues.map { |i| hash_including('id' => i.to_gid.to_s, 'discussionLocked' => true) },
+ *unlocked_discussion_issues.map { |i| hash_including('id' => i.to_gid.to_s, 'discussionLocked' => false) }
+ )
+ end
+
+ def to_gid_list(instance_list)
+ instance_list.map { |instance| instance.to_gid.to_s }
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
index 1b609915f32..fb4aacfd7a9 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
@@ -114,7 +114,7 @@ RSpec.shared_examples 'group and project packages query' do
end
[:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC, :CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:sorted_packages) { packages_order_map.fetch(order) }
it_behaves_like 'sorted paginated query' do
diff --git a/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb
new file mode 100644
index 00000000000..54cc13fac94
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'perform graphql requests for AccessLevel type objects' do |access_level_kind|
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
+ let_it_be(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for("#{access_level_kind.to_s.classify}AccessLevel", max_depth: 2) }
+ let(:access_levels) { protected_branch.public_send("#{access_level_kind}_access_levels") }
+ let(:access_levels_count) { access_levels.size }
+ let(:maintainer_access_level) { access_levels.for_role.first }
+ let(:maintainer_access_level_data) { access_levels_data.first }
+ let(:access_levels_data) do
+ graphql_data_at('project',
+ 'branchRules',
+ 'nodes',
+ 0,
+ 'branchProtection',
+ "#{access_level_kind.to_s.camelize(:lower)}AccessLevels",
+ 'nodes')
+ end
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ #{access_level_kind.to_s.camelize(:lower)}AccessLevels {
+ nodes {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when request AccessLevel type objects as a guest user' do
+ let_it_be(:protected_branch) { create(:protected_branch, project: project) }
+
+ before do
+ project.add_guest(current_user)
+
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(access_levels_data).not_to be_present }
+ end
+
+ context 'when request AccessLevel type objects as a maintainer' do
+ let_it_be(:protected_branch) do
+ create(:protected_branch, "maintainers_can_#{access_level_kind}", project: project)
+ end
+
+ before do
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all the access level attributes' do
+ expect(maintainer_access_level_data['accessLevel']).to eq(maintainer_access_level.access_level)
+ expect(maintainer_access_level_data['accessLevelDescription']).to eq(maintainer_access_level.humanize)
+ expect(maintainer_access_level_data.dig('group', 'name')).to be_nil
+ expect(maintainer_access_level_data.dig('user', 'name')).to be_nil
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/issues_shared_examples.rb b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
index 991dbced02d..6328fb9cd8a 100644
--- a/spec/support/shared_examples/requests/api/issues_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
@@ -37,7 +37,7 @@ RSpec.shared_examples 'labeled issues with labels and label_name params' do
context 'negation' do
context 'array of labeled issues when all labels match with negation' do
- let(:params) { { labels: "#{label.title},#{label_b.title}", not: { labels: "#{label_c.title}" } } }
+ let(:params) { { labels: "#{label.title},#{label_b.title}", not: { labels: label_c.title.to_s } } }
it_behaves_like 'returns negated label names'
end
diff --git a/spec/support/shared_examples/requests/api/members_shared_examples.rb b/spec/support/shared_examples/requests/api/members_shared_examples.rb
index fce75c29971..9136f60eb93 100644
--- a/spec/support/shared_examples/requests/api/members_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/members_shared_examples.rb
@@ -11,3 +11,11 @@ RSpec.shared_examples 'a 404 response when source is private' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+RSpec.shared_examples 'a 403 response when user does not have rights to manage members of a specific access level' do
+ it 'returns 403' do
+ route
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb b/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
index fa111ca5811..d749479544d 100644
--- a/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
@@ -5,6 +5,7 @@ RSpec.shared_examples 'multiple and scoped issue boards' do |route_definition|
context 'multiple issue boards' do
before do
+ stub_feature_flags(apollo_boards: false)
board_parent.add_reporter(user)
stub_licensed_features(multiple_group_issue_boards: true)
end
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 8479493911b..11f9565989f 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -179,7 +179,8 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
end
- if parent_type == 'projects'
+ case parent_type
+ when 'projects'
context 'by a project owner' do
let(:user) { project.first_owner }
@@ -211,7 +212,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
end
end
- elsif parent_type == 'groups'
+ when 'groups'
context 'by a group owner' do
it 'sets the creation time on the new note' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
@@ -288,7 +289,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
it 'allows user in allow-list to create notes' do
- stub_application_setting(notes_create_limit_allowlist: ["#{user.username}"])
+ stub_application_setting(notes_create_limit_allowlist: [user.username.to_s])
subject
expect(response).to have_gitlab_http_status(:created)
diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
index 11e19d8d067..a9b44015206 100644
--- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
@@ -221,6 +221,27 @@ RSpec.shared_examples 'rejects PyPI access with unknown group id' do
end
end
+RSpec.shared_examples 'allow access for everyone with public package_registry_access_level' do
+ context 'with private project but public access to package registry' do
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ context 'as non-member user' do
+ let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'returning response status', :success
+ end
+
+ context 'as anonymous' do
+ let(:headers) { {} }
+
+ it_behaves_like 'returning response status', :success
+ end
+ end
+end
+
RSpec.shared_examples 'pypi simple API endpoint' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
index 544a0ed8fdd..bdff2c65691 100644
--- a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
@@ -63,9 +63,9 @@ RSpec.shared_examples 'redirects to version download' do |user_type, status, add
it 'returns a valid response' do
subject
- expect(request.url).to include 'module-1/system/download'
+ expect(request.url).to include "#{package.name}/download"
expect(response.headers).to include 'Location'
- expect(response.headers['Location']).to include 'module-1/system/1.0.1/download'
+ expect(response.headers['Location']).to include "#{package.name}/1.0.1/download"
end
end
end