1 //
2 // Copyright 2022 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <errno.h>
17 
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include "absl/log/internal/test_actions.h"
21 #include "absl/log/internal/test_helpers.h"
22 #include "absl/log/internal/test_matchers.h"
23 #include "absl/log/log.h"
24 #include "absl/log/log_sink.h"
25 #include "absl/log/scoped_mock_log.h"
26 #include "absl/strings/match.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/time/time.h"
29 
30 namespace {
31 #if GTEST_HAS_DEATH_TEST
32 using ::absl::log_internal::DeathTestExpectedLogging;
33 using ::absl::log_internal::DeathTestUnexpectedLogging;
34 using ::absl::log_internal::DeathTestValidateExpectations;
35 using ::absl::log_internal::DiedOfQFatal;
36 #endif
37 using ::absl::log_internal::LogSeverity;
38 using ::absl::log_internal::Prefix;
39 using ::absl::log_internal::SourceBasename;
40 using ::absl::log_internal::SourceFilename;
41 using ::absl::log_internal::SourceLine;
42 using ::absl::log_internal::Stacktrace;
43 using ::absl::log_internal::TextMessage;
44 using ::absl::log_internal::TextMessageWithPrefix;
45 using ::absl::log_internal::TextMessageWithPrefixAndNewline;
46 using ::absl::log_internal::TextPrefix;
47 using ::absl::log_internal::ThreadID;
48 using ::absl::log_internal::Timestamp;
49 using ::absl::log_internal::Verbosity;
50 
51 using ::testing::AllOf;
52 using ::testing::AnyNumber;
53 using ::testing::AnyOf;
54 using ::testing::Eq;
55 using ::testing::IsEmpty;
56 using ::testing::IsFalse;
57 using ::testing::Truly;
58 
TEST(TailCallsModifiesTest,AtLocationFileLine)59 TEST(TailCallsModifiesTest, AtLocationFileLine) {
60   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
61 
62   EXPECT_CALL(
63       test_sink,
64       Send(AllOf(
65           // The metadata should change:
66           SourceFilename(Eq("/my/very/very/very_long_source_file.cc")),
67           SourceBasename(Eq("very_long_source_file.cc")), SourceLine(Eq(777)),
68           // The logged line should change too, even though the prefix must
69           // grow to fit the new metadata.
70           TextMessageWithPrefix(Truly([](absl::string_view msg) {
71             return absl::EndsWith(msg,
72                                   " very_long_source_file.cc:777] hello world");
73           })))));
74 
75   test_sink.StartCapturingLogs();
76   LOG(INFO).AtLocation("/my/very/very/very_long_source_file.cc", 777)
77       << "hello world";
78 }
79 
TEST(TailCallsModifiesTest,NoPrefix)80 TEST(TailCallsModifiesTest, NoPrefix) {
81   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
82 
83   EXPECT_CALL(test_sink, Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
84                                     TextMessageWithPrefix(Eq("hello world")))));
85 
86   test_sink.StartCapturingLogs();
87   LOG(INFO).NoPrefix() << "hello world";
88 }
89 
TEST(TailCallsModifiesTest,NoPrefixNoMessageNoShirtNoShoesNoService)90 TEST(TailCallsModifiesTest, NoPrefixNoMessageNoShirtNoShoesNoService) {
91   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
92 
93   EXPECT_CALL(test_sink,
94               Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
95                          TextMessageWithPrefix(IsEmpty()),
96                          TextMessageWithPrefixAndNewline(Eq("\n")))));
97   test_sink.StartCapturingLogs();
98   LOG(INFO).NoPrefix();
99 }
100 
TEST(TailCallsModifiesTest,WithVerbosity)101 TEST(TailCallsModifiesTest, WithVerbosity) {
102   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
103 
104   EXPECT_CALL(test_sink, Send(Verbosity(Eq(2))));
105 
106   test_sink.StartCapturingLogs();
107   LOG(INFO).WithVerbosity(2) << "hello world";
108 }
109 
TEST(TailCallsModifiesTest,WithVerbosityNoVerbosity)110 TEST(TailCallsModifiesTest, WithVerbosityNoVerbosity) {
111   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
112 
113   EXPECT_CALL(test_sink,
114               Send(Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel))));
115 
116   test_sink.StartCapturingLogs();
117   LOG(INFO).WithVerbosity(2).WithVerbosity(absl::LogEntry::kNoVerbosityLevel)
118       << "hello world";
119 }
120 
TEST(TailCallsModifiesTest,WithTimestamp)121 TEST(TailCallsModifiesTest, WithTimestamp) {
122   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
123 
124   EXPECT_CALL(test_sink, Send(Timestamp(Eq(absl::UnixEpoch()))));
125 
126   test_sink.StartCapturingLogs();
127   LOG(INFO).WithTimestamp(absl::UnixEpoch()) << "hello world";
128 }
129 
TEST(TailCallsModifiesTest,WithThreadID)130 TEST(TailCallsModifiesTest, WithThreadID) {
131   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
132 
133   EXPECT_CALL(test_sink,
134               Send(AllOf(ThreadID(Eq(absl::LogEntry::tid_t{1234})))));
135 
136   test_sink.StartCapturingLogs();
137   LOG(INFO).WithThreadID(1234) << "hello world";
138 }
139 
TEST(TailCallsModifiesTest,WithMetadataFrom)140 TEST(TailCallsModifiesTest, WithMetadataFrom) {
141   class ForwardingLogSink : public absl::LogSink {
142    public:
143     void Send(const absl::LogEntry &entry) override {
144       LOG(LEVEL(entry.log_severity())).WithMetadataFrom(entry)
145           << "forwarded: " << entry.text_message();
146     }
147   } forwarding_sink;
148 
149   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
150 
151   EXPECT_CALL(
152       test_sink,
153       Send(AllOf(SourceFilename(Eq("fake/file")), SourceBasename(Eq("file")),
154                  SourceLine(Eq(123)), Prefix(IsFalse()),
155                  LogSeverity(Eq(absl::LogSeverity::kWarning)),
156                  Timestamp(Eq(absl::UnixEpoch())),
157                  ThreadID(Eq(absl::LogEntry::tid_t{456})),
158                  TextMessage(Eq("forwarded: hello world")), Verbosity(Eq(7)),
159                  ENCODED_MESSAGE(
160                      EqualsProto(R"pb(value { literal: "forwarded: " }
161                                       value { str: "hello world" })pb")))));
162 
163   test_sink.StartCapturingLogs();
164   LOG(WARNING)
165           .AtLocation("fake/file", 123)
166           .NoPrefix()
167           .WithTimestamp(absl::UnixEpoch())
168           .WithThreadID(456)
169           .WithVerbosity(7)
170           .ToSinkOnly(&forwarding_sink)
171       << "hello world";
172 }
173 
TEST(TailCallsModifiesTest,WithPerror)174 TEST(TailCallsModifiesTest, WithPerror) {
175   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
176 
177   EXPECT_CALL(
178       test_sink,
179       Send(AllOf(TextMessage(AnyOf(Eq("hello world: Bad file number [9]"),
180                                    Eq("hello world: Bad file descriptor [9]"),
181                                    Eq("hello world: Bad file descriptor [8]"))),
182                  ENCODED_MESSAGE(
183                      AnyOf(EqualsProto(R"pb(value { literal: "hello world" }
184                                             value { literal: ": " }
185                                             value { str: "Bad file number" }
186                                             value { literal: " [" }
187                                             value { str: "9" }
188                                             value { literal: "]" })pb"),
189                            EqualsProto(R"pb(value { literal: "hello world" }
190                                             value { literal: ": " }
191                                             value { str: "Bad file descriptor" }
192                                             value { literal: " [" }
193                                             value { str: "9" }
194                                             value { literal: "]" })pb"),
195                            EqualsProto(R"pb(value { literal: "hello world" }
196                                             value { literal: ": " }
197                                             value { str: "Bad file descriptor" }
198                                             value { literal: " [" }
199                                             value { str: "8" }
200                                             value { literal: "]" })pb"))))));
201 
202   test_sink.StartCapturingLogs();
203   errno = EBADF;
204   LOG(INFO).WithPerror() << "hello world";
205 }
206 
207 #if GTEST_HAS_DEATH_TEST
TEST(ModifierMethodDeathTest,ToSinkOnlyQFatal)208 TEST(ModifierMethodDeathTest, ToSinkOnlyQFatal) {
209   EXPECT_EXIT(
210       {
211         absl::ScopedMockLog test_sink(
212             absl::MockLogDefault::kDisallowUnexpected);
213 
214         auto do_log = [&test_sink] {
215           LOG(QFATAL).ToSinkOnly(&test_sink.UseAsLocalSink()) << "hello world";
216         };
217 
218         EXPECT_CALL(test_sink, Send)
219             .Times(AnyNumber())
220             .WillRepeatedly(DeathTestUnexpectedLogging());
221 
222         EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("hello world")),
223                                           Stacktrace(IsEmpty()))))
224             .WillOnce(DeathTestExpectedLogging());
225 
226         test_sink.StartCapturingLogs();
227         do_log();
228       },
229       DiedOfQFatal, DeathTestValidateExpectations());
230 }
231 #endif
232 
233 }  // namespace
234