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 "logging/logFileStreamOutput.hpp"
  26 #include "logging/logLevel.hpp"
  27 #include "logging/logOutput.hpp"
  28 #include "logging/logOutputList.hpp"
  29 #include "runtime/os.hpp"
  30 #include "unittest.hpp"
  31 
  32 // Count the outputs in the given list, starting from the specified level
  33 static size_t output_count(LogOutputList* list, LogLevelType from = LogLevel::Error)  {
  34   size_t count = 0;
  35   for (LogOutputList::Iterator it = list->iterator(from); it != list->end(); it++) {
  36     count++;
  37   }
  38   return count;
  39 }
  40 
  41 // Get the level for an output in the given list
  42 static LogLevelType find_output_level(LogOutputList* list, LogOutput* o) {
  43   for (size_t levelnum = 1; levelnum < LogLevel::Count; levelnum++) {
  44     LogLevelType level = static_cast<LogLevelType>(levelnum);
  45     for (LogOutputList::Iterator it = list->iterator(level); it != list->end(); it++) {
  46       if (*it == o) {
  47         return level;
  48       }
  49     }
  50   }
  51   return LogLevel::Off;
  52 }
  53 
  54 // Create a dummy output pointer with the specified id.
  55 // This dummy pointer should not be used for anything
  56 // but pointer comparisons with other dummies.
  57 static LogOutput* dummy_output(size_t id) {
  58   return reinterpret_cast<LogOutput*>(id + 1);
  59 }
  60 
  61 // Randomly update and verify some outputs some number of times
  62 TEST(LogOutputList, set_output_level_update) {
  63   const size_t TestOutputCount = 10;
  64   const size_t TestIterations = 10000;
  65   LogOutputList list;
  66   size_t outputs_on_level[LogLevel::Count];
  67   LogLevelType expected_level_for_output[TestOutputCount];
  68 
  69   os::init_random(0x4711);
  70   for (size_t i = 0; i < LogLevel::Count; i++) {
  71     outputs_on_level[i] = 0;
  72   }
  73   outputs_on_level[LogLevel::Off] = TestOutputCount;
  74   for (size_t i = 0; i < TestOutputCount; i++) {
  75     expected_level_for_output[i] = LogLevel::Off;
  76   }
  77 
  78   for (size_t iteration = 0; iteration < TestIterations; iteration++) {
  79     size_t output_idx = os::random() % TestOutputCount;
  80     size_t levelnum = os::random() % LogLevel::Count;
  81     LogLevelType level = static_cast<LogLevelType>(levelnum);
  82 
  83     // Update the expectations
  84     outputs_on_level[expected_level_for_output[output_idx]]--;
  85     outputs_on_level[levelnum]++;
  86     expected_level_for_output[output_idx] = level;
  87 
  88     // Update the actual list
  89     list.set_output_level(dummy_output(output_idx), level);
  90 
  91     // Verify expected levels
  92     for (size_t i = 0; i < TestOutputCount; i++) {
  93       ASSERT_EQ(expected_level_for_output[i], find_output_level(&list, dummy_output(i)));
  94     }
  95     // Verify output counts
  96     size_t expected_count = 0;
  97     for (size_t i = 1; i < LogLevel::Count; i++) {
  98       expected_count += outputs_on_level[i];
  99       ASSERT_EQ(expected_count, output_count(&list, static_cast<LogLevelType>(i)));
 100     }
 101     ASSERT_EQ(TestOutputCount, expected_count + outputs_on_level[LogLevel::Off]);
 102   }
 103 }
 104 
 105 // Test removing outputs from a LogOutputList
 106 TEST(LogOutputList, set_output_level_remove) {
 107   LogOutputList list;
 108 
 109   // Add three dummy outputs per loglevel
 110   for (size_t i = 1; i < LogLevel::Count; i++) {
 111     list.set_output_level(dummy_output(i), static_cast<LogLevelType>(i));
 112     list.set_output_level(dummy_output(i*10), static_cast<LogLevelType>(i));
 113     list.set_output_level(dummy_output(i*100), static_cast<LogLevelType>(i));
 114   }
 115 
 116   // Verify that they have been added successfully
 117   // (Count - 1 since we don't count LogLevel::Off)
 118   EXPECT_EQ(3u * (LogLevel::Count - 1), output_count(&list));
 119   // Now remove the second output from each loglevel
 120   for (size_t i = 1; i < LogLevel::Count; i++) {
 121     list.set_output_level(dummy_output(i*10), LogLevel::Off);
 122   }
 123   // Make sure they have been successfully removed
 124   EXPECT_EQ(2u * (LogLevel::Count - 1), output_count(&list));
 125 
 126   // Now remove the remaining outputs
 127   for (size_t i = 1; i < LogLevel::Count; i++) {
 128     list.set_output_level(dummy_output(i), LogLevel::Off);
 129     list.set_output_level(dummy_output(i*100), LogLevel::Off);
 130   }
 131   EXPECT_EQ(0u, output_count(&list));
 132 }
 133 
 134 // Test adding to a LogOutputList
 135 TEST(LogOutputList, set_output_level_add) {
 136   LogOutputList list;
 137 
 138   // First add 5 outputs to Info level
 139   for (size_t i = 10; i < 15; i++) {
 140     list.set_output_level(dummy_output(i), LogLevel::Info);
 141   }
 142 
 143   // Verify that they have been added successfully
 144   size_t count = 0;
 145   for (LogOutputList::Iterator it = list.iterator(); it != list.end(); it++) {
 146     ASSERT_EQ(dummy_output(10 + count++), *it);
 147   }
 148   ASSERT_EQ(5u, count);
 149 
 150   // Now add more outputs, but on all different levels
 151   for (size_t i = 5; i < 10; i++) {
 152     list.set_output_level(dummy_output(i), LogLevel::Warning);
 153   }
 154   for (size_t i = 0; i < 5; i++) {
 155     list.set_output_level(dummy_output(i), LogLevel::Error);
 156   }
 157   for (size_t i = 15; i < 20; i++) {
 158     list.set_output_level(dummy_output(i), LogLevel::Debug);
 159   }
 160   for (size_t i = 20; i < 25; i++) {
 161     list.set_output_level(dummy_output(i), LogLevel::Trace);
 162   }
 163 
 164   // Verify that that all outputs have been added, and that the order is Error, Warning, Info, Debug, Trace
 165   count = 0;
 166   for (LogOutputList::Iterator it = list.iterator(); it != list.end(); it++) {
 167     ASSERT_EQ(dummy_output(count++), *it);
 168   }
 169   ASSERT_EQ(25u, count);
 170 }
 171 
 172 // Test is_level() on lists with a single output on different levels
 173 TEST(LogOutputList, is_level_single_output) {
 174   for (size_t i = LogLevel::First; i < LogLevel::Count; i++) {
 175     LogLevelType level = static_cast<LogLevelType>(i);
 176     LogOutputList list;
 177     list.set_output_level(&StdoutLog, level);
 178     for (size_t j = LogLevel::First; j < LogLevel::Count; j++) {
 179       LogLevelType other = static_cast<LogLevelType>(j);
 180       // Verify that levels finer than the current level for stdout are reported as disabled,
 181       // and levels equal to or included in the current level are reported as enabled
 182       if (other >= level) {
 183         EXPECT_TRUE(list.is_level(other))
 184           << LogLevel::name(other) << " >= " << LogLevel::name(level) << " but is_level() returns false";
 185       } else {
 186         EXPECT_FALSE(list.is_level(other))
 187           << LogLevel::name(other) << " < " << LogLevel::name(level) << " but is_level() returns true";
 188       }
 189     }
 190   }
 191 }
 192 
 193 // Test is_level() with an empty list
 194 TEST(LogOutputList, is_level_empty) {
 195   LogOutputList emptylist;
 196   for (size_t i = LogLevel::First; i < LogLevel::Count; i++) {
 197     LogLevelType other = static_cast<LogLevelType>(i);
 198     EXPECT_FALSE(emptylist.is_level(other)) << "is_level() returns true even though the list is empty";
 199   }
 200 }
 201 
 202 // Test is_level() on lists with two outputs on different levels
 203 TEST(LogOutputList, is_level_multiple_outputs) {
 204   for (size_t i = LogLevel::First; i < LogLevel::Count - 1; i++) {
 205       LogOutput* dummy1 = &StdoutLog;
 206       LogOutput* dummy2 = &StderrLog;
 207       LogLevelType first = static_cast<LogLevelType>(i);
 208       LogLevelType second = static_cast<LogLevelType>(i + 1);
 209       LogOutputList list;
 210       list.set_output_level(dummy1, first);
 211       list.set_output_level(dummy2, second);
 212       for (size_t j = LogLevel::First; j < LogLevel::Count; j++) {
 213         LogLevelType other = static_cast<LogLevelType>(j);
 214         // The first output's level will be the finest, expect it's level to be reported by the list
 215         if (other >= first) {
 216           EXPECT_TRUE(list.is_level(other))
 217             << LogLevel::name(other) << " >= " << LogLevel::name(first) << " but is_level() returns false";
 218         } else {
 219           EXPECT_FALSE(list.is_level(other))
 220             << LogLevel::name(other) << " < " << LogLevel::name(first) << " but is_level() returns true";
 221         }
 222       }
 223     }
 224 }
 225 
 226 TEST(LogOutputList, level_for) {
 227   LogOutputList list;
 228 
 229   // Ask the empty list about stdout, stderr
 230   EXPECT_EQ(LogLevel::Off, list.level_for(&StdoutLog));
 231   EXPECT_EQ(LogLevel::Off, list.level_for(&StderrLog));
 232 
 233   // Ask for level in a list with two outputs on different levels
 234   list.set_output_level(&StdoutLog, LogLevel::Info);
 235   list.set_output_level(&StderrLog, LogLevel::Trace);
 236   EXPECT_EQ(LogLevel::Info, list.level_for(&StdoutLog));
 237   EXPECT_EQ(LogLevel::Trace, list.level_for(&StderrLog));
 238 
 239   // Remove and ask again
 240   list.set_output_level(&StdoutLog, LogLevel::Off);
 241   EXPECT_EQ(LogLevel::Off, list.level_for(&StdoutLog));
 242   EXPECT_EQ(LogLevel::Trace, list.level_for(&StderrLog));
 243 
 244   // Ask about an unknown output
 245   LogOutput* dummy = dummy_output(4711);
 246   EXPECT_EQ(LogLevel::Off, list.level_for(dummy));
 247 
 248   for (size_t i = LogLevel::First; i <= LogLevel::Last; i++) {
 249     LogLevelType level = static_cast<LogLevelType>(i);
 250     list.set_output_level(dummy, level);
 251     EXPECT_EQ(level, list.level_for(dummy));
 252   }
 253 
 254   // Make sure the stderr level is still the same
 255   EXPECT_EQ(LogLevel::Trace, list.level_for(&StderrLog));
 256 }