Commit 669fc74f authored by Markus Koller's avatar Markus Koller

Merge branch...

Merge branch '301013-factories-do-not-allow-subgroups-to-be-created-under-namespaces-allow-them-to-be-created' into 'master'

Resolve "Validate the nature of the parent for `Group` & `Namespace`"  [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!54094
parents 71f58295 796c75db
...@@ -63,6 +63,7 @@ class Namespace < ApplicationRecord ...@@ -63,6 +63,7 @@ class Namespace < ApplicationRecord
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true } validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
validate :validate_parent_type, if: -> { Feature.enabled?(:validate_namespace_parent_type) }
validate :nesting_level_allowed validate :nesting_level_allowed
validate :changing_shared_runners_enabled_is_allowed validate :changing_shared_runners_enabled_is_allowed
validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed
...@@ -448,6 +449,16 @@ class Namespace < ApplicationRecord ...@@ -448,6 +449,16 @@ class Namespace < ApplicationRecord
end end
end end
def validate_parent_type
return unless has_parent?
if user?
errors.add(:parent_id, 'a user namespace cannot have a parent')
elsif group?
errors.add(:parent_id, 'a group cannot have a user namespace as its parent') if parent.user?
end
end
def sync_share_with_group_lock_with_parent def sync_share_with_group_lock_with_parent
if parent&.share_with_group_lock? if parent&.share_with_group_lock?
self.share_with_group_lock = true self.share_with_group_lock = true
......
---
name: validate_namespace_parent_type
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54094
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/322101
milestone: '13.10'
type: development
group: group::access
default_enabled: false
...@@ -484,7 +484,6 @@ module EE ...@@ -484,7 +484,6 @@ module EE
def execute_subgroup_hooks(event) def execute_subgroup_hooks(event)
return unless subgroup? return unless subgroup?
return unless parent.group? # TODO: Remove this after fixing https://gitlab.com/gitlab-org/gitlab/-/issues/301013
return unless feature_available?(:group_webhooks) return unless feature_available?(:group_webhooks)
run_after_commit do run_after_commit do
......
...@@ -368,24 +368,31 @@ RSpec.describe ApplicationSetting do ...@@ -368,24 +368,31 @@ RSpec.describe ApplicationSetting do
end end
context 'namespaces' do context 'namespaces' do
let(:namespaces) { create_list(:namespace, 2) } context 'with personal namespaces' do
let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: namespaces.last } let(:namespaces) { create_list(:namespace, 2) }
let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: namespaces.last }
it 'tells you if a namespace is allowed to be indexed' do it 'tells you if a namespace is allowed to be indexed' do
expect(setting.elasticsearch_indexes_namespace?(namespaces.last)).to be_truthy expect(setting.elasticsearch_indexes_namespace?(namespaces.last)).to be_truthy
expect(setting.elasticsearch_indexes_namespace?(namespaces.first)).to be_falsey expect(setting.elasticsearch_indexes_namespace?(namespaces.first)).to be_falsey
end
end end
it 'returns namespaces that are allowed to be indexed' do context 'with groups' do
child_namespace = create(:namespace, parent: namespaces.first) let(:groups) { create_list(:group, 2) }
create :elasticsearch_indexed_namespace, namespace: child_namespace let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: groups.last }
it 'returns groups that are allowed to be indexed' do
child_group = create(:group, parent: groups.first)
create :elasticsearch_indexed_namespace, namespace: child_group
child_namespace_indexed_through_parent = create(:namespace, parent: namespaces.last) child_group_indexed_through_parent = create(:group, parent: groups.last)
expect(setting.elasticsearch_limited_namespaces).to match_array( expect(setting.elasticsearch_limited_namespaces).to match_array(
[namespaces.last, child_namespace, child_namespace_indexed_through_parent]) [groups.last, child_group, child_group_indexed_through_parent])
expect(setting.elasticsearch_limited_namespaces(true)).to match_array( expect(setting.elasticsearch_limited_namespaces(true)).to match_array(
[namespaces.last, child_namespace]) [groups.last, child_group])
end
end end
describe '#elasticsearch_indexes_project?' do describe '#elasticsearch_indexes_project?' do
......
...@@ -222,12 +222,13 @@ RSpec.describe Namespace do ...@@ -222,12 +222,13 @@ RSpec.describe Namespace do
describe '.eligible_for_subscription' do describe '.eligible_for_subscription' do
let_it_be(:namespace) { create :namespace } let_it_be(:namespace) { create :namespace }
let_it_be(:sub_namespace) { create(:namespace, parent: namespace) } let_it_be(:group) { create :group }
let_it_be(:subgroup) { create(:group, parent: group) }
subject { described_class.eligible_for_subscription.ids } subject { described_class.eligible_for_subscription.ids }
context 'when there is no subscription' do context 'when there is no subscription' do
it { is_expected.to eq([namespace.id]) } it { is_expected.to contain_exactly(group.id, namespace.id) }
end end
context 'when there is a subscription' do context 'when there is a subscription' do
...@@ -238,28 +239,31 @@ RSpec.describe Namespace do ...@@ -238,28 +239,31 @@ RSpec.describe Namespace do
context 'and has not yet been trialed' do context 'and has not yet been trialed' do
before do before do
create :gitlab_subscription, plan, namespace: namespace create :gitlab_subscription, plan, namespace: namespace
create :gitlab_subscription, plan, namespace: sub_namespace create :gitlab_subscription, plan, namespace: group
create :gitlab_subscription, plan, namespace: subgroup
end end
it { is_expected.to eq([namespace.id]) } it { is_expected.to contain_exactly(group.id, namespace.id) }
end end
context 'but has already had a trial' do context 'but has already had a trial' do
before do before do
create :gitlab_subscription, plan, :expired_trial, namespace: namespace create :gitlab_subscription, plan, namespace: namespace
create :gitlab_subscription, plan, :expired_trial, namespace: sub_namespace create :gitlab_subscription, plan, :expired_trial, namespace: group
create :gitlab_subscription, plan, :expired_trial, namespace: subgroup
end end
it { is_expected.to eq([namespace.id]) } it { is_expected.to contain_exactly(group.id, namespace.id) }
end end
context 'but is currently being trialed' do context 'but is currently being trialed' do
before do before do
create :gitlab_subscription, plan, :active_trial, namespace: namespace create :gitlab_subscription, plan, namespace: namespace
create :gitlab_subscription, plan, :active_trial, namespace: sub_namespace create :gitlab_subscription, plan, :active_trial, namespace: group
create :gitlab_subscription, plan, :active_trial, namespace: subgroup
end end
it { is_expected.to eq([namespace.id]) } it { is_expected.to contain_exactly(group.id, namespace.id) }
end end
end end
end end
...@@ -277,10 +281,11 @@ RSpec.describe Namespace do ...@@ -277,10 +281,11 @@ RSpec.describe Namespace do
with_them do with_them do
before do before do
create :gitlab_subscription, plan_name, :active_trial, namespace: namespace create :gitlab_subscription, plan_name, :active_trial, namespace: namespace
create :gitlab_subscription, plan_name, :active_trial, namespace: sub_namespace create :gitlab_subscription, plan_name, :active_trial, namespace: group
create :gitlab_subscription, plan_name, :active_trial, namespace: subgroup
end end
it { is_expected.to eq([namespace.id]) } it { is_expected.to contain_exactly(group.id, namespace.id) }
end end
end end
...@@ -291,6 +296,7 @@ RSpec.describe Namespace do ...@@ -291,6 +296,7 @@ RSpec.describe Namespace do
context 'and has not yet been trialed' do context 'and has not yet been trialed' do
before do before do
create :gitlab_subscription, plan, namespace: namespace create :gitlab_subscription, plan, namespace: namespace
create :gitlab_subscription, plan, namespace: group
end end
it { is_expected.to be_empty } it { is_expected.to be_empty }
...@@ -366,22 +372,23 @@ RSpec.describe Namespace do ...@@ -366,22 +372,23 @@ RSpec.describe Namespace do
describe '#validate_shared_runner_minutes_support' do describe '#validate_shared_runner_minutes_support' do
context 'when changing :shared_runners_minutes_limit' do context 'when changing :shared_runners_minutes_limit' do
before do before do
namespace.shared_runners_minutes_limit = 100 group.shared_runners_minutes_limit = 100
end end
context 'when group is subgroup' do context 'when group is a subgroup' do
let_it_be(:root_ancestor) { create(:group) } let(:group) { create(:group, :nested) }
let(:namespace) { create(:namespace, parent: root_ancestor) }
it 'is invalid' do it 'is invalid' do
expect(namespace).not_to be_valid expect(group).not_to be_valid
expect(namespace.errors[:shared_runners_minutes_limit]).to include('is not supported for this namespace') expect(group.errors[:shared_runners_minutes_limit]).to include('is not supported for this namespace')
end end
end end
context 'when group is root' do context 'when group is root' do
let(:group) { create(:group) }
it 'is valid' do it 'is valid' do
expect(namespace).to be_valid expect(group).to be_valid
end end
end end
end end
...@@ -702,49 +709,54 @@ RSpec.describe Namespace do ...@@ -702,49 +709,54 @@ RSpec.describe Namespace do
allow(Gitlab).to receive(:com?).and_return(true) allow(Gitlab).to receive(:com?).and_return(true)
end end
context 'when namespace has a subscription associated' do context 'for personal namespaces' do
before do context 'when namespace has a subscription associated' do
create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan, start_date: start_date) before do
end create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan, start_date: start_date)
end
context 'when this subscription was purchased before EoA rollout (legacy)' do context 'when this subscription was purchased before EoA rollout (legacy)' do
let(:start_date) { GitlabSubscription::EOA_ROLLOUT_DATE.to_date - 3.days } let(:start_date) { GitlabSubscription::EOA_ROLLOUT_DATE.to_date - 3.days }
it 'returns the legacy plan from the subscription' do it 'returns the legacy plan from the subscription' do
expect(namespace.actual_plan).to eq(ultimate_plan) expect(namespace.actual_plan).to eq(ultimate_plan)
expect(namespace.gitlab_subscription).to be_present expect(namespace.gitlab_subscription).to be_present
end
end end
end
context 'when this subscription was purchase after EoA rollout (new plan)' do context 'when this subscription was purchase after EoA rollout (new plan)' do
let(:start_date) { GitlabSubscription::EOA_ROLLOUT_DATE.to_date + 3.days } let(:start_date) { GitlabSubscription::EOA_ROLLOUT_DATE.to_date + 3.days }
it 'returns the new plan from the subscription' do it 'returns the new plan from the subscription' do
expect(namespace.actual_plan).to be_an_instance_of(Subscriptions::NewPlanPresenter) expect(namespace.actual_plan).to be_an_instance_of(Subscriptions::NewPlanPresenter)
expect(namespace.gitlab_subscription).to be_present expect(namespace.gitlab_subscription).to be_present
end
end end
end end
end
context 'when namespace does not have a subscription associated' do
it 'generates a subscription and returns free plan' do
expect(namespace.actual_plan).to eq(Plan.free)
expect(namespace.gitlab_subscription).to be_present
end
context 'when free plan does exist' do context 'when namespace does not have a subscription associated' do
before do it 'generates a subscription and returns free plan' do
free_plan expect(namespace.actual_plan).to eq(Plan.free)
expect(namespace.gitlab_subscription).to be_present
end end
it 'generates a subscription' do context 'when free plan does exist' do
expect(namespace.actual_plan).to eq(free_plan) before do
expect(namespace.gitlab_subscription).to be_present free_plan
end
it 'generates a subscription' do
expect(namespace.actual_plan).to eq(free_plan)
expect(namespace.gitlab_subscription).to be_present
end
end end
end end
end
context 'when namespace is a subgroup with a parent' do context 'for groups' do
let(:subgroup) { create(:namespace, parent: namespace) } context 'when the group is a subgroup with a parent' do
let(:parent) { create(:group) }
let(:subgroup) { create(:group, parent: parent) }
context 'when free plan does exist' do context 'when free plan does exist' do
before do before do
...@@ -757,9 +769,9 @@ RSpec.describe Namespace do ...@@ -757,9 +769,9 @@ RSpec.describe Namespace do
end end
end end
context 'when namespace has a subscription associated' do context 'when parent group has a subscription associated' do
before do before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan) create(:gitlab_subscription, namespace: parent, hosted_plan: ultimate_plan)
end end
it 'returns the plan from the subscription' do it 'returns the plan from the subscription' do
...@@ -784,38 +796,43 @@ RSpec.describe Namespace do ...@@ -784,38 +796,43 @@ RSpec.describe Namespace do
allow(Gitlab).to receive(:com?).and_return(true) allow(Gitlab).to receive(:com?).and_return(true)
end end
context 'when namespace has a subscription associated' do context 'for personal namespaces' do
before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan)
end
it 'returns an associated plan name' do
expect(namespace.actual_plan_name).to eq 'ultimate'
end
end
context 'when namespace does not have subscription associated' do
it 'returns a free plan name' do
expect(namespace.actual_plan_name).to eq 'free'
end
end
context 'when namespace is a subgroup with a parent' do
let(:subgroup) { create(:namespace, parent: namespace) }
context 'when namespace has a subscription associated' do context 'when namespace has a subscription associated' do
before do before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan) create(:gitlab_subscription, namespace: namespace, hosted_plan: ultimate_plan)
end end
it 'returns an associated plan name' do it 'returns an associated plan name' do
expect(subgroup.actual_plan_name).to eq 'ultimate' expect(namespace.actual_plan_name).to eq 'ultimate'
end end
end end
context 'when namespace does not have subscription associated' do context 'when namespace does not have subscription associated' do
it 'returns a free plan name' do it 'returns a free plan name' do
expect(subgroup.actual_plan_name).to eq 'free' expect(namespace.actual_plan_name).to eq 'free'
end
end
end
context 'for groups' do
context 'when the group is a subgroup with a parent' do
let(:parent) { create(:group) }
let(:subgroup) { create(:group, parent: parent) }
context 'when parent group has a subscription associated' do
before do
create(:gitlab_subscription, namespace: parent, hosted_plan: ultimate_plan)
end
it 'returns an associated plan name' do
expect(subgroup.actual_plan_name).to eq 'ultimate'
end
end
context 'when parent group does not have subscription associated' do
it 'returns a free plan name' do
expect(subgroup.actual_plan_name).to eq 'free'
end
end end
end end
end end
...@@ -1584,46 +1601,64 @@ RSpec.describe Namespace do ...@@ -1584,46 +1601,64 @@ RSpec.describe Namespace do
end end
describe '#closest_gitlab_subscription' do describe '#closest_gitlab_subscription' do
subject { namespace.closest_gitlab_subscription } subject { group.closest_gitlab_subscription }
context 'when there is a root ancestor' do context 'when there is a root ancestor' do
let(:namespace) { create(:namespace, parent: root) } let(:group) { create(:group, parent: root) }
context 'when root has a subscription' do context 'when root has a subscription' do
let(:root) { create(:namespace_with_plan) } let(:root) { create(:group_with_plan) }
it { is_expected.to be_a(GitlabSubscription) } it { is_expected.to be_a(GitlabSubscription) }
end end
context 'when root has no subscription' do context 'when root has no subscription' do
let(:root) { create(:namespace) } let(:root) { create(:group) }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
end end
context 'when there is no root ancestor' do context 'when there is no root ancestor' do
context 'has a subscription' do context 'for groups' do
let(:namespace) { create(:namespace_with_plan) } context 'has a subscription' do
let(:group) { create(:group_with_plan) }
it { is_expected.to be_a(GitlabSubscription) } it { is_expected.to be_a(GitlabSubscription) }
end
context 'it has no subscription' do
let(:group) { create(:group) }
it { is_expected.to be_nil }
end
end end
context 'it has no subscription' do context 'for personal namespaces' do
let(:namespace) { create(:namespace) } subject { namespace.closest_gitlab_subscription }
it { is_expected.to be_nil } context 'has a subscription' do
let(:namespace) { create(:namespace_with_plan) }
it { is_expected.to be_a(GitlabSubscription) }
end
context 'it has no subscription' do
let(:namespace) { create(:namespace) }
it { is_expected.to be_nil }
end
end end
end end
end end
describe '#namespace_limit' do describe '#namespace_limit' do
let(:namespace) { create(:namespace, parent: parent) } let(:group) { create(:group, parent: parent) }
subject(:namespace_limit) { namespace.namespace_limit } subject(:namespace_limit) { group.namespace_limit }
context 'when there is a parent namespace' do context 'when there is a parent namespace' do
let_it_be(:parent) { create(:namespace) } let_it_be(:parent) { create(:group) }
context 'with a namespace limit' do context 'with a namespace limit' do
it 'returns the parent namespace limit' do it 'returns the parent namespace limit' do
...@@ -1645,19 +1680,43 @@ RSpec.describe Namespace do ...@@ -1645,19 +1680,43 @@ RSpec.describe Namespace do
context 'when there is no parent ancestor' do context 'when there is no parent ancestor' do
let(:parent) { nil } let(:parent) { nil }
context 'with a namespace limit' do context 'for personal namespaces' do
it 'returns the namespace limit' do let(:namespace) { create(:namespace, parent: parent) }
limit = create(:namespace_limit, namespace: namespace)
expect(namespace_limit).to be_persisted subject(:namespace_limit) { namespace.namespace_limit }
expect(namespace_limit).to eq limit
context 'with a namespace limit' do
it 'returns the namespace limit' do
limit = create(:namespace_limit, namespace: namespace)
expect(namespace_limit).to be_persisted
expect(namespace_limit).to eq limit
end
end
context 'with no namespace limit' do
it 'builds namespace limit' do
expect(namespace_limit).to be_present
expect(namespace_limit).not_to be_persisted
end
end end
end end
context 'with no namespace limit' do context 'for groups' do
it 'builds namespace limit' do context 'with a namespace limit' do
expect(namespace_limit).to be_present it 'returns the namespace limit' do
expect(namespace_limit).not_to be_persisted limit = create(:namespace_limit, namespace: group)
expect(namespace_limit).to be_persisted
expect(namespace_limit).to eq limit
end
end
context 'with no namespace limit' do
it 'builds namespace limit' do
expect(namespace_limit).to be_present
expect(namespace_limit).not_to be_persisted
end
end end
end end
end end
......
...@@ -34,17 +34,22 @@ RSpec.describe ComplianceManagement::Frameworks::CreateService do ...@@ -34,17 +34,22 @@ RSpec.describe ComplianceManagement::Frameworks::CreateService do
end end
context 'namespace has a parent' do context 'namespace has a parent' do
let_it_be_with_reload(:namespace) { create(:namespace, :with_hierarchy) } let_it_be(:user) { create(:user) }
let(:descendant) { namespace.descendants.first } let_it_be_with_reload(:group) { create(:group, :with_hierarchy) }
let(:descendant) { group.descendants.first }
subject { described_class.new(namespace: descendant, params: params, current_user: namespace.owner) } before do
group.add_owner(user)
end
subject { described_class.new(namespace: descendant, params: params, current_user: user) }
it 'responds with a successful service response' do it 'responds with a successful service response' do
expect(subject.execute.success?).to be true expect(subject.execute.success?).to be true
end end
it 'creates the new framework in the root namespace' do it 'creates the new framework in the root namespace' do
expect(subject.execute.payload[:framework].namespace).to eq(namespace) expect(subject.execute.payload[:framework].namespace).to eq(group)
end end
end end
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
require "spec_helper" require "spec_helper"
RSpec.describe Projects::UpdatePagesService do RSpec.describe Projects::UpdatePagesService do
let(:root_namespace) { create(:namespace, max_pages_size: 300) } let(:group) { create(:group, :nested, max_pages_size: 200) }
let(:namespace) { create(:namespace, parent: root_namespace, max_pages_size: 200) } let(:project) { create(:project, :repository, namespace: group, max_pages_size: 250) }
let(:project) { create(:project, :repository, namespace: namespace, max_pages_size: 250) }
let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) } let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
let(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') } let(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') }
......
...@@ -61,5 +61,35 @@ FactoryBot.define do ...@@ -61,5 +61,35 @@ FactoryBot.define do
trait :allow_descendants_override_disabled_shared_runners do trait :allow_descendants_override_disabled_shared_runners do
allow_descendants_override_disabled_shared_runners { true } allow_descendants_override_disabled_shared_runners { true }
end end
# Construct a hierarchy underneath the group.
# Each group will have `children` amount of children,
# and `depth` levels of descendants.
trait :with_hierarchy do
transient do
children { 4 }
depth { 4 }
end
after(:create) do |group, evaluator|
def create_graph(parent: nil, children: 4, depth: 4)
return unless depth > 1
children.times do
factory_name = parent.model_name.singular
child = FactoryBot.create(factory_name, parent: parent)
create_graph(parent: child, children: children, depth: depth - 1)
end
parent
end
create_graph(
parent: group,
children: evaluator.children,
depth: evaluator.depth
)
end
end
end end
end end
...@@ -34,36 +34,6 @@ FactoryBot.define do ...@@ -34,36 +34,6 @@ FactoryBot.define do
association :namespace_settings, factory: :namespace_settings association :namespace_settings, factory: :namespace_settings
end end
# Construct a hierarchy underneath the namespace.
# Each namespace will have `children` amount of children,
# and `depth` levels of descendants.
trait :with_hierarchy do
transient do
children { 4 }
depth { 4 }
end
after(:create) do |namespace, evaluator|
def create_graph(parent: nil, children: 4, depth: 4)
return unless depth > 1
children.times do
factory_name = parent.model_name.singular
child = FactoryBot.create(factory_name, parent: parent)
create_graph(parent: child, children: children, depth: depth - 1)
end
parent
end
create_graph(
parent: namespace,
children: evaluator.children,
depth: evaluator.depth
)
end
end
trait :shared_runners_disabled do trait :shared_runners_disabled do
shared_runners_enabled { false } shared_runners_enabled { false }
end end
......
...@@ -81,7 +81,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, : ...@@ -81,7 +81,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :
end end
describe '#rename_path_for_routable' do describe '#rename_path_for_routable' do
context 'for namespaces' do context 'for personal namespaces' do
let(:namespace) { create(:namespace, path: 'the-path') } let(:namespace) { create(:namespace, path: 'the-path') }
it "renames namespaces called the-path" do it "renames namespaces called the-path" do
...@@ -119,13 +119,16 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, : ...@@ -119,13 +119,16 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :
expect(project.route.reload.path).to eq('the-path-but-not-really/the-project') expect(project.route.reload.path).to eq('the-path-but-not-really/the-project')
end end
end
context "the-path namespace -> subgroup -> the-path0 project" do context 'for groups' do
context "the-path group -> subgroup -> the-path0 project" do
it "updates the route of the project correctly" do it "updates the route of the project correctly" do
subgroup = create(:group, path: "subgroup", parent: namespace) group = create(:group, path: 'the-path')
subgroup = create(:group, path: "subgroup", parent: group)
project = create(:project, :repository, path: "the-path0", namespace: subgroup) project = create(:project, :repository, path: "the-path0", namespace: subgroup)
subject.rename_path_for_routable(migration_namespace(namespace)) subject.rename_path_for_routable(migration_namespace(group))
expect(project.route.reload.path).to eq("the-path0/subgroup/the-path0") expect(project.route.reload.path).to eq("the-path0/subgroup/the-path0")
end end
...@@ -158,23 +161,27 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, : ...@@ -158,23 +161,27 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :
end end
describe '#perform_rename' do describe '#perform_rename' do
describe 'for namespaces' do context 'for personal namespaces' do
let(:namespace) { create(:namespace, path: 'the-path') }
it 'renames the path' do it 'renames the path' do
namespace = create(:namespace, path: 'the-path')
subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed')
expect(namespace.reload.path).to eq('renamed') expect(namespace.reload.path).to eq('renamed')
expect(namespace.reload.route.path).to eq('renamed')
end end
end
it 'renames all the routes for the namespace' do context 'for groups' do
child = create(:group, path: 'child', parent: namespace) it 'renames all the routes for the group' do
group = create(:group, path: 'the-path')
child = create(:group, path: 'child', parent: group)
project = create(:project, :repository, namespace: child, path: 'the-project') project = create(:project, :repository, namespace: child, path: 'the-project')
other_one = create(:namespace, path: 'the-path-is-similar') other_one = create(:group, path: 'the-path-is-similar')
subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') subject.perform_rename(migration_namespace(group), 'the-path', 'renamed')
expect(namespace.reload.route.path).to eq('renamed') expect(group.reload.route.path).to eq('renamed')
expect(child.reload.route.path).to eq('renamed/child') expect(child.reload.route.path).to eq('renamed/child')
expect(project.reload.route.path).to eq('renamed/child/the-project') expect(project.reload.route.path).to eq('renamed/child/the-project')
expect(other_one.reload.route.path).to eq('the-path-is-similar') expect(other_one.reload.route.path).to eq('the-path-is-similar')
......
...@@ -64,6 +64,59 @@ RSpec.describe Group do ...@@ -64,6 +64,59 @@ RSpec.describe Group do
it { is_expected.to validate_presence_of :two_factor_grace_period } it { is_expected.to validate_presence_of :two_factor_grace_period }
it { is_expected.to validate_numericality_of(:two_factor_grace_period).is_greater_than_or_equal_to(0) } it { is_expected.to validate_numericality_of(:two_factor_grace_period).is_greater_than_or_equal_to(0) }
context 'validating the parent of a group' do
context 'when the group has no parent' do
it 'allows a group to have no parent associated with it' do
group = build(:group)
expect(group).to be_valid
end
end
context 'when the group has a parent' do
it 'does not allow a group to have a namespace as its parent' do
group = build(:group, parent: build(:namespace))
expect(group).not_to be_valid
expect(group.errors[:parent_id].first).to eq('a group cannot have a user namespace as its parent')
end
it 'allows a group to have another group as its parent' do
group = build(:group, parent: build(:group))
expect(group).to be_valid
end
end
context 'when the feature flag `validate_namespace_parent_type` is disabled' do
before do
stub_feature_flags(validate_namespace_parent_type: false)
end
context 'when the group has no parent' do
it 'allows a group to have no parent associated with it' do
group = build(:group)
expect(group).to be_valid
end
end
context 'when the group has a parent' do
it 'allows a group to have a namespace as its parent' do
group = build(:group, parent: build(:namespace))
expect(group).to be_valid
end
it 'allows a group to have another group as its parent' do
group = build(:group, parent: build(:group))
expect(group).to be_valid
end
end
end
end
describe 'path validation' do describe 'path validation' do
it 'rejects paths reserved on the root namespace when the group has no parent' do it 'rejects paths reserved on the root namespace when the group has no parent' do
group = build(:group, path: 'api') group = build(:group, path: 'api')
......
...@@ -3,41 +3,41 @@ ...@@ -3,41 +3,41 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Namespace::TraversalHierarchy, type: :model do RSpec.describe Namespace::TraversalHierarchy, type: :model do
let_it_be(:root, reload: true) { create(:namespace, :with_hierarchy) } let_it_be(:root, reload: true) { create(:group, :with_hierarchy) }
describe '.for_namespace' do describe '.for_namespace' do
let(:hierarchy) { described_class.for_namespace(namespace) } let(:hierarchy) { described_class.for_namespace(group) }
context 'with root group' do context 'with root group' do
let(:namespace) { root } let(:group) { root }
it { expect(hierarchy.root).to eq root } it { expect(hierarchy.root).to eq root }
end end
context 'with child group' do context 'with child group' do
let(:namespace) { root.children.first.children.first } let(:group) { root.children.first.children.first }
it { expect(hierarchy.root).to eq root } it { expect(hierarchy.root).to eq root }
end end
context 'with group outside of hierarchy' do context 'with group outside of hierarchy' do
let(:namespace) { create(:namespace) } let(:group) { create(:namespace) }
it { expect(hierarchy.root).not_to eq root } it { expect(hierarchy.root).not_to eq root }
end end
end end
describe '.new' do describe '.new' do
let(:hierarchy) { described_class.new(namespace) } let(:hierarchy) { described_class.new(group) }
context 'with root group' do context 'with root group' do
let(:namespace) { root } let(:group) { root }
it { expect(hierarchy.root).to eq root } it { expect(hierarchy.root).to eq root }
end end
context 'with child group' do context 'with child group' do
let(:namespace) { root.children.first } let(:group) { root.children.first }
it { expect { hierarchy }.to raise_error(StandardError, 'Must specify a root node') } it { expect { hierarchy }.to raise_error(StandardError, 'Must specify a root node') }
end end
......
...@@ -32,14 +32,68 @@ RSpec.describe Namespace do ...@@ -32,14 +32,68 @@ RSpec.describe Namespace do
it { is_expected.to validate_presence_of(:owner) } it { is_expected.to validate_presence_of(:owner) }
it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) } it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) }
context 'validating the parent of a namespace' do
context 'when the namespace has no parent' do
it 'allows a namespace to have no parent associated with it' do
namespace = build(:namespace)
expect(namespace).to be_valid
end
end
context 'when the namespace has a parent' do
it 'does not allow a namespace to have a group as its parent' do
namespace = build(:namespace, parent: build(:group))
expect(namespace).not_to be_valid
expect(namespace.errors[:parent_id].first).to eq('a user namespace cannot have a parent')
end
it 'does not allow a namespace to have another namespace as its parent' do
namespace = build(:namespace, parent: build(:namespace))
expect(namespace).not_to be_valid
expect(namespace.errors[:parent_id].first).to eq('a user namespace cannot have a parent')
end
end
context 'when the feature flag `validate_namespace_parent_type` is disabled' do
before do
stub_feature_flags(validate_namespace_parent_type: false)
end
context 'when the namespace has no parent' do
it 'allows a namespace to have no parent associated with it' do
namespace = build(:namespace)
expect(namespace).to be_valid
end
end
context 'when the namespace has a parent' do
it 'allows a namespace to have a group as its parent' do
namespace = build(:namespace, parent: build(:group))
expect(namespace).to be_valid
end
it 'allows a namespace to have another namespace as its parent' do
namespace = build(:namespace, parent: build(:namespace))
expect(namespace).to be_valid
end
end
end
end
it 'does not allow too deep nesting' do it 'does not allow too deep nesting' do
ancestors = (1..21).to_a ancestors = (1..21).to_a
nested = build(:namespace, parent: namespace) group = build(:group)
allow(nested).to receive(:ancestors).and_return(ancestors) allow(group).to receive(:ancestors).and_return(ancestors)
expect(nested).not_to be_valid expect(group).not_to be_valid
expect(nested.errors[:parent_id].first).to eq('has too deep level of nesting') expect(group.errors[:parent_id].first).to eq('has too deep level of nesting')
end end
describe 'reserved path validation' do describe 'reserved path validation' do
...@@ -172,45 +226,45 @@ RSpec.describe Namespace do ...@@ -172,45 +226,45 @@ RSpec.describe Namespace do
end end
describe '.search' do describe '.search' do
let_it_be(:first_namespace) { build(:namespace, name: 'my first namespace', path: 'old-path').tap(&:save!) } let_it_be(:first_group) { build(:group, name: 'my first namespace', path: 'old-path').tap(&:save!) }
let_it_be(:parent_namespace) { build(:namespace, name: 'my parent namespace', path: 'parent-path').tap(&:save!) } let_it_be(:parent_group) { build(:group, name: 'my parent namespace', path: 'parent-path').tap(&:save!) }
let_it_be(:second_namespace) { build(:namespace, name: 'my second namespace', path: 'new-path', parent: parent_namespace).tap(&:save!) } let_it_be(:second_group) { build(:group, name: 'my second namespace', path: 'new-path', parent: parent_group).tap(&:save!) }
let_it_be(:project_with_same_path) { create(:project, id: second_namespace.id, path: first_namespace.path) } let_it_be(:project_with_same_path) { create(:project, id: second_group.id, path: first_group.path) }
it 'returns namespaces with a matching name' do it 'returns namespaces with a matching name' do
expect(described_class.search('my first namespace')).to eq([first_namespace]) expect(described_class.search('my first namespace')).to eq([first_group])
end end
it 'returns namespaces with a partially matching name' do it 'returns namespaces with a partially matching name' do
expect(described_class.search('first')).to eq([first_namespace]) expect(described_class.search('first')).to eq([first_group])
end end
it 'returns namespaces with a matching name regardless of the casing' do it 'returns namespaces with a matching name regardless of the casing' do
expect(described_class.search('MY FIRST NAMESPACE')).to eq([first_namespace]) expect(described_class.search('MY FIRST NAMESPACE')).to eq([first_group])
end end
it 'returns namespaces with a matching path' do it 'returns namespaces with a matching path' do
expect(described_class.search('old-path')).to eq([first_namespace]) expect(described_class.search('old-path')).to eq([first_group])
end end
it 'returns namespaces with a partially matching path' do it 'returns namespaces with a partially matching path' do
expect(described_class.search('old')).to eq([first_namespace]) expect(described_class.search('old')).to eq([first_group])
end end
it 'returns namespaces with a matching path regardless of the casing' do it 'returns namespaces with a matching path regardless of the casing' do
expect(described_class.search('OLD-PATH')).to eq([first_namespace]) expect(described_class.search('OLD-PATH')).to eq([first_group])
end end
it 'returns namespaces with a matching route path' do it 'returns namespaces with a matching route path' do
expect(described_class.search('parent-path/new-path', include_parents: true)).to eq([second_namespace]) expect(described_class.search('parent-path/new-path', include_parents: true)).to eq([second_group])
end end
it 'returns namespaces with a partially matching route path' do it 'returns namespaces with a partially matching route path' do
expect(described_class.search('parent-path/new', include_parents: true)).to eq([second_namespace]) expect(described_class.search('parent-path/new', include_parents: true)).to eq([second_group])
end end
it 'returns namespaces with a matching route path regardless of the casing' do it 'returns namespaces with a matching route path regardless of the casing' do
expect(described_class.search('PARENT-PATH/NEW-PATH', include_parents: true)).to eq([second_namespace]) expect(described_class.search('PARENT-PATH/NEW-PATH', include_parents: true)).to eq([second_group])
end end
end end
...@@ -309,12 +363,13 @@ RSpec.describe Namespace do ...@@ -309,12 +363,13 @@ RSpec.describe Namespace do
describe '.top_most' do describe '.top_most' do
let_it_be(:namespace) { create(:namespace) } let_it_be(:namespace) { create(:namespace) }
let_it_be(:sub_namespace) { create(:namespace, parent: namespace) } let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
subject { described_class.top_most.ids } subject { described_class.top_most.ids }
it 'only contains root namespace' do it 'only contains root namespaces' do
is_expected.to eq([namespace.id]) is_expected.to contain_exactly(group.id, namespace.id)
end end
end end
...@@ -1259,14 +1314,14 @@ RSpec.describe Namespace do ...@@ -1259,14 +1314,14 @@ RSpec.describe Namespace do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
shared_examples_for 'fetching closest setting' do shared_examples_for 'fetching closest setting' do
let!(:root_namespace) { create(:namespace) } let!(:parent) { create(:group) }
let!(:namespace) { create(:namespace, parent: root_namespace) } let!(:group) { create(:group, parent: parent) }
let(:setting) { namespace.closest_setting(setting_name) } let(:setting) { group.closest_setting(setting_name) }
before do before do
root_namespace.update_attribute(setting_name, root_setting) parent.update_attribute(setting_name, root_setting)
namespace.update_attribute(setting_name, child_setting) group.update_attribute(setting_name, child_setting)
end end
it 'returns closest non-nil value' do it 'returns closest non-nil value' do
...@@ -1357,30 +1412,30 @@ RSpec.describe Namespace do ...@@ -1357,30 +1412,30 @@ RSpec.describe Namespace do
context 'with a parent' do context 'with a parent' do
context 'when parent has shared runners disabled' do context 'when parent has shared runners disabled' do
let(:parent) { create(:namespace, :shared_runners_disabled) } let(:parent) { create(:group, :shared_runners_disabled) }
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
it 'is invalid' do it 'is invalid' do
expect(sub_namespace).to be_invalid expect(group).to be_invalid
expect(sub_namespace.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled') expect(group.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled')
end end
end end
context 'when parent has shared runners disabled but allows override' do context 'when parent has shared runners disabled but allows override' do
let(:parent) { create(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) } let(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
it 'is valid' do it 'is valid' do
expect(sub_namespace).to be_valid expect(group).to be_valid
end end
end end
context 'when parent has shared runners enabled' do context 'when parent has shared runners enabled' do
let(:parent) { create(:namespace, shared_runners_enabled: true) } let(:parent) { create(:group, shared_runners_enabled: true) }
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
it 'is valid' do it 'is valid' do
expect(sub_namespace).to be_valid expect(group).to be_valid
end end
end end
end end
...@@ -1410,30 +1465,30 @@ RSpec.describe Namespace do ...@@ -1410,30 +1465,30 @@ RSpec.describe Namespace do
context 'with a parent' do context 'with a parent' do
context 'when parent does not allow shared runners' do context 'when parent does not allow shared runners' do
let(:parent) { create(:namespace, :shared_runners_disabled) } let(:parent) { create(:group, :shared_runners_disabled) }
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
it 'is invalid' do it 'is invalid' do
expect(sub_namespace).to be_invalid expect(group).to be_invalid
expect(sub_namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it') expect(group.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it')
end end
end end
context 'when parent allows shared runners and setting to true' do context 'when parent allows shared runners and setting to true' do
let(:parent) { create(:namespace, shared_runners_enabled: true) } let(:parent) { create(:group, shared_runners_enabled: true) }
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
it 'is valid' do it 'is valid' do
expect(sub_namespace).to be_valid expect(group).to be_valid
end end
end end
context 'when parent allows shared runners and setting to false' do context 'when parent allows shared runners and setting to false' do
let(:parent) { create(:namespace, shared_runners_enabled: true) } let(:parent) { create(:group, shared_runners_enabled: true) }
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) } let(:group) { build(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) }
it 'is valid' do it 'is valid' do
expect(sub_namespace).to be_valid expect(group).to be_valid
end end
end end
end end
......
...@@ -106,7 +106,7 @@ RSpec.describe OnboardingProgress do ...@@ -106,7 +106,7 @@ RSpec.describe OnboardingProgress do
end end
context 'when not given a root namespace' do context 'when not given a root namespace' do
let(:namespace) { create(:namespace, parent: build(:namespace)) } let(:namespace) { create(:group, parent: build(:group)) }
it 'does not add a record for the namespace' do it 'does not add a record for the namespace' do
expect { onboard }.not_to change(described_class, :count).from(0) expect { onboard }.not_to change(described_class, :count).from(0)
......
...@@ -145,7 +145,7 @@ RSpec.describe Project, factory_default: :keep do ...@@ -145,7 +145,7 @@ RSpec.describe Project, factory_default: :keep do
end end
it_behaves_like 'model with wiki' do it_behaves_like 'model with wiki' do
let_it_be(:container) { create(:project, :wiki_repo) } let_it_be(:container) { create(:project, :wiki_repo, namespace: create(:group)) }
let(:container_without_wiki) { create(:project) } let(:container_without_wiki) { create(:project) }
end end
......
...@@ -17,9 +17,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -17,9 +17,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
describe '/api/v4/jobs' do describe '/api/v4/jobs' do
let(:root_namespace) { create(:namespace) } let(:parent_group) { create(:group) }
let(:namespace) { create(:namespace, parent: root_namespace) } let(:group) { create(:group, parent: parent_group) }
let(:project) { create(:project, namespace: namespace, shared_runners_enabled: false) } let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -78,7 +78,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -78,7 +78,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
before do before do
stub_application_setting(max_artifacts_size: application_max_size) stub_application_setting(max_artifacts_size: application_max_size)
root_namespace.update!(max_artifacts_size: sample_max_size) parent_group.update!(max_artifacts_size: sample_max_size)
end end
it_behaves_like 'failed request' it_behaves_like 'failed request'
...@@ -90,8 +90,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -90,8 +90,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
before do before do
stub_application_setting(max_artifacts_size: application_max_size) stub_application_setting(max_artifacts_size: application_max_size)
root_namespace.update!(max_artifacts_size: root_namespace_max_size) parent_group.update!(max_artifacts_size: root_namespace_max_size)
namespace.update!(max_artifacts_size: sample_max_size) group.update!(max_artifacts_size: sample_max_size)
end end
it_behaves_like 'failed request' it_behaves_like 'failed request'
...@@ -104,8 +104,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -104,8 +104,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
before do before do
stub_application_setting(max_artifacts_size: application_max_size) stub_application_setting(max_artifacts_size: application_max_size)
root_namespace.update!(max_artifacts_size: root_namespace_max_size) parent_group.update!(max_artifacts_size: root_namespace_max_size)
namespace.update!(max_artifacts_size: child_namespace_max_size) group.update!(max_artifacts_size: child_namespace_max_size)
project.update!(max_artifacts_size: sample_max_size) project.update!(max_artifacts_size: sample_max_size)
end end
......
...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
describe '/api/v4/jobs' do describe '/api/v4/jobs' do
let(:root_namespace) { create(:namespace) } let(:group) { create(:group, :nested) }
let(:namespace) { create(:namespace, parent: root_namespace) } let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:project) { create(:project, namespace: namespace, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
describe '/api/v4/jobs' do describe '/api/v4/jobs' do
let(:root_namespace) { create(:namespace) } let(:group) { create(:group, :nested) }
let(:namespace) { create(:namespace, parent: root_namespace) } let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:project) { create(:project, namespace: namespace, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -17,9 +17,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
describe '/api/v4/jobs' do describe '/api/v4/jobs' do
let(:root_namespace) { create(:namespace) } let(:group) { create(:group, :nested) }
let(:namespace) { create(:namespace, parent: root_namespace) } let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:project) { create(:project, namespace: namespace, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -45,8 +45,7 @@ RSpec.describe OnboardingProgressService do ...@@ -45,8 +45,7 @@ RSpec.describe OnboardingProgressService do
end end
describe '#execute' do describe '#execute' do
let(:namespace) { create(:namespace, parent: root_namespace) } let(:namespace) { create(:namespace) }
let(:root_namespace) { nil }
let(:action) { :namespace_action } let(:action) { :namespace_action }
subject(:execute_service) { described_class.new(namespace).execute(action: :subscription_created) } subject(:execute_service) { described_class.new(namespace).execute(action: :subscription_created) }
...@@ -64,16 +63,16 @@ RSpec.describe OnboardingProgressService do ...@@ -64,16 +63,16 @@ RSpec.describe OnboardingProgressService do
end end
context 'when the namespace is not the root' do context 'when the namespace is not the root' do
let(:root_namespace) { build(:namespace) } let(:group) { create(:group, :nested) }
before do before do
OnboardingProgress.onboard(root_namespace) OnboardingProgress.onboard(group)
end end
it 'registers a namespace onboarding progress action for the root namespace' do it 'does not register a namespace onboarding progress action' do
execute_service execute_service
expect(OnboardingProgress.completed?(root_namespace, :subscription_created)).to eq(true) expect(OnboardingProgress.completed?(group, :subscription_created)).to be(nil)
end end
end end
...@@ -83,7 +82,7 @@ RSpec.describe OnboardingProgressService do ...@@ -83,7 +82,7 @@ RSpec.describe OnboardingProgressService do
it 'does not register a namespace onboarding progress action' do it 'does not register a namespace onboarding progress action' do
execute_service execute_service
expect(OnboardingProgress.completed?(root_namespace, :subscription_created)).to be(nil) expect(OnboardingProgress.completed?(namespace, :subscription_created)).to be(nil)
end end
end end
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