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 }