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 | } |
257 | |