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