| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/system_logs/single_log_source.h" | 5 #include "chrome/browser/chromeos/system_logs/single_log_source.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/memory/ptr_util.h" |
| 14 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
| 15 #include "base/test/scoped_task_environment.h" | 16 #include "base/test/scoped_task_environment.h" |
| 16 #include "content/public/test/test_browser_thread_bundle.h" | 17 #include "content/public/test/test_browser_thread_bundle.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 18 | 19 |
| 19 namespace system_logs { | 20 namespace system_logs { |
| 20 | 21 |
| 21 class SingleLogSourceTest : public ::testing::Test { | 22 class SingleLogSourceTest : public ::testing::Test { |
| 22 public: | 23 public: |
| 23 SingleLogSourceTest() | 24 SingleLogSourceTest() |
| 24 : scoped_task_environment_( | 25 : scoped_task_environment_( |
| 25 base::test::ScopedTaskEnvironment::MainThreadType::UI), | 26 base::test::ScopedTaskEnvironment::MainThreadType::UI), |
| 26 source_(SingleLogSource::SupportedSource::kMessages), | |
| 27 num_callback_calls_(0) { | 27 num_callback_calls_(0) { |
| 28 CHECK(dir_.CreateUniqueTempDir()); | 28 InitializeTestLogDir(); |
| 29 log_file_path_ = dir_.GetPath().Append("log_file"); | |
| 30 | |
| 31 // Create the dummy log file for writing. | |
| 32 base::File new_file; | |
| 33 new_file.Initialize(log_file_path_, base::File::FLAG_CREATE_ALWAYS | | |
| 34 base::File::FLAG_WRITE); | |
| 35 new_file.Close(); | |
| 36 CHECK(base::PathExists(log_file_path_)); | |
| 37 | |
| 38 // Open the dummy log file for reading from within the log source. | |
| 39 source_.file_.Initialize(log_file_path_, | |
| 40 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 41 CHECK(source_.file_.IsValid()); | |
| 42 } | 29 } |
| 43 | 30 |
| 44 ~SingleLogSourceTest() override {} | 31 ~SingleLogSourceTest() override {} |
| 45 | 32 |
| 46 // Writes a string to |log_file_path_|. | 33 protected: |
| 47 bool WriteFile(const std::string& input) { | 34 // Sets up a dummy system log directory. |
| 48 return base::WriteFile(log_file_path_, input.data(), input.size()); | 35 void InitializeTestLogDir() { |
| 36 ASSERT_TRUE(log_dir_.CreateUniqueTempDir()); |
| 37 |
| 38 // Create file "messages". |
| 39 const base::FilePath messages_path = log_dir_.GetPath().Append("messages"); |
| 40 base::WriteFile(messages_path, "", 0); |
| 41 EXPECT_TRUE(base::PathExists(messages_path)) << messages_path.value(); |
| 42 |
| 43 // Create file "ui/ui.LATEST". |
| 44 const base::FilePath ui_dir_path = log_dir_.GetPath().Append("ui"); |
| 45 ASSERT_TRUE(base::CreateDirectory(ui_dir_path)) << ui_dir_path.value(); |
| 46 |
| 47 const base::FilePath ui_latest_path = ui_dir_path.Append("ui.LATEST"); |
| 48 base::WriteFile(ui_latest_path, "", 0); |
| 49 ASSERT_TRUE(base::PathExists(ui_latest_path)) << ui_latest_path.value(); |
| 49 } | 50 } |
| 50 // Appends a string to |log_file_path_|. | 51 |
| 51 bool AppendToFile(const std::string& input) { | 52 // Initializes the unit under test, |source_| to read a file from the dummy |
| 52 return base::AppendToFile(log_file_path_, input.data(), input.size()); | 53 // system log directory. |
| 54 void InitializeSource(SingleLogSource::SupportedSource source_type) { |
| 55 source_ = base::MakeUnique<SingleLogSource>(source_type); |
| 56 source_->log_file_dir_path_ = log_dir_.GetPath(); |
| 57 log_file_path_ = source_->log_file_dir_path_.Append(source_->source_name()); |
| 58 ASSERT_TRUE(base::PathExists(log_file_path_)) << log_file_path_.value(); |
| 59 } |
| 60 |
| 61 // Writes/appends (respectively) a string |input| to file indicated by |
| 62 // |relative_path| under |log_dir_|. |
| 63 bool WriteFile(const base::FilePath& relative_path, |
| 64 const std::string& input) { |
| 65 return base::WriteFile(log_dir_.GetPath().Append(relative_path), |
| 66 input.data(), input.size()); |
| 67 } |
| 68 bool AppendToFile(const base::FilePath& relative_path, |
| 69 const std::string& input) { |
| 70 return base::AppendToFile(log_dir_.GetPath().Append(relative_path), |
| 71 input.data(), input.size()); |
| 53 } | 72 } |
| 54 | 73 |
| 55 // Calls source_.Fetch() to start a logs fetch operation. Passes in | 74 // Calls source_.Fetch() to start a logs fetch operation. Passes in |
| 56 // OnFileRead() as a callback. Runs until Fetch() has completed. | 75 // OnFileRead() as a callback. Runs until Fetch() has completed. |
| 57 void FetchFromSource() { | 76 void FetchFromSource() { |
| 58 source_.Fetch( | 77 source_->Fetch( |
| 59 base::Bind(&SingleLogSourceTest::OnFileRead, base::Unretained(this))); | 78 base::Bind(&SingleLogSourceTest::OnFileRead, base::Unretained(this))); |
| 60 scoped_task_environment_.RunUntilIdle(); | 79 scoped_task_environment_.RunUntilIdle(); |
| 61 } | 80 } |
| 62 | 81 |
| 63 // Callback for fetching logs from |source_|. Overwrites the previous stored | 82 // Callback for fetching logs from |source_|. Overwrites the previous stored |
| 64 // value of |latest_response_|. | 83 // value of |latest_response_|. |
| 65 void OnFileRead(SystemLogsResponse* response) { | 84 void OnFileRead(SystemLogsResponse* response) { |
| 66 ++num_callback_calls_; | 85 ++num_callback_calls_; |
| 67 if (response->empty()) | 86 if (response->empty()) |
| 68 return; | 87 return; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 81 | 100 |
| 82 private: | 101 private: |
| 83 // For running scheduled tasks. | 102 // For running scheduled tasks. |
| 84 base::test::ScopedTaskEnvironment scoped_task_environment_; | 103 base::test::ScopedTaskEnvironment scoped_task_environment_; |
| 85 | 104 |
| 86 // Creates the necessary browser threads. Defined after | 105 // Creates the necessary browser threads. Defined after |
| 87 // |scoped_task_environment_| in order to use the MessageLoop it created. | 106 // |scoped_task_environment_| in order to use the MessageLoop it created. |
| 88 content::TestBrowserThreadBundle browser_thread_bundle_; | 107 content::TestBrowserThreadBundle browser_thread_bundle_; |
| 89 | 108 |
| 90 // Unit under test. | 109 // Unit under test. |
| 91 SingleLogSource source_; | 110 std::unique_ptr<SingleLogSource> source_; |
| 92 | 111 |
| 93 // Counts the number of times that |source_| has invoked the callback. | 112 // Counts the number of times that |source_| has invoked the callback. |
| 94 int num_callback_calls_; | 113 int num_callback_calls_; |
| 95 | 114 |
| 96 // Stores the string response returned from |source_| the last time it invoked | 115 // Stores the string response returned from |source_| the last time it invoked |
| 97 // OnFileRead. | 116 // OnFileRead. |
| 98 std::string latest_response_; | 117 std::string latest_response_; |
| 99 | 118 |
| 100 // Temporary dir for creating a dummy log file. | 119 // Temporary dir for creating a dummy log file. |
| 101 base::ScopedTempDir dir_; | 120 base::ScopedTempDir log_dir_; |
| 102 | 121 |
| 103 // Path to the dummy log file in |dir_|. | 122 // Path to the dummy log file in |log_dir_|. |
| 104 base::FilePath log_file_path_; | 123 base::FilePath log_file_path_; |
| 105 | 124 |
| 106 DISALLOW_COPY_AND_ASSIGN(SingleLogSourceTest); | 125 DISALLOW_COPY_AND_ASSIGN(SingleLogSourceTest); |
| 107 }; | 126 }; |
| 108 | 127 |
| 109 TEST_F(SingleLogSourceTest, EmptyFile) { | 128 TEST_F(SingleLogSourceTest, EmptyFile) { |
| 129 InitializeSource(SingleLogSource::SupportedSource::kMessages); |
| 110 FetchFromSource(); | 130 FetchFromSource(); |
| 111 | 131 |
| 112 EXPECT_EQ(1, num_callback_calls()); | 132 EXPECT_EQ(1, num_callback_calls()); |
| 113 EXPECT_EQ("", latest_response()); | 133 EXPECT_EQ("", latest_response()); |
| 114 } | 134 } |
| 115 | 135 |
| 116 TEST_F(SingleLogSourceTest, SingleRead) { | 136 TEST_F(SingleLogSourceTest, SingleRead) { |
| 117 EXPECT_TRUE(AppendToFile("Hello world!\n")); | 137 InitializeSource(SingleLogSource::SupportedSource::kUiLatest); |
| 138 |
| 139 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), "Hello world!\n")); |
| 118 FetchFromSource(); | 140 FetchFromSource(); |
| 119 | 141 |
| 120 EXPECT_EQ(1, num_callback_calls()); | 142 EXPECT_EQ(1, num_callback_calls()); |
| 121 EXPECT_EQ("Hello world!\n", latest_response()); | 143 EXPECT_EQ("Hello world!\n", latest_response()); |
| 122 } | 144 } |
| 123 | 145 |
| 124 TEST_F(SingleLogSourceTest, IncrementalReads) { | 146 TEST_F(SingleLogSourceTest, IncrementalReads) { |
| 125 EXPECT_TRUE(AppendToFile("Hello world!\n")); | 147 InitializeSource(SingleLogSource::SupportedSource::kMessages); |
| 148 |
| 149 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "Hello world!\n")); |
| 126 FetchFromSource(); | 150 FetchFromSource(); |
| 127 | 151 |
| 128 EXPECT_EQ(1, num_callback_calls()); | 152 EXPECT_EQ(1, num_callback_calls()); |
| 129 EXPECT_EQ("Hello world!\n", latest_response()); | 153 EXPECT_EQ("Hello world!\n", latest_response()); |
| 130 | 154 |
| 131 EXPECT_TRUE(AppendToFile("The quick brown fox jumps over the lazy dog\n")); | 155 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), |
| 156 "The quick brown fox jumps over the lazy dog\n")); |
| 132 FetchFromSource(); | 157 FetchFromSource(); |
| 133 | 158 |
| 134 EXPECT_EQ(2, num_callback_calls()); | 159 EXPECT_EQ(2, num_callback_calls()); |
| 135 EXPECT_EQ("The quick brown fox jumps over the lazy dog\n", latest_response()); | 160 EXPECT_EQ("The quick brown fox jumps over the lazy dog\n", latest_response()); |
| 136 | 161 |
| 137 EXPECT_TRUE(AppendToFile("Some like it hot.\nSome like it cold\n")); | 162 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), |
| 163 "Some like it hot.\nSome like it cold\n")); |
| 138 FetchFromSource(); | 164 FetchFromSource(); |
| 139 | 165 |
| 140 EXPECT_EQ(3, num_callback_calls()); | 166 EXPECT_EQ(3, num_callback_calls()); |
| 141 EXPECT_EQ("Some like it hot.\nSome like it cold\n", latest_response()); | 167 EXPECT_EQ("Some like it hot.\nSome like it cold\n", latest_response()); |
| 142 | 168 |
| 143 // As a sanity check, read entire contents of file separately to make sure it | 169 // As a sanity check, read entire contents of file separately to make sure it |
| 144 // was written incrementally, and hence read incrementally. | 170 // was written incrementally, and hence read incrementally. |
| 145 std::string file_contents; | 171 std::string file_contents; |
| 146 EXPECT_TRUE(base::ReadFileToString(log_file_path(), &file_contents)); | 172 EXPECT_TRUE(base::ReadFileToString(log_file_path(), &file_contents)); |
| 147 EXPECT_EQ( | 173 EXPECT_EQ( |
| 148 "Hello world!\nThe quick brown fox jumps over the lazy dog\n" | 174 "Hello world!\nThe quick brown fox jumps over the lazy dog\n" |
| 149 "Some like it hot.\nSome like it cold\n", | 175 "Some like it hot.\nSome like it cold\n", |
| 150 file_contents); | 176 file_contents); |
| 151 } | 177 } |
| 152 | 178 |
| 153 // The log files read by SingleLogSource are not expected to be overwritten. | 179 // The log files read by SingleLogSource are not expected to be overwritten. |
| 154 // This test is just to ensure that the SingleLogSource class is robust enough | 180 // This test is just to ensure that the SingleLogSource class is robust enough |
| 155 // not to break in the event of an overwrite. | 181 // not to break in the event of an overwrite. |
| 156 TEST_F(SingleLogSourceTest, FileOverwrite) { | 182 TEST_F(SingleLogSourceTest, FileOverwrite) { |
| 157 EXPECT_TRUE(AppendToFile("0123456789\n")); | 183 InitializeSource(SingleLogSource::SupportedSource::kUiLatest); |
| 184 |
| 185 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), "0123456789\n")); |
| 158 FetchFromSource(); | 186 FetchFromSource(); |
| 159 | 187 |
| 160 EXPECT_EQ(1, num_callback_calls()); | 188 EXPECT_EQ(1, num_callback_calls()); |
| 161 EXPECT_EQ("0123456789\n", latest_response()); | 189 EXPECT_EQ("0123456789\n", latest_response()); |
| 162 | 190 |
| 163 // Overwrite the file. | 191 // Overwrite the file. |
| 164 EXPECT_TRUE(WriteFile("abcdefg\n")); | 192 EXPECT_TRUE(WriteFile(base::FilePath("ui/ui.LATEST"), "abcdefg\n")); |
| 165 FetchFromSource(); | 193 FetchFromSource(); |
| 166 | 194 |
| 167 // Should re-read from the beginning. | 195 // Should re-read from the beginning. |
| 168 EXPECT_EQ(2, num_callback_calls()); | 196 EXPECT_EQ(2, num_callback_calls()); |
| 169 EXPECT_EQ("abcdefg\n", latest_response()); | 197 EXPECT_EQ("abcdefg\n", latest_response()); |
| 170 | 198 |
| 171 // Append to the file to make sure incremental read still works. | 199 // Append to the file to make sure incremental read still works. |
| 172 EXPECT_TRUE(AppendToFile("hijk\n")); | 200 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), "hijk\n")); |
| 173 FetchFromSource(); | 201 FetchFromSource(); |
| 174 | 202 |
| 175 EXPECT_EQ(3, num_callback_calls()); | 203 EXPECT_EQ(3, num_callback_calls()); |
| 176 EXPECT_EQ("hijk\n", latest_response()); | 204 EXPECT_EQ("hijk\n", latest_response()); |
| 177 | 205 |
| 178 // Overwrite again, this time with a longer length than the existing file. | 206 // Overwrite again, this time with a longer length than the existing file. |
| 179 // Previous contents: | 207 // Previous contents: |
| 180 // abcdefg~hijk~ <-- "~" is a single-char representation of newline. | 208 // abcdefg~hijk~ <-- "~" is a single-char representation of newline. |
| 181 // New contents: | 209 // New contents: |
| 182 // lmnopqrstuvwxyz~ <-- excess text beyond end of prev contents: "yz~" | 210 // lmnopqrstuvwxyz~ <-- excess text beyond end of prev contents: "yz~" |
| 183 EXPECT_TRUE(WriteFile("lmnopqrstuvwxyz\n")); | 211 EXPECT_TRUE(WriteFile(base::FilePath("ui/ui.LATEST"), "lmnopqrstuvwxyz\n")); |
| 184 FetchFromSource(); | 212 FetchFromSource(); |
| 185 | 213 |
| 186 EXPECT_EQ(4, num_callback_calls()); | 214 EXPECT_EQ(4, num_callback_calls()); |
| 187 EXPECT_EQ("yz\n", latest_response()); | 215 EXPECT_EQ("yz\n", latest_response()); |
| 188 } | 216 } |
| 189 | 217 |
| 190 TEST_F(SingleLogSourceTest, IncompleteLines) { | 218 TEST_F(SingleLogSourceTest, IncompleteLines) { |
| 191 EXPECT_TRUE(AppendToFile("0123456789")); | 219 InitializeSource(SingleLogSource::SupportedSource::kMessages); |
| 220 |
| 221 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "0123456789")); |
| 192 FetchFromSource(); | 222 FetchFromSource(); |
| 193 | 223 |
| 194 EXPECT_EQ(1, num_callback_calls()); | 224 EXPECT_EQ(1, num_callback_calls()); |
| 195 EXPECT_EQ("", latest_response()); | 225 EXPECT_EQ("", latest_response()); |
| 196 | 226 |
| 197 EXPECT_TRUE(AppendToFile("abcdefg")); | 227 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "abcdefg")); |
| 198 FetchFromSource(); | 228 FetchFromSource(); |
| 199 | 229 |
| 200 EXPECT_EQ(2, num_callback_calls()); | 230 EXPECT_EQ(2, num_callback_calls()); |
| 201 EXPECT_EQ("", latest_response()); | 231 EXPECT_EQ("", latest_response()); |
| 202 | 232 |
| 203 EXPECT_TRUE(AppendToFile("hijk\n")); | 233 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "hijk\n")); |
| 204 FetchFromSource(); | 234 FetchFromSource(); |
| 205 | 235 |
| 206 EXPECT_EQ(3, num_callback_calls()); | 236 EXPECT_EQ(3, num_callback_calls()); |
| 207 // All the previously written text should be read this time. | 237 // All the previously written text should be read this time. |
| 208 EXPECT_EQ("0123456789abcdefghijk\n", latest_response()); | 238 EXPECT_EQ("0123456789abcdefghijk\n", latest_response()); |
| 209 | 239 |
| 210 EXPECT_TRUE(AppendToFile("Hello world\n")); | 240 // Partial whole-line reads are not supported. The last byte of the read must |
| 211 EXPECT_TRUE(AppendToFile("Goodbye world")); | 241 // be a new line. |
| 242 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "Hello world\n")); |
| 243 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "Goodbye world")); |
| 212 FetchFromSource(); | 244 FetchFromSource(); |
| 213 | 245 |
| 214 // Partial whole-line reads are not supported. The last byte of the read must | |
| 215 // be a new line. | |
| 216 EXPECT_EQ(4, num_callback_calls()); | 246 EXPECT_EQ(4, num_callback_calls()); |
| 217 EXPECT_EQ("", latest_response()); | 247 EXPECT_EQ("", latest_response()); |
| 218 | 248 |
| 219 EXPECT_TRUE(AppendToFile("\n")); | 249 EXPECT_TRUE(AppendToFile(base::FilePath("messages"), "\n")); |
| 220 FetchFromSource(); | 250 FetchFromSource(); |
| 221 | 251 |
| 222 EXPECT_EQ(5, num_callback_calls()); | 252 EXPECT_EQ(5, num_callback_calls()); |
| 223 EXPECT_EQ("Hello world\nGoodbye world\n", latest_response()); | 253 EXPECT_EQ("Hello world\nGoodbye world\n", latest_response()); |
| 224 } | 254 } |
| 225 | 255 |
| 226 TEST_F(SingleLogSourceTest, Anonymize) { | 256 TEST_F(SingleLogSourceTest, Anonymize) { |
| 227 EXPECT_TRUE(AppendToFile("My MAC address is: 11:22:33:44:55:66\n")); | 257 InitializeSource(SingleLogSource::SupportedSource::kUiLatest); |
| 258 |
| 259 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), |
| 260 "My MAC address is: 11:22:33:44:55:66\n")); |
| 228 FetchFromSource(); | 261 FetchFromSource(); |
| 229 | 262 |
| 230 EXPECT_EQ(1, num_callback_calls()); | 263 EXPECT_EQ(1, num_callback_calls()); |
| 231 EXPECT_EQ("My MAC address is: 11:22:33:00:00:01\n", latest_response()); | 264 EXPECT_EQ("My MAC address is: 11:22:33:00:00:01\n", latest_response()); |
| 232 | 265 |
| 233 // Suppose the write operation is not atomic, and the MAC address is written | 266 // Suppose the write operation is not atomic, and the MAC address is written |
| 234 // across two separate writes. | 267 // across two separate writes. |
| 235 EXPECT_TRUE(AppendToFile("Your MAC address is: AB:88:C")); | 268 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), |
| 269 "Your MAC address is: AB:88:C")); |
| 236 FetchFromSource(); | 270 FetchFromSource(); |
| 237 | 271 |
| 238 EXPECT_EQ(2, num_callback_calls()); | 272 EXPECT_EQ(2, num_callback_calls()); |
| 239 EXPECT_EQ("", latest_response()); | 273 EXPECT_EQ("", latest_response()); |
| 240 | 274 |
| 241 EXPECT_TRUE(AppendToFile("D:99:EF:77\n")); | 275 EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), "D:99:EF:77\n")); |
| 242 FetchFromSource(); | 276 FetchFromSource(); |
| 243 | 277 |
| 244 EXPECT_EQ(3, num_callback_calls()); | 278 EXPECT_EQ(3, num_callback_calls()); |
| 245 EXPECT_EQ("Your MAC address is: ab:88:cd:00:00:02\n", latest_response()); | 279 EXPECT_EQ("Your MAC address is: ab:88:cd:00:00:02\n", latest_response()); |
| 246 } | 280 } |
| 247 | 281 |
| 248 } // namespace system_logs | 282 } // namespace system_logs |
| OLD | NEW |