• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.harmony.logging.tests.java.util.logging;
19 
20 import java.io.BufferedInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.FilePermission;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.PrintStream;
31 import java.io.StringWriter;
32 import java.security.Permission;
33 import java.util.Properties;
34 import java.util.logging.FileHandler;
35 import java.util.logging.Filter;
36 import java.util.logging.Formatter;
37 import java.util.logging.Handler;
38 import java.util.logging.Level;
39 import java.util.logging.LogManager;
40 import java.util.logging.LogRecord;
41 import java.util.logging.LoggingPermission;
42 import java.util.logging.XMLFormatter;
43 
44 import junit.framework.TestCase;
45 
46 import org.apache.harmony.logging.tests.java.util.logging.HandlerTest.NullOutputStream;
47 import org.apache.harmony.logging.tests.java.util.logging.util.EnvironmentHelper;
48 
49 /**
50  */
51 public class FileHandlerTest extends TestCase {
52 
53     static LogManager manager = LogManager.getLogManager();
54 
55     final static Properties props = new Properties();
56 
57     final static String className = FileHandlerTest.class.getName();
58 
59     final static StringWriter writer = new StringWriter();
60 
61     final static String USR_HOME_KEY = "user.home";
62 
63     final static String TMP_DIR_KEY = "java.io.tmpdir";
64 
65     final static String HOMEPATH = System.getProperty(USR_HOME_KEY);
66 
67     final static String TEMPPATH = System.getProperty(TMP_DIR_KEY);
68 
69     final static String SEP = File.separator;
70 
71     private final PrintStream err = System.err;
72 
73     private OutputStream errSubstituteStream = null;
74 
75     FileHandler handler;
76 
77     LogRecord r;
78 
79     /*
80      * @see TestCase#setUp()
81      */
setUp()82     protected void setUp() throws Exception {
83         super.setUp();
84         manager.reset();
85         initProps();
86         File file = new File(TEMPPATH + SEP + "log");
87         file.mkdir();
88         manager.readConfiguration(EnvironmentHelper
89                 .PropertiesToInputStream(props));
90         handler = new FileHandler();
91         r = new LogRecord(Level.CONFIG, "msg");
92         errSubstituteStream = new NullOutputStream();
93         System.setErr(new PrintStream(errSubstituteStream));
94     }
95 
96     /**
97      *
98      */
initProps()99     private void initProps() {
100         props.clear();
101         props.put("java.util.logging.FileHandler.level", "FINE");
102         props.put("java.util.logging.FileHandler.filter", className
103                 + "$MockFilter");
104         props.put("java.util.logging.FileHandler.formatter", className
105                 + "$MockFormatter");
106         props.put("java.util.logging.FileHandler.encoding", "iso-8859-1");
107         // limit to only two message
108         props.put("java.util.logging.FileHandler.limit", "1000");
109         // rotation count is 2
110         props.put("java.util.logging.FileHandler.count", "2");
111         // using append mode
112         props.put("java.util.logging.FileHandler.append", "true");
113         props
114                 .put("java.util.logging.FileHandler.pattern",
115                         "%t/log/java%u.test");
116     }
117 
118     /*
119      * @see TestCase#tearDown()
120      */
tearDown()121     protected void tearDown() throws Exception {
122         if (null != handler) {
123             handler.close();
124         }
125         reset(TEMPPATH + SEP + "log", "");
126         System.setErr(err);
127         super.tearDown();
128     }
129 
testConstructor_NoUsrHome()130     public void testConstructor_NoUsrHome() throws IOException {
131         System.clearProperty(USR_HOME_KEY);
132 
133         try {
134             new FileHandler("%h/log_NoUsrHome.log");
135             fail("should throw NullPointerException");
136         } catch (NullPointerException e) {
137             // Expected
138         } finally {
139             if (HOMEPATH != null) {
140                 System.setProperty(USR_HOME_KEY, HOMEPATH);
141             }
142         }
143     }
144 
testConstructor_NoTmpDir()145     public void testConstructor_NoTmpDir() throws IOException {
146         System.clearProperty(TMP_DIR_KEY);
147 
148         try {
149             new FileHandler("%t/log_NoTmpDir.log");
150         } finally {
151             if (TEMPPATH != null) {
152                 System.setProperty(TMP_DIR_KEY, TEMPPATH);
153             }
154         }
155         assertFalse(new File(TEMPPATH, "log_NoTmpDir.log").exists());
156         assertTrue(new File(HOMEPATH, "log_NoTmpDir.log").exists());
157         new File(HOMEPATH, "log_NoTmpDir.log").delete();
158     }
159 
testConstructor_NoTmpDir_NoUsrHome()160     public void testConstructor_NoTmpDir_NoUsrHome() throws IOException {
161         System.clearProperty(TMP_DIR_KEY);
162         System.clearProperty(USR_HOME_KEY);
163 
164         try {
165             new FileHandler("%t/log_NoTmpDir_NoUsrHome.log");
166             fail("should throw NullPointerException");
167         } catch (NullPointerException e) {
168             // Expected
169         } finally {
170             if (TEMPPATH != null) {
171                 System.setProperty(TMP_DIR_KEY, TEMPPATH);
172             }
173             if (HOMEPATH != null) {
174                 System.setProperty(USR_HOME_KEY, HOMEPATH);
175             }
176         }
177     }
178 
testLock()179     public void testLock() throws Exception {
180         FileOutputStream output = new FileOutputStream(TEMPPATH + SEP + "log"
181                 + SEP + "java1.test.0");
182         FileHandler h = new FileHandler();
183         h.publish(r);
184         h.close();
185         assertFileContent(TEMPPATH + SEP + "log", "java1.test.0", h
186                 .getFormatter(), "UTF-8");
187         output.close();
188     }
189 
190     /*
191      * Class under test for void FileHandler()
192      */
testFileHandler()193     public void testFileHandler() throws Exception {
194         assertEquals(handler.getEncoding(), "iso-8859-1");
195         assertTrue(handler.getFilter() instanceof MockFilter);
196         assertTrue(handler.getFormatter() instanceof MockFormatter);
197         assertEquals(handler.getLevel(), Level.FINE);
198         assertNotNull(handler.getErrorManager());
199         handler.publish(r);
200         handler.close();
201         // output 3 times, and all records left
202         // append mode is true
203         for (int i = 0; i < 3; i++) {
204             handler = new FileHandler();
205             handler.publish(r);
206             handler.close();
207         }
208         assertFileContent(TEMPPATH + SEP + "log", "java0.test.0",
209                 new LogRecord[] { r, null, r, null, r, null, r },
210                 new MockFormatter(), "UTF-8");
211     }
212 
testDefaultValue()213     public void testDefaultValue() throws Exception {
214         handler.publish(r);
215         handler.close();
216         props.clear();
217         manager.readConfiguration(EnvironmentHelper
218                 .PropertiesToInputStream(props));
219         handler = new FileHandler();
220         assertNull(handler.getEncoding());
221         assertNull(handler.getFilter());
222         assertTrue(handler.getFormatter() instanceof XMLFormatter);
223         assertEquals(handler.getLevel(), Level.ALL);
224         assertNotNull(handler.getErrorManager());
225         handler.publish(r);
226         handler.close();
227         // output 3 times, and only one record left
228         // default append mode is false
229         for (int i = 0; i < 3; i++) {
230             handler = new FileHandler();
231             handler.publish(r);
232             handler.close();
233         }
234         assertFileContent(HOMEPATH, "java0.log", new XMLFormatter(), null);
235     }
236 
assertFileContent(String homepath, String filename, Formatter formatter, String encoding)237     private void assertFileContent(String homepath, String filename,
238             Formatter formatter, String encoding) throws Exception {
239         assertFileContent(homepath, filename, new LogRecord[] { r }, formatter, encoding);
240     }
241 
assertFileContent(String homepath, String filename, LogRecord[] lr, Formatter formatter, String encoding)242     private void assertFileContent(String homepath, String filename,
243             LogRecord[] lr, Formatter formatter, String encoding) throws Exception {
244         handler.close();
245         String msg = "";
246         // if formatter is null, the file content should be empty
247         // else the message should be formatted given records
248         if (null != formatter) {
249             StringBuffer sb = new StringBuffer();
250             sb.append(formatter.getHead(handler));
251             for (int i = 0; i < lr.length; i++) {
252                 if (null == lr[i] && i < lr.length - 1) {
253                     // if one record is null and is not the last record, means
254                     // here is
255                     // output completion point, should output tail, then output
256                     // head
257                     // (ready for next output)
258                     sb.append(formatter.getTail(handler));
259                     sb.append(formatter.getHead(handler));
260                 } else {
261                     sb.append(formatter.format(lr[i]));
262                 }
263             }
264             sb.append(formatter.getTail(handler));
265             msg = sb.toString();
266         }
267         byte[] bytes = new byte[msg.length()];
268         InputStream inputStream = null;
269         try {
270             inputStream = new BufferedInputStream(new FileInputStream(homepath
271                     + SEP + filename));
272             inputStream.read(bytes);
273             if (encoding == null) {
274                 assertEquals(msg, new String(bytes));
275             } else {
276                 assertEquals(msg, new String(bytes, encoding));
277             }
278             // assert has reached the end of the file
279             assertEquals(-1, inputStream.read());
280         } finally {
281             try {
282                 if (inputStream != null) {
283                     inputStream.close();
284                 }
285             } catch (Exception e) {
286                 // ignored
287             }
288             reset(homepath, filename);
289         }
290     }
291 
292     /**
293      * Does a cleanup of given file
294      *
295      * @param homepath
296      * @param filename
297      */
reset(String homepath, String filename)298     private void reset(String homepath, String filename) {
299         File file = null;
300         try {
301             file = new File(homepath + SEP + filename);
302             if (file.isFile()) {
303                 file.delete();
304             } else if (file.isDirectory()) {
305                 File[] files = file.listFiles();
306                 for (int i = 0; i < files.length; i++) {
307                     files[i].delete();
308                 }
309                 file.delete();
310             }
311         } catch (Exception e) {
312             e.printStackTrace();
313         }
314         try {
315             file = new File(homepath + SEP + filename + ".lck");
316             file.delete();
317         } catch (Exception e) {
318             e.printStackTrace();
319         }
320     }
321 
testLimitAndCount()322     public void testLimitAndCount() throws Exception {
323         handler.close();
324         // very small limit value, count=2
325         // output, rename current output file to the second generation file
326         // close it and open a new file as rotation output
327         handler = new FileHandler("%t/testLimitCount%g", 1, 2, false);
328         handler.publish(r);
329         handler.close();
330         assertFileContent(TEMPPATH, "testLimitCount1", handler.getFormatter(), "UTF-8");
331 
332         // very small limit value, count=1
333         // output once, rotate(equals to nothing output)
334         handler = new FileHandler("%t/testLimitCount%g", 1, 1, false);
335         handler.publish(r);
336         handler.close();
337         assertFileContent(TEMPPATH, "testLimitCount0", new LogRecord[0],
338                 handler.getFormatter(), "UTF-8");
339 
340         // normal case, limit is 60(>2*msg length <3*msg length), append is
341         // false
342         handler = new FileHandler("%t/testLimitCount%u", 60, 3, false);
343         LogRecord[] rs = new LogRecord[10];
344         // batch output twice to test the append mode
345         for (int i = 0; i < 5; i++) {
346             rs[i] = new LogRecord(Level.SEVERE, "msg" + i);
347             handler.publish(rs[i]);
348         }
349         handler.close();
350         handler = new FileHandler("%t/testLimitCount%u", 60, 3, false);
351         for (int i = 5; i < 10; i++) {
352             rs[i] = new LogRecord(Level.SEVERE, "msg" + i);
353             handler.publish(rs[i]);
354         }
355 
356         assertFileContent(TEMPPATH, "testLimitCount0.1", new LogRecord[] {
357                 rs[5], rs[6], rs[7] }, handler.getFormatter(), "UTF-8");
358         assertFileContent(TEMPPATH, "testLimitCount0.0", new LogRecord[] {
359                 rs[8], rs[9] }, handler.getFormatter(), "UTF-8");
360 
361         // normal case, limit is 60(>2*msg length <3*msg length), append is true
362         handler = new FileHandler("%t/testLimitCount%u", 60, 3, false);
363         // batch output twice to test the append mode
364         for (int i = 0; i < 5; i++) {
365             rs[i] = new LogRecord(Level.SEVERE, "msg" + i);
366             handler.publish(rs[i]);
367         }
368         handler.close();
369         handler = new FileHandler("%t/testLimitCount%u", 60, 3, true);
370         for (int i = 5; i < 10; i++) {
371             rs[i] = new LogRecord(Level.SEVERE, "msg" + i);
372             handler.publish(rs[i]);
373         }
374         handler.close();
375         assertFileContent(TEMPPATH, "testLimitCount0.2", new LogRecord[] {
376                 rs[3], rs[4], null, rs[5] }, handler.getFormatter(), "UTF-8");
377         assertFileContent(TEMPPATH, "testLimitCount0.1", new LogRecord[] {
378                 rs[6], rs[7], rs[8] }, handler.getFormatter(), "UTF-8");
379         assertFileContent(TEMPPATH, "testLimitCount0.0",
380                 new LogRecord[] { rs[9] }, handler.getFormatter(), "UTF-8");
381 
382         FileHandler h1 = null;
383         FileHandler h2 = null;
384         try {
385             File logDir = new File("log");
386             reset("log", "");
387             logDir.mkdir();
388             h1 = new FileHandler("log/a", 0, 1);
389             assertNotNull(h1);
390             h2 = new FileHandler("log/a", 0, 1, false);
391             assertNotNull(h2);
392         } finally {
393             try {
394                 h1.close();
395             } catch (Exception e) {
396             }
397             try {
398                 h2.close();
399             } catch (Exception e) {
400             }
401             reset("log", "");
402         }
403     }
404 
testInvalidProperty()405     public void testInvalidProperty() throws Exception {
406         props.put("java.util.logging.FileHandler.level", "null");
407         props.put("java.util.logging.FileHandler.filter", className
408                 + "$MockFilte");
409         props.put("java.util.logging.FileHandler.formatter", className
410                 + "$MockFormatte");
411         props.put("java.util.logging.FileHandler.encoding", "ut");
412         // limit to only two message
413         props.put("java.util.logging.FileHandler.limit", "-1");
414         // rotation count is 2
415         props.put("java.util.logging.FileHandler.count", "-1");
416         // using append mode
417         props.put("java.util.logging.FileHandler.append", "bad");
418 
419         handler.close();
420 
421         manager.readConfiguration(EnvironmentHelper
422                 .PropertiesToInputStream(props));
423         handler = new FileHandler();
424         assertEquals(Level.ALL, handler.getLevel());
425         assertNull(handler.getFilter());
426         assertTrue(handler.getFormatter() instanceof XMLFormatter);
427         assertNull(handler.getEncoding());
428         handler.close();
429 
430         props.put("java.util.logging.FileHandler.pattern", "");
431         manager.readConfiguration(EnvironmentHelper
432                 .PropertiesToInputStream(props));
433         try {
434             handler = new FileHandler();
435             fail("shouldn't open file with empty name");
436         } catch (NullPointerException e) {
437         }
438     }
439 
testInvalidParams()440     public void testInvalidParams() throws IOException {
441 
442         // %t and %p parsing can add file separator automatically
443         FileHandler h1 = new FileHandler("%taaa");
444         h1.close();
445         File file = new File(TEMPPATH + SEP + "aaa");
446         assertTrue(file.exists());
447         reset(TEMPPATH, "aaa");
448 
449         // always parse special pattern
450         try {
451             h1 = new FileHandler("%t/%h");
452             fail("should throw null exception");
453         } catch (FileNotFoundException e) {
454         }
455         h1 = new FileHandler("%t%g");
456         h1.close();
457         file = new File(TEMPPATH + SEP + "0");
458         assertTrue(file.exists());
459         reset(TEMPPATH, "0");
460         h1 = new FileHandler("%t%u%g");
461         h1.close();
462         file = new File(TEMPPATH + SEP + "00");
463         assertTrue(file.exists());
464         reset(TEMPPATH, "00");
465 
466         // this is normal case
467         h1 = new FileHandler("%t/%u%g%%g");
468         h1.close();
469         file = new File(TEMPPATH + SEP + "00%g");
470         assertTrue(file.exists());
471         reset(TEMPPATH, "00%g");
472 
473         // multi separator has no effect
474         h1 = new FileHandler("//%t//multi%g");
475         h1.close();
476         file = new File(TEMPPATH + SEP + "multi0");
477         assertTrue(file.exists());
478         reset(TEMPPATH, "multi0");
479 
480         // bad directory, IOException
481         try {
482             h1 = new FileHandler("%t/baddir/multi%g");
483             fail("should throw IO exception");
484         } catch (IOException e) {
485         }
486         file = new File(TEMPPATH + SEP + "baddir" + SEP + "multi0");
487         assertFalse(file.exists());
488 
489         try {
490             new FileHandler(null);
491             fail("should throw null exception");
492         } catch (NullPointerException e) {
493         }
494         try {
495             handler.publish(null);
496         } catch (NullPointerException e) {
497             fail("should not throw NPE");
498         }
499         try {
500             new FileHandler(null, false);
501             fail("should throw null exception");
502         } catch (NullPointerException e) {
503         }
504         try {
505             // regression test for Harmony-1299
506             new FileHandler("");
507             fail("should throw IllegalArgumentException");
508         } catch (IllegalArgumentException e) {
509             // expected
510         }
511         try {
512             new FileHandler("%t/java%u", 0, 0);
513             fail("should throw IllegalArgumentException");
514         } catch (IllegalArgumentException e) {
515         }
516         try {
517             new FileHandler("%t/java%u", -1, 1);
518             fail("should throw IllegalArgumentException");
519         } catch (IllegalArgumentException e) {
520         }
521     }
522 
523     // set output stream still works, just like super StreamHandler
testSetOutputStream()524     public void testSetOutputStream() throws Exception {
525         MockFileHandler handler = new MockFileHandler("%h/setoutput.log");
526         handler.setFormatter(new MockFormatter());
527         handler.publish(r);
528 
529         ByteArrayOutputStream out = new ByteArrayOutputStream();
530         handler.publicSetOutputStream(out);
531         handler.publish(r);
532         handler.close();
533         String msg = new String(out.toByteArray());
534         Formatter f = handler.getFormatter();
535         assertEquals(msg, f.getHead(handler) + f.format(r) + f.getTail(handler));
536         assertFileContent(HOMEPATH, "setoutput.log", handler.getFormatter(), null);
537     }
538 
539     /*
540      * Class under test for void FileHandler(String)
541      */
testFileHandlerString()542     public void testFileHandlerString() throws Exception {
543         // test if unique ids not specified, it will append at the end
544         // no generation number is used
545         FileHandler h = new FileHandler("%t/log/string");
546         FileHandler h2 = new FileHandler("%t/log/string");
547         FileHandler h3 = new FileHandler("%t/log/string");
548         FileHandler h4 = new FileHandler("%t/log/string");
549         h.publish(r);
550         h2.publish(r);
551         h3.publish(r);
552         h4.publish(r);
553         h.close();
554         h2.close();
555         h3.close();
556         h4.close();
557         assertFileContent(TEMPPATH + SEP + "log", "string", h.getFormatter(), "UTF-8");
558         assertFileContent(TEMPPATH + SEP + "log", "string.1", h.getFormatter(), "UTF-8");
559         assertFileContent(TEMPPATH + SEP + "log", "string.2", h.getFormatter(), "UTF-8");
560         assertFileContent(TEMPPATH + SEP + "log", "string.3", h.getFormatter(), "UTF-8");
561 
562         // default is append mode
563         FileHandler h6 = new FileHandler("%t/log/string%u.log");
564         h6.publish(r);
565         h6.close();
566         FileHandler h7 = new FileHandler("%t/log/string%u.log");
567         h7.publish(r);
568         h7.close();
569         try {
570             assertFileContent(TEMPPATH + SEP + "log", "string0.log", h
571                     .getFormatter(), "UTF-8");
572             fail("should assertion failed");
573         } catch (Error e) {
574         }
575         File file = new File(TEMPPATH + SEP + "log");
576         assertTrue(file.list().length <= 2);
577 
578         // test unique ids
579         FileHandler h8 = new FileHandler("%t/log/%ustring%u.log");
580         h8.publish(r);
581         FileHandler h9 = new FileHandler("%t/log/%ustring%u.log");
582         h9.publish(r);
583         h9.close();
584         h8.close();
585         assertFileContent(TEMPPATH + SEP + "log", "0string0.log", h
586                 .getFormatter(), "UTF-8");
587         assertFileContent(TEMPPATH + SEP + "log", "1string1.log", h
588                 .getFormatter(), "UTF-8");
589         file = new File(TEMPPATH + SEP + "log");
590         assertTrue(file.list().length <= 2);
591     }
592 
testEmptyPattern_3params()593     public void testEmptyPattern_3params() throws SecurityException,
594             IOException {
595         // regression HARMONY-2421
596         try {
597             new FileHandler(new String(), 1, 1);
598             fail("Expected an IllegalArgumentException");
599         } catch (IllegalArgumentException e) {
600             // Expected
601         }
602     }
603 
testEmptyPattern_2params()604     public void testEmptyPattern_2params() throws SecurityException,
605             IOException {
606         // regression HARMONY-2421
607         try {
608             new FileHandler(new String(), true);
609             fail("Expected an IllegalArgumentException");
610         } catch (IllegalArgumentException e) {
611             // Expected
612         }
613     }
614 
testEmptyPattern_4params()615     public void testEmptyPattern_4params() throws SecurityException,
616             IOException {
617         // regression HARMONY-2421
618         try {
619             new FileHandler(new String(), 1, 1, true);
620             fail("Expected an IllegalArgumentException");
621         } catch (IllegalArgumentException e) {
622             // Expected
623         }
624     }
625 
626     /*
627      * mock classes
628      */
629     public static class MockFilter implements Filter {
isLoggable(LogRecord record)630         public boolean isLoggable(LogRecord record) {
631             return !record.getMessage().equals("false");
632         }
633     }
634 
635     public static class MockFormatter extends Formatter {
format(LogRecord r)636         public String format(LogRecord r) {
637             if (null == r) {
638                 return "";
639             }
640             return r.getMessage() + " by MockFormatter\n";
641         }
642 
getTail(Handler h)643         public String getTail(Handler h) {
644             return "tail\n";
645         }
646 
getHead(Handler h)647         public String getHead(Handler h) {
648             return "head\n";
649         }
650     }
651 
652     public static class MockFileHandler extends FileHandler {
MockFileHandler()653         public MockFileHandler() throws IOException {
654             super();
655         }
656 
MockFileHandler(String pattern)657         public MockFileHandler(String pattern) throws IOException {
658             super(pattern);
659         }
660 
publicSetOutputStream(OutputStream stream)661         public void publicSetOutputStream(OutputStream stream) {
662             super.setOutputStream(stream);
663         }
664     }
665 }
666