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
18package org.apache.harmony.logging.tests.java.util.logging;
19
20import java.io.ByteArrayOutputStream;
21import java.io.IOException;
22import java.io.OutputStream;
23import java.io.PrintStream;
24import java.security.Permission;
25import java.util.Properties;
26import java.util.logging.ConsoleHandler;
27import java.util.logging.Filter;
28import java.util.logging.Formatter;
29import java.util.logging.Handler;
30import java.util.logging.Level;
31import java.util.logging.LogManager;
32import java.util.logging.LogRecord;
33import java.util.logging.LoggingPermission;
34import java.util.logging.SimpleFormatter;
35
36import junit.framework.TestCase;
37
38import org.apache.harmony.logging.tests.java.util.logging.util.EnvironmentHelper;
39
40import tests.util.CallVerificationStack;
41
42/**
43 * Test class java.util.logging.ConsoleHandler
44 */
45public class ConsoleHandlerTest extends TestCase {
46
47    private final static String INVALID_LEVEL = "impossible_level";
48
49    private final PrintStream err = System.err;
50
51    private OutputStream errSubstituteStream = null;
52
53    private static String className = ConsoleHandlerTest.class.getName();
54
55    /*
56      * @see TestCase#setUp()
57      */
58    protected void setUp() throws Exception {
59        super.setUp();
60        errSubstituteStream = new MockOutputStream();
61        System.setErr(new PrintStream(errSubstituteStream));
62        LogManager.getLogManager().reset();
63    }
64
65    /*
66      * @see TestCase#tearDown()
67      */
68    protected void tearDown() throws Exception {
69        super.tearDown();
70        LogManager.getLogManager().reset();
71        CallVerificationStack.getInstance().clear();
72        System.setErr(err);
73    }
74
75    /*
76      * Test the constructor with no relevant log manager properties are set.
77      */
78    public void testConstructor_NoProperties() {
79        assertNull(LogManager.getLogManager().getProperty(
80                "java.util.logging.ConsoleHandler.level"));
81        assertNull(LogManager.getLogManager().getProperty(
82                "java.util.logging.ConsoleHandler.filter"));
83        assertNull(LogManager.getLogManager().getProperty(
84                "java.util.logging.ConsoleHandler.formatter"));
85        assertNull(LogManager.getLogManager().getProperty(
86                "java.util.logging.ConsoleHandler.encoding"));
87
88        ConsoleHandler h = new ConsoleHandler();
89        assertSame(h.getLevel(), Level.INFO);
90        assertTrue(h.getFormatter() instanceof SimpleFormatter);
91        assertNull(h.getFilter());
92        assertSame(h.getEncoding(), null);
93    }
94
95    /*
96      * Test the constructor with valid relevant log manager properties are set.
97      */
98    public void testConstructor_ValidProperties() throws Exception {
99        Properties p = new Properties();
100        p.put("java.util.logging.ConsoleHandler.level", "FINE");
101        p.put("java.util.logging.ConsoleHandler.filter", className
102                + "$MockFilter");
103        p.put("java.util.logging.ConsoleHandler.formatter", className
104                + "$MockFormatter");
105        p.put("java.util.logging.ConsoleHandler.encoding", "iso-8859-1");
106        LogManager.getLogManager().readConfiguration(
107                EnvironmentHelper.PropertiesToInputStream(p));
108
109        assertEquals(LogManager.getLogManager().getProperty(
110                "java.util.logging.ConsoleHandler.level"), "FINE");
111        assertEquals(LogManager.getLogManager().getProperty(
112                "java.util.logging.ConsoleHandler.encoding"), "iso-8859-1");
113        ConsoleHandler h = new ConsoleHandler();
114        assertSame(h.getLevel(), Level.parse("FINE"));
115        assertTrue(h.getFormatter() instanceof MockFormatter);
116        assertTrue(h.getFilter() instanceof MockFilter);
117        assertEquals(h.getEncoding(), "iso-8859-1");
118    }
119
120    /*
121      * Test the constructor with invalid relevant log manager properties are
122      * set.
123      */
124    public void testConstructor_InvalidProperties() throws Exception {
125        Properties p = new Properties();
126        p.put("java.util.logging.ConsoleHandler.level", INVALID_LEVEL);
127        p.put("java.util.logging.ConsoleHandler.filter", className);
128        p.put("java.util.logging.ConsoleHandler.formatter", className);
129        p.put("java.util.logging.ConsoleHandler.encoding", "XXXX");
130        LogManager.getLogManager().readConfiguration(
131                EnvironmentHelper.PropertiesToInputStream(p));
132
133        assertEquals(LogManager.getLogManager().getProperty(
134                "java.util.logging.ConsoleHandler.level"), INVALID_LEVEL);
135        assertEquals(LogManager.getLogManager().getProperty(
136                "java.util.logging.ConsoleHandler.encoding"), "XXXX");
137        ConsoleHandler h = new ConsoleHandler();
138        assertSame(h.getLevel(), Level.INFO);
139        assertTrue(h.getFormatter() instanceof SimpleFormatter);
140        assertNull(h.getFilter());
141        assertNull(h.getEncoding());
142        h.publish(new LogRecord(Level.SEVERE, "test"));
143        assertNull(h.getEncoding());
144    }
145
146    /*
147      * Test close() when having sufficient privilege, and a record has been
148      * written to the output stream.
149      */
150    public void testClose_SufficientPrivilege_NormalClose() throws Exception {
151        Properties p = new Properties();
152        p.put("java.util.logging.ConsoleHandler.formatter", className
153                + "$MockFormatter");
154        LogManager.getLogManager().readConfiguration(
155                EnvironmentHelper.PropertiesToInputStream(p));
156        ConsoleHandler h = new ConsoleHandler();
157        h.publish(new LogRecord(Level.SEVERE,
158                "testClose_SufficientPrivilege_NormalClose msg"));
159        h.close();
160        assertEquals("flush", CallVerificationStack.getInstance()
161                .getCurrentSourceMethod());
162        assertNull(CallVerificationStack.getInstance().pop());
163        h.close();
164    }
165
166    /*
167      * Test close() when having sufficient privilege, and an output stream that
168      * always throws exceptions.
169      */
170    public void testClose_SufficientPrivilege_Exception() throws Exception {
171        Properties p = new Properties();
172        p.put("java.util.logging.ConsoleHandler.formatter", className
173                + "$MockFormatter");
174        LogManager.getLogManager().readConfiguration(
175                EnvironmentHelper.PropertiesToInputStream(p));
176        ConsoleHandler h = new ConsoleHandler();
177
178        h.publish(new LogRecord(Level.SEVERE,
179                "testClose_SufficientPrivilege_Exception msg"));
180        h.flush();
181        h.close();
182    }
183
184    /*
185      * Test close() when having sufficient privilege, and no record has been
186      * written to the output stream.
187      */
188    public void testClose_SufficientPrivilege_DirectClose() throws Exception {
189        Properties p = new Properties();
190        p.put("java.util.logging.ConsoleHandler.formatter", className
191                + "$MockFormatter");
192        LogManager.getLogManager().readConfiguration(
193                EnvironmentHelper.PropertiesToInputStream(p));
194        ConsoleHandler h = new ConsoleHandler();
195
196        h.close();
197        assertEquals("flush", CallVerificationStack.getInstance()
198                .getCurrentSourceMethod());
199        assertNull(CallVerificationStack.getInstance().pop());
200        assertTrue(CallVerificationStack.getInstance().empty());
201    }
202
203    /*
204      * Test publish(), use no filter, having output stream, normal log record.
205      */
206    public void testPublish_NoFilter() throws Exception {
207        Properties p = new Properties();
208        p.put("java.util.logging.ConsoleHandler.formatter", className
209                + "$MockFormatter");
210        LogManager.getLogManager().readConfiguration(
211                EnvironmentHelper.PropertiesToInputStream(p));
212        ConsoleHandler h = new ConsoleHandler();
213
214        LogRecord r = new LogRecord(Level.INFO, "testPublish_NoFilter");
215        h.setLevel(Level.INFO);
216        h.publish(r);
217        h.flush();
218        assertEquals("MockFormatter_Head" + "testPublish_NoFilter",
219                this.errSubstituteStream.toString());
220
221        h.setLevel(Level.WARNING);
222        h.publish(r);
223        h.flush();
224        assertEquals("MockFormatter_Head" + "testPublish_NoFilter",
225                this.errSubstituteStream.toString());
226
227        h.setLevel(Level.CONFIG);
228        h.publish(r);
229        h.flush();
230        assertEquals("MockFormatter_Head" + "testPublish_NoFilter"
231                + "testPublish_NoFilter", this.errSubstituteStream.toString());
232
233        r.setLevel(Level.OFF);
234        h.setLevel(Level.OFF);
235        h.publish(r);
236        h.flush();
237        assertEquals("MockFormatter_Head" + "testPublish_NoFilter"
238                + "testPublish_NoFilter", this.errSubstituteStream.toString());
239    }
240
241    /*
242      * Test publish(), after system err is reset.
243      */
244    public void testPublish_AfterResetSystemErr() throws Exception {
245        Properties p = new Properties();
246        p.put("java.util.logging.ConsoleHandler.formatter", className
247                + "$MockFormatter");
248        LogManager.getLogManager().readConfiguration(
249                EnvironmentHelper.PropertiesToInputStream(p));
250        ConsoleHandler h = new ConsoleHandler();
251        h.setFilter(new MockFilter());
252
253        System.setErr(new PrintStream(new ByteArrayOutputStream()));
254
255        LogRecord r = new LogRecord(Level.INFO, "testPublish_WithFilter");
256        h.setLevel(Level.INFO);
257        h.publish(r);
258        assertNull(CallVerificationStack.getInstance().pop());
259        assertSame(r, CallVerificationStack.getInstance().pop());
260        assertEquals("", this.errSubstituteStream.toString());
261    }
262
263    /*
264      * Test publish(), use a filter, having output stream, normal log record.
265      */
266    public void testPublish_WithFilter() throws Exception {
267        Properties p = new Properties();
268        p.put("java.util.logging.ConsoleHandler.formatter", className
269                + "$MockFormatter");
270        LogManager.getLogManager().readConfiguration(
271                EnvironmentHelper.PropertiesToInputStream(p));
272        ConsoleHandler h = new ConsoleHandler();
273        h.setFilter(new MockFilter());
274
275        LogRecord r = new LogRecord(Level.INFO, "testPublish_WithFilter");
276        h.setLevel(Level.INFO);
277        h.publish(r);
278        assertNull(CallVerificationStack.getInstance().pop());
279        assertSame(r, CallVerificationStack.getInstance().pop());
280        assertEquals("", this.errSubstituteStream.toString());
281
282        h.setLevel(Level.WARNING);
283        h.publish(r);
284        assertNull(CallVerificationStack.getInstance().pop());
285        assertTrue(CallVerificationStack.getInstance().empty());
286        assertEquals("", this.errSubstituteStream.toString());
287
288        h.setLevel(Level.CONFIG);
289        h.publish(r);
290        assertNull(CallVerificationStack.getInstance().pop());
291        assertSame(r, CallVerificationStack.getInstance().pop());
292        assertEquals("", this.errSubstituteStream.toString());
293
294        r.setLevel(Level.OFF);
295        h.setLevel(Level.OFF);
296        h.publish(r);
297        assertNull(CallVerificationStack.getInstance().pop());
298        assertEquals("", this.errSubstituteStream.toString());
299        assertTrue(CallVerificationStack.getInstance().empty());
300    }
301
302    /*
303      * Test publish(), null log record, having output stream, spec said
304      * rather than throw exception, handler should call errormanager to handle
305      * exception case, so NullPointerException shouldn't be thrown.
306      */
307    public void testPublish_Null() throws Exception {
308        Properties p = new Properties();
309        p.put("java.util.logging.ConsoleHandler.formatter", className
310                + "$MockFormatter");
311        LogManager.getLogManager().readConfiguration(
312                EnvironmentHelper.PropertiesToInputStream(p));
313        ConsoleHandler h = new ConsoleHandler();
314        h.publish(null);
315    }
316
317    /*
318      * Test publish(), a log record with empty msg, having output stream
319      */
320    public void testPublish_EmptyMsg() throws Exception {
321        Properties p = new Properties();
322        p.put("java.util.logging.ConsoleHandler.formatter", className
323                + "$MockFormatter");
324        LogManager.getLogManager().readConfiguration(
325                EnvironmentHelper.PropertiesToInputStream(p));
326        ConsoleHandler h = new ConsoleHandler();
327        LogRecord r = new LogRecord(Level.INFO, "");
328        h.publish(r);
329        h.flush();
330        assertEquals("MockFormatter_Head", this.errSubstituteStream.toString());
331    }
332
333    /*
334      * Test publish(), a log record with null msg, having output stream
335      */
336    public void testPublish_NullMsg() throws Exception {
337        Properties p = new Properties();
338        p.put("java.util.logging.ConsoleHandler.formatter", className
339                + "$MockFormatter");
340        LogManager.getLogManager().readConfiguration(
341                EnvironmentHelper.PropertiesToInputStream(p));
342        ConsoleHandler h = new ConsoleHandler();
343        LogRecord r = new LogRecord(Level.INFO, null);
344        h.publish(r);
345        h.flush();
346        // assertEquals("MockFormatter_Head",
347        // this.errSubstituteStream.toString());
348    }
349
350    public void testPublish_AfterClose() throws Exception {
351        PrintStream backup = System.err;
352        try {
353            ByteArrayOutputStream bos = new ByteArrayOutputStream();
354            System.setErr(new PrintStream(bos));
355            Properties p = new Properties();
356            p.put("java.util.logging.ConsoleHandler.level", "FINE");
357            p.put("java.util.logging.ConsoleHandler.formatter", className
358                    + "$MockFormatter");
359            LogManager.getLogManager().readConfiguration(
360                    EnvironmentHelper.PropertiesToInputStream(p));
361            ConsoleHandler h = new ConsoleHandler();
362            assertSame(h.getLevel(), Level.FINE);
363            LogRecord r1 = new LogRecord(Level.INFO, "testPublish_Record1");
364            LogRecord r2 = new LogRecord(Level.INFO, "testPublish_Record2");
365            assertTrue(h.isLoggable(r1));
366            h.publish(r1);
367            assertTrue(bos.toString().indexOf("testPublish_Record1") >= 0);
368            h.close();
369            // assertFalse(h.isLoggable(r));
370            assertTrue(h.isLoggable(r2));
371            h.publish(r2);
372            assertTrue(bos.toString().indexOf("testPublish_Record2") >= 0);
373            h.flush();
374            // assertEquals("MockFormatter_Head",
375            // this.errSubstituteStream.toString());
376        } catch (IOException e) {
377            e.printStackTrace();
378        } finally {
379            System.setErr(backup);
380        }
381    }
382
383    /*
384      * Test setOutputStream() under normal condition.
385      */
386    public void testSetOutputStream_Normal() {
387        MockStreamHandler h = new MockStreamHandler();
388        h.setFormatter(new MockFormatter());
389
390        LogRecord r = new LogRecord(Level.INFO, "testSetOutputStream_Normal");
391        h.publish(r);
392        assertNull(CallVerificationStack.getInstance().pop());
393        assertSame(r, CallVerificationStack.getInstance().pop());
394        assertTrue(CallVerificationStack.getInstance().empty());
395        assertEquals("MockFormatter_Head" + "testSetOutputStream_Normal",
396                this.errSubstituteStream.toString());
397
398        ByteArrayOutputStream aos2 = new ByteArrayOutputStream();
399        h.setOutputStream(aos2);
400
401        // assertEquals("close", DelegationParameterStack.getInstance()
402        // .getCurrentSourceMethod());
403        // assertNull(DelegationParameterStack.getInstance().pop());
404        // assertEquals("flush", DelegationParameterStack.getInstance()
405        // .getCurrentSourceMethod());
406        // assertNull(DelegationParameterStack.getInstance().pop());
407        // assertEquals("MockFormatter_Head" + "testSetOutputStream_Normal"
408        // + "MockFormatter_Tail", this.errSubstituteStream.toString());
409        // r = new LogRecord(Level.INFO, "testSetOutputStream_Normal2");
410        // h.publish(r);
411        // assertSame(r, DelegationParameterStack.getInstance().pop());
412        // assertTrue(DelegationParameterStack.getInstance().empty());
413        // assertEquals("MockFormatter_Head" + "testSetOutputStream_Normal2",
414        // aos2
415        // .toString());
416        // assertEquals("MockFormatter_Head" + "testSetOutputStream_Normal"
417        // + "MockFormatter_Tail", this.errSubstituteStream.toString());
418    }
419
420    /*
421      * A mock filter, always return false.
422      */
423    public static class MockFilter implements Filter {
424
425        public boolean isLoggable(LogRecord record) {
426            CallVerificationStack.getInstance().push(record);
427            // System.out.println("filter called...");
428            return false;
429        }
430    }
431
432    /*
433      * A mock formatter.
434      */
435    public static class MockFormatter extends Formatter {
436        public String format(LogRecord r) {
437            // System.out.println("formatter called...");
438            return super.formatMessage(r);
439        }
440
441        /*
442           * (non-Javadoc)
443           *
444           * @see java.util.logging.Formatter#getHead(java.util.logging.Handler)
445           */
446        public String getHead(Handler h) {
447            return "MockFormatter_Head";
448        }
449
450        /*
451           * (non-Javadoc)
452           *
453           * @see java.util.logging.Formatter#getTail(java.util.logging.Handler)
454           */
455        public String getTail(Handler h) {
456            return "MockFormatter_Tail";
457        }
458    }
459
460    /*
461      * A mock output stream.
462      */
463    public static class MockOutputStream extends ByteArrayOutputStream {
464
465        /*
466           * (non-Javadoc)
467           *
468           * @see java.io.OutputStream#close()
469           */
470        public void close() throws IOException {
471            CallVerificationStack.getInstance().push(null);
472            super.close();
473        }
474
475        /*
476           * (non-Javadoc)
477           *
478           * @see java.io.OutputStream#flush()
479           */
480        public void flush() throws IOException {
481            CallVerificationStack.getInstance().push(null);
482            super.flush();
483        }
484
485        /*
486           * (non-Javadoc)
487           *
488           * @see java.io.OutputStream#write(int)
489           */
490        public void write(int oneByte) {
491            // TODO Auto-generated method stub
492            super.write(oneByte);
493        }
494    }
495
496    /*
497      * A mock stream handler, expose setOutputStream.
498      */
499    public static class MockStreamHandler extends ConsoleHandler {
500        public MockStreamHandler() {
501            super();
502        }
503
504        public void setOutputStream(OutputStream out) {
505            super.setOutputStream(out);
506        }
507
508        public boolean isLoggable(LogRecord r) {
509            CallVerificationStack.getInstance().push(r);
510            return super.isLoggable(r);
511        }
512    }
513
514}
515