Use linear version of User#ci_owned_runners

In this commit we're adding a feature flag
to test the linear version of the
User#ci_owned_runners method.

Changelog: performance
parent fabcc24b
......@@ -1614,8 +1614,14 @@ class User < ApplicationRecord
.joins(:runner)
.select('ci_runners.*')
base_and_descendants = if Feature.enabled?(:linear_user_ci_owned_runners, self, default_enabled: :yaml)
owned_groups.self_and_descendant_ids
else
Gitlab::ObjectHierarchy.new(owned_groups).base_and_descendants.select(:id)
end
group_runners = Ci::RunnerNamespace
.where(namespace_id: Gitlab::ObjectHierarchy.new(owned_groups).base_and_descendants.select(:id))
.where(namespace_id: base_and_descendants)
.joins(:runner)
.select('ci_runners.*')
......
---
name: linear_user_ci_owned_runners
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68848
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339435
milestone: '14.6'
type: development
group: group::access
default_enabled: false
......@@ -3673,309 +3673,321 @@ RSpec.describe User do
end
describe '#ci_owned_runners' do
let(:user) { create(:user) }
shared_examples 'ci_owned_runners examples' do
let(:user) { create(:user) }
shared_examples :nested_groups_owner do
context 'when the user is the owner of a multi-level group' do
before do
set_permissions_for_users
end
shared_examples :nested_groups_owner do
context 'when the user is the owner of a multi-level group' do
before do
set_permissions_for_users
end
it 'loads all the runners in the tree of groups' do
expect(user.ci_owned_runners).to contain_exactly(runner, group_runner)
end
it 'loads all the runners in the tree of groups' do
expect(user.ci_owned_runners).to contain_exactly(runner, group_runner)
end
it 'returns true for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(true)
expect(user.owns_runner?(group_runner)).to eq(true)
it 'returns true for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(true)
expect(user.owns_runner?(group_runner)).to eq(true)
end
end
end
end
shared_examples :group_owner do
context 'when the user is the owner of a one level group' do
before do
group.add_owner(user)
end
shared_examples :group_owner do
context 'when the user is the owner of a one level group' do
before do
group.add_owner(user)
end
it 'loads the runners in the group' do
expect(user.ci_owned_runners).to contain_exactly(group_runner)
end
it 'loads the runners in the group' do
expect(user.ci_owned_runners).to contain_exactly(group_runner)
end
it 'returns true for owns_runner?' do
expect(user.owns_runner?(group_runner)).to eq(true)
it 'returns true for owns_runner?' do
expect(user.owns_runner?(group_runner)).to eq(true)
end
end
end
end
shared_examples :project_owner do
context 'when the user is the owner of a project' do
it 'loads the runner belonging to the project' do
expect(user.ci_owned_runners).to contain_exactly(runner)
end
shared_examples :project_owner do
context 'when the user is the owner of a project' do
it 'loads the runner belonging to the project' do
expect(user.ci_owned_runners).to contain_exactly(runner)
end
it 'returns true for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(true)
it 'returns true for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(true)
end
end
end
end
shared_examples :project_member do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
end
shared_examples :project_member do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
end
it 'loads the runners of the project' do
expect(user.ci_owned_runners).to contain_exactly(project_runner)
end
it 'loads the runners of the project' do
expect(user.ci_owned_runners).to contain_exactly(project_runner)
end
it 'returns true for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(true)
it 'returns true for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(true)
end
end
end
context 'when the user is a developer' do
before do
add_user(:developer)
end
context 'when the user is a developer' do
before do
add_user(:developer)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
end
end
end
context 'when the user is a reporter' do
before do
add_user(:reporter)
end
context 'when the user is a reporter' do
before do
add_user(:reporter)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
end
end
end
context 'when the user is a guest' do
before do
add_user(:guest)
end
context 'when the user is a guest' do
before do
add_user(:guest)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(project_runner)).to eq(false)
end
end
end
end
shared_examples :group_member do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
end
shared_examples :group_member do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
end
it 'does not load the runners of the group' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load the runners of the group' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
end
end
end
context 'when the user is a developer' do
before do
add_user(:developer)
end
context 'when the user is a developer' do
before do
add_user(:developer)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
end
end
end
context 'when the user is a reporter' do
before do
add_user(:reporter)
end
context 'when the user is a reporter' do
before do
add_user(:reporter)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
end
end
end
context 'when the user is a guest' do
before do
add_user(:guest)
context 'when the user is a guest' do
before do
add_user(:guest)
end
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
end
end
end
context 'without any projects nor groups' do
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
it 'returns false for owns_runner?' do
expect(user.owns_runner?(runner)).to eq(false)
expect(user.owns_runner?(create(:ci_runner))).to eq(false)
end
end
end
context 'without any projects nor groups' do
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
context 'with runner in a personal project' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:project) { create(:project, namespace: namespace) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
it 'returns false for owns_runner?' do
expect(user.owns_runner?(create(:ci_runner))).to eq(false)
it_behaves_like :project_owner
end
end
context 'with runner in a personal project' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:project) { create(:project, namespace: namespace) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with group runner in a non owned group' do
let!(:group) { create(:group) }
let!(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like :project_owner
end
context 'with group runner in a non owned group' do
let!(:group) { create(:group) }
let!(:runner) { create(:ci_runner, :group, groups: [group]) }
def add_user(access)
group.add_user(user, access)
end
def add_user(access)
group.add_user(user, access)
it_behaves_like :group_member
end
it_behaves_like :group_member
end
context 'with group runner in an owned group' do
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
context 'with group runner in an owned group' do
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like :group_owner
end
it_behaves_like :group_owner
end
context 'with group runner in an owned group and group runner in a different owner subgroup' do
let!(:group) { create(:group) }
let!(:runner) { create(:ci_runner, :group, groups: [group]) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:another_user) { create(:user) }
context 'with group runner in an owned group and group runner in a different owner subgroup' do
let!(:group) { create(:group) }
let!(:runner) { create(:ci_runner, :group, groups: [group]) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:another_user) { create(:user) }
def set_permissions_for_users
group.add_owner(user)
subgroup.add_owner(another_user)
end
def set_permissions_for_users
group.add_owner(user)
subgroup.add_owner(another_user)
it_behaves_like :nested_groups_owner
end
it_behaves_like :nested_groups_owner
end
context 'with personal project runner in an an owned group and a group runner in that same group' do
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:project) { create(:project, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with personal project runner in an an owned group and a group runner in that same group' do
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:project) { create(:project, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
def set_permissions_for_users
group.add_owner(user)
end
def set_permissions_for_users
group.add_owner(user)
it_behaves_like :nested_groups_owner
end
it_behaves_like :nested_groups_owner
end
context 'with personal project runner in an owned group and a group runner in a subgroup' do
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:project) { create(:project, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with personal project runner in an owned group and a group runner in a subgroup' do
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:project) { create(:project, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
def set_permissions_for_users
group.add_owner(user)
end
def set_permissions_for_users
group.add_owner(user)
it_behaves_like :nested_groups_owner
end
it_behaves_like :nested_groups_owner
end
context 'with personal project runner in an owned group in an owned namespace and a group runner in that group' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:project) { create(:project, namespace: namespace, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with personal project runner in an owned group in an owned namespace and a group runner in that group' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:project) { create(:project, namespace: namespace, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
def set_permissions_for_users
group.add_owner(user)
end
def set_permissions_for_users
group.add_owner(user)
it_behaves_like :nested_groups_owner
end
it_behaves_like :nested_groups_owner
end
context 'with personal project runner in an owned namespace, an owned group, a subgroup and a group runner in that subgroup' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:project) { create(:project, namespace: namespace, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with personal project runner in an owned namespace, an owned group, a subgroup and a group runner in that subgroup' do
let!(:namespace) { create(:user_namespace, owner: user) }
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:project) { create(:project, namespace: namespace, group: group) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
def set_permissions_for_users
group.add_owner(user)
end
def set_permissions_for_users
group.add_owner(user)
it_behaves_like :nested_groups_owner
end
it_behaves_like :nested_groups_owner
end
context 'with a project runner that belong to projects that belong to a not owned group' do
let!(:group) { create(:group) }
let!(:project) { create(:project, group: group) }
let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
context 'with a project runner that belong to projects that belong to a not owned group' do
let!(:group) { create(:group) }
let!(:project) { create(:project, group: group) }
let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
def add_user(access)
project.add_user(user, access)
end
def add_user(access)
project.add_user(user, access)
it_behaves_like :project_member
end
it_behaves_like :project_member
end
context 'with project runners that belong to projects that do not belong to any group' do
let!(:project) { create(:project) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'with project runners that belong to projects that do not belong to any group' do
let!(:project) { create(:project) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
end
end
context 'with a group runner that belongs to a subgroup of a group owned by another user' do
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:another_user) { create(:user) }
it 'does not load any runner' do
expect(user.ci_owned_runners).to be_empty
def add_user(access)
subgroup.add_user(user, access)
group.add_user(another_user, :owner)
end
it_behaves_like :group_member
end
end
context 'with a group runner that belongs to a subgroup of a group owned by another user' do
let!(:group) { create(:group) }
let!(:subgroup) { create(:group, parent: group) }
let!(:runner) { create(:ci_runner, :group, groups: [subgroup]) }
let!(:another_user) { create(:user) }
it_behaves_like 'ci_owned_runners examples'
def add_user(access)
subgroup.add_user(user, access)
group.add_user(another_user, :owner)
context 'when feature flag :linear_user_ci_owned_runners is disabled' do
before do
stub_feature_flags(linear_user_ci_owned_runners: false)
end
it_behaves_like :group_member
it_behaves_like 'ci_owned_runners examples'
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment