undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645
|
||||
* @summary tests that LogRecord has nanos...
|
||||
* @run main LogRecordWithNanos
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class LogRecordWithNanos {
|
||||
|
||||
static final int MILLIS_IN_SECOND = 1000;
|
||||
static final int NANOS_IN_MILLI = 1000_000;
|
||||
static final int NANOS_IN_SECOND = 1000_000_000;
|
||||
|
||||
static final boolean verbose = false;
|
||||
|
||||
static final class TestAssertException extends RuntimeException {
|
||||
TestAssertException(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
private static void assertEquals(long expected, long received, String msg) {
|
||||
if (expected != received) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a log record, then deserializes it and check that both
|
||||
* records match.
|
||||
* @param record the log record to serialize & deserialize.
|
||||
* @throws IOException Unexpected.
|
||||
* @throws ClassNotFoundException Unexpected.
|
||||
*/
|
||||
public static void test(LogRecord record)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
// Format the given logRecord using the SimpleFormatter
|
||||
SimpleFormatter formatter = new SimpleFormatter();
|
||||
String str = formatter.format(record);
|
||||
|
||||
// Serialize the given LogRecord
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(record);
|
||||
oos.flush();
|
||||
oos.close();
|
||||
|
||||
// First checks that the log record can be deserialized
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
final ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
final LogRecord record2 = (LogRecord)ois.readObject();
|
||||
|
||||
assertEquals(record.getMillis(), record2.getMillis(), "getMillis()");
|
||||
assertEquals(record.getInstant().getEpochSecond(),
|
||||
record2.getInstant().getEpochSecond(),
|
||||
"getInstant().getEpochSecond()");
|
||||
assertEquals(record.getInstant().getNano(),
|
||||
record2.getInstant().getNano(),
|
||||
"getInstant().getNano()");
|
||||
assertEquals(record.getInstant().toEpochMilli(),
|
||||
record2.getInstant().toEpochMilli(),
|
||||
"getInstant().toEpochMilli()");
|
||||
assertEquals(record.getMillis(),
|
||||
record.getInstant().toEpochMilli(),
|
||||
"getMillis()/getInstant().toEpochMilli()");
|
||||
assertEquals(record2.getMillis(),
|
||||
record2.getInstant().toEpochMilli(),
|
||||
"getMillis()/getInstant().toEpochMilli()");
|
||||
assertEquals((record.getMillis()%MILLIS_IN_SECOND)*NANOS_IN_MILLI
|
||||
+ (record.getInstant().getNano() % NANOS_IN_MILLI),
|
||||
record.getInstant().getNano(),
|
||||
"record.getMillis()%1000)*1000_000"
|
||||
+ " + record.getInstant().getNano()%1000_000 / getInstant().getNano()");
|
||||
assertEquals((record2.getMillis()%MILLIS_IN_SECOND)*NANOS_IN_MILLI
|
||||
+ (record2.getInstant().getNano() % NANOS_IN_MILLI),
|
||||
record2.getInstant().getNano(),
|
||||
"record2.getMillis()%1000)*1000_000"
|
||||
+ " + record2.getInstant().getNano()%1000_000 / getInstant().getNano()");
|
||||
|
||||
// Format the deserialized LogRecord using the SimpleFormatter, and
|
||||
// check that the string representation obtained matches the string
|
||||
// representation of the original LogRecord
|
||||
String str2 = formatter.format(record2);
|
||||
if (!str.equals(str2))
|
||||
throw new RuntimeException("Unexpected values in deserialized object:"
|
||||
+ "\n\tExpected: " + str
|
||||
+ "\n\tRetrieved: "+str);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int count=0;
|
||||
for (int i=0; i<1000; i++) {
|
||||
LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {System.getProperty("java.version")});
|
||||
if (record.getInstant().getNano() % 1000_000 != 0) {
|
||||
count++;
|
||||
}
|
||||
test(record);
|
||||
}
|
||||
if (count == 0) {
|
||||
throw new RuntimeException("Expected at least one record to have nanos");
|
||||
}
|
||||
System.out.println(count + "/1000 records had nano adjustment.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645 8144262
|
||||
* @summary tests the new methods added to LogRecord.
|
||||
* @run main LogRecordWithNanosAPI
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class LogRecordWithNanosAPI {
|
||||
|
||||
static final int MILLIS_IN_SECOND = 1000;
|
||||
static final int NANOS_IN_MILLI = 1000_000;
|
||||
static final int NANOS_IN_SECOND = 1000_000_000;
|
||||
|
||||
static final boolean verbose = true;
|
||||
|
||||
static final class TestAssertException extends RuntimeException {
|
||||
TestAssertException(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
private static void assertEquals(long expected, long received, String msg) {
|
||||
if (expected != received) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEquals(Object expected, Object received, String msg) {
|
||||
if (!Objects.equals(expected, received)) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
// The nano second fractional part of a second, contained in a time expressed
|
||||
// as a number of millisecond from the epoch.
|
||||
private static long nanoInSecondFromEpochMilli(long millis) {
|
||||
return (((millis%MILLIS_IN_SECOND) + MILLIS_IN_SECOND)%MILLIS_IN_SECOND)*NANOS_IN_MILLI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a log record, then deserializes it and check that both
|
||||
* records match.
|
||||
* @param record the log record to serialize & deserialize.
|
||||
* @param hasExceedingNanos whether the record has a nano adjustment whose
|
||||
* value exceeds 1ms.
|
||||
* @throws IOException Unexpected.
|
||||
* @throws ClassNotFoundException Unexpected.
|
||||
*/
|
||||
public static void test(LogRecord record, boolean hasExceedingNanos)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
// Format the given logRecord using the SimpleFormatter
|
||||
SimpleFormatter formatter = new SimpleFormatter();
|
||||
String str = formatter.format(record);
|
||||
|
||||
// Serialize the given LogRecord
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(record);
|
||||
oos.flush();
|
||||
oos.close();
|
||||
|
||||
// First checks that the log record can be deserialized
|
||||
final ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(baos.toByteArray());
|
||||
final ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
final LogRecord record2 = (LogRecord)ois.readObject();
|
||||
|
||||
assertEquals(record.getMillis(), record2.getMillis(), "getMillis()");
|
||||
assertEquals(record.getInstant().getEpochSecond(),
|
||||
record2.getInstant().getEpochSecond(),
|
||||
"getInstant().getEpochSecond()");
|
||||
assertEquals(record.getInstant().getNano(),
|
||||
record2.getInstant().getNano(),
|
||||
"getInstant().getNano()");
|
||||
assertEquals(record.getInstant().toEpochMilli(),
|
||||
record2.getInstant().toEpochMilli(),
|
||||
"getInstant().toEpochMilli()");
|
||||
long millis = record.getMillis();
|
||||
millis = hasExceedingNanos
|
||||
? Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI
|
||||
+ record.getInstant().getNano() % NANOS_IN_MILLI).toEpochMilli()
|
||||
: millis;
|
||||
assertEquals(millis, record.getInstant().toEpochMilli(),
|
||||
"getMillis()/getInstant().toEpochMilli()");
|
||||
millis = record2.getMillis();
|
||||
millis = hasExceedingNanos
|
||||
? Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI
|
||||
+ record2.getInstant().getNano() % NANOS_IN_MILLI).toEpochMilli()
|
||||
: millis;
|
||||
assertEquals(millis, record2.getInstant().toEpochMilli(),
|
||||
"getMillis()/getInstant().toEpochMilli()");
|
||||
long nanos = nanoInSecondFromEpochMilli(record.getMillis())
|
||||
+ record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
assertEquals(nanos, record.getInstant().getNano(),
|
||||
"nanoInSecondFromEpochMilli(record.getMillis())"
|
||||
+ " + record.getInstant().getNano() % NANOS_IN_MILLI /getInstant().getNano()");
|
||||
nanos = nanoInSecondFromEpochMilli(record2.getMillis())
|
||||
+ record2.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
assertEquals(nanos, record2.getInstant().getNano(),
|
||||
"nanoInSecondFromEpochMilli(record2.getMillis())"
|
||||
+ " + record2.getInstant().getNano() % NANOS_IN_MILLI /getInstant().getNano()");
|
||||
|
||||
// Format the deserialized LogRecord using the SimpleFormatter, and
|
||||
// check that the string representation obtained matches the string
|
||||
// representation of the original LogRecord
|
||||
String str2 = formatter.format(record2);
|
||||
if (!str.equals(str2))
|
||||
throw new RuntimeException("Unexpected values in deserialized object:"
|
||||
+ "\n\tExpected: " + str
|
||||
+ "\n\tRetrieved: "+str);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int count=0;
|
||||
LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {System.getProperty("java.version")});
|
||||
final int nanos = record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
final long millis = record.getMillis();
|
||||
final Instant instant = record.getInstant();
|
||||
if (millis != instant.toEpochMilli()) {
|
||||
throw new RuntimeException("Unexpected millis: "
|
||||
+ record.getMillis());
|
||||
}
|
||||
test(record, false);
|
||||
|
||||
// nano adjustment < 1ms (canonical case)
|
||||
int newNanos = (nanos + 111111) % NANOS_IN_MILLI;
|
||||
record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newNanos));
|
||||
assertEquals(newNanos, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis, record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
test(record, false);
|
||||
assertEquals(newNanos, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis, record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
|
||||
// nano adjustment > 1ms - non canonical - should still work
|
||||
int newExceedingNanos = 2111_111;
|
||||
record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos));
|
||||
assertEquals(newExceedingNanos % NANOS_IN_MILLI,
|
||||
record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI,
|
||||
record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
test(record, true);
|
||||
assertEquals(newExceedingNanos % NANOS_IN_MILLI,
|
||||
record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI,
|
||||
record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
|
||||
// nano adjustement > 1s - non canonical - should still work
|
||||
newExceedingNanos = 1111_111_111;
|
||||
record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos));
|
||||
assertEquals(newExceedingNanos % NANOS_IN_MILLI,
|
||||
record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI,
|
||||
record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
test(record, true);
|
||||
assertEquals(newExceedingNanos % NANOS_IN_MILLI,
|
||||
record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI,
|
||||
record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
|
||||
// nano adjustement < 0 - non canonical - should still work
|
||||
newExceedingNanos = -1;
|
||||
record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos));
|
||||
assertEquals(newExceedingNanos + NANOS_IN_MILLI,
|
||||
record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
assertEquals(millis -1, record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
test(record, true);
|
||||
record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos));
|
||||
assertEquals(millis -1, record.getMillis(), "record.getMillis()");
|
||||
assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND,
|
||||
(millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos),
|
||||
record.getInstant(), "record.getInstant()");
|
||||
|
||||
// setMillis
|
||||
record.setMillis(millis-1);
|
||||
assertEquals(millis-1, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(millis-1, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
test(record, false);
|
||||
assertEquals(millis-1, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(millis-1, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
|
||||
// setMillis to 0
|
||||
record.setMillis(0);
|
||||
assertEquals(0, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(0, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
test(record, false);
|
||||
assertEquals(0, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(0, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
|
||||
// setMillis to -1
|
||||
record.setMillis(-1);
|
||||
assertEquals(-1, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(-1, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
test(record, false);
|
||||
assertEquals(-1, record.getInstant().toEpochMilli(),
|
||||
"record.getInstant().toEpochMilli()");
|
||||
assertEquals(-1, record.getMillis(),
|
||||
"record.getMillis()");
|
||||
assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI,
|
||||
"record.getInstant().getNano() % NANOS_IN_MILLI");
|
||||
|
||||
try {
|
||||
record.setInstant(null);
|
||||
throw new RuntimeException("Expected NullPointerException not thrown");
|
||||
} catch (NullPointerException x) {
|
||||
System.out.println("Got expected NPE when trying to call record.setInstant(null): " + x);
|
||||
}
|
||||
|
||||
// This instant is the biggest for which toEpochMilli will not throw...
|
||||
final Instant max = Instant.ofEpochMilli(Long.MAX_VALUE).plusNanos(999_999L);
|
||||
record.setInstant(max);
|
||||
assertEquals(Long.MAX_VALUE / 1000L,
|
||||
record.getInstant().getEpochSecond(),
|
||||
"max instant seconds [record.getInstant().getEpochSecond()]");
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
record.getInstant().toEpochMilli(),
|
||||
"max instant millis [record.getInstant().toEpochMilli()]");
|
||||
assertEquals(Long.MAX_VALUE, record.getMillis(),
|
||||
"max instant millis [record.getMillis()]");
|
||||
assertEquals((Long.MAX_VALUE % 1000L)*1000_000L + 999_999L,
|
||||
record.getInstant().getNano(),
|
||||
"max instant nanos [record.getInstant().getNano()]");
|
||||
|
||||
// Too big by 1 ns.
|
||||
final Instant tooBig = max.plusNanos(1L);
|
||||
try {
|
||||
record.setInstant(tooBig);
|
||||
throw new RuntimeException("Expected ArithmeticException not thrown");
|
||||
} catch (ArithmeticException x) {
|
||||
System.out.println("Got expected ArithmeticException when trying"
|
||||
+ " to call record.setInstant(Instant.ofEpochMilli(Long.MAX_VALUE)"
|
||||
+ ".plusNanos(999_999L).plusNanos(1L)): " + x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Base64;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645
|
||||
* @summary tests the compatibility of LogRecord serial form between
|
||||
* JDK 8 and JDK 9. Ideally this test should be run on both platforms.
|
||||
* (It is designed to run on both).
|
||||
* @run main/othervm SerializeLogRecord
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class SerializeLogRecord {
|
||||
|
||||
/**
|
||||
* Serializes a log record, encode the serialized bytes in base 64, and
|
||||
* prints pseudo java code that can be cut and pasted into this test.
|
||||
* @param record the log record to serialize, encode in base 64, and for
|
||||
* which test data will be generated.
|
||||
* @return A string containing the generated pseudo java code.
|
||||
* @throws IOException Unexpected.
|
||||
* @throws ClassNotFoundException Unexpected.
|
||||
*/
|
||||
public static String generate(LogRecord record) throws IOException, ClassNotFoundException {
|
||||
|
||||
// Format the given logRecord using the SimpleFormatter
|
||||
SimpleFormatter formatter = new SimpleFormatter();
|
||||
String str = formatter.format(record);
|
||||
|
||||
// Serialize the given LogRecord
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(record);
|
||||
oos.flush();
|
||||
oos.close();
|
||||
|
||||
// Now we're going to perform a number of smoke tests before
|
||||
// generating the Java pseudo code.
|
||||
//
|
||||
// First checks that the log record can be deserialized
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
final ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
final LogRecord record2 = (LogRecord)ois.readObject();
|
||||
|
||||
// Format the deserialized LogRecord using the SimpleFormatter, and
|
||||
// check that the string representation obtained matches the string
|
||||
// representation of the original LogRecord
|
||||
String str2 = formatter.format(record2);
|
||||
if (!str.equals(str2)) throw new RuntimeException("Unexpected values in deserialized object:"
|
||||
+ "\n\tExpected: " + str
|
||||
+ "\n\tRetrieved: "+str);
|
||||
|
||||
// Now get a Base64 string representation of the serialized bytes.
|
||||
final String base64 = Base64.getEncoder().encodeToString(baos.toByteArray());
|
||||
|
||||
// Check that we can deserialize a log record from the Base64 string
|
||||
// representation we just computed.
|
||||
final ByteArrayInputStream bais2 = new ByteArrayInputStream(Base64.getDecoder().decode(base64));
|
||||
final ObjectInputStream ois2 = new ObjectInputStream(bais2);
|
||||
final LogRecord record3 = (LogRecord)ois2.readObject();
|
||||
|
||||
// Format the new deserialized LogRecord using the SimpleFormatter, and
|
||||
// check that the string representation obtained matches the string
|
||||
// representation of the original LogRecord
|
||||
String str3 = formatter.format(record3);
|
||||
if (!str.equals(str3)) throw new RuntimeException("Unexpected values in deserialized object:"
|
||||
+ "\n\tExpected: " + str
|
||||
+ "\n\tRetrieved: "+str);
|
||||
//System.out.println(base64);
|
||||
//System.out.println();
|
||||
|
||||
// Generates the Java Pseudo code that can be cut & pasted into
|
||||
// this test (see Jdk8SerializedLog and Jdk9SerializedLog below)
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(" /**").append('\n');
|
||||
sb.append(" * Base64 encoded string for LogRecord object.").append('\n');
|
||||
sb.append(" * Java version: ").append(System.getProperty("java.version")).append('\n');
|
||||
sb.append(" **/").append('\n');
|
||||
sb.append(" final String base64 = ").append("\n ");
|
||||
final int last = base64.length() - 1;
|
||||
for (int i=0; i<base64.length();i++) {
|
||||
if (i%64 == 0) sb.append("\"");
|
||||
sb.append(base64.charAt(i));
|
||||
if (i%64 == 63 || i == last) {
|
||||
sb.append("\"");
|
||||
if (i == last) sb.append(";\n");
|
||||
else sb.append("\n + ");
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
sb.append(" /**").append('\n');
|
||||
sb.append(" * SimpleFormatter output for LogRecord object.").append('\n');
|
||||
sb.append(" * Java version: ").append(System.getProperty("java.version")).append('\n');
|
||||
sb.append(" **/").append('\n');
|
||||
sb.append(" final String str = ").append("\n ");
|
||||
sb.append("\"").append(str.replace("\n", "\\n")).append("\";\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class to test that a log record previously serialized on a
|
||||
* different java version can be deserialized in the current java version.
|
||||
* (see Jdk8SerializedLog and Jdk9SerializedLog below)
|
||||
*/
|
||||
public abstract static class SerializedLog {
|
||||
public abstract String getBase64();
|
||||
public abstract String getString();
|
||||
|
||||
/**
|
||||
* Deserializes the Base64 encoded string returned by {@link
|
||||
* #getBase64()}, format the obtained LogRecord using a
|
||||
* SimpleFormatter, and checks that the string representation obtained
|
||||
* matches the original string representation returned by {@link
|
||||
* #getString()}.
|
||||
*/
|
||||
protected void dotest() {
|
||||
try {
|
||||
final String base64 = getBase64();
|
||||
final ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(Base64.getDecoder().decode(base64));
|
||||
final ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
final LogRecord record = (LogRecord)ois.readObject();
|
||||
final SimpleFormatter formatter = new SimpleFormatter();
|
||||
String expected = getString();
|
||||
String str2 = formatter.format(record);
|
||||
check(expected, str2);
|
||||
System.out.println(str2);
|
||||
System.out.println("PASSED: "+this.getClass().getName()+"\n");
|
||||
} catch (IOException | ClassNotFoundException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check that the actual String representation obtained matches the
|
||||
* expected String representation.
|
||||
* @param expected Expected String representation, as returned by
|
||||
* {@link #getString()}.
|
||||
* @param actual Actual String representation obtained by formatting
|
||||
* the LogRecord obtained by the deserialization of the
|
||||
* bytes encoded in {@link #getBase64()}.
|
||||
*/
|
||||
protected void check(String expected, String actual) {
|
||||
if (!expected.equals(actual)) {
|
||||
throw new RuntimeException(this.getClass().getName()
|
||||
+ " - Unexpected values in deserialized object:"
|
||||
+ "\n\tExpected: " + expected
|
||||
+ "\n\tRetrieved: "+ actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Jdk8SerializedLog extends SerializedLog {
|
||||
|
||||
// Generated by generate() on JDK 8.
|
||||
// --------------------------------
|
||||
// BEGIN
|
||||
|
||||
/**
|
||||
* Base64 encoded string for LogRecord object.
|
||||
* Java version: 1.8.0_11
|
||||
**/
|
||||
final String base64 =
|
||||
"rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMACkoA"
|
||||
+ "Bm1pbGxpc0oADnNlcXVlbmNlTnVtYmVySQAIdGhyZWFkSURMAAVsZXZlbHQAGUxq"
|
||||
+ "YXZhL3V0aWwvbG9nZ2luZy9MZXZlbDtMAApsb2dnZXJOYW1ldAASTGphdmEvbGFu"
|
||||
+ "Zy9TdHJpbmc7TAAHbWVzc2FnZXEAfgACTAAScmVzb3VyY2VCdW5kbGVOYW1lcQB+"
|
||||
+ "AAJMAA9zb3VyY2VDbGFzc05hbWVxAH4AAkwAEHNvdXJjZU1ldGhvZE5hbWVxAH4A"
|
||||
+ "AkwABnRocm93bnQAFUxqYXZhL2xhbmcvVGhyb3dhYmxlO3hwAAABSjUCgo0AAAAA"
|
||||
+ "AAAAAAAAAAFzcgAXamF2YS51dGlsLmxvZ2dpbmcuTGV2ZWyOiHETUXM2kgIAA0kA"
|
||||
+ "BXZhbHVlTAAEbmFtZXEAfgACTAAScmVzb3VyY2VCdW5kbGVOYW1lcQB+AAJ4cAAA"
|
||||
+ "AyB0AARJTkZPdAAic3VuLnV0aWwubG9nZ2luZy5yZXNvdXJjZXMubG9nZ2luZ3QA"
|
||||
+ "BHRlc3R0ABFKYXZhIFZlcnNpb246IHswfXBwcHB3BgEAAAAAAXQACDEuOC4wXzEx"
|
||||
+ "eA==";
|
||||
|
||||
/**
|
||||
* SimpleFormatter output for LogRecord object.
|
||||
* Java version: 1.8.0_11
|
||||
**/
|
||||
final String str =
|
||||
"Dec 10, 2014 4:22:44.621000000 PM test - INFO: Java Version: 1.8.0_11";
|
||||
// ^^^
|
||||
// Notice the milli second resolution above...
|
||||
|
||||
// END
|
||||
// --------------------------------
|
||||
|
||||
@Override
|
||||
public String getBase64() {
|
||||
return base64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
new Jdk8SerializedLog().dotest();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Jdk9SerializedLog extends SerializedLog {
|
||||
|
||||
// Generated by generate() on JDK 9.
|
||||
// --------------------------------
|
||||
// BEGIN
|
||||
|
||||
/**
|
||||
* Base64 encoded string for LogRecord object.
|
||||
* Java version: 1.9.0-internal
|
||||
**/
|
||||
final String base64 =
|
||||
"rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMAC0oA"
|
||||
+ "Bm1pbGxpc0kADm5hbm9BZGp1c3RtZW50SgAOc2VxdWVuY2VOdW1iZXJJAAh0aHJl"
|
||||
+ "YWRJREwABWxldmVsdAAZTGphdmEvdXRpbC9sb2dnaW5nL0xldmVsO0wACmxvZ2dl"
|
||||
+ "ck5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMAAdtZXNzYWdlcQB+AAJMABJyZXNv"
|
||||
+ "dXJjZUJ1bmRsZU5hbWVxAH4AAkwAD3NvdXJjZUNsYXNzTmFtZXEAfgACTAAQc291"
|
||||
+ "cmNlTWV0aG9kTmFtZXEAfgACTAAGdGhyb3dudAAVTGphdmEvbGFuZy9UaHJvd2Fi"
|
||||
+ "bGU7eHAAAAFLl3u6OAAOU/gAAAAAAAAAAAAAAAFzcgAXamF2YS51dGlsLmxvZ2dp"
|
||||
+ "bmcuTGV2ZWyOiHETUXM2kgIAA0kABXZhbHVlTAAEbmFtZXEAfgACTAAScmVzb3Vy"
|
||||
+ "Y2VCdW5kbGVOYW1lcQB+AAJ4cAAAAyB0AARJTkZPdAAic3VuLnV0aWwubG9nZ2lu"
|
||||
+ "Zy5yZXNvdXJjZXMubG9nZ2luZ3QABHRlc3R0ABFKYXZhIFZlcnNpb246IHswfXBw"
|
||||
+ "cHB3BgEAAAAAAXQADjEuOS4wLWludGVybmFseA==";
|
||||
|
||||
/**
|
||||
* SimpleFormatter output for LogRecord object.
|
||||
* Java version: 1.9.0-internal
|
||||
**/
|
||||
final String str =
|
||||
"Feb 17, 2015 12:20:43.192939000 PM test - INFO: Java Version: 1.9.0-internal";
|
||||
// ^^^
|
||||
// Notice the micro second resolution above...
|
||||
|
||||
// END
|
||||
// --------------------------------
|
||||
|
||||
@Override
|
||||
public String getBase64() {
|
||||
return base64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void check(String expected, String actual) {
|
||||
if (System.getProperty("java.version").startsWith("1.8")) {
|
||||
// If we are in JDK 8 and print a log record serialized in JDK 9,
|
||||
// then we won't be able to print anything below the millisecond
|
||||
// precision, since that hasn't been implemented in JDK 8.
|
||||
// Therefore - we need to replace anything below millseconds by
|
||||
// zeroes in the expected string (which was generated on JDK 9).
|
||||
Pattern pattern = Pattern.compile("^"
|
||||
+ "(.*\\.[0-9][0-9][0-9])" // group1: everything up to milliseconds
|
||||
+ "([0-9][0-9][0-9][0-9][0-9][0-9])" // group 2: micros and nanos
|
||||
+ "(.* - .*)$"); // group three: all the rest...
|
||||
Matcher matcher = pattern.matcher(expected);
|
||||
if (matcher.matches()) {
|
||||
expected = matcher.group(1) + "000000" + matcher.group(3);
|
||||
}
|
||||
}
|
||||
super.check(expected, actual);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
new Jdk9SerializedLog().dotest();
|
||||
}
|
||||
}
|
||||
|
||||
public static void generate() {
|
||||
try {
|
||||
LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {System.getProperty("java.version")});
|
||||
System.out.println(generate(record));
|
||||
} catch (IOException | ClassNotFoundException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
static enum TestCase { GENERATE, TESTJDK8, TESTJDK9 };
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Set the locale and time zone to make sure we won't depend on the
|
||||
// test env - in particular we don't want to depend on the
|
||||
// time zone in which the test machine might be located.
|
||||
// So we're gong to use Locale English and Time Zone UTC for this test.
|
||||
// (Maybe that should be Locale.ROOT?)
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC")));
|
||||
|
||||
// Set the format property to make sure we always have the nanos, and
|
||||
// to make sure it's the same format than what we used when
|
||||
// computing the formatted string for Jdk8SerializedLog and
|
||||
// Jdk9SerializedLog above.
|
||||
//
|
||||
// If you change the formatting, then you will need to regenerate
|
||||
// the data for Jdk8SerializedLog and Jdk9SerializedLog.
|
||||
//
|
||||
// To do that - just run this test on JDK 8, and cut & paste the
|
||||
// pseudo code printed by generate() into Jdk8SerializedLog.
|
||||
// Then run this test again on JDK 9, and cut & paste the
|
||||
// pseudo code printed by generate() into Jdk9SerializedLog.
|
||||
// [Note: you can pass GENERATE as single arg to main() to avoid
|
||||
// running the actual test]
|
||||
// Finally run the test again to check that it still passes after
|
||||
// your modifications.
|
||||
//
|
||||
System.setProperty("java.util.logging.SimpleFormatter.format",
|
||||
"%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS.%1$tN %1$Tp %2$s - %4$s: %5$s%6$s");
|
||||
|
||||
// If no args, then run everything....
|
||||
if (args == null || args.length == 0) {
|
||||
args = new String[] { "GENERATE", "TESTJDK8", "TESTJDK9" };
|
||||
}
|
||||
|
||||
// Run the specified test case(s)
|
||||
Stream.of(args).map(x -> TestCase.valueOf(x)).forEach((x) -> {
|
||||
switch(x) {
|
||||
case GENERATE: generate(); break;
|
||||
case TESTJDK8: Jdk8SerializedLog.test(); break;
|
||||
case TESTJDK9: Jdk9SerializedLog.test(); break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645
|
||||
* @summary tests that SimpleFormatter can print out dates with the new
|
||||
* nanosecond precision.
|
||||
* @run main/othervm SimpleFormatterNanos
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class SimpleFormatterNanos {
|
||||
|
||||
static final int MILLIS_IN_SECOND = 1000;
|
||||
static final int NANOS_IN_MILLI = 1000_000;
|
||||
static final int NANOS_IN_MICRO = 1000;
|
||||
static final int NANOS_IN_SECOND = 1000_000_000;
|
||||
|
||||
static final boolean verbose = true;
|
||||
|
||||
static final class TestAssertException extends RuntimeException {
|
||||
TestAssertException(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
private static void assertEquals(long expected, long received, String msg) {
|
||||
if (expected != received) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
static int getNanoAdjustment(LogRecord record) {
|
||||
return record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
}
|
||||
static void setNanoAdjustment(LogRecord record, int nanos) {
|
||||
record.setInstant(Instant.ofEpochSecond(record.getInstant().getEpochSecond(),
|
||||
(record.getInstant().getNano() / NANOS_IN_MILLI) * NANOS_IN_MILLI + nanos));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {System.getProperty("java.version")});
|
||||
int nanos = getNanoAdjustment(record);
|
||||
long millis = record.getMillis();
|
||||
// make sure we don't have leading zeros when printing below
|
||||
// the second precision
|
||||
if (millis % MILLIS_IN_SECOND < 100) millis = millis + 100;
|
||||
// make sure we have some nanos
|
||||
if (nanos % NANOS_IN_MICRO == 0) nanos = nanos + 999;
|
||||
record.setMillis(millis);
|
||||
setNanoAdjustment(record, nanos);
|
||||
final Instant instant = record.getInstant();
|
||||
if (nanos < 0) {
|
||||
throw new RuntimeException("Unexpected negative nano adjustment: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (nanos >= NANOS_IN_MILLI) {
|
||||
throw new RuntimeException("Nano adjustment exceeds 1ms: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (millis != record.getMillis()) {
|
||||
throw new RuntimeException("Unexpected millis: " + millis + " != "
|
||||
+ record.getMillis());
|
||||
}
|
||||
if (millis != record.getInstant().toEpochMilli()) {
|
||||
throw new RuntimeException("Unexpected millis: "
|
||||
+ record.getInstant().toEpochMilli());
|
||||
}
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
int zdtNanos = zdt.getNano();
|
||||
long expectedNanos = (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + nanos;
|
||||
assertEquals(expectedNanos, instant.getNano(), "Instant.getNano()");
|
||||
assertEquals(expectedNanos, zdtNanos, "ZonedDateTime.getNano()");
|
||||
String match = "."+expectedNanos+" ";
|
||||
|
||||
System.out.println("Testing with default format...");
|
||||
|
||||
SimpleFormatter formatter = new SimpleFormatter();
|
||||
String str = formatter.format(record);
|
||||
if (str.contains(match)) {
|
||||
throw new RuntimeException("SimpleFormatter.format()"
|
||||
+ " string contains unexpected nanos: "
|
||||
+ "\n\tdid not expect match for: '" + match + "'"
|
||||
+ "\n\tin: " + str);
|
||||
}
|
||||
|
||||
System.out.println("Nanos omitted as expected: no '"+match+"' in "+str);
|
||||
|
||||
|
||||
System.out.println("Changing format to print nanos...");
|
||||
System.setProperty("java.util.logging.SimpleFormatter.format",
|
||||
"%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS.%1$tN %1$Tp %2$s%n%4$s: %5$s%6$s%n");
|
||||
|
||||
SimpleFormatter formatter2 = new SimpleFormatter();
|
||||
str = formatter2.format(record);
|
||||
if (!str.contains(match)) {
|
||||
throw new RuntimeException("SimpleFormatter.format()"
|
||||
+ " string does not contain expected nanos: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: " + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in "+str);
|
||||
|
||||
|
||||
System.out.println("Changing format to omit nanos...");
|
||||
System.setProperty("java.util.logging.SimpleFormatter.format",
|
||||
"%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n");
|
||||
|
||||
SimpleFormatter formatter3 = new SimpleFormatter();
|
||||
str = formatter3.format(record);
|
||||
String notMatch = match;
|
||||
if (str.contains(notMatch)) {
|
||||
throw new RuntimeException("SimpleFormatter.format()"
|
||||
+ " string contains unexpected nanos: "
|
||||
+ "\n\tdid not expect match for: '" + notMatch + "'"
|
||||
+ "\n\tin: " + str);
|
||||
}
|
||||
System.out.println("Nanos omitted as expected: no '"+notMatch+"' in "+str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.XMLFormatter;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645
|
||||
* @summary tests that XmlFormatter will print out dates with the new
|
||||
* nanosecond precision.
|
||||
* @run main/othervm XmlFormatterNanos
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class XmlFormatterNanos {
|
||||
|
||||
static final int MILLIS_IN_SECOND = 1000;
|
||||
static final int NANOS_IN_MILLI = 1000_000;
|
||||
static final int NANOS_IN_MICRO = 1000;
|
||||
static final int NANOS_IN_SECOND = 1000_000_000;
|
||||
|
||||
static final boolean verbose = true;
|
||||
|
||||
static final class TestAssertException extends RuntimeException {
|
||||
TestAssertException(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
private static void assertEquals(long expected, long received, String msg) {
|
||||
if (expected != received) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEquals(Object expected, Object received, String msg) {
|
||||
if (!Objects.equals(expected, received)) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomXMLFormatter extends XMLFormatter {}
|
||||
|
||||
static class Configuration {
|
||||
final Properties propertyFile;
|
||||
private Configuration(Properties properties) {
|
||||
propertyFile = properties;
|
||||
}
|
||||
public Configuration apply() {
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
propertyFile.store(bytes, testName());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray());
|
||||
LogManager.getLogManager().readConfiguration(bais);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static String useInstantProperty(Class<?> type) {
|
||||
return type.getName()+".useInstant";
|
||||
}
|
||||
|
||||
public boolean useInstant(XMLFormatter formatter) {
|
||||
return Boolean.parseBoolean(propertyFile.getProperty(
|
||||
formatter.getClass().getName()+".useInstant", "true"));
|
||||
}
|
||||
|
||||
public String testName() {
|
||||
return propertyFile.getProperty("test.name", "????");
|
||||
}
|
||||
|
||||
public static Configuration of(Properties props) {
|
||||
return new Configuration(props);
|
||||
}
|
||||
|
||||
public static Configuration apply(Properties props) {
|
||||
return of(props).apply();
|
||||
}
|
||||
}
|
||||
|
||||
static final List<Properties> properties;
|
||||
static {
|
||||
Properties props1 = new Properties();
|
||||
props1.setProperty("test.name", "with XML nano element (default)");
|
||||
Properties props2 = new Properties();
|
||||
props2.setProperty("test.name", "with XML nano element (standard=true, custom=false)");
|
||||
props2.setProperty(Configuration.useInstantProperty(XMLFormatter.class), "true");
|
||||
props2.setProperty(Configuration.useInstantProperty(CustomXMLFormatter.class), "false");
|
||||
Properties props3 = new Properties();
|
||||
props3.setProperty("test.name", "with XML nano element (standard=false, custom=true)");
|
||||
props3.setProperty(Configuration.useInstantProperty(XMLFormatter.class), "false");
|
||||
props3.setProperty(Configuration.useInstantProperty(CustomXMLFormatter.class), "true");
|
||||
|
||||
properties = Collections.unmodifiableList(Arrays.asList(
|
||||
props1,
|
||||
props2));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
properties.stream().forEach(XmlFormatterNanos::test);
|
||||
}
|
||||
|
||||
static int getNanoAdjustment(LogRecord record) {
|
||||
return record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
}
|
||||
static void setNanoAdjustment(LogRecord record, int nanos) {
|
||||
record.setInstant(Instant.ofEpochSecond(record.getInstant().getEpochSecond(),
|
||||
(record.getInstant().getNano() / NANOS_IN_MILLI) * NANOS_IN_MILLI + nanos));
|
||||
}
|
||||
|
||||
public static void test(Properties props) {
|
||||
Configuration conf = Configuration.apply(props);
|
||||
|
||||
LogRecord record = new LogRecord(Level.INFO, "Test Name: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {conf.testName()});
|
||||
int nanos = record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
long millis = record.getMillis();
|
||||
// make sure we don't have leading zeros when printing below
|
||||
// the second precision
|
||||
if (millis % MILLIS_IN_SECOND < 100) millis = millis + 100;
|
||||
// make sure we some nanos - and make sure we don't have
|
||||
// trailing zeros
|
||||
if (nanos % 10 == 0) nanos = nanos + 7;
|
||||
|
||||
record.setMillis(millis);
|
||||
setNanoAdjustment(record, nanos);
|
||||
final Instant instant = record.getInstant();
|
||||
if (nanos < 0) {
|
||||
throw new RuntimeException("Unexpected negative nano adjustment: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (nanos >= NANOS_IN_MILLI) {
|
||||
throw new RuntimeException("Nano adjustment exceeds 1ms: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (millis != record.getMillis()) {
|
||||
throw new RuntimeException("Unexpected millis: " + millis + " != "
|
||||
+ record.getMillis());
|
||||
}
|
||||
if (millis != record.getInstant().toEpochMilli()) {
|
||||
throw new RuntimeException("Unexpected millis: "
|
||||
+ record.getInstant().toEpochMilli());
|
||||
}
|
||||
long expectedNanos = (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + nanos;
|
||||
assertEquals(expectedNanos, instant.getNano(), "Instant.getNano()");
|
||||
|
||||
XMLFormatter formatter = new XMLFormatter();
|
||||
testMatching(formatter, record, instant, expectedNanos, conf.useInstant(formatter));
|
||||
|
||||
XMLFormatter custom = new CustomXMLFormatter();
|
||||
testMatching(custom, record, instant, expectedNanos, conf.useInstant(custom));
|
||||
}
|
||||
|
||||
private static void testMatching(XMLFormatter formatter,
|
||||
LogRecord record, Instant instant, long expectedNanos,
|
||||
boolean useInstant) {
|
||||
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
int zdtNanos = zdt.getNano();
|
||||
assertEquals(expectedNanos, zdtNanos, "ZonedDateTime.getNano()");
|
||||
|
||||
String str = formatter.format(record);
|
||||
|
||||
String match = "."+expectedNanos;
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected nanos: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
match = "<millis>"+instant.toEpochMilli()+"</millis>";
|
||||
if (!str.contains(match)) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected millis: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
match = "<nanos>";
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string "
|
||||
+ (useInstant
|
||||
? "does not contain expected nanos: "
|
||||
: "contains unexpected nanos: ")
|
||||
+ "\n\t" + (useInstant ? "expected" : "unexpected")
|
||||
+ " match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
match = "<nanos>"+getNanoAdjustment(record)+"</nanos>";
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string "
|
||||
+ (useInstant
|
||||
? "does not contain expected nanos: "
|
||||
: "contains unexpected nanos: ")
|
||||
+ "\n\t" + (useInstant ? "expected" : "unexpected")
|
||||
+ " match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
if (useInstant) {
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
} else {
|
||||
System.out.println("As expected '"+match+"' is not present in \n"+str);
|
||||
}
|
||||
|
||||
match = useInstant ? DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||
: zdt.truncatedTo(ChronoUnit.SECONDS)
|
||||
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
match = "<date>"+match+"</date>";
|
||||
if (!str.contains(match)) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected date: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue