This is an automated email from the ASF dual-hosted git repository. davydm pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4net.git
commit dd6e40acf8e53c507cd1d22a352a53495f3c44f8 Author: Davyd McColl <[email protected]> AuthorDate: Fri Jul 22 14:35:32 2022 +0200 :white_check_mark: add test trying to repro LOG4NET-684, but the issue doesn't repro --- src/log4net.Tests/Context/ThreadContextTest.cs | 352 ++++++++++++++----------- 1 file changed, 203 insertions(+), 149 deletions(-) diff --git a/src/log4net.Tests/Context/ThreadContextTest.cs b/src/log4net.Tests/Context/ThreadContextTest.cs index e489efc4..951d32d2 100644 --- a/src/log4net.Tests/Context/ThreadContextTest.cs +++ b/src/log4net.Tests/Context/ThreadContextTest.cs @@ -1,4 +1,5 @@ #region Apache License + // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with @@ -15,213 +16,266 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #endregion using System; +using System.Collections.Generic; using System.Threading; - using log4net.Config; using log4net.Layout; using log4net.Repository; using log4net.Tests.Appender; using log4net.Util; - using NUnit.Framework; +using static NExpect.Expectations; +using NExpect; namespace log4net.Tests.Context { - /// <summary> - /// Used for internal unit testing the <see cref="ThreadContext"/> class. - /// </summary> - /// <remarks> - /// Used for internal unit testing the <see cref="ThreadContext"/> class. - /// </remarks> - [TestFixture] - public class ThreadContextTest - { + /// <summary> + /// Used for internal unit testing the <see cref="ThreadContext"/> class. + /// </summary> + /// <remarks> + /// Used for internal unit testing the <see cref="ThreadContext"/> class. + /// </remarks> + [TestFixture] + public class ThreadContextTest + { [TearDown] - public void TearDown() { + public void TearDown() + { Utils.RemovePropertyFromAllContexts(); } [Test] - public void TestThreadPropertiesPattern() - { - StringAppender stringAppender = new StringAppender(); - stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); + public void TestThreadPropertiesPattern() + { + StringAppender stringAppender = new StringAppender(); + stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); - ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); + ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); - ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); + ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread properties value set"); - stringAppender.Reset(); + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread properties value set"); + stringAppender.Reset(); - ThreadContext.Properties[Utils.PROPERTY_KEY] = "val1"; + ThreadContext.Properties[Utils.PROPERTY_KEY] = "val1"; - log1.Info("TestMessage"); - Assert.AreEqual("val1", stringAppender.GetString(), "Test thread properties value set"); - stringAppender.Reset(); + log1.Info("TestMessage"); + Assert.AreEqual("val1", stringAppender.GetString(), "Test thread properties value set"); + stringAppender.Reset(); - ThreadContext.Properties.Remove(Utils.PROPERTY_KEY); + ThreadContext.Properties.Remove(Utils.PROPERTY_KEY); - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread properties value removed"); - stringAppender.Reset(); - } + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread properties value removed"); + stringAppender.Reset(); + } - [Test] - public void TestThreadStackPattern() - { - StringAppender stringAppender = new StringAppender(); + [Test] + public void TestThreadStackPattern() + { + StringAppender stringAppender = new StringAppender(); stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); - ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); + ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); - ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); + ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); - stringAppender.Reset(); + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); + stringAppender.Reset(); - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) - { - log1.Info("TestMessage"); - Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); - stringAppender.Reset(); - } + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) + { + log1.Info("TestMessage"); + Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); + stringAppender.Reset(); + } - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); - stringAppender.Reset(); - } + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); + stringAppender.Reset(); + } - [Test] - public void TestThreadStackPattern2() - { - StringAppender stringAppender = new StringAppender(); + [Test] + public void TestThreadStackPattern2() + { + StringAppender stringAppender = new StringAppender(); stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); - ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); - - ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); - - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); - stringAppender.Reset(); - - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) - { - log1.Info("TestMessage"); - Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); - stringAppender.Reset(); - - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val2")) - { - log1.Info("TestMessage"); - Assert.AreEqual("val1 val2", stringAppender.GetString(), "Test thread stack value pushed 2nd val"); - stringAppender.Reset(); - } - } - - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); - stringAppender.Reset(); - } - - [Test] - public void TestThreadStackPatternNullVal() - { - StringAppender stringAppender = new StringAppender(); + ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); + + ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); + + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); + stringAppender.Reset(); + + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) + { + log1.Info("TestMessage"); + Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); + stringAppender.Reset(); + + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val2")) + { + log1.Info("TestMessage"); + Assert.AreEqual("val1 val2", stringAppender.GetString(), "Test thread stack value pushed 2nd val"); + stringAppender.Reset(); + } + } + + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); + stringAppender.Reset(); + } + + [Test] + public void TestThreadStackPatternNullVal() + { + StringAppender stringAppender = new StringAppender(); stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); - ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); + ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); - ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); + ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); - stringAppender.Reset(); + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); + stringAppender.Reset(); - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push(null)) - { - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value set"); - stringAppender.Reset(); - } + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push(null)) + { + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value set"); + stringAppender.Reset(); + } - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); - stringAppender.Reset(); - } + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); + stringAppender.Reset(); + } - [Test] - public void TestThreadStackPatternNullVal2() - { - StringAppender stringAppender = new StringAppender(); + [Test] + public void TestThreadStackPatternNullVal2() + { + StringAppender stringAppender = new StringAppender(); stringAppender.Layout = new PatternLayout("%property{" + Utils.PROPERTY_KEY + "}"); - ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); + ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); - ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); + ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadStackPattern"); - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); - stringAppender.Reset(); + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test no thread stack value set"); + stringAppender.Reset(); - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) - { - log1.Info("TestMessage"); - Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); - stringAppender.Reset(); + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push("val1")) + { + log1.Info("TestMessage"); + Assert.AreEqual("val1", stringAppender.GetString(), "Test thread stack value set"); + stringAppender.Reset(); - using(ThreadContext.Stacks[Utils.PROPERTY_KEY].Push(null)) - { - log1.Info("TestMessage"); - Assert.AreEqual("val1 ", stringAppender.GetString(), "Test thread stack value pushed null"); - stringAppender.Reset(); - } - } + using (ThreadContext.Stacks[Utils.PROPERTY_KEY].Push(null)) + { + log1.Info("TestMessage"); + Assert.AreEqual("val1 ", stringAppender.GetString(), "Test thread stack value pushed null"); + stringAppender.Reset(); + } + } - log1.Info("TestMessage"); - Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); - stringAppender.Reset(); - } + log1.Info("TestMessage"); + Assert.AreEqual(SystemInfo.NullText, stringAppender.GetString(), "Test thread stack value removed"); + stringAppender.Reset(); + } private static string TestBackgroundThreadContextPropertyRepository; - [Test] - public void TestBackgroundThreadContextProperty() - { - StringAppender stringAppender = new StringAppender(); - stringAppender.Layout = new PatternLayout("%property{DateTimeTodayToString}"); + [Test] + public void TestBackgroundThreadContextProperty() + { + StringAppender stringAppender = new StringAppender(); + stringAppender.Layout = new PatternLayout("%property{DateTimeTodayToString}"); - ILoggerRepository rep = LogManager.CreateRepository(TestBackgroundThreadContextPropertyRepository = "TestBackgroundThreadContextPropertyRepository" + Guid.NewGuid().ToString()); - BasicConfigurator.Configure(rep, stringAppender); + ILoggerRepository rep = LogManager.CreateRepository(TestBackgroundThreadContextPropertyRepository = + "TestBackgroundThreadContextPropertyRepository" + Guid.NewGuid().ToString()); + BasicConfigurator.Configure(rep, stringAppender); - Thread thread = new Thread(new ThreadStart(ExecuteBackgroundThread)); - thread.Start(); + Thread thread = new Thread(new ThreadStart(ExecuteBackgroundThread)); + thread.Start(); - Thread.CurrentThread.Join(2000); - } + Thread.CurrentThread.Join(2000); + } - private static void ExecuteBackgroundThread() - { + private static void ExecuteBackgroundThread() + { ILog log = LogManager.GetLogger(TestBackgroundThreadContextPropertyRepository, "ExecuteBackGroundThread"); - ThreadContext.Properties["DateTimeTodayToString"] = DateTime.Today.ToString(); + ThreadContext.Properties["DateTimeTodayToString"] = DateTime.Today.ToString(); - log.Info("TestMessage"); + log.Info("TestMessage"); - Repository.Hierarchy.Hierarchy hierarchyLoggingRepository = (Repository.Hierarchy.Hierarchy)log.Logger.Repository; - StringAppender stringAppender = (StringAppender)hierarchyLoggingRepository.Root.Appenders[0]; + Repository.Hierarchy.Hierarchy hierarchyLoggingRepository = + (Repository.Hierarchy.Hierarchy) log.Logger.Repository; + StringAppender stringAppender = (StringAppender) hierarchyLoggingRepository.Root.Appenders[0]; - Assert.AreEqual(DateTime.Today.ToString(), stringAppender.GetString()); - } - } + Assert.AreEqual(DateTime.Today.ToString(), stringAppender.GetString()); + } + + [Test] + public void PropertiesShouldBeThreadSafe() + { + // Arrange + var threads = new List<Thread>(); + var flags = new List<FlagContainer>(); + + // Act + for (var i = 0; i < 256; i++) + { + var t = new Thread(SpinAndCheck); + var flag = new FlagContainer(); + t.Start(flag); + flags.Add(flag); + threads.Add(t); + } + + foreach (var t in threads) + { + t.Join(); + } + + // Assert + Expect(flags) + .To.Contain.All.Matched.By(o => o.Flag == false); + } + + public class FlagContainer + { + public bool Flag { get; set; } + } + + private void SpinAndCheck(object obj) + { + var container = obj as FlagContainer; + var threadid = Thread.CurrentThread.ManagedThreadId; + for (var i = 0; i < 100000; i++) + { + ThreadContext.Properties["threadid"] = threadid; + Thread.Sleep(0); + if ((int) ThreadContext.Properties["threadid"] != threadid) + { + container.Flag = true; + break; + } + } + } + } } \ No newline at end of file
