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
24import java.io.PrintStream;
25import java.lang.System.Logger;
26import java.lang.System.Logger.Level;
27import java.util.ArrayList;
28import java.util.concurrent.atomic.AtomicBoolean;
29import java.util.Enumeration;
30import java.util.List;
31import java.util.ResourceBundle;
32import java.util.Set;
33import jdk.internal.logger.BootstrapLogger;
34import jdk.internal.logger.LazyLoggers;
35
36/*
37 * @test
38 * @bug     8144460 8144214
39 * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
40 *          and logXX APIs of SimpleConsoleLogger.
41 * @modules java.base/jdk.internal.logger:+open
42 *          java.base/sun.util.logging
43 * @build BootstrapLoggerUtils LogStream
44 * @run main/othervm BootstrapLoggerAPIsTest
45 */
46
47public class BootstrapLoggerAPIsTest {
48
49    private static final LogStream ERR = new LogStream();
50
51    public static void main(String[] args) throws Exception {
52
53        final ContentManager MGR = new ContentManager();
54
55        // private reflection hook that allows us to simulate a non booted VM
56        final AtomicBoolean VM_BOOTED = new AtomicBoolean(false);
57
58        BootstrapLoggerUtils.setBootedHook(() -> VM_BOOTED.get());
59
60        // We replace System.err to check the messages that have been logged
61        // by the JUL ConsoleHandler and default SimpleConsoleLogger
62        // implementaion
63        System.setErr(new PrintStream(ERR));
64
65        VM_BOOTED.getAndSet(false);
66        if (BootstrapLogger.isBooted()) {
67            throw new RuntimeException("VM should not be booted!");
68        }
69
70        final Logger LOGGER =
71                LazyLoggers.getLogger("foo.bar", Thread.class.getModule());
72        final sun.util.logging.PlatformLogger.Level PLATFORM_LEVEL =
73                sun.util.logging.PlatformLogger.Level.SEVERE;
74        final MyResources BUNDLE = new MyResources();
75
76        /*
77         * Test logXX APIs for interface java.lang.System.Logger. Log content
78         * before VM is booted should be retained. Log content after VM was
79         * booted should be flushed instantly. VM is not booted in first round
80         * of loop, VM is booted in second round of loop.
81         */
82        for (int i = 0; i < 2; i++) {
83            boolean booted = BootstrapLogger.isBooted();
84
85            // make sure there is no [remaining] content in the LogStream.
86            MGR.failLog("xyz", "throwable #", "MyClass_#", "MyMethod_#");
87
88            /*
89             * test logXX APIs for interface java.lang.System.Logger.
90             */
91            // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
92            //          java.lang.String,java.lang.Throwable)
93            LOGGER.log(Level.ERROR, BUNDLE, "abc #0", new RuntimeException("throwable #0"));
94            MGR.checkLog(booted, "xyz #0", "throwable #0");
95
96            // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
97            //          java.lang.String,java.lang.Object[])
98            LOGGER.log(Level.ERROR, BUNDLE, "abc #1");
99            MGR.checkLog(booted, "xyz #1");
100
101            // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Object[])
102            LOGGER.log(Level.ERROR, BUNDLE, "abc {0}", "#2");
103            MGR.checkLog(booted, "xyz #2");
104
105            // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Throwable)
106            LOGGER.log(Level.ERROR, "xyz #3", new RuntimeException("throwable #3"));
107            MGR.checkLog(booted, "xyz #3", "throwable #3");
108
109            // void log(java.lang.System$Logger$Level,java.util.function.Supplier)
110            LOGGER.log(Level.ERROR, () -> "xyz #4");
111            MGR.checkLog(booted, "xyz #4");
112
113            // void log(java.lang.System$Logger$Level,java.lang.Object)
114            LOGGER.log(Level.ERROR, new MyObject("xyz #5"));
115            MGR.checkLog(booted, "xyz #5");
116
117            // void log(java.lang.System$Logger$Level,java.util.function.Supplier,
118            //          java.lang.Throwable)
119            LOGGER.log(Level.ERROR, () -> "xyz #6", new RuntimeException("throwable #6"));
120            MGR.checkLog(booted, "xyz #6", "throwable #6");
121
122
123            /*
124             * test logXX APIs for interface
125             * sun.util.logging.PlatformLogger.Bridge.
126             */
127            sun.util.logging.PlatformLogger.Bridge bridge =
128                    (sun.util.logging.PlatformLogger.Bridge) LOGGER;
129
130            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String)
131            bridge.log(PLATFORM_LEVEL, "xyz #7");
132            MGR.checkLog(booted, "xyz #7");
133
134            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Throwable)
135            bridge.log(PLATFORM_LEVEL, "xyz #8", new RuntimeException("throwable #8"));
136            MGR.checkLog(booted, "xyz #8", "throwable #8");
137
138            // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Object[])
139            bridge.log(PLATFORM_LEVEL, "xyz {0}", "#9");
140            MGR.checkLog(booted, "xyz #9");
141
142            // void log(sun.util.logging.PlatformLogger$Level,java.util.function.Supplier)
143            bridge.log(PLATFORM_LEVEL, () -> "xyz #10");
144            MGR.checkLog(booted, "xyz #10");
145
146            // void log(sun.util.logging.PlatformLogger$Level,
147            //        java.lang.Throwable,java.util.function.Supplier)
148            bridge.log(PLATFORM_LEVEL, new RuntimeException("throwable #11"), () -> "xyz #11");
149            MGR.checkLog(booted, "xyz #11", "throwable #11");
150
151            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
152            //          java.lang.String,java.lang.String)
153            bridge.logp(PLATFORM_LEVEL, "MyClass_#12", "MyMethod_#12", "xyz #12");
154            MGR.checkLog(booted, "xyz #12", "MyClass_#12", "MyMethod_#12");
155
156            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
157            //          java.lang.String,java.util.function.Supplier)
158            bridge.logp(PLATFORM_LEVEL, "MyClass_#13", "MyMethod_#13", () -> "xyz #13");
159            MGR.checkLog(booted, "xyz #13", "MyClass_#13", "MyMethod_#13");
160
161            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
162            //          java.lang.String,java.lang.String,java.lang.Object[])
163            bridge.logp(PLATFORM_LEVEL, "MyClass_#14", "MyMethod_#14", "xyz {0}", "#14");
164            MGR.checkLog(booted, "xyz #14", "MyClass_#14", "MyMethod_#14");
165
166            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
167            //          java.lang.String,java.lang.String,java.lang.Throwable)
168            bridge.logp(PLATFORM_LEVEL, "MyClass_#15", "MyMethod_#15",
169                    "xyz #15", new RuntimeException("throwable #15"));
170            MGR.checkLog(booted, "xyz #15", "throwable #15", "MyClass_#15", "MyMethod_#15");
171
172            // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
173            //          java.lang.String,java.lang.Throwable,java.util.function.Supplier)
174            bridge.logp(PLATFORM_LEVEL, "MyClass_#16", "MyMethod_#16",
175                    new RuntimeException("throwable #16"), () -> "xyz #16");
176            MGR.checkLog(booted, "xyz #16", "throwable #16", "MyClass_#16", "MyMethod_#16");
177
178            // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
179            //          java.util.ResourceBundle,java.lang.String,java.lang.Object[])
180            bridge.logrb(PLATFORM_LEVEL, "MyClass_#17", "MyMethod_#17",
181                    BUNDLE, "abc {0}", "#17");
182            MGR.checkLog(booted, "xyz #17", "MyClass_#17", "MyMethod_#17");
183
184            // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
185            //          java.util.ResourceBundle,java.lang.String,java.lang.Throwable)
186            bridge.logrb(PLATFORM_LEVEL, "MyClass_#18", "MyMethod_#18",
187                    BUNDLE, "abc #18", new RuntimeException("throwable #18"));
188            MGR.checkLog(booted, "xyz #18", "throwable #18", "MyClass_#18", "MyMethod_#18");
189
190            // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
191            //          java.lang.String,java.lang.Object[])
192            bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc {0}", "#19");
193            MGR.checkLog(booted, "xyz #19");
194
195            // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
196            //          java.lang.String,java.lang.Throwable)
197            bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc #20",
198                        new RuntimeException("throwable #20"));
199            MGR.checkLog(booted, "xyz #20", "throwable #20");
200
201            /*
202             * retained log content should be flushed after VM is booted.
203             */
204            if (!booted) {
205                VM_BOOTED.getAndSet(true);
206                // trigger the flush, make sure to call LOGGER.log(...)
207                // after VM_BOOTED.getAndSet(true) and before MGR.assertCachedLog()
208                LOGGER.log(Level.ERROR, "VM was just booted! This log should flush the cached logs.");
209                MGR.assertCachedLog();
210            }
211        }
212    }
213
214    private static class ContentManager {
215        final List<String[]> cached = new ArrayList<String[]>();
216        String[] last;
217
218        public void cache() {
219            cached.add(last);
220        }
221
222        public ContentManager failLog(String... nonexistent) {
223            last = nonexistent;
224            for (String c : nonexistent) {
225                if (ERR.drain().contains(c)) {
226                    throw new RuntimeException("Content \"" + nonexistent
227                            + "\" should not exist in the log!");
228                }
229            }
230            return this;
231        }
232
233        public void assertLog(String... logs) {
234            String log = ERR.drain();
235            for (String str : logs) {
236                if (!log.contains(str)) {
237                    throw new RuntimeException("Content \"" + str + "\" does not exist in the log!");
238                }
239            }
240        }
241
242        public void checkLog(boolean booted, String... logs) {
243            if (!booted) {
244                failLog(logs).cache();
245            } else {
246                assertLog(logs);
247            }
248        }
249
250        public void assertCachedLog() {
251            String log = ERR.drain();
252            for (String[] arr : cached) {
253                for (String c : arr) {
254                    if (!log.contains(c)) {
255                        throw new RuntimeException("Content \"" + c + "\" does not exist in the log!");
256                    }
257                }
258            }
259        }
260    }
261
262    private static class MyObject {
263        String str;
264
265        public MyObject(String str) {
266            this.str = str;
267        }
268
269        public String toString() {
270            return str;
271        }
272    }
273
274    private static class MyResources extends ResourceBundle {
275        public Object handleGetObject(String key) {
276            if (key.contains("abc #") || key.contains("abc {")) {
277                return key.replaceAll("abc ", "xyz ");
278            }
279            return null;
280        }
281
282        public Enumeration<String> getKeys() {
283            return null;
284        }
285    }
286}
287