001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.logging.jdk14;
019
020
021 import java.io.ByteArrayOutputStream;
022 import java.io.InputStream;
023 import java.lang.reflect.Method;
024 import java.util.Iterator;
025 import java.util.logging.Handler;
026 import java.util.logging.Level;
027 import java.util.logging.LogManager;
028 import java.util.logging.LogRecord;
029 import java.util.logging.Logger;
030
031 import junit.framework.Test;
032
033 import org.apache.commons.logging.DummyException;
034 import org.apache.commons.logging.PathableClassLoader;
035 import org.apache.commons.logging.PathableTestSuite;
036
037
038 /**
039 * <p>TestCase for JDK 1.4 logging when running on a JDK 1.4 system with
040 * custom configuration, so that JDK 1.4 should be selected and an appropriate
041 * logger configured per the configuration properties.</p>
042 *
043 * @author Craig R. McClanahan
044 * @version $Revision: 568760 $ $Date: 2007-08-23 00:19:45 +0200 (to, 23 aug 2007) $
045 */
046
047 public class CustomConfigTestCase extends DefaultConfigTestCase {
048
049 protected static final String HANDLER_NAME
050 = "org.apache.commons.logging.jdk14.TestHandler";
051
052 // ----------------------------------------------------------- Constructors
053
054
055 /**
056 * <p>Construct a new instance of this test case.</p>
057 *
058 * @param name Name of the test case
059 */
060 public CustomConfigTestCase(String name) {
061 super(name);
062 }
063
064
065 // ----------------------------------------------------- Instance Variables
066
067
068 /**
069 * <p>The customized <code>Handler</code> we will be using.</p>
070 */
071 protected TestHandler handler = null;
072
073
074 /**
075 * <p>The underlying <code>Handler</code>s we will be using.</p>
076 */
077 protected Handler handlers[] = null;
078
079
080 /**
081 * <p>The underlying <code>Logger</code> we will be using.</p>
082 */
083 protected Logger logger = null;
084
085
086 /**
087 * <p>The underlying <code>LogManager</code> we will be using.</p>
088 */
089 protected LogManager manager = null;
090
091
092 /**
093 * <p>The message levels that should have been logged.</p>
094 */
095 protected Level testLevels[] =
096 { Level.FINE, Level.INFO, Level.WARNING, Level.SEVERE, Level.SEVERE };
097
098
099 /**
100 * <p>The message strings that should have been logged.</p>
101 */
102 protected String testMessages[] =
103 { "debug", "info", "warn", "error", "fatal" };
104
105
106 // ------------------------------------------- JUnit Infrastructure Methods
107
108
109 /**
110 * Given the name of a class that is somewhere in the classpath of the provided
111 * classloader, return the contents of the corresponding .class file.
112 */
113 protected static byte[] readClass(String name, ClassLoader srcCL) throws Exception {
114 String resName = name.replace('.', '/') + ".class";
115 System.err.println("Trying to load resource [" + resName + "]");
116 InputStream is = srcCL.getResourceAsStream(resName);
117 ByteArrayOutputStream baos = new ByteArrayOutputStream();
118 System.err.println("Reading resource [" + resName + "]");
119 byte[] buf = new byte[1000];
120 for(;;) {
121 int read = is.read(buf);
122 if (read <= 0) {
123 break;
124 }
125 baos.write(buf, 0, read);
126 }
127 is.close();
128 return baos.toByteArray();
129 }
130
131 /**
132 * Make a class available in the system classloader even when its classfile is
133 * not present in the classpath configured for that classloader. This only
134 * works for classes for which all dependencies are already loaded in
135 * that classloader.
136 */
137 protected static void loadTestHandler(String className, ClassLoader targetCL) {
138 try {
139 targetCL.loadClass(className);
140 // fail("Class already in target classloader");
141 return;
142 } catch(ClassNotFoundException ex) {
143 // ok, go ahead and load it
144 }
145
146 try {
147 ClassLoader srcCL = CustomConfigAPITestCase.class.getClassLoader();
148 byte[] classData = readClass(className, srcCL);
149
150 Class[] params = new Class[] {
151 String.class, classData.getClass(),
152 Integer.TYPE, Integer.TYPE};
153 Method m = ClassLoader.class.getDeclaredMethod("defineClass", params);
154
155 Object[] args = new Object[4];
156 args[0] = className;
157 args[1] = classData;
158 args[2] = new Integer(0);
159 args[3] = new Integer(classData.length);
160 m.setAccessible(true);
161 m.invoke(targetCL, args);
162 } catch(Exception e) {
163 e.printStackTrace();
164 fail("Unable to load class " + className);
165 }
166 }
167
168 /**
169 * Set up instance variables required by this test case.
170 */
171 public void setUp() throws Exception {
172 setUpManager
173 ("org/apache/commons/logging/jdk14/CustomConfig.properties");
174 setUpLogger("TestLogger");
175 setUpHandlers();
176 setUpFactory();
177 setUpLog("TestLogger");
178 }
179
180
181 /**
182 * Return the tests included in this test suite.
183 */
184 public static Test suite() throws Exception {
185 PathableClassLoader cl = new PathableClassLoader(null);
186 cl.useExplicitLoader("junit.", Test.class.getClassLoader());
187
188 // the TestHandler class must be accessable from the System classloader
189 // in order for java.util.logging.LogManager.readConfiguration to
190 // be able to instantiate it. And this test case must see the same
191 // class in order to be able to access its data. Yes this is ugly
192 // but the whole jdk14 API is a ******* mess anyway.
193 ClassLoader scl = ClassLoader.getSystemClassLoader();
194 loadTestHandler(HANDLER_NAME, scl);
195 cl.useExplicitLoader(HANDLER_NAME, scl);
196 cl.addLogicalLib("commons-logging");
197 cl.addLogicalLib("testclasses");
198
199 Class testClass = cl.loadClass(CustomConfigTestCase.class.getName());
200 return new PathableTestSuite(testClass, cl);
201 }
202
203 /**
204 * Tear down instance variables required by this test case.
205 */
206 public void tearDown() {
207 super.tearDown();
208 handlers = null;
209 logger = null;
210 manager = null;
211 }
212
213
214 // ----------------------------------------------------------- Test Methods
215
216
217 // Test logging message strings with exceptions
218 public void testExceptionMessages() throws Exception {
219
220 logExceptionMessages();
221 checkLogRecords(true);
222
223 }
224
225
226 // Test logging plain message strings
227 public void testPlainMessages() throws Exception {
228
229 logPlainMessages();
230 checkLogRecords(false);
231
232 }
233
234
235 // Test pristine Handlers instances
236 public void testPristineHandlers() {
237
238 assertNotNull(handlers);
239 assertEquals(1, handlers.length);
240 assertTrue(handlers[0] instanceof TestHandler);
241 assertNotNull(handler);
242
243 }
244
245
246 // Test pristine Logger instance
247 public void testPristineLogger() {
248
249 assertNotNull("Logger exists", logger);
250 assertEquals("Logger name", "TestLogger", logger.getName());
251
252 // Assert which logging levels have been enabled
253 assertTrue(logger.isLoggable(Level.SEVERE));
254 assertTrue(logger.isLoggable(Level.WARNING));
255 assertTrue(logger.isLoggable(Level.INFO));
256 assertTrue(logger.isLoggable(Level.CONFIG));
257 assertTrue(logger.isLoggable(Level.FINE));
258 assertTrue(!logger.isLoggable(Level.FINER));
259 assertTrue(!logger.isLoggable(Level.FINEST));
260
261 }
262
263
264 // Test Serializability of Log instance
265 public void testSerializable() throws Exception {
266
267 super.testSerializable();
268 testExceptionMessages();
269
270 }
271
272
273 // -------------------------------------------------------- Support Methods
274
275
276 // Check the log instance
277 protected void checkLog() {
278
279 assertNotNull("Log exists", log);
280 assertEquals("Log class",
281 "org.apache.commons.logging.impl.Jdk14Logger",
282 log.getClass().getName());
283
284 // Assert which logging levels have been enabled
285 assertTrue(log.isFatalEnabled());
286 assertTrue(log.isErrorEnabled());
287 assertTrue(log.isWarnEnabled());
288 assertTrue(log.isInfoEnabled());
289 assertTrue(log.isDebugEnabled());
290 assertTrue(!log.isTraceEnabled());
291
292 }
293
294
295 // Check the recorded messages
296 protected void checkLogRecords(boolean thrown) {
297 Iterator records = handler.records();
298 for (int i = 0; i < testMessages.length; i++) {
299 assertTrue(records.hasNext());
300 LogRecord record = (LogRecord) records.next();
301 assertEquals("LogRecord level",
302 testLevels[i], record.getLevel());
303 assertEquals("LogRecord message",
304 testMessages[i], record.getMessage());
305 assertTrue("LogRecord class",
306 record.getSourceClassName().startsWith(
307 "org.apache.commons.logging.jdk14.CustomConfig"));
308 if (thrown) {
309 assertEquals("LogRecord method",
310 "logExceptionMessages",
311 record.getSourceMethodName());
312 } else {
313 assertEquals("LogRecord method",
314 "logPlainMessages",
315 record.getSourceMethodName());
316 }
317 if (thrown) {
318 assertNotNull("LogRecord thrown", record.getThrown());
319 assertTrue("LogRecord thrown type",
320 record.getThrown() instanceof DummyException);
321 } else {
322 assertNull("LogRecord thrown",
323 record.getThrown());
324 }
325 }
326 assertTrue(!records.hasNext());
327 handler.flush();
328 }
329
330
331 // Log the messages with exceptions
332 protected void logExceptionMessages() {
333 Throwable t = new DummyException();
334 log.trace("trace", t); // Should not actually get logged
335 log.debug("debug", t);
336 log.info("info", t);
337 log.warn("warn", t);
338 log.error("error", t);
339 log.fatal("fatal", t);
340 }
341
342
343 // Log the plain messages
344 protected void logPlainMessages() {
345 log.trace("trace"); // Should not actually get logged
346 log.debug("debug");
347 log.info("info");
348 log.warn("warn");
349 log.error("error");
350 log.fatal("fatal");
351 }
352
353
354 // Set up handlers instance
355 protected void setUpHandlers() throws Exception {
356 Logger parent = logger;
357 while (parent.getParent() != null) {
358 parent = parent.getParent();
359 }
360 handlers = parent.getHandlers();
361
362 // The CustomConfig.properties file explicitly defines one handler class
363 // to be attached to the root logger, so if it isn't there then
364 // something is badly wrong...
365 //
366 // Yes this testing is also done in testPristineHandlers but
367 // unfortunately:
368 // * we need to set up the handlers variable here,
369 // * we don't want that to be set up incorrectly, as that can
370 // produce weird error messages in other tests, and
371 // * we can't rely on testPristineHandlers being the first
372 // test to run.
373 // so we need to test things here too.
374 assertNotNull("No Handlers defined for JDK14 logging", handlers);
375 assertEquals("Unexpected number of handlers for JDK14 logging", 1, handlers.length);
376 assertNotNull("Handler is null", handlers[0]);
377 assertTrue("Handler not of expected type", handlers[0] instanceof TestHandler);
378 handler = (TestHandler) handlers[0];
379 }
380
381
382 // Set up logger instance
383 protected void setUpLogger(String name) throws Exception {
384 logger = Logger.getLogger(name);
385 }
386
387
388 // Set up LogManager instance
389 protected void setUpManager(String config) throws Exception {
390 manager = LogManager.getLogManager();
391 InputStream is =
392 this.getClass().getClassLoader().getResourceAsStream(config);
393 manager.readConfiguration(is);
394 is.close();
395 }
396
397
398 }