This commit is contained in:
Christian Tornqvist 2016-08-23 17:27:56 +00:00
commit 3d2138fde0
16 changed files with 1686 additions and 28 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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:

View File

@ -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;
}
}

View 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");
}

View 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();
};

View 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 << ")";
}

View 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();
}

View 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));
}
}

View 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());
}

View 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";
}

View 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
}

View 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));
}

View 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
}

View 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()));
}

View 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);
}