[release/6.0] Allow runtimeconfig StartupHooks and Environment StartupHooks to both...
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Wed, 15 Dec 2021 18:40:04 +0000 (12:40 -0600)
committerGitHub <noreply@github.com>
Wed, 15 Dec 2021 18:40:04 +0000 (12:40 -0600)
* Allow configProperties "STARTUP_HOOKS" and env "DOTNET_STARTUP_HOOKS" to both be present

* Fix duplicate_property_error property names to reflect the actual duplicate

* fixup! Allow configProperties "STARTUP_HOOKS" and env "DOTNET_STARTUP_HOOKS" to both be present

* Enforce env startup hook precedence over runtimeconfig startup hooks

Co-authored-by: Tom de Goede <tom.degoede@afas.nl>
src/installer/tests/HostActivation.Tests/StartupHooks.cs
src/native/corehost/hostpolicy/hostpolicy_context.cpp

index a0533a6..3e16853 100644 (file)
@@ -13,6 +13,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
     {
         private SharedTestState sharedTestState;
         private string startupHookVarName = "DOTNET_STARTUP_HOOKS";
+        private string startupHookRuntimeConfigName = "STARTUP_HOOKS";
         private string startupHookSupport = "System.StartupHookProvider.IsSupported";
 
         public StartupHooks(StartupHooks.SharedTestState fixture)
@@ -105,6 +106,64 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
                 .And.HaveStdOutContaining("Hello World");
         }
 
+        [Fact]
+        public void Muxer_activation_of_RuntimeConfig_StartupHook_Succeeds()
+        {
+            var fixture = sharedTestState.PortableAppFixture.Copy();
+            var dotnet = fixture.BuiltDotnet;
+            var appDll = fixture.TestProject.AppDll;
+
+            var startupHookFixture = sharedTestState.StartupHookFixture.Copy();
+            var startupHookDll = startupHookFixture.TestProject.AppDll;
+
+            RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson)
+                .WithProperty(startupHookRuntimeConfigName, startupHookDll)
+                .Save();
+
+            // RuntimeConfig defined startup hook
+            dotnet.Exec(appDll)
+                .CaptureStdOut()
+                .CaptureStdErr()
+                .Execute()
+                .Should().Pass()
+                .And.HaveStdOutContaining("Hello from startup hook!")
+                .And.HaveStdOutContaining("Hello World");
+        }
+
+        [Fact]
+        public void Muxer_activation_of_RuntimeConfig_And_Environment_StartupHooks_SucceedsInExpectedOrder()
+        {
+            var fixture = sharedTestState.PortableAppFixture.Copy();
+            var dotnet = fixture.BuiltDotnet;
+            var appDll = fixture.TestProject.AppDll;
+
+            var startupHookFixture = sharedTestState.StartupHookFixture.Copy();
+            var startupHookDll = startupHookFixture.TestProject.AppDll;
+
+            RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson)
+                .WithProperty(startupHookRuntimeConfigName, startupHookDll)
+                .Save();
+
+            var startupHook2Fixture = sharedTestState.StartupHookWithDependencyFixture.Copy();
+            var startupHook2Dll = startupHook2Fixture.TestProject.AppDll;
+
+            // include any char to counter output from other threads such as in #57243
+            const string wildcardPattern = @"[\r\n\s.]*";
+
+            // RuntimeConfig and Environment startup hooks in expected order
+            dotnet.Exec(appDll)
+                .EnvironmentVariable(startupHookVarName, startupHook2Dll)
+                .CaptureStdOut()
+                .CaptureStdErr()
+                .Execute()
+                .Should().Pass()
+                .And.HaveStdOutMatching("Hello from startup hook with dependency!" +
+                                        wildcardPattern +
+                                        "Hello from startup hook!" +
+                                        wildcardPattern +
+                                        "Hello World");
+        }
+
         // Empty startup hook variable
         [Fact]
         public void Muxer_activation_of_Empty_StartupHook_Variable_Succeeds()
index e213e78..e4165f0 100644 (file)
@@ -287,11 +287,16 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a
     pal::string_t startup_hooks;
     if (pal::getenv(_X("DOTNET_STARTUP_HOOKS"), &startup_hooks))
     {
-        if (!coreclr_properties.add(common_property::StartUpHooks, startup_hooks.c_str()))
+        const pal::char_t *config_startup_hooks;
+        if (coreclr_properties.try_get(common_property::StartUpHooks, &config_startup_hooks))
         {
-            log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::StartUpHooks));
-            return StatusCode::LibHostDuplicateProperty;
+            // env startup hooks shoold have precedence over config startup hooks
+            // therefore append config_startup_hooks AFTER startup_hooks
+            startup_hooks.push_back(PATH_SEPARATOR);
+            startup_hooks.append(config_startup_hooks);
         }
+        
+        coreclr_properties.add(common_property::StartUpHooks, startup_hooks.c_str());
     }
 
     // Single-File Bundle Probe
@@ -303,7 +308,7 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a
 
         if (!coreclr_properties.add(common_property::BundleProbe, ptr_stream.str().c_str()))
         {
-            log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::StartUpHooks));
+            log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::BundleProbe));
             return StatusCode::LibHostDuplicateProperty;
         }
     }
@@ -318,7 +323,7 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a
 
         if (!coreclr_properties.add(common_property::PInvokeOverride, ptr_stream.str().c_str()))
         {
-            log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::StartUpHooks));
+            log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::PInvokeOverride));
             return StatusCode::LibHostDuplicateProperty;
         }
     }
@@ -327,7 +332,7 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a
 #if defined(HOSTPOLICY_EMBEDDED)
     if (!coreclr_properties.add(common_property::HostPolicyEmbedded, _X("true")))
     {
-        log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::StartUpHooks));
+        log_duplicate_property_error(coreclr_property_bag_t::common_property_to_string(common_property::HostPolicyEmbedded));
         return StatusCode::LibHostDuplicateProperty;
     }
 #endif