1 #region Copyright & License 2 // 3 // Copyright 2001-2005 The Apache Software Foundation 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 #endregion 18 19 using System; 20 using System.Collections; 21 using System.Runtime.Remoting; 22 using System.Runtime.Remoting.Channels; 23 using System.Runtime.Remoting.Channels.Tcp; 24 25 using log4net.Core; 26 using log4net.Appender; 27 using IRemoteLoggingSink = log4net.Appender.RemotingAppender.IRemoteLoggingSink; 28 29 using NUnit.Framework; 30 31 namespace log4net.Tests.Appender 32 { 33 /// <summary> 34 /// Used for internal unit testing the <see cref="RemotingAppender"/> class. 35 /// </summary> 36 /// <remarks> 37 /// Used for internal unit testing the <see cref="RemotingAppender"/> class. 38 /// </remarks> 39 [TestFixture] public class RemotingAppenderTest 40 { 41 private IChannel m_remotingChannel = null; 42 43 /// <summary> 44 /// Test that the Message property is correctly remoted 45 /// </summary> TestRemotedMessage()46 [Test] public void TestRemotedMessage() 47 { 48 // Setup the remoting appender 49 ConfigureRootAppender(FixFlags.Partial); 50 51 RemoteLoggingSinkImpl.Instance.Reset(); 52 53 log4net.Repository.Hierarchy.Logger root = null; 54 root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root; 55 56 string testMessage = string.Format("test message [ {0} ]", (new Random()).Next()); 57 58 // Log a message that will be remoted 59 root.Log(Level.Debug, testMessage, null); 60 61 // Wait for the remoted object to be delivered 62 System.Threading.Thread.Sleep(1000); 63 64 LoggingEvent[] events = RemoteLoggingSinkImpl.Instance.Events; 65 Assert.AreEqual(1, events.Length, "Expect to receive 1 remoted event"); 66 67 Assert.AreEqual(testMessage, events[0].RenderedMessage, "Expect Message match after remoting event"); 68 } 69 70 /// <summary> 71 /// Test that the UserName property is not remoted when doing a Fix.Partial 72 /// </summary> TestPartialFix()73 [Test] public void TestPartialFix() 74 { 75 // Setup the remoting appender 76 ConfigureRootAppender(FixFlags.Partial); 77 78 RemoteLoggingSinkImpl.Instance.Reset(); 79 80 log4net.Repository.Hierarchy.Logger root = null; 81 root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root; 82 83 // Log a message that will be remoted 84 root.Log(Level.Debug, "test message", null); 85 86 // Wait for the remoted object to be delivered 87 System.Threading.Thread.Sleep(1000); 88 89 LoggingEvent[] events = RemoteLoggingSinkImpl.Instance.Events; 90 Assert.AreEqual(1, events.Length, "Expect to receive 1 remoted event"); 91 92 // Grab the event data 93 LoggingEventData eventData = GetLoggingEventData(events[0]); 94 95 Assert.IsNull(eventData.UserName, "Expect username to be null because only doing a partial fix"); 96 } 97 98 /// <summary> 99 /// Test that the UserName property is remoted when doing a Fix.All 100 /// </summary> TestFullFix()101 [Test] public void TestFullFix() 102 { 103 // Setup the remoting appender 104 ConfigureRootAppender(FixFlags.All); 105 106 RemoteLoggingSinkImpl.Instance.Reset(); 107 108 log4net.Repository.Hierarchy.Logger root = null; 109 root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root; 110 111 // Log a message that will be remoted 112 root.Log(Level.Debug, "test message", null); 113 114 // Wait for the remoted object to be delivered 115 System.Threading.Thread.Sleep(1000); 116 117 LoggingEvent[] events = RemoteLoggingSinkImpl.Instance.Events; 118 Assert.AreEqual(1, events.Length, "Expect to receive 1 remoted event"); 119 120 // Grab the event data 121 LoggingEventData eventData = GetLoggingEventData(events[0]); 122 123 Assert.IsNotNull(eventData.UserName, "Expect username to not be null because doing a full fix"); 124 } 125 126 /// <summary> 127 /// Test that the Message property is correctly remoted 128 /// </summary> TestRemotedMessageNdcPushPop()129 [Test] public void TestRemotedMessageNdcPushPop() 130 { 131 // Setup the remoting appender 132 ConfigureRootAppender(FixFlags.Partial); 133 134 RemoteLoggingSinkImpl.Instance.Reset(); 135 136 log4net.Repository.Hierarchy.Logger root = null; 137 root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root; 138 139 string testMessage = string.Format("test message [ {0} ]", (new Random()).Next()); 140 141 using(NDC.Push("value")) {} 142 143 // Log a message that will be remoted 144 root.Log(Level.Debug, testMessage, null); 145 146 // Wait for the remoted object to be delivered 147 System.Threading.Thread.Sleep(1000); 148 149 LoggingEvent[] events = RemoteLoggingSinkImpl.Instance.Events; 150 Assert.AreEqual(1, events.Length, "Expect to receive 1 remoted event"); 151 152 Assert.AreEqual(testMessage, events[0].RenderedMessage, "Expect Message match after remoting event"); 153 } 154 TestNestedNdc()155 [Test] public void TestNestedNdc() 156 { 157 // This test can suffer from timing and ordering issues as the RemotingAppender does dispatch events asynchronously 158 159 // Setup the remoting appender 160 ConfigureRootAppender(FixFlags.Partial); 161 162 RemoteLoggingSinkImpl.Instance.Reset(); 163 164 log4net.Tests.Appender.Remoting.UserInterfaces.TestService t; 165 t = new log4net.Tests.Appender.Remoting.UserInterfaces.TestService(); 166 t.Test(); 167 168 // Wait for the remoted objects to be delivered 169 System.Threading.Thread.Sleep(3000); 170 171 LoggingEvent[] events = RemoteLoggingSinkImpl.Instance.Events; 172 Assert.AreEqual(5, events.Length, "Expect to receive 5 remoted event"); 173 174 Assert.AreEqual("begin test", events[0].RenderedMessage, "Verify event 1 RenderedMessage"); 175 Assert.AreEqual("feature", events[1].RenderedMessage, "Verify event 2 RenderedMessage"); 176 Assert.AreEqual("return", events[2].RenderedMessage, "Verify event 3 RenderedMessage"); 177 Assert.AreEqual("return", events[3].RenderedMessage, "Verify event 4 RenderedMessage"); 178 Assert.AreEqual("end test", events[4].RenderedMessage, "Verify event 5 RenderedMessage"); 179 180 Assert.IsNull(events[0].Properties["NDC"], "Verify event 1 Properties"); 181 Assert.AreEqual("test1", events[1].Properties["NDC"], "Verify event 2 Properties"); 182 Assert.AreEqual("test1 test2", events[2].Properties["NDC"], "Verify event 3 Properties"); 183 Assert.AreEqual("test1", events[3].Properties["NDC"], "Verify event 4 Properties"); 184 Assert.IsNull(events[4].Properties["NDC"], "Verify event 5 Properties"); 185 } 186 187 188 RegisterRemotingServerChannel()189 private void RegisterRemotingServerChannel() 190 { 191 if (m_remotingChannel == null) 192 { 193 m_remotingChannel = new TcpChannel(8085); 194 195 // Setup remoting server 196 try 197 { 198 #if NET_2_0 199 ChannelServices.RegisterChannel(m_remotingChannel, false); 200 #else 201 ChannelServices.RegisterChannel(m_remotingChannel); 202 #endif 203 } 204 catch(Exception) 205 { 206 } 207 208 // Marshal the sink object 209 RemotingServices.Marshal(RemoteLoggingSinkImpl.Instance, "LoggingSink", typeof(IRemoteLoggingSink)); 210 } 211 } 212 213 /// <summary> 214 /// Shuts down any loggers in the hierarchy, along 215 /// with all appenders. 216 /// </summary> ResetRepository()217 private void ResetRepository() 218 { 219 // Regular users should not use the clear method lightly! 220 LogManager.GetRepository().ResetConfiguration(); 221 LogManager.GetRepository().Shutdown(); 222 ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Clear(); 223 } 224 225 /// <summary> 226 /// Any initialization that happens before each test can 227 /// go here 228 /// </summary> SetUp()229 [SetUp] public void SetUp() 230 { 231 ResetRepository(); 232 RegisterRemotingServerChannel(); 233 } 234 235 /// <summary> 236 /// Any steps that happen after each test go here 237 /// </summary> TearDown()238 [TearDown] public void TearDown() 239 { 240 ResetRepository(); 241 } 242 243 /// <summary> 244 /// Configures the root appender for counting and rolling 245 /// </summary> ConfigureRootAppender(FixFlags fixFlags)246 private void ConfigureRootAppender(FixFlags fixFlags) 247 { 248 log4net.Repository.Hierarchy.Logger root = null; 249 root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root; 250 root.Level = Level.Debug; 251 root.AddAppender(CreateAppender(fixFlags)); 252 root.Repository.Configured = true; 253 } 254 CreateAppender(FixFlags fixFlags)255 private RemotingAppender CreateAppender(FixFlags fixFlags) 256 { 257 RemotingAppender appender = new RemotingAppender(); 258 appender.Sink = "tcp://localhost:8085/LoggingSink"; 259 appender.Lossy = false; 260 appender.BufferSize = 1; 261 appender.Fix = fixFlags; 262 263 appender.ActivateOptions(); 264 265 return appender; 266 } 267 268 public class RemoteLoggingSinkImpl : MarshalByRefObject, IRemoteLoggingSink 269 { 270 public static readonly RemoteLoggingSinkImpl Instance = new RemoteLoggingSinkImpl(); 271 272 private ArrayList m_events = new ArrayList(); 273 274 #region Public Instance Constructors 275 RemoteLoggingSinkImpl()276 private RemoteLoggingSinkImpl() 277 { 278 } 279 280 #endregion Public Instance Constructors 281 282 #region Implementation of IRemoteLoggingSink 283 284 /// <summary> 285 /// Logs the events to to an internal buffer 286 /// </summary> 287 /// <param name="events">The events to log.</param> 288 /// <remarks> 289 /// Logs the events to to an internal buffer. The logged events can 290 /// be retrieved via the <see cref="Events"/> property. To clear 291 /// the buffer call the <see cref="Reset"/> method. 292 /// </remarks> LogEvents(LoggingEvent[] events)293 public void LogEvents(LoggingEvent[] events) 294 { 295 m_events.AddRange(events); 296 } 297 298 #endregion Implementation of IRemoteLoggingSink 299 300 #region Override implementation of MarshalByRefObject 301 302 /// <summary> 303 /// Obtains a lifetime service object to control the lifetime 304 /// policy for this instance. 305 /// </summary> 306 /// <returns> 307 /// <c>null</c> to indicate that this instance should live 308 /// forever. 309 /// </returns> InitializeLifetimeService()310 public override object InitializeLifetimeService() 311 { 312 return null; 313 } 314 315 #endregion Override implementation of MarshalByRefObject 316 Reset()317 public void Reset() 318 { 319 m_events.Clear(); 320 } 321 322 public LoggingEvent[] Events 323 { 324 get 325 { 326 return (LoggingEvent[])m_events.ToArray(typeof(LoggingEvent)); 327 } 328 } 329 } 330 331 // 332 // Helper functions to dig into the appender 333 // 334 GetLoggingEventData(LoggingEvent loggingEvent)335 private static LoggingEventData GetLoggingEventData(LoggingEvent loggingEvent) 336 { 337 return (LoggingEventData)Utils.GetField(loggingEvent, "m_data"); 338 } 339 } 340 } 341 342 // helper for TestNestedNdc 343 namespace log4net.Tests.Appender.Remoting.UserInterfaces 344 { 345 public class TestService 346 { 347 static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 348 Test()349 public void Test() 350 { 351 log.Info("begin test"); 352 System.Threading.Thread.Sleep(100); 353 354 Feature f = new Feature(); 355 f.Test(); 356 log.Info("end test"); 357 System.Threading.Thread.Sleep(100); 358 } 359 } 360 } 361 // helper for TestNestedNdc 362 namespace log4net.Tests.Appender.Remoting 363 { 364 public class Feature 365 { 366 static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 367 Test()368 public void Test() 369 { 370 using(NDC.Push("test1")) 371 { 372 log.Info("feature"); 373 System.Threading.Thread.Sleep(100); 374 375 log4net.Tests.Appender.Remoting.Data.Dal d = new log4net.Tests.Appender.Remoting.Data.Dal(); 376 d.Test(); 377 log.Info("return"); 378 System.Threading.Thread.Sleep(100); 379 } 380 } 381 } 382 } 383 // helper for TestNestedNdc 384 namespace log4net.Tests.Appender.Remoting.Data 385 { 386 public class Dal 387 { 388 static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 389 Test()390 public void Test() 391 { 392 using(NDC.Push("test2")) 393 { 394 log.Info("return"); 395 System.Threading.Thread.Sleep(100); 396 } 397 } 398 } 399 } 400 401 402