| /* |
| * The MIT License (MIT) |
| * |
| * Copyright (c) 2015 Microsoft Corporation |
| * |
| * -=- Robust Distributed System Nucleus (rDSN) -=- |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| */ |
| |
| #include <fmt/core.h> |
| #include <unistd.h> |
| #include <memory> |
| #include <regex> |
| #include <set> |
| #include <string> |
| #include <thread> |
| #include <utility> |
| #include <vector> |
| |
| #include "gtest/gtest.h" |
| #include "utils/api_utilities.h" |
| #include "utils/filesystem.h" |
| #include "utils/flags.h" |
| #include "utils/logging_provider.h" |
| #include "utils/simple_logger.h" |
| #include "utils/test_macros.h" |
| |
| DSN_DECLARE_uint64(max_number_of_log_files_on_disk); |
| |
| namespace dsn { |
| namespace tools { |
| class logger_test : public testing::Test |
| { |
| public: |
| void SetUp() override |
| { |
| // Deregister commands to avoid re-register error. |
| dsn::logging_provider::instance()->deregister_commands(); |
| } |
| }; |
| |
| class simple_logger_test : public logger_test |
| { |
| public: |
| void SetUp() override |
| { |
| logger_test::SetUp(); |
| |
| std::string cwd; |
| ASSERT_TRUE(dsn::utils::filesystem::get_current_directory(cwd)); |
| // NOTE: Don't name the dir with "test", otherwise the whole utils test dir would be |
| // removed. |
| test_dir = dsn::utils::filesystem::path_combine(cwd, "simple_logger_test"); |
| |
| NO_FATALS(prepare_test_dir()); |
| std::set<std::string> files; |
| NO_FATALS(get_log_files(files)); |
| NO_FATALS(clear_files(files)); |
| } |
| |
| void get_log_files(std::set<std::string> &file_names) |
| { |
| std::vector<std::string> sub_list; |
| ASSERT_TRUE(utils::filesystem::get_subfiles(test_dir, sub_list, false)); |
| |
| file_names.clear(); |
| std::regex pattern(R"(SimpleLogger\.log\.[0-9]{8}_[0-9]{6}_[0-9]{3})"); |
| for (const auto &path : sub_list) { |
| std::string name(utils::filesystem::get_file_name(path)); |
| if (std::regex_match(name, pattern)) { |
| ASSERT_TRUE(file_names.insert(name).second); |
| } |
| } |
| } |
| |
| void compare_log_files(const std::set<std::string> &before_files, |
| const std::set<std::string> &after_files) |
| { |
| ASSERT_FALSE(after_files.empty()); |
| |
| // One new log file is created. |
| if (after_files.size() == before_files.size() + 1) { |
| // All the file names are the same. |
| for (auto it1 = before_files.begin(), it2 = after_files.begin(); |
| it1 != before_files.end(); |
| ++it1, ++it2) { |
| ASSERT_EQ(*it1, *it2); |
| } |
| // The number of log files is the same, but they have rolled. |
| } else if (after_files.size() == before_files.size()) { |
| auto it1 = before_files.begin(); |
| auto it2 = after_files.begin(); |
| // The first file is different, the one in 'before_files' is older. |
| ASSERT_NE(*it1, *it2); |
| |
| // The rest of the files are the same. |
| for (++it1; it1 != before_files.end(); ++it1, ++it2) { |
| ASSERT_EQ(*it1, *it2); |
| } |
| } else { |
| ASSERT_TRUE(false) << "Invalid number of log files, before=" << before_files.size() |
| << ", after=" << after_files.size(); |
| } |
| } |
| |
| void clear_files(const std::set<std::string> &file_names) |
| { |
| for (const auto &file_name : file_names) { |
| ASSERT_TRUE(dsn::utils::filesystem::remove_path(file_name)); |
| } |
| } |
| |
| void prepare_test_dir() |
| { |
| ASSERT_TRUE(dsn::utils::filesystem::create_directory(test_dir)) << test_dir; |
| } |
| |
| void remove_test_dir() |
| { |
| ASSERT_TRUE(dsn::utils::filesystem::remove_path(test_dir)) << test_dir; |
| } |
| |
| public: |
| std::string test_dir; |
| }; |
| |
| #define LOG_PRINT(logger, ...) \ |
| (logger)->log( \ |
| __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_DEBUG, fmt::format(__VA_ARGS__).c_str()) |
| |
| TEST_F(logger_test, screen_logger_test) |
| { |
| auto logger = std::make_unique<screen_logger>(nullptr, nullptr); |
| LOG_PRINT(logger.get(), "{}", "test_print"); |
| std::thread t([](screen_logger *lg) { LOG_PRINT(lg, "{}", "test_print"); }, logger.get()); |
| t.join(); |
| logger->flush(); |
| } |
| |
| TEST_F(simple_logger_test, redundant_log_test) |
| { |
| // Create redundant log files to test if their number could be restricted. |
| for (unsigned int i = 0; i < FLAGS_max_number_of_log_files_on_disk + 10; ++i) { |
| std::set<std::string> before_files; |
| NO_FATALS(get_log_files(before_files)); |
| |
| auto logger = std::make_unique<simple_logger>(test_dir.c_str(), "SimpleLogger"); |
| for (unsigned int i = 0; i != 1000; ++i) { |
| LOG_PRINT(logger.get(), "{}", "test_print"); |
| } |
| logger->flush(); |
| |
| std::set<std::string> after_files; |
| NO_FATALS(get_log_files(after_files)); |
| NO_FATALS(compare_log_files(before_files, after_files)); |
| ::usleep(2000); |
| } |
| |
| std::set<std::string> files; |
| NO_FATALS(get_log_files(files)); |
| ASSERT_FALSE(files.empty()); |
| ASSERT_EQ(FLAGS_max_number_of_log_files_on_disk, files.size()); |
| } |
| |
| } // namespace tools |
| } // namespace dsn |