1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 #include "precompiled.hpp" 25 #include "logTestFixture.hpp" 26 #include "logTestUtils.inline.hpp" 27 #include "logging/logConfiguration.hpp" 28 #include "logging/logLevel.hpp" 29 #include "logging/logOutput.hpp" 30 #include "logging/logTag.hpp" 31 #include "logging/logTagSet.hpp" 32 #include "memory/resourceArea.hpp" 33 #include "unittest.hpp" 34 #include "utilities/ostream.hpp" 35 36 class LogConfigurationTest : public LogTestFixture { 37 protected: 38 static char _all_decorators[256]; 39 40 public: 41 static void SetUpTestCase(); 42 }; 43 44 char LogConfigurationTest::_all_decorators[256]; 45 46 // Prepare _all_decorators to contain the full list of decorators (comma separated) 47 void LogConfigurationTest::SetUpTestCase() { 48 char *pos = _all_decorators; 49 for (size_t i = 0; i < LogDecorators::Count; i++) { 50 pos += jio_snprintf(pos, sizeof(_all_decorators) - (pos - _all_decorators), "%s%s", 51 (i == 0 ? "" : ","), 52 LogDecorators::name(static_cast<LogDecorators::Decorator>(i))); 53 } 54 } 55 56 // Check if the given text is included by LogConfiguration::describe() 57 static bool is_described(const char* text) { 58 ResourceMark rm; 59 stringStream ss; 60 LogConfiguration::describe(&ss); 61 return string_contains_substring(ss.as_string(), text); 62 } 63 64 TEST_F(LogConfigurationTest, describe) { 65 ResourceMark rm; 66 stringStream ss; 67 LogConfiguration::describe(&ss); 68 const char* description = ss.as_string(); 69 70 // Verify that stdout and stderr are listed by default 71 EXPECT_PRED2(string_contains_substring, description, LogOutput::Stdout->name()); 72 EXPECT_PRED2(string_contains_substring, description, LogOutput::Stderr->name()); 73 74 // Verify that each tag, level and decorator is listed 75 for (size_t i = 0; i < LogTag::Count; i++) { 76 EXPECT_PRED2(string_contains_substring, description, LogTag::name(static_cast<LogTagType>(i))); 77 } 78 for (size_t i = 0; i < LogLevel::Count; i++) { 79 EXPECT_PRED2(string_contains_substring, description, LogLevel::name(static_cast<LogLevelType>(i))); 80 } 81 for (size_t i = 0; i < LogDecorators::Count; i++) { 82 EXPECT_PRED2(string_contains_substring, description, LogDecorators::name(static_cast<LogDecorators::Decorator>(i))); 83 } 84 85 // Verify that the default configuration is printed 86 char expected_buf[256]; 87 int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "=%s", LogLevel::name(LogLevel::Default)); 88 ASSERT_NE(-1, ret); 89 EXPECT_PRED2(string_contains_substring, description, expected_buf); 90 EXPECT_PRED2(string_contains_substring, description, "#1: stderr all=off"); 91 92 // Verify default decorators are listed 93 LogDecorators default_decorators; 94 expected_buf[0] = '\0'; 95 for (size_t i = 0; i < LogDecorators::Count; i++) { 96 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i); 97 if (default_decorators.is_decorator(d)) { 98 ASSERT_LT(strlen(expected_buf), sizeof(expected_buf)); 99 ret = jio_snprintf(expected_buf + strlen(expected_buf), 100 sizeof(expected_buf) - strlen(expected_buf), 101 "%s%s", 102 strlen(expected_buf) > 0 ? "," : "", 103 LogDecorators::name(d)); 104 ASSERT_NE(-1, ret); 105 } 106 } 107 EXPECT_PRED2(string_contains_substring, description, expected_buf); 108 109 // Add a new output and verify that it gets described after it has been added 110 const char* what = "all=trace"; 111 EXPECT_FALSE(is_described(TestLogFileName)) << "Test output already exists!"; 112 set_log_config(TestLogFileName, what); 113 EXPECT_TRUE(is_described(TestLogFileName)); 114 EXPECT_TRUE(is_described("logging=trace")); 115 } 116 117 // Test updating an existing log output 118 TEST_F(LogConfigurationTest, update_output) { 119 // Update stdout twice, first using it's name, and the second time its index # 120 const char* test_outputs[] = { "stdout", "#0" }; 121 for (size_t i = 0; i < ARRAY_SIZE(test_outputs); i++) { 122 set_log_config(test_outputs[i], "all=info"); 123 124 // Verify configuration using LogConfiguration::describe 125 EXPECT_TRUE(is_described("#0: stdout")); 126 EXPECT_TRUE(is_described("logging=info")); 127 128 // Verify by iterating over tagsets 129 LogOutput* o = LogOutput::Stdout; 130 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 131 EXPECT_TRUE(ts->has_output(o)); 132 EXPECT_TRUE(ts->is_level(LogLevel::Info)); 133 EXPECT_FALSE(ts->is_level(LogLevel::Debug)); 134 } 135 136 // Now change the level and verify the change propagated 137 set_log_config(test_outputs[i], "all=debug"); 138 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 139 EXPECT_TRUE(ts->has_output(o)); 140 EXPECT_TRUE(ts->is_level(LogLevel::Debug)); 141 EXPECT_FALSE(ts->is_level(LogLevel::Trace)); 142 } 143 } 144 } 145 146 // Test adding a new output to the configuration 147 TEST_F(LogConfigurationTest, add_new_output) { 148 const char* what = "all=trace"; 149 150 ASSERT_FALSE(is_described(TestLogFileName)); 151 set_log_config(TestLogFileName, what); 152 153 // Verify new output using LogConfiguration::describe 154 EXPECT_TRUE(is_described(TestLogFileName)); 155 EXPECT_TRUE(is_described("logging=trace")); 156 157 // Also verify by iterating over tagsets, checking levels on tagsets 158 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 159 EXPECT_TRUE(ts->is_level(LogLevel::Trace)); 160 } 161 } 162 163 TEST_F(LogConfigurationTest, disable_logging) { 164 // Add TestLogFileName as an output 165 set_log_config(TestLogFileName, "logging=info"); 166 167 LogConfiguration::disable_logging(); 168 169 // Verify TestLogFileName was disabled 170 EXPECT_FALSE(is_described(TestLogFileName)); 171 172 // Verify that no tagset has logging enabled 173 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 174 EXPECT_FALSE(ts->has_output(LogOutput::Stdout)); 175 EXPECT_FALSE(ts->has_output(LogOutput::Stderr)); 176 EXPECT_FALSE(ts->is_level(LogLevel::Error)); 177 } 178 } 179 180 // Test disabling a particular output 181 TEST_F(LogConfigurationTest, disable_output) { 182 // Disable the default configuration for stdout 183 set_log_config("stdout", "all=off"); 184 185 // Verify configuration using LogConfiguration::describe 186 EXPECT_TRUE(is_described("#0: stdout all=off")); 187 188 // Verify by iterating over tagsets 189 LogOutput* o = LogOutput::Stdout; 190 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 191 EXPECT_FALSE(ts->has_output(o)); 192 EXPECT_FALSE(ts->is_level(LogLevel::Error)); 193 } 194 195 // Add a new file output 196 const char* what = "all=debug"; 197 set_log_config(TestLogFileName, what); 198 EXPECT_TRUE(is_described(TestLogFileName)); 199 200 // Now disable it, verifying it is removed completely 201 set_log_config(TestLogFileName, "all=off"); 202 EXPECT_FALSE(is_described(TestLogFileName)); 203 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 204 EXPECT_FALSE(ts->is_level(LogLevel::Error)); 205 } 206 } 207 208 // Test reconfiguration of the selected decorators for an output 209 TEST_F(LogConfigurationTest, reconfigure_decorators) { 210 // Configure stderr with all decorators 211 set_log_config("stderr", "all=off", _all_decorators); 212 char buf[256]; 213 int ret = jio_snprintf(buf, sizeof(buf), "#1: stderr all=off %s", _all_decorators); 214 ASSERT_NE(-1, ret); 215 EXPECT_TRUE(is_described(buf)) << "'" << buf << "' not described after reconfiguration"; 216 217 // Now reconfigure logging on stderr with no decorators 218 set_log_config("stderr", "all=off", "none"); 219 EXPECT_TRUE(is_described("#1: stderr all=off \n")) << "Expecting no decorators"; 220 } 221 222 // Test that invalid options cause configuration errors 223 TEST_F(LogConfigurationTest, invalid_configure_options) { 224 LogConfiguration::disable_logging(); 225 const char* invalid_outputs[] = { "#2", "invalidtype=123", ":invalid/path}to*file?" }; 226 for (size_t i = 0; i < ARRAY_SIZE(invalid_outputs); i++) { 227 EXPECT_FALSE(set_log_config(invalid_outputs[i], "", "", "", true)) 228 << "Accepted invalid output '" << invalid_outputs[i] << "'"; 229 } 230 EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all=invalid_level")); 231 EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("what=invalid")); 232 EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all::invalid_decorator")); 233 } 234 235 // Test empty configuration options 236 TEST_F(LogConfigurationTest, parse_empty_command_line_arguments) { 237 const char* empty_variations[] = { "", ":", "::", ":::", "::::" }; 238 for (size_t i = 0; i < ARRAY_SIZE(empty_variations); i++) { 239 const char* cmdline = empty_variations[i]; 240 bool ret = LogConfiguration::parse_command_line_arguments(cmdline); 241 EXPECT_TRUE(ret) << "Error parsing command line arguments '" << cmdline << "'"; 242 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 243 EXPECT_EQ(LogLevel::Unspecified, ts->level_for(LogOutput::Stdout)); 244 } 245 } 246 } 247 248 // Test basic command line parsing & configuration 249 TEST_F(LogConfigurationTest, parse_command_line_arguments) { 250 // Prepare a command line for logging*=debug on stderr with all decorators 251 int ret; 252 char buf[256]; 253 ret = jio_snprintf(buf, sizeof(buf), "logging*=debug:stderr:%s", _all_decorators); 254 ASSERT_NE(-1, ret); 255 256 bool success = LogConfiguration::parse_command_line_arguments(buf); 257 EXPECT_TRUE(success) << "Error parsing valid command line arguments '" << buf << "'"; 258 // Ensure the new configuration applied 259 EXPECT_TRUE(is_described("logging=debug")); 260 EXPECT_TRUE(is_described(_all_decorators)); 261 262 // Test the configuration of file outputs as well 263 ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName); 264 ASSERT_NE(-1, ret); 265 EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); 266 } 267 268 // Test split up log configuration arguments 269 TEST_F(LogConfigurationTest, parse_log_arguments) { 270 ResourceMark rm; 271 stringStream ss; 272 // Verify that it's possible to configure each individual tag 273 for (size_t t = 1 /* Skip _NO_TAG */; t < LogTag::Count; t++) { 274 const LogTagType tag = static_cast<LogTagType>(t); 275 EXPECT_TRUE(LogConfiguration::parse_log_arguments("stdout", LogTag::name(tag), "", "", &ss)); 276 } 277 // Same for each level 278 for (size_t l = 0; l < LogLevel::Count; l++) { 279 const LogLevelType level = static_cast<LogLevelType>(l); 280 char expected_buf[256]; 281 int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "all=%s", LogLevel::name(level)); 282 ASSERT_NE(-1, ret); 283 EXPECT_TRUE(LogConfiguration::parse_log_arguments("stderr", expected_buf, "", "", &ss)); 284 } 285 // And for each decorator 286 for (size_t d = 0; d < LogDecorators::Count; d++) { 287 const LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d); 288 EXPECT_TRUE(LogConfiguration::parse_log_arguments("#0", "", LogDecorators::name(decorator), "", &ss)); 289 } 290 EXPECT_STREQ("", ss.as_string()) << "Error reported while parsing: " << ss.as_string(); 291 }