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