Merge
This commit is contained in:
commit
3d2138fde0
@ -31,12 +31,12 @@
|
||||
#include "prims/jvmtiEnvBase.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
|
||||
static ClassFileStream* prologue(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
JvmtiCachedClassFileData** cached_class_file,
|
||||
TRAPS) {
|
||||
static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
JvmtiCachedClassFileData** cached_class_file,
|
||||
TRAPS) {
|
||||
|
||||
assert(stream != NULL, "invariant");
|
||||
|
||||
@ -102,8 +102,6 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
assert(loader_data != NULL, "invariant");
|
||||
assert(THREAD->is_Java_thread(), "must be a JavaThread");
|
||||
|
||||
bool changed_by_loadhook = false;
|
||||
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
|
||||
@ -111,12 +109,15 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
|
||||
ClassFileStream* old_stream = stream;
|
||||
|
||||
stream = prologue(stream,
|
||||
name,
|
||||
loader_data,
|
||||
protection_domain,
|
||||
&cached_class_file,
|
||||
CHECK_NULL);
|
||||
// Skip this processing for VM anonymous classes
|
||||
if (host_klass == NULL) {
|
||||
stream = check_class_file_load_hook(stream,
|
||||
name,
|
||||
loader_data,
|
||||
protection_domain,
|
||||
&cached_class_file,
|
||||
CHECK_NULL);
|
||||
}
|
||||
|
||||
ClassFileParser parser(stream,
|
||||
name,
|
||||
|
@ -53,10 +53,6 @@ class LogDecorations VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators);
|
||||
|
||||
LogLevelType level() const {
|
||||
return _level;
|
||||
}
|
||||
|
||||
void set_level(LogLevelType level) {
|
||||
_level = level;
|
||||
}
|
||||
|
@ -60,6 +60,11 @@ class LogOutputList VALUE_OBJ_CLASS_SPEC {
|
||||
void add_output(LogOutput* output, LogLevelType level);
|
||||
void update_output_level(LogOutputNode* node, LogLevelType level);
|
||||
|
||||
// Bookkeeping functions to keep track of number of active readers/iterators for the list.
|
||||
jint increase_readers();
|
||||
jint decrease_readers();
|
||||
void wait_until_no_readers() const;
|
||||
|
||||
public:
|
||||
LogOutputList() : _active_readers(0) {
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
@ -83,11 +88,6 @@ class LogOutputList VALUE_OBJ_CLASS_SPEC {
|
||||
// Set (add/update/remove) the output to the specified level.
|
||||
void set_output_level(LogOutput* output, LogLevelType level);
|
||||
|
||||
// Bookkeeping functions to keep track of number of active readers/iterators for the list.
|
||||
jint increase_readers();
|
||||
jint decrease_readers();
|
||||
void wait_until_no_readers() const;
|
||||
|
||||
class Iterator VALUE_OBJ_CLASS_SPEC {
|
||||
friend class LogOutputList;
|
||||
private:
|
||||
|
@ -21,6 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.management.GarbageCollectorMXBean;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -28,6 +29,8 @@ import jdk.test.lib.ByteCodeLoader;
|
||||
import jdk.test.lib.InMemoryJavaCompiler;
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
|
||||
import static jdk.test.lib.Asserts.*;
|
||||
|
||||
/* @test TestMetaspacePerfCounters
|
||||
@ -38,7 +41,7 @@ import static jdk.test.lib.Asserts.*;
|
||||
* space exists and works.
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
* java.management/sun.management
|
||||
* jdk.jvmstat/sun.jvmstat.monitor
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters
|
||||
@ -51,6 +54,7 @@ import static jdk.test.lib.Asserts.*;
|
||||
public class TestMetaspacePerfCounters {
|
||||
public static Class fooClass = null;
|
||||
private static final String[] counterNames = {"minCapacity", "maxCapacity", "capacity", "used"};
|
||||
private static final List<GarbageCollectorMXBean> gcBeans = ManagementFactoryHelper.getGarbageCollectorMXBeans();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String metaspace = "sun.gc.metaspace";
|
||||
@ -68,10 +72,27 @@ public class TestMetaspacePerfCounters {
|
||||
}
|
||||
|
||||
private static void checkPerfCounters(String ns) throws Exception {
|
||||
long minCapacity = getMinCapacity(ns);
|
||||
long maxCapacity = getMaxCapacity(ns);
|
||||
long capacity = getCapacity(ns);
|
||||
long used = getUsed(ns);
|
||||
long gcCountBefore;
|
||||
long gcCountAfter;
|
||||
long minCapacity;
|
||||
long maxCapacity;
|
||||
long capacity;
|
||||
long used;
|
||||
|
||||
// The perf counter values are updated during GC and to be able to
|
||||
// do the assertions below we need to ensure that the values are from
|
||||
// the same GC cycle.
|
||||
do {
|
||||
gcCountBefore = currentGCCount();
|
||||
|
||||
minCapacity = getMinCapacity(ns);
|
||||
maxCapacity = getMaxCapacity(ns);
|
||||
capacity = getCapacity(ns);
|
||||
used = getUsed(ns);
|
||||
|
||||
gcCountAfter = currentGCCount();
|
||||
assertGTE(gcCountAfter, gcCountBefore);
|
||||
} while(gcCountAfter > gcCountBefore);
|
||||
|
||||
assertGTE(minCapacity, 0L);
|
||||
assertGTE(used, minCapacity);
|
||||
@ -130,4 +151,12 @@ public class TestMetaspacePerfCounters {
|
||||
private static long getUsed(String ns) throws Exception {
|
||||
return PerfCounters.findByName(ns + ".used").longValue();
|
||||
}
|
||||
|
||||
private static long currentGCCount() {
|
||||
long gcCount = 0;
|
||||
for (GarbageCollectorMXBean bean : gcBeans) {
|
||||
gcCount += bean.getCollectionCount();
|
||||
}
|
||||
return gcCount;
|
||||
}
|
||||
}
|
||||
|
66
hotspot/test/native/logging/logTestFixture.cpp
Normal file
66
hotspot/test/native/logging/logTestFixture.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
LogTestFixture::LogTestFixture() {
|
||||
// Set up TestLogFileName to include PID, testcase name and test name
|
||||
int ret = jio_snprintf(_filename, sizeof(_filename), "testlog.pid%d.%s.%s.log",
|
||||
os::current_process_id(),
|
||||
::testing::UnitTest::GetInstance()->current_test_info()->test_case_name(),
|
||||
::testing::UnitTest::GetInstance()->current_test_info()->name());
|
||||
EXPECT_GT(ret, 0) << "_filename buffer issue";
|
||||
TestLogFileName = _filename;
|
||||
}
|
||||
|
||||
LogTestFixture::~LogTestFixture() {
|
||||
restore_default_log_config();
|
||||
delete_file(TestLogFileName);
|
||||
}
|
||||
|
||||
bool LogTestFixture::set_log_config(const char* output,
|
||||
const char* what,
|
||||
const char* decorators,
|
||||
const char* options,
|
||||
bool allow_failure) {
|
||||
ResourceMark rm;
|
||||
stringStream stream;
|
||||
bool success = LogConfiguration::parse_log_arguments(output, what, decorators, options, &stream);
|
||||
if (!allow_failure) {
|
||||
const char* errmsg = stream.as_string();
|
||||
EXPECT_STREQ("", errmsg) << "Unexpected error reported";
|
||||
EXPECT_TRUE(success) << "Shouldn't cause errors";
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void LogTestFixture::restore_default_log_config() {
|
||||
LogConfiguration::disable_logging();
|
||||
set_log_config("stdout", "all=warning");
|
||||
}
|
50
hotspot/test/native/logging/logTestFixture.hpp
Normal file
50
hotspot/test/native/logging/logTestFixture.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// A fixture base class for tests that need to change the log configuration,
|
||||
// or use a log file. After each test, the fixture will automatically restore
|
||||
// the log configuration and remove the test file (if used).
|
||||
// Provides TestLogFileName which is unique for each test, and is automatically
|
||||
// deleted after the test completes.
|
||||
class LogTestFixture : public testing::Test {
|
||||
private:
|
||||
char _filename[2 * K];
|
||||
|
||||
protected:
|
||||
const char* TestLogFileName;
|
||||
|
||||
LogTestFixture();
|
||||
~LogTestFixture();
|
||||
|
||||
static bool set_log_config(const char* output,
|
||||
const char* what,
|
||||
const char* decorators = "",
|
||||
const char* options = "",
|
||||
bool allow_failure = false);
|
||||
|
||||
static void restore_default_log_config();
|
||||
};
|
||||
|
45
hotspot/test/native/logging/logTestUtils.inline.hpp
Normal file
45
hotspot/test/native/logging/logTestUtils.inline.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "runtime/os.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
#define LOG_TEST_STRING_LITERAL "a (hopefully) unique log message for testing"
|
||||
|
||||
static inline bool string_contains_substring(const char* haystack, const char* needle) {
|
||||
return strstr(haystack, needle) != NULL;
|
||||
}
|
||||
|
||||
static inline bool file_exists(const char* filename) {
|
||||
struct stat st;
|
||||
return os::stat(filename, &st) == 0;
|
||||
}
|
||||
|
||||
static inline void delete_file(const char* filename) {
|
||||
if (!file_exists(filename)) {
|
||||
return;
|
||||
}
|
||||
int ret = remove(filename);
|
||||
EXPECT_TRUE(ret == 0 || errno == ENOENT) << "failed to remove file '" << filename << "': "
|
||||
<< os::strerror(errno) << " (" << errno << ")";
|
||||
}
|
291
hotspot/test/native/logging/test_logConfiguration.cpp
Normal file
291
hotspot/test/native/logging/test_logConfiguration.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
class LogConfigurationTest : public LogTestFixture {
|
||||
protected:
|
||||
static char _all_decorators[256];
|
||||
|
||||
public:
|
||||
static void SetUpTestCase();
|
||||
};
|
||||
|
||||
char LogConfigurationTest::_all_decorators[256];
|
||||
|
||||
// Prepare _all_decorators to contain the full list of decorators (comma separated)
|
||||
void LogConfigurationTest::SetUpTestCase() {
|
||||
char *pos = _all_decorators;
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
pos += jio_snprintf(pos, sizeof(_all_decorators) - (pos - _all_decorators), "%s%s",
|
||||
(i == 0 ? "" : ","),
|
||||
LogDecorators::name(static_cast<LogDecorators::Decorator>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the given text is included by LogConfiguration::describe()
|
||||
static bool is_described(const char* text) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
LogConfiguration::describe(&ss);
|
||||
return string_contains_substring(ss.as_string(), text);
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, describe) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
LogConfiguration::describe(&ss);
|
||||
const char* description = ss.as_string();
|
||||
|
||||
// Verify that stdout and stderr are listed by default
|
||||
EXPECT_PRED2(string_contains_substring, description, LogOutput::Stdout->name());
|
||||
EXPECT_PRED2(string_contains_substring, description, LogOutput::Stderr->name());
|
||||
|
||||
// Verify that each tag, level and decorator is listed
|
||||
for (size_t i = 0; i < LogTag::Count; i++) {
|
||||
EXPECT_PRED2(string_contains_substring, description, LogTag::name(static_cast<LogTagType>(i)));
|
||||
}
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
EXPECT_PRED2(string_contains_substring, description, LogLevel::name(static_cast<LogLevelType>(i)));
|
||||
}
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
EXPECT_PRED2(string_contains_substring, description, LogDecorators::name(static_cast<LogDecorators::Decorator>(i)));
|
||||
}
|
||||
|
||||
// Verify that the default configuration is printed
|
||||
char expected_buf[256];
|
||||
int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "=%s", LogLevel::name(LogLevel::Default));
|
||||
ASSERT_NE(-1, ret);
|
||||
EXPECT_PRED2(string_contains_substring, description, expected_buf);
|
||||
EXPECT_PRED2(string_contains_substring, description, "#1: stderr all=off");
|
||||
|
||||
// Verify default decorators are listed
|
||||
LogDecorators default_decorators;
|
||||
expected_buf[0] = '\0';
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
|
||||
if (default_decorators.is_decorator(d)) {
|
||||
ASSERT_LT(strlen(expected_buf), sizeof(expected_buf));
|
||||
ret = jio_snprintf(expected_buf + strlen(expected_buf),
|
||||
sizeof(expected_buf) - strlen(expected_buf),
|
||||
"%s%s",
|
||||
strlen(expected_buf) > 0 ? "," : "",
|
||||
LogDecorators::name(d));
|
||||
ASSERT_NE(-1, ret);
|
||||
}
|
||||
}
|
||||
EXPECT_PRED2(string_contains_substring, description, expected_buf);
|
||||
|
||||
// Add a new output and verify that it gets described after it has been added
|
||||
const char* what = "all=trace";
|
||||
EXPECT_FALSE(is_described(TestLogFileName)) << "Test output already exists!";
|
||||
set_log_config(TestLogFileName, what);
|
||||
EXPECT_TRUE(is_described(TestLogFileName));
|
||||
EXPECT_TRUE(is_described("logging=trace"));
|
||||
}
|
||||
|
||||
// Test updating an existing log output
|
||||
TEST_F(LogConfigurationTest, update_output) {
|
||||
// Update stdout twice, first using it's name, and the second time its index #
|
||||
const char* test_outputs[] = { "stdout", "#0" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(test_outputs); i++) {
|
||||
set_log_config(test_outputs[i], "all=info");
|
||||
|
||||
// Verify configuration using LogConfiguration::describe
|
||||
EXPECT_TRUE(is_described("#0: stdout"));
|
||||
EXPECT_TRUE(is_described("logging=info"));
|
||||
|
||||
// Verify by iterating over tagsets
|
||||
LogOutput* o = LogOutput::Stdout;
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_TRUE(ts->has_output(o));
|
||||
EXPECT_TRUE(ts->is_level(LogLevel::Info));
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Debug));
|
||||
}
|
||||
|
||||
// Now change the level and verify the change propagated
|
||||
set_log_config(test_outputs[i], "all=debug");
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_TRUE(ts->has_output(o));
|
||||
EXPECT_TRUE(ts->is_level(LogLevel::Debug));
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Trace));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test adding a new output to the configuration
|
||||
TEST_F(LogConfigurationTest, add_new_output) {
|
||||
const char* what = "all=trace";
|
||||
|
||||
ASSERT_FALSE(is_described(TestLogFileName));
|
||||
set_log_config(TestLogFileName, what);
|
||||
|
||||
// Verify new output using LogConfiguration::describe
|
||||
EXPECT_TRUE(is_described(TestLogFileName));
|
||||
EXPECT_TRUE(is_described("logging=trace"));
|
||||
|
||||
// Also verify by iterating over tagsets, checking levels on tagsets
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_TRUE(ts->is_level(LogLevel::Trace));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, disable_logging) {
|
||||
// Add TestLogFileName as an output
|
||||
set_log_config(TestLogFileName, "logging=info");
|
||||
|
||||
LogConfiguration::disable_logging();
|
||||
|
||||
// Verify TestLogFileName was disabled
|
||||
EXPECT_FALSE(is_described(TestLogFileName));
|
||||
|
||||
// Verify that no tagset has logging enabled
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_FALSE(ts->has_output(LogOutput::Stdout));
|
||||
EXPECT_FALSE(ts->has_output(LogOutput::Stderr));
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Error));
|
||||
}
|
||||
}
|
||||
|
||||
// Test disabling a particular output
|
||||
TEST_F(LogConfigurationTest, disable_output) {
|
||||
// Disable the default configuration for stdout
|
||||
set_log_config("stdout", "all=off");
|
||||
|
||||
// Verify configuration using LogConfiguration::describe
|
||||
EXPECT_TRUE(is_described("#0: stdout all=off"));
|
||||
|
||||
// Verify by iterating over tagsets
|
||||
LogOutput* o = LogOutput::Stdout;
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_FALSE(ts->has_output(o));
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Error));
|
||||
}
|
||||
|
||||
// Add a new file output
|
||||
const char* what = "all=debug";
|
||||
set_log_config(TestLogFileName, what);
|
||||
EXPECT_TRUE(is_described(TestLogFileName));
|
||||
|
||||
// Now disable it, verifying it is removed completely
|
||||
set_log_config(TestLogFileName, "all=off");
|
||||
EXPECT_FALSE(is_described(TestLogFileName));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Error));
|
||||
}
|
||||
}
|
||||
|
||||
// Test reconfiguration of the selected decorators for an output
|
||||
TEST_F(LogConfigurationTest, reconfigure_decorators) {
|
||||
// Configure stderr with all decorators
|
||||
set_log_config("stderr", "all=off", _all_decorators);
|
||||
char buf[256];
|
||||
int ret = jio_snprintf(buf, sizeof(buf), "#1: stderr all=off %s", _all_decorators);
|
||||
ASSERT_NE(-1, ret);
|
||||
EXPECT_TRUE(is_described(buf)) << "'" << buf << "' not described after reconfiguration";
|
||||
|
||||
// Now reconfigure logging on stderr with no decorators
|
||||
set_log_config("stderr", "all=off", "none");
|
||||
EXPECT_TRUE(is_described("#1: stderr all=off \n")) << "Expecting no decorators";
|
||||
}
|
||||
|
||||
// Test that invalid options cause configuration errors
|
||||
TEST_F(LogConfigurationTest, invalid_configure_options) {
|
||||
LogConfiguration::disable_logging();
|
||||
const char* invalid_outputs[] = { "#2", "invalidtype=123", ":invalid/path}to*file?" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(invalid_outputs); i++) {
|
||||
EXPECT_FALSE(set_log_config(invalid_outputs[i], "", "", "", true))
|
||||
<< "Accepted invalid output '" << invalid_outputs[i] << "'";
|
||||
}
|
||||
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all=invalid_level"));
|
||||
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("what=invalid"));
|
||||
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all::invalid_decorator"));
|
||||
}
|
||||
|
||||
// Test empty configuration options
|
||||
TEST_F(LogConfigurationTest, parse_empty_command_line_arguments) {
|
||||
const char* empty_variations[] = { "", ":", "::", ":::", "::::" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(empty_variations); i++) {
|
||||
const char* cmdline = empty_variations[i];
|
||||
bool ret = LogConfiguration::parse_command_line_arguments(cmdline);
|
||||
EXPECT_TRUE(ret) << "Error parsing command line arguments '" << cmdline << "'";
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Unspecified, ts->level_for(LogOutput::Stdout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test basic command line parsing & configuration
|
||||
TEST_F(LogConfigurationTest, parse_command_line_arguments) {
|
||||
// Prepare a command line for logging*=debug on stderr with all decorators
|
||||
int ret;
|
||||
char buf[256];
|
||||
ret = jio_snprintf(buf, sizeof(buf), "logging*=debug:stderr:%s", _all_decorators);
|
||||
ASSERT_NE(-1, ret);
|
||||
|
||||
bool success = LogConfiguration::parse_command_line_arguments(buf);
|
||||
EXPECT_TRUE(success) << "Error parsing valid command line arguments '" << buf << "'";
|
||||
// Ensure the new configuration applied
|
||||
EXPECT_TRUE(is_described("logging=debug"));
|
||||
EXPECT_TRUE(is_described(_all_decorators));
|
||||
|
||||
// Test the configuration of file outputs as well
|
||||
ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName);
|
||||
ASSERT_NE(-1, ret);
|
||||
EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf));
|
||||
}
|
||||
|
||||
// Test split up log configuration arguments
|
||||
TEST_F(LogConfigurationTest, parse_log_arguments) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
// Verify that it's possible to configure each individual tag
|
||||
for (size_t t = 1 /* Skip _NO_TAG */; t < LogTag::Count; t++) {
|
||||
const LogTagType tag = static_cast<LogTagType>(t);
|
||||
EXPECT_TRUE(LogConfiguration::parse_log_arguments("stdout", LogTag::name(tag), "", "", &ss));
|
||||
}
|
||||
// Same for each level
|
||||
for (size_t l = 0; l < LogLevel::Count; l++) {
|
||||
const LogLevelType level = static_cast<LogLevelType>(l);
|
||||
char expected_buf[256];
|
||||
int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "all=%s", LogLevel::name(level));
|
||||
ASSERT_NE(-1, ret);
|
||||
EXPECT_TRUE(LogConfiguration::parse_log_arguments("stderr", expected_buf, "", "", &ss));
|
||||
}
|
||||
// And for each decorator
|
||||
for (size_t d = 0; d < LogDecorators::Count; d++) {
|
||||
const LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
|
||||
EXPECT_TRUE(LogConfiguration::parse_log_arguments("#0", "", LogDecorators::name(decorator), "", &ss));
|
||||
}
|
||||
EXPECT_STREQ("", ss.as_string()) << "Error reported while parsing: " << ss.as_string();
|
||||
}
|
186
hotspot/test/native/logging/test_logDecorations.cpp
Normal file
186
hotspot/test/native/logging/test_logDecorations.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logDecorations.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
static const LogTagSet& tagset = LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset();
|
||||
static const LogDecorators default_decorators;
|
||||
|
||||
TEST(LogDecorations, level) {
|
||||
for (uint l = LogLevel::First; l <= LogLevel::Last; l++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(l);
|
||||
// Create a decorations object for the current level
|
||||
LogDecorations decorations(level, tagset, default_decorators);
|
||||
// Verify that the level decoration matches the specified level
|
||||
EXPECT_STREQ(LogLevel::name(level), decorations.decoration(LogDecorators::level_decorator));
|
||||
|
||||
// Test changing level after object creation time
|
||||
LogLevelType other_level;
|
||||
if (l != LogLevel::Last) {
|
||||
other_level = static_cast<LogLevelType>(l + 1);
|
||||
} else {
|
||||
other_level = static_cast<LogLevelType>(LogLevel::First);
|
||||
}
|
||||
decorations.set_level(other_level);
|
||||
EXPECT_STREQ(LogLevel::name(other_level), decorations.decoration(LogDecorators::level_decorator))
|
||||
<< "Decoration reports incorrect value after changing the level";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorations, uptime) {
|
||||
// Verify the format of the decoration
|
||||
int a, b;
|
||||
char decimal_point;
|
||||
LogDecorations decorations(LogLevel::Info, tagset, default_decorators);
|
||||
const char* uptime = decorations.decoration(LogDecorators::uptime_decorator);
|
||||
int read = sscanf(uptime, "%d%c%ds", &a, &decimal_point, &b);
|
||||
EXPECT_EQ(3, read) << "Invalid uptime decoration: " << uptime;
|
||||
EXPECT_TRUE(decimal_point == '.' || decimal_point == ',') << "Invalid uptime decoration: " << uptime;
|
||||
|
||||
// Verify that uptime increases
|
||||
double prev = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
os::naked_short_sleep(10);
|
||||
LogDecorations d(LogLevel::Info, tagset, default_decorators);
|
||||
double cur = strtod(d.decoration(LogDecorators::uptime_decorator), NULL);
|
||||
ASSERT_LT(prev, cur);
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorations, tags) {
|
||||
char expected_tags[1 * K];
|
||||
tagset.label(expected_tags, sizeof(expected_tags));
|
||||
// Verify that the expected tags are included in the tags decoration
|
||||
LogDecorations decorations(LogLevel::Info, tagset, default_decorators);
|
||||
EXPECT_STREQ(expected_tags, decorations.decoration(LogDecorators::tags_decorator));
|
||||
}
|
||||
|
||||
// Test each variation of the different timestamp decorations (ms, ns, uptime ms, uptime ns)
|
||||
TEST(LogDecorations, timestamps) {
|
||||
struct {
|
||||
const LogDecorators::Decorator decorator;
|
||||
const char* suffix;
|
||||
} test_decorator[] = {
|
||||
{ LogDecorators::timemillis_decorator, "ms" },
|
||||
{ LogDecorators::uptimemillis_decorator, "ms" },
|
||||
{ LogDecorators::timenanos_decorator, "ns" },
|
||||
{ LogDecorators::uptimenanos_decorator, "ns" }
|
||||
};
|
||||
|
||||
for (uint i = 0; i < ARRAY_SIZE(test_decorator); i++) {
|
||||
LogDecorators::Decorator decorator = test_decorator[i].decorator;
|
||||
LogDecorators decorator_selection;
|
||||
ASSERT_TRUE(decorator_selection.parse(LogDecorators::name(decorator)));
|
||||
|
||||
// Create decorations with the decorator we want to test included
|
||||
LogDecorations decorations(LogLevel::Info, tagset, decorator_selection);
|
||||
const char* decoration = decorations.decoration(decorator);
|
||||
|
||||
// Verify format of timestamp
|
||||
const char* suffix;
|
||||
for (suffix = decoration; isdigit(*suffix); suffix++) {
|
||||
// Skip over digits
|
||||
}
|
||||
EXPECT_STREQ(test_decorator[i].suffix, suffix);
|
||||
|
||||
// Verify timestamp values
|
||||
julong prev = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
os::naked_short_sleep(5);
|
||||
LogDecorations d(LogLevel::Info, tagset, decorator_selection);
|
||||
julong val = strtoull(d.decoration(decorator), NULL, 10);
|
||||
ASSERT_LT(prev, val);
|
||||
prev = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test the time decoration
|
||||
TEST(LogDecorations, iso8601_time) {
|
||||
LogDecorators decorator_selection;
|
||||
ASSERT_TRUE(decorator_selection.parse("time"));
|
||||
LogDecorations decorations(LogLevel::Info, tagset, decorator_selection);
|
||||
|
||||
const char *timestr = decorations.decoration(LogDecorators::time_decorator);
|
||||
time_t expected_ts = time(NULL);
|
||||
|
||||
// Verify format
|
||||
int y, M, d, h, m;
|
||||
double s;
|
||||
int read = sscanf(timestr, "%d-%d-%dT%d:%d:%lfZ", &y, &M, &d, &h, &m, &s);
|
||||
ASSERT_EQ(6, read);
|
||||
|
||||
// Verify reported time & date
|
||||
struct tm reported_time = {0};
|
||||
reported_time.tm_year = y - 1900;
|
||||
reported_time.tm_mon = M - 1;
|
||||
reported_time.tm_mday = d;
|
||||
reported_time.tm_hour = h;
|
||||
reported_time.tm_min = m;
|
||||
reported_time.tm_sec = s;
|
||||
reported_time.tm_isdst = daylight;
|
||||
time_t reported_ts = mktime(&reported_time);
|
||||
expected_ts = mktime(localtime(&expected_ts));
|
||||
time_t diff = reported_ts - expected_ts;
|
||||
if (diff < 0) {
|
||||
diff = -diff;
|
||||
}
|
||||
// Allow up to 10 seconds in difference
|
||||
ASSERT_LE(diff, 10) << "Reported time: " << reported_ts << " (" << timestr << ")"
|
||||
<< ", expected time: " << expected_ts;
|
||||
}
|
||||
|
||||
// Test the pid and tid decorations
|
||||
TEST(LogDecorations, identifiers) {
|
||||
LogDecorators decorator_selection;
|
||||
ASSERT_TRUE(decorator_selection.parse("pid,tid"));
|
||||
LogDecorations decorations(LogLevel::Info, tagset, decorator_selection);
|
||||
|
||||
struct {
|
||||
intx expected;
|
||||
LogDecorators::Decorator decorator;
|
||||
} ids[] = {
|
||||
{ os::current_process_id(), LogDecorators::pid_decorator },
|
||||
{ os::current_thread_id(), LogDecorators::tid_decorator },
|
||||
};
|
||||
|
||||
for (uint i = 0; i < ARRAY_SIZE(ids); i++) {
|
||||
const char* reported = decorations.decoration(ids[i].decorator);
|
||||
|
||||
// Verify format
|
||||
const char* str;
|
||||
for (str = reported; isdigit(*str); str++) {
|
||||
// Skip over digits
|
||||
}
|
||||
EXPECT_EQ('\0', *str) << "Should only contain digits";
|
||||
|
||||
// Verify value
|
||||
EXPECT_EQ(ids[i].expected, strtol(reported, NULL, 10));
|
||||
}
|
||||
}
|
216
hotspot/test/native/logging/test_logDecorators.cpp
Normal file
216
hotspot/test/native/logging/test_logDecorators.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
static LogDecorators::Decorator decorator_array[] = {
|
||||
#define DECORATOR(name, abbr) LogDecorators::name##_decorator,
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
};
|
||||
|
||||
static const char* decorator_name_array[] = {
|
||||
#define DECORATOR(name, abbr) #name,
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
};
|
||||
|
||||
static const char* decorator_abbr_array[] = {
|
||||
#define DECORATOR(name, abbr) #abbr,
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
};
|
||||
|
||||
// Assert that the given decorators object has the default decorators (uptime, level, tags)
|
||||
// If exclusive = true, also assert that no other decorators are selected
|
||||
static void assert_default_decorators(LogDecorators* decorators, bool exclusive = true) {
|
||||
for (int i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator decorator = decorator_array[i];
|
||||
if (decorator == LogDecorators::uptime_decorator ||
|
||||
decorator == LogDecorators::level_decorator ||
|
||||
decorator == LogDecorators::tags_decorator) {
|
||||
EXPECT_TRUE(decorators->is_decorator(decorator));
|
||||
} else if (exclusive) {
|
||||
EXPECT_FALSE(decorators->is_decorator(decorator));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorators, defaults) {
|
||||
LogDecorators decorators;
|
||||
assert_default_decorators(&decorators);
|
||||
}
|
||||
|
||||
// Test converting between name and decorator (string and enum)
|
||||
TEST(LogDecorators, from_and_to_name) {
|
||||
EXPECT_EQ(LogDecorators::Invalid, LogDecorators::from_string("unknown"));
|
||||
EXPECT_EQ(LogDecorators::Invalid, LogDecorators::from_string(""));
|
||||
|
||||
for (int i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator decorator = decorator_array[i];
|
||||
|
||||
const char* name = LogDecorators::name(decorator);
|
||||
EXPECT_STREQ(decorator_name_array[i], name);
|
||||
|
||||
LogDecorators::Decorator decorator2 = LogDecorators::from_string(name);
|
||||
EXPECT_EQ(decorator, decorator2);
|
||||
|
||||
// Test case insensitivity
|
||||
char* name_cpy = strdup(name);
|
||||
name_cpy[0] = toupper(name_cpy[0]);
|
||||
decorator2 = LogDecorators::from_string(name_cpy);
|
||||
free(name_cpy);
|
||||
EXPECT_EQ(decorator, decorator2);
|
||||
}
|
||||
}
|
||||
|
||||
// Test decorator abbreviations
|
||||
TEST(LogDecorators, from_and_to_abbr) {
|
||||
for (int i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator decorator = decorator_array[i];
|
||||
|
||||
const char* abbr = LogDecorators::abbreviation(decorator);
|
||||
EXPECT_STREQ(decorator_abbr_array[i], abbr);
|
||||
|
||||
LogDecorators::Decorator decorator2 = LogDecorators::from_string(abbr);
|
||||
ASSERT_EQ(decorator, decorator2);
|
||||
|
||||
// Test case insensitivity
|
||||
char* abbr_cpy = strdup(abbr);
|
||||
abbr_cpy[0] = toupper(abbr_cpy[0]);
|
||||
decorator2 = LogDecorators::from_string(abbr_cpy);
|
||||
free(abbr_cpy);
|
||||
EXPECT_EQ(decorator, decorator2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorators, parse_default) {
|
||||
LogDecorators decorators;
|
||||
decorators.parse(""); // Empty string means we should use the default decorators
|
||||
assert_default_decorators(&decorators);
|
||||
}
|
||||
|
||||
// Test that "none" gives no decorators at all
|
||||
TEST(LogDecorators, parse_none) {
|
||||
LogDecorators decorators;
|
||||
decorators.parse("none");
|
||||
for (int i = 0; i < LogDecorators::Count; i++) {
|
||||
EXPECT_FALSE(decorators.is_decorator(decorator_array[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Test a few invalid decorator selections
|
||||
TEST(LogDecorators, parse_invalid) {
|
||||
LogDecorators decorators;
|
||||
EXPECT_FALSE(decorators.parse("invalid"));
|
||||
EXPECT_FALSE(decorators.parse(",invalid"));
|
||||
EXPECT_FALSE(decorators.parse(",invalid,"));
|
||||
assert_default_decorators(&decorators);
|
||||
}
|
||||
|
||||
// Assert that the given decorator has all decorators between first and last
|
||||
static void assert_decorations_between(const LogDecorators* decorator, size_t first, size_t last) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(decorator_array); i++) {
|
||||
if (i >= first && i <= last) {
|
||||
EXPECT_TRUE(decorator->is_decorator(decorator_array[i]));
|
||||
} else {
|
||||
EXPECT_FALSE(decorator->is_decorator(decorator_array[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorators, parse) {
|
||||
LogDecorators decorators;
|
||||
|
||||
// Verify a bunch of different decorator selections
|
||||
char decstr[1 * K];
|
||||
decstr[0] = '\0';
|
||||
size_t written = 0;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(decorator_array); i++) {
|
||||
for (size_t j = i; j < ARRAY_SIZE(decorator_array); j++) {
|
||||
for (size_t k = i; k <= j; k++) {
|
||||
ASSERT_LT(written, sizeof(decstr)) << "decstr overflow";
|
||||
int ret = jio_snprintf(decstr + written, sizeof(decstr) - written, "%s%s",
|
||||
written == 0 ? "" : ",",
|
||||
((k + j) % 2 == 0) ? decorator_name_array[k] : decorator_abbr_array[k]);
|
||||
ASSERT_NE(-1, ret);
|
||||
written += ret;
|
||||
}
|
||||
EXPECT_TRUE(decorators.parse(decstr)) << "Valid decorator selection did not parse: " << decstr;
|
||||
assert_decorations_between(&decorators, i, j);
|
||||
written = 0;
|
||||
decstr[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorators, combine_with) {
|
||||
LogDecorators dec1;
|
||||
LogDecorators dec2;
|
||||
|
||||
// Select first and third decorator for dec1
|
||||
char input[64];
|
||||
sprintf(input, "%s,%s", decorator_name_array[0], decorator_name_array[2]);
|
||||
dec1.parse(input);
|
||||
EXPECT_TRUE(dec1.is_decorator(decorator_array[0]));
|
||||
EXPECT_TRUE(dec1.is_decorator(decorator_array[2]));
|
||||
|
||||
// Select the default decorators for dec2
|
||||
EXPECT_FALSE(dec2.is_decorator(decorator_array[0]));
|
||||
EXPECT_FALSE(dec2.is_decorator(decorator_array[2]));
|
||||
assert_default_decorators(&dec2);
|
||||
|
||||
// Combine and verify that the combination includes first, third and default decorators
|
||||
dec2.combine_with(dec1);
|
||||
EXPECT_TRUE(dec2.is_decorator(decorator_array[0]));
|
||||
EXPECT_TRUE(dec2.is_decorator(decorator_array[2]));
|
||||
assert_default_decorators(&dec2, false);
|
||||
}
|
||||
|
||||
TEST(LogDecorators, clear) {
|
||||
// Start with default decorators and then clear it
|
||||
LogDecorators dec;
|
||||
EXPECT_FALSE(dec.is_empty());
|
||||
|
||||
dec.clear();
|
||||
EXPECT_TRUE(dec.is_empty());
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
EXPECT_FALSE(dec.is_decorator(decorator_array[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Test the decorator constant None
|
||||
TEST(LogDecorators, none) {
|
||||
LogDecorators dec = LogDecorators::None;
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
EXPECT_FALSE(dec.is_decorator(decorator_array[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorators, is_empty) {
|
||||
LogDecorators def, none = LogDecorators::None;
|
||||
EXPECT_FALSE(def.is_empty());
|
||||
EXPECT_TRUE(none.is_empty());
|
||||
}
|
103
hotspot/test/native/logging/test_logFileOutput.cpp
Normal file
103
hotspot/test/native/logging/test_logFileOutput.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logFileOutput.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
static const char* name = "testlog.pid%p.%t.log";
|
||||
|
||||
// Test parsing a bunch of valid file output options
|
||||
TEST(LogFileOutput, parse_valid) {
|
||||
const char* valid_options[] = {
|
||||
"", "filecount=10", "filesize=512",
|
||||
"filecount=11,filesize=256",
|
||||
"filesize=256,filecount=11",
|
||||
"filesize=0", "filecount=1",
|
||||
"filesize=1m", "filesize=1M",
|
||||
"filesize=1k", "filesize=1G"
|
||||
};
|
||||
|
||||
// Override LogOutput's vm_start time to get predictable file name
|
||||
LogFileOutput::set_file_name_parameters(0);
|
||||
char expected_filename[1 * K];
|
||||
int ret = jio_snprintf(expected_filename, sizeof(expected_filename),
|
||||
"testlog.pid%d.1970-01-01_01-00-00.log",
|
||||
os::current_process_id());
|
||||
ASSERT_GT(ret, 0) << "Buffer too small";
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(valid_options); i++) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
{
|
||||
LogFileOutput fo(name);
|
||||
EXPECT_STREQ(name, fo.name());
|
||||
EXPECT_TRUE(fo.initialize(valid_options[i], &ss))
|
||||
<< "Did not accept valid option(s) '" << valid_options[i] << "': " << ss.as_string();
|
||||
}
|
||||
remove(expected_filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Test parsing a bunch of invalid file output options
|
||||
TEST(LogFileOutput, parse_invalid) {
|
||||
const char* invalid_options[] = {
|
||||
"invalidopt", "filecount=",
|
||||
"filesize=,filecount=10",
|
||||
"fileco=10", "ilesize=512",
|
||||
"filecount=11,,filesize=256",
|
||||
",filesize=256,filecount=11",
|
||||
"filesize=256,filecount=11,",
|
||||
"filesize=-1", "filecount=0.1",
|
||||
"filecount=-2", "filecount=2.0",
|
||||
"filecount= 2", "filesize=2 ",
|
||||
"filecount=ab", "filesize=0xz",
|
||||
"filecount=1MB", "filesize=99bytes",
|
||||
"filesize=9999999999999999999999999"
|
||||
"filecount=9999999999999999999999999"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(invalid_options); i++) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
LogFileOutput fo(name);
|
||||
EXPECT_FALSE(fo.initialize(invalid_options[i], &ss))
|
||||
<< "Accepted invalid option(s) '" << invalid_options[i] << "': " << ss.as_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Test for overflows with filesize
|
||||
TEST(LogFileOutput, filesize_overflow) {
|
||||
char buf[256];
|
||||
int ret = jio_snprintf(buf, sizeof(buf), "filesize=" SIZE_FORMAT "K", SIZE_MAX);
|
||||
ASSERT_GT(ret, 0) << "Buffer too small";
|
||||
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
LogFileOutput fo(name);
|
||||
EXPECT_FALSE(fo.initialize(buf, &ss)) << "Accepted filesize that overflows";
|
||||
}
|
54
hotspot/test/native/logging/test_logLevel.cpp
Normal file
54
hotspot/test/native/logging/test_logLevel.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(LogLevel, from_string) {
|
||||
LogLevelType level;
|
||||
|
||||
// Verify each name defined in the LOG_LEVEL_LIST
|
||||
#define LOG_LEVEL(lname, lstring) \
|
||||
level = LogLevel::from_string(#lstring); \
|
||||
EXPECT_EQ(level, LogLevel::lname);
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
|
||||
// Verify a few invalid level strings
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("bad level"));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("debugger"));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("inf"));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("info "));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string(" info"));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("=info"));
|
||||
EXPECT_EQ(LogLevel::Invalid, LogLevel::from_string("infodebugwarning"));
|
||||
}
|
||||
|
||||
TEST(LogLevel, name) {
|
||||
// Use names from macro as reference
|
||||
#define LOG_LEVEL(lname, lstring) \
|
||||
EXPECT_STREQ(LogLevel::name(LogLevel::lname), #lstring);
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
}
|
255
hotspot/test/native/logging/test_logOutputList.cpp
Normal file
255
hotspot/test/native/logging/test_logOutputList.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "logging/logOutputList.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
// Count the outputs in the given list, starting from the specified level
|
||||
static size_t output_count(LogOutputList* list, LogLevelType from = LogLevel::Error) {
|
||||
size_t count = 0;
|
||||
for (LogOutputList::Iterator it = list->iterator(from); it != list->end(); it++) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Get the level for an output in the given list
|
||||
static LogLevelType find_output_level(LogOutputList* list, LogOutput* o) {
|
||||
for (size_t levelnum = 1; levelnum < LogLevel::Count; levelnum++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(levelnum);
|
||||
for (LogOutputList::Iterator it = list->iterator(level); it != list->end(); it++) {
|
||||
if (*it == o) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
}
|
||||
return LogLevel::Off;
|
||||
}
|
||||
|
||||
// Create a dummy output pointer with the specified id.
|
||||
// This dummy pointer should not be used for anything
|
||||
// but pointer comparisons with other dummies.
|
||||
static LogOutput* dummy_output(size_t id) {
|
||||
return reinterpret_cast<LogOutput*>(id + 1);
|
||||
}
|
||||
|
||||
// Randomly update and verify some outputs some number of times
|
||||
TEST(LogOutputList, set_output_level_update) {
|
||||
const size_t TestOutputCount = 10;
|
||||
const size_t TestIterations = 10000;
|
||||
LogOutputList list;
|
||||
size_t outputs_on_level[LogLevel::Count];
|
||||
LogLevelType expected_level_for_output[TestOutputCount];
|
||||
|
||||
os::init_random(0x4711);
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
outputs_on_level[i] = 0;
|
||||
}
|
||||
outputs_on_level[LogLevel::Off] = TestOutputCount;
|
||||
for (size_t i = 0; i < TestOutputCount; i++) {
|
||||
expected_level_for_output[i] = LogLevel::Off;
|
||||
}
|
||||
|
||||
for (size_t iteration = 0; iteration < TestIterations; iteration++) {
|
||||
size_t output_idx = os::random() % TestOutputCount;
|
||||
size_t levelnum = os::random() % LogLevel::Count;
|
||||
LogLevelType level = static_cast<LogLevelType>(levelnum);
|
||||
|
||||
// Update the expectations
|
||||
outputs_on_level[expected_level_for_output[output_idx]]--;
|
||||
outputs_on_level[levelnum]++;
|
||||
expected_level_for_output[output_idx] = level;
|
||||
|
||||
// Update the actual list
|
||||
list.set_output_level(dummy_output(output_idx), level);
|
||||
|
||||
// Verify expected levels
|
||||
for (size_t i = 0; i < TestOutputCount; i++) {
|
||||
ASSERT_EQ(expected_level_for_output[i], find_output_level(&list, dummy_output(i)));
|
||||
}
|
||||
// Verify output counts
|
||||
size_t expected_count = 0;
|
||||
for (size_t i = 1; i < LogLevel::Count; i++) {
|
||||
expected_count += outputs_on_level[i];
|
||||
ASSERT_EQ(expected_count, output_count(&list, static_cast<LogLevelType>(i)));
|
||||
}
|
||||
ASSERT_EQ(TestOutputCount, expected_count + outputs_on_level[LogLevel::Off]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test removing outputs from a LogOutputList
|
||||
TEST(LogOutputList, set_output_level_remove) {
|
||||
LogOutputList list;
|
||||
|
||||
// Add three dummy outputs per loglevel
|
||||
for (size_t i = 1; i < LogLevel::Count; i++) {
|
||||
list.set_output_level(dummy_output(i), static_cast<LogLevelType>(i));
|
||||
list.set_output_level(dummy_output(i*10), static_cast<LogLevelType>(i));
|
||||
list.set_output_level(dummy_output(i*100), static_cast<LogLevelType>(i));
|
||||
}
|
||||
|
||||
// Verify that they have been added successfully
|
||||
// (Count - 1 since we don't count LogLevel::Off)
|
||||
EXPECT_EQ(3u * (LogLevel::Count - 1), output_count(&list));
|
||||
// Now remove the second output from each loglevel
|
||||
for (size_t i = 1; i < LogLevel::Count; i++) {
|
||||
list.set_output_level(dummy_output(i*10), LogLevel::Off);
|
||||
}
|
||||
// Make sure they have been successfully removed
|
||||
EXPECT_EQ(2u * (LogLevel::Count - 1), output_count(&list));
|
||||
|
||||
// Now remove the remaining outputs
|
||||
for (size_t i = 1; i < LogLevel::Count; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Off);
|
||||
list.set_output_level(dummy_output(i*100), LogLevel::Off);
|
||||
}
|
||||
EXPECT_EQ(0u, output_count(&list));
|
||||
}
|
||||
|
||||
// Test adding to a LogOutputList
|
||||
TEST(LogOutputList, set_output_level_add) {
|
||||
LogOutputList list;
|
||||
|
||||
// First add 5 outputs to Info level
|
||||
for (size_t i = 10; i < 15; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Info);
|
||||
}
|
||||
|
||||
// Verify that they have been added successfully
|
||||
size_t count = 0;
|
||||
for (LogOutputList::Iterator it = list.iterator(); it != list.end(); it++) {
|
||||
ASSERT_EQ(dummy_output(10 + count++), *it);
|
||||
}
|
||||
ASSERT_EQ(5u, count);
|
||||
|
||||
// Now add more outputs, but on all different levels
|
||||
for (size_t i = 5; i < 10; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Warning);
|
||||
}
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Error);
|
||||
}
|
||||
for (size_t i = 15; i < 20; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Debug);
|
||||
}
|
||||
for (size_t i = 20; i < 25; i++) {
|
||||
list.set_output_level(dummy_output(i), LogLevel::Trace);
|
||||
}
|
||||
|
||||
// Verify that that all outputs have been added, and that the order is Error, Warning, Info, Debug, Trace
|
||||
count = 0;
|
||||
for (LogOutputList::Iterator it = list.iterator(); it != list.end(); it++) {
|
||||
ASSERT_EQ(dummy_output(count++), *it);
|
||||
}
|
||||
ASSERT_EQ(25u, count);
|
||||
}
|
||||
|
||||
// Test is_level() on lists with a single output on different levels
|
||||
TEST(LogOutputList, is_level_single_output) {
|
||||
for (size_t i = LogLevel::First; i < LogLevel::Count; i++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(i);
|
||||
LogOutputList list;
|
||||
list.set_output_level(LogOutput::Stdout, level);
|
||||
for (size_t j = LogLevel::First; j < LogLevel::Count; j++) {
|
||||
LogLevelType other = static_cast<LogLevelType>(j);
|
||||
// Verify that levels finer than the current level for stdout are reported as disabled,
|
||||
// and levels equal to or included in the current level are reported as enabled
|
||||
if (other >= level) {
|
||||
EXPECT_TRUE(list.is_level(other))
|
||||
<< LogLevel::name(other) << " >= " << LogLevel::name(level) << " but is_level() returns false";
|
||||
} else {
|
||||
EXPECT_FALSE(list.is_level(other))
|
||||
<< LogLevel::name(other) << " < " << LogLevel::name(level) << " but is_level() returns true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test is_level() with an empty list
|
||||
TEST(LogOutputList, is_level_empty) {
|
||||
LogOutputList emptylist;
|
||||
for (size_t i = LogLevel::First; i < LogLevel::Count; i++) {
|
||||
LogLevelType other = static_cast<LogLevelType>(i);
|
||||
EXPECT_FALSE(emptylist.is_level(other)) << "is_level() returns true even though the list is empty";
|
||||
}
|
||||
}
|
||||
|
||||
// Test is_level() on lists with two outputs on different levels
|
||||
TEST(LogOutputList, is_level_multiple_outputs) {
|
||||
for (size_t i = LogLevel::First; i < LogLevel::Count - 1; i++) {
|
||||
LogOutput* dummy1 = LogOutput::Stdout;
|
||||
LogOutput* dummy2 = LogOutput::Stderr;
|
||||
LogLevelType first = static_cast<LogLevelType>(i);
|
||||
LogLevelType second = static_cast<LogLevelType>(i + 1);
|
||||
LogOutputList list;
|
||||
list.set_output_level(dummy1, first);
|
||||
list.set_output_level(dummy2, second);
|
||||
for (size_t j = LogLevel::First; j < LogLevel::Count; j++) {
|
||||
LogLevelType other = static_cast<LogLevelType>(j);
|
||||
// The first output's level will be the finest, expect it's level to be reported by the list
|
||||
if (other >= first) {
|
||||
EXPECT_TRUE(list.is_level(other))
|
||||
<< LogLevel::name(other) << " >= " << LogLevel::name(first) << " but is_level() returns false";
|
||||
} else {
|
||||
EXPECT_FALSE(list.is_level(other))
|
||||
<< LogLevel::name(other) << " < " << LogLevel::name(first) << " but is_level() returns true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogOutputList, level_for) {
|
||||
LogOutputList list;
|
||||
|
||||
// Ask the empty list about stdout, stderr
|
||||
EXPECT_EQ(LogLevel::Off, list.level_for(LogOutput::Stdout));
|
||||
EXPECT_EQ(LogLevel::Off, list.level_for(LogOutput::Stderr));
|
||||
|
||||
// Ask for level in a list with two outputs on different levels
|
||||
list.set_output_level(LogOutput::Stdout, LogLevel::Info);
|
||||
list.set_output_level(LogOutput::Stderr, LogLevel::Trace);
|
||||
EXPECT_EQ(LogLevel::Info, list.level_for(LogOutput::Stdout));
|
||||
EXPECT_EQ(LogLevel::Trace, list.level_for(LogOutput::Stderr));
|
||||
|
||||
// Remove and ask again
|
||||
list.set_output_level(LogOutput::Stdout, LogLevel::Off);
|
||||
EXPECT_EQ(LogLevel::Off, list.level_for(LogOutput::Stdout));
|
||||
EXPECT_EQ(LogLevel::Trace, list.level_for(LogOutput::Stderr));
|
||||
|
||||
// Ask about an unknown output
|
||||
LogOutput* dummy = dummy_output(4711);
|
||||
EXPECT_EQ(LogLevel::Off, list.level_for(dummy));
|
||||
|
||||
for (size_t i = LogLevel::First; i <= LogLevel::Last; i++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(i);
|
||||
list.set_output_level(dummy, level);
|
||||
EXPECT_EQ(level, list.level_for(dummy));
|
||||
}
|
||||
|
||||
// Make sure the stderr level is still the same
|
||||
EXPECT_EQ(LogLevel::Trace, list.level_for(LogOutput::Stderr));
|
||||
}
|
53
hotspot/test/native/logging/test_logTag.cpp
Normal file
53
hotspot/test/native/logging/test_logTag.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(LogTag, from_string) {
|
||||
// Verify for all tags defined in LOG_TAG_LIST
|
||||
#define LOG_TAG(tag) \
|
||||
EXPECT_EQ(PREFIX_LOG_TAG(tag), LogTag::from_string(#tag));
|
||||
LOG_TAG_LIST
|
||||
#undef LOG_TAG
|
||||
|
||||
// Verify a couple of invalid strings parsing as invalid tags
|
||||
const char* invalid_tag[] = {
|
||||
"bad tag", ".^@", "**", "*", "gcc", "+gc", "gc+", "gc+safepoint",
|
||||
"gc+safepoint=warning", "warning", "=info", "gcsafepointlogging",
|
||||
"gc+safepointlogging", "gclogging", "+", " gc", "logging ", ","
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(invalid_tag) / sizeof(*invalid_tag); i++) {
|
||||
EXPECT_EQ(LogTag::__NO_TAG, LogTag::from_string(invalid_tag[i]))
|
||||
<< "'" << invalid_tag[i] << "' did not parse as an invalid tag";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogTag, name) {
|
||||
// Verify for each tag from the macro
|
||||
#define LOG_TAG(tag) \
|
||||
EXPECT_STREQ(#tag, LogTag::name(PREFIX_LOG_TAG(tag)));
|
||||
LOG_TAG_LIST
|
||||
#undef LOG_TAG
|
||||
}
|
183
hotspot/test/native/logging/test_logTagLevelExpression.cpp
Normal file
183
hotspot/test/native/logging/test_logTagLevelExpression.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logTagLevelExpression.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
TEST(LogTagLevelExpression, parse) {
|
||||
char buf[256];
|
||||
const char* invalid_substr[] = {
|
||||
"=", "+", " ", "+=", "+=*", "*+", " +", "**", "++", ".", ",", ",," ",+",
|
||||
" *", "all+", "all*", "+all", "+all=Warning", "==Info", "=InfoWarning",
|
||||
"BadTag+", "logging++", "logging*+", ",=", "gc+gc+gc+gc+gc+gc"
|
||||
};
|
||||
const char* valid_expression[] = {
|
||||
"all", "gc", "gc,logging", "gc+logging", "logging+gc", "logging+gc,gc", "logging+gc*", "gc=trace",
|
||||
"gc=trace,logging=info", "logging+gc=trace", "logging+gc=trace,gc+logging=warning,logging",
|
||||
"gc,all=info", "logging*", "logging*=info", "gc+logging*=error", "logging*,gc=info"
|
||||
};
|
||||
|
||||
// Verify valid expressions parse without problems
|
||||
for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
|
||||
LogTagLevelExpression expr;
|
||||
EXPECT_TRUE(expr.parse(valid_expression[i])) << "Valid expression '" << valid_expression[i] << "' did not parse";
|
||||
}
|
||||
|
||||
// Verify we can use 'all' with each available level
|
||||
for (uint level = LogLevel::First; level <= LogLevel::Last; level++) {
|
||||
char buf[32];
|
||||
int ret = jio_snprintf(buf, sizeof(buf), "all=%s", LogLevel::name(static_cast<LogLevelType>(level)));
|
||||
ASSERT_NE(ret, -1);
|
||||
|
||||
LogTagLevelExpression expr;
|
||||
EXPECT_TRUE(expr.parse(buf));
|
||||
}
|
||||
|
||||
// Verify invalid expressions do not parse
|
||||
for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(invalid_substr); j++) {
|
||||
// Prefix with invalid substr
|
||||
LogTagLevelExpression expr;
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s", invalid_substr[j], valid_expression[i]);
|
||||
EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
|
||||
|
||||
// Suffix with invalid substr
|
||||
LogTagLevelExpression expr1;
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_substr[j]);
|
||||
EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
|
||||
|
||||
// Use only the invalid substr
|
||||
LogTagLevelExpression expr2;
|
||||
EXPECT_FALSE(expr2.parse(invalid_substr[j])) << "'" << invalid_substr[j] << "'" << " considered legal";
|
||||
}
|
||||
|
||||
// Suffix/prefix with some unique invalid prefixes/suffixes
|
||||
LogTagLevelExpression expr;
|
||||
jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
|
||||
EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
|
||||
|
||||
LogTagLevelExpression expr1;
|
||||
jio_snprintf(buf, sizeof(buf), "logging*%s", valid_expression[i]);
|
||||
EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
|
||||
}
|
||||
}
|
||||
|
||||
// Test the level_for() function for an empty expression
|
||||
TEST(LogTagLevelExpression, level_for_empty) {
|
||||
LogTagLevelExpression emptyexpr;
|
||||
ASSERT_TRUE(emptyexpr.parse(""));
|
||||
// All tagsets should be unspecified since the expression doesn't involve any tagset
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Unspecified, emptyexpr.level_for(*ts));
|
||||
}
|
||||
}
|
||||
|
||||
// Test level_for() with "all" without any specified level
|
||||
TEST(LogTagLevelExpression, level_for_all) {
|
||||
LogTagLevelExpression allexpr;
|
||||
ASSERT_TRUE(allexpr.parse("all"));
|
||||
// Level will be unspecified since no level was given
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Unspecified, allexpr.level_for(*ts));
|
||||
}
|
||||
}
|
||||
|
||||
// Test level_for() with "all=debug"
|
||||
TEST(LogTagLevelExpression, level_for_all_debug) {
|
||||
LogTagLevelExpression alldebugexpr;
|
||||
ASSERT_TRUE(alldebugexpr.parse("all=debug"));
|
||||
// All tagsets should report debug level
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Debug, alldebugexpr.level_for(*ts));
|
||||
}
|
||||
}
|
||||
|
||||
// Test level_for() with "all=off"
|
||||
TEST(LogTagLevelExpression, level_for_all_off) {
|
||||
LogTagLevelExpression alloffexpr;
|
||||
ASSERT_TRUE(alloffexpr.parse("all=off"));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Off, alloffexpr.level_for(*ts));
|
||||
}
|
||||
}
|
||||
|
||||
// Test level_for() with an expression that has overlap (last subexpression should be used)
|
||||
TEST(LogTagLevelExpression, level_for_overlap) {
|
||||
LogTagLevelExpression overlapexpr;
|
||||
// The all=warning will be overridden with gc=info and/or logging+safepoint*=trace
|
||||
ASSERT_TRUE(overlapexpr.parse("all=warning,gc=info,logging+safepoint*=trace"));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
if (ts->contains(PREFIX_LOG_TAG(gc)) && ts->ntags() == 1) {
|
||||
EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(*ts));
|
||||
} else if (ts->contains(PREFIX_LOG_TAG(logging)) && ts->contains(PREFIX_LOG_TAG(safepoint))) {
|
||||
EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(*ts));
|
||||
} else {
|
||||
EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(*ts));
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Trace,
|
||||
overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc, class, safepoint, heap)>::tagset()));
|
||||
}
|
||||
|
||||
// Test level_for() with an expression containing two independent subexpressions
|
||||
TEST(LogTagLevelExpression, level_for_disjoint) {
|
||||
LogTagLevelExpression reducedexpr;
|
||||
ASSERT_TRUE(reducedexpr.parse("gc+logging=trace,class*=error"));
|
||||
EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint, class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Trace, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
|
||||
}
|
||||
|
||||
// Test level_for() with an expression that is completely overridden in the last part of the expression
|
||||
TEST(LogTagLevelExpression, level_for_override) {
|
||||
LogTagLevelExpression overrideexpr;
|
||||
// No matter what, everything should be set to error level because of the last part
|
||||
ASSERT_TRUE(overrideexpr.parse("logging,gc*=trace,all=error"));
|
||||
EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
|
||||
}
|
||||
|
||||
// Test level_for() with a mixed expression with a bit of everything
|
||||
TEST(LogTagLevelExpression, level_for_mixed) {
|
||||
LogTagLevelExpression mixedexpr;
|
||||
ASSERT_TRUE(mixedexpr.parse("all=warning,gc*=debug,gc=trace,safepoint*=off"));
|
||||
EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, class)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, safepoint, logging)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
|
||||
EXPECT_EQ(LogLevel::Trace, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
|
||||
}
|
130
hotspot/test/native/logging/test_logTagSet.cpp
Normal file
130
hotspot/test/native/logging/test_logTagSet.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* ac_heapanied 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 "logging/logLevel.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
// Test the default level for each tagset
|
||||
TEST(LogTagSet, defaults) {
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
char buf[256];
|
||||
ts->label(buf, sizeof(buf));
|
||||
SCOPED_TRACE(buf);
|
||||
EXPECT_TRUE(ts->is_level(LogLevel::Error));
|
||||
EXPECT_TRUE(ts->is_level(LogLevel::Warning));
|
||||
EXPECT_FALSE(ts->is_level(LogLevel::Info));
|
||||
EXPECT_TRUE(ts->has_output(LogOutput::Stdout));
|
||||
EXPECT_FALSE(ts->has_output(LogOutput::Stderr));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogTagSet, has_output) {
|
||||
LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
ts.set_output_level(LogOutput::Stderr, LogLevel::Trace);
|
||||
EXPECT_TRUE(ts.has_output(LogOutput::Stderr));
|
||||
EXPECT_FALSE(ts.has_output(NULL));
|
||||
ts.set_output_level(LogOutput::Stderr, LogLevel::Off);
|
||||
EXPECT_FALSE(ts.has_output(LogOutput::Stderr));
|
||||
}
|
||||
|
||||
TEST(LogTagSet, ntags) {
|
||||
const LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
EXPECT_EQ(1u, ts.ntags());
|
||||
const LogTagSet& ts2 = LogTagSetMapping<LOG_TAGS(logging, gc, class, safepoint, heap)>::tagset();
|
||||
EXPECT_EQ(5u, ts2.ntags());
|
||||
}
|
||||
|
||||
TEST(LogTagSet, is_level) {
|
||||
LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
// Set info level on stdout and verify that is_level() reports correctly
|
||||
ts.set_output_level(LogOutput::Stdout, LogLevel::Info);
|
||||
EXPECT_TRUE(ts.is_level(LogLevel::Error));
|
||||
EXPECT_TRUE(ts.is_level(LogLevel::Warning));
|
||||
EXPECT_TRUE(ts.is_level(LogLevel::Info));
|
||||
EXPECT_FALSE(ts.is_level(LogLevel::Debug));
|
||||
EXPECT_FALSE(ts.is_level(LogLevel::Trace));
|
||||
ts.set_output_level(LogOutput::Stdout, LogLevel::Default);
|
||||
EXPECT_TRUE(ts.is_level(LogLevel::Default));
|
||||
}
|
||||
|
||||
TEST(LogTagSet, level_for) {
|
||||
LogOutput* output = LogOutput::Stdout;
|
||||
LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
for (uint i = 0; i < LogLevel::Count; i++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(i);
|
||||
// Set the level and verify that level_for() reports it back
|
||||
ts.set_output_level(output, level);
|
||||
EXPECT_EQ(level, ts.level_for(output));
|
||||
}
|
||||
ts.set_output_level(output, LogLevel::Default);
|
||||
}
|
||||
|
||||
TEST(LogTagSet, contains) {
|
||||
// Verify that contains works as intended for a few predetermined tagsets
|
||||
const LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
EXPECT_TRUE(ts.contains(PREFIX_LOG_TAG(logging)));
|
||||
EXPECT_FALSE(ts.contains(PREFIX_LOG_TAG(gc)));
|
||||
EXPECT_FALSE(ts.contains(PREFIX_LOG_TAG(class)));
|
||||
|
||||
const LogTagSet& ts2 = LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset();
|
||||
EXPECT_TRUE(ts2.contains(PREFIX_LOG_TAG(logging)));
|
||||
EXPECT_TRUE(ts2.contains(PREFIX_LOG_TAG(gc)));
|
||||
EXPECT_FALSE(ts2.contains(PREFIX_LOG_TAG(class)));
|
||||
|
||||
const LogTagSet& ts3 = LogTagSetMapping<LOG_TAGS(logging, gc, class)>::tagset();
|
||||
EXPECT_TRUE(ts3.contains(PREFIX_LOG_TAG(logging)));
|
||||
EXPECT_TRUE(ts3.contains(PREFIX_LOG_TAG(gc)));
|
||||
EXPECT_TRUE(ts3.contains(PREFIX_LOG_TAG(class)));
|
||||
EXPECT_FALSE(ts3.contains(PREFIX_LOG_TAG(safepoint)));
|
||||
|
||||
const LogTagSet& ts4 = LogTagSetMapping<LOG_TAGS(logging, gc, class, safepoint, heap)>::tagset();
|
||||
EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(logging)));
|
||||
EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(gc)));
|
||||
EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(class)));
|
||||
EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(safepoint)));
|
||||
EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(heap)));
|
||||
}
|
||||
|
||||
TEST(LogTagSet, label) {
|
||||
char buf[256];
|
||||
const LogTagSet& ts = LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset();
|
||||
ASSERT_NE(-1, ts.label(buf, sizeof(buf)));
|
||||
EXPECT_STREQ("logging,safepoint", buf);
|
||||
// Verify using a custom separator
|
||||
ASSERT_NE(-1, ts.label(buf, sizeof(buf), "++"));
|
||||
EXPECT_STREQ("logging++safepoint", buf);
|
||||
|
||||
// Verify with three tags
|
||||
const LogTagSet& ts1 = LogTagSetMapping<LOG_TAGS(logging, safepoint, jni)>::tagset();
|
||||
ASSERT_NE(-1, ts1.label(buf, sizeof(buf)));
|
||||
EXPECT_STREQ("logging,safepoint,jni", buf);
|
||||
|
||||
// Verify with a single tag
|
||||
const LogTagSet& ts2 = LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
ASSERT_NE(-1, ts2.label(buf, sizeof(buf)));
|
||||
EXPECT_STREQ("logging", buf);
|
||||
}
|
Loading…
Reference in New Issue
Block a user