From 368479e51fda94f3cd85c16858e333ee3f004614 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Mon, 4 Mar 2019 10:50:33 +0300 Subject: [PATCH] Implemented FeatureDefinitionManager --- framework/Volo.Abp.sln | 9 +- .../Authorization/AbpAuthorizationModule.cs | 1 + .../Volo/Abp/Features/AbpFeaturesModule.cs | 27 ++++- .../Volo/Abp/Features/FeatureChecker.cs | 16 ++- .../Abp/Features/FeatureCheckerExtensions.cs | 18 ++- .../Volo/Abp/Features/FeatureDefinition.cs | 14 +++ .../Abp/Features/FeatureDefinitionContext.cs | 43 ++++--- .../Abp/Features/FeatureDefinitionManager.cs | 73 +++++++++--- .../Abp/Features/FeatureGroupDefinition.cs | 108 ++++++++++++++++++ .../Abp/Features/IFeatureDefinitionContext.cs | 11 +- .../Volo.Abp.Features.Tests.csproj | 22 ++++ .../Volo/Abp/Features/AbpFeaturesTestBase.cs | 10 ++ .../Abp/Features/AbpFeaturesTestModule.cs | 18 +++ .../FeatureDefinitionManager_Tests.cs | 35 ++++++ .../Features/TestFeatureDefinitionProvider.cs | 12 ++ 15 files changed, 369 insertions(+), 48 deletions(-) create mode 100644 framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestBase.cs create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestModule.cs create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureDefinitionManager_Tests.cs create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/TestFeatureDefinitionProvider.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index f99d6cebbc..f9c3730467 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -226,7 +226,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.Cli EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.Contracts", "src\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj", "{88F6D091-CA16-4B71-9499-8D5B8FA2E712}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Features", "src\Volo.Abp.Features\Volo.Abp.Features.csproj", "{01E3D389-8872-4EB1-9D3D-13B6ED54DE0E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Features", "src\Volo.Abp.Features\Volo.Abp.Features.csproj", "{01E3D389-8872-4EB1-9D3D-13B6ED54DE0E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Features.Tests", "test\Volo.Abp.Features.Tests\Volo.Abp.Features.Tests.csproj", "{575BEFA1-19C2-49B1-8D31-B5D4472328DE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -646,6 +648,10 @@ Global {01E3D389-8872-4EB1-9D3D-13B6ED54DE0E}.Debug|Any CPU.Build.0 = Debug|Any CPU {01E3D389-8872-4EB1-9D3D-13B6ED54DE0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {01E3D389-8872-4EB1-9D3D-13B6ED54DE0E}.Release|Any CPU.Build.0 = Release|Any CPU + {575BEFA1-19C2-49B1-8D31-B5D4472328DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {575BEFA1-19C2-49B1-8D31-B5D4472328DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {575BEFA1-19C2-49B1-8D31-B5D4472328DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {575BEFA1-19C2-49B1-8D31-B5D4472328DE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -756,6 +762,7 @@ Global {E803DDB8-81EA-454B-9A66-9C2941100B67} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {88F6D091-CA16-4B71-9499-8D5B8FA2E712} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {01E3D389-8872-4EB1-9D3D-13B6ED54DE0E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {575BEFA1-19C2-49B1-8D31-B5D4472328DE} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs index 57472d7cf1..3ea2789e8e 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -16,6 +16,7 @@ namespace Volo.Abp.Authorization public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.OnRegistred(AuthorizationInterceptorRegistrar.RegisterIfNeeded); + //TODO: Auto Add Providers to PermissionOptions just like did in AbpFeaturesModule.AutoAddProviders } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs index f83797334f..db64ce6c57 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs @@ -1,4 +1,7 @@ -using Volo.Abp.Localization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; @@ -10,9 +13,27 @@ namespace Volo.Abp.Features )] public class AbpFeaturesModule : AbpModule { - public override void ConfigureServices(ServiceConfigurationContext context) + public override void PreConfigureServices(ServiceConfigurationContext context) { - + AutoAddProviders(context.Services); + } + + private static void AutoAddProviders(IServiceCollection services) + { + var featureDefinitionProviders = new List(); + + services.OnRegistred(context => + { + if (typeof(IFeatureDefinitionProvider).IsAssignableFrom(context.ImplementationType)) + { + featureDefinitionProviders.Add(context.ImplementationType); + } + }); + + services.Configure(options => + { + options.DefinitionProviders.AddIfNotContains(featureDefinitionProviders); + }); } } } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs index 17bd05db6d..68db290f1b 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs @@ -10,33 +10,37 @@ namespace Volo.Abp.Features { public class FeatureChecker : IFeatureChecker, ITransientDependency { - protected IFeatureDefinitionManager FeatureDefinitionManager { get; } - protected Lazy> Providers { get; } protected FeatureOptions Options { get; } + protected IServiceProvider ServiceProvider { get; } + protected IFeatureDefinitionManager FeatureDefinitionManager { get; } + protected List Providers => _providers.Value; + + private readonly Lazy> _providers; public FeatureChecker( IOptions options, IServiceProvider serviceProvider, IFeatureDefinitionManager featureDefinitionManager) { + ServiceProvider = serviceProvider; FeatureDefinitionManager = featureDefinitionManager; Options = options.Value; - Providers = new Lazy>( + _providers = new Lazy>( () => Options .ValueProviders - .Select(type => serviceProvider.GetRequiredService(type) as IFeatureValueProvider) + .Select(type => ServiceProvider.GetRequiredService(type) as IFeatureValueProvider) .ToList(), true ); } - + public virtual async Task GetOrNullAsync(string name) { var featureDefinition = FeatureDefinitionManager.Get(name); var providers = Enumerable - .Reverse(Providers.Value); + .Reverse(Providers); if (featureDefinition.AllowedProviders.Any()) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs index 05122e8e6a..c43f8f04de 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs @@ -7,7 +7,10 @@ namespace Volo.Abp.Features { public static class FeatureCheckerExtensions { - public static async Task GetAsync([NotNull] this IFeatureChecker featureChecker, [NotNull] string name, T defaultValue = default) + public static async Task GetAsync( + [NotNull] this IFeatureChecker featureChecker, + [NotNull] string name, + T defaultValue = default) where T : struct { Check.NotNull(featureChecker, nameof(featureChecker)); @@ -17,19 +20,26 @@ namespace Volo.Abp.Features return value?.To() ?? defaultValue; } - public static string GetOrNull([NotNull] this IFeatureChecker featureChecker, [NotNull] string name) + public static string GetOrNull( + [NotNull] this IFeatureChecker featureChecker, + [NotNull] string name) { Check.NotNull(featureChecker, nameof(featureChecker)); return AsyncHelper.RunSync(() => featureChecker.GetOrNullAsync(name)); } - public static T Get([NotNull] this IFeatureChecker featureChecker, [NotNull] string name, T defaultValue = default) + public static T Get( + [NotNull] this IFeatureChecker featureChecker, + [NotNull] string name, + T defaultValue = default) where T : struct { return AsyncHelper.RunSync(() => featureChecker.GetAsync(name, defaultValue)); } - public static bool IsEnabled([NotNull] this IFeatureChecker featureChecker, [NotNull] string name) + public static bool IsEnabled( + [NotNull] this IFeatureChecker featureChecker, + [NotNull] string name) { return AsyncHelper.RunSync(() => featureChecker.IsEnabledAsync(name)); } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs index 675697334f..6a1c030b21 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs @@ -55,6 +55,20 @@ namespace Volo.Abp.Features /// public List AllowedProviders { get; } + /// + /// Gets/sets a key-value on the . + /// + /// Name of the property + /// + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. + /// + public object this[string name] + { + get => Properties.GetOrDefault(name); + set => Properties[name] = value; + } + /// /// Can be used to get/set custom properties for this feature. /// diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionContext.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionContext.cs index d14695b30a..be9c1beec9 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionContext.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionContext.cs @@ -1,38 +1,51 @@ using System.Collections.Generic; -using System.Collections.Immutable; +using Volo.Abp.Localization; namespace Volo.Abp.Features { public class FeatureDefinitionContext : IFeatureDefinitionContext { - protected Dictionary Features { get; } + internal Dictionary Groups { get; } - public FeatureDefinitionContext(Dictionary features) + public FeatureDefinitionContext() { - Features = features; + Groups = new Dictionary(); } - public virtual FeatureDefinition GetOrNull(string name) + public FeatureGroupDefinition AddGroup(string name, ILocalizableString displayName = null) { - return Features.GetOrDefault(name); - } + Check.NotNull(name, nameof(name)); - public virtual IReadOnlyList GetAll() - { - return Features.Values.ToImmutableList(); + if (Groups.ContainsKey(name)) + { + throw new AbpException($"There is already an existing permission group with name: {name}"); + } + + return Groups[name] = new FeatureGroupDefinition(name, displayName); } - public virtual void Add(params FeatureDefinition[] definitions) + public FeatureGroupDefinition GetGroupOrNull(string name) { - if (definitions.IsNullOrEmpty()) + Check.NotNull(name, nameof(name)); + + if (!Groups.ContainsKey(name)) { - return; + return null; } - foreach (var definition in definitions) + return Groups[name]; + } + + public void RemoveGroup(string name) + { + Check.NotNull(name, nameof(name)); + + if (!Groups.ContainsKey(name)) { - Features[definition.Name] = definition; + throw new AbpException($"Undefined feature group: '{name}'."); } + + Groups.Remove(name); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs index bf36c114d3..13d15ac95e 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs @@ -10,9 +10,11 @@ namespace Volo.Abp.Features { public class FeatureDefinitionManager : IFeatureDefinitionManager, ISingletonDependency { - protected Lazy> Providers { get; } + protected IDictionary FeatureGroupDefinitions => _lazyFeatureGroupDefinitions.Value; + private readonly Lazy> _lazyFeatureGroupDefinitions; - protected Lazy> FeatureDefinitions { get; } + protected IDictionary FeatureDefinitions => _lazyFeatureDefinitions.Value; + private readonly Lazy> _lazyFeatureDefinitions; protected FeatureOptions Options { get; } @@ -25,8 +27,15 @@ namespace Volo.Abp.Features _serviceProvider = serviceProvider; Options = options.Value; - Providers = new Lazy>(CreateFeatureProviders, true); - FeatureDefinitions = new Lazy>(CreateFeatureDefinitions, true); + _lazyFeatureDefinitions = new Lazy>( + CreateFeatureDefinitions, + isThreadSafe: true + ); + + _lazyFeatureGroupDefinitions = new Lazy>( + CreateFeatureGroupDefinitions, + isThreadSafe:true + ); } public virtual FeatureDefinition Get(string name) @@ -45,32 +54,64 @@ namespace Volo.Abp.Features public virtual IReadOnlyList GetAll() { - return FeatureDefinitions.Value.Values.ToImmutableList(); + return FeatureDefinitions.Values.ToImmutableList(); } public virtual FeatureDefinition GetOrNull(string name) { - return FeatureDefinitions.Value.GetOrDefault(name); + return FeatureDefinitions.GetOrDefault(name); } - protected virtual List CreateFeatureProviders() + protected virtual Dictionary CreateFeatureDefinitions() { - return Options - .DefinitionProviders - .Select(p => _serviceProvider.GetRequiredService(p) as IFeatureDefinitionProvider) - .ToList(); + var features = new Dictionary(); + + foreach (var groupDefinition in FeatureGroupDefinitions.Values) + { + foreach (var feature in groupDefinition.Features) + { + AddFeatureToDictionaryRecursively(features, feature); + } + } + + return features; } - protected virtual IDictionary CreateFeatureDefinitions() + protected virtual void AddFeatureToDictionaryRecursively( + Dictionary features, + FeatureDefinition feature) { - var features = new Dictionary(); + if (features.ContainsKey(feature.Name)) + { + throw new AbpException("Duplicate feature name: " + feature.Name); + } + + features[feature.Name] = feature; - foreach (var provider in Providers.Value) + foreach (var child in feature.Children) { - provider.Define(new FeatureDefinitionContext(features)); + AddFeatureToDictionaryRecursively(features, child); } + } - return features; + protected virtual Dictionary CreateFeatureGroupDefinitions() + { + var context = new FeatureDefinitionContext(); + + using (var scope = _serviceProvider.CreateScope()) + { + var providers = Options + .DefinitionProviders + .Select(p => scope.ServiceProvider.GetRequiredService(p) as IFeatureDefinitionProvider) + .ToList(); + + foreach (var provider in providers) + { + provider.Define(context); + } + } + + return context.Groups; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs new file mode 100644 index 0000000000..4d0ccbba62 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using Volo.Abp.Localization; + +namespace Volo.Abp.Features +{ + public class FeatureGroupDefinition + { + /// + /// Unique name of the group. + /// + public string Name { get; } + + public Dictionary Properties { get; } + + public ILocalizableString DisplayName + { + get => _displayName; + set => _displayName = Check.NotNull(value, nameof(value)); + } + private ILocalizableString _displayName; + + public IReadOnlyList Features => _features.ToImmutableList(); + private readonly List _features; + + /// + /// Gets/sets a key-value on the . + /// + /// Name of the property + /// + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. + /// + public object this[string name] + { + get => Properties.GetOrDefault(name); + set => Properties[name] = value; + } + + protected internal FeatureGroupDefinition( + string name, + ILocalizableString displayName = null) + { + Name = name; + DisplayName = displayName ?? new FixedLocalizableString(Name); + + Properties = new Dictionary(); + _features = new List(); + } + + public virtual FeatureDefinition AddFeature( + string name, + string defaultValue = null, + ILocalizableString displayName = null, + ILocalizableString description = null, + bool isVisibleToClients = true) + { + var feature = new FeatureDefinition( + name, + defaultValue, + displayName, + description, + isVisibleToClients + ); + + _features.Add(feature); + + return feature; + } + + public virtual List GetFeaturesWithChildren() + { + var features = new List(); + + foreach (var feature in _features) + { + AddFeatureToListRecursively(features, feature); + } + + return features; + } + + /// + /// Sets a property in the dictionary. + /// This is a shortcut for nested calls on this object. + /// + public virtual FeatureGroupDefinition WithProperty(string key, object value) + { + Properties[key] = value; + return this; + } + + private void AddFeatureToListRecursively(List features, FeatureDefinition feature) + { + features.Add(feature); + + foreach (var child in feature.Children) + { + AddFeatureToListRecursively(features, child); + } + } + + public override string ToString() + { + return $"[{nameof(FeatureGroupDefinition)} {Name}]"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureDefinitionContext.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureDefinitionContext.cs index 8762b9d34b..03fc14c579 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureDefinitionContext.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureDefinitionContext.cs @@ -1,9 +1,14 @@ -namespace Volo.Abp.Features +using JetBrains.Annotations; +using Volo.Abp.Localization; + +namespace Volo.Abp.Features { public interface IFeatureDefinitionContext { - FeatureDefinition GetOrNull(string name); + FeatureGroupDefinition AddGroup([NotNull] string name, ILocalizableString displayName = null); - void Add(params FeatureDefinition[] definitions); + FeatureGroupDefinition GetGroupOrNull(string name); + + void RemoveGroup(string name); } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj b/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj new file mode 100644 index 0000000000..3632aa2bf3 --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp2.2 + latest + Volo.Abp.Features.Tests + Volo.Abp.Features.Tests + true + false + false + false + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestBase.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestBase.cs new file mode 100644 index 0000000000..a3c9170798 --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestBase.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.Features +{ + public class AbpFeaturesTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestModule.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestModule.cs new file mode 100644 index 0000000000..7b0927b80d --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/AbpFeaturesTestModule.cs @@ -0,0 +1,18 @@ +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Features +{ + [DependsOn( + typeof(AbpFeaturesModule), + typeof(AbpTestBaseModule), + typeof(AbpAutofacModule) + )] + public class AbpFeaturesTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + + } + } +} diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureDefinitionManager_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureDefinitionManager_Tests.cs new file mode 100644 index 0000000000..beb94ec283 --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureDefinitionManager_Tests.cs @@ -0,0 +1,35 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.Features +{ + public class FeatureDefinitionManager_Tests : AbpFeaturesTestBase + { + private readonly IFeatureDefinitionManager _featureDefinitionManager; + + public FeatureDefinitionManager_Tests() + { + _featureDefinitionManager = GetRequiredService(); + } + + [Fact] + public void Should_Get_Defined_Features() + { + _featureDefinitionManager.GetOrNull("BooleanTestFeature1").ShouldNotBeNull(); + _featureDefinitionManager.Get("BooleanTestFeature1").Name.ShouldBe("BooleanTestFeature1"); + + _featureDefinitionManager.GetOrNull("IntegerTestFeature1").ShouldNotBeNull(); + _featureDefinitionManager.Get("IntegerTestFeature1").Name.ShouldBe("IntegerTestFeature1"); + } + + [Fact] + public void Should_Not_Get_Undefined_Features() + { + _featureDefinitionManager.GetOrNull("UndefinedFeature").ShouldBeNull(); + Assert.Throws(() => + { + _featureDefinitionManager.Get("UndefinedFeature"); + }); + } + } +} diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/TestFeatureDefinitionProvider.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/TestFeatureDefinitionProvider.cs new file mode 100644 index 0000000000..aceb39b6f4 --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/TestFeatureDefinitionProvider.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.Features +{ + public class TestFeatureDefinitionProvider : FeatureDefinitionProvider + { + public override void Define(IFeatureDefinitionContext context) + { + var group = context.AddGroup("Test Group"); + group.AddFeature("BooleanTestFeature1"); + group.AddFeature("IntegerTestFeature1", defaultValue: "1"); + } + } +}