jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java
author dfuchs
Wed, 27 Apr 2016 18:04:16 +0200
changeset 37672 03684934dc09
parent 35315 67dcc46f8241
child 42338 a60f280f803c
permissions -rw-r--r--
8148568: LoggerFinder.getLogger and LoggerFinder.getLocalizedLogger should take a Module argument instead of a Class. Summary: Changes System.LoggerFinder methods to take a Module argument instead of a Class. Reviewed-by: mchung

/*
 * 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.PrintStream;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Enumeration;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import java.lang.reflect.Module;
import jdk.internal.logger.BootstrapLogger;
import jdk.internal.logger.LazyLoggers;

/*
 * @test
 * @bug     8144460 8144214
 * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
 *          and logXX APIs of SimpleConsoleLogger.
 * @modules java.base/jdk.internal.logger
 *          java.base/sun.util.logging
 * @build BootstrapLoggerUtils LogStream
 * @run main/othervm BootstrapLoggerAPIsTest
 */

public class BootstrapLoggerAPIsTest {

    private static final LogStream ERR = new LogStream();

    public static void main(String[] args) throws Exception {

        final ContentManager MGR = new ContentManager();

        // private reflection hook that allows us to simulate a non booted VM
        final AtomicBoolean VM_BOOTED = new AtomicBoolean(false);

        BootstrapLoggerUtils.setBootedHook(() -> VM_BOOTED.get());

        // We replace System.err to check the messages that have been logged
        // by the JUL ConsoleHandler and default SimpleConsoleLogger
        // implementaion
        System.setErr(new PrintStream(ERR));

        VM_BOOTED.getAndSet(false);
        if (BootstrapLogger.isBooted()) {
            throw new RuntimeException("VM should not be booted!");
        }

        final Logger LOGGER =
                LazyLoggers.getLogger("foo.bar", Thread.class.getModule());
        final sun.util.logging.PlatformLogger.Level PLATFORM_LEVEL =
                sun.util.logging.PlatformLogger.Level.SEVERE;
        final MyResources BUNDLE = new MyResources();

        /*
         * Test logXX APIs for interface java.lang.System.Logger. Log content
         * before VM is booted should be retained. Log content after VM was
         * booted should be flushed instantly. VM is not booted in first round
         * of loop, VM is booted in second round of loop.
         */
        for (int i = 0; i < 2; i++) {
            boolean booted = BootstrapLogger.isBooted();

            // make sure there is no [remaining] content in the LogStream.
            MGR.failLog("xyz", "throwable #", "MyClass_#", "MyMethod_#");

            /*
             * test logXX APIs for interface java.lang.System.Logger.
             */
            // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
            //          java.lang.String,java.lang.Throwable)
            LOGGER.log(Level.ERROR, BUNDLE, "abc #0", new RuntimeException("throwable #0"));
            MGR.checkLog(booted, "xyz #0", "throwable #0");

            // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
            //          java.lang.String,java.lang.Object[])
            LOGGER.log(Level.ERROR, BUNDLE, "abc #1");
            MGR.checkLog(booted, "xyz #1");

            // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Object[])
            LOGGER.log(Level.ERROR, BUNDLE, "abc {0}", "#2");
            MGR.checkLog(booted, "xyz #2");

            // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Throwable)
            LOGGER.log(Level.ERROR, "xyz #3", new RuntimeException("throwable #3"));
            MGR.checkLog(booted, "xyz #3", "throwable #3");

            // void log(java.lang.System$Logger$Level,java.util.function.Supplier)
            LOGGER.log(Level.ERROR, () -> "xyz #4");
            MGR.checkLog(booted, "xyz #4");

            // void log(java.lang.System$Logger$Level,java.lang.Object)
            LOGGER.log(Level.ERROR, new MyObject("xyz #5"));
            MGR.checkLog(booted, "xyz #5");

            // void log(java.lang.System$Logger$Level,java.util.function.Supplier,
            //          java.lang.Throwable)
            LOGGER.log(Level.ERROR, () -> "xyz #6", new RuntimeException("throwable #6"));
            MGR.checkLog(booted, "xyz #6", "throwable #6");


            /*
             * test logXX APIs for interface
             * sun.util.logging.PlatformLogger.Bridge.
             */
            sun.util.logging.PlatformLogger.Bridge bridge =
                    (sun.util.logging.PlatformLogger.Bridge) LOGGER;

            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String)
            bridge.log(PLATFORM_LEVEL, "xyz #7");
            MGR.checkLog(booted, "xyz #7");

            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Throwable)
            bridge.log(PLATFORM_LEVEL, "xyz #8", new RuntimeException("throwable #8"));
            MGR.checkLog(booted, "xyz #8", "throwable #8");

            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Object[])
            bridge.log(PLATFORM_LEVEL, "xyz {0}", "#9");
            MGR.checkLog(booted, "xyz #9");

            // void log(sun.util.logging.PlatformLogger$Level,java.util.function.Supplier)
            bridge.log(PLATFORM_LEVEL, () -> "xyz #10");
            MGR.checkLog(booted, "xyz #10");

            // void log(sun.util.logging.PlatformLogger$Level,
            //        java.lang.Throwable,java.util.function.Supplier)
            bridge.log(PLATFORM_LEVEL, new RuntimeException("throwable #11"), () -> "xyz #11");
            MGR.checkLog(booted, "xyz #11", "throwable #11");

            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
            //          java.lang.String,java.lang.String)
            bridge.logp(PLATFORM_LEVEL, "MyClass_#12", "MyMethod_#12", "xyz #12");
            MGR.checkLog(booted, "xyz #12", "MyClass_#12", "MyMethod_#12");

            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
            //          java.lang.String,java.util.function.Supplier)
            bridge.logp(PLATFORM_LEVEL, "MyClass_#13", "MyMethod_#13", () -> "xyz #13");
            MGR.checkLog(booted, "xyz #13", "MyClass_#13", "MyMethod_#13");

            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
            //          java.lang.String,java.lang.String,java.lang.Object[])
            bridge.logp(PLATFORM_LEVEL, "MyClass_#14", "MyMethod_#14", "xyz {0}", "#14");
            MGR.checkLog(booted, "xyz #14", "MyClass_#14", "MyMethod_#14");

            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
            //          java.lang.String,java.lang.String,java.lang.Throwable)
            bridge.logp(PLATFORM_LEVEL, "MyClass_#15", "MyMethod_#15",
                    "xyz #15", new RuntimeException("throwable #15"));
            MGR.checkLog(booted, "xyz #15", "throwable #15", "MyClass_#15", "MyMethod_#15");

            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
            //          java.lang.String,java.lang.Throwable,java.util.function.Supplier)
            bridge.logp(PLATFORM_LEVEL, "MyClass_#16", "MyMethod_#16",
                    new RuntimeException("throwable #16"), () -> "xyz #16");
            MGR.checkLog(booted, "xyz #16", "throwable #16", "MyClass_#16", "MyMethod_#16");

            // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
            //          java.util.ResourceBundle,java.lang.String,java.lang.Object[])
            bridge.logrb(PLATFORM_LEVEL, "MyClass_#17", "MyMethod_#17",
                    BUNDLE, "abc {0}", "#17");
            MGR.checkLog(booted, "xyz #17", "MyClass_#17", "MyMethod_#17");

            // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
            //          java.util.ResourceBundle,java.lang.String,java.lang.Throwable)
            bridge.logrb(PLATFORM_LEVEL, "MyClass_#18", "MyMethod_#18",
                    BUNDLE, "abc #18", new RuntimeException("throwable #18"));
            MGR.checkLog(booted, "xyz #18", "throwable #18", "MyClass_#18", "MyMethod_#18");

            // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
            //          java.lang.String,java.lang.Object[])
            bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc {0}", "#19");
            MGR.checkLog(booted, "xyz #19");

            // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
            //          java.lang.String,java.lang.Throwable)
            bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc #20",
                        new RuntimeException("throwable #20"));
            MGR.checkLog(booted, "xyz #20", "throwable #20");

            /*
             * retained log content should be flushed after VM is booted.
             */
            if (!booted) {
                VM_BOOTED.getAndSet(true);
                // trigger the flush, make sure to call LOGGER.log(...)
                // after VM_BOOTED.getAndSet(true) and before MGR.assertCachedLog()
                LOGGER.log(Level.ERROR, "VM was just booted! This log should flush the cached logs.");
                MGR.assertCachedLog();
            }
        }
    }

    private static class ContentManager {
        final List<String[]> cached = new ArrayList<String[]>();
        String[] last;

        public void cache() {
            cached.add(last);
        }

        public ContentManager failLog(String... nonexistent) {
            last = nonexistent;
            for (String c : nonexistent) {
                if (ERR.drain().contains(c)) {
                    throw new RuntimeException("Content \"" + nonexistent
                            + "\" should not exist in the log!");
                }
            }
            return this;
        }

        public void assertLog(String... logs) {
            String log = ERR.drain();
            for (String str : logs) {
                if (!log.contains(str)) {
                    throw new RuntimeException("Content \"" + str + "\" does not exist in the log!");
                }
            }
        }

        public void checkLog(boolean booted, String... logs) {
            if (!booted) {
                failLog(logs).cache();
            } else {
                assertLog(logs);
            }
        }

        public void assertCachedLog() {
            String log = ERR.drain();
            for (String[] arr : cached) {
                for (String c : arr) {
                    if (!log.contains(c)) {
                        throw new RuntimeException("Content \"" + c + "\" does not exist in the log!");
                    }
                }
            }
        }
    }

    private static class MyObject {
        String str;

        public MyObject(String str) {
            this.str = str;
        }

        public String toString() {
            return str;
        }
    }

    private static class MyResources extends ResourceBundle {
        public Object handleGetObject(String key) {
            if (key.contains("abc #") || key.contains("abc {")) {
                return key.replaceAll("abc ", "xyz ");
            }
            return null;
        }

        public Enumeration<String> getKeys() {
            return null;
        }
    }
}