Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2020 The Android Open Source Project |
| 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 | |
| 17 | #pragma once |
| 18 | |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 19 | #include <chrono> |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 20 | #include <mutex> |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 21 | #include <string> |
| 22 | #include <vector> |
| 23 | |
| 24 | #include <gtest/gtest.h> |
| 25 | |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 26 | #include "LogBuffer.h" |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 27 | #include "LogReaderList.h" |
| 28 | #include "LogStatistics.h" |
| 29 | #include "LogTags.h" |
Tom Cherry | 3236191 | 2020-06-16 10:14:09 -0700 | [diff] [blame] | 30 | #include "PruneList.h" |
Tom Cherry | fb150dd | 2020-05-13 09:28:37 -0700 | [diff] [blame] | 31 | #include "SerializedLogBuffer.h" |
Tom Cherry | 0c6eb46 | 2020-05-12 12:46:43 -0700 | [diff] [blame] | 32 | #include "SimpleLogBuffer.h" |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 33 | |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 34 | using namespace std::chrono_literals; |
| 35 | |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 36 | struct LogMessage { |
| 37 | logger_entry entry; |
| 38 | std::string message; |
| 39 | bool regex_compare = false; // Only set for expected messages, when true 'message' should be |
| 40 | // interpretted as a regex. |
| 41 | }; |
| 42 | |
| 43 | // Compares the ordered list of expected and result, causing a test failure with appropriate |
| 44 | // information on failure. |
| 45 | void CompareLogMessages(const std::vector<LogMessage>& expected, |
| 46 | const std::vector<LogMessage>& result); |
| 47 | // Sets hdr_size and len parameters appropriately. |
| 48 | void FixupMessages(std::vector<LogMessage>* messages); |
| 49 | |
| 50 | class TestWriter : public LogWriter { |
| 51 | public: |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 52 | TestWriter(std::vector<LogMessage>* msgs, std::mutex* mutex, bool* released) |
| 53 | : LogWriter(0, true), mutex_(mutex ?: &logd_lock), msgs_(msgs), released_(released) {} |
| 54 | |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 55 | bool Write(const logger_entry& entry, const char* message) override { |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 56 | auto lock = std::lock_guard{*mutex_}; |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 57 | msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false}); |
| 58 | return true; |
| 59 | } |
| 60 | |
| 61 | void Release() { |
| 62 | if (released_) *released_ = true; |
| 63 | } |
| 64 | |
| 65 | std::string name() const override { return "test_writer"; } |
| 66 | |
| 67 | private: |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 68 | std::mutex* mutex_; |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 69 | std::vector<LogMessage>* msgs_; |
| 70 | bool* released_; |
| 71 | }; |
| 72 | |
| 73 | class LogBufferTest : public testing::TestWithParam<std::string> { |
| 74 | protected: |
| 75 | void SetUp() override { |
Elliott Hughes | 225e5c6 | 2022-09-16 23:01:59 +0000 | [diff] [blame] | 76 | if (GetParam() == "serialized") { |
Tom Cherry | fb150dd | 2020-05-13 09:28:37 -0700 | [diff] [blame] | 77 | log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_)); |
Tom Cherry | 0c6eb46 | 2020-05-12 12:46:43 -0700 | [diff] [blame] | 78 | } else if (GetParam() == "simple") { |
| 79 | log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_)); |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 80 | } else { |
| 81 | FAIL() << "Unknown buffer type selected for test"; |
| 82 | } |
Tom Cherry | 8022895 | 2020-08-05 12:14:45 -0700 | [diff] [blame] | 83 | |
| 84 | log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); } |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | void LogMessages(const std::vector<LogMessage>& messages) { |
| 88 | for (auto& [entry, message, _] : messages) { |
Tom Cherry | 0f7ec30 | 2020-11-13 10:52:35 -0800 | [diff] [blame] | 89 | EXPECT_GT(log_buffer_->Log(static_cast<log_id_t>(entry.lid), |
| 90 | log_time(entry.sec, entry.nsec), entry.uid, entry.pid, |
| 91 | entry.tid, message.c_str(), message.size()), |
| 92 | 0); |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 93 | } |
| 94 | } |
| 95 | |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 96 | struct FlushMessagesResult { |
| 97 | std::vector<LogMessage> messages; |
| 98 | uint64_t next_sequence; |
| 99 | }; |
| 100 | |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 101 | FlushMessagesResult FlushMessages(std::mutex* mutex = nullptr) { |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 102 | std::vector<LogMessage> read_log_messages; |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 103 | std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, mutex, nullptr)); |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 104 | |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 105 | auto lock = std::lock_guard{logd_lock}; |
| 106 | auto flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll); |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 107 | EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr)); |
| 108 | return {read_log_messages, flush_to_state->start()}; |
| 109 | } |
| 110 | |
| 111 | struct ReaderThreadParams { |
| 112 | bool non_block = true; |
| 113 | unsigned long tail = 0; |
| 114 | LogMask log_mask = kLogMaskAll; |
| 115 | pid_t pid = 0; |
| 116 | log_time start_time = {}; |
| 117 | uint64_t sequence = 1; |
| 118 | std::chrono::steady_clock::time_point deadline = {}; |
| 119 | }; |
| 120 | |
| 121 | class TestReaderThread { |
| 122 | public: |
| 123 | TestReaderThread(const ReaderThreadParams& params, LogBufferTest& test) : test_(test) { |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 124 | auto lock = std::lock_guard{mutex_}; |
| 125 | std::unique_ptr<LogWriter> test_writer( |
| 126 | new TestWriter(&read_log_messages_, &mutex_, &released_)); |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 127 | std::unique_ptr<LogReaderThread> log_reader(new LogReaderThread( |
| 128 | test_.log_buffer_.get(), &test_.reader_list_, std::move(test_writer), |
| 129 | params.non_block, params.tail, params.log_mask, params.pid, params.start_time, |
| 130 | params.sequence, params.deadline)); |
Wenhao Wang | b1f6c6c | 2021-11-19 16:42:43 -0800 | [diff] [blame] | 131 | test_.reader_list_.AddAndRunThread(std::move(log_reader)); |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | void WaitUntilReleased() { |
| 135 | while (!released_) { |
| 136 | usleep(5000); |
| 137 | } |
| 138 | } |
| 139 | |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 140 | std::vector<LogMessage> WaitForMessages(size_t n) { |
| 141 | int retry_count = 1s / 5000us; |
| 142 | while (retry_count--) { |
| 143 | usleep(5000); |
| 144 | auto lock = std::lock_guard{mutex_}; |
| 145 | if (read_log_messages_.size() == n) { |
| 146 | return read_log_messages_; |
| 147 | } |
| 148 | } |
| 149 | return {}; |
| 150 | } |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 151 | |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 152 | std::vector<LogMessage> read_log_messages() { |
| 153 | auto lock = std::lock_guard{mutex_}; |
| 154 | return read_log_messages_; |
| 155 | } |
| 156 | |
| 157 | private: |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 158 | LogBufferTest& test_; |
mtk27743 | 4860765 | 2022-09-06 14:49:30 +0800 | [diff] [blame] | 159 | std::mutex mutex_; |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 160 | std::vector<LogMessage> read_log_messages_; |
| 161 | bool released_ = false; |
| 162 | }; |
| 163 | |
| 164 | std::vector<LogMessage> ReadLogMessagesNonBlockingThread(const ReaderThreadParams& params) { |
| 165 | EXPECT_TRUE(params.non_block) |
| 166 | << "params.non_block must be true for ReadLogMessagesNonBlockingThread()"; |
| 167 | |
| 168 | auto reader = TestReaderThread(params, *this); |
| 169 | reader.WaitUntilReleased(); |
| 170 | auto lock = std::lock_guard{logd_lock}; |
Wenhao Wang | b1f6c6c | 2021-11-19 16:42:43 -0800 | [diff] [blame] | 171 | EXPECT_EQ(0U, reader_list_.running_reader_threads().size()); |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 172 | |
| 173 | return reader.read_log_messages(); |
| 174 | } |
| 175 | |
| 176 | void ReleaseAndJoinReaders() { |
| 177 | { |
| 178 | auto lock = std::lock_guard{logd_lock}; |
Wenhao Wang | b1f6c6c | 2021-11-19 16:42:43 -0800 | [diff] [blame] | 179 | for (auto& reader : reader_list_.running_reader_threads()) { |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 180 | reader->Release(); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | auto retries = 1s / 5000us; |
| 185 | while (retries--) { |
| 186 | usleep(5000); |
| 187 | auto lock = std::lock_guard{logd_lock}; |
Wenhao Wang | b1f6c6c | 2021-11-19 16:42:43 -0800 | [diff] [blame] | 188 | if (reader_list_.running_reader_threads().size() == 0) { |
Tom Cherry | 60a08d8 | 2020-11-18 14:24:07 -0800 | [diff] [blame] | 189 | return; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | FAIL() << "ReleaseAndJoinReaders() timed out with reader threads still running"; |
| 194 | } |
| 195 | |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 196 | LogReaderList reader_list_; |
| 197 | LogTags tags_; |
| 198 | PruneList prune_; |
Tom Cherry | a3d6aa6 | 2020-06-19 12:21:21 -0700 | [diff] [blame] | 199 | LogStatistics stats_{false, true}; |
Tom Cherry | 6bc6f49 | 2020-05-21 12:13:20 -0700 | [diff] [blame] | 200 | std::unique_ptr<LogBuffer> log_buffer_; |
| 201 | }; |