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