8315220: Event NativeLibraryLoad breaks invariant by taking a stacktrace when thread is in state _thread_in_native

Reviewed-by: mbaesken, egahlin
This commit is contained in:
Markus Grönlund 2023-09-07 16:12:55 +00:00
parent 8f7e29b2cd
commit 1cae0f53a9
10 changed files with 281 additions and 152 deletions

View File

@ -81,7 +81,7 @@
#include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#endif
// put OS-includes here (sorted alphabetically)
@ -1116,11 +1116,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
return nullptr;
}
#if INCLUDE_JFR
EventNativeLibraryLoad event;
event.set_name(filename);
#endif
// RTLD_LAZY has currently the same behavior as RTLD_NOW
// The dl is loaded immediately with all its dependants.
int dflags = RTLD_LAZY;
@ -1131,19 +1126,14 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
dflags |= RTLD_MEMBER;
}
void * result= ::dlopen(filename, dflags);
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
result = ::dlopen(filename, dflags);
if (result != nullptr) {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
// Reload dll cache. Don't do this in signal handling.
LoadedLibraries::reload();
log_info(os)("shared library load of %s was successful", filename);
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
return result;
} else {
// error analysis when dlopen fails
@ -1157,12 +1147,7 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
log_info(os)("shared library load of %s failed, %s", filename, error_report);
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(error_report);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(error_report);)
}
return nullptr;
}

View File

@ -71,6 +71,7 @@
#include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#endif
// put OS-includes here
@ -979,21 +980,13 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
#else
log_info(os)("attempting shared library load of %s", filename);
#if INCLUDE_JFR
EventNativeLibraryLoad event;
event.set_name(filename);
#endif
void * result= ::dlopen(filename, RTLD_LAZY);
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
result = ::dlopen(filename, RTLD_LAZY);
if (result != nullptr) {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
// Successful loading
log_info(os)("shared library load of %s was successful", filename);
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
return result;
}
@ -1008,11 +1001,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
log_info(os)("shared library load of %s failed, %s", filename, error_report);
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(error_report);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(error_report);)
return nullptr;
#endif // STATIC_BUILD
@ -1024,21 +1013,13 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
#else
log_info(os)("attempting shared library load of %s", filename);
#if INCLUDE_JFR
EventNativeLibraryLoad event;
event.set_name(filename);
#endif
void * result= ::dlopen(filename, RTLD_LAZY);
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
result = ::dlopen(filename, RTLD_LAZY);
if (result != nullptr) {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
// Successful loading
log_info(os)("shared library load of %s was successful", filename);
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
return result;
}
@ -1055,11 +1036,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
log_info(os)("shared library load of %s failed, %s", filename, error_report);
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(error_report);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(error_report);)
int diag_msg_max_length=ebuflen-strlen(ebuf);
char* diag_msg_buf=ebuf+strlen(ebuf);

View File

@ -82,6 +82,7 @@
#include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#endif
// put OS-includes here
@ -1794,15 +1795,10 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
return nullptr;
}
void * os::Linux::dlopen_helper(const char *filename, char *ebuf,
int ebuflen) {
void * result = ::dlopen(filename, RTLD_LAZY);
#if INCLUDE_JFR
EventNativeLibraryLoad event;
event.set_name(filename);
#endif
void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
result = ::dlopen(filename, RTLD_LAZY);
if (result == nullptr) {
const char* error_report = ::dlerror();
if (error_report == nullptr) {
@ -1814,19 +1810,10 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf,
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
log_info(os)("shared library load of %s failed, %s", filename, error_report);
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(error_report);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(error_report);)
} else {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
log_info(os)("shared library load of %s was successful", filename);
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
}
return result;
}

View File

@ -51,7 +51,7 @@
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#endif
#ifdef AIX
@ -728,10 +728,7 @@ void os::dll_unload(void *lib) {
}
#endif // LINUX
#if INCLUDE_JFR
EventNativeLibraryUnload event;
event.set_name(l_path);
#endif
JFR_ONLY(NativeLibraryUnloadEvent unload_event(l_path);)
if (l_path == nullptr) {
l_path = "<not available>";
@ -742,11 +739,7 @@ void os::dll_unload(void *lib) {
Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]",
l_path, p2i(lib));
log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib));
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
JFR_ONLY(unload_event.set_result(true);)
} else {
const char* error_report = ::dlerror();
if (error_report == nullptr) {
@ -757,11 +750,7 @@ void os::dll_unload(void *lib) {
l_path, p2i(lib), error_report);
log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s",
l_path, p2i(lib), error_report);
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(error_report);
event.commit();
#endif
JFR_ONLY(unload_event.set_error_msg(error_report);)
}
// Update the dll cache
AIX_ONLY(LoadedLibraries::reload());

View File

@ -80,6 +80,7 @@
#include "windbghelp.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#endif
#ifdef _DEBUG
@ -1246,33 +1247,22 @@ void os::dll_unload(void *lib) {
snprintf(name, MAX_PATH, "<not available>");
}
#if INCLUDE_JFR
EventNativeLibraryUnload event;
event.set_name(name);
#endif
JFR_ONLY(NativeLibraryUnloadEvent unload_event(name);)
if (::FreeLibrary((HMODULE)lib)) {
Events::log_dll_message(nullptr, "Unloaded dll \"%s\" [" INTPTR_FORMAT "]", name, p2i(lib));
log_info(os)("Unloaded dll \"%s\" [" INTPTR_FORMAT "]", name, p2i(lib));
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
JFR_ONLY(unload_event.set_result(true);)
} else {
const DWORD errcode = ::GetLastError();
char buf[500];
size_t tl = os::lasterror(buf, sizeof(buf));
Events::log_dll_message(nullptr, "Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode);
log_info(os)("Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode);
#if INCLUDE_JFR
event.set_success(false);
if (tl == 0) {
os::snprintf(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode);
}
event.set_errorMessage(buf);
event.commit();
#endif
JFR_ONLY(unload_event.set_error_msg(buf);)
}
}
@ -1541,21 +1531,14 @@ static int _print_module(const char* fname, address base_address,
// same architecture as Hotspot is running on
void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
log_info(os)("attempting shared library load of %s", name);
#if INCLUDE_JFR
EventNativeLibraryLoad event;
event.set_name(name);
#endif
void * result = LoadLibrary(name);
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(name, &result);)
result = LoadLibrary(name);
if (result != nullptr) {
Events::log_dll_message(nullptr, "Loaded shared library %s", name);
// Recalculate pdb search path if a DLL was loaded successfully.
SymbolEngine::recalc_search_path();
log_info(os)("shared library load of %s was successful", name);
#if INCLUDE_JFR
event.set_success(true);
event.set_errorMessage(nullptr);
event.commit();
#endif
return result;
}
DWORD errcode = GetLastError();
@ -1569,11 +1552,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
if (errcode == ERROR_MOD_NOT_FOUND) {
strncpy(ebuf, "Can't find dependent libraries", ebuflen - 1);
ebuf[ebuflen - 1] = '\0';
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(ebuf);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(ebuf);)
return nullptr;
}
@ -1584,11 +1563,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
// else call os::lasterror to obtain system error message
int fd = ::open(name, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage("open on dll file did not work");
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg("open on dll file did not work");)
return nullptr;
}
@ -1615,11 +1590,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
::close(fd);
if (failed_to_get_lib_arch) {
// file i/o error - report os::lasterror(...) msg
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage("failed to get lib architecture");
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg("failed to get lib architecture");)
return nullptr;
}
@ -1664,11 +1635,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
// If the architecture is right
// but some other error took place - report os::lasterror(...) msg
if (lib_arch == running_arch) {
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage("lib architecture matches, but other error occured");
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg("lib architecture matches, but other error occured");)
return nullptr;
}
@ -1682,12 +1649,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
"Can't load this .dll (machine code=0x%x) on a %s-bit platform",
lib_arch, running_arch_str);
}
#if INCLUDE_JFR
event.set_success(false);
event.set_errorMessage(ebuf);
event.commit();
#endif
JFR_ONLY(load_event.set_error_msg(ebuf);)
return nullptr;
}

View File

@ -939,14 +939,14 @@
<Field type="ulong" contentType="address" name="topAddress" label="Top Address" description="Ending address of the module, if available" />
</Event>
<Event name="NativeLibraryLoad" category="Java Virtual Machine, Runtime" label="Native Library Load" thread="false" stackTrace="true" startTime="true"
<Event name="NativeLibraryLoad" category="Java Virtual Machine, Runtime" label="Native Library Load" thread="true" stackTrace="true" startTime="true"
description="Information about a dynamic library or other native image load operation">
<Field type="string" name="name" label="Name" />
<Field type="boolean" name="success" label="Success" description="Success or failure of the load operation" />
<Field type="string" name="errorMessage" label="Error Message" description="In case of a load error, error description" />
</Event>
<Event name="NativeLibraryUnload" category="Java Virtual Machine, Runtime" label="Native Library Unload" thread="false" stackTrace="true" startTime="true"
<Event name="NativeLibraryUnload" category="Java Virtual Machine, Runtime" label="Native Library Unload" thread="true" stackTrace="true" startTime="true"
description="Information about a dynamic library or other native image unload operation">
<Field type="string" name="name" label="Name" />
<Field type="boolean" name="success" label="Success" description="Success or failure of the unload operation" />

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2023, 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.
*
*/
#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/thread.inline.hpp"
JfrNativeLibraryEventBase::JfrNativeLibraryEventBase(const char* name) : _name(name), _error_msg(nullptr), _start_time(nullptr) {}
JfrNativeLibraryEventBase::~JfrNativeLibraryEventBase() {
delete _start_time;
}
const char* JfrNativeLibraryEventBase::name() const {
return _name;
}
JfrTicksWrapper* JfrNativeLibraryEventBase::start_time() const {
return _start_time;
}
bool JfrNativeLibraryEventBase::has_start_time() const {
return _start_time != nullptr;
}
const char* JfrNativeLibraryEventBase::error_msg() const {
return _error_msg;
}
void JfrNativeLibraryEventBase::set_error_msg(const char* error_msg) {
assert(_error_msg == nullptr, "invariant");
_error_msg = error_msg;
}
/*
* The JfrTicks value is heap allocated inside an object of type JfrTicksWrapper.
* The reason is that a raw value object of type Ticks is not possible at this
* location because this code runs as part of early VM bootstrap, at a moment
* where Ticks support is not yet initialized.
*/
template <typename EventType>
static inline JfrTicksWrapper* allocate_start_time() {
return EventType::is_enabled() ? new JfrTicksWrapper() : nullptr;
}
NativeLibraryLoadEvent::NativeLibraryLoadEvent(const char* name, void** result) : JfrNativeLibraryEventBase(name), _result(result) {
assert(_result != nullptr, "invariant");
_start_time = allocate_start_time<EventNativeLibraryLoad>();
}
bool NativeLibraryLoadEvent::success() const {
return *_result != nullptr;
}
NativeLibraryUnloadEvent::NativeLibraryUnloadEvent(const char* name) : JfrNativeLibraryEventBase(name), _result(false) {
_start_time = allocate_start_time<EventNativeLibraryUnload>();
}
bool NativeLibraryUnloadEvent::success() const {
return _result;
}
void NativeLibraryUnloadEvent::set_result(bool result) {
_result = result;
}
template <typename EventType, typename HelperType>
static void commit(HelperType& helper) {
if (!helper.has_start_time()) {
return;
}
EventType event(UNTIMED);
event.set_endtime(JfrTicks::now());
event.set_starttime(*helper.start_time());
event.set_name(helper.name());
event.set_errorMessage(helper.error_msg());
event.set_success(helper.success());
Thread* thread = Thread::current();
assert(thread != nullptr, "invariant");
if (thread->is_Java_thread()) {
JavaThread* jt = JavaThread::cast(thread);
if (jt->thread_state() != _thread_in_vm) {
assert(jt->thread_state() == _thread_in_native, "invariant");
// For a JavaThread to take a JFR stacktrace, it must be in _thread_in_vm. Can safepoint here.
ThreadInVMfromNative transition(jt);
event.commit();
return;
}
}
event.commit();
}
NativeLibraryLoadEvent::~NativeLibraryLoadEvent() {
commit<EventNativeLibraryLoad>(*this);
}
NativeLibraryUnloadEvent::~NativeLibraryUnloadEvent() {
commit<EventNativeLibraryUnload>(*this);
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, 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.
*
*/
#ifndef SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP
#define SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP
#include "memory/allocation.hpp"
class JfrTicksWrapper;
/*
* Helper types for populating NativeLibrary events.
* Event commit is run as part of destructors.
*/
class JfrNativeLibraryEventBase : public StackObj {
protected:
const char* _name;
const char* _error_msg;
JfrTicksWrapper* _start_time;
JfrNativeLibraryEventBase(const char* name);
~JfrNativeLibraryEventBase();
public:
const char* name() const;
const char* error_msg() const;
void set_error_msg(const char* error_msg);
JfrTicksWrapper* start_time() const;
bool has_start_time() const;
};
class NativeLibraryLoadEvent : public JfrNativeLibraryEventBase {
private:
void** _result;
public:
NativeLibraryLoadEvent(const char* name, void** result);
~NativeLibraryLoadEvent();
bool success() const;
};
class NativeLibraryUnloadEvent : public JfrNativeLibraryEventBase {
private:
bool _result;
public:
NativeLibraryUnloadEvent(const char* name);
~NativeLibraryUnloadEvent();
bool success() const;
void set_result(bool result);
};
#endif // SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023, 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
@ -25,6 +25,7 @@
#ifndef SHARE_JFR_UTILITIES_JFRTIME_HPP
#define SHARE_JFR_UTILITIES_JFRTIME_HPP
#include "jfr/utilities/jfrAllocation.hpp"
#include "utilities/ticks.hpp"
typedef TimeInstant<CounterRepresentation, FastUnorderedElapsedCounterSource> JfrTicks;
@ -41,4 +42,13 @@ class JfrTime {
static const void* time_function();
};
// For dynamically allocated Ticks values.
class JfrTicksWrapper : public JfrCHeapObj {
private:
JfrTicks _ticks;
public:
JfrTicksWrapper() : _ticks(JfrTicks::now()) {}
operator JfrTicks() const { return _ticks; }
};
#endif // SHARE_JFR_UTILITIES_JFRTIME_HPP

View File

@ -23,14 +23,15 @@
package jdk.jfr.event.runtime;
import static jdk.test.lib.Asserts.assertNotNull;
import static jdk.test.lib.Asserts.assertNull;
import static jdk.test.lib.Asserts.assertTrue;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordedMethod;
import jdk.jfr.consumer.RecordedStackTrace;
import jdk.test.lib.Platform;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;
@ -46,25 +47,49 @@ import jdk.test.lib.jfr.Events;
public class TestNativeLibraryLoadEvent {
private final static String EVENT_NAME = EventNames.NativeLibraryLoad;
private final static String LOAD_CLASS_NAME = "java.lang.System";
private final static String LOAD_METHOD_NAME = "loadLibrary";
private final static String LIBRARY = "instrument";
private final static String PLATFORM_LIBRARY_NAME = Platform.buildSharedLibraryName(LIBRARY);
public static void main(String[] args) throws Throwable {
try (Recording recording = new Recording()) {
recording.enable(EVENT_NAME);
recording.start();
System.loadLibrary("instrument");
System.loadLibrary(LIBRARY);
recording.stop();
String expectedLib = Platform.buildSharedLibraryName("instrument");
boolean expectedLibFound = false;
for (RecordedEvent event : Events.fromRecording(recording)) {
System.out.println("Event:" + event);
String lib = Events.assertField(event, "name").notEmpty().getValue();
Events.assertField(event, "success");
if (lib.contains(expectedLib)) {
expectedLibFound = true;
if (validate(event)) {
return;
}
}
assertTrue(expectedLibFound, "Missing library " + expectedLib);
assertTrue(false, "Missing library " + PLATFORM_LIBRARY_NAME);
}
}
private static boolean validate(RecordedEvent event) {
assertTrue(event.getEventType().getName().equals(EVENT_NAME));
String lib = Events.assertField(event, "name").notEmpty().getValue();
System.out.println(lib);
if (!lib.endsWith(PLATFORM_LIBRARY_NAME)) {
return false;
}
assertTrue(Events.assertField(event, "success").getValue());
assertNull(Events.assertField(event, "errorMessage").getValue());
RecordedStackTrace stacktrace = event.getStackTrace();
assertNotNull(stacktrace);
for (RecordedFrame f : stacktrace.getFrames()) {
if (match(f.getMethod())) {
return true;
}
}
return false;
}
private static boolean match(RecordedMethod method) {
assertNotNull(method);
System.out.println(method.getType().getName() + "." + method.getName());
return method.getName().equals(LOAD_METHOD_NAME) && method.getType().getName().equals(LOAD_CLASS_NAME);
}
}