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