1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  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  
18  package org.apache.log4j.net;
19  
20  import junit.framework.TestCase;
21  import junit.framework.TestSuite;
22  import junit.framework.Test;
23  
24  import org.apache.log4j.*;
25  import org.apache.log4j.util.*;
26  
27  
28  import org.apache.log4j.Logger;
29  import org.apache.log4j.NDC;
30  import org.apache.log4j.xml.XLevel;
31  
32  /**
33     @author  Ceki Gülcü
34  */
35  public class SocketServerTestCase extends TestCase {
36    
37    static String TEMP = "output/temp";
38    static String FILTERED = "output/filtered";
39  
40    // %5p %x [%t] %c %m%n
41    // DEBUG T1 [main] org.apache.log4j.net.SocketAppenderTestCase Message 1
42    static String PAT1 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) T1 \\[main]\\ "
43                         + ".* Message \\d{1,2}";
44  
45    // DEBUG T2 [main] ? (?:?) Message 1
46    static String PAT2 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) T2 \\[main]\\ "
47                         + "\\? \\(\\?:\\?\\) Message \\d{1,2}";
48  
49  
50    // DEBUG T3 [main] org.apache.log4j.net.SocketServerTestCase (SocketServerTestCase.java:121) Message 1
51    static String PAT3 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) T3 \\[main]\\ "
52                         + "org.apache.log4j.net.SocketServerTestCase "
53                         + "\\(SocketServerTestCase.java:\\d{3}\\) Message \\d{1,2}";
54  
55  
56    // DEBUG some T4 MDC-TEST4 [main] SocketAppenderTestCase - Message 1   
57    // DEBUG some T4 MDC-TEST4 [main] SocketAppenderTestCase - Message 1 
58    static String PAT4 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some T4 MDC-TEST4 \\[main]\\"
59                         + " (root|SocketServerTestCase) - Message \\d{1,2}";
60  
61    static String PAT5 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some5 T5 MDC-TEST5 \\[main]\\"
62                         + " (root|SocketServerTestCase) - Message \\d{1,2}";
63  
64    static String PAT6 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some6 T6 client-test6 MDC-TEST6"
65                         + " \\[main]\\ (root|SocketServerTestCase) - Message \\d{1,2}";
66  
67    static String PAT7 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some7 T7 client-test7 MDC-TEST7"
68                         + " \\[main]\\ (root|SocketServerTestCase) - Message \\d{1,2}";
69  
70    // DEBUG some8 T8 shortSocketServer MDC-TEST7 [main] SocketServerTestCase - Message 1
71    static String PAT8 = "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some8 T8 shortSocketServer"
72                         + " MDC-TEST8 \\[main]\\ (root|SocketServerTestCase) - Message \\d{1,2}";
73  
74  
75  
76    static String EXCEPTION1 = "java.lang.Exception: Just testing";
77    static String EXCEPTION2 = "\\s*at .*\\(.*\\)";
78    static String EXCEPTION3 = "\\s*at .*\\(Native Method\\)";
79    static String EXCEPTION4 = "\\s*at .*\\(.*Compiled Code\\)";
80    static String EXCEPTION5 = "\\s*at .*\\(.*libgcj.*\\)";
81  
82  
83    static Logger logger = Logger.getLogger(SocketServerTestCase.class);
84    static public final int PORT = 12345;  
85    static Logger rootLogger = Logger.getRootLogger();
86    SocketAppender socketAppender;
87  
88    public SocketServerTestCase(String name) {
89      super(name);
90    }
91  
92    public void setUp() {
93      System.out.println("Setting up test case.");
94    }
95    
96    public void tearDown() {
97      System.out.println("Tearing down test case.");
98      socketAppender = null;
99      rootLogger.removeAllAppenders();
100   }
101 
102   /**
103    * The pattern on the server side: %5p %x [%t] %c %m%n     
104    *
105    * We are testing NDC functionality across the wire.  
106    */
107   public void test1() throws Exception {
108     socketAppender = new SocketAppender("localhost", PORT);
109     rootLogger.addAppender(socketAppender);
110     common("T1", "key1", "MDC-TEST1");
111     delay(1);
112     ControlFilter cf = new ControlFilter(new String[]{PAT1, EXCEPTION1, 
113 						       EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
114     
115     Transformer.transform(
116       TEMP, FILTERED,
117       new Filter[] { cf, new LineNumberFilter(), 
118           new JunitTestRunnerFilter(),
119           new SunReflectFilter() });
120 
121     assertTrue(Compare.compare(FILTERED, "witness/socketServer.1"));
122   }
123 
124   /**
125    * The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
126    *
127    * We are testing NDC across the wire. Localization is turned off by
128    * default so it is not tested here even if the conversion pattern
129    * uses localization. */
130   public void test2() throws Exception {
131     socketAppender = new SocketAppender("localhost", PORT);
132     rootLogger.addAppender(socketAppender);
133 
134     common("T2", "key2", "MDC-TEST2");
135     delay(1);
136     ControlFilter cf = new ControlFilter(new String[]{PAT2, EXCEPTION1, 
137 						       EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
138     
139     Transformer.transform(
140       TEMP, FILTERED,
141       new Filter[] { cf, new LineNumberFilter(), 
142           new JunitTestRunnerFilter(),
143           new SunReflectFilter() });
144 
145     assertTrue(Compare.compare(FILTERED, "witness/socketServer.2"));
146   }
147 
148   /**
149    *  The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
150    *  meaning that we are testing NDC and locatization functionality
151    *  across the wire.  */
152   public void test3() throws Exception {
153     socketAppender = new SocketAppender("localhost", PORT);
154     socketAppender.setLocationInfo(true);
155     rootLogger.addAppender(socketAppender);
156 
157     common("T3", "key3", "MDC-TEST3");
158     delay(1);
159     ControlFilter cf = new ControlFilter(new String[]{PAT3, EXCEPTION1, 
160 						       EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
161     
162     Transformer.transform(
163       TEMP, FILTERED,
164       new Filter[] { cf, new LineNumberFilter(), 
165           new JunitTestRunnerFilter(),
166           new SunReflectFilter() });
167 
168     assertTrue(Compare.compare(FILTERED, "witness/socketServer.3"));
169   }
170 
171   /**
172    *  The pattern on the server side: %5p %x %X{key1}%X{key4} [%t] %c{1} - %m%n 
173    *  meaning that we are testing NDC, MDC and localization functionality across 
174    *  the wire.  
175   */
176   public void test4() throws Exception {
177     socketAppender = new SocketAppender("localhost", PORT);
178     socketAppender.setLocationInfo(true);
179     rootLogger.addAppender(socketAppender);
180 
181     NDC.push("some");
182     common("T4", "key4", "MDC-TEST4");
183     NDC.pop();
184     delay(1);
185     //
186     //  These tests check MDC operation which
187     //    requires JDK 1.2 or later
188     if(!System.getProperty("java.version").startsWith("1.1.")) {
189     
190         ControlFilter cf = new ControlFilter(new String[]{PAT4, EXCEPTION1, 
191 						           EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
192         Transformer.transform(
193           TEMP, FILTERED,
194           new Filter[] { cf, new LineNumberFilter(), 
195               new JunitTestRunnerFilter(),
196               new SunReflectFilter() });
197 
198         assertTrue(Compare.compare(FILTERED, "witness/socketServer.4"));
199     }
200   }
201 
202   /**
203    * The pattern on the server side: %5p %x %X{key1}%X{key5} [%t] %c{1} - %m%n 
204    *
205    * The test case uses wraps an AsyncAppender around the
206    * SocketAppender. This tests was written specifically for bug
207    * report #9155.
208 
209    * Prior to the bug fix the output on the server did not contain the
210    * MDC-TEST5 string because the MDC clone operation (in getMDCCopy
211    * method) operation is performed twice, once from the main thread
212    * which is correct, and a second time from the AsyncAppender's
213    * dispatch thread which is incrorrect.
214 
215    */
216   public void test5() throws Exception {
217     socketAppender = new SocketAppender("localhost", PORT);
218     socketAppender.setLocationInfo(true);
219     AsyncAppender asyncAppender = new AsyncAppender();
220     asyncAppender.setLocationInfo(true);
221     asyncAppender.addAppender(socketAppender);
222     rootLogger.addAppender(asyncAppender);
223 
224     NDC.push("some5");
225     common("T5", "key5", "MDC-TEST5");
226     NDC.pop();
227     delay(2);
228     //
229     //  These tests check MDC operation which
230     //    requires JDK 1.2 or later
231     if(!System.getProperty("java.version").startsWith("1.1.")) {
232         ControlFilter cf = new ControlFilter(new String[]{PAT5, EXCEPTION1, 
233 						           EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
234     
235         Transformer.transform(
236           TEMP, FILTERED,
237           new Filter[] { cf, new LineNumberFilter(), 
238               new JunitTestRunnerFilter(),
239               new SunReflectFilter() });
240 
241         assertTrue(Compare.compare(FILTERED, "witness/socketServer.5"));
242     }
243   }
244 
245   /**
246    * The pattern on the server side: %5p %x %X{hostID}${key6} [%t] %c{1} - %m%n 
247    *
248    * This test checks whether client-side MDC overrides the server side.
249    * It uses an AsyncAppender encapsulating a SocketAppender
250    */
251   public void test6() throws Exception {
252     socketAppender = new SocketAppender("localhost", PORT);
253     socketAppender.setLocationInfo(true);
254     AsyncAppender asyncAppender = new AsyncAppender();
255     asyncAppender.setLocationInfo(true);
256     asyncAppender.addAppender(socketAppender);
257     rootLogger.addAppender(asyncAppender);
258 
259     NDC.push("some6");
260     MDC.put("hostID", "client-test6");
261     common("T6", "key6", "MDC-TEST6");
262     NDC.pop();
263     MDC.remove("hostID");
264     delay(2);
265     //
266     //  These tests check MDC operation which
267     //    requires JDK 1.2 or later
268     if(!System.getProperty("java.version").startsWith("1.1.")) {
269         ControlFilter cf = new ControlFilter(new String[]{PAT6, EXCEPTION1, 
270 						           EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
271     
272         Transformer.transform(
273           TEMP, FILTERED,
274           new Filter[] { cf, new LineNumberFilter(), 
275               new JunitTestRunnerFilter(),
276               new SunReflectFilter() });
277 
278         assertTrue(Compare.compare(FILTERED, "witness/socketServer.6"));
279     }
280   }
281 
282   /**
283    * The pattern on the server side: %5p %x %X{hostID}${key7} [%t] %c{1} - %m%n 
284    *
285    * This test checks whether client-side MDC overrides the server side.
286    */
287   public void test7() throws Exception {
288     socketAppender = new SocketAppender("localhost", PORT);
289     socketAppender.setLocationInfo(true);
290     rootLogger.addAppender(socketAppender);
291 
292     NDC.push("some7");
293     MDC.put("hostID", "client-test7");
294     common("T7", "key7", "MDC-TEST7");
295     NDC.pop();
296     MDC.remove("hostID"); 
297     delay(2);
298     //
299     //  These tests check MDC operation which
300     //    requires JDK 1.2 or later
301     if(!System.getProperty("java.version").startsWith("1.1.")) {
302         ControlFilter cf = new ControlFilter(new String[]{PAT7, EXCEPTION1, 
303 						           EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
304     
305         Transformer.transform(
306           TEMP, FILTERED,
307           new Filter[] { cf, new LineNumberFilter(), 
308               new JunitTestRunnerFilter(),
309               new SunReflectFilter() });
310         assertTrue(Compare.compare(FILTERED, "witness/socketServer.7"));
311     }
312   }
313 
314   /**
315    * The pattern on the server side: %5p %x %X{hostID} ${key8} [%t] %c{1} - %m%n
316    *
317    * This test checks whether server side MDC works.
318    */
319   public void test8() throws Exception {
320     socketAppender = new SocketAppender("localhost", PORT);
321     socketAppender.setLocationInfo(true);
322     rootLogger.addAppender(socketAppender);
323 
324     NDC.push("some8");
325 
326     //
327     //   The test has relied on the receiving code to
328     //      combine the sent MDC with the receivers MDC
329     //      (which contains a value for hostID).
330     //      The mechanism of how that happens is not clear
331     //      and it does not work with Apache Harmony.
332     //      Unclear if it is a Harmony issue.
333     if (System.getProperty("java.vendor").indexOf("Apache") != -1) {
334         MDC.put("hostID", "shortSocketServer");
335     }
336 
337     common("T8", "key8", "MDC-TEST8");
338     NDC.pop();
339     delay(2);
340     //
341     //  These tests check MDC operation which
342     //    requires JDK 1.2 or later
343     if(!System.getProperty("java.version").startsWith("1.1.")) {
344         ControlFilter cf = new ControlFilter(new String[]{PAT8, EXCEPTION1, 
345 						           EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
346     
347         Transformer.transform(
348           TEMP, FILTERED,
349           new Filter[] { cf, new LineNumberFilter(), 
350               new JunitTestRunnerFilter(),
351               new SunReflectFilter() });
352         assertTrue(Compare.compare(FILTERED, "witness/socketServer.8"));
353     }
354   }
355 
356   static 
357   void common(String dc, String key, Object o) {
358     String oldThreadName = Thread.currentThread().getName();
359     Thread.currentThread().setName("main");
360 
361     int i = -1; 
362     NDC.push(dc); 
363     MDC.put(key, o);
364     Logger root = Logger.getRootLogger();
365 
366     logger.setLevel(Level.DEBUG);
367     rootLogger.setLevel(Level.DEBUG);
368     
369     logger.log(XLevel.TRACE, "Message " + ++i);
370 
371     logger.setLevel(Level.TRACE);
372     rootLogger.setLevel(Level.TRACE);
373     
374     logger.trace("Message " + ++i);
375     root.trace("Message " + ++i);
376     logger.debug("Message " + ++i);
377     root.debug("Message " + ++i);
378     logger.info("Message " + ++i);
379     logger.warn("Message " + ++i);
380     logger.log(XLevel.LETHAL, "Message " + ++i); //5
381     
382     Exception e = new Exception("Just testing");
383     logger.debug("Message " + ++i, e);
384     root.error("Message " + ++i, e);
385     NDC.pop();
386     MDC.remove(key);
387 
388     Thread.currentThread().setName(oldThreadName);
389   }
390 
391   public void delay(int secs) {
392     try {Thread.sleep(secs*1000);} catch(Exception e) {}
393   }
394 
395 
396   public static Test suite() {
397     TestSuite suite = new TestSuite();
398     suite.addTest(new SocketServerTestCase("test1"));
399     suite.addTest(new SocketServerTestCase("test2"));
400     suite.addTest(new SocketServerTestCase("test3"));
401     suite.addTest(new SocketServerTestCase("test4"));
402     suite.addTest(new SocketServerTestCase("test5"));
403     suite.addTest(new SocketServerTestCase("test6"));
404     suite.addTest(new SocketServerTestCase("test7"));
405     suite.addTest(new SocketServerTestCase("test8"));
406     return suite;
407   }
408 }