Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/hotspot/gtest/logging/test_logConfiguration.cpp
64438 views
1
/*
2
* Copyright (c) 2016, 2022, 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 "concurrentTestRunner.inline.hpp"
27
#include "logTestFixture.hpp"
28
#include "logTestUtils.inline.hpp"
29
#include "logging/logConfiguration.hpp"
30
#include "logging/logFileStreamOutput.hpp"
31
#include "logging/logLevel.hpp"
32
#include "logging/logOutput.hpp"
33
#include "logging/logTag.hpp"
34
#include "logging/logTagSet.hpp"
35
#include "memory/resourceArea.hpp"
36
#include "unittest.hpp"
37
#include "utilities/ostream.hpp"
38
39
class LogConfigurationTest : public LogTestFixture {
40
protected:
41
static char _all_decorators[256];
42
43
public:
44
static void SetUpTestCase();
45
};
46
47
char LogConfigurationTest::_all_decorators[256];
48
49
// Prepare _all_decorators to contain the full list of decorators (comma separated)
50
void LogConfigurationTest::SetUpTestCase() {
51
char *pos = _all_decorators;
52
for (size_t i = 0; i < LogDecorators::Count; i++) {
53
pos += jio_snprintf(pos, sizeof(_all_decorators) - (pos - _all_decorators), "%s%s",
54
(i == 0 ? "" : ","),
55
LogDecorators::name(static_cast<LogDecorators::Decorator>(i)));
56
}
57
}
58
59
// Check if the given text is included by LogConfiguration::describe()
60
static bool is_described(const char* text) {
61
ResourceMark rm;
62
stringStream ss;
63
LogConfiguration::describe(&ss);
64
return string_contains_substring(ss.as_string(), text);
65
}
66
67
TEST_VM_F(LogConfigurationTest, describe) {
68
ResourceMark rm;
69
stringStream ss;
70
LogConfiguration::describe(&ss);
71
const char* description = ss.as_string();
72
73
// Verify that stdout and stderr are listed by default
74
EXPECT_PRED2(string_contains_substring, description, StdoutLog.name());
75
EXPECT_PRED2(string_contains_substring, description, StderrLog.name());
76
77
// Verify that each tag, level and decorator is listed
78
for (size_t i = 0; i < LogTag::Count; i++) {
79
EXPECT_PRED2(string_contains_substring, description, LogTag::name(static_cast<LogTagType>(i)));
80
}
81
for (size_t i = 0; i < LogLevel::Count; i++) {
82
EXPECT_PRED2(string_contains_substring, description, LogLevel::name(static_cast<LogLevelType>(i)));
83
}
84
for (size_t i = 0; i < LogDecorators::Count; i++) {
85
EXPECT_PRED2(string_contains_substring, description, LogDecorators::name(static_cast<LogDecorators::Decorator>(i)));
86
}
87
88
// Verify that the default configuration is printed
89
char expected_buf[256];
90
int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "=%s", LogLevel::name(LogLevel::Default));
91
ASSERT_NE(-1, ret);
92
EXPECT_PRED2(string_contains_substring, description, expected_buf);
93
EXPECT_PRED2(string_contains_substring, description, "#1: stderr all=off");
94
95
// Verify default decorators are listed
96
LogDecorators default_decorators;
97
expected_buf[0] = '\0';
98
for (size_t i = 0; i < LogDecorators::Count; i++) {
99
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
100
if (default_decorators.is_decorator(d)) {
101
ASSERT_LT(strlen(expected_buf), sizeof(expected_buf));
102
ret = jio_snprintf(expected_buf + strlen(expected_buf),
103
sizeof(expected_buf) - strlen(expected_buf),
104
"%s%s",
105
strlen(expected_buf) > 0 ? "," : "",
106
LogDecorators::name(d));
107
ASSERT_NE(-1, ret);
108
}
109
}
110
EXPECT_PRED2(string_contains_substring, description, expected_buf);
111
112
// Add a new output and verify that it gets described after it has been added
113
const char* what = "all=trace";
114
EXPECT_FALSE(is_described(TestLogFileName)) << "Test output already exists!";
115
set_log_config(TestLogFileName, what);
116
EXPECT_TRUE(is_described(TestLogFileName));
117
EXPECT_TRUE(is_described("all=trace"));
118
}
119
120
// Test updating an existing log output
121
TEST_VM_F(LogConfigurationTest, update_output) {
122
// Update stdout twice, first using it's name, and the second time its index #
123
const char* test_outputs[] = { "stdout", "#0" };
124
for (size_t i = 0; i < ARRAY_SIZE(test_outputs); i++) {
125
set_log_config(test_outputs[i], "all=info");
126
127
// Verify configuration using LogConfiguration::describe
128
EXPECT_TRUE(is_described("#0: stdout"));
129
EXPECT_TRUE(is_described("all=info"));
130
131
// Verify by iterating over tagsets
132
LogOutput* o = &StdoutLog;
133
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
134
EXPECT_TRUE(ts->has_output(o));
135
EXPECT_TRUE(ts->is_level(LogLevel::Info));
136
EXPECT_FALSE(ts->is_level(LogLevel::Debug));
137
}
138
139
// Now change the level and verify the change propagated
140
set_log_config(test_outputs[i], "all=debug");
141
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
142
EXPECT_TRUE(ts->has_output(o));
143
EXPECT_TRUE(ts->is_level(LogLevel::Debug));
144
EXPECT_FALSE(ts->is_level(LogLevel::Trace));
145
}
146
}
147
}
148
149
// Test adding a new output to the configuration
150
TEST_VM_F(LogConfigurationTest, add_new_output) {
151
const char* what = "all=trace";
152
153
ASSERT_FALSE(is_described(TestLogFileName));
154
set_log_config(TestLogFileName, what);
155
156
// Verify new output using LogConfiguration::describe
157
EXPECT_TRUE(is_described(TestLogFileName));
158
EXPECT_TRUE(is_described("all=trace"));
159
160
// Also verify by iterating over tagsets, checking levels on tagsets
161
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
162
EXPECT_TRUE(ts->is_level(LogLevel::Trace));
163
}
164
}
165
166
TEST_VM_F(LogConfigurationTest, disable_logging) {
167
// Add TestLogFileName as an output
168
set_log_config(TestLogFileName, "logging=info");
169
170
// Add a second file output
171
char other_file_name[2 * K];
172
jio_snprintf(other_file_name, sizeof(other_file_name), "%s-other", TestLogFileName);
173
set_log_config(other_file_name, "logging=info");
174
175
LogConfiguration::disable_logging();
176
177
// Verify that both file outputs were disabled
178
EXPECT_FALSE(is_described(TestLogFileName));
179
EXPECT_FALSE(is_described(other_file_name));
180
delete_file(other_file_name);
181
182
// Verify that no tagset has logging enabled
183
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
184
EXPECT_FALSE(ts->has_output(&StdoutLog));
185
EXPECT_FALSE(ts->has_output(&StderrLog));
186
EXPECT_FALSE(ts->is_level(LogLevel::Error));
187
}
188
}
189
190
// Test disabling a particular output
191
TEST_VM_F(LogConfigurationTest, disable_output) {
192
// Disable the default configuration for stdout
193
set_log_config("stdout", "all=off");
194
195
// Verify configuration using LogConfiguration::describe
196
EXPECT_TRUE(is_described("#0: stdout all=off"));
197
198
// Verify by iterating over tagsets
199
LogOutput* o = &StdoutLog;
200
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
201
EXPECT_FALSE(ts->has_output(o));
202
EXPECT_FALSE(ts->is_level(LogLevel::Error));
203
}
204
205
// Add a new file output
206
const char* what = "all=debug";
207
set_log_config(TestLogFileName, what);
208
EXPECT_TRUE(is_described(TestLogFileName));
209
210
// Now disable it, verifying it is removed completely
211
set_log_config(TestLogFileName, "all=off");
212
EXPECT_FALSE(is_described(TestLogFileName));
213
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
214
EXPECT_FALSE(ts->is_level(LogLevel::Error));
215
}
216
}
217
218
// Test reconfiguration of the selected decorators for an output
219
TEST_VM_F(LogConfigurationTest, reconfigure_decorators) {
220
// Configure stderr with all decorators
221
set_log_config("stderr", "all=off", _all_decorators);
222
char buf[256];
223
int ret = jio_snprintf(buf, sizeof(buf), "#1: stderr all=off %s", _all_decorators);
224
ASSERT_NE(-1, ret);
225
EXPECT_TRUE(is_described(buf)) << "'" << buf << "' not described after reconfiguration";
226
227
// Now reconfigure logging on stderr with no decorators
228
set_log_config("stderr", "all=off", "none");
229
EXPECT_TRUE(is_described("#1: stderr all=off none (reconfigured)\n")) << "Expecting no decorators";
230
}
231
232
class ConcurrentLogsite : public TestRunnable {
233
int _id;
234
235
public:
236
ConcurrentLogsite(int id) : _id(id) {}
237
void runUnitTest() const override {
238
log_debug(logging)("ConcurrentLogsite %d emits a log", _id);
239
}
240
};
241
242
// Dynamically change decorators while loggings are emitting.
243
TEST_VM_F(LogConfigurationTest, reconfigure_decorators_MT) {
244
const int nrOfThreads = 2;
245
ConcurrentLogsite logsites[nrOfThreads] = {0, 1};
246
Semaphore done(0);
247
const long testDurationMillis = 1000;
248
UnitTestThread* t[nrOfThreads];
249
250
set_log_config(TestLogFileName, "logging=debug", "none", "filecount=0");
251
set_log_config("stdout", "all=off", "none");
252
set_log_config("stderr", "all=off", "none");
253
for (int i = 0; i < nrOfThreads; ++i) {
254
t[i] = new UnitTestThread(&logsites[i], &done, testDurationMillis);
255
}
256
257
for (int i = 0; i < nrOfThreads; i++) {
258
t[i]->doit();
259
}
260
261
jlong time_start = os::elapsed_counter();
262
while (true) {
263
jlong elapsed = (jlong)TimeHelper::counter_to_millis(os::elapsed_counter() - time_start);
264
if (elapsed > testDurationMillis) {
265
break;
266
}
267
268
// Take turn logging with different decorators, either None or All.
269
set_log_config(TestLogFileName, "logging=debug", "none");
270
set_log_config(TestLogFileName, "logging=debug", _all_decorators);
271
}
272
273
for (int i = 0; i < nrOfThreads; ++i) {
274
done.wait();
275
}
276
}
277
278
// Dynamically change tags while loggings are emitting.
279
TEST_VM_F(LogConfigurationTest, reconfigure_tags_MT) {
280
const int nrOfThreads = 2;
281
ConcurrentLogsite logsites[nrOfThreads] = {0, 1};
282
Semaphore done(0);
283
const long testDurationMillis = 1000;
284
UnitTestThread* t[nrOfThreads];
285
286
set_log_config(TestLogFileName, "logging=debug", "", "filecount=0");
287
set_log_config("stdout", "all=off", "none");
288
set_log_config("stderr", "all=off", "none");
289
290
for (int i = 0; i < nrOfThreads; ++i) {
291
t[i] = new UnitTestThread(&logsites[i], &done, testDurationMillis);
292
}
293
294
for (int i = 0; i < nrOfThreads; i++) {
295
t[i]->doit();
296
}
297
298
jlong time_start = os::elapsed_counter();
299
while (true) {
300
jlong elapsed = (jlong)TimeHelper::counter_to_millis(os::elapsed_counter() - time_start);
301
if (elapsed > testDurationMillis) {
302
break;
303
}
304
305
// turn on/off the tagset 'logging'.
306
set_log_config(TestLogFileName, "logging=off");
307
set_log_config(TestLogFileName, "logging=debug", "", "filecount=0");
308
// sleep a prime number milliseconds to allow concurrent logsites to write logs
309
os::naked_short_nanosleep(37);
310
}
311
312
for (int i = 0; i < nrOfThreads; ++i) {
313
done.wait();
314
}
315
}
316
317
// Test that invalid options cause configuration errors
318
TEST_VM_F(LogConfigurationTest, invalid_configure_options) {
319
LogConfiguration::disable_logging();
320
const char* invalid_outputs[] = { "#2", "invalidtype=123", ":invalid/path}to*file?" };
321
for (size_t i = 0; i < ARRAY_SIZE(invalid_outputs); i++) {
322
EXPECT_FALSE(set_log_config(invalid_outputs[i], "", "", "", true))
323
<< "Accepted invalid output '" << invalid_outputs[i] << "'";
324
}
325
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all=invalid_level"));
326
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("what=invalid"));
327
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("all::invalid_decorator"));
328
EXPECT_FALSE(LogConfiguration::parse_command_line_arguments("*"));
329
}
330
331
// Test empty configuration options
332
TEST_VM_F(LogConfigurationTest, parse_empty_command_line_arguments) {
333
const char* empty_variations[] = { "", ":", "::", ":::", "::::" };
334
for (size_t i = 0; i < ARRAY_SIZE(empty_variations); i++) {
335
const char* cmdline = empty_variations[i];
336
bool ret = LogConfiguration::parse_command_line_arguments(cmdline);
337
EXPECT_TRUE(ret) << "Error parsing command line arguments '" << cmdline << "'";
338
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
339
EXPECT_EQ(LogLevel::Unspecified, ts->level_for(&StdoutLog));
340
}
341
}
342
}
343
344
// Test basic command line parsing & configuration
345
TEST_VM_F(LogConfigurationTest, parse_command_line_arguments) {
346
// Prepare a command line for logging*=debug on stderr with all decorators
347
int ret;
348
char buf[256];
349
ret = jio_snprintf(buf, sizeof(buf), "logging*=debug:stderr:%s", _all_decorators);
350
ASSERT_NE(-1, ret);
351
352
bool success = LogConfiguration::parse_command_line_arguments(buf);
353
EXPECT_TRUE(success) << "Error parsing valid command line arguments '" << buf << "'";
354
// Ensure the new configuration applied
355
EXPECT_TRUE(is_described("logging*=debug"));
356
EXPECT_TRUE(is_described(_all_decorators));
357
358
// Test the configuration of file outputs as well
359
ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName);
360
ASSERT_NE(-1, ret);
361
EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf));
362
363
#ifdef _WINDOWS
364
// We need to test the special-case parsing for drive letters in
365
// log file paths e.g. c:\log.txt and c:/log.txt. Our temp directory
366
// based TestLogFileName should already be the \ format (we print it
367
// below to visually verify) so we only need to convert to /.
368
printf("Checked: %s\n", buf);
369
// First disable logging so the current log file will be closed and we
370
// can delete it, so that UL won't try to perform log file rotation.
371
// The rotated file would not be auto-deleted.
372
set_log_config(TestLogFileName, "all=off");
373
delete_file(TestLogFileName);
374
375
// now convert \ to /
376
char* current_pos = strchr(buf,'\\');
377
while (current_pos != nullptr) {
378
*current_pos = '/';
379
current_pos = strchr(current_pos + 1, '\\');
380
}
381
printf("Checking: %s\n", buf);
382
EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf));
383
#endif
384
385
}
386
387
// Test split up log configuration arguments
388
TEST_VM_F(LogConfigurationTest, parse_log_arguments) {
389
ResourceMark rm;
390
stringStream ss;
391
// Verify that it's possible to configure each individual tag
392
for (size_t t = 1 /* Skip _NO_TAG */; t < LogTag::Count; t++) {
393
const LogTagType tag = static_cast<LogTagType>(t);
394
EXPECT_TRUE(LogConfiguration::parse_log_arguments("stdout", LogTag::name(tag), "", "", &ss));
395
}
396
// Same for each level
397
for (size_t l = 0; l < LogLevel::Count; l++) {
398
const LogLevelType level = static_cast<LogLevelType>(l);
399
char expected_buf[256];
400
int ret = jio_snprintf(expected_buf, sizeof(expected_buf), "all=%s", LogLevel::name(level));
401
ASSERT_NE(-1, ret);
402
EXPECT_TRUE(LogConfiguration::parse_log_arguments("stderr", expected_buf, "", "", &ss));
403
}
404
// And for each decorator
405
for (size_t d = 0; d < LogDecorators::Count; d++) {
406
const LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
407
EXPECT_TRUE(LogConfiguration::parse_log_arguments("#0", "", LogDecorators::name(decorator), "", &ss));
408
}
409
}
410
411
TEST_VM_F(LogConfigurationTest, configure_stdout) {
412
// Start out with all logging disabled
413
LogConfiguration::disable_logging();
414
415
// Enable 'logging=info', verifying it has been set
416
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(logging));
417
EXPECT_TRUE(log_is_enabled(Info, logging));
418
EXPECT_FALSE(log_is_enabled(Debug, logging));
419
EXPECT_FALSE(log_is_enabled(Info, gc));
420
LogTagSet* logging_ts = &LogTagSetMapping<LOG_TAGS(logging)>::tagset();
421
EXPECT_EQ(LogLevel::Info, logging_ts->level_for(&StdoutLog));
422
423
// Enable 'gc=debug' (no wildcard), verifying no other tags are enabled
424
LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
425
EXPECT_TRUE(log_is_enabled(Debug, gc));
426
EXPECT_TRUE(log_is_enabled(Info, logging));
427
EXPECT_FALSE(log_is_enabled(Debug, gc, heap));
428
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
429
if (ts->contains(PREFIX_LOG_TAG(gc))) {
430
if (ts->ntags() == 1) {
431
EXPECT_EQ(LogLevel::Debug, ts->level_for(&StdoutLog));
432
} else {
433
EXPECT_EQ(LogLevel::Off, ts->level_for(&StdoutLog));
434
}
435
}
436
}
437
438
// Enable 'gc*=trace' (with wildcard), verifying that all tag combinations with gc are enabled (gc+...)
439
LogConfiguration::configure_stdout(LogLevel::Trace, false, LOG_TAGS(gc));
440
EXPECT_TRUE(log_is_enabled(Trace, gc));
441
EXPECT_TRUE(log_is_enabled(Trace, gc, heap));
442
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
443
if (ts->contains(PREFIX_LOG_TAG(gc))) {
444
EXPECT_EQ(LogLevel::Trace, ts->level_for(&StdoutLog));
445
} else if (ts == logging_ts) {
446
// Previous setting for 'logging' should remain
447
EXPECT_EQ(LogLevel::Info, ts->level_for(&StdoutLog));
448
} else {
449
EXPECT_EQ(LogLevel::Off, ts->level_for(&StdoutLog));
450
}
451
}
452
453
// Disable 'gc*' and 'logging', verifying all logging is properly disabled
454
LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(logging));
455
EXPECT_FALSE(log_is_enabled(Error, logging));
456
LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(gc));
457
EXPECT_FALSE(log_is_enabled(Error, gc));
458
EXPECT_FALSE(log_is_enabled(Error, gc, heap));
459
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
460
EXPECT_EQ(LogLevel::Off, ts->level_for(&StdoutLog));
461
}
462
}
463
464
static int Test_logconfiguration_subscribe_triggered = 0;
465
static void Test_logconfiguration_subscribe_helper() {
466
Test_logconfiguration_subscribe_triggered++;
467
}
468
469
TEST_VM_F(LogConfigurationTest, subscribe) {
470
ResourceMark rm;
471
Log(logging) log;
472
set_log_config("stdout", "logging*=trace");
473
474
LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper);
475
476
LogStream ls(log.error());
477
LogConfiguration::parse_log_arguments("stdout", "logging=trace", NULL, NULL, &ls);
478
ASSERT_EQ(1, Test_logconfiguration_subscribe_triggered);
479
480
LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
481
ASSERT_EQ(2, Test_logconfiguration_subscribe_triggered);
482
483
LogConfiguration::disable_logging();
484
ASSERT_EQ(3, Test_logconfiguration_subscribe_triggered);
485
}
486
487
TEST_VM_F(LogConfigurationTest, parse_invalid_tagset) {
488
static const char* invalid_tagset = "logging+start+exit+safepoint+gc"; // Must not exist for test to function.
489
490
// Make sure warning is produced if one or more configured tagsets are invalid
491
ResourceMark rm;
492
stringStream ss;
493
bool success = LogConfiguration::parse_log_arguments("stdout", invalid_tagset, NULL, NULL, &ss);
494
const char* msg = ss.as_string();
495
EXPECT_TRUE(success) << "Should only cause a warning, not an error";
496
EXPECT_TRUE(string_contains_substring(msg, "No tag set matches selection:"));
497
EXPECT_TRUE(string_contains_substring(msg, invalid_tagset));
498
}
499
500
TEST_VM_F(LogConfigurationTest, output_name_normalization) {
501
const char* patterns[] = { "%s", "file=%s", "\"%s\"", "file=\"%s\"" };
502
char buf[1 * K];
503
for (size_t i = 0; i < ARRAY_SIZE(patterns); i++) {
504
int ret = jio_snprintf(buf, sizeof(buf), patterns[i], TestLogFileName);
505
ASSERT_NE(-1, ret);
506
set_log_config(buf, "logging=trace");
507
EXPECT_TRUE(is_described("#2: "));
508
EXPECT_TRUE(is_described(TestLogFileName));
509
EXPECT_FALSE(is_described("#3: "))
510
<< "duplicate file output due to incorrect normalization for pattern: " << patterns[i];
511
}
512
513
// Make sure prefixes are ignored when used within quotes
514
// (this should create a log with "file=" in its filename)
515
// Note that the filename cannot contain directories because
516
// it is being prefixed with "file=".
517
const char* leafFileName = "\"file=leaf_file_name\"";
518
set_log_config(leafFileName, "logging=trace");
519
EXPECT_TRUE(is_described("#3: ")) << "prefix within quotes not ignored as it should be";
520
set_log_config(leafFileName, "all=off");
521
522
// Remove the extra log file created
523
delete_file("file=leaf_file_name");
524
}
525
526
static size_t count_occurrences(const char* haystack, const char* needle) {
527
size_t count = 0;
528
for (const char* p = strstr(haystack, needle); p != NULL; p = strstr(p + 1, needle)) {
529
count++;
530
}
531
return count;
532
}
533
534
TEST_OTHER_VM(LogConfiguration, output_reconfigured) {
535
ResourceMark rm;
536
stringStream ss;
537
538
EXPECT_FALSE(is_described("(reconfigured)"));
539
540
bool success = LogConfiguration::parse_log_arguments("#1", "all=warning", NULL, NULL, &ss);
541
ASSERT_TRUE(success);
542
EXPECT_EQ(0u, ss.size());
543
544
LogConfiguration::describe(&ss);
545
EXPECT_EQ(1u, count_occurrences(ss.as_string(), "(reconfigured)"));
546
547
ss.reset();
548
LogConfiguration::configure_stdout(LogLevel::Info, false, LOG_TAGS(logging));
549
LogConfiguration::describe(&ss);
550
EXPECT_EQ(2u, count_occurrences(ss.as_string(), "(reconfigured)"));
551
}
552
553
TEST_VM_F(LogConfigurationTest, suggest_similar_selection) {
554
static const char* nonexisting_tagset = "logging+start+exit+safepoint+gc";
555
556
ResourceMark rm;
557
stringStream ss;
558
LogConfiguration::parse_log_arguments("stdout", nonexisting_tagset, NULL, NULL, &ss);
559
560
const char* suggestion = ss.as_string();
561
SCOPED_TRACE(suggestion);
562
EXPECT_TRUE(string_contains_substring(ss.as_string(), "Did you mean any of the following?"));
563
EXPECT_TRUE(string_contains_substring(suggestion, "logging") ||
564
string_contains_substring(suggestion, "start") ||
565
string_contains_substring(suggestion, "exit") ||
566
string_contains_substring(suggestion, "safepoint") ||
567
string_contains_substring(suggestion, "gc")) <<
568
"suggestion must contain AT LEAST one of the tags in user supplied selection";
569
}
570
571