--- a/hotspot/src/share/vm/logging/logDecorations.hpp Sun Aug 21 20:56:37 2016 -0400
+++ b/hotspot/src/share/vm/logging/logDecorations.hpp Thu Jul 14 09:52:03 2016 +0200
@@ -53,10 +53,6 @@
LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators);
- LogLevelType level() const {
- return _level;
- }
-
void set_level(LogLevelType level) {
_level = level;
}
--- a/hotspot/src/share/vm/logging/logOutputList.hpp Sun Aug 21 20:56:37 2016 -0400
+++ b/hotspot/src/share/vm/logging/logOutputList.hpp Thu Jul 14 09:52:03 2016 +0200
@@ -60,6 +60,11 @@
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 @@
// 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:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/logTestFixture.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/logTestFixture.hpp Thu Jul 14 09:52:03 2016 +0200
@@ -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();
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/logTestUtils.inline.hpp Thu Jul 14 09:52:03 2016 +0200
@@ -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 << ")";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logConfiguration.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logDecorations.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logDecorators.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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());
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logFileOutput.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logLevel.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logOutputList.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logTag.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logTagLevelExpression.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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()));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logTagSet.cpp Thu Jul 14 09:52:03 2016 +0200
@@ -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);
+}