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 <string> 21 #include <vector> 22 23 #include <gtest/gtest.h> 24 25 #include "ChattyLogBuffer.h" 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,bool * released)52 TestWriter(std::vector<LogMessage>* msgs, bool* released) 53 : LogWriter(0, true), msgs_(msgs), released_(released) {} Write(const logger_entry & entry,const char * message)54 bool Write(const logger_entry& entry, const char* message) override { 55 msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false}); 56 return true; 57 } 58 Release()59 void Release() { 60 if (released_) *released_ = true; 61 } 62 name()63 std::string name() const override { return "test_writer"; } 64 65 private: 66 std::vector<LogMessage>* msgs_; 67 bool* released_; 68 }; 69 70 class LogBufferTest : public testing::TestWithParam<std::string> { 71 protected: SetUp()72 void SetUp() override { 73 if (GetParam() == "chatty") { 74 log_buffer_.reset(new ChattyLogBuffer(&reader_list_, &tags_, &prune_, &stats_)); 75 } else if (GetParam() == "serialized") { 76 log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_)); 77 } else if (GetParam() == "simple") { 78 log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_)); 79 } else { 80 FAIL() << "Unknown buffer type selected for test"; 81 } 82 83 log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); } 84 } 85 LogMessages(const std::vector<LogMessage> & messages)86 void LogMessages(const std::vector<LogMessage>& messages) { 87 for (auto& [entry, message, _] : messages) { 88 EXPECT_GT(log_buffer_->Log(static_cast<log_id_t>(entry.lid), 89 log_time(entry.sec, entry.nsec), entry.uid, entry.pid, 90 entry.tid, message.c_str(), message.size()), 91 0); 92 } 93 } 94 95 struct FlushMessagesResult { 96 std::vector<LogMessage> messages; 97 uint64_t next_sequence; 98 }; 99 100 FlushMessagesResult FlushMessages(uint64_t sequence = 1, LogMask log_mask = kLogMaskAll) { 101 std::vector<LogMessage> read_log_messages; 102 auto lock = std::lock_guard{logd_lock}; 103 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr)); 104 105 auto flush_to_state = log_buffer_->CreateFlushToState(sequence, log_mask); 106 EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr)); 107 return {read_log_messages, flush_to_state->start()}; 108 } 109 110 struct ReaderThreadParams { 111 bool non_block = true; 112 unsigned long tail = 0; 113 LogMask log_mask = kLogMaskAll; 114 pid_t pid = 0; 115 log_time start_time = {}; 116 uint64_t sequence = 1; 117 std::chrono::steady_clock::time_point deadline = {}; 118 }; 119 120 class TestReaderThread { 121 public: TestReaderThread(const ReaderThreadParams & params,LogBufferTest & test)122 TestReaderThread(const ReaderThreadParams& params, LogBufferTest& test) : test_(test) { 123 auto lock = std::lock_guard{logd_lock}; 124 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages_, &released_)); 125 std::unique_ptr<LogReaderThread> log_reader(new LogReaderThread( 126 test_.log_buffer_.get(), &test_.reader_list_, std::move(test_writer), 127 params.non_block, params.tail, params.log_mask, params.pid, params.start_time, 128 params.sequence, params.deadline)); 129 test_.reader_list_.reader_threads().emplace_back(std::move(log_reader)); 130 } 131 WaitUntilReleased()132 void WaitUntilReleased() { 133 while (!released_) { 134 usleep(5000); 135 } 136 } 137 read_log_messages()138 std::vector<LogMessage> read_log_messages() const { return read_log_messages_; } 139 140 LogBufferTest& test_; 141 std::vector<LogMessage> read_log_messages_; 142 bool released_ = false; 143 }; 144 ReadLogMessagesNonBlockingThread(const ReaderThreadParams & params)145 std::vector<LogMessage> ReadLogMessagesNonBlockingThread(const ReaderThreadParams& params) { 146 EXPECT_TRUE(params.non_block) 147 << "params.non_block must be true for ReadLogMessagesNonBlockingThread()"; 148 149 auto reader = TestReaderThread(params, *this); 150 reader.WaitUntilReleased(); 151 auto lock = std::lock_guard{logd_lock}; 152 EXPECT_EQ(0U, reader_list_.reader_threads().size()); 153 154 return reader.read_log_messages(); 155 } 156 ReleaseAndJoinReaders()157 void ReleaseAndJoinReaders() { 158 { 159 auto lock = std::lock_guard{logd_lock}; 160 for (auto& reader : reader_list_.reader_threads()) { 161 reader->Release(); 162 } 163 } 164 165 auto retries = 1s / 5000us; 166 while (retries--) { 167 usleep(5000); 168 auto lock = std::lock_guard{logd_lock}; 169 if (reader_list_.reader_threads().size() == 0) { 170 return; 171 } 172 } 173 174 FAIL() << "ReleaseAndJoinReaders() timed out with reader threads still running"; 175 } 176 177 LogReaderList reader_list_; 178 LogTags tags_; 179 PruneList prune_; 180 LogStatistics stats_{false, true}; 181 std::unique_ptr<LogBuffer> log_buffer_; 182 }; 183