blob: a7b7e43dca6615e8c7d6af0ad058e2fe92cb2f04 [file] [log] [blame]
/*
* Copyright (c) 2015, 2016, 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 static java.lang.StackWalker.Option.*;
import java.lang.StackWalker.StackFrame;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* @test
* @bug 8140450
* @summary Stack Stream Test
* @modules java.logging
* @run main/othervm StackStreamTest
*/
public class StackStreamTest {
public static void main(String[] argv) throws Exception {
new StackStreamTest().test();
}
private static Logger logger = Logger.getLogger("stackstream");
public StackStreamTest() {
}
public void test() {
A.a();
}
static class A {
public static void a() {
B.b();
}
}
static class B {
public static void b() {
C.c();
}
}
static class C {
public static void c() {
D.d();
}
}
static class D {
public static void d() {
E.e();
}
}
static class E {
public static void e() {
F.f();
}
}
static class F {
public static void f() {
logger.severe("log message");
G.g();
new K().k();
}
}
private static boolean isTestClass(StackFrame f) {
// Filter jtreg frames from the end of the stack
return f.getClassName().startsWith("StackStreamTest");
}
static class G {
static StackWalker STE_WALKER = StackWalker.getInstance();
static StackWalker DEFAULT_WALKER = StackWalker.getInstance();
private static final List<String> GOLDEN_CLASS_NAMES =
Arrays.asList("StackStreamTest$G",
"StackStreamTest$F",
"StackStreamTest$E",
"StackStreamTest$D",
"StackStreamTest$C",
"StackStreamTest$B",
"StackStreamTest$A",
"StackStreamTest",
"StackStreamTest");
private static final List<String> GOLDEN_METHOD_NAMES =
Arrays.asList("g", "f", "e", "d", "c", "b", "a", "test", "main");
public static void g() {
System.out.println("Thread dump");
Thread.dumpStack();
caller();
firstFrame();
// Check class names
System.out.println("check class names");
List<String> sfs = DEFAULT_WALKER.walk(s -> {
return s.filter(StackStreamTest::isTestClass)
.map(StackFrame::getClassName)
.collect(Collectors.toList());
});
equalsOrThrow("class names", sfs, GOLDEN_CLASS_NAMES);
// Check method names
System.out.println("methodNames()");
sfs = DEFAULT_WALKER.walk(s -> {
return s.filter(StackStreamTest::isTestClass)
.map(StackFrame::getMethodName)
.collect(Collectors.toList());}
);
equalsOrThrow("method names", sfs, GOLDEN_METHOD_NAMES);
Exception exc = new Exception("G.g stack");
exc.printStackTrace();
System.out.println("Stream of StackTraceElement");
StackWalker.getInstance()
.walk(s ->
{
s.map(StackFrame::toStackTraceElement)
.forEach(ste -> System.out.println("STE: " + ste));
return null;
});
// Do we need this?
System.out.println("Collect StackTraceElement");
List<StackTraceElement> stacktrace = STE_WALKER.walk(s ->
{
// Filter out jtreg frames
return s.filter(StackStreamTest::isTestClass)
.collect(Collectors.mapping(StackFrame::toStackTraceElement, Collectors.toList()));
});
int i=0;
for (StackTraceElement s : stacktrace) {
System.out.format(" %d: %s%n", i++, s);
}
// Check STEs for correctness
checkStackTraceElements(GOLDEN_CLASS_NAMES, GOLDEN_METHOD_NAMES, stacktrace);
}
static void checkStackTraceElements(List<String> classNames,
List<String> methodNames,
List<StackTraceElement> stes) {
if (classNames.size() != methodNames.size() ) {
throw new RuntimeException("Test error: classNames and methodNames should be same size");
}
if (classNames.size() != stes.size()) {
dumpSTEInfo(classNames, methodNames, stes);
throw new RuntimeException("wrong number of elements in stes");
}
for (int i = 0; i < classNames.size() ; i++) {
if (!classNames.get(i).equals(stes.get(i).getClassName()) ||
!methodNames.get(i).equals(stes.get(i).getMethodName())) {
dumpSTEInfo(classNames, methodNames, stes);
throw new RuntimeException("class & method names don't match");
}
}
}
static void dumpSTEInfo(List<String> classNames, List<String> methodNames,
List<StackTraceElement> stes) {
System.out.println("Observed class, method names:");
for (StackTraceElement ste : stes) {
System.out.println(" " + ste.getClassName() + ", " + ste.getMethodName());
}
System.out.println("Expected class, method names:");
for (int i = 0; i < classNames.size(); i++) {
System.out.println(" " + classNames.get(i) + ", " + methodNames.get(i));
}
}
static void firstFrame() {
System.out.println("first frame()");
StackWalker sw = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
sw.forEach(e -> {
System.out.println(e.getClassName() + "," + e.getMethodName());
});
System.out.println("\n");
Optional<StackFrame> frame = sw.walk(s ->
{
return s.filter(e -> {
System.err.println(e.getClassName() + " == " +
e.getClassName().equals("StackStreamTest"));
return e.getClassName().equals("StackStreamTest");
}).findFirst();
});
Class<?> c = frame.get().getDeclaringClass();
System.out.println("\nfirst frame: " + c);
if (c != StackStreamTest.class) {
throw new RuntimeException("Unexpected first caller class " + c);
}
}
}
private static <T> void equalsOrThrow(String label, List<T> list, List<T> expected) {
System.out.println("List: " + list);
System.out.println("Expectd: " + list);
if (!list.equals(expected)) {
System.err.println("Observed " + label);
for (T s1 : list) {
System.out.println(" " + s1);
}
System.err.println("Expected " + label);
for (T s2 : expected) {
System.out.println(" " + s2);
}
throw new RuntimeException("Error with " + label);
}
}
static class K {
void k() {
k1();
}
void k1() {
k2();
}
void k2() {
k3();
}
void k3() {
k4();
}
void k4() {
k5();
}
void k5() {
k6();
}
void k6() {
k7();
}
void k7() {
k8();
}
void k8() {
k9();
}
void k9() {
k10();
}
void k10() {
k20();
}
void k20() {
new Caller().test();
}
class Caller {
void test() {
Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass();
System.out.println("\nTesting K class : " + c);
Thread.dumpStack();
if (c != K.class) {
throw new RuntimeException("Unexpected caller class "+ c);
}
}
}
}
static void caller() {
Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass();
System.out.println("\ncaller class : " + c);
if (c != G.class) {
throw new RuntimeException("Unexpected caller class "+ c);
}
}
}