1/*
2 * Copyright (c) 2016, 2018, 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 "jvm.h"
26#include "logging/logLevel.hpp"
27#include "logging/logSelection.hpp"
28#include "logging/logTagSet.hpp"
29#include "utilities/globalDefinitions.hpp"
30#include "logTestUtils.inline.hpp"
31#include "unittest.hpp"
32
33// These tests can only run in debug VMs because they rely on the (debug-only) LogTag::_test
34#ifdef ASSERT
35
36#define NON_EXISTING_TAG_SET "logging+test+start+exit+safepoint"
37
38// let google test know how to print LogSelection nicely for better error messages
39void PrintTo(const LogSelection& sel, ::std::ostream* os) {
40 if (sel == LogSelection::Invalid) {
41 *os << "LogSelection::Invalid";
42 return;
43 }
44 char buf[256];
45 sel.describe(buf, sizeof(buf));
46 *os << buf;
47}
48
49TEST(LogSelection, sanity) {
50 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
51 LogSelection selection(tags, false, LogLevel::Trace);
52
53 EXPECT_EQ(2u, selection.ntags());
54 EXPECT_EQ(LogLevel::Trace, selection.level());
55
56 // Verify that copying the selection also works as expected
57 LogSelection copy = selection;
58 EXPECT_EQ(2u, copy.ntags());
59 EXPECT_EQ(LogLevel::Trace, copy.level());
60
61 tags[0] = PREFIX_LOG_TAG(gc);
62 tags[1] = PREFIX_LOG_TAG(_NO_TAG);
63 LogSelection copy2(tags, true, LogLevel::Off); // start with a completely different selection
64 copy2 = selection; // and test copy assignment
65 EXPECT_EQ(2u, copy2.ntags());
66 EXPECT_EQ(LogLevel::Trace, copy2.level());
67}
68
69TEST(LogSelection, tag_sets_selected) {
70 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
71 LogSelection selection(tags, false, LogLevel::Trace);
72
73 EXPECT_EQ(1u, selection.tag_sets_selected()) << "there should be a single (it's not a wildcard selection) "
74 "tag set selected by this (in gtest libjvm)";
75
76 EXPECT_EQ(LogTagSet::ntagsets(), LogSelection::parse("all").tag_sets_selected()) << "all should select every tag set";
77 EXPECT_EQ(0u, LogSelection::parse(NON_EXISTING_TAG_SET).tag_sets_selected()) <<
78 "(assuming the tag set doesn't exist) the selection shouldn't select any tag sets";
79}
80
81static const char* valid_expression[] = {
82 "all", "gc", "gc+logging", "logging+gc", "logging+gc*", "gc=trace",
83 "logging+gc=trace", "logging*", "logging*=info", "gc+logging*=error"
84};
85
86TEST(LogSelection, parse) {
87 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
88 LogSelection selection(tags, true, LogLevel::Off);
89 LogSelection parsed = LogSelection::parse("logging+test*=off");
90 EXPECT_EQ(selection, parsed) << "parsed selection not equal to programmatically constructed";
91
92 // Verify valid expressions parse without problems
93 for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
94 EXPECT_NE(LogSelection::Invalid, LogSelection::parse(valid_expression[i])) <<
95 "Valid expression '" << valid_expression[i] << "' did not parse";
96 }
97
98 // Test 'all' with each level
99 for (LogLevelType level = LogLevel::First; level <= LogLevel::Last; level = static_cast<LogLevelType>(level + 1)) {
100 char buf[64];
101 int ret = jio_snprintf(buf, sizeof(buf), "all=%s", LogLevel::name(level));
102 ASSERT_NE(-1, ret);
103
104 LogSelection sel = LogSelection::parse(buf);
105 EXPECT_EQ(LogTagSet::ntagsets(), sel.tag_sets_selected()) << "'all' should select all tag sets";
106 EXPECT_EQ(level, sel.level());
107 }
108
109 // Test with 5 tags
110 LogTagType expected_tags[] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(start),
111 PREFIX_LOG_TAG(exit), PREFIX_LOG_TAG(safepoint) };
112 LogSelection expected(expected_tags, false, LogLevel::Debug);
113 LogSelection five_tag_selection = LogSelection::parse("logging+test+start+exit+safepoint=debug");
114 EXPECT_EQ(5u, five_tag_selection.ntags()) << "parsed wrong number of tags";
115 EXPECT_EQ(expected, five_tag_selection);
116 EXPECT_EQ(LogLevel::Debug, five_tag_selection.level());
117
118 // Test implicit level
119 selection = LogSelection::parse("logging");
120 EXPECT_EQ(LogLevel::Unspecified, selection.level()) << "parsed implicit level incorrectly";
121 EXPECT_EQ(1u, selection.ntags());
122}
123
124TEST(LogSelection, parse_invalid) {
125
126 // Attempt to parse an expression with too many tags
127 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(NON_EXISTING_TAG_SET "+gc"));
128
129 // Construct a bunch of invalid expressions and verify that they don't parse
130 for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
131 char buf[256];
132 for (size_t j = 0; j < ARRAY_SIZE(invalid_selection_substr); j++) {
133 // Prefix with invalid substr
134 jio_snprintf(buf, sizeof(buf), "%s%s", invalid_selection_substr[j], valid_expression[i]);
135 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
136
137 // Suffix with invalid substr
138 jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_selection_substr[j]);
139 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
140
141 // Use only the invalid substr
142 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(invalid_selection_substr[j])) <<
143 "'" << invalid_selection_substr[j] << "'" << " considered legal";
144 }
145
146 // Suffix/prefix with some unique invalid prefixes/suffixes
147 jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
148 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
149
150 jio_snprintf(buf, sizeof(buf), "logging*%s", valid_expression[i]);
151 EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
152 }
153}
154
155TEST(LogSelection, equals) {
156 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
157 LogSelection selection(tags, true, LogLevel::Info);
158 LogSelection copy(tags, true, LogLevel::Info);
159 EXPECT_EQ(selection, selection);
160 EXPECT_EQ(selection, copy);
161
162 tags[0] = PREFIX_LOG_TAG(gc);
163 LogSelection other_tags(tags, true, LogLevel::Info);
164 EXPECT_NE(selection, other_tags);
165
166 tags[0] = PREFIX_LOG_TAG(test);
167 tags[1] = PREFIX_LOG_TAG(logging);
168 LogSelection reversed(tags, true, LogLevel::Info);
169 EXPECT_NE(selection, reversed);
170
171 LogSelection no_wildcard(tags, false, LogLevel::Info);
172 EXPECT_NE(selection, no_wildcard);
173
174 LogSelection different_level(tags, true, LogLevel::Warning);
175 EXPECT_NE(selection, different_level);
176
177 tags[2] = PREFIX_LOG_TAG(gc);
178 tags[3] = PREFIX_LOG_TAG(_NO_TAG);
179 LogSelection more_tags(tags, true, LogLevel::Info);
180 EXPECT_NE(selection, more_tags);
181
182 tags[1] = PREFIX_LOG_TAG(_NO_TAG);
183 LogSelection fewer_tags(tags, true, LogLevel::Info);
184 EXPECT_NE(selection, fewer_tags);
185}
186
187TEST(LogSelection, consists_of) {
188 LogTagType tags[LogTag::MaxTags] = {
189 PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG)
190 };
191 LogSelection s(tags, false, LogLevel::Off);
192 EXPECT_TRUE(s.consists_of(tags));
193
194 tags[2] = PREFIX_LOG_TAG(safepoint);
195 EXPECT_FALSE(s.consists_of(tags));
196
197 s = LogSelection(tags, true, LogLevel::Info);
198 EXPECT_TRUE(s.consists_of(tags));
199}
200
201TEST(LogSelection, describe_tags) {
202 char buf[256];
203 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
204 LogSelection selection(tags, true, LogLevel::Off);
205 selection.describe_tags(buf, sizeof(buf));
206 EXPECT_STREQ("logging+test*", buf);
207}
208
209TEST(LogSelection, describe) {
210 char buf[256];
211 LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
212 LogSelection selection(tags, true, LogLevel::Off);
213 selection.describe(buf, sizeof(buf));
214 EXPECT_STREQ("logging+test*=off", buf);
215}
216
217#endif
218