Commit 796c75db authored by Manoj M J's avatar Manoj M J Committed by Markus Koller

Validate nature of parent for Group & Namespace

This change adds validation to check the nature
of parent for Group & Namespace records
parent 075086e7
...@@ -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
...@@ -485,7 +485,6 @@ module EE ...@@ -485,7 +485,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,6 +368,7 @@ RSpec.describe ApplicationSetting do ...@@ -368,6 +368,7 @@ RSpec.describe ApplicationSetting do
end end
context 'namespaces' do context 'namespaces' do
context 'with personal namespaces' do
let(:namespaces) { create_list(:namespace, 2) } let(:namespaces) { create_list(:namespace, 2) }
let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: namespaces.last } let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: namespaces.last }
...@@ -375,17 +376,23 @@ RSpec.describe ApplicationSetting do ...@@ -375,17 +376,23 @@ RSpec.describe ApplicationSetting 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
context 'with groups' do
let(:groups) { create_list(:group, 2) }
let!(:indexed_namespace) { create :elasticsearch_indexed_namespace, namespace: groups.last }
it 'returns namespaces that are allowed to be indexed' do it 'returns groups that are allowed to be indexed' do
child_namespace = create(:namespace, parent: namespaces.first) child_group = create(:group, parent: groups.first)
create :elasticsearch_indexed_namespace, namespace: child_namespace 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
......
This diff is collapsed.
...@@ -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
......
This diff is collapsed.
...@@ -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