diff --git a/src/DynamoUtilities/DynamoFeatureFlagsManager.cs b/src/DynamoUtilities/DynamoFeatureFlagsManager.cs index 32be9566ca6..bc041138f35 100644 --- a/src/DynamoUtilities/DynamoFeatureFlagsManager.cs +++ b/src/DynamoUtilities/DynamoFeatureFlagsManager.cs @@ -2,16 +2,17 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Reflection; using System.Threading; -using System.Threading.Tasks; namespace DynamoUtilities { + internal interface IFFlags + { + internal T CheckFeatureFlag(DynamoFeatureFlagsManager mgr, string featureFlagKey, T defaultval); + } /// /// A wrapper around the DynamoFeatureFlags CLI tool. @@ -20,9 +21,21 @@ namespace DynamoUtilities /// internal class DynamoFeatureFlagsManager : CLIWrapper { + // Utility class that supports mocking during tests + class FFlags : IFFlags + { + T IFFlags.CheckFeatureFlag(DynamoFeatureFlagsManager mgr, string featureFlagKey, T defaultval) + { + return mgr.CheckFeatureFlagInternal(featureFlagKey, defaultval); + } + } + + // Useful for mocking in tests + internal IFFlags flags { get; set; } = new FFlags(); private string relativePath = Path.Combine("DynamoFeatureFlags", "DynamoFeatureFlags.exe"); private Dictionary AllFlagsCache { get; set; }//TODO lock is likely overkill. private SynchronizationContext syncContext; + private readonly bool testmode = false; internal static event Action FlagsRetrieved; //TODO(DYN-6464)- remove this field!. @@ -43,8 +56,10 @@ internal class DynamoFeatureFlagsManager : CLIWrapper /// context used for raising FlagRetrieved event. /// will not contact feature flag service in testmode, will respond with defaults. internal DynamoFeatureFlagsManager(string userkey, SynchronizationContext syncContext, bool testmode=false) - { + { this.syncContext = syncContext; + this.testmode = testmode; + //dont pass userkey arg if null/empty var userkeyarg = $"-u {userkey}"; var testmodearg = string.Empty; @@ -62,7 +77,6 @@ internal DynamoFeatureFlagsManager(string userkey, SynchronizationContext syncCo internal void CacheAllFlags() { - //wait for response var dataFromCLI = GetData(featureFlagTimeoutMs); //convert from json string to dictionary. @@ -91,6 +105,13 @@ internal void CacheAllFlags() /// Currently the flag and default val MUST be a bool or string. /// internal T CheckFeatureFlag(string featureFlagKey, T defaultval) + { + // with testmode = true, the call goes through an interface so that we can intercept it with Mock + // with testmode = false, the call simply goes to the CheckFeatureFlagInternal + return testmode ? flags.CheckFeatureFlag(this, featureFlagKey, defaultval) : CheckFeatureFlagInternal(featureFlagKey, defaultval); + } + + private T CheckFeatureFlagInternal(string featureFlagKey, T defaultval) { if(!(defaultval is bool || defaultval is string)){ throw new ArgumentException("unsupported flag type", defaultval.GetType().ToString()); diff --git a/src/DynamoUtilities/Properties/AssemblyInfo.cs b/src/DynamoUtilities/Properties/AssemblyInfo.cs index c4f51c14e99..6ff91d38d74 100644 --- a/src/DynamoUtilities/Properties/AssemblyInfo.cs +++ b/src/DynamoUtilities/Properties/AssemblyInfo.cs @@ -30,3 +30,5 @@ [assembly: InternalsVisibleTo("Notifications")] [assembly: InternalsVisibleTo("SystemTestServices")] [assembly: InternalsVisibleTo("PackageManagerTests")] +//DynamicProxyGenAssembly2 is used by Mock to allow stubbing internal interfaces +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/Tools/DynamoFeatureFlags/FeatureFlagsClient.cs b/src/Tools/DynamoFeatureFlags/FeatureFlagsClient.cs index 8eaeb1b4bb8..26917652f79 100644 --- a/src/Tools/DynamoFeatureFlags/FeatureFlagsClient.cs +++ b/src/Tools/DynamoFeatureFlags/FeatureFlagsClient.cs @@ -85,9 +85,7 @@ internal FeatureFlagsClient(string userkey, string mobileKey = null, bool testMo AllFlags = LdValue.ObjectFrom(new Dictionary { { "TestFlag1",LdValue.Of(true) }, { "TestFlag2", LdValue.Of("I am a string") }, //in tests we want instancing on so we can test it. - { "graphics-primitive-instancing", LdValue.Of(true) }, - { "IsolatePackages", LdValue.Of("Package1,Package2,Package") }, - { "DoNotIsolatePackages", LdValue.Of("Package") } + { "graphics-primitive-instancing", LdValue.Of(true) } }); return; } diff --git a/test/Libraries/PackageManagerTests/PackageLoaderTests.cs b/test/Libraries/PackageManagerTests/PackageLoaderTests.cs index f52c2b90762..93400322194 100644 --- a/test/Libraries/PackageManagerTests/PackageLoaderTests.cs +++ b/test/Libraries/PackageManagerTests/PackageLoaderTests.cs @@ -652,13 +652,21 @@ public void PlacingCustomNodeInstanceFromPackageRetainsCorrectPackageInfoState() [Test] public void LoadPackagesInAssemblyIsolation() { + var ff = new Mock(); + DynamoModel.FeatureFlags.flags = ff.Object; + ff.Setup(x => x.CheckFeatureFlag(DynamoModel.FeatureFlags, "IsolatePackages", "")).Returns(() => "Package1,Package2,Package"); + ff.Setup(x => x.CheckFeatureFlag(DynamoModel.FeatureFlags, "DoNotIsolatePackages", "")).Returns(() => "Package"); + // Needed for FeatureFlags Assert.IsTrue(DynamoModel.IsTestMode); Assert.AreEqual("Package1,Package2,Package", DynamoModel.FeatureFlags.CheckFeatureFlag("IsolatePackages", "")); Assert.AreEqual("Package", DynamoModel.FeatureFlags.CheckFeatureFlag("DoNotIsolatePackages", "")); - - var loader = GetPackageLoader(); + var pathManager = new Mock(); + pathManager.SetupGet(x => x.PackagesDirectories).Returns( + () => new List { PackagesDirectory }); + + var loader = new PackageLoader(pathManager.Object); var libraryLoader = new ExtensionLibraryLoader(CurrentDynamoModel); loader.PackagesLoaded += libraryLoader.LoadPackages;