83724f29d11c59038575847c4503387a31a28784
[folly.git] / folly / experimental / logging / test / FileHandlerFactoryTest.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
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  *   http://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 <folly/experimental/logging/FileHandlerFactory.h>
17
18 #include <folly/Exception.h>
19 #include <folly/experimental/TestUtil.h>
20 #include <folly/experimental/logging/AsyncFileWriter.h>
21 #include <folly/experimental/logging/GlogStyleFormatter.h>
22 #include <folly/experimental/logging/ImmediateFileWriter.h>
23 #include <folly/experimental/logging/StandardLogHandler.h>
24 #include <folly/portability/GTest.h>
25
26 using namespace folly;
27 using folly::test::TemporaryFile;
28 using std::make_pair;
29
30 void checkAsyncWriter(
31     const LogWriter* writer,
32     const char* expectedPath,
33     size_t expectedMaxBufferSize) {
34   auto asyncWriter = dynamic_cast<const AsyncFileWriter*>(writer);
35   ASSERT_TRUE(asyncWriter)
36       << "FileHandlerFactory should have created an AsyncFileWriter";
37   EXPECT_EQ(expectedMaxBufferSize, asyncWriter->getMaxBufferSize());
38
39   // Make sure this refers to the expected output file
40   struct stat expectedStatInfo;
41   checkUnixError(stat(expectedPath, &expectedStatInfo), "stat failed");
42   struct stat actualStatInfo;
43   checkUnixError(
44       fstat(asyncWriter->getFile().fd(), &actualStatInfo), "fstat failed");
45   EXPECT_EQ(expectedStatInfo.st_dev, actualStatInfo.st_dev);
46   EXPECT_EQ(expectedStatInfo.st_ino, actualStatInfo.st_ino);
47 }
48
49 void checkAsyncWriter(
50     const LogWriter* writer,
51     int expectedFD,
52     size_t expectedMaxBufferSize) {
53   auto asyncWriter = dynamic_cast<const AsyncFileWriter*>(writer);
54   ASSERT_TRUE(asyncWriter)
55       << "FileHandlerFactory should have created an AsyncFileWriter";
56   EXPECT_EQ(expectedMaxBufferSize, asyncWriter->getMaxBufferSize());
57   EXPECT_EQ(expectedFD, asyncWriter->getFile().fd());
58 }
59
60 TEST(FileHandlerFactory, pathOnly) {
61   FileHandlerFactory factory;
62
63   TemporaryFile tmpFile{"logging_test"};
64   auto options = FileHandlerFactory::Options{
65       make_pair("path", tmpFile.path().string()),
66   };
67   auto handler = factory.createHandler(options);
68
69   auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
70   ASSERT_TRUE(stdHandler);
71
72   auto formatter =
73       std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
74   EXPECT_TRUE(formatter)
75       << "FileHandlerFactory should have created a GlogStyleFormatter";
76
77   checkAsyncWriter(
78       stdHandler->getWriter().get(),
79       tmpFile.path().string().c_str(),
80       AsyncFileWriter::kDefaultMaxBufferSize);
81 }
82
83 TEST(FileHandlerFactory, stderrStream) {
84   FileHandlerFactory factory;
85
86   TemporaryFile tmpFile{"logging_test"};
87   auto options = FileHandlerFactory::Options{
88       make_pair("stream", "stderr"),
89   };
90   auto handler = factory.createHandler(options);
91
92   auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
93   ASSERT_TRUE(stdHandler);
94
95   auto formatter =
96       std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
97   EXPECT_TRUE(formatter)
98       << "FileHandlerFactory should have created a GlogStyleFormatter";
99
100   checkAsyncWriter(
101       stdHandler->getWriter().get(),
102       STDERR_FILENO,
103       AsyncFileWriter::kDefaultMaxBufferSize);
104 }
105
106 TEST(FileHandlerFactory, stdoutWithMaxBuffer) {
107   FileHandlerFactory factory;
108
109   TemporaryFile tmpFile{"logging_test"};
110   auto options = FileHandlerFactory::Options{
111       make_pair("stream", "stdout"),
112       make_pair("max_buffer_size", "4096"),
113   };
114   auto handler = factory.createHandler(options);
115
116   auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
117   ASSERT_TRUE(stdHandler);
118
119   auto formatter =
120       std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
121   EXPECT_TRUE(formatter)
122       << "FileHandlerFactory should have created a GlogStyleFormatter";
123
124   checkAsyncWriter(stdHandler->getWriter().get(), STDOUT_FILENO, 4096);
125 }
126
127 TEST(FileHandlerFactory, pathWithMaxBufferSize) {
128   FileHandlerFactory factory;
129
130   TemporaryFile tmpFile{"logging_test"};
131   auto options = FileHandlerFactory::Options{
132       make_pair("path", tmpFile.path().string()),
133       make_pair("max_buffer_size", "4096000"),
134   };
135   auto handler = factory.createHandler(options);
136
137   auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
138   ASSERT_TRUE(stdHandler);
139
140   auto formatter =
141       std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
142   EXPECT_TRUE(formatter)
143       << "FileHandlerFactory should have created a GlogStyleFormatter";
144
145   checkAsyncWriter(
146       stdHandler->getWriter().get(), tmpFile.path().string().c_str(), 4096000);
147 }
148
149 TEST(FileHandlerFactory, nonAsyncStderr) {
150   FileHandlerFactory factory;
151
152   TemporaryFile tmpFile{"logging_test"};
153   auto options = FileHandlerFactory::Options{
154       make_pair("stream", "stderr"),
155       make_pair("async", "no"),
156   };
157   auto handler = factory.createHandler(options);
158
159   auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
160   ASSERT_TRUE(stdHandler);
161
162   auto formatter =
163       std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
164   EXPECT_TRUE(formatter)
165       << "FileHandlerFactory should have created a GlogStyleFormatter";
166
167   auto writer =
168       std::dynamic_pointer_cast<ImmediateFileWriter>(stdHandler->getWriter());
169   ASSERT_TRUE(writer);
170   EXPECT_EQ(STDERR_FILENO, writer->getFile().fd());
171 }
172
173 TEST(FileHandlerFactory, errors) {
174   FileHandlerFactory factory;
175   TemporaryFile tmpFile{"logging_test"};
176
177   {
178     auto options = FileHandlerFactory::Options{};
179     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
180         << "one of path or stream required";
181   }
182
183   {
184     auto options = FileHandlerFactory::Options{
185         make_pair("path", tmpFile.path().string()),
186         make_pair("stream", "stderr"),
187     };
188     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
189         << "path and stream cannot both be specified";
190   }
191
192   {
193     auto options = FileHandlerFactory::Options{
194         make_pair("stream", "nonstdout"),
195     };
196     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
197         << "invalid stream";
198   }
199
200   {
201     auto options = FileHandlerFactory::Options{
202         make_pair("stream", "stderr"),
203         make_pair("async", "foobar"),
204     };
205     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
206         << "invalid async value";
207   }
208
209   {
210     auto options = FileHandlerFactory::Options{
211         make_pair("stream", "stderr"),
212         make_pair("async", "false"),
213         make_pair("max_buffer_size", "1234"),
214     };
215     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
216         << "max_buffer_size only valid for async writers";
217   }
218
219   {
220     auto options = FileHandlerFactory::Options{
221         make_pair("stream", "stderr"),
222         make_pair("max_buffer_size", "hello"),
223     };
224     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
225         << "max_buffer_size must be an integer";
226   }
227
228   {
229     auto options = FileHandlerFactory::Options{
230         make_pair("stream", "stderr"),
231         make_pair("max_buffer_size", "0"),
232     };
233     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
234         << "max_buffer_size must be a positive integer";
235   }
236
237   {
238     auto options = FileHandlerFactory::Options{
239         make_pair("stream", "stderr"),
240         make_pair("foo", "bar"),
241     };
242     EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
243         << "unknown parameter foo";
244   }
245 }