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 19 #include <chrono> 20 #include <mutex> 21 #include <string> 22 #include <vector> 23 24 #include <gtest/gtest.h> 25 26 #include "LogBuffer.h" 27 #include "LogReaderList.h" 28 #include "LogStatistics.h" 29 #include "LogTags.h" 30 #include "PruneList.h" 31 #include "SerializedLogBuffer.h" 32 #include "SimpleLogBuffer.h" 33 34 using namespace std::chrono_literals; 35 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: TestWriter(std::vector<LogMessage> * msgs,std::mutex * mutex,bool * released)52 TestWriter(std::vector<LogMessage>* msgs, std::mutex* mutex, bool* released) 53 : LogWriter(0, true), mutex_(mutex ?: &logd_lock), msgs_(msgs), released_(released) {} 54 Write(const logger_entry & entry,const char * message)55 bool Write(const logger_entry& entry, const char* message) override { 56 auto lock = std::lock_guard{*mutex_}; 57 msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false}); 58 return true; 59 } 60 Release()61 void Release() { 62 if (released_) *released_ = true; 63 } 64 name()65 std::string name() const override { return "test_writer"; } 66 67 private: 68 std::mutex* mutex_; 69 std::vector<LogMessage>* msgs_; 70 bool* released_; 71 }; 72 73 class LogBufferTest : public testing::TestWithParam<std::string> { 74 protected: SetUp()75 void SetUp() override { 76 if (GetParam() == "serialized") { 77 log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_)); 78 } else if (GetParam() == "simple") { 79 log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_)); 80 } else { 81 FAIL() << "Unknown buffer type selected for test"; 82 } 83 84 log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); } 85 } 86 LogMessages(const std::vector<LogMessage> & messages)87 void LogMessages(const std::vector<LogMessage>& messages) { 88 for (auto& [entry, message, _] : messages) { 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); 93 } 94 } 95 96 struct FlushMessagesResult { 97 std::vector<LogMessage> messages; 98 uint64_t next_sequence; 99 }; 100 101 FlushMessagesResult FlushMessages(std::mutex* mutex = nullptr) { 102 std::vector<LogMessage> read_log_messages; 103 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, mutex, nullptr)); 104 105 auto lock = std::lock_guard{logd_lock}; 106 auto flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll); 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: TestReaderThread(const ReaderThreadParams & params,LogBufferTest & test)123 TestReaderThread(const ReaderThreadParams& params, LogBufferTest& test) : test_(test) { 124 auto lock = std::lock_guard{mutex_}; 125 std::unique_ptr<LogWriter> test_writer( 126 new TestWriter(&read_log_messages_, &mutex_, &released_)); 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)); 131 test_.reader_list_.AddAndRunThread(std::move(log_reader)); 132 } 133 WaitUntilReleased()134 void WaitUntilReleased() { 135 while (!released_) { 136 usleep(5000); 137 } 138 } 139 WaitForMessages(size_t n)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 } 151 read_log_messages()152 std::vector<LogMessage> read_log_messages() { 153 auto lock = std::lock_guard{mutex_}; 154 return read_log_messages_; 155 } 156 157 private: 158 LogBufferTest& test_; 159 std::mutex mutex_; 160 std::vector<LogMessage> read_log_messages_; 161 bool released_ = false; 162 }; 163 ReadLogMessagesNonBlockingThread(const ReaderThreadParams & params)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}; 171 EXPECT_EQ(0U, reader_list_.running_reader_threads().size()); 172 173 return reader.read_log_messages(); 174 } 175 ReleaseAndJoinReaders()176 void ReleaseAndJoinReaders() { 177 { 178 auto lock = std::lock_guard{logd_lock}; 179 for (auto& reader : reader_list_.running_reader_threads()) { 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}; 188 if (reader_list_.running_reader_threads().size() == 0) { 189 return; 190 } 191 } 192 193 FAIL() << "ReleaseAndJoinReaders() timed out with reader threads still running"; 194 } 195 196 LogReaderList reader_list_; 197 LogTags tags_; 198 PruneList prune_; 199 LogStatistics stats_{false, true}; 200 std::unique_ptr<LogBuffer> log_buffer_; 201 }; 202