jdk/test/java/util/logging/HigherResolutionTimeStamps/SerializeLogRecord.java
changeset 29117 7956b5dc0eac
child 32649 2ee9017c7597
equal deleted inserted replaced
29116:9918719cfcc0 29117:7956b5dc0eac
       
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 import java.io.ByteArrayInputStream;
       
    24 import java.io.ByteArrayOutputStream;
       
    25 import java.io.IOException;
       
    26 import java.io.ObjectInputStream;
       
    27 import java.io.ObjectOutputStream;
       
    28 import java.time.ZoneId;
       
    29 import java.util.Base64;
       
    30 import java.util.Locale;
       
    31 import java.util.TimeZone;
       
    32 import java.util.logging.Level;
       
    33 import java.util.logging.LogRecord;
       
    34 import java.util.logging.SimpleFormatter;
       
    35 import java.util.regex.Matcher;
       
    36 import java.util.regex.Pattern;
       
    37 import java.util.stream.Stream;
       
    38 
       
    39 /**
       
    40  * @test
       
    41  * @bug 8072645
       
    42  * @summary tests the compatibility of LogRecord serial form between
       
    43  *          JDK 8 and JDK 9. Ideally this test should be run on both platforms.
       
    44  *          (It is designed to run on both).
       
    45  * @run main/othervm SerializeLogRecord
       
    46  * @author danielfuchs
       
    47  */
       
    48 public class SerializeLogRecord {
       
    49 
       
    50     /**
       
    51      * Serializes a log record, encode the serialized bytes in base 64, and
       
    52      * prints pseudo java code that can be cut and pasted into this test.
       
    53      * @param record the log record to serialize, encode in base 64, and for
       
    54      *               which test data will be generated.
       
    55      * @return A string containing the generated pseudo java code.
       
    56      * @throws IOException Unexpected.
       
    57      * @throws ClassNotFoundException  Unexpected.
       
    58      */
       
    59     public static String generate(LogRecord record) throws IOException, ClassNotFoundException {
       
    60 
       
    61         // Format the given logRecord using the SimpleFormatter
       
    62         SimpleFormatter formatter = new SimpleFormatter();
       
    63         String str = formatter.format(record);
       
    64 
       
    65         // Serialize the given LogRecord
       
    66         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
       
    67         final ObjectOutputStream oos = new ObjectOutputStream(baos);
       
    68         oos.writeObject(record);
       
    69         oos.flush();
       
    70         oos.close();
       
    71 
       
    72         // Now we're going to perform a number of smoke tests before
       
    73         // generating the Java pseudo code.
       
    74         //
       
    75         // First checks that the log record can be deserialized
       
    76         final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
       
    77         final ObjectInputStream ois = new ObjectInputStream(bais);
       
    78         final LogRecord record2 = (LogRecord)ois.readObject();
       
    79 
       
    80         // Format the deserialized LogRecord using the SimpleFormatter, and
       
    81         // check that the string representation obtained matches the string
       
    82         // representation of the original LogRecord
       
    83         String str2 = formatter.format(record2);
       
    84         if (!str.equals(str2)) throw new RuntimeException("Unexpected values in deserialized object:"
       
    85                 + "\n\tExpected:  " + str
       
    86                 + "\n\tRetrieved: "+str);
       
    87 
       
    88         // Now get a Base64 string representation of the serialized bytes.
       
    89         final String base64 = Base64.getEncoder().encodeToString(baos.toByteArray());
       
    90 
       
    91         // Check that we can deserialize a log record from the Base64 string
       
    92         // representation we just computed.
       
    93         final ByteArrayInputStream bais2 = new ByteArrayInputStream(Base64.getDecoder().decode(base64));
       
    94         final ObjectInputStream ois2 = new ObjectInputStream(bais2);
       
    95         final LogRecord record3 = (LogRecord)ois2.readObject();
       
    96 
       
    97         // Format the new deserialized LogRecord using the SimpleFormatter, and
       
    98         // check that the string representation obtained matches the string
       
    99         // representation of the original LogRecord
       
   100         String str3 = formatter.format(record3);
       
   101         if (!str.equals(str3)) throw new RuntimeException("Unexpected values in deserialized object:"
       
   102                 + "\n\tExpected:  " + str
       
   103                 + "\n\tRetrieved: "+str);
       
   104         //System.out.println(base64);
       
   105         //System.out.println();
       
   106 
       
   107         // Generates the Java Pseudo code that can be cut & pasted into
       
   108         // this test (see Jdk8SerializedLog and Jdk9SerializedLog below)
       
   109         final StringBuilder sb = new StringBuilder();
       
   110         sb.append("    /**").append('\n');
       
   111         sb.append("     * Base64 encoded string for LogRecord object.").append('\n');
       
   112         sb.append("     * Java version: ").append(System.getProperty("java.version")).append('\n');
       
   113         sb.append("     **/").append('\n');
       
   114         sb.append("    final String base64 = ").append("\n          ");
       
   115         final int last = base64.length() - 1;
       
   116         for (int i=0; i<base64.length();i++) {
       
   117             if (i%64 == 0) sb.append("\"");
       
   118             sb.append(base64.charAt(i));
       
   119             if (i%64 == 63 || i == last) {
       
   120                 sb.append("\"");
       
   121                 if (i == last) sb.append(";\n");
       
   122                 else sb.append("\n        + ");
       
   123             }
       
   124         }
       
   125         sb.append('\n');
       
   126         sb.append("    /**").append('\n');
       
   127         sb.append("     * SimpleFormatter output for LogRecord object.").append('\n');
       
   128         sb.append("     * Java version: ").append(System.getProperty("java.version")).append('\n');
       
   129         sb.append("     **/").append('\n');
       
   130         sb.append("    final String str = ").append("\n          ");
       
   131         sb.append("\"").append(str.replace("\n", "\\n")).append("\";\n");
       
   132         return sb.toString();
       
   133     }
       
   134 
       
   135     /**
       
   136      * An abstract class to test that a log record previously serialized on a
       
   137      * different java version can be deserialized in the current java version.
       
   138      * (see Jdk8SerializedLog and Jdk9SerializedLog below)
       
   139      */
       
   140     public static abstract class SerializedLog {
       
   141         public abstract String getBase64();
       
   142         public abstract String getString();
       
   143 
       
   144         /**
       
   145          * Deserializes the Base64 encoded string returned by {@link
       
   146          * #getBase64()}, format the obtained LogRecord using a
       
   147          * SimpleFormatter, and checks that the string representation obtained
       
   148          * matches the original string representation returned by {@link
       
   149          * #getString()}.
       
   150          */
       
   151         protected void dotest() {
       
   152             try {
       
   153                 final String base64 = getBase64();
       
   154                 final ByteArrayInputStream bais =
       
   155                         new ByteArrayInputStream(Base64.getDecoder().decode(base64));
       
   156                 final ObjectInputStream ois = new ObjectInputStream(bais);
       
   157                 final LogRecord record = (LogRecord)ois.readObject();
       
   158                 final SimpleFormatter formatter = new SimpleFormatter();
       
   159                 String expected = getString();
       
   160                 String str2 = formatter.format(record);
       
   161                 check(expected, str2);
       
   162                 System.out.println(str2);
       
   163                 System.out.println("PASSED: "+this.getClass().getName()+"\n");
       
   164             } catch (IOException | ClassNotFoundException x) {
       
   165                 throw new RuntimeException(x);
       
   166             }
       
   167         }
       
   168         /**
       
   169          * Check that the actual String representation obtained matches the
       
   170          * expected String representation.
       
   171          * @param expected Expected String representation, as returned by
       
   172          *                 {@link #getString()}.
       
   173          * @param actual   Actual String representation obtained by formatting
       
   174          *                 the LogRecord obtained by the deserialization of the
       
   175          *                 bytes encoded in {@link #getBase64()}.
       
   176          */
       
   177         protected void check(String expected, String actual) {
       
   178             if (!expected.equals(actual)) {
       
   179                 throw new RuntimeException(this.getClass().getName()
       
   180                     + " - Unexpected values in deserialized object:"
       
   181                     + "\n\tExpected:  " + expected
       
   182                     + "\n\tRetrieved: "+ actual);
       
   183             }
       
   184         }
       
   185     }
       
   186 
       
   187     public static class Jdk8SerializedLog extends SerializedLog {
       
   188 
       
   189         // Generated by generate() on JDK 8.
       
   190         // --------------------------------
       
   191         // BEGIN
       
   192 
       
   193         /**
       
   194          * Base64 encoded string for LogRecord object.
       
   195          * Java version: 1.8.0_11
       
   196          **/
       
   197         final String base64 =
       
   198               "rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMACkoA"
       
   199             + "Bm1pbGxpc0oADnNlcXVlbmNlTnVtYmVySQAIdGhyZWFkSURMAAVsZXZlbHQAGUxq"
       
   200             + "YXZhL3V0aWwvbG9nZ2luZy9MZXZlbDtMAApsb2dnZXJOYW1ldAASTGphdmEvbGFu"
       
   201             + "Zy9TdHJpbmc7TAAHbWVzc2FnZXEAfgACTAAScmVzb3VyY2VCdW5kbGVOYW1lcQB+"
       
   202             + "AAJMAA9zb3VyY2VDbGFzc05hbWVxAH4AAkwAEHNvdXJjZU1ldGhvZE5hbWVxAH4A"
       
   203             + "AkwABnRocm93bnQAFUxqYXZhL2xhbmcvVGhyb3dhYmxlO3hwAAABSjUCgo0AAAAA"
       
   204             + "AAAAAAAAAAFzcgAXamF2YS51dGlsLmxvZ2dpbmcuTGV2ZWyOiHETUXM2kgIAA0kA"
       
   205             + "BXZhbHVlTAAEbmFtZXEAfgACTAAScmVzb3VyY2VCdW5kbGVOYW1lcQB+AAJ4cAAA"
       
   206             + "AyB0AARJTkZPdAAic3VuLnV0aWwubG9nZ2luZy5yZXNvdXJjZXMubG9nZ2luZ3QA"
       
   207             + "BHRlc3R0ABFKYXZhIFZlcnNpb246IHswfXBwcHB3BgEAAAAAAXQACDEuOC4wXzEx"
       
   208             + "eA==";
       
   209 
       
   210         /**
       
   211          * SimpleFormatter output for LogRecord object.
       
   212          * Java version: 1.8.0_11
       
   213          **/
       
   214         final String str =
       
   215               "Dec 10, 2014 4:22:44.621000000 PM test - INFO: Java Version: 1.8.0_11";
       
   216               //                    ^^^
       
   217               // Notice the milli second resolution above...
       
   218 
       
   219         // END
       
   220         // --------------------------------
       
   221 
       
   222         @Override
       
   223         public String getBase64() {
       
   224             return base64;
       
   225         }
       
   226 
       
   227         @Override
       
   228         public String getString() {
       
   229             return str;
       
   230         }
       
   231 
       
   232         public static void test() {
       
   233             new Jdk8SerializedLog().dotest();
       
   234         }
       
   235     }
       
   236 
       
   237     public static class Jdk9SerializedLog extends SerializedLog {
       
   238 
       
   239         // Generated by generate() on JDK 9.
       
   240         // --------------------------------
       
   241         // BEGIN
       
   242 
       
   243         /**
       
   244          * Base64 encoded string for LogRecord object.
       
   245          * Java version: 1.9.0-internal
       
   246          **/
       
   247         final String base64 =
       
   248               "rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMAC0oA"
       
   249             + "Bm1pbGxpc0kADm5hbm9BZGp1c3RtZW50SgAOc2VxdWVuY2VOdW1iZXJJAAh0aHJl"
       
   250             + "YWRJREwABWxldmVsdAAZTGphdmEvdXRpbC9sb2dnaW5nL0xldmVsO0wACmxvZ2dl"
       
   251             + "ck5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMAAdtZXNzYWdlcQB+AAJMABJyZXNv"
       
   252             + "dXJjZUJ1bmRsZU5hbWVxAH4AAkwAD3NvdXJjZUNsYXNzTmFtZXEAfgACTAAQc291"
       
   253             + "cmNlTWV0aG9kTmFtZXEAfgACTAAGdGhyb3dudAAVTGphdmEvbGFuZy9UaHJvd2Fi"
       
   254             + "bGU7eHAAAAFLl3u6OAAOU/gAAAAAAAAAAAAAAAFzcgAXamF2YS51dGlsLmxvZ2dp"
       
   255             + "bmcuTGV2ZWyOiHETUXM2kgIAA0kABXZhbHVlTAAEbmFtZXEAfgACTAAScmVzb3Vy"
       
   256             + "Y2VCdW5kbGVOYW1lcQB+AAJ4cAAAAyB0AARJTkZPdAAic3VuLnV0aWwubG9nZ2lu"
       
   257             + "Zy5yZXNvdXJjZXMubG9nZ2luZ3QABHRlc3R0ABFKYXZhIFZlcnNpb246IHswfXBw"
       
   258             + "cHB3BgEAAAAAAXQADjEuOS4wLWludGVybmFseA==";
       
   259 
       
   260         /**
       
   261          * SimpleFormatter output for LogRecord object.
       
   262          * Java version: 1.9.0-internal
       
   263          **/
       
   264         final String str =
       
   265               "Feb 17, 2015 12:20:43.192939000 PM test - INFO: Java Version: 1.9.0-internal";
       
   266               //                       ^^^
       
   267               // Notice the micro second resolution above...
       
   268 
       
   269         // END
       
   270         // --------------------------------
       
   271 
       
   272         @Override
       
   273         public String getBase64() {
       
   274             return base64;
       
   275         }
       
   276 
       
   277         @Override
       
   278         public String getString() {
       
   279             return str;
       
   280         }
       
   281 
       
   282         @Override
       
   283         protected void check(String expected, String actual) {
       
   284             if (System.getProperty("java.version").startsWith("1.8")) {
       
   285                 // If we are in JDK 8 and print a log record serialized in JDK 9,
       
   286                 // then we won't be able to print anything below the millisecond
       
   287                 // precision, since that hasn't been implemented in JDK 8.
       
   288                 // Therefore - we need to replace anything below millseconds by
       
   289                 // zeroes in the expected string (which was generated on JDK 9).
       
   290                 Pattern pattern = Pattern.compile("^"
       
   291                         + "(.*\\.[0-9][0-9][0-9])" // group1: everything up to milliseconds
       
   292                         + "([0-9][0-9][0-9][0-9][0-9][0-9])" // group 2: micros and nanos
       
   293                         + "(.* - .*)$"); // group three: all the rest...
       
   294                 Matcher matcher = pattern.matcher(expected);
       
   295                 if (matcher.matches()) {
       
   296                     expected = matcher.group(1) + "000000" + matcher.group(3);
       
   297                 }
       
   298             }
       
   299             super.check(expected, actual);
       
   300         }
       
   301 
       
   302         public static void test() {
       
   303             new Jdk9SerializedLog().dotest();
       
   304         }
       
   305     }
       
   306 
       
   307     public static void generate() {
       
   308         try {
       
   309             LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
       
   310             record.setLoggerName("test");
       
   311             record.setParameters(new Object[] {System.getProperty("java.version")});
       
   312             System.out.println(generate(record));
       
   313         } catch (IOException | ClassNotFoundException x) {
       
   314             throw new RuntimeException(x);
       
   315         }
       
   316     }
       
   317 
       
   318     static enum TestCase { GENERATE, TESTJDK8, TESTJDK9 };
       
   319 
       
   320     public static void main(String[] args) {
       
   321         // Set the locale and time zone to make sure we won't depend on the
       
   322         // test env - in particular we don't want to depend on the
       
   323         // time zone in which the test machine might be located.
       
   324         // So we're gong to use Locale English and Time Zone UTC for this test.
       
   325         // (Maybe that should be Locale.ROOT?)
       
   326         Locale.setDefault(Locale.ENGLISH);
       
   327         TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC")));
       
   328 
       
   329         // Set the format property to make sure we always have the nanos, and
       
   330         // to make sure it's the same format than what we used when
       
   331         // computing the formatted string for Jdk8SerializedLog and
       
   332         // Jdk9SerializedLog above.
       
   333         //
       
   334         // If you change the formatting, then you will need to regenerate
       
   335         // the data for Jdk8SerializedLog and Jdk9SerializedLog.
       
   336         //
       
   337         // To do that - just run this test on JDK 8, and cut & paste the
       
   338         // pseudo code printed by generate() into Jdk8SerializedLog.
       
   339         // Then run this test again on JDK 9, and cut & paste the
       
   340         // pseudo code printed by generate() into Jdk9SerializedLog.
       
   341         // [Note: you can pass GENERATE as single arg to main() to avoid
       
   342         //        running the actual test]
       
   343         // Finally run the test again to check that it still passes after
       
   344         // your modifications.
       
   345         //
       
   346         System.setProperty("java.util.logging.SimpleFormatter.format",
       
   347                 "%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS.%1$tN %1$Tp %2$s - %4$s: %5$s%6$s");
       
   348 
       
   349         // If no args, then run everything....
       
   350         if (args == null || args.length == 0) {
       
   351             args = new String[] { "GENERATE", "TESTJDK8", "TESTJDK9" };
       
   352         }
       
   353 
       
   354         // Run the specified test case(s)
       
   355         Stream.of(args).map(x -> TestCase.valueOf(x)).forEach((x) -> {
       
   356             switch(x) {
       
   357                 case GENERATE: generate(); break;
       
   358                 case TESTJDK8: Jdk8SerializedLog.test(); break;
       
   359                 case TESTJDK9: Jdk9SerializedLog.test(); break;
       
   360             }
       
   361         });
       
   362     }
       
   363 }