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   // Add a second file output
 168   char other_file_name[2 * K];
 169   jio_snprintf(other_file_name, sizeof(other_file_name), "%s-other", TestLogFileName);
 170   set_log_config(other_file_name, "logging=info");
 171 
 172   LogConfiguration::disable_logging();
 173 
 174   // Verify that both file outputs were disabled
 175   EXPECT_FALSE(is_described(TestLogFileName));
 176   EXPECT_FALSE(is_described(other_file_name));
 177   delete_file(other_file_name);
 178 
 179   // Verify that no tagset has logging enabled
 180   for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 181     EXPECT_FALSE(ts->has_output(LogOutput::Stdout));
 182     EXPECT_FALSE(ts->has_output(LogOutput::Stderr));
 183     EXPECT_FALSE(ts->is_level(LogLevel::Error));
 184   }
 185 }
 186 
 187 // Test disabling a particular output
 188 TEST_F(LogConfigurationTest, disable_output) {
 189   // Disable the default configuration for stdout
 190   set_log_config("stdout", "all=off");
 191 
 192   // Verify configuration using LogConfiguration::describe
 193   EXPECT_TRUE(is_described("#0: stdout all=off"));
 194 
 195   // Verify by iterating over tagsets
 196   LogOutput* o = LogOutput::Stdout;
 197   for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 198     EXPECT_FALSE(ts->has_output(o));
 199     EXPECT_FALSE(ts->is_level(LogLevel::Error));
 200   }
 201 
 202   // Add a new file output
 203   const char* what = "all=debug";
 204   set_log_config(TestLogFileName, what);
 205   EXPECT_TRUE(is_described(TestLogFileName));
 206 
 207   // Now disable it, verifying it is removed completely
 208   set_log_config(TestLogFileName, "all=off");
 209   EXPECT_FALSE(is_described(TestLogFileName));
 210   for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 211     EXPECT_FALSE(ts->is_level(LogLevel::Error));
 212   }
 213 }
 214 
 215 // Test reconfiguration of the selected decorators for an output
 216 TEST_F(LogConfigurationTest, reconfigure_decorators) {
 217   // Configure stderr with all decorators
 218   set_log_config("stderr", "all=off", _all_decorators);
 219   char buf[256];
 220   int ret = jio_snprintf(buf, sizeof(buf), "#1: stderr all=off %s", _all_decorators);
 221   ASSERT_NE(-1, ret);
 222   EXPECT_TRUE(is_described(buf)) << "'" << buf << "' not described after reconfiguration";
 223 
 224   // Now reconfigure logging on stderr with no decorators
 225   set_log_config("stderr", "all=off", "none");
 226   EXPECT_TRUE(is_described("#1: stderr all=off \n")) << "Expecting no decorators";
 227 }
 228 
 229 // Test that invalid options cause configuration errors
 230 TEST_F(LogConfigurationTest, invalid_configure_options) {
 231   LogConfiguration::disable_logging();
 232   const char* invalid_outputs[] = { "#2", "invalidtype=123", ":invalid/path}to*file?" };
 233   for (size_t i = 0; i < ARRAY_SIZE(invalid_outputs); i++) {
 234     EXPECT_FALSE(set_log_config(invalid_outputs[i], "", "", "", true))
 235       << "Accepted invalid output '" << invalid_outputs[i] << "'";
 236   }
 237   EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all=invalid_level"));
 238   EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("what=invalid"));
 239   EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all::invalid_decorator"));
 240 }
 241 
 242 // Test empty configuration options
 243 TEST_F(LogConfigurationTest, parse_empty_command_line_arguments) {
 244   const char* empty_variations[] = { "", ":", "::", ":::", "::::" };
 245   for (size_t i = 0; i < ARRAY_SIZE(empty_variations); i++) {
 246     const char* cmdline = empty_variations[i];
 247     bool ret = LogConfiguration::parse_command_line_arguments(cmdline);
 248     EXPECT_TRUE(ret) << "Error parsing command line arguments '" << cmdline << "'";
 249     for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 250       EXPECT_EQ(LogLevel::Unspecified, ts->level_for(LogOutput::Stdout));
 251     }
 252   }
 253 }
 254 
 255 // Test basic command line parsing & configuration
 256 TEST_F(LogConfigurationTest, parse_command_line_arguments) {
 257   // Prepare a command line for logging*=debug on stderr with all decorators
 258   int ret;
 259   char buf[256];
 260   ret = jio_snprintf(buf, sizeof(buf), "logging*=debug:stderr:%s", _all_decorators);
 261   ASSERT_NE(-1, ret);
 262 
 263   bool success = LogConfiguration::parse_command_line_arguments(buf);
 264   EXPECT_TRUE(success) << "Error parsing valid command line arguments '" << buf << "'";
 265   // Ensure the new configuration applied
 266   EXPECT_TRUE(is_described("logging=debug"));
 267   EXPECT_TRUE(is_described(_all_decorators));
 268 
 269   // Test the configuration of file outputs as well
 270   ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName);
 271   ASSERT_NE(-1, ret);
 272   EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf));
 273 }
 274 
 275 // Test split up log configuration arguments
 276 TEST_F(LogConfigurationTest, parse_log_arguments) {
 277   ResourceMark rm;
 278   stringStream ss;
 279   // Verify that it's possible to configure each individual tag
 280   for (size_t t = 1 /* Skip _NO_TAG */; t < LogTag::Count; t++) {
 281     const LogTagType tag = static_cast<LogTagType>(t);
 282     EXPECT_TRUE(LogConfiguration::parse_log_arguments("stdout", LogTag::name(tag), "", "", &ss));
 283   }
 284   // Same for each level
 285   for (size_t l = 0; l < LogLevel::Count; l++) {
 286     const LogLevelType level = static_cast<LogLevelType>(l);
 287     char expected_buf[256];
 288     int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "all=%s", LogLevel::name(level));
 289     ASSERT_NE(-1, ret);
 290     EXPECT_TRUE(LogConfiguration::parse_log_arguments("stderr", expected_buf, "", "", &ss));
 291   }
 292   // And for each decorator
 293   for (size_t d = 0; d < LogDecorators::Count; d++) {
 294     const LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
 295     EXPECT_TRUE(LogConfiguration::parse_log_arguments("#0", "", LogDecorators::name(decorator), "", &ss));
 296   }
 297   EXPECT_STREQ("", ss.as_string()) << "Error reported while parsing: " << ss.as_string();
 298 }