debian-mirror-gitlab/spec/requests/api/groups_spec.rb

2448 lines
92 KiB
Ruby
Raw Permalink Normal View History

2019-12-26 22:10:19 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2023-03-04 22:38:38 +05:30
RSpec.describe API::Groups, feature_category: :subgroups do
2019-12-21 20:55:43 +05:30
include GroupAPIHelpers
2017-08-17 22:00:37 +05:30
include UploadHelpers
2022-10-11 01:57:18 +05:30
include WorkhorseHelpers
2023-06-20 00:43:36 +05:30
include KeysetPaginationHelpers
2014-09-02 18:07:02 +05:30
2020-05-24 23:13:21 +05:30
let_it_be(:user1) { create(:user, can_create_group: false) }
let_it_be(:user2) { create(:user) }
let_it_be(:user3) { create(:user) }
let_it_be(:admin) { create(:admin) }
2021-10-27 15:23:28 +05:30
let_it_be(:group1) { create(:group, path: 'some_path', avatar: File.open(uploaded_image_temp_path)) }
2020-05-24 23:13:21 +05:30
let_it_be(:group2) { create(:group, :private) }
let_it_be(:project1) { create(:project, namespace: group1) }
let_it_be(:project2) { create(:project, namespace: group2) }
let_it_be(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
2020-07-28 23:09:34 +05:30
let_it_be(:archived_project) { create(:project, namespace: group1, archived: true) }
2014-09-02 18:07:02 +05:30
2021-09-30 23:02:18 +05:30
before_all do
2014-09-02 18:07:02 +05:30
group1.add_owner(user1)
group2.add_owner(user2)
end
2020-04-08 14:13:33 +05:30
shared_examples 'group avatar upload' do
context 'when valid' do
let(:file_path) { 'spec/fixtures/banana_sample.gif' }
it 'returns avatar url in response' do
make_upload_request
group_id = json_response['id']
expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\
'-/system/group/avatar/'\
"#{group_id}/banana_sample.gif")
end
end
context 'when invalid' do
shared_examples 'invalid file upload request' do
2023-06-20 00:43:36 +05:30
it 'returns 400', :aggregate_failures do
2020-04-08 14:13:33 +05:30
make_upload_request
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.message).to eq('Bad Request')
expect(json_response['message'].to_s).to match(/#{message}/)
end
end
context 'when file format is not supported' do
let(:file_path) { 'spec/fixtures/doc_sample.txt' }
let(:message) { 'file format is not supported. Please try one of the following supported formats: image/png, image/jpeg, image/gif, image/bmp, image/tiff, image/vnd.microsoft.icon' }
it_behaves_like 'invalid file upload request'
end
2021-03-11 19:13:27 +05:30
context 'when file is too large' do
2020-04-08 14:13:33 +05:30
let(:file_path) { 'spec/fixtures/big-image.png' }
let(:message) { 'is too big' }
it_behaves_like 'invalid file upload request'
end
end
end
2021-10-27 15:23:28 +05:30
shared_examples 'skips searching in full path' do
2023-06-20 00:43:36 +05:30
it 'does not find groups by full path', :aggregate_failures do
2021-10-27 15:23:28 +05:30
subgroup = create(:group, parent: parent, path: "#{parent.path}-subgroup")
create(:group, parent: parent, path: 'not_matching_path')
get endpoint, params: { search: parent.path }
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(subgroup.id)
end
end
2014-09-02 18:07:02 +05:30
describe "GET /groups" do
context "when unauthenticated" do
2023-06-20 00:43:36 +05:30
it "returns public groups", :aggregate_failures do
2014-09-02 18:07:02 +05:30
get api("/groups")
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
2020-04-22 19:07:51 +05:30
expect(json_response.first['created_at']).to be_present
2018-03-17 18:26:18 +05:30
expect(json_response)
.to satisfy_one { |group| group['name'] == group1.name }
end
2023-01-13 00:05:48 +05:30
it 'avoids N+1 queries', :use_sql_query_cache do
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
2023-06-20 00:43:36 +05:30
get api("/groups")
2018-03-17 18:26:18 +05:30
end
create(:group)
expect do
2023-06-20 00:43:36 +05:30
get api("/groups")
2023-01-13 00:05:48 +05:30
end.not_to exceed_all_query_limit(control)
2014-09-02 18:07:02 +05:30
end
2020-05-24 23:13:21 +05:30
context 'when statistics are requested' do
2023-06-20 00:43:36 +05:30
it 'does not include statistics', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api("/groups"), params: { statistics: true }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first).not_to include 'statistics'
end
end
2014-09-02 18:07:02 +05:30
end
context "when authenticated as user" do
2023-06-20 00:43:36 +05:30
it "normal user: returns an array of groups of user1", :aggregate_failures do
2014-09-02 18:07:02 +05:30
get api("/groups", user1)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2015-04-26 12:48:37 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
2017-08-17 22:00:37 +05:30
expect(json_response)
.to satisfy_one { |group| group['name'] == group1.name }
end
2023-06-20 00:43:36 +05:30
it "does not include runners_token information", :aggregate_failures do
2019-12-04 20:38:33 +05:30
get api("/groups", user1)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first).not_to include('runners_token')
end
2023-06-20 00:43:36 +05:30
it "does not include statistics", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { statistics: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first).not_to include 'statistics'
2014-09-02 18:07:02 +05:30
end
2020-04-22 19:07:51 +05:30
2023-06-20 00:43:36 +05:30
it "includes a created_at timestamp", :aggregate_failures do
2020-04-22 19:07:51 +05:30
get api("/groups", user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first['created_at']).to be_present
end
2014-09-02 18:07:02 +05:30
end
2021-11-11 11:23:49 +05:30
context 'pagination strategies' do
let_it_be(:group_1) { create(:group, name: '1_group') }
let_it_be(:group_2) { create(:group, name: '2_group') }
context 'when the user is anonymous' do
context 'offset pagination' do
context 'on making requests beyond the allowed offset pagination threshold' do
it 'returns error and suggests to use keyset pagination' do
get api('/groups'), params: { page: 3000, per_page: 25 }
expect(response).to have_gitlab_http_status(:method_not_allowed)
expect(json_response['error']).to eq(
'Offset pagination has a maximum allowed offset of 50000 for requests that return objects of type Group. '\
'Remaining records can be retrieved using keyset pagination.'
)
end
end
context 'on making requests below the allowed offset pagination threshold' do
2023-06-20 00:43:36 +05:30
it 'paginates the records', :aggregate_failures do
2021-11-11 11:23:49 +05:30
get api('/groups'), params: { page: 1, per_page: 1 }
expect(response).to have_gitlab_http_status(:ok)
records = json_response
expect(records.size).to eq(1)
expect(records.first['id']).to eq(group_1.id)
# next page
get api('/groups'), params: { page: 2, per_page: 1 }
expect(response).to have_gitlab_http_status(:ok)
records = Gitlab::Json.parse(response.body)
expect(records.size).to eq(1)
expect(records.first['id']).to eq(group_2.id)
end
end
end
context 'keyset pagination' do
context 'on making requests with supported ordering structure' do
2023-06-20 00:43:36 +05:30
it 'paginates the records correctly', :aggregate_failures do
2021-11-11 11:23:49 +05:30
# first page
get api('/groups'), params: { pagination: 'keyset', per_page: 1 }
expect(response).to have_gitlab_http_status(:ok)
records = json_response
expect(records.size).to eq(1)
expect(records.first['id']).to eq(group_1.id)
2023-06-20 00:43:36 +05:30
params_for_next_page = pagination_params_from_next_url(response)
2021-11-11 11:23:49 +05:30
expect(params_for_next_page).to include('cursor')
get api('/groups'), params: params_for_next_page
expect(response).to have_gitlab_http_status(:ok)
records = Gitlab::Json.parse(response.body)
expect(records.size).to eq(1)
expect(records.first['id']).to eq(group_2.id)
end
end
context 'on making requests with unsupported ordering structure' do
2023-06-20 00:43:36 +05:30
it 'returns error', :aggregate_failures do
2021-11-11 11:23:49 +05:30
get api('/groups'), params: { pagination: 'keyset', per_page: 1, order_by: 'path', sort: 'desc' }
expect(response).to have_gitlab_http_status(:method_not_allowed)
expect(json_response['error']).to eq('Keyset pagination is not yet available for this type of request')
end
end
end
end
end
2017-08-17 22:00:37 +05:30
context "when authenticated as admin" do
2023-06-20 00:43:36 +05:30
it "admin: returns an array of all groups", :aggregate_failures do
get api("/groups", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2015-04-26 12:48:37 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
it "does not include runners_token information", :aggregate_failures do
get api("/groups", admin, admin_mode: true)
2019-12-04 20:38:33 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(json_response.first).not_to include('runners_token')
end
2023-06-20 00:43:36 +05:30
it "does not include statistics by default", :aggregate_failures do
get api("/groups", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first).not_to include('statistics')
end
2023-06-20 00:43:36 +05:30
it "includes a created_at timestamp", :aggregate_failures do
get api("/groups", admin, admin_mode: true)
2020-04-22 19:07:51 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first['created_at']).to be_present
end
2023-06-20 00:43:36 +05:30
it "includes statistics if requested", :aggregate_failures do
2017-08-17 22:00:37 +05:30
attributes = {
2021-12-11 22:18:48 +05:30
storage_size: 4093,
2017-08-17 22:00:37 +05:30
repository_size: 123,
2019-09-04 21:01:54 +05:30
wiki_size: 456,
2017-08-17 22:00:37 +05:30
lfs_objects_size: 234,
2020-07-28 23:09:34 +05:30
build_artifacts_size: 345,
2021-12-11 22:18:48 +05:30
pipeline_artifacts_size: 456,
packages_size: 567,
snippets_size: 1234,
uploads_size: 678
2017-08-17 22:00:37 +05:30
}.stringify_keys
exposed_attributes = attributes.dup
exposed_attributes['job_artifacts_size'] = exposed_attributes.delete('build_artifacts_size')
project1.statistics.update!(attributes)
2023-06-20 00:43:36 +05:30
get api("/groups", admin, admin_mode: true), params: { statistics: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response)
.to satisfy_one { |group| group['statistics'] == exposed_attributes }
end
2014-09-02 18:07:02 +05:30
end
2016-11-03 12:29:30 +05:30
context "when using skip_groups in request" do
2023-06-20 00:43:36 +05:30
it "returns all groups excluding skipped groups", :aggregate_failures do
get api("/groups", admin, admin_mode: true), params: { skip_groups: [group2.id] }
2016-11-03 12:29:30 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2016-11-03 12:29:30 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
end
end
2017-08-17 22:00:37 +05:30
context "when using all_available in request" do
let(:response_groups) { json_response.map { |group| group['name'] } }
2023-06-20 00:43:36 +05:30
it "returns all groups you have access to", :aggregate_failures do
2017-08-17 22:00:37 +05:30
public_group = create :group, :public
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { all_available: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups).to contain_exactly(public_group.name, group1.name)
end
end
2020-06-23 00:09:42 +05:30
context "when using top_level_only" do
let(:top_level_group) { create(:group, name: 'top-level-group') }
let(:subgroup) { create(:group, :nested, name: 'subgroup') }
let(:response_groups) { json_response.map { |group| group['name'] } }
before do
top_level_group.add_owner(user1)
subgroup.add_owner(user1)
end
2023-06-20 00:43:36 +05:30
it "doesn't return subgroups", :aggregate_failures do
2020-06-23 00:09:42 +05:30
get api("/groups", user1), params: { top_level_only: true }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups).to include(top_level_group.name)
expect(response_groups).not_to include(subgroup.name)
end
end
2017-08-17 22:00:37 +05:30
context "when using sorting" do
2021-09-30 23:02:18 +05:30
let_it_be(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") }
let_it_be(:group4) { create(:group, name: "same-name", path: "y#{group1.path}") }
let_it_be(:group5) { create(:group, name: "same-name") }
2017-08-17 22:00:37 +05:30
let(:response_groups) { json_response.map { |group| group['name'] } }
2018-11-08 19:23:39 +05:30
let(:response_groups_ids) { json_response.map { |group| group['id'] } }
2017-08-17 22:00:37 +05:30
2021-09-30 23:02:18 +05:30
before_all do
2017-08-17 22:00:37 +05:30
group3.add_owner(user1)
2018-11-08 19:23:39 +05:30
group4.add_owner(user1)
group5.add_owner(user1)
2017-08-17 22:00:37 +05:30
end
2023-06-20 00:43:36 +05:30
it "sorts by name ascending by default", :aggregate_failures do
2017-08-17 22:00:37 +05:30
get api("/groups", user1)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
2018-11-08 19:23:39 +05:30
expect(response_groups).to eq(groups_visible_to_user(user1).order(:name).pluck(:name))
2017-08-17 22:00:37 +05:30
end
2023-06-20 00:43:36 +05:30
it "sorts in descending order when passed", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { sort: "desc" }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
2018-11-08 19:23:39 +05:30
expect(response_groups).to eq(groups_visible_to_user(user1).order(name: :desc).pluck(:name))
2017-08-17 22:00:37 +05:30
end
2023-06-20 00:43:36 +05:30
it "sorts by path in order_by param", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { order_by: "path" }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
2018-11-08 19:23:39 +05:30
expect(response_groups).to eq(groups_visible_to_user(user1).order(:path).pluck(:name))
end
2023-06-20 00:43:36 +05:30
it "sorts by id in the order_by param", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { order_by: "id" }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups).to eq(groups_visible_to_user(user1).order(:id).pluck(:name))
end
2023-06-20 00:43:36 +05:30
it "sorts also by descending id with pagination fix", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { order_by: "id", sort: "desc" }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups).to eq(groups_visible_to_user(user1).order(id: :desc).pluck(:name))
end
2023-06-20 00:43:36 +05:30
it "sorts identical keys by id for good pagination", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { search: "same-name", order_by: "name" }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort)
end
2023-06-20 00:43:36 +05:30
it "sorts descending identical keys by id for good pagination", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups", user1), params: { search: "same-name", order_by: "name", sort: "desc" }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort)
end
2021-09-30 23:02:18 +05:30
context 'when searching with similarity ordering', :aggregate_failures do
let_it_be(:group6) { create(:group, name: 'same-name subgroup', parent: group4) }
let_it_be(:group7) { create(:group, name: 'same-name parent') }
let(:params) { { order_by: 'similarity', search: 'same-name' } }
before_all do
group6.add_owner(user1)
group7.add_owner(user1)
end
subject { get api('/groups', user1), params: params }
2023-06-20 00:43:36 +05:30
it 'sorts top level groups before subgroups with exact matches first', :aggregate_failures do
2021-09-30 23:02:18 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(4)
expect(response_groups).to eq(['same-name', 'same-name parent', 'same-name subgroup', 'same-name'])
end
context 'when `search` parameter is not given' do
let(:params) { { order_by: 'similarity' } }
2023-06-20 00:43:36 +05:30
it 'sorts items ordered by name', :aggregate_failures do
2021-09-30 23:02:18 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(6)
expect(response_groups).to eq(groups_visible_to_user(user1).order(:name).pluck(:name))
end
end
end
2018-11-08 19:23:39 +05:30
def groups_visible_to_user(user)
Group.where(id: user.authorized_groups.select(:id).reorder(nil))
2017-08-17 22:00:37 +05:30
end
end
context 'when using owned in the request' do
2023-06-20 00:43:36 +05:30
it 'returns an array of groups the user owns', :aggregate_failures do
2018-11-18 11:00:15 +05:30
group1.add_maintainer(user2)
2018-03-17 18:26:18 +05:30
2019-02-15 15:39:39 +05:30
get api('/groups', user2), params: { owned: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
2018-03-17 18:26:18 +05:30
expect(json_response.length).to eq(1)
2017-08-17 22:00:37 +05:30
expect(json_response.first['name']).to eq(group2.name)
end
end
2018-11-18 11:00:15 +05:30
context 'when using min_access_level in the request' do
let!(:group3) { create(:group, :private) }
let(:response_groups) { json_response.map { |group| group['id'] } }
before do
group1.add_developer(user2)
2020-04-22 19:07:51 +05:30
group3.add_maintainer(user2)
2018-11-18 11:00:15 +05:30
end
2022-11-25 23:54:43 +05:30
context 'with min_access_level parameter' do
2023-06-20 00:43:36 +05:30
it 'returns an array of groups the user has at least master access', :aggregate_failures do
2022-11-25 23:54:43 +05:30
get api('/groups', user2), params: { min_access_level: 40 }
2018-11-18 11:00:15 +05:30
2022-11-25 23:54:43 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(response_groups).to contain_exactly(group2.id, group3.id)
end
2023-06-20 00:43:36 +05:30
context 'distinct count' do
2022-11-25 23:54:43 +05:30
subject { get api('/groups', user2), params: { min_access_level: 40 } }
2023-06-20 00:43:36 +05:30
# Prevent Rails from optimizing the count query and inadvertadly creating a poor performing databse query.
# https://gitlab.com/gitlab-org/gitlab/-/issues/368969
2022-11-25 23:54:43 +05:30
it 'counts with *' do
count_sql = /#{Regexp.escape('SELECT count(*)')}/i
expect { subject }.to make_queries_matching count_sql
end
end
2018-11-18 11:00:15 +05:30
end
end
2021-10-27 15:23:28 +05:30
context 'when searching' do
let_it_be(:subgroup1) { create(:group, parent: group1, path: 'some_path') }
let(:response_groups) { json_response.map { |group| group['id'] } }
subject { get api('/groups', user1), params: { search: group1.path } }
2023-06-20 00:43:36 +05:30
it 'finds also groups with full path matching search param', :aggregate_failures do
2021-10-27 15:23:28 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(response_groups).to match_array([group1.id, subgroup1.id])
end
end
2014-09-02 18:07:02 +05:30
end
describe "GET /groups/:id" do
2018-03-17 18:26:18 +05:30
# Given a group, create one project for each visibility level
#
# group - Group to add projects to
# share_with - If provided, each project will be shared with this Group
#
# Returns a Hash of visibility_level => Project pairs
def add_projects_to_group(group, share_with: nil)
projects = {
2022-10-11 01:57:18 +05:30
public: create(:project, :public, namespace: group),
2018-03-17 18:26:18 +05:30
internal: create(:project, :internal, namespace: group),
2022-10-11 01:57:18 +05:30
private: create(:project, :private, namespace: group)
2018-03-17 18:26:18 +05:30
}
if share_with
create(:project_group_link, project: projects[:public], group: share_with)
create(:project_group_link, project: projects[:internal], group: share_with)
create(:project_group_link, project: projects[:private], group: share_with)
end
projects
end
2018-11-18 11:00:15 +05:30
def response_project_ids(json_response, key)
json_response[key].map do |project|
project['id'].to_i
end
end
2018-03-17 18:26:18 +05:30
context 'when unauthenticated' do
it 'returns 404 for a private group' do
get api("/groups/#{group2.id}")
2018-11-18 11:00:15 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
2023-06-20 00:43:36 +05:30
it 'returns 200 for a public group', :aggregate_failures do
2018-03-17 18:26:18 +05:30
get api("/groups/#{group1.id}")
2018-11-18 11:00:15 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(json_response).not_to include('runners_token')
2020-04-22 19:07:51 +05:30
expect(json_response).to include('created_at')
2018-03-17 18:26:18 +05:30
end
it 'returns only public projects in the group' do
public_group = create(:group, :public)
projects = add_projects_to_group(public_group)
get api("/groups/#{public_group.id}")
2018-11-18 11:00:15 +05:30
expect(response_project_ids(json_response, 'projects'))
2018-03-17 18:26:18 +05:30
.to contain_exactly(projects[:public].id)
end
it 'returns only public projects shared with the group' do
public_group = create(:group, :public)
projects = add_projects_to_group(public_group, share_with: group1)
get api("/groups/#{group1.id}")
2018-11-18 11:00:15 +05:30
expect(response_project_ids(json_response, 'shared_projects'))
2018-03-17 18:26:18 +05:30
.to contain_exactly(projects[:public].id)
end
end
2014-09-02 18:07:02 +05:30
context "when authenticated as user" do
2023-06-20 00:43:36 +05:30
it "returns one of user1's groups", :aggregate_failures do
2017-09-10 17:25:29 +05:30
project = create(:project, namespace: group2, path: 'Foo')
2016-08-24 12:49:21 +05:30
create(:project_group_link, project: project, group: group1)
2020-06-23 00:09:42 +05:30
group = create(:group)
link = create(:group_group_link, shared_group: group1, shared_with_group: group)
2016-08-24 12:49:21 +05:30
2014-09-02 18:07:02 +05:30
get api("/groups/#{group1.id}", user1)
2016-08-24 12:49:21 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2016-08-24 12:49:21 +05:30
expect(json_response['id']).to eq(group1.id)
expect(json_response['name']).to eq(group1.name)
expect(json_response['path']).to eq(group1.path)
expect(json_response['description']).to eq(group1.description)
2017-08-17 22:00:37 +05:30
expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
2017-09-10 17:25:29 +05:30
expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
2019-12-21 20:55:43 +05:30
expect(json_response['share_with_group_lock']).to eq(group1.share_with_group_lock)
2021-09-30 23:02:18 +05:30
expect(json_response['prevent_sharing_groups_outside_hierarchy']).to eq(group2.namespace_settings.prevent_sharing_groups_outside_hierarchy)
2019-12-21 20:55:43 +05:30
expect(json_response['require_two_factor_authentication']).to eq(group1.require_two_factor_authentication)
expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period)
expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled)
expect(json_response['emails_disabled']).to eq(group1.emails_disabled)
2020-03-13 15:44:24 +05:30
expect(json_response['mentions_disabled']).to eq(group1.mentions_disabled)
2019-12-21 20:55:43 +05:30
expect(json_response['project_creation_level']).to eq('maintainer')
expect(json_response['subgroup_creation_level']).to eq('maintainer')
2016-08-24 12:49:21 +05:30
expect(json_response['web_url']).to eq(group1.web_url)
2017-08-17 22:00:37 +05:30
expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled)
expect(json_response['full_name']).to eq(group1.full_name)
expect(json_response['full_path']).to eq(group1.full_path)
expect(json_response['parent_id']).to eq(group1.parent_id)
2020-04-22 19:07:51 +05:30
expect(json_response['created_at']).to be_present
2020-06-23 00:09:42 +05:30
expect(json_response['shared_with_groups']).to be_an Array
expect(json_response['shared_with_groups'].length).to eq(1)
expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name)
expect(json_response['shared_with_groups'][0]['group_full_path']).to eq(group.full_path)
expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access)
expect(json_response['shared_with_groups'][0]).to have_key('expires_at')
2016-08-24 12:49:21 +05:30
expect(json_response['projects']).to be_an Array
2020-07-28 23:09:34 +05:30
expect(json_response['projects'].length).to eq(3)
2016-08-24 12:49:21 +05:30
expect(json_response['shared_projects']).to be_an Array
expect(json_response['shared_projects'].length).to eq(1)
expect(json_response['shared_projects'][0]['id']).to eq(project.id)
2014-09-02 18:07:02 +05:30
end
2023-06-20 00:43:36 +05:30
it "returns one of user1's groups without projects when with_projects option is set to false", :aggregate_failures do
2018-11-18 11:00:15 +05:30
project = create(:project, namespace: group2, path: 'Foo')
create(:project_group_link, project: project, group: group1)
2022-08-13 15:12:31 +05:30
get api("/groups/#{group2.id}", user1), params: { with_projects: false }
2018-11-18 11:00:15 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-18 11:00:15 +05:30
expect(json_response['projects']).to be_nil
expect(json_response['shared_projects']).to be_nil
2019-12-04 20:38:33 +05:30
expect(json_response).not_to include('runners_token')
end
2023-06-20 00:43:36 +05:30
it "doesn't return runners_token if the user is not the owner of the group", :aggregate_failures do
2019-12-04 20:38:33 +05:30
get api("/groups/#{group1.id}", user3)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(json_response).not_to include('runners_token')
end
2023-06-20 00:43:36 +05:30
it "returns runners_token if the user is the owner of the group", :aggregate_failures do
2019-12-04 20:38:33 +05:30
group1.add_owner(user3)
get api("/groups/#{group1.id}", user3)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(json_response).to include('runners_token')
2018-11-18 11:00:15 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not return a non existing group" do
2021-09-04 01:27:46 +05:30
get api("/groups/#{non_existing_record_id}", user1)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not return a group not attached to user1" do
2014-09-02 18:07:02 +05:30
get api("/groups/#{group2.id}", user1)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
it 'returns only public and internal projects in the group' do
public_group = create(:group, :public)
projects = add_projects_to_group(public_group)
get api("/groups/#{public_group.id}", user2)
2018-11-18 11:00:15 +05:30
expect(response_project_ids(json_response, 'projects'))
2018-03-17 18:26:18 +05:30
.to contain_exactly(projects[:public].id, projects[:internal].id)
end
it 'returns only public and internal projects shared with the group' do
public_group = create(:group, :public)
projects = add_projects_to_group(public_group, share_with: group1)
get api("/groups/#{group1.id}", user2)
2018-11-18 11:00:15 +05:30
expect(response_project_ids(json_response, 'shared_projects'))
2018-03-17 18:26:18 +05:30
.to contain_exactly(projects[:public].id, projects[:internal].id)
2014-09-02 18:07:02 +05:30
end
2019-03-02 22:35:43 +05:30
2023-06-20 00:43:36 +05:30
it 'avoids N+1 queries with project links', :aggregate_failures do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}", user1)
2023-06-20 00:43:36 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-03-02 22:35:43 +05:30
control_count = ActiveRecord::QueryRecorder.new do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}", user1)
2019-03-02 22:35:43 +05:30
end.count
create(:project, namespace: group1)
expect do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}", user1)
2019-03-02 22:35:43 +05:30
end.not_to exceed_query_limit(control_count)
end
2020-06-23 00:09:42 +05:30
it 'avoids N+1 queries with shared group links' do
# setup at least 1 shared group, so that we record the queries that preload the nested associations too.
create(:group_group_link, shared_group: group1, shared_with_group: create(:group))
control_count = ActiveRecord::QueryRecorder.new do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}", user1)
2020-06-23 00:09:42 +05:30
end.count
# setup "n" more shared groups
create(:group_group_link, shared_group: group1, shared_with_group: create(:group))
create(:group_group_link, shared_group: group1, shared_with_group: create(:group))
# test that no of queries for 1 shared group is same as for n shared groups
expect do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}", user1)
2020-06-23 00:09:42 +05:30
end.not_to exceed_query_limit(control_count)
end
2014-09-02 18:07:02 +05:30
end
context "when authenticated as admin" do
2023-06-20 00:43:36 +05:30
it "returns any existing group", :aggregate_failures do
get api("/groups/#{group2.id}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2015-12-23 02:04:40 +05:30
expect(json_response['name']).to eq(group2.name)
2014-09-02 18:07:02 +05:30
end
2023-06-20 00:43:36 +05:30
it "returns information of the runners_token for the group", :aggregate_failures do
get api("/groups/#{group2.id}", admin, admin_mode: true)
2019-12-04 20:38:33 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-04 20:38:33 +05:30
expect(json_response).to include('runners_token')
end
2023-06-20 00:43:36 +05:30
it "returns runners_token and no projects when with_projects option is set to false", :aggregate_failures do
2022-08-13 15:12:31 +05:30
project = create(:project, namespace: group2, path: 'Foo')
create(:project_group_link, project: project, group: group1)
2023-06-20 00:43:36 +05:30
get api("/groups/#{group2.id}", admin, admin_mode: true), params: { with_projects: false }
2022-08-13 15:12:31 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['projects']).to be_nil
expect(json_response['shared_projects']).to be_nil
expect(json_response).to include('runners_token')
end
2016-09-13 17:45:13 +05:30
it "does not return a non existing group" do
2023-06-20 00:43:36 +05:30
get api("/groups/#{non_existing_record_id}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2015-04-26 12:48:37 +05:30
end
end
context 'when using group path in URL' do
2023-06-20 00:43:36 +05:30
it 'returns any existing group', :aggregate_failures do
2015-04-26 12:48:37 +05:30
get api("/groups/#{group1.path}", admin)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2015-12-23 02:04:40 +05:30
expect(json_response['name']).to eq(group1.name)
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not return a non existing group' do
2023-06-20 00:43:36 +05:30
get api('/groups/unknown', admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not return a group not attached to user1' do
2015-04-26 12:48:37 +05:30
get api("/groups/#{group2.path}", user1)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2016-06-02 11:05:42 +05:30
end
end
2020-01-01 13:55:28 +05:30
context 'limiting the number of projects and shared_projects in the response' do
let(:limit) { 1 }
before do
stub_const("GroupProjectsFinder::DEFAULT_PROJECTS_LIMIT", limit)
# creates 3 public projects
create_list(:project, 3, :public, namespace: group1)
# creates 3 shared projects
public_group = create(:group, :public)
projects_to_be_shared = create_list(:project, 3, :public, namespace: public_group)
projects_to_be_shared.each do |project|
create(:project_group_link, project: project, group: group1)
end
end
2023-06-20 00:43:36 +05:30
it 'limits projects and shared_projects', :aggregate_failures do
2021-09-04 01:27:46 +05:30
get api("/groups/#{group1.id}")
2020-01-01 13:55:28 +05:30
2021-09-04 01:27:46 +05:30
expect(json_response['projects'].count).to eq(limit)
expect(json_response['shared_projects'].count).to eq(limit)
2020-01-01 13:55:28 +05:30
end
end
2022-03-02 08:16:31 +05:30
context 'when a group is shared', :aggregate_failures do
let_it_be(:shared_group) { create(:group) }
let_it_be(:group2_sub) { create(:group, :private, parent: group2) }
let_it_be(:group_link_1) { create(:group_group_link, shared_group: shared_group, shared_with_group: group1) }
let_it_be(:group_link_2) { create(:group_group_link, shared_group: shared_group, shared_with_group: group2_sub) }
subject(:shared_with_groups) { json_response['shared_with_groups'].map { _1['group_id']} }
context 'when authenticated as admin' do
2023-06-20 00:43:36 +05:30
it 'returns all groups that share the group', :aggregate_failures do
get api("/groups/#{shared_group.id}", admin, admin_mode: true)
2022-03-02 08:16:31 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(shared_with_groups).to contain_exactly(group_link_1.shared_with_group_id, group_link_2.shared_with_group_id)
end
end
context 'when unauthenticated' do
2023-06-20 00:43:36 +05:30
it 'returns only public groups that share the group', :aggregate_failures do
2022-03-02 08:16:31 +05:30
get api("/groups/#{shared_group.id}")
expect(response).to have_gitlab_http_status(:ok)
expect(shared_with_groups).to contain_exactly(group_link_1.shared_with_group_id)
end
end
context 'when authenticated as a member of a parent group that has shared the group' do
2023-06-20 00:43:36 +05:30
it 'returns private group if direct member', :aggregate_failures do
2022-03-02 08:16:31 +05:30
group2_sub.add_guest(user3)
get api("/groups/#{shared_group.id}", user3)
expect(response).to have_gitlab_http_status(:ok)
expect(shared_with_groups).to contain_exactly(group_link_1.shared_with_group_id, group_link_2.shared_with_group_id)
end
2023-06-20 00:43:36 +05:30
it 'returns private group if inherited member', :aggregate_failures do
2022-03-02 08:16:31 +05:30
inherited_guest_member = create(:user)
group2.add_guest(inherited_guest_member)
get api("/groups/#{shared_group.id}", inherited_guest_member)
expect(response).to have_gitlab_http_status(:ok)
expect(shared_with_groups).to contain_exactly(group_link_1.shared_with_group_id, group_link_2.shared_with_group_id)
end
end
end
2016-06-02 11:05:42 +05:30
end
describe 'PUT /groups/:id' do
2022-08-27 11:52:29 +05:30
let(:new_group_name) { 'New Group' }
2021-03-11 19:13:27 +05:30
let(:file_path) { 'spec/fixtures/dk.png' }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
it_behaves_like 'group avatar upload' do
def make_upload_request
group_param = {
avatar: fixture_file_upload(file_path)
}
2022-10-11 01:57:18 +05:30
workhorse_form_with_file(
api("/groups/#{group1.id}", user1),
method: :put,
file_key: :avatar,
params: group_param
)
2020-04-08 14:13:33 +05:30
end
end
2016-06-02 11:05:42 +05:30
context 'when authenticated as the group owner' do
2023-06-20 00:43:36 +05:30
it 'updates the group', :aggregate_failures do
2022-10-11 01:57:18 +05:30
workhorse_form_with_file(
api("/groups/#{group1.id}", user1),
method: :put,
file_key: :avatar,
params: {
name: new_group_name,
request_access_enabled: true,
project_creation_level: "noone",
subgroup_creation_level: "maintainer",
default_branch_protection: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS,
prevent_sharing_groups_outside_hierarchy: true,
avatar: fixture_file_upload(file_path)
}
)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2016-06-02 11:05:42 +05:30
expect(json_response['name']).to eq(new_group_name)
2019-12-21 20:55:43 +05:30
expect(json_response['description']).to eq('')
expect(json_response['visibility']).to eq('public')
expect(json_response['share_with_group_lock']).to eq(false)
expect(json_response['require_two_factor_authentication']).to eq(false)
expect(json_response['two_factor_grace_period']).to eq(48)
expect(json_response['auto_devops_enabled']).to eq(nil)
expect(json_response['emails_disabled']).to eq(nil)
2020-03-13 15:44:24 +05:30
expect(json_response['mentions_disabled']).to eq(nil)
2019-12-21 20:55:43 +05:30
expect(json_response['project_creation_level']).to eq("noone")
expect(json_response['subgroup_creation_level']).to eq("maintainer")
2016-09-29 09:46:39 +05:30
expect(json_response['request_access_enabled']).to eq(true)
2019-12-21 20:55:43 +05:30
expect(json_response['parent_id']).to eq(nil)
2020-04-22 19:07:51 +05:30
expect(json_response['created_at']).to be_present
2019-12-21 20:55:43 +05:30
expect(json_response['projects']).to be_an Array
2020-07-28 23:09:34 +05:30
expect(json_response['projects'].length).to eq(3)
2019-12-21 20:55:43 +05:30
expect(json_response['shared_projects']).to be_an Array
expect(json_response['shared_projects'].length).to eq(0)
2020-04-08 14:13:33 +05:30
expect(json_response['default_branch_protection']).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
2021-03-11 19:13:27 +05:30
expect(json_response['avatar_url']).to end_with('dk.png')
2021-09-30 23:02:18 +05:30
expect(json_response['prevent_sharing_groups_outside_hierarchy']).to eq(true)
2016-06-02 11:05:42 +05:30
end
2023-06-20 00:43:36 +05:30
it 'removes the group avatar', :aggregate_failures do
2022-10-11 01:57:18 +05:30
put api("/groups/#{group1.id}", user1), params: { avatar: '' }
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to be_nil
expect(group1.reload.avatar_url).to be_nil
end
end
2023-06-20 00:43:36 +05:30
it 'does not update visibility_level if it is restricted', :aggregate_failures do
2021-10-29 20:43:33 +05:30
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
put api("/groups/#{group1.id}", user1), params: { visibility: 'internal' }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['visibility_level']).to include('internal has been restricted by your GitLab administrator')
end
2020-05-24 23:13:21 +05:30
context 'updating the `default_branch_protection` attribute' do
subject do
put api("/groups/#{group1.id}", user1), params: { default_branch_protection: ::Gitlab::Access::PROTECTION_NONE }
end
context 'for users who have the ability to update default_branch_protection' do
2023-06-20 00:43:36 +05:30
it 'updates the attribute', :aggregate_failures do
2020-05-24 23:13:21 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['default_branch_protection']).to eq(Gitlab::Access::PROTECTION_NONE)
end
end
context 'for users who does not have the ability to update default_branch_protection`' do
2023-06-20 00:43:36 +05:30
it 'does not update the attribute', :aggregate_failures do
2020-05-24 23:13:21 +05:30
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user1, :update_default_branch_protection, group1) { false }
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['default_branch_protection']).not_to eq(Gitlab::Access::PROTECTION_NONE)
end
end
end
2020-03-28 13:19:24 +05:30
context 'malicious group name' do
subject { put api("/groups/#{group1.id}", user1), params: { name: "<SCRIPT>alert('DOUBLE-ATTACK!')</SCRIPT>" } }
it 'returns bad request' do
subject
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'does not update group name' do
expect { subject }.not_to change { group1.reload.name }
end
end
2016-06-02 11:05:42 +05:30
it 'returns 404 for a non existing group' do
2021-09-04 01:27:46 +05:30
put api("/groups/#{non_existing_record_id}", user1), params: { name: new_group_name }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2016-06-02 11:05:42 +05:30
end
2019-12-21 20:55:43 +05:30
context 'within a subgroup' do
let(:group3) { create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
let!(:subgroup) { create(:group, parent: group3, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
before do
group3.add_owner(user3)
end
2023-06-20 00:43:36 +05:30
it 'does not change visibility when not requested', :aggregate_failures do
2019-12-21 20:55:43 +05:30
put api("/groups/#{group3.id}", user3), params: { description: 'Bug #23083' }
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-12-21 20:55:43 +05:30
expect(json_response['visibility']).to eq('public')
end
2023-06-20 00:43:36 +05:30
it 'prevents making private a group containing public subgroups', :aggregate_failures do
2019-12-21 20:55:43 +05:30
put api("/groups/#{group3.id}", user3), params: { visibility: 'private' }
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:bad_request)
2019-12-21 20:55:43 +05:30
expect(json_response['message']['visibility_level']).to contain_exactly('private is not allowed since there are sub-groups with higher visibility.')
end
2021-09-30 23:02:18 +05:30
2023-06-20 00:43:36 +05:30
it 'does not update prevent_sharing_groups_outside_hierarchy', :aggregate_failures do
2021-09-30 23:02:18 +05:30
put api("/groups/#{subgroup.id}", user3), params: { description: 'it works', prevent_sharing_groups_outside_hierarchy: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.keys).not_to include('prevent_sharing_groups_outside_hierarchy')
expect(subgroup.reload.prevent_sharing_groups_outside_hierarchy).to eq(false)
expect(json_response['description']).to eq('it works')
end
2019-12-21 20:55:43 +05:30
end
2016-06-02 11:05:42 +05:30
end
context 'when authenticated as the admin' do
2023-06-20 00:43:36 +05:30
it 'updates the group', :aggregate_failures do
put api("/groups/#{group1.id}", admin, admin_mode: true), params: { name: new_group_name }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2016-06-02 11:05:42 +05:30
expect(json_response['name']).to eq(new_group_name)
end
2021-10-29 20:43:33 +05:30
2023-06-20 00:43:36 +05:30
it 'ignores visibility level restrictions', :aggregate_failures do
2021-10-29 20:43:33 +05:30
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
2023-06-20 00:43:36 +05:30
put api("/groups/#{group1.id}", admin, admin_mode: true), params: { visibility: 'internal' }
2021-10-29 20:43:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['visibility']).to eq('internal')
end
2016-06-02 11:05:42 +05:30
end
context 'when authenticated as an user that can see the group' do
it 'does not updates the group' do
2019-02-15 15:39:39 +05:30
put api("/groups/#{group1.id}", user2), params: { name: new_group_name }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:forbidden)
2014-09-02 18:07:02 +05:30
end
end
2016-06-02 11:05:42 +05:30
context 'when authenticated as an user that cannot see the group' do
it 'returns 404 when trying to update the group' do
2019-02-15 15:39:39 +05:30
put api("/groups/#{group2.id}", user1), params: { name: new_group_name }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2016-06-02 11:05:42 +05:30
end
end
2014-09-02 18:07:02 +05:30
end
2015-12-23 02:04:40 +05:30
describe "GET /groups/:id/projects" do
context "when authenticated as user" do
2019-12-04 20:38:33 +05:30
context 'with min access level' do
it 'returns projects with min access level or higher' do
group_guest = create(:user)
group1.add_guest(group_guest)
project4 = create(:project, group: group1)
project1.add_guest(group_guest)
project3.add_reporter(group_guest)
project4.add_developer(group_guest)
get api("/groups/#{group1.id}/projects", group_guest), params: { min_access_level: Gitlab::Access::REPORTER }
project_ids = json_response.map { |proj| proj['id'] }
expect(project_ids).to match_array([project3.id, project4.id])
end
end
2023-06-20 00:43:36 +05:30
it "returns the group's projects", :aggregate_failures do
2015-12-23 02:04:40 +05:30
get api("/groups/#{group1.id}/projects", user1)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2020-07-28 23:09:34 +05:30
expect(json_response.length).to eq(3)
2017-08-17 22:00:37 +05:30
project_names = json_response.map { |proj| proj['name'] }
2020-07-28 23:09:34 +05:30
expect(project_names).to match_array([project1.name, project3.name, archived_project.name])
2017-08-17 22:00:37 +05:30
expect(json_response.first['visibility']).to be_present
end
2020-07-28 23:09:34 +05:30
context 'and using archived' do
2023-06-20 00:43:36 +05:30
it "returns the group's archived projects", :aggregate_failures do
2020-07-28 23:09:34 +05:30
get api("/groups/#{group1.id}/projects?archived=true", user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(Project.public_or_visible_to_user(user1).where(archived: true).size)
expect(json_response.map { |project| project['id'] }).to include(archived_project.id)
end
2023-06-20 00:43:36 +05:30
it "returns the group's non-archived projects", :aggregate_failures do
2020-07-28 23:09:34 +05:30
get api("/groups/#{group1.id}/projects?archived=false", user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(Project.public_or_visible_to_user(user1).where(archived: false).size)
expect(json_response.map { |project| project['id'] }).not_to include(archived_project.id)
end
2023-06-20 00:43:36 +05:30
it "returns all of the group's projects", :aggregate_failures do
2020-07-28 23:09:34 +05:30
get api("/groups/#{group1.id}/projects", user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(*Project.public_or_visible_to_user(user1).pluck(:id))
end
end
2020-10-24 23:57:45 +05:30
context 'with similarity ordering' do
let_it_be(:group_with_projects) { create(:group) }
let_it_be(:project_1) { create(:project, name: 'Project', path: 'project', group: group_with_projects) }
let_it_be(:project_2) { create(:project, name: 'Test Project', path: 'test-project', group: group_with_projects) }
let_it_be(:project_3) { create(:project, name: 'Test', path: 'test', group: group_with_projects) }
let(:params) { { order_by: 'similarity', search: 'test' } }
subject { get api("/groups/#{group_with_projects.id}/projects", user1), params: params }
before do
group_with_projects.add_owner(user1)
end
2023-06-20 00:43:36 +05:30
it 'returns items based ordered by similarity', :aggregate_failures do
2020-10-24 23:57:45 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
project_names = json_response.map { |proj| proj['name'] }
expect(project_names).to eq(['Test', 'Test Project'])
end
context 'when `search` parameter is not given' do
before do
params.delete(:search)
end
2023-06-20 00:43:36 +05:30
it 'returns items ordered by name', :aggregate_failures do
2020-10-24 23:57:45 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(3)
project_names = json_response.map { |proj| proj['name'] }
expect(project_names).to eq(['Project', 'Test', 'Test Project'])
end
end
end
2023-06-20 00:43:36 +05:30
it "returns the group's projects with simple representation", :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups/#{group1.id}/projects", user1), params: { simple: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2020-07-28 23:09:34 +05:30
expect(json_response.length).to eq(3)
2017-08-17 22:00:37 +05:30
project_names = json_response.map { |proj| proj['name'] }
2020-07-28 23:09:34 +05:30
expect(project_names).to match_array([project1.name, project3.name, archived_project.name])
2017-08-17 22:00:37 +05:30
expect(json_response.first['visibility']).not_to be_present
end
2023-06-20 00:43:36 +05:30
it "filters the groups projects", :aggregate_failures do
2017-09-10 17:25:29 +05:30
public_project = create(:project, :public, path: 'test1', group: group1)
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
get api("/groups/#{group1.id}/projects", user1), params: { visibility: 'public' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(public_project.name)
2015-12-23 02:04:40 +05:30
end
2023-06-20 00:43:36 +05:30
it "returns projects excluding shared", :aggregate_failures do
2019-02-15 15:39:39 +05:30
create(:project_group_link, project: create(:project), group: group1)
create(:project_group_link, project: create(:project), group: group1)
create(:project_group_link, project: create(:project), group: group1)
get api("/groups/#{group1.id}/projects", user1), params: { with_shared: false }
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2019-02-15 15:39:39 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
2020-07-28 23:09:34 +05:30
expect(json_response.length).to eq(3)
2019-02-15 15:39:39 +05:30
end
2022-04-04 11:22:00 +05:30
context 'when include_subgroups is true' do
2022-06-21 17:19:12 +05:30
before do
2022-04-04 11:22:00 +05:30
subgroup = create(:group, parent: group1)
2022-06-21 17:19:12 +05:30
subgroup2 = create(:group, parent: subgroup)
2022-04-04 11:22:00 +05:30
create(:project, group: subgroup)
create(:project, group: subgroup)
2022-06-21 17:19:12 +05:30
create(:project, group: subgroup2)
group1.reload
end
2023-06-20 00:43:36 +05:30
it "returns projects including those in subgroups", :aggregate_failures do
2022-04-04 11:22:00 +05:30
get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
2019-02-15 15:39:39 +05:30
2022-04-04 11:22:00 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
2022-06-21 17:19:12 +05:30
expect(json_response.length).to eq(6)
end
2023-01-13 00:05:48 +05:30
2023-06-20 00:43:36 +05:30
it 'avoids N+1 queries', :aggregate_failures, :use_sql_query_cache, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/383788' do
get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
expect(respone).to have_gitlab_http_status(:ok)
2023-01-13 00:05:48 +05:30
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
end
create_list(:project, 2, :public, namespace: group1)
expect do
get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
end.not_to exceed_all_query_limit(control.count)
end
2022-04-04 11:22:00 +05:30
end
context 'when include_ancestor_groups is true' do
2023-06-20 00:43:36 +05:30
it 'returns ancestors groups projects', :aggregate_failures do
2022-04-04 11:22:00 +05:30
subgroup = create(:group, parent: group1)
subgroup_project = create(:project, group: subgroup)
get api("/groups/#{subgroup.id}/projects", user1), params: { include_ancestor_groups: true }
records = Gitlab::Json.parse(response.body)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(records.map { |r| r['id'] }).to match_array([project1.id, project3.id, subgroup_project.id, archived_project.id])
end
2019-02-15 15:39:39 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not return a non existing group" do
2021-09-04 01:27:46 +05:30
get api("/groups/#{non_existing_record_id}/projects", user1)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2015-12-23 02:04:40 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not return a group not attached to user1" do
2015-12-23 02:04:40 +05:30
get api("/groups/#{group2.id}/projects", user1)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2015-12-23 02:04:40 +05:30
end
2023-06-20 00:43:36 +05:30
it "only returns projects to which user has access", :aggregate_failures do
2018-03-17 18:26:18 +05:30
project3.add_developer(user3)
get api("/groups/#{group1.id}/projects", user3)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(project3.name)
end
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
it 'only returns the projects owned by user', :aggregate_failures do
2017-08-17 22:00:37 +05:30
project2.group.add_owner(user3)
2019-02-15 15:39:39 +05:30
get api("/groups/#{project2.group.id}/projects", user3), params: { owned: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(project2.name)
end
2023-06-20 00:43:36 +05:30
it 'only returns the projects starred by user', :aggregate_failures do
2017-08-17 22:00:37 +05:30
user1.starred_projects = [project1]
2019-02-15 15:39:39 +05:30
get api("/groups/#{group1.id}/projects", user1), params: { starred: true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(project1.name)
end
2021-11-18 22:05:49 +05:30
2023-06-20 00:43:36 +05:30
it 'avoids N+1 queries', :aggregate_failures do
2021-11-18 22:05:49 +05:30
get api("/groups/#{group1.id}/projects", user1)
2023-06-20 00:43:36 +05:30
expect(response).to have_gitlab_http_status(:ok)
2021-11-18 22:05:49 +05:30
control_count = ActiveRecord::QueryRecorder.new do
get api("/groups/#{group1.id}/projects", user1)
end.count
create(:project, namespace: group1)
expect do
get api("/groups/#{group1.id}/projects", user1)
end.not_to exceed_query_limit(control_count)
end
2015-12-23 02:04:40 +05:30
end
context "when authenticated as admin" do
2023-06-20 00:43:36 +05:30
it "returns any existing group", :aggregate_failures do
get api("/groups/#{group2.id}/projects", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
2015-12-23 02:04:40 +05:30
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(project2.name)
end
2017-08-17 22:00:37 +05:30
it "does not return a non existing group" do
2023-06-20 00:43:36 +05:30
get api("/groups/#{non_existing_record_id}/projects", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
2015-12-23 02:04:40 +05:30
end
context 'when using group path in URL' do
2023-06-20 00:43:36 +05:30
it 'returns any existing group', :aggregate_failures do
get api("/groups/#{group1.path}/projects", admin, admin_mode: true)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(response).to include_pagination_headers
project_names = json_response.map { |proj| proj['name'] }
2020-07-28 23:09:34 +05:30
expect(project_names).to match_array([project1.name, project3.name, archived_project.name])
2015-12-23 02:04:40 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not return a non existing group' do
2023-06-20 00:43:36 +05:30
get api('/groups/unknown/projects', admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2015-12-23 02:04:40 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not return a group not attached to user1' do
2015-12-23 02:04:40 +05:30
get api("/groups/#{group2.path}/projects", user1)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
end
end
2020-05-24 23:13:21 +05:30
describe "GET /groups/:id/projects/shared" do
let!(:project4) do
create(:project, namespace: group2, path: 'test_project', visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
2020-10-24 23:57:45 +05:30
2020-05-24 23:13:21 +05:30
let(:path) { "/groups/#{group1.id}/projects/shared" }
before do
create(:project_group_link, project: project2, group: group1)
create(:project_group_link, project: project4, group: group1)
end
context 'when authenticated as user' do
2023-06-20 00:43:36 +05:30
it 'returns the shared projects in the group', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api(path, user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
project_ids = json_response.map { |project| project['id'] }
expect(project_ids).to match_array([project2.id, project4.id])
expect(json_response.first['visibility']).to be_present
end
2023-06-20 00:43:36 +05:30
it 'returns shared projects with min access level or higher', :aggregate_failures do
2020-05-24 23:13:21 +05:30
user = create(:user)
project2.add_guest(user)
project4.add_reporter(user)
get api(path, user), params: { min_access_level: Gitlab::Access::REPORTER }
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(project4.id)
end
2023-06-20 00:43:36 +05:30
it 'returns the shared projects of the group with simple representation', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api(path, user1), params: { simple: true }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
project_ids = json_response.map { |project| project['id'] }
expect(project_ids).to match_array([project2.id, project4.id])
expect(json_response.first['visibility']).not_to be_present
end
2023-06-20 00:43:36 +05:30
it 'filters the shared projects in the group based on visibility', :aggregate_failures do
2020-05-24 23:13:21 +05:30
internal_project = create(:project, :internal, namespace: create(:group))
create(:project_group_link, project: internal_project, group: group1)
get api(path, user1), params: { visibility: 'internal' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(internal_project.id)
end
2023-06-20 00:43:36 +05:30
it 'filters the shared projects in the group based on search params', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api(path, user1), params: { search: 'test_project' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(project4.id)
end
2023-06-20 00:43:36 +05:30
it 'does not return the projects owned by the group', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api(path, user1)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
project_ids = json_response.map { |project| project['id'] }
expect(project_ids).not_to include(project1.id)
end
it 'returns 404 for a non-existing group' do
get api("/groups/0000/projects/shared", user1)
expect(response).to have_gitlab_http_status(:not_found)
end
it 'does not return a group not attached to the user' do
group = create(:group, :private)
get api("/groups/#{group.id}/projects/shared", user1)
expect(response).to have_gitlab_http_status(:not_found)
end
2023-06-20 00:43:36 +05:30
it 'only returns shared projects to which user has access', :aggregate_failures do
2020-05-24 23:13:21 +05:30
project4.add_developer(user3)
get api(path, user3)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(project4.id)
end
2023-06-20 00:43:36 +05:30
it 'only returns the projects starred by user', :aggregate_failures do
2020-05-24 23:13:21 +05:30
user1.starred_projects = [project2]
get api(path, user1), params: { starred: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(project2.id)
end
end
context "when authenticated as admin" do
2023-06-20 00:43:36 +05:30
subject { get api(path, admin, admin_mode: true) }
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it "returns shared projects of an existing group", :aggregate_failures do
2020-05-24 23:13:21 +05:30
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
project_ids = json_response.map { |project| project['id'] }
expect(project_ids).to match_array([project2.id, project4.id])
end
context 'for a non-existent group' do
let(:path) { "/groups/000/projects/shared" }
it 'returns 404 for a non-existent group' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
2023-06-20 00:43:36 +05:30
it 'avoids N+1 queries', :aggregate_failures, :use_sql_query_cache do
subject
expect(response).to have_gitlab_http_status(:ok)
2020-05-24 23:13:21 +05:30
control_count = ActiveRecord::QueryRecorder.new do
subject
end.count
create(:project_group_link, project: create(:project), group: group1)
expect do
subject
end.not_to exceed_query_limit(control_count)
end
end
context 'when using group path in URL' do
let(:path) { "/groups/#{group1.path}/projects/shared" }
2023-06-20 00:43:36 +05:30
it 'returns the right details', :aggregate_failures do
get api(path, admin, admin_mode: true)
2020-05-24 23:13:21 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
project_ids = json_response.map { |project| project['id'] }
expect(project_ids).to match_array([project2.id, project4.id])
end
it 'returns 404 for a non-existent group' do
2023-06-20 00:43:36 +05:30
get api('/groups/unknown/projects/shared', admin, admin_mode: true)
2020-05-24 23:13:21 +05:30
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
2019-10-12 21:52:04 +05:30
describe 'GET /groups/:id/subgroups' do
2018-03-17 18:26:18 +05:30
let!(:subgroup1) { create(:group, parent: group1) }
let!(:subgroup2) { create(:group, :private, parent: group1) }
let!(:subgroup3) { create(:group, :private, parent: group2) }
context 'when unauthenticated' do
2023-06-20 00:43:36 +05:30
it 'returns only public subgroups', :aggregate_failures do
2018-03-17 18:26:18 +05:30
get api("/groups/#{group1.id}/subgroups")
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(subgroup1.id)
expect(json_response.first['parent_id']).to eq(group1.id)
end
it 'returns 404 for a private group' do
get api("/groups/#{group2.id}/subgroups")
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
2020-05-24 23:13:21 +05:30
context 'when statistics are requested' do
2023-06-20 00:43:36 +05:30
it 'does not include statistics', :aggregate_failures do
2020-05-24 23:13:21 +05:30
get api("/groups/#{group1.id}/subgroups"), params: { statistics: true }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first).not_to include 'statistics'
end
end
2018-03-17 18:26:18 +05:30
end
context 'when authenticated as user' do
context 'when user is not member of a public group' do
2023-06-20 00:43:36 +05:30
it 'returns no subgroups for the public group', :aggregate_failures do
2018-03-17 18:26:18 +05:30
get api("/groups/#{group1.id}/subgroups", user2)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(0)
end
context 'when using all_available in request' do
2023-06-20 00:43:36 +05:30
it 'returns public subgroups', :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups/#{group1.id}/subgroups", user2), params: { all_available: true }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response[0]['id']).to eq(subgroup1.id)
expect(json_response[0]['parent_id']).to eq(group1.id)
end
end
end
context 'when user is not member of a private group' do
it 'returns 404 for the private group' do
get api("/groups/#{group2.id}/subgroups", user1)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2018-03-17 18:26:18 +05:30
end
end
context 'when user is member of public group' do
before do
group1.add_guest(user2)
end
2023-06-20 00:43:36 +05:30
it 'returns private subgroups', :aggregate_failures do
2018-03-17 18:26:18 +05:30
get api("/groups/#{group1.id}/subgroups", user2)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
private_subgroups = json_response.select { |group| group['visibility'] == 'private' }
expect(private_subgroups.length).to eq(1)
expect(private_subgroups.first['id']).to eq(subgroup2.id)
expect(private_subgroups.first['parent_id']).to eq(group1.id)
end
context 'when using statistics in request' do
2023-06-20 00:43:36 +05:30
it 'does not include statistics', :aggregate_failures do
2019-02-15 15:39:39 +05:30
get api("/groups/#{group1.id}/subgroups", user2), params: { statistics: true }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.first).not_to include 'statistics'
end
end
end
context 'when user is member of private group' do
before do
group2.add_guest(user1)
end
2023-06-20 00:43:36 +05:30
it 'returns subgroups', :aggregate_failures do
2018-03-17 18:26:18 +05:30
get api("/groups/#{group2.id}/subgroups", user1)
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(subgroup3.id)
expect(json_response.first['parent_id']).to eq(group2.id)
end
end
end
context 'when authenticated as admin' do
2023-06-20 00:43:36 +05:30
it 'returns private subgroups of a public group', :aggregate_failures do
get api("/groups/#{group1.id}/subgroups", admin, admin_mode: true)
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
end
2023-06-20 00:43:36 +05:30
it 'returns subgroups of a private group', :aggregate_failures do
get api("/groups/#{group2.id}/subgroups", admin, admin_mode: true)
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
end
2023-06-20 00:43:36 +05:30
it 'does not include statistics by default', :aggregate_failures do
get api("/groups/#{group1.id}/subgroups", admin, admin_mode: true)
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.first).not_to include('statistics')
end
2023-06-20 00:43:36 +05:30
it 'includes statistics if requested', :aggregate_failures do
get api("/groups/#{group1.id}/subgroups", admin, admin_mode: true), params: { statistics: true }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-03-17 18:26:18 +05:30
expect(json_response).to be_an Array
expect(json_response.first).to include('statistics')
2015-12-23 02:04:40 +05:30
end
end
2021-10-27 15:23:28 +05:30
it_behaves_like 'skips searching in full path' do
let(:parent) { group1 }
let(:endpoint) { api("/groups/#{group1.id}/subgroups", user1) }
end
2015-12-23 02:04:40 +05:30
end
2021-01-03 14:25:43 +05:30
describe 'GET /groups/:id/descendant_groups' do
let_it_be(:child_group1) { create(:group, parent: group1) }
let_it_be(:private_child_group1) { create(:group, :private, parent: group1) }
let_it_be(:sub_child_group1) { create(:group, parent: child_group1) }
let_it_be(:child_group2) { create(:group, :private, parent: group2) }
let_it_be(:sub_child_group2) { create(:group, :private, parent: child_group2) }
2021-09-30 23:02:18 +05:30
2021-01-03 14:25:43 +05:30
let(:response_groups) { json_response.map { |group| group['name'] } }
context 'when unauthenticated' do
2023-06-20 00:43:36 +05:30
it 'returns only public descendants', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group1.id}/descendant_groups")
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name)
end
it 'returns 404 for a private group' do
get api("/groups/#{group2.id}/descendant_groups")
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when authenticated as user' do
context 'when user is not member of a public group' do
2023-06-20 00:43:36 +05:30
it 'returns no descendants for the public group', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group1.id}/descendant_groups", user2)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(0)
end
context 'when using all_available in request' do
2023-06-20 00:43:36 +05:30
it 'returns public descendants', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group1.id}/descendant_groups", user2), params: { all_available: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name)
end
end
end
context 'when user is not member of a private group' do
it 'returns 404 for the private group' do
get api("/groups/#{group2.id}/descendant_groups", user1)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when user is member of public group' do
before do
group1.add_guest(user2)
end
2023-06-20 00:43:36 +05:30
it 'returns private descendants', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group1.id}/descendant_groups", user2)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(3)
expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name, private_child_group1.name)
end
context 'when using statistics in request' do
2023-06-20 00:43:36 +05:30
it 'does not include statistics', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group1.id}/descendant_groups", user2), params: { statistics: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.first).not_to include 'statistics'
end
end
end
context 'when user is member of private group' do
before do
group2.add_guest(user1)
end
2023-06-20 00:43:36 +05:30
it 'returns descendants', :aggregate_failures do
2021-01-03 14:25:43 +05:30
get api("/groups/#{group2.id}/descendant_groups", user1)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(response_groups).to contain_exactly(child_group2.name, sub_child_group2.name)
end
end
end
context 'when authenticated as admin' do
2023-06-20 00:43:36 +05:30
it 'returns private descendants of a public group', :aggregate_failures do
get api("/groups/#{group1.id}/descendant_groups", admin, admin_mode: true)
2021-01-03 14:25:43 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(3)
end
2023-06-20 00:43:36 +05:30
it 'returns descendants of a private group', :aggregate_failures do
get api("/groups/#{group2.id}/descendant_groups", admin, admin_mode: true)
2021-01-03 14:25:43 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
end
2023-06-20 00:43:36 +05:30
it 'does not include statistics by default', :aggregate_failures do
get api("/groups/#{group1.id}/descendant_groups", admin, admin_mode: true)
2021-01-03 14:25:43 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.first).not_to include('statistics')
end
2023-06-20 00:43:36 +05:30
it 'includes statistics if requested', :aggregate_failures do
get api("/groups/#{group1.id}/descendant_groups", admin, admin_mode: true), params: { statistics: true }
2021-01-03 14:25:43 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.first).to include('statistics')
end
end
2021-10-27 15:23:28 +05:30
it_behaves_like 'skips searching in full path' do
let(:parent) { group1 }
let(:endpoint) { api("/groups/#{group1.id}/descendant_groups", user1) }
end
2021-01-03 14:25:43 +05:30
end
2014-09-02 18:07:02 +05:30
describe "POST /groups" do
2020-04-08 14:13:33 +05:30
it_behaves_like 'group avatar upload' do
def make_upload_request
params = attributes_for_group_api(request_access_enabled: false).tap do |attrs|
attrs[:avatar] = fixture_file_upload(file_path)
end
2022-10-11 01:57:18 +05:30
workhorse_form_with_file(
api('/groups', user3),
method: :post,
file_key: :avatar,
params: params
)
2020-04-08 14:13:33 +05:30
end
end
2015-09-11 14:41:01 +05:30
context "when authenticated as user without group permissions" do
2016-09-13 17:45:13 +05:30
it "does not create group" do
2019-12-21 20:55:43 +05:30
group = attributes_for_group_api
post api("/groups", user1), params: group
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:forbidden)
2018-03-17 18:26:18 +05:30
end
2019-10-12 21:52:04 +05:30
context 'as owner' do
2018-03-17 18:26:18 +05:30
before do
group2.add_owner(user1)
end
it 'can create subgroups' do
2019-02-15 15:39:39 +05:30
post api("/groups", user1), params: { parent_id: group2.id, name: 'foo', path: 'foo' }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2018-03-17 18:26:18 +05:30
end
end
2019-10-12 21:52:04 +05:30
context 'as maintainer' do
2018-03-17 18:26:18 +05:30
before do
2018-11-18 11:00:15 +05:30
group2.add_maintainer(user1)
2018-03-17 18:26:18 +05:30
end
2019-10-12 21:52:04 +05:30
it 'can create subgroups' do
2019-02-15 15:39:39 +05:30
post api("/groups", user1), params: { parent_id: group2.id, name: 'foo', path: 'foo' }
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2018-03-17 18:26:18 +05:30
end
2014-09-02 18:07:02 +05:30
end
end
2015-09-11 14:41:01 +05:30
context "when authenticated as user with group permissions" do
2023-06-20 00:43:36 +05:30
it "creates group", :aggregate_failures do
2019-12-21 20:55:43 +05:30
group = attributes_for_group_api request_access_enabled: false
2016-09-29 09:46:39 +05:30
2019-02-15 15:39:39 +05:30
post api("/groups", user3), params: group
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2016-09-29 09:46:39 +05:30
expect(json_response["name"]).to eq(group[:name])
expect(json_response["path"]).to eq(group[:path])
expect(json_response["request_access_enabled"]).to eq(group[:request_access_enabled])
2018-03-17 18:26:18 +05:30
expect(json_response["visibility"]).to eq(Gitlab::VisibilityLevel.string_level(Gitlab::CurrentSettings.current_application_settings.default_group_visibility))
2014-09-02 18:07:02 +05:30
end
2023-06-20 00:43:36 +05:30
it "creates a nested group", :aggregate_failures do
2017-08-17 22:00:37 +05:30
parent = create(:group)
parent.add_owner(user3)
2019-12-21 20:55:43 +05:30
group = attributes_for_group_api parent_id: parent.id
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
post api("/groups", user3), params: group
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2017-08-17 22:00:37 +05:30
expect(json_response["full_path"]).to eq("#{parent.path}/#{group[:path]}")
expect(json_response["parent_id"]).to eq(parent.id)
end
2020-03-28 13:19:24 +05:30
context 'malicious group name' do
subject { post api("/groups", user3), params: group_params }
let(:group_params) { attributes_for_group_api name: "<SCRIPT>alert('ATTACKED!')</SCRIPT>", path: "unique-url" }
it 'returns bad request' do
subject
expect(response).to have_gitlab_http_status(:bad_request)
end
it { expect { subject }.not_to change { Group.count } }
end
2020-05-24 23:13:21 +05:30
context 'when creating a group with `default_branch_protection` attribute' do
let(:params) { attributes_for_group_api default_branch_protection: Gitlab::Access::PROTECTION_NONE }
subject { post api("/groups", user3), params: params }
context 'for users who have the ability to create a group with `default_branch_protection`' do
2023-06-20 00:43:36 +05:30
it 'creates group with the specified branch protection level', :aggregate_failures do
2020-05-24 23:13:21 +05:30
subject
expect(response).to have_gitlab_http_status(:created)
expect(json_response['default_branch_protection']).to eq(Gitlab::Access::PROTECTION_NONE)
end
end
context 'for users who do not have the ability to create a group with `default_branch_protection`' do
2023-06-20 00:43:36 +05:30
it 'does not create the group with the specified branch protection level', :aggregate_failures do
2020-05-24 23:13:21 +05:30
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user3, :create_group_with_default_branch_protection) { false }
subject
expect(response).to have_gitlab_http_status(:created)
expect(json_response['default_branch_protection']).not_to eq(Gitlab::Access::PROTECTION_NONE)
end
end
end
2023-06-20 00:43:36 +05:30
it "does not create group, duplicate", :aggregate_failures do
2019-02-15 15:39:39 +05:30
post api("/groups", user3), params: { name: 'Duplicate Test', path: group2.path }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:bad_request)
2015-04-26 12:48:37 +05:30
expect(response.message).to eq("Bad Request")
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "returns 400 bad request error if name not given" do
2019-02-15 15:39:39 +05:30
post api("/groups", user3), params: { path: group2.path }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:bad_request)
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "returns 400 bad request error if path not given" do
2019-02-15 15:39:39 +05:30
post api("/groups", user3), params: { name: 'test' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:bad_request)
2014-09-02 18:07:02 +05:30
end
end
end
describe "DELETE /groups/:id" do
context "when authenticated as user" do
2016-09-13 17:45:13 +05:30
it "removes group" do
2018-11-08 19:23:39 +05:30
Sidekiq::Testing.fake! do
expect { delete api("/groups/#{group1.id}", user1) }.to change(GroupDestroyWorker.jobs, :size).by(1)
end
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:accepted)
2018-03-17 18:26:18 +05:30
end
it_behaves_like '412 response' do
let(:request) { api("/groups/#{group1.id}", user1) }
2018-11-08 19:23:39 +05:30
let(:success_status) { 202 }
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not remove a group if not an owner" do
2015-09-11 14:41:01 +05:30
user4 = create(:user)
2018-11-18 11:00:15 +05:30
group1.add_maintainer(user4)
2017-08-17 22:00:37 +05:30
2014-09-02 18:07:02 +05:30
delete api("/groups/#{group1.id}", user3)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:forbidden)
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not remove a non existing group" do
2021-09-04 01:27:46 +05:30
delete api("/groups/#{non_existing_record_id}", user1)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not remove a group not attached to user1" do
2014-09-02 18:07:02 +05:30
delete api("/groups/#{group2.id}", user1)
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2014-09-02 18:07:02 +05:30
end
end
context "when authenticated as admin" do
2016-09-13 17:45:13 +05:30
it "removes any existing group" do
2023-06-20 00:43:36 +05:30
delete api("/groups/#{group2.id}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:accepted)
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "does not remove a non existing group" do
2023-06-20 00:43:36 +05:30
delete api("/groups/#{non_existing_record_id}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2014-09-02 18:07:02 +05:30
end
end
end
describe "POST /groups/:id/projects/:project_id" do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
let(:project_path) { CGI.escape(project.full_path) }
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
before do
2020-01-01 13:55:28 +05:30
allow_next_instance_of(Projects::TransferService) do |instance|
allow(instance).to receive(:execute).and_return(true)
end
2014-09-02 18:07:02 +05:30
end
context "when authenticated as user" do
2016-09-13 17:45:13 +05:30
it "does not transfer project to group" do
2014-09-02 18:07:02 +05:30
post api("/groups/#{group1.id}/projects/#{project.id}", user2)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:forbidden)
2014-09-02 18:07:02 +05:30
end
end
context "when authenticated as admin" do
2016-09-13 17:45:13 +05:30
it "transfers project to group" do
2023-06-20 00:43:36 +05:30
post api("/groups/#{group1.id}/projects/#{project.id}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when using project path in URL' do
context 'with a valid project path' do
it "transfers project to group" do
2023-06-20 00:43:36 +05:30
post api("/groups/#{group1.id}/projects/#{project_path}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2017-08-17 22:00:37 +05:30
end
end
context 'with a non-existent project path' do
it "does not transfer project to group" do
2023-06-20 00:43:36 +05:30
post api("/groups/#{group1.id}/projects/nogroup%2Fnoproject", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2017-08-17 22:00:37 +05:30
end
end
end
context 'when using a group path in URL' do
context 'with a valid group path' do
it "transfers project to group" do
2023-06-20 00:43:36 +05:30
post api("/groups/#{group1.path}/projects/#{project_path}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:created)
2017-08-17 22:00:37 +05:30
end
end
context 'with a non-existent group path' do
it "does not transfer project to group" do
2023-06-20 00:43:36 +05:30
post api("/groups/noexist/projects/#{project_path}", admin, admin_mode: true)
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2017-08-17 22:00:37 +05:30
end
end
end
2014-09-02 18:07:02 +05:30
end
end
2018-03-17 18:26:18 +05:30
2022-10-11 01:57:18 +05:30
describe 'GET /groups/:id/transfer_locations' do
let_it_be(:user) { create(:user) }
let_it_be(:source_group) { create(:group, :private) }
let(:params) { {} }
subject(:request) do
get api("/groups/#{source_group.id}/transfer_locations", user), params: params
end
context 'when the user has rights to transfer the group' do
let_it_be(:guest_group) { create(:group) }
let_it_be(:maintainer_group) { create(:group, name: 'maintainer group', path: 'maintainer-group') }
let_it_be(:owner_group_1) { create(:group, name: 'owner group', path: 'owner-group') }
let_it_be(:owner_group_2) { create(:group, name: 'gitlab group', path: 'gitlab-group') }
let_it_be(:shared_with_group_where_direct_owner_as_owner) { create(:group) }
before do
source_group.add_owner(user)
guest_group.add_guest(user)
maintainer_group.add_maintainer(user)
owner_group_1.add_owner(user)
owner_group_2.add_owner(user)
create(:group_group_link, :owner,
shared_with_group: owner_group_1,
shared_group: shared_with_group_where_direct_owner_as_owner
)
end
it 'returns 200' do
request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
end
it 'only includes groups where the user has permissions to transfer a group to' do
request
expect(group_ids_from_response).to contain_exactly(
owner_group_1.id,
owner_group_2.id,
shared_with_group_where_direct_owner_as_owner.id
)
end
context 'with search' do
let(:params) { { search: 'gitlab' } }
it 'includes groups where the user has permissions to transfer a group to, matching the search term' do
request
expect(group_ids_from_response).to contain_exactly(owner_group_2.id)
end
end
def group_ids_from_response
json_response.map { |group| group['id'] }
end
end
context 'when the user does not have permissions to transfer the group' do
before do
source_group.add_developer(user)
end
it 'returns 403' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'for an anonymous user' do
let_it_be(:user) { nil }
it 'returns 404' do
request
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
2022-01-26 12:08:38 +05:30
describe 'POST /groups/:id/transfer' do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:new_parent_group) { create(:group, :private) }
let_it_be_with_reload(:group) { create(:group, :nested, :private) }
before do
new_parent_group.add_owner(user)
group.add_owner(user)
end
def make_request(user)
post api("/groups/#{group.id}/transfer", user), params: params
end
context 'when promoting a subgroup to a root group' do
shared_examples_for 'promotes the subgroup to a root group' do
2023-06-20 00:43:36 +05:30
it 'returns success', :aggregate_failures do
2022-01-26 12:08:38 +05:30
make_request(user)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['parent_id']).to be_nil
end
end
context 'when no group_id is specified' do
let(:params) {}
it_behaves_like 'promotes the subgroup to a root group'
end
context 'when group_id is specified as blank' do
let(:params) { { group_id: '' } }
it_behaves_like 'promotes the subgroup to a root group'
end
context 'when the group is already a root group' do
let(:group) { create(:group) }
let(:params) { { group_id: '' } }
2023-06-20 00:43:36 +05:30
it 'returns error', :aggregate_failures do
2022-01-26 12:08:38 +05:30
make_request(user)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq('Transfer failed: Group is already a root group.')
end
end
end
context 'when transferring a subgroup to a different group' do
let(:params) { { group_id: new_parent_group.id } }
context 'when the user does not have admin rights to the group being transferred' do
it 'forbids the operation' do
developer_user = create(:user)
group.add_developer(developer_user)
make_request(developer_user)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when the user does not have access to the new parent group' do
it 'fails with 404' do
user_without_access_to_new_parent_group = create(:user)
group.add_owner(user_without_access_to_new_parent_group)
make_request(user_without_access_to_new_parent_group)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when the ID of a non-existent group is mentioned as the new parent group' do
let(:params) { { group_id: non_existing_record_id } }
it 'fails with 404' do
make_request(user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when the transfer fails due to an error' do
before do
expect_next_instance_of(::Groups::TransferService) do |service|
expect(service).to receive(:proceed_to_transfer).and_raise(Gitlab::UpdatePathError, 'namespace directory cannot be moved')
end
end
2023-06-20 00:43:36 +05:30
it 'returns error', :aggregate_failures do
2022-01-26 12:08:38 +05:30
make_request(user)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq('Transfer failed: namespace directory cannot be moved')
end
end
context 'when the transfer succceds' do
2023-06-20 00:43:36 +05:30
it 'returns success', :aggregate_failures do
2022-01-26 12:08:38 +05:30
make_request(user)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['parent_id']).to eq(new_parent_group.id)
end
end
end
end
2018-03-17 18:26:18 +05:30
it_behaves_like 'custom attributes endpoints', 'groups' do
let(:attributable) { group1 }
let(:other_attributable) { group2 }
let(:user) { user1 }
before do
group2.add_owner(user1)
end
end
2020-06-23 00:09:42 +05:30
describe "POST /groups/:id/share" do
shared_examples 'shares group with group' do
2023-06-20 00:43:36 +05:30
let_it_be(:admin_mode) { false }
it "shares group with group", :aggregate_failures do
2020-06-23 00:09:42 +05:30
expires_at = 10.days.from_now.to_date
expect do
2023-06-20 00:43:36 +05:30
post api("/groups/#{group.id}/share", user, admin_mode: admin_mode), params: { group_id: shared_with_group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at }
2020-06-23 00:09:42 +05:30
end.to change { group.shared_with_group_links.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['shared_with_groups']).to be_an Array
expect(json_response['shared_with_groups'].length).to eq(1)
expect(json_response['shared_with_groups'][0]['group_id']).to eq(shared_with_group.id)
expect(json_response['shared_with_groups'][0]['group_name']).to eq(shared_with_group.name)
expect(json_response['shared_with_groups'][0]['group_full_path']).to eq(shared_with_group.full_path)
expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(Gitlab::Access::DEVELOPER)
expect(json_response['shared_with_groups'][0]['expires_at']).to eq(expires_at.to_s)
end
it "returns a 400 error when group id is not given" do
post api("/groups/#{group.id}/share", user), params: { group_access: Gitlab::Access::DEVELOPER }
expect(response).to have_gitlab_http_status(:bad_request)
end
it "returns a 400 error when access level is not given" do
post api("/groups/#{group.id}/share", user), params: { group_id: shared_with_group.id }
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns a 404 error when group does not exist' do
post api("/groups/#{group.id}/share", user), params: { group_id: non_existing_record_id, group_access: Gitlab::Access::DEVELOPER }
expect(response).to have_gitlab_http_status(:not_found)
end
2023-06-20 00:43:36 +05:30
it "returns a 400 error when wrong params passed", :aggregate_failures do
2020-06-23 00:09:42 +05:30
post api("/groups/#{group.id}/share", user), params: { group_id: shared_with_group.id, group_access: non_existing_record_access_level }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'group_access does not have a valid value'
end
it "returns a 409 error when link is not saved" do
allow(::Groups::GroupLinks::CreateService).to receive_message_chain(:new, :execute)
.and_return({ status: :error, http_status: 409, message: 'error' })
post api("/groups/#{group.id}/share", user), params: { group_id: shared_with_group.id, group_access: Gitlab::Access::DEVELOPER }
expect(response).to have_gitlab_http_status(:conflict)
end
end
context 'when authenticated as owner' do
let(:owner_group) { create(:group) }
let(:owner_user) { create(:user) }
before do
owner_group.add_owner(owner_user)
end
it_behaves_like 'shares group with group' do
let(:user) { owner_user }
let(:group) { owner_group }
let(:shared_with_group) { create(:group) }
end
end
context 'when the user is not the owner of the group' do
let(:group) { create(:group) }
let(:user4) { create(:user) }
let(:expires_at) { 10.days.from_now.to_date }
before do
group1.add_maintainer(user4)
end
it 'does not create group share' do
post api("/groups/#{group1.id}/share", user4), params: { group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at }
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when authenticated as admin' do
it_behaves_like 'shares group with group' do
let(:user) { admin }
let(:group) { create(:group) }
let(:shared_with_group) { create(:group) }
2023-06-20 00:43:36 +05:30
let(:admin_mode) { true }
2020-06-23 00:09:42 +05:30
end
end
end
describe 'DELETE /groups/:id/share/:group_id' do
shared_examples 'deletes group share' do
2023-06-20 00:43:36 +05:30
let_it_be(:admin_mode) { false }
it 'deletes a group share', :aggregate_failures do
2020-06-23 00:09:42 +05:30
expect do
2023-06-20 00:43:36 +05:30
delete api("/groups/#{shared_group.id}/share/#{shared_with_group.id}", user, admin_mode: admin_mode)
2020-06-23 00:09:42 +05:30
expect(response).to have_gitlab_http_status(:no_content)
expect(shared_group.shared_with_group_links).to be_empty
end.to change { shared_group.shared_with_group_links.count }.by(-1)
end
it 'requires the group id to be an integer' do
delete api("/groups/#{shared_group.id}/share/foo", user)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns a 404 error when group link does not exist' do
delete api("/groups/#{shared_group.id}/share/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
end
it 'returns a 404 error when group does not exist' do
delete api("/groups/123/share/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when authenticated as owner' do
let(:group_a) { create(:group) }
before do
create(:group_group_link, shared_group: group1, shared_with_group: group_a)
end
it_behaves_like 'deletes group share' do
let(:user) { user1 }
let(:shared_group) { group1 }
let(:shared_with_group) { group_a }
end
end
context 'when the user is not the owner of the group' do
let(:group_a) { create(:group) }
let(:user4) { create(:user) }
before do
group1.add_maintainer(user4)
create(:group_group_link, shared_group: group1, shared_with_group: group_a)
end
2023-06-20 00:43:36 +05:30
it 'does not remove group share', :aggregate_failures do
2020-06-23 00:09:42 +05:30
expect do
delete api("/groups/#{group1.id}/share/#{group_a.id}", user4)
expect(response).to have_gitlab_http_status(:no_content)
end.not_to change { group1.shared_with_group_links }
end
end
context 'when authenticated as admin' do
let(:group_b) { create(:group) }
before do
create(:group_group_link, shared_group: group2, shared_with_group: group_b)
end
it_behaves_like 'deletes group share' do
let(:user) { admin }
let(:shared_group) { group2 }
let(:shared_with_group) { group_b }
2023-06-20 00:43:36 +05:30
let(:admin_mode) { true }
2020-06-23 00:09:42 +05:30
end
end
end
2014-09-02 18:07:02 +05:30
end