1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 
7 #include "logging/env_logger.h"
8 #include "env/mock_env.h"
9 #include "test_util/testharness.h"
10 #include "test_util/testutil.h"
11 
12 namespace ROCKSDB_NAMESPACE {
13 
14 namespace {
15 // In this test we only want to Log some simple log message with
16 // no format.
LogMessage(std::shared_ptr<Logger> logger,const std::string & message)17 void LogMessage(std::shared_ptr<Logger> logger, const std::string& message) {
18   Log(logger, "%s", message.c_str());
19 }
20 
21 // Helper method to write the message num_times in the given logger.
WriteLogs(std::shared_ptr<Logger> logger,const std::string & message,int num_times)22 void WriteLogs(std::shared_ptr<Logger> logger, const std::string& message,
23                int num_times) {
24   for (int ii = 0; ii < num_times; ++ii) {
25     LogMessage(logger, message);
26   }
27 }
28 
29 }  // namespace
30 
31 class EnvLoggerTest : public testing::Test {
32  public:
33   Env* env_;
34 
EnvLoggerTest()35   EnvLoggerTest() : env_(Env::Default()) {}
36 
37   ~EnvLoggerTest() = default;
38 
CreateLogger()39   std::shared_ptr<Logger> CreateLogger() {
40     std::shared_ptr<Logger> result;
41     assert(NewEnvLogger(kLogFile, env_, &result).ok());
42     assert(result);
43     result->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
44     return result;
45   }
46 
DeleteLogFile()47   void DeleteLogFile() { ASSERT_OK(env_->DeleteFile(kLogFile)); }
48 
49   static const std::string kSampleMessage;
50   static const std::string kTestDir;
51   static const std::string kLogFile;
52 };
53 
54 const std::string EnvLoggerTest::kSampleMessage =
55     "this is the message to be written to the log file!!";
56 const std::string EnvLoggerTest::kLogFile = test::PerThreadDBPath("log_file");
57 
TEST_F(EnvLoggerTest,EmptyLogFile)58 TEST_F(EnvLoggerTest, EmptyLogFile) {
59   auto logger = CreateLogger();
60   ASSERT_EQ(logger->Close(), Status::OK());
61 
62   // Check the size of the log file.
63   uint64_t file_size;
64   ASSERT_EQ(env_->GetFileSize(kLogFile, &file_size), Status::OK());
65   ASSERT_EQ(file_size, 0);
66   DeleteLogFile();
67 }
68 
TEST_F(EnvLoggerTest,LogMultipleLines)69 TEST_F(EnvLoggerTest, LogMultipleLines) {
70   auto logger = CreateLogger();
71 
72   // Write multiple lines.
73   const int kNumIter = 10;
74   WriteLogs(logger, kSampleMessage, kNumIter);
75 
76   // Flush the logs.
77   logger->Flush();
78   ASSERT_EQ(logger->Close(), Status::OK());
79 
80   // Validate whether the log file has 'kNumIter' number of lines.
81   ASSERT_EQ(test::GetLinesCount(kLogFile, kSampleMessage), kNumIter);
82   DeleteLogFile();
83 }
84 
TEST_F(EnvLoggerTest,Overwrite)85 TEST_F(EnvLoggerTest, Overwrite) {
86   {
87     auto logger = CreateLogger();
88 
89     // Write multiple lines.
90     const int kNumIter = 10;
91     WriteLogs(logger, kSampleMessage, kNumIter);
92 
93     ASSERT_EQ(logger->Close(), Status::OK());
94 
95     // Validate whether the log file has 'kNumIter' number of lines.
96     ASSERT_EQ(test::GetLinesCount(kLogFile, kSampleMessage), kNumIter);
97   }
98 
99   // Now reopen the file again.
100   {
101     auto logger = CreateLogger();
102 
103     // File should be empty.
104     uint64_t file_size;
105     ASSERT_EQ(env_->GetFileSize(kLogFile, &file_size), Status::OK());
106     ASSERT_EQ(file_size, 0);
107     ASSERT_EQ(logger->GetLogFileSize(), 0);
108     ASSERT_EQ(logger->Close(), Status::OK());
109   }
110   DeleteLogFile();
111 }
112 
TEST_F(EnvLoggerTest,Close)113 TEST_F(EnvLoggerTest, Close) {
114   auto logger = CreateLogger();
115 
116   // Write multiple lines.
117   const int kNumIter = 10;
118   WriteLogs(logger, kSampleMessage, kNumIter);
119 
120   ASSERT_EQ(logger->Close(), Status::OK());
121 
122   // Validate whether the log file has 'kNumIter' number of lines.
123   ASSERT_EQ(test::GetLinesCount(kLogFile, kSampleMessage), kNumIter);
124   DeleteLogFile();
125 }
126 
TEST_F(EnvLoggerTest,ConcurrentLogging)127 TEST_F(EnvLoggerTest, ConcurrentLogging) {
128   auto logger = CreateLogger();
129 
130   const int kNumIter = 20;
131   std::function<void()> cb = [&]() {
132     WriteLogs(logger, kSampleMessage, kNumIter);
133     logger->Flush();
134   };
135 
136   // Write to the logs from multiple threads.
137   std::vector<port::Thread> threads;
138   const int kNumThreads = 5;
139   // Create threads.
140   for (int ii = 0; ii < kNumThreads; ++ii) {
141     threads.push_back(port::Thread(cb));
142   }
143 
144   // Wait for them to complete.
145   for (auto& th : threads) {
146     th.join();
147   }
148 
149   ASSERT_EQ(logger->Close(), Status::OK());
150 
151   // Verfiy the log file.
152   ASSERT_EQ(test::GetLinesCount(kLogFile, kSampleMessage),
153             kNumIter * kNumThreads);
154   DeleteLogFile();
155 }
156 
157 }  // namespace ROCKSDB_NAMESPACE
158 
main(int argc,char ** argv)159 int main(int argc, char** argv) {
160   ::testing::InitGoogleTest(&argc, argv);
161   return RUN_ALL_TESTS();
162 }
163