blob: 728b5fe3cb37be590d0c5221cd995fca4f99a48b [file] [log] [blame]
Austin Schuh906616c2019-01-21 20:25:11 -08001// Copyright (c) 2002, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Author: Ray Sidney
31
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070032#include "config.h"
Austin Schuh906616c2019-01-21 20:25:11 -080033#include "utilities.h"
34
35#include <fcntl.h>
36#ifdef HAVE_GLOB_H
37# include <glob.h>
38#endif
39#include <sys/stat.h>
40#ifdef HAVE_UNISTD_H
41# include <unistd.h>
42#endif
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070043#ifdef HAVE_SYS_WAIT_H
44# include <sys/wait.h>
45#endif
Austin Schuh906616c2019-01-21 20:25:11 -080046
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070047#include <cstdio>
48#include <cstdlib>
49#include <fstream>
Austin Schuh906616c2019-01-21 20:25:11 -080050#include <iomanip>
51#include <iostream>
52#include <memory>
53#include <queue>
54#include <sstream>
55#include <string>
56#include <vector>
57
Austin Schuh906616c2019-01-21 20:25:11 -080058#include "base/commandlineflags.h"
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070059#include <glog/logging.h>
60#include <glog/raw_logging.h>
Austin Schuh906616c2019-01-21 20:25:11 -080061#include "googletest.h"
62
63DECLARE_string(log_backtrace_at); // logging.cc
64
65#ifdef HAVE_LIB_GFLAGS
66#include <gflags/gflags.h>
67using namespace GFLAGS_NAMESPACE;
68#endif
69
70#ifdef HAVE_LIB_GMOCK
71#include <gmock/gmock.h>
72#include "mock-log.h"
73// Introduce several symbols from gmock.
74using testing::_;
75using testing::AnyNumber;
76using testing::HasSubstr;
77using testing::AllOf;
78using testing::StrNe;
79using testing::StrictMock;
80using testing::InitGoogleMock;
81using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
82#endif
83
84using namespace std;
85using namespace GOOGLE_NAMESPACE;
86
87// Some non-advertised functions that we want to test or use.
88_START_GOOGLE_NAMESPACE_
89namespace base {
90namespace internal {
91bool GetExitOnDFatal();
92void SetExitOnDFatal(bool value);
93} // namespace internal
94} // namespace base
95_END_GOOGLE_NAMESPACE_
96
97static void TestLogging(bool check_counts);
98static void TestRawLogging();
99static void LogWithLevels(int v, int severity, bool err, bool alsoerr);
100static void TestLoggingLevels();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700101static void TestVLogModule();
Austin Schuh906616c2019-01-21 20:25:11 -0800102static void TestLogString();
103static void TestLogSink();
104static void TestLogToString();
105static void TestLogSinkWaitTillSent();
106static void TestCHECK();
107static void TestDCHECK();
108static void TestSTREQ();
109static void TestBasename();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700110static void TestBasenameAppendWhenNoTimestamp();
111static void TestTwoProcessesWrite();
Austin Schuh906616c2019-01-21 20:25:11 -0800112static void TestSymlink();
113static void TestExtension();
114static void TestWrapper();
115static void TestErrno();
116static void TestTruncate();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700117static void TestCustomLoggerDeletionOnShutdown();
118static void TestLogPeriodically();
Austin Schuh906616c2019-01-21 20:25:11 -0800119
120static int x = -1;
121static void BM_Check1(int n) {
122 while (n-- > 0) {
123 CHECK_GE(n, x);
124 CHECK_GE(n, x);
125 CHECK_GE(n, x);
126 CHECK_GE(n, x);
127 CHECK_GE(n, x);
128 CHECK_GE(n, x);
129 CHECK_GE(n, x);
130 CHECK_GE(n, x);
131 }
132}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700133BENCHMARK(BM_Check1)
Austin Schuh906616c2019-01-21 20:25:11 -0800134
135static void CheckFailure(int a, int b, const char* file, int line, const char* msg);
136static void BM_Check3(int n) {
137 while (n-- > 0) {
138 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
139 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
140 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
141 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
142 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
143 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
144 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
145 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
146 }
147}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700148BENCHMARK(BM_Check3)
Austin Schuh906616c2019-01-21 20:25:11 -0800149
150static void BM_Check2(int n) {
151 if (n == 17) {
152 x = 5;
153 }
154 while (n-- > 0) {
155 CHECK(n >= x);
156 CHECK(n >= x);
157 CHECK(n >= x);
158 CHECK(n >= x);
159 CHECK(n >= x);
160 CHECK(n >= x);
161 CHECK(n >= x);
162 CHECK(n >= x);
163 }
164}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700165BENCHMARK(BM_Check2)
Austin Schuh906616c2019-01-21 20:25:11 -0800166
167static void CheckFailure(int, int, const char* /* file */, int /* line */,
168 const char* /* msg */) {
169}
170
171static void BM_logspeed(int n) {
172 while (n-- > 0) {
173 LOG(INFO) << "test message";
174 }
175}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700176BENCHMARK(BM_logspeed)
Austin Schuh906616c2019-01-21 20:25:11 -0800177
178static void BM_vlog(int n) {
179 while (n-- > 0) {
180 VLOG(1) << "test message";
181 }
182}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700183BENCHMARK(BM_vlog)
Austin Schuh906616c2019-01-21 20:25:11 -0800184
185int main(int argc, char **argv) {
186 FLAGS_colorlogtostderr = false;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700187 FLAGS_timestamp_in_logfile_name = true;
188
Austin Schuh906616c2019-01-21 20:25:11 -0800189 // Make sure stderr is not buffered as stderr seems to be buffered
190 // on recent windows.
191 setbuf(stderr, NULL);
192
193 // Test some basics before InitGoogleLogging:
194 CaptureTestStderr();
195 LogWithLevels(FLAGS_v, FLAGS_stderrthreshold,
196 FLAGS_logtostderr, FLAGS_alsologtostderr);
197 LogWithLevels(0, 0, 0, 0); // simulate "before global c-tors"
198 const string early_stderr = GetCapturedTestStderr();
199
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700200 EXPECT_FALSE(IsGoogleLoggingInitialized());
201
Austin Schuh906616c2019-01-21 20:25:11 -0800202 InitGoogleLogging(argv[0]);
203
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700204 EXPECT_TRUE(IsGoogleLoggingInitialized());
205
Austin Schuh906616c2019-01-21 20:25:11 -0800206 RunSpecifiedBenchmarks();
207
208 FLAGS_logtostderr = true;
209
210 InitGoogleTest(&argc, argv);
211#ifdef HAVE_LIB_GMOCK
212 InitGoogleMock(&argc, argv);
213#endif
214
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700215#ifdef HAVE_LIB_GFLAGS
216 ParseCommandLineFlags(&argc, &argv, true);
217#endif
218
Austin Schuh906616c2019-01-21 20:25:11 -0800219 // so that death tests run before we use threads
220 CHECK_EQ(RUN_ALL_TESTS(), 0);
221
222 CaptureTestStderr();
223
224 // re-emit early_stderr
225 LogMessage("dummy", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << early_stderr;
226
227 TestLogging(true);
228 TestRawLogging();
229 TestLoggingLevels();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700230 TestVLogModule();
Austin Schuh906616c2019-01-21 20:25:11 -0800231 TestLogString();
232 TestLogSink();
233 TestLogToString();
234 TestLogSinkWaitTillSent();
235 TestCHECK();
236 TestDCHECK();
237 TestSTREQ();
238
239 // TODO: The golden test portion of this test is very flakey.
240 EXPECT_TRUE(
241 MungeAndDiffTestStderr(FLAGS_test_srcdir + "/src/logging_unittest.err"));
242
243 FLAGS_logtostderr = false;
244
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700245 FLAGS_logtostdout = true;
246 FLAGS_stderrthreshold = NUM_SEVERITIES;
247 CaptureTestStdout();
248 TestRawLogging();
249 TestLoggingLevels();
250 TestLogString();
251 TestLogSink();
252 TestLogToString();
253 TestLogSinkWaitTillSent();
254 TestCHECK();
255 TestDCHECK();
256 TestSTREQ();
257 EXPECT_TRUE(
258 MungeAndDiffTestStdout(FLAGS_test_srcdir + "/src/logging_unittest.out"));
259 FLAGS_logtostdout = false;
260
Austin Schuh906616c2019-01-21 20:25:11 -0800261 TestBasename();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700262 TestBasenameAppendWhenNoTimestamp();
263 TestTwoProcessesWrite();
Austin Schuh906616c2019-01-21 20:25:11 -0800264 TestSymlink();
265 TestExtension();
266 TestWrapper();
267 TestErrno();
268 TestTruncate();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700269 TestCustomLoggerDeletionOnShutdown();
270 TestLogPeriodically();
Austin Schuh906616c2019-01-21 20:25:11 -0800271
272 fprintf(stdout, "PASS\n");
273 return 0;
274}
275
276void TestLogging(bool check_counts) {
277 int64 base_num_infos = LogMessage::num_messages(GLOG_INFO);
278 int64 base_num_warning = LogMessage::num_messages(GLOG_WARNING);
279 int64 base_num_errors = LogMessage::num_messages(GLOG_ERROR);
280
281 LOG(INFO) << string("foo ") << "bar " << 10 << ' ' << 3.4;
282 for ( int i = 0; i < 10; ++i ) {
283 int old_errno = errno;
284 errno = i;
285 PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER;
286 errno = old_errno;
287
288 LOG_EVERY_N(ERROR, 3) << "Log every 3, iteration " << COUNTER << endl;
289 LOG_EVERY_N(ERROR, 4) << "Log every 4, iteration " << COUNTER << endl;
290
291 LOG_IF_EVERY_N(WARNING, true, 5) << "Log if every 5, iteration " << COUNTER;
292 LOG_IF_EVERY_N(WARNING, false, 3)
293 << "Log if every 3, iteration " << COUNTER;
294 LOG_IF_EVERY_N(INFO, true, 1) << "Log if every 1, iteration " << COUNTER;
295 LOG_IF_EVERY_N(ERROR, (i < 3), 2)
296 << "Log if less than 3 every 2, iteration " << COUNTER;
297 }
298 LOG_IF(WARNING, true) << "log_if this";
299 LOG_IF(WARNING, false) << "don't log_if this";
300
301 char s[] = "array";
302 LOG(INFO) << s;
303 const char const_s[] = "const array";
304 LOG(INFO) << const_s;
305 int j = 1000;
306 LOG(ERROR) << string("foo") << ' '<< j << ' ' << setw(10) << j << " "
307 << setw(1) << hex << j;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700308 LOG(INFO) << "foo " << std::setw(10) << 1.0;
Austin Schuh906616c2019-01-21 20:25:11 -0800309
310 {
311 google::LogMessage outer(__FILE__, __LINE__, GLOG_ERROR);
312 outer.stream() << "outer";
313
314 LOG(ERROR) << "inner";
315 }
316
317 LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << "no prefix";
318
319 if (check_counts) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700320 CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));
Austin Schuh906616c2019-01-21 20:25:11 -0800321 CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(GLOG_WARNING));
322 CHECK_EQ(base_num_errors + 17, LogMessage::num_messages(GLOG_ERROR));
323 }
324}
325
326static void NoAllocNewHook() {
327 LOG(FATAL) << "unexpected new";
328}
329
330struct NewHook {
331 NewHook() {
332 g_new_hook = &NoAllocNewHook;
333 }
334 ~NewHook() {
335 g_new_hook = NULL;
336 }
337};
338
339TEST(DeathNoAllocNewHook, logging) {
340 // tests that NewHook used below works
341 NewHook new_hook;
342 ASSERT_DEATH({
343 new int;
344 }, "unexpected new");
345}
346
347void TestRawLogging() {
348 string* foo = new string("foo ");
349 string huge_str(50000, 'a');
350
351 FlagSaver saver;
352
353 // Check that RAW loggging does not use mallocs.
354 NewHook new_hook;
355
356 RAW_LOG(INFO, "%s%s%d%c%f", foo->c_str(), "bar ", 10, ' ', 3.4);
357 char s[] = "array";
358 RAW_LOG(WARNING, "%s", s);
359 const char const_s[] = "const array";
360 RAW_LOG(INFO, "%s", const_s);
361 void* p = reinterpret_cast<void*>(PTR_TEST_VALUE);
362 RAW_LOG(INFO, "ptr %p", p);
363 p = NULL;
364 RAW_LOG(INFO, "ptr %p", p);
365 int j = 1000;
366 RAW_LOG(ERROR, "%s%d%c%010d%s%1x", foo->c_str(), j, ' ', j, " ", j);
367 RAW_VLOG(0, "foo %d", j);
368
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700369#if defined(NDEBUG)
Austin Schuh906616c2019-01-21 20:25:11 -0800370 RAW_LOG(INFO, "foo %d", j); // so that have same stderr to compare
371#else
372 RAW_DLOG(INFO, "foo %d", j); // test RAW_DLOG in debug mode
373#endif
374
375 // test how long messages are chopped:
376 RAW_LOG(WARNING, "Huge string: %s", huge_str.c_str());
377 RAW_VLOG(0, "Huge string: %s", huge_str.c_str());
378
379 FLAGS_v = 0;
380 RAW_LOG(INFO, "log");
381 RAW_VLOG(0, "vlog 0 on");
382 RAW_VLOG(1, "vlog 1 off");
383 RAW_VLOG(2, "vlog 2 off");
384 RAW_VLOG(3, "vlog 3 off");
385 FLAGS_v = 2;
386 RAW_LOG(INFO, "log");
387 RAW_VLOG(1, "vlog 1 on");
388 RAW_VLOG(2, "vlog 2 on");
389 RAW_VLOG(3, "vlog 3 off");
390
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700391#if defined(NDEBUG)
Austin Schuh906616c2019-01-21 20:25:11 -0800392 RAW_DCHECK(1 == 2, " RAW_DCHECK's shouldn't be compiled in normal mode");
393#endif
394
395 RAW_CHECK(1 == 1, "should be ok");
396 RAW_DCHECK(true, "should be ok");
397
398 delete foo;
399}
400
401void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
402 RAW_LOG(INFO,
403 "Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d",
404 v, severity, err, alsoerr);
405
406 FlagSaver saver;
407
408 FLAGS_v = v;
409 FLAGS_stderrthreshold = severity;
410 FLAGS_logtostderr = err;
411 FLAGS_alsologtostderr = alsoerr;
412
413 RAW_VLOG(-1, "vlog -1");
414 RAW_VLOG(0, "vlog 0");
415 RAW_VLOG(1, "vlog 1");
416 RAW_LOG(INFO, "log info");
417 RAW_LOG(WARNING, "log warning");
418 RAW_LOG(ERROR, "log error");
419
420 VLOG(-1) << "vlog -1";
421 VLOG(0) << "vlog 0";
422 VLOG(1) << "vlog 1";
423 LOG(INFO) << "log info";
424 LOG(WARNING) << "log warning";
425 LOG(ERROR) << "log error";
426
427 VLOG_IF(-1, true) << "vlog_if -1";
428 VLOG_IF(-1, false) << "don't vlog_if -1";
429 VLOG_IF(0, true) << "vlog_if 0";
430 VLOG_IF(0, false) << "don't vlog_if 0";
431 VLOG_IF(1, true) << "vlog_if 1";
432 VLOG_IF(1, false) << "don't vlog_if 1";
433 LOG_IF(INFO, true) << "log_if info";
434 LOG_IF(INFO, false) << "don't log_if info";
435 LOG_IF(WARNING, true) << "log_if warning";
436 LOG_IF(WARNING, false) << "don't log_if warning";
437 LOG_IF(ERROR, true) << "log_if error";
438 LOG_IF(ERROR, false) << "don't log_if error";
439
440 int c;
441 c = 1; VLOG_IF(100, c -= 2) << "vlog_if 100 expr"; EXPECT_EQ(c, -1);
442 c = 1; VLOG_IF(0, c -= 2) << "vlog_if 0 expr"; EXPECT_EQ(c, -1);
443 c = 1; LOG_IF(INFO, c -= 2) << "log_if info expr"; EXPECT_EQ(c, -1);
444 c = 1; LOG_IF(ERROR, c -= 2) << "log_if error expr"; EXPECT_EQ(c, -1);
445 c = 2; VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr"; EXPECT_EQ(c, 0);
446 c = 2; LOG_IF(ERROR, c -= 2) << "don't log_if error expr"; EXPECT_EQ(c, 0);
447
448 c = 3; LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
449 EXPECT_EQ(c, -1);
450 c = 3; LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
451 EXPECT_EQ(c, -1);
452 c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
453 EXPECT_EQ(c, 0);
454 c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
455 EXPECT_EQ(c, 0);
456 c = 5; VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
457 EXPECT_EQ(c, 1);
458 c = 5; VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
459 EXPECT_EQ(c, 1);
460 c = 6; VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
461 EXPECT_EQ(c, 0);
462 c = 6; VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
463 EXPECT_EQ(c, 0);
464}
465
466void TestLoggingLevels() {
467 LogWithLevels(0, GLOG_INFO, false, false);
468 LogWithLevels(1, GLOG_INFO, false, false);
469 LogWithLevels(-1, GLOG_INFO, false, false);
470 LogWithLevels(0, GLOG_WARNING, false, false);
471 LogWithLevels(0, GLOG_ERROR, false, false);
472 LogWithLevels(0, GLOG_FATAL, false, false);
473 LogWithLevels(0, GLOG_FATAL, true, false);
474 LogWithLevels(0, GLOG_FATAL, false, true);
475 LogWithLevels(1, GLOG_WARNING, false, false);
476 LogWithLevels(1, GLOG_FATAL, false, true);
477}
478
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700479int TestVlogHelper() {
480 if (VLOG_IS_ON(1)) {
481 return 1;
482 }
483 return 0;
484}
485
486void TestVLogModule() {
487 int c = TestVlogHelper();
488 EXPECT_EQ(0, c);
489
490#if defined(__GNUC__)
491 EXPECT_EQ(0, SetVLOGLevel("logging_unittest", 1));
492 c = TestVlogHelper();
493 EXPECT_EQ(1, c);
494#endif
495}
496
Austin Schuh906616c2019-01-21 20:25:11 -0800497TEST(DeathRawCHECK, logging) {
498 ASSERT_DEATH(RAW_CHECK(false, "failure 1"),
499 "RAW: Check false failed: failure 1");
500 ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, "failure 2"),
501 "RAW: Check 1 == 2 failed: failure 2");
502}
503
504void TestLogString() {
505 vector<string> errors;
506 vector<string> *no_errors = NULL;
507
508 LOG_STRING(INFO, &errors) << "LOG_STRING: " << "collected info";
509 LOG_STRING(WARNING, &errors) << "LOG_STRING: " << "collected warning";
510 LOG_STRING(ERROR, &errors) << "LOG_STRING: " << "collected error";
511
512 LOG_STRING(INFO, no_errors) << "LOG_STRING: " << "reported info";
513 LOG_STRING(WARNING, no_errors) << "LOG_STRING: " << "reported warning";
514 LOG_STRING(ERROR, NULL) << "LOG_STRING: " << "reported error";
515
516 for (size_t i = 0; i < errors.size(); ++i) {
517 LOG(INFO) << "Captured by LOG_STRING: " << errors[i];
518 }
519}
520
521void TestLogToString() {
522 string error;
523 string* no_error = NULL;
524
525 LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: " << "collected info";
526 LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
527 LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: " << "collected warning";
528 LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
529 LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: " << "collected error";
530 LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
531
532 LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: " << "reported info";
533 LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: " << "reported warning";
534 LOG_TO_STRING(ERROR, NULL) << "LOG_TO_STRING: " << "reported error";
535}
536
537class TestLogSinkImpl : public LogSink {
538 public:
539 vector<string> errors;
540 virtual void send(LogSeverity severity, const char* /* full_filename */,
541 const char* base_filename, int line,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700542 const LogMessageTime &logmsgtime,
Austin Schuh906616c2019-01-21 20:25:11 -0800543 const char* message, size_t message_len) {
544 errors.push_back(
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700545 ToString(severity, base_filename, line, logmsgtime, message, message_len));
Austin Schuh906616c2019-01-21 20:25:11 -0800546 }
547};
548
549void TestLogSink() {
550 TestLogSinkImpl sink;
551 LogSink *no_sink = NULL;
552
553 LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: " << "collected info";
554 LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: " << "collected warning";
555 LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: " << "collected error";
556
557 LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: " << "reported info";
558 LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning";
559 LOG_TO_SINK(NULL, ERROR) << "LOG_TO_SINK: " << "reported error";
560
561 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
562 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected info";
563 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
564 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected warning";
565 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
566 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected error";
567
568 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
569 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed info";
570 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
571 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed warning";
572 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(NULL, ERROR)
573 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed error";
574
575 LOG(INFO) << "Captured by LOG_TO_SINK:";
576 for (size_t i = 0; i < sink.errors.size(); ++i) {
577 LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream()
578 << sink.errors[i];
579 }
580}
581
582// For testing using CHECK*() on anonymous enums.
583enum {
584 CASE_A,
585 CASE_B
586};
587
588void TestCHECK() {
589 // Tests using CHECK*() on int values.
590 CHECK(1 == 1);
591 CHECK_EQ(1, 1);
592 CHECK_NE(1, 2);
593 CHECK_GE(1, 1);
594 CHECK_GE(2, 1);
595 CHECK_LE(1, 1);
596 CHECK_LE(1, 2);
597 CHECK_GT(2, 1);
598 CHECK_LT(1, 2);
599
600 // Tests using CHECK*() on anonymous enums.
601 // Apple's GCC doesn't like this.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700602#if !defined(GLOG_OS_MACOSX)
Austin Schuh906616c2019-01-21 20:25:11 -0800603 CHECK_EQ(CASE_A, CASE_A);
604 CHECK_NE(CASE_A, CASE_B);
605 CHECK_GE(CASE_A, CASE_A);
606 CHECK_GE(CASE_B, CASE_A);
607 CHECK_LE(CASE_A, CASE_A);
608 CHECK_LE(CASE_A, CASE_B);
609 CHECK_GT(CASE_B, CASE_A);
610 CHECK_LT(CASE_A, CASE_B);
611#endif
612}
613
614void TestDCHECK() {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700615#if defined(NDEBUG)
Austin Schuh906616c2019-01-21 20:25:11 -0800616 DCHECK( 1 == 2 ) << " DCHECK's shouldn't be compiled in normal mode";
617#endif
618 DCHECK( 1 == 1 );
619 DCHECK_EQ(1, 1);
620 DCHECK_NE(1, 2);
621 DCHECK_GE(1, 1);
622 DCHECK_GE(2, 1);
623 DCHECK_LE(1, 1);
624 DCHECK_LE(1, 2);
625 DCHECK_GT(2, 1);
626 DCHECK_LT(1, 2);
627
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700628 int64* orig_ptr = new int64;
629 int64* ptr = DCHECK_NOTNULL(orig_ptr);
630 CHECK_EQ(ptr, orig_ptr);
631 delete orig_ptr;
Austin Schuh906616c2019-01-21 20:25:11 -0800632}
633
634void TestSTREQ() {
635 CHECK_STREQ("this", "this");
636 CHECK_STREQ(NULL, NULL);
637 CHECK_STRCASEEQ("this", "tHiS");
638 CHECK_STRCASEEQ(NULL, NULL);
639 CHECK_STRNE("this", "tHiS");
640 CHECK_STRNE("this", NULL);
641 CHECK_STRCASENE("this", "that");
642 CHECK_STRCASENE(NULL, "that");
643 CHECK_STREQ((string("a")+"b").c_str(), "ab");
644 CHECK_STREQ(string("test").c_str(),
645 (string("te") + string("st")).c_str());
646}
647
648TEST(DeathSTREQ, logging) {
649 ASSERT_DEATH(CHECK_STREQ(NULL, "this"), "");
650 ASSERT_DEATH(CHECK_STREQ("this", "siht"), "");
651 ASSERT_DEATH(CHECK_STRCASEEQ(NULL, "siht"), "");
652 ASSERT_DEATH(CHECK_STRCASEEQ("this", "siht"), "");
653 ASSERT_DEATH(CHECK_STRNE(NULL, NULL), "");
654 ASSERT_DEATH(CHECK_STRNE("this", "this"), "");
655 ASSERT_DEATH(CHECK_STREQ((string("a")+"b").c_str(), "abc"), "");
656}
657
658TEST(CheckNOTNULL, Simple) {
659 int64 t;
660 void *ptr = static_cast<void *>(&t);
661 void *ref = CHECK_NOTNULL(ptr);
662 EXPECT_EQ(ptr, ref);
663 CHECK_NOTNULL(reinterpret_cast<char *>(ptr));
664 CHECK_NOTNULL(reinterpret_cast<unsigned char *>(ptr));
665 CHECK_NOTNULL(reinterpret_cast<int *>(ptr));
666 CHECK_NOTNULL(reinterpret_cast<int64 *>(ptr));
667}
668
669TEST(DeathCheckNN, Simple) {
670 ASSERT_DEATH(CHECK_NOTNULL(static_cast<void *>(NULL)), "");
671}
672
673// Get list of file names that match pattern
674static void GetFiles(const string& pattern, vector<string>* files) {
675 files->clear();
676#if defined(HAVE_GLOB_H)
677 glob_t g;
678 const int r = glob(pattern.c_str(), 0, NULL, &g);
679 CHECK((r == 0) || (r == GLOB_NOMATCH)) << ": error matching " << pattern;
680 for (size_t i = 0; i < g.gl_pathc; i++) {
681 files->push_back(string(g.gl_pathv[i]));
682 }
683 globfree(&g);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700684#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800685 WIN32_FIND_DATAA data;
686 HANDLE handle = FindFirstFileA(pattern.c_str(), &data);
687 size_t index = pattern.rfind('\\');
688 if (index == string::npos) {
689 LOG(FATAL) << "No directory separator.";
690 }
691 const string dirname = pattern.substr(0, index + 1);
692 if (handle == INVALID_HANDLE_VALUE) {
693 // Finding no files is OK.
694 return;
695 }
696 do {
697 files->push_back(dirname + data.cFileName);
698 } while (FindNextFileA(handle, &data));
699 BOOL result = FindClose(handle);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700700 LOG_SYSRESULT(result != 0);
Austin Schuh906616c2019-01-21 20:25:11 -0800701#else
702# error There is no way to do glob.
703#endif
704}
705
706// Delete files patching pattern
707static void DeleteFiles(const string& pattern) {
708 vector<string> files;
709 GetFiles(pattern, &files);
710 for (size_t i = 0; i < files.size(); i++) {
711 CHECK(unlink(files[i].c_str()) == 0) << ": " << strerror(errno);
712 }
713}
714
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700715//check string is in file (or is *NOT*, depending on optional checkInFileOrNot)
716static void CheckFile(const string& name, const string& expected_string, const bool checkInFileOrNot = true) {
Austin Schuh906616c2019-01-21 20:25:11 -0800717 vector<string> files;
718 GetFiles(name + "*", &files);
719 CHECK_EQ(files.size(), 1UL);
720
721 FILE* file = fopen(files[0].c_str(), "r");
722 CHECK(file != NULL) << ": could not open " << files[0];
723 char buf[1000];
724 while (fgets(buf, sizeof(buf), file) != NULL) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700725 char* first = strstr(buf, expected_string.c_str());
726 //if first == NULL, not found.
727 //Terser than if (checkInFileOrNot && first != NULL || !check...
728 if (checkInFileOrNot != (first == NULL)) {
Austin Schuh906616c2019-01-21 20:25:11 -0800729 fclose(file);
730 return;
731 }
732 }
733 fclose(file);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700734 LOG(FATAL) << "Did " << (checkInFileOrNot? "not " : "") << "find " << expected_string << " in " << files[0];
Austin Schuh906616c2019-01-21 20:25:11 -0800735}
736
737static void TestBasename() {
738 fprintf(stderr, "==== Test setting log file basename\n");
739 const string dest = FLAGS_test_tmpdir + "/logging_test_basename";
740 DeleteFiles(dest + "*");
741
742 SetLogDestination(GLOG_INFO, dest.c_str());
743 LOG(INFO) << "message to new base";
744 FlushLogFiles(GLOG_INFO);
745
746 CheckFile(dest, "message to new base");
747
748 // Release file handle for the destination file to unlock the file in Windows.
749 LogToStderr();
750 DeleteFiles(dest + "*");
751}
752
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700753static void TestBasenameAppendWhenNoTimestamp() {
754 fprintf(stderr, "==== Test setting log file basename without timestamp and appending properly\n");
755 const string dest = FLAGS_test_tmpdir + "/logging_test_basename_append_when_no_timestamp";
756 DeleteFiles(dest + "*");
757
758 ofstream out(dest.c_str());
759 out << "test preexisting content" << endl;
760 out.close();
761
762 CheckFile(dest, "test preexisting content");
763
764 FLAGS_timestamp_in_logfile_name=false;
765 SetLogDestination(GLOG_INFO, dest.c_str());
766 LOG(INFO) << "message to new base, appending to preexisting file";
767 FlushLogFiles(GLOG_INFO);
768 FLAGS_timestamp_in_logfile_name=true;
769
770 //if the logging overwrites the file instead of appending it will fail.
771 CheckFile(dest, "test preexisting content");
772 CheckFile(dest, "message to new base, appending to preexisting file");
773
774 // Release file handle for the destination file to unlock the file in Windows.
775 LogToStderr();
776 DeleteFiles(dest + "*");
777}
778
779static void TestTwoProcessesWrite() {
780// test only implemented for platforms with fork & wait; the actual implementation relies on flock
781#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)
782 fprintf(stderr, "==== Test setting log file basename and two processes writing - second should fail\n");
783 const string dest = FLAGS_test_tmpdir + "/logging_test_basename_two_processes_writing";
784 DeleteFiles(dest + "*");
785
786 //make both processes write into the same file (easier test)
787 FLAGS_timestamp_in_logfile_name=false;
788 SetLogDestination(GLOG_INFO, dest.c_str());
789 LOG(INFO) << "message to new base, parent";
790 FlushLogFiles(GLOG_INFO);
791
792 pid_t pid = fork();
793 CHECK_ERR(pid);
794 if (pid == 0) {
795 LOG(INFO) << "message to new base, child - should only appear on STDERR not on the file";
796 ShutdownGoogleLogging(); //for children proc
797 exit(EXIT_SUCCESS);
798 } else if (pid > 0) {
799 wait(NULL);
800 }
801 FLAGS_timestamp_in_logfile_name=true;
802
803 CheckFile(dest, "message to new base, parent");
804 CheckFile(dest, "message to new base, child - should only appear on STDERR not on the file", false);
805
806 // Release
807 LogToStderr();
808 DeleteFiles(dest + "*");
809#endif
810}
811
Austin Schuh906616c2019-01-21 20:25:11 -0800812static void TestSymlink() {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700813#ifndef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800814 fprintf(stderr, "==== Test setting log file symlink\n");
815 string dest = FLAGS_test_tmpdir + "/logging_test_symlink";
816 string sym = FLAGS_test_tmpdir + "/symlinkbase";
817 DeleteFiles(dest + "*");
818 DeleteFiles(sym + "*");
819
820 SetLogSymlink(GLOG_INFO, "symlinkbase");
821 SetLogDestination(GLOG_INFO, dest.c_str());
822 LOG(INFO) << "message to new symlink";
823 FlushLogFiles(GLOG_INFO);
824 CheckFile(sym, "message to new symlink");
825
826 DeleteFiles(dest + "*");
827 DeleteFiles(sym + "*");
828#endif
829}
830
831static void TestExtension() {
832 fprintf(stderr, "==== Test setting log file extension\n");
833 string dest = FLAGS_test_tmpdir + "/logging_test_extension";
834 DeleteFiles(dest + "*");
835
836 SetLogDestination(GLOG_INFO, dest.c_str());
837 SetLogFilenameExtension("specialextension");
838 LOG(INFO) << "message to new extension";
839 FlushLogFiles(GLOG_INFO);
840 CheckFile(dest, "message to new extension");
841
842 // Check that file name ends with extension
843 vector<string> filenames;
844 GetFiles(dest + "*", &filenames);
845 CHECK_EQ(filenames.size(), 1UL);
846 CHECK(strstr(filenames[0].c_str(), "specialextension") != NULL);
847
848 // Release file handle for the destination file to unlock the file in Windows.
849 LogToStderr();
850 DeleteFiles(dest + "*");
851}
852
853struct MyLogger : public base::Logger {
854 string data;
855
856 virtual void Write(bool /* should_flush */,
857 time_t /* timestamp */,
858 const char* message,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700859 size_t length) {
Austin Schuh906616c2019-01-21 20:25:11 -0800860 data.append(message, length);
861 }
862
863 virtual void Flush() { }
864
865 virtual uint32 LogSize() { return data.length(); }
866};
867
868static void TestWrapper() {
869 fprintf(stderr, "==== Test log wrapper\n");
870
871 MyLogger my_logger;
872 base::Logger* old_logger = base::GetLogger(GLOG_INFO);
873 base::SetLogger(GLOG_INFO, &my_logger);
874 LOG(INFO) << "Send to wrapped logger";
875 FlushLogFiles(GLOG_INFO);
876 base::SetLogger(GLOG_INFO, old_logger);
877
878 CHECK(strstr(my_logger.data.c_str(), "Send to wrapped logger") != NULL);
879}
880
881static void TestErrno() {
882 fprintf(stderr, "==== Test errno preservation\n");
883
884 errno = ENOENT;
885 TestLogging(false);
886 CHECK_EQ(errno, ENOENT);
887}
888
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700889static void TestOneTruncate(const char *path, uint64 limit, uint64 keep,
890 size_t dsize, size_t ksize, size_t expect) {
Austin Schuh906616c2019-01-21 20:25:11 -0800891 int fd;
892 CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600));
893
894 const char *discardstr = "DISCARDME!", *keepstr = "KEEPME!";
895 const size_t discard_size = strlen(discardstr), keep_size = strlen(keepstr);
896
897 // Fill the file with the requested data; first discard data, then kept data
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700898 size_t written = 0;
Austin Schuh906616c2019-01-21 20:25:11 -0800899 while (written < dsize) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700900 size_t bytes = min(dsize - written, discard_size);
Austin Schuh906616c2019-01-21 20:25:11 -0800901 CHECK_ERR(write(fd, discardstr, bytes));
902 written += bytes;
903 }
904 written = 0;
905 while (written < ksize) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700906 size_t bytes = min(ksize - written, keep_size);
Austin Schuh906616c2019-01-21 20:25:11 -0800907 CHECK_ERR(write(fd, keepstr, bytes));
908 written += bytes;
909 }
910
911 TruncateLogFile(path, limit, keep);
912
913 // File should now be shorter
914 struct stat statbuf;
915 CHECK_ERR(fstat(fd, &statbuf));
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700916 CHECK_EQ(static_cast<size_t>(statbuf.st_size), expect);
Austin Schuh906616c2019-01-21 20:25:11 -0800917 CHECK_ERR(lseek(fd, 0, SEEK_SET));
918
919 // File should contain the suffix of the original file
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700920 const size_t buf_size = static_cast<size_t>(statbuf.st_size) + 1;
Austin Schuh906616c2019-01-21 20:25:11 -0800921 char* buf = new char[buf_size];
922 memset(buf, 0, buf_size);
923 CHECK_ERR(read(fd, buf, buf_size));
924
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700925 const char* p = buf;
926 size_t checked = 0;
Austin Schuh906616c2019-01-21 20:25:11 -0800927 while (checked < expect) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700928 size_t bytes = min(expect - checked, keep_size);
Austin Schuh906616c2019-01-21 20:25:11 -0800929 CHECK(!memcmp(p, keepstr, bytes));
930 checked += bytes;
931 }
932 close(fd);
933 delete[] buf;
934}
935
936static void TestTruncate() {
937#ifdef HAVE_UNISTD_H
938 fprintf(stderr, "==== Test log truncation\n");
939 string path = FLAGS_test_tmpdir + "/truncatefile";
940
941 // Test on a small file
942 TestOneTruncate(path.c_str(), 10, 10, 10, 10, 10);
943
944 // And a big file (multiple blocks to copy)
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700945 TestOneTruncate(path.c_str(), 2U << 20U, 4U << 10U, 3U << 20U, 4U << 10U,
946 4U << 10U);
Austin Schuh906616c2019-01-21 20:25:11 -0800947
948 // Check edge-case limits
949 TestOneTruncate(path.c_str(), 10, 20, 0, 20, 20);
950 TestOneTruncate(path.c_str(), 10, 0, 0, 0, 0);
951 TestOneTruncate(path.c_str(), 10, 50, 0, 10, 10);
952 TestOneTruncate(path.c_str(), 50, 100, 0, 30, 30);
953
954 // MacOSX 10.4 doesn't fail in this case.
955 // Windows doesn't have symlink.
956 // Let's just ignore this test for these cases.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700957#if !defined(GLOG_OS_MACOSX) && !defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800958 // Through a symlink should fail to truncate
959 string linkname = path + ".link";
960 unlink(linkname.c_str());
961 CHECK_ERR(symlink(path.c_str(), linkname.c_str()));
962 TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30);
963#endif
964
965 // The /proc/self path makes sense only for linux.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700966#if defined(GLOG_OS_LINUX)
Austin Schuh906616c2019-01-21 20:25:11 -0800967 // Through an open fd symlink should work
968 int fd;
969 CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY));
970 char fdpath[64];
971 snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd);
972 TestOneTruncate(fdpath, 10, 10, 10, 10, 10);
973#endif
974
975#endif
976}
977
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700978struct RecordDeletionLogger : public base::Logger {
979 RecordDeletionLogger(bool* set_on_destruction,
980 base::Logger* wrapped_logger) :
981 set_on_destruction_(set_on_destruction),
982 wrapped_logger_(wrapped_logger)
983 {
984 *set_on_destruction_ = false;
985 }
986 virtual ~RecordDeletionLogger() {
987 *set_on_destruction_ = true;
988 }
989 virtual void Write(bool force_flush,
990 time_t timestamp,
991 const char* message,
992 size_t length) {
993 wrapped_logger_->Write(force_flush, timestamp, message, length);
994 }
995 virtual void Flush() { wrapped_logger_->Flush(); }
996 virtual uint32 LogSize() { return wrapped_logger_->LogSize(); }
997 private:
998 bool* set_on_destruction_;
999 base::Logger* wrapped_logger_;
1000};
1001
1002static void TestCustomLoggerDeletionOnShutdown() {
1003 bool custom_logger_deleted = false;
1004 base::SetLogger(GLOG_INFO,
1005 new RecordDeletionLogger(&custom_logger_deleted,
1006 base::GetLogger(GLOG_INFO)));
1007 EXPECT_TRUE(IsGoogleLoggingInitialized());
1008 ShutdownGoogleLogging();
1009 EXPECT_TRUE(custom_logger_deleted);
1010 EXPECT_FALSE(IsGoogleLoggingInitialized());
1011}
1012
1013namespace LogTimes {
1014// Log a "message" every 10ms, 10 times. These numbers are nice compromise
1015// between total running time of 100ms and the period of 10ms. The period is
1016// large enough such that any CPU and OS scheduling variation shouldn't affect
1017// the results from the ideal case by more than 5% (500us or 0.5ms)
1018GLOG_CONSTEXPR int64_t LOG_PERIOD_NS = 10000000; // 10ms
1019GLOG_CONSTEXPR int64_t LOG_PERIOD_TOL_NS = 500000; // 500us
1020
1021// Set an upper limit for the number of times the stream operator can be
1022// called. Make sure not to exceed this number of times the stream operator is
1023// called, since it is also the array size and will be indexed by the stream
1024// operator.
1025GLOG_CONSTEXPR size_t MAX_CALLS = 10;
1026} // namespace LogTimes
1027
1028#if defined(HAVE_CXX11_CHRONO) && __cplusplus >= 201103L
1029struct LogTimeRecorder {
1030 LogTimeRecorder() : m_streamTimes(0) {}
1031 size_t m_streamTimes;
1032 std::chrono::steady_clock::time_point m_callTimes[LogTimes::MAX_CALLS];
1033};
1034// The stream operator is called by LOG_EVERY_T every time a logging event
1035// occurs. Make sure to save the times for each call as they will be used later
1036// to verify the time delta between each call.
1037std::ostream& operator<<(std::ostream& stream, LogTimeRecorder& t) {
1038 t.m_callTimes[t.m_streamTimes++] = std::chrono::steady_clock::now();
1039 return stream;
1040}
1041// get elapsed time in nanoseconds
1042int64 elapsedTime_ns(const std::chrono::steady_clock::time_point& begin,
1043 const std::chrono::steady_clock::time_point& end) {
1044 return std::chrono::duration_cast<std::chrono::nanoseconds>((end - begin))
1045 .count();
1046}
1047#elif defined(GLOG_OS_WINDOWS)
1048struct LogTimeRecorder {
1049 LogTimeRecorder() : m_streamTimes(0) {}
1050 size_t m_streamTimes;
1051 LARGE_INTEGER m_callTimes[LogTimes::MAX_CALLS];
1052};
1053std::ostream& operator<<(std::ostream& stream, LogTimeRecorder& t) {
1054 QueryPerformanceCounter(&t.m_callTimes[t.m_streamTimes++]);
1055 return stream;
1056}
1057// get elapsed time in nanoseconds
1058int64 elapsedTime_ns(const LARGE_INTEGER& begin, const LARGE_INTEGER& end) {
1059 LARGE_INTEGER freq;
1060 QueryPerformanceFrequency(&freq);
1061 return (end.QuadPart - begin.QuadPart) * LONGLONG(1000000000) / freq.QuadPart;
1062}
1063#else
1064struct LogTimeRecorder {
1065 LogTimeRecorder() : m_streamTimes(0) {}
1066 size_t m_streamTimes;
1067 timespec m_callTimes[LogTimes::MAX_CALLS];
1068};
1069std::ostream& operator<<(std::ostream& stream, LogTimeRecorder& t) {
1070 clock_gettime(CLOCK_MONOTONIC, &t.m_callTimes[t.m_streamTimes++]);
1071 return stream;
1072}
1073// get elapsed time in nanoseconds
1074int64 elapsedTime_ns(const timespec& begin, const timespec& end) {
1075 return (end.tv_sec - begin.tv_sec) * 1000000000 +
1076 (end.tv_nsec - begin.tv_nsec);
1077}
1078#endif
1079
1080static void TestLogPeriodically() {
1081 fprintf(stderr, "==== Test log periodically\n");
1082
1083 LogTimeRecorder timeLogger;
1084
1085 GLOG_CONSTEXPR double LOG_PERIOD_SEC = LogTimes::LOG_PERIOD_NS * 1e-9;
1086
1087 while (timeLogger.m_streamTimes < LogTimes::MAX_CALLS) {
1088 LOG_EVERY_T(INFO, LOG_PERIOD_SEC)
1089 << timeLogger << "Timed Message #" << timeLogger.m_streamTimes;
1090 }
1091
1092 // Calculate time between each call in nanoseconds for higher resolution to
1093 // minimize error.
1094 int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];
1095 for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {
1096 nsBetweenCalls[i - 1] = elapsedTime_ns(
1097 timeLogger.m_callTimes[i - 1], timeLogger.m_callTimes[i]);
1098 }
1099
1100 for (size_t idx = 0; idx < LogTimes::MAX_CALLS - 1; ++idx) {
1101 int64 time_ns = nsBetweenCalls[idx];
1102 EXPECT_NEAR(time_ns, LogTimes::LOG_PERIOD_NS, LogTimes::LOG_PERIOD_TOL_NS);
1103 }
1104}
1105
Austin Schuh906616c2019-01-21 20:25:11 -08001106_START_GOOGLE_NAMESPACE_
1107namespace glog_internal_namespace_ {
1108extern // in logging.cc
1109bool SafeFNMatch_(const char* pattern, size_t patt_len,
1110 const char* str, size_t str_len);
1111} // namespace glog_internal_namespace_
1112using glog_internal_namespace_::SafeFNMatch_;
1113_END_GOOGLE_NAMESPACE_
1114
1115static bool WrapSafeFNMatch(string pattern, string str) {
1116 pattern += "abc";
1117 str += "defgh";
1118 return SafeFNMatch_(pattern.data(), pattern.size() - 3,
1119 str.data(), str.size() - 5);
1120}
1121
1122TEST(SafeFNMatch, logging) {
1123 CHECK(WrapSafeFNMatch("foo", "foo"));
1124 CHECK(!WrapSafeFNMatch("foo", "bar"));
1125 CHECK(!WrapSafeFNMatch("foo", "fo"));
1126 CHECK(!WrapSafeFNMatch("foo", "foo2"));
1127 CHECK(WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext"));
1128 CHECK(WrapSafeFNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"));
1129 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/baz.ext"));
1130 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo"));
1131 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext.zip"));
1132 CHECK(WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext"));
1133 CHECK(WrapSafeFNMatch("ba?/*.ext", "baZ/FOO.ext"));
1134 CHECK(!WrapSafeFNMatch("ba?/*.ext", "barr/foo.ext"));
1135 CHECK(!WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext2"));
1136 CHECK(WrapSafeFNMatch("ba?/*", "bar/foo.ext2"));
1137 CHECK(WrapSafeFNMatch("ba?/*", "bar/"));
1138 CHECK(!WrapSafeFNMatch("ba?/?", "bar/"));
1139 CHECK(!WrapSafeFNMatch("ba?/*", "bar"));
1140}
1141
1142// TestWaitingLogSink will save messages here
1143// No lock: Accessed only by TestLogSinkWriter thread
1144// and after its demise by its creator.
1145static vector<string> global_messages;
1146
1147// helper for TestWaitingLogSink below.
1148// Thread that does the logic of TestWaitingLogSink
1149// It's free to use LOG() itself.
1150class TestLogSinkWriter : public Thread {
1151 public:
1152
1153 TestLogSinkWriter() : should_exit_(false) {
1154 SetJoinable(true);
1155 Start();
1156 }
1157
1158 // Just buffer it (can't use LOG() here).
1159 void Buffer(const string& message) {
1160 mutex_.Lock();
1161 RAW_LOG(INFO, "Buffering");
1162 messages_.push(message);
1163 mutex_.Unlock();
1164 RAW_LOG(INFO, "Buffered");
1165 }
1166
1167 // Wait for the buffer to clear (can't use LOG() here).
1168 void Wait() {
1169 RAW_LOG(INFO, "Waiting");
1170 mutex_.Lock();
1171 while (!NoWork()) {
1172 mutex_.Unlock();
1173 SleepForMilliseconds(1);
1174 mutex_.Lock();
1175 }
1176 RAW_LOG(INFO, "Waited");
1177 mutex_.Unlock();
1178 }
1179
1180 // Trigger thread exit.
1181 void Stop() {
1182 MutexLock l(&mutex_);
1183 should_exit_ = true;
1184 }
1185
1186 private:
1187
1188 // helpers ---------------
1189
1190 // For creating a "Condition".
1191 bool NoWork() { return messages_.empty(); }
1192 bool HaveWork() { return !messages_.empty() || should_exit_; }
1193
1194 // Thread body; CAN use LOG() here!
1195 virtual void Run() {
1196 while (1) {
1197 mutex_.Lock();
1198 while (!HaveWork()) {
1199 mutex_.Unlock();
1200 SleepForMilliseconds(1);
1201 mutex_.Lock();
1202 }
1203 if (should_exit_ && messages_.empty()) {
1204 mutex_.Unlock();
1205 break;
1206 }
1207 // Give the main thread time to log its message,
1208 // so that we get a reliable log capture to compare to golden file.
1209 // Same for the other sleep below.
1210 SleepForMilliseconds(20);
1211 RAW_LOG(INFO, "Sink got a messages"); // only RAW_LOG under mutex_ here
1212 string message = messages_.front();
1213 messages_.pop();
1214 // Normally this would be some more real/involved logging logic
1215 // where LOG() usage can't be eliminated,
1216 // e.g. pushing the message over with an RPC:
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001217 size_t messages_left = messages_.size();
Austin Schuh906616c2019-01-21 20:25:11 -08001218 mutex_.Unlock();
1219 SleepForMilliseconds(20);
1220 // May not use LOG while holding mutex_, because Buffer()
1221 // acquires mutex_, and Buffer is called from LOG(),
1222 // which has its own internal mutex:
1223 // LOG()->LogToSinks()->TestWaitingLogSink::send()->Buffer()
1224 LOG(INFO) << "Sink is sending out a message: " << message;
1225 LOG(INFO) << "Have " << messages_left << " left";
1226 global_messages.push_back(message);
1227 }
1228 }
1229
1230 // data ---------------
1231
1232 Mutex mutex_;
1233 bool should_exit_;
1234 queue<string> messages_; // messages to be logged
1235};
1236
1237// A log sink that exercises WaitTillSent:
1238// it pushes data to a buffer and wakes up another thread to do the logging
1239// (that other thread can than use LOG() itself),
1240class TestWaitingLogSink : public LogSink {
1241 public:
1242
1243 TestWaitingLogSink() {
1244 tid_ = pthread_self(); // for thread-specific behavior
1245 AddLogSink(this);
1246 }
1247 ~TestWaitingLogSink() {
1248 RemoveLogSink(this);
1249 writer_.Stop();
1250 writer_.Join();
1251 }
1252
1253 // (re)define LogSink interface
1254
1255 virtual void send(LogSeverity severity, const char* /* full_filename */,
1256 const char* base_filename, int line,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001257 const LogMessageTime &logmsgtime,
Austin Schuh906616c2019-01-21 20:25:11 -08001258 const char* message, size_t message_len) {
1259 // Push it to Writer thread if we are the original logging thread.
1260 // Note: Something like ThreadLocalLogSink is a better choice
1261 // to do thread-specific LogSink logic for real.
1262 if (pthread_equal(tid_, pthread_self())) {
1263 writer_.Buffer(ToString(severity, base_filename, line,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001264 logmsgtime, message, message_len));
Austin Schuh906616c2019-01-21 20:25:11 -08001265 }
1266 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001267
Austin Schuh906616c2019-01-21 20:25:11 -08001268 virtual void WaitTillSent() {
1269 // Wait for Writer thread if we are the original logging thread.
1270 if (pthread_equal(tid_, pthread_self())) writer_.Wait();
1271 }
1272
1273 private:
1274
1275 pthread_t tid_;
1276 TestLogSinkWriter writer_;
1277};
1278
1279// Check that LogSink::WaitTillSent can be used in the advertised way.
1280// We also do golden-stderr comparison.
1281static void TestLogSinkWaitTillSent() {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001282 // Clear global_messages here to make sure that this test case can be
1283 // reentered
1284 global_messages.clear();
Austin Schuh906616c2019-01-21 20:25:11 -08001285 { TestWaitingLogSink sink;
1286 // Sleeps give the sink threads time to do all their work,
1287 // so that we get a reliable log capture to compare to the golden file.
1288 LOG(INFO) << "Message 1";
1289 SleepForMilliseconds(60);
1290 LOG(ERROR) << "Message 2";
1291 SleepForMilliseconds(60);
1292 LOG(WARNING) << "Message 3";
1293 SleepForMilliseconds(60);
1294 }
1295 for (size_t i = 0; i < global_messages.size(); ++i) {
1296 LOG(INFO) << "Sink capture: " << global_messages[i];
1297 }
1298 CHECK_EQ(global_messages.size(), 3UL);
1299}
1300
1301TEST(Strerror, logging) {
1302 int errcode = EINTR;
1303 char *msg = strdup(strerror(errcode));
1304 const size_t buf_size = strlen(msg) + 1;
1305 char *buf = new char[buf_size];
1306 CHECK_EQ(posix_strerror_r(errcode, NULL, 0), -1);
1307 buf[0] = 'A';
1308 CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
1309 CHECK_EQ(buf[0], 'A');
1310 CHECK_EQ(posix_strerror_r(errcode, NULL, buf_size), -1);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001311#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || defined(GLOG_OS_OPENBSD)
Austin Schuh906616c2019-01-21 20:25:11 -08001312 // MacOSX or FreeBSD considers this case is an error since there is
1313 // no enough space.
1314 CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
1315#else
1316 CHECK_EQ(posix_strerror_r(errcode, buf, 1), 0);
1317#endif
1318 CHECK_STREQ(buf, "");
1319 CHECK_EQ(posix_strerror_r(errcode, buf, buf_size), 0);
1320 CHECK_STREQ(buf, msg);
1321 delete[] buf;
1322 CHECK_EQ(msg, StrError(errcode));
1323 free(msg);
1324}
1325
1326// Simple routines to look at the sizes of generated code for LOG(FATAL) and
1327// CHECK(..) via objdump
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001328/*
Austin Schuh906616c2019-01-21 20:25:11 -08001329static void MyFatal() {
1330 LOG(FATAL) << "Failed";
1331}
1332static void MyCheck(bool a, bool b) {
1333 CHECK_EQ(a, b);
1334}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001335*/
Austin Schuh906616c2019-01-21 20:25:11 -08001336#ifdef HAVE_LIB_GMOCK
1337
1338TEST(DVLog, Basic) {
1339 ScopedMockLog log;
1340
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001341#if defined(NDEBUG)
Austin Schuh906616c2019-01-21 20:25:11 -08001342 // We are expecting that nothing is logged.
1343 EXPECT_CALL(log, Log(_, _, _)).Times(0);
1344#else
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001345 EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "debug log"));
Austin Schuh906616c2019-01-21 20:25:11 -08001346#endif
1347
1348 FLAGS_v = 1;
1349 DVLOG(1) << "debug log";
1350}
1351
1352TEST(DVLog, V0) {
1353 ScopedMockLog log;
1354
1355 // We are expecting that nothing is logged.
1356 EXPECT_CALL(log, Log(_, _, _)).Times(0);
1357
1358 FLAGS_v = 0;
1359 DVLOG(1) << "debug log";
1360}
1361
1362TEST(LogAtLevel, Basic) {
1363 ScopedMockLog log;
1364
1365 // The function version outputs "logging.h" as a file name.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001366 EXPECT_CALL(log, Log(GLOG_WARNING, StrNe(__FILE__), "function version"));
1367 EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "macro version"));
Austin Schuh906616c2019-01-21 20:25:11 -08001368
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001369 int severity = GLOG_WARNING;
Austin Schuh906616c2019-01-21 20:25:11 -08001370 LogAtLevel(severity, "function version");
1371
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001372 severity = GLOG_INFO;
Austin Schuh906616c2019-01-21 20:25:11 -08001373 // We can use the macro version as a C++ stream.
1374 LOG_AT_LEVEL(severity) << "macro" << ' ' << "version";
1375}
1376
1377TEST(TestExitOnDFatal, ToBeOrNotToBe) {
1378 // Check the default setting...
1379 EXPECT_TRUE(base::internal::GetExitOnDFatal());
1380
1381 // Turn off...
1382 base::internal::SetExitOnDFatal(false);
1383 EXPECT_FALSE(base::internal::GetExitOnDFatal());
1384
1385 // We don't die.
1386 {
1387 ScopedMockLog log;
1388 //EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
1389 // LOG(DFATAL) has severity FATAL if debugging, but is
1390 // downgraded to ERROR if not debugging.
1391 const LogSeverity severity =
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001392#if defined(NDEBUG)
1393 GLOG_ERROR;
Austin Schuh906616c2019-01-21 20:25:11 -08001394#else
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001395 GLOG_FATAL;
Austin Schuh906616c2019-01-21 20:25:11 -08001396#endif
1397 EXPECT_CALL(log, Log(severity, __FILE__, "This should not be fatal"));
1398 LOG(DFATAL) << "This should not be fatal";
1399 }
1400
1401 // Turn back on...
1402 base::internal::SetExitOnDFatal(true);
1403 EXPECT_TRUE(base::internal::GetExitOnDFatal());
1404
1405#ifdef GTEST_HAS_DEATH_TEST
1406 // Death comes on little cats' feet.
1407 EXPECT_DEBUG_DEATH({
1408 LOG(DFATAL) << "This should be fatal in debug mode";
1409 }, "This should be fatal in debug mode");
1410#endif
1411}
1412
1413#ifdef HAVE_STACKTRACE
1414
1415static void BacktraceAtHelper() {
1416 LOG(INFO) << "Not me";
1417
1418// The vertical spacing of the next 3 lines is significant.
1419 LOG(INFO) << "Backtrace me";
1420}
1421static int kBacktraceAtLine = __LINE__ - 2; // The line of the LOG(INFO) above
1422
1423TEST(LogBacktraceAt, DoesNotBacktraceWhenDisabled) {
1424 StrictMock<ScopedMockLog> log;
1425
1426 FLAGS_log_backtrace_at = "";
1427
1428 EXPECT_CALL(log, Log(_, _, "Backtrace me"));
1429 EXPECT_CALL(log, Log(_, _, "Not me"));
1430
1431 BacktraceAtHelper();
1432}
1433
1434TEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) {
1435 StrictMock<ScopedMockLog> log;
1436
1437 char where[100];
1438 snprintf(where, 100, "%s:%d", const_basename(__FILE__), kBacktraceAtLine);
1439 FLAGS_log_backtrace_at = where;
1440
1441 // The LOG at the specified line should include a stacktrace which includes
1442 // the name of the containing function, followed by the log message.
1443 // We use HasSubstr()s instead of ContainsRegex() for environments
1444 // which don't have regexp.
1445 EXPECT_CALL(log, Log(_, _, AllOf(HasSubstr("stacktrace:"),
1446 HasSubstr("BacktraceAtHelper"),
1447 HasSubstr("main"),
1448 HasSubstr("Backtrace me"))));
1449 // Other LOGs should not include a backtrace.
1450 EXPECT_CALL(log, Log(_, _, "Not me"));
1451
1452 BacktraceAtHelper();
1453}
1454
1455#endif // HAVE_STACKTRACE
1456
1457#endif // HAVE_LIB_GMOCK
1458
1459struct UserDefinedClass {
1460 bool operator==(const UserDefinedClass&) const { return true; }
1461};
1462
1463inline ostream& operator<<(ostream& out, const UserDefinedClass&) {
1464 out << "OK";
1465 return out;
1466}
1467
1468TEST(UserDefinedClass, logging) {
1469 UserDefinedClass u;
1470 vector<string> buf;
1471 LOG_STRING(INFO, &buf) << u;
1472 CHECK_EQ(1UL, buf.size());
1473 CHECK(buf[0].find("OK") != string::npos);
1474
1475 // We must be able to compile this.
1476 CHECK_EQ(u, u);
1477}