1/* 2 * Copyright (c) 2015, 2016, 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 static java.lang.StackWalker.Option.*; 25import java.lang.StackWalker.StackFrame; 26import java.util.Arrays; 27import java.util.List; 28import java.util.Optional; 29import java.util.logging.Logger; 30import java.util.stream.Collectors; 31 32/** 33 * @test 34 * @bug 8140450 35 * @summary Stack Stream Test 36 * @modules java.logging 37 * @run main/othervm StackStreamTest 38 */ 39public class StackStreamTest { 40 public static void main(String[] argv) throws Exception { 41 new StackStreamTest().test(); 42 } 43 44 private static Logger logger = Logger.getLogger("stackstream"); 45 public StackStreamTest() { 46 } 47 48 public void test() { 49 A.a(); 50 } 51 static class A { 52 public static void a() { 53 B.b(); 54 } 55 } 56 static class B { 57 public static void b() { 58 C.c(); 59 } 60 } 61 static class C { 62 public static void c() { 63 D.d(); 64 } 65 } 66 static class D { 67 public static void d() { 68 E.e(); 69 } 70 } 71 static class E { 72 public static void e() { 73 F.f(); 74 } 75 } 76 static class F { 77 public static void f() { 78 logger.severe("log message"); 79 G.g(); 80 new K().k(); 81 } 82 } 83 84 private static boolean isTestClass(StackFrame f) { 85 // Filter jtreg frames from the end of the stack 86 return f.getClassName().startsWith("StackStreamTest"); 87 } 88 89 static class G { 90 static StackWalker STE_WALKER = StackWalker.getInstance(); 91 static StackWalker DEFAULT_WALKER = StackWalker.getInstance(); 92 93 private static final List<String> GOLDEN_CLASS_NAMES = 94 Arrays.asList("StackStreamTest$G", 95 "StackStreamTest$F", 96 "StackStreamTest$E", 97 "StackStreamTest$D", 98 "StackStreamTest$C", 99 "StackStreamTest$B", 100 "StackStreamTest$A", 101 "StackStreamTest", 102 "StackStreamTest"); 103 private static final List<String> GOLDEN_METHOD_NAMES = 104 Arrays.asList("g", "f", "e", "d", "c", "b", "a", "test", "main"); 105 106 107 public static void g() { 108 109 System.out.println("Thread dump"); 110 Thread.dumpStack(); 111 112 caller(); 113 firstFrame(); 114 115 // Check class names 116 System.out.println("check class names"); 117 List<String> sfs = DEFAULT_WALKER.walk(s -> { 118 return s.filter(StackStreamTest::isTestClass) 119 .map(StackFrame::getClassName) 120 .collect(Collectors.toList()); 121 }); 122 equalsOrThrow("class names", sfs, GOLDEN_CLASS_NAMES); 123 124 // Check method names 125 System.out.println("methodNames()"); 126 sfs = DEFAULT_WALKER.walk(s -> { 127 return s.filter(StackStreamTest::isTestClass) 128 .map(StackFrame::getMethodName) 129 .collect(Collectors.toList());} 130 ); 131 equalsOrThrow("method names", sfs, GOLDEN_METHOD_NAMES); 132 133 Exception exc = new Exception("G.g stack"); 134 exc.printStackTrace(); 135 136 System.out.println("Stream of StackTraceElement"); 137 StackWalker.getInstance() 138 .walk(s -> 139 { 140 s.map(StackFrame::toStackTraceElement) 141 .forEach(ste -> System.out.println("STE: " + ste)); 142 return null; 143 }); 144 145 // Do we need this? 146 System.out.println("Collect StackTraceElement"); 147 List<StackTraceElement> stacktrace = STE_WALKER.walk(s -> 148 { 149 // Filter out jtreg frames 150 return s.filter(StackStreamTest::isTestClass) 151 .collect(Collectors.mapping(StackFrame::toStackTraceElement, Collectors.toList())); 152 }); 153 int i=0; 154 for (StackTraceElement s : stacktrace) { 155 System.out.format(" %d: %s%n", i++, s); 156 } 157 158 // Check STEs for correctness 159 checkStackTraceElements(GOLDEN_CLASS_NAMES, GOLDEN_METHOD_NAMES, stacktrace); 160 } 161 162 static void checkStackTraceElements(List<String> classNames, 163 List<String> methodNames, 164 List<StackTraceElement> stes) { 165 if (classNames.size() != methodNames.size() ) { 166 throw new RuntimeException("Test error: classNames and methodNames should be same size"); 167 } 168 if (classNames.size() != stes.size()) { 169 dumpSTEInfo(classNames, methodNames, stes); 170 throw new RuntimeException("wrong number of elements in stes"); 171 } 172 for (int i = 0; i < classNames.size() ; i++) { 173 if (!classNames.get(i).equals(stes.get(i).getClassName()) || 174 !methodNames.get(i).equals(stes.get(i).getMethodName())) { 175 dumpSTEInfo(classNames, methodNames, stes); 176 throw new RuntimeException("class & method names don't match"); 177 } 178 } 179 } 180 181 static void dumpSTEInfo(List<String> classNames, List<String> methodNames, 182 List<StackTraceElement> stes) { 183 System.out.println("Observed class, method names:"); 184 for (StackTraceElement ste : stes) { 185 System.out.println(" " + ste.getClassName() + ", " + ste.getMethodName()); 186 } 187 System.out.println("Expected class, method names:"); 188 for (int i = 0; i < classNames.size(); i++) { 189 System.out.println(" " + classNames.get(i) + ", " + methodNames.get(i)); 190 } 191 } 192 193 static void firstFrame() { 194 System.out.println("first frame()"); 195 StackWalker sw = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 196 sw.forEach(e -> { 197 System.out.println(e.getClassName() + "," + e.getMethodName()); 198 }); 199 System.out.println("\n"); 200 Optional<StackFrame> frame = sw.walk(s -> 201 { 202 return s.filter(e -> { 203 System.err.println(e.getClassName() + " == " + 204 e.getClassName().equals("StackStreamTest")); 205 return e.getClassName().equals("StackStreamTest"); 206 }).findFirst(); 207 }); 208 Class<?> c = frame.get().getDeclaringClass(); 209 System.out.println("\nfirst frame: " + c); 210 if (c != StackStreamTest.class) { 211 throw new RuntimeException("Unexpected first caller class " + c); 212 } 213 } 214 } 215 216 private static <T> void equalsOrThrow(String label, List<T> list, List<T> expected) { 217 System.out.println("List: " + list); 218 System.out.println("Expectd: " + list); 219 if (!list.equals(expected)) { 220 System.err.println("Observed " + label); 221 for (T s1 : list) { 222 System.out.println(" " + s1); 223 } 224 System.err.println("Expected " + label); 225 for (T s2 : expected) { 226 System.out.println(" " + s2); 227 } 228 throw new RuntimeException("Error with " + label); 229 } 230 } 231 232 233 static class K { 234 void k() { 235 k1(); 236 } 237 void k1() { 238 k2(); 239 } 240 void k2() { 241 k3(); 242 } 243 void k3() { 244 k4(); 245 } 246 void k4() { 247 k5(); 248 } 249 void k5() { 250 k6(); 251 } 252 void k6() { 253 k7(); 254 } 255 void k7() { 256 k8(); 257 } 258 void k8() { 259 k9(); 260 } 261 void k9() { 262 k10(); 263 } 264 void k10() { 265 k20(); 266 } 267 void k20() { 268 new Caller().test(); 269 } 270 271 class Caller { 272 void test() { 273 Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); 274 System.out.println("\nTesting K class : " + c); 275 Thread.dumpStack(); 276 if (c != K.class) { 277 throw new RuntimeException("Unexpected caller class "+ c); 278 } 279 } 280 } 281 } 282 283 static void caller() { 284 Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); 285 System.out.println("\ncaller class : " + c); 286 if (c != G.class) { 287 throw new RuntimeException("Unexpected caller class "+ c); 288 } 289 } 290 291} 292