You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by da...@apache.org on 2022/07/22 12:37:09 UTC

[logging-log4net] 05/06: :white_check_mark: add test trying to repro LOG4NET-684, but the issue doesn't repro

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 <da...@gmail.com>
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