| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" |
| 6 |
| 7 #include "base/json/json_writer.h" |
| 8 #include "base/macros.h" |
| 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/test/simple_test_tick_clock.h" |
| 11 #include "base/values.h" |
| 12 #include "chrome/browser/extensions/api/feedback_private/log_source_resource.h" |
| 13 #include "chrome/browser/extensions/api/feedback_private/single_log_source_facto
ry.h" |
| 14 #include "chrome/browser/extensions/extension_api_unittest.h" |
| 15 #include "extensions/browser/api_test_utils.h" |
| 16 |
| 17 namespace extensions { |
| 18 |
| 19 namespace { |
| 20 |
| 21 using api::feedback_private::ReadLogSourceResult; |
| 22 using api::feedback_private::ReadLogSourceParams; |
| 23 using base::TimeDelta; |
| 24 using system_logs::SingleLogSource; |
| 25 using system_logs::SystemLogsResponse; |
| 26 using SupportedSource = system_logs::SingleLogSource::SupportedSource; |
| 27 |
| 28 std::unique_ptr<KeyedService> ApiResourceManagerTestFactory( |
| 29 content::BrowserContext* context) { |
| 30 return base::MakeUnique<ApiResourceManager<LogSourceResource>>(context); |
| 31 } |
| 32 |
| 33 // Converts |params| to a string containing a JSON dictionary within an argument |
| 34 // list. |
| 35 std::string ParamsToJSON(const ReadLogSourceParams& params) { |
| 36 base::ListValue params_value; |
| 37 params_value.Append(params.ToValue()); |
| 38 std::string params_json_string; |
| 39 EXPECT_TRUE(base::JSONWriter::Write(params_value, ¶ms_json_string)); |
| 40 |
| 41 return params_json_string; |
| 42 } |
| 43 |
| 44 // A dummy SingleLogSource that does not require real system logs to be |
| 45 // available during testing. |
| 46 class TestSingleLogSource : public SingleLogSource { |
| 47 public: |
| 48 explicit TestSingleLogSource(SupportedSource type) |
| 49 : SingleLogSource(type), call_count_(0) {} |
| 50 |
| 51 ~TestSingleLogSource() override = default; |
| 52 |
| 53 // Fetch() will return a single different string each time, in the following |
| 54 // sequence: "a", "bb", "ccc", until a string of 26 z's. Will never return an |
| 55 // empty result. |
| 56 void Fetch(const system_logs::SysLogsSourceCallback& callback) override { |
| 57 int count_modulus = call_count_ % kNumCharsToIterate; |
| 58 std::string result(count_modulus + 1, kInitialChar + count_modulus); |
| 59 ASSERT_GT(result.size(), 0U); |
| 60 ++call_count_; |
| 61 |
| 62 SystemLogsResponse* result_map = new SystemLogsResponse; |
| 63 result_map->emplace("", result); |
| 64 |
| 65 // Do not directly pass the result to the callback, because that's not how |
| 66 // log sources actually work. Instead, simulate the asynchronous operation |
| 67 // of a SingleLogSource by invoking the callback separately. |
| 68 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 69 FROM_HERE, base::Bind(callback, base::Owned(result_map))); |
| 70 } |
| 71 |
| 72 // Instantiates a new instance of this class. Does not retain ownership. Used |
| 73 // to create a Callback that can be used to override the default behavior of |
| 74 // SingleLogSourceFactory. |
| 75 static std::unique_ptr<SingleLogSource> Create(SupportedSource type) { |
| 76 return base::MakeUnique<TestSingleLogSource>(type); |
| 77 } |
| 78 |
| 79 private: |
| 80 // Iterate over the whole lowercase alphabet, starting from 'a'. |
| 81 const int kNumCharsToIterate = 26; |
| 82 const char kInitialChar = 'a'; |
| 83 |
| 84 // Keep track of how many times Fetch() has been called, in order to determine |
| 85 // its behavior each time. |
| 86 int call_count_; |
| 87 |
| 88 DISALLOW_COPY_AND_ASSIGN(TestSingleLogSource); |
| 89 }; |
| 90 |
| 91 } // namespace |
| 92 |
| 93 class FeedbackPrivateApiUnittest : public ExtensionApiUnittest { |
| 94 public: |
| 95 FeedbackPrivateApiUnittest() |
| 96 : create_callback_(base::Bind(&TestSingleLogSource::Create)) {} |
| 97 ~FeedbackPrivateApiUnittest() override {} |
| 98 |
| 99 void SetUp() override { |
| 100 ExtensionApiUnittest::SetUp(); |
| 101 |
| 102 // The ApiResourceManager used for LogSourceResource is destroyed every time |
| 103 // a unit test finishes, during TearDown(). There is no way to re-create it |
| 104 // normally. The below code forces it to be re-created during SetUp(), so |
| 105 // that there is always a valid ApiResourceManager<LogSourceResource> when |
| 106 // subsequent unit tests are running. |
| 107 ApiResourceManager<LogSourceResource>::GetFactoryInstance() |
| 108 ->SetTestingFactoryAndUse(profile(), ApiResourceManagerTestFactory); |
| 109 |
| 110 SingleLogSourceFactory::SetForTesting(&create_callback_); |
| 111 } |
| 112 |
| 113 void TearDown() override { |
| 114 SingleLogSourceFactory::SetForTesting(nullptr); |
| 115 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(nullptr); |
| 116 |
| 117 FeedbackPrivateAPI::GetFactoryInstance() |
| 118 ->Get(profile()) |
| 119 ->GetLogSourceAccessManager() |
| 120 ->SetTickClockForTesting(nullptr); |
| 121 |
| 122 ExtensionApiUnittest::TearDown(); |
| 123 } |
| 124 |
| 125 // Runs the feedbackPrivate.readLogSource() function. See API function |
| 126 // definition for argument descriptions. |
| 127 // |
| 128 // The API function is expected to complete successfully. For running the |
| 129 // function with an expectation of an error result, call |
| 130 // RunReadLogSourceFunctionWithError(). |
| 131 // |
| 132 // Note that the second argument of the result is a list of strings, but the |
| 133 // test class TestSingleLogSource always returns a list containing a single |
| 134 // string. To simplify things, the single string result will be returned in |
| 135 // |*result_string|, while the reader ID is returned in |*result_reader_id|. |
| 136 testing::AssertionResult RunReadLogSourceFunction( |
| 137 const ReadLogSourceParams& params, |
| 138 int* result_reader_id, |
| 139 std::string* result_string) { |
| 140 scoped_refptr<FeedbackPrivateReadLogSourceFunction> function = |
| 141 new FeedbackPrivateReadLogSourceFunction; |
| 142 |
| 143 std::unique_ptr<base::Value> result_value = |
| 144 RunFunctionAndReturnValue(function.get(), ParamsToJSON(params)); |
| 145 if (!result_value) |
| 146 return testing::AssertionFailure() << "No result"; |
| 147 |
| 148 ReadLogSourceResult result; |
| 149 if (!ReadLogSourceResult::Populate(*result_value, &result)) { |
| 150 return testing::AssertionFailure() |
| 151 << "Unable to parse a valid result from " << *result_value; |
| 152 } |
| 153 |
| 154 if (result.log_lines.size() != 1) { |
| 155 return testing::AssertionFailure() |
| 156 << "Expected |log_lines| to contain 1 string, actual number: " |
| 157 << result.log_lines.size(); |
| 158 } |
| 159 |
| 160 *result_reader_id = result.reader_id; |
| 161 *result_string = result.log_lines[0]; |
| 162 |
| 163 return testing::AssertionSuccess(); |
| 164 } |
| 165 |
| 166 // Similar to RunReadLogSourceFunction(), but expects to return an error. |
| 167 // Returns a string containing the error message. Does not return any result |
| 168 // from the API function. |
| 169 std::string RunReadLogSourceFunctionWithError( |
| 170 const ReadLogSourceParams& params) { |
| 171 scoped_refptr<FeedbackPrivateReadLogSourceFunction> function = |
| 172 new FeedbackPrivateReadLogSourceFunction; |
| 173 |
| 174 return RunFunctionAndReturnError(function.get(), ParamsToJSON(params)); |
| 175 } |
| 176 |
| 177 private: |
| 178 // Passed to SingleLogSourceFactory so that the API can create an instance of |
| 179 // TestSingleLogSource for testing. |
| 180 SingleLogSourceFactory::CreateCallback create_callback_; |
| 181 |
| 182 DISALLOW_COPY_AND_ASSIGN(FeedbackPrivateApiUnittest); |
| 183 }; |
| 184 |
| 185 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceInvalidId) { |
| 186 const TimeDelta timeout(TimeDelta::FromMilliseconds(0)); |
| 187 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 188 |
| 189 ReadLogSourceParams params; |
| 190 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 191 params.incremental = true; |
| 192 params.reader_id.reset(new int(9999)); |
| 193 |
| 194 EXPECT_NE("", RunReadLogSourceFunctionWithError(params)); |
| 195 } |
| 196 |
| 197 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceNonIncremental) { |
| 198 const TimeDelta timeout(TimeDelta::FromMilliseconds(0)); |
| 199 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 200 |
| 201 ReadLogSourceParams params; |
| 202 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 203 params.incremental = false; |
| 204 |
| 205 // Test multiple non-incremental reads. |
| 206 int result_reader_id = -1; |
| 207 std::string result_string; |
| 208 EXPECT_TRUE( |
| 209 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 210 EXPECT_EQ(0, result_reader_id); |
| 211 EXPECT_EQ("a", result_string); |
| 212 |
| 213 result_reader_id = -1; |
| 214 result_string.clear(); |
| 215 EXPECT_TRUE( |
| 216 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 217 EXPECT_EQ(0, result_reader_id); |
| 218 EXPECT_EQ("a", result_string); |
| 219 |
| 220 result_reader_id = -1; |
| 221 result_string.clear(); |
| 222 EXPECT_TRUE( |
| 223 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 224 EXPECT_EQ(0, result_reader_id); |
| 225 EXPECT_EQ("a", result_string); |
| 226 } |
| 227 |
| 228 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceIncremental) { |
| 229 const TimeDelta timeout(TimeDelta::FromMilliseconds(0)); |
| 230 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 231 |
| 232 ReadLogSourceParams params; |
| 233 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 234 params.incremental = true; |
| 235 |
| 236 int result_reader_id = 0; |
| 237 std::string result_string; |
| 238 EXPECT_TRUE( |
| 239 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 240 EXPECT_GT(result_reader_id, 0); |
| 241 EXPECT_EQ("a", result_string); |
| 242 params.reader_id.reset(new int(result_reader_id)); |
| 243 |
| 244 EXPECT_TRUE( |
| 245 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 246 EXPECT_EQ(*params.reader_id, result_reader_id); |
| 247 EXPECT_EQ("bb", result_string); |
| 248 |
| 249 EXPECT_TRUE( |
| 250 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 251 EXPECT_EQ(*params.reader_id, result_reader_id); |
| 252 EXPECT_EQ("ccc", result_string); |
| 253 |
| 254 // End the incremental read. |
| 255 params.incremental = false; |
| 256 EXPECT_TRUE( |
| 257 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 258 EXPECT_EQ(0, result_reader_id); |
| 259 EXPECT_EQ("dddd", result_string); |
| 260 |
| 261 // The log source will no longer be valid if we try to read it. |
| 262 params.incremental = true; |
| 263 EXPECT_NE("", RunReadLogSourceFunctionWithError(params)); |
| 264 } |
| 265 |
| 266 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceMultipleSources) { |
| 267 const TimeDelta timeout(TimeDelta::FromMilliseconds(0)); |
| 268 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 269 |
| 270 int result_reader_id = 0; |
| 271 std::string result_string; |
| 272 |
| 273 // Attempt to open LOG_SOURCE_MESSAGES twice. |
| 274 ReadLogSourceParams params_1st_read; |
| 275 params_1st_read.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 276 params_1st_read.incremental = true; |
| 277 EXPECT_TRUE(RunReadLogSourceFunction(params_1st_read, &result_reader_id, |
| 278 &result_string)); |
| 279 EXPECT_GT(result_reader_id, 0); |
| 280 // Store the reader ID back into the params to set up for the next call. |
| 281 params_1st_read.reader_id = base::MakeUnique<int>(result_reader_id); |
| 282 |
| 283 // Cannot create a second reader from the same log source. |
| 284 ReadLogSourceParams params_1st_read_repeated; |
| 285 params_1st_read_repeated.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 286 params_1st_read_repeated.incremental = true; |
| 287 EXPECT_NE("", RunReadLogSourceFunctionWithError(params_1st_read_repeated)); |
| 288 |
| 289 // Attempt to open LOG_SOURCE_UI_LATEST twice. |
| 290 ReadLogSourceParams params_2nd_read; |
| 291 params_2nd_read.source = api::feedback_private::LOG_SOURCE_UILATEST; |
| 292 params_2nd_read.incremental = true; |
| 293 result_reader_id = -1; |
| 294 EXPECT_TRUE(RunReadLogSourceFunction(params_2nd_read, &result_reader_id, |
| 295 &result_string)); |
| 296 EXPECT_GT(result_reader_id, 0); |
| 297 EXPECT_NE(*params_1st_read.reader_id, result_reader_id); |
| 298 // Store the reader ID back into the params to set up for the next call. |
| 299 params_2nd_read.reader_id = base::MakeUnique<int>(result_reader_id); |
| 300 |
| 301 // Cannot create a second reader from the same log source. |
| 302 ReadLogSourceParams params_2nd_read_repeated; |
| 303 params_2nd_read_repeated.source = api::feedback_private::LOG_SOURCE_UILATEST; |
| 304 params_2nd_read_repeated.incremental = true; |
| 305 EXPECT_NE("", RunReadLogSourceFunctionWithError(params_2nd_read_repeated)); |
| 306 |
| 307 // Close the two open log source readers, and make sure new ones can be |
| 308 // opened. |
| 309 params_1st_read.incremental = false; |
| 310 result_reader_id = -1; |
| 311 EXPECT_TRUE(RunReadLogSourceFunction(params_1st_read, &result_reader_id, |
| 312 &result_string)); |
| 313 EXPECT_EQ(0, result_reader_id); |
| 314 |
| 315 params_2nd_read.incremental = false; |
| 316 result_reader_id = -1; |
| 317 EXPECT_TRUE(RunReadLogSourceFunction(params_2nd_read, &result_reader_id, |
| 318 &result_string)); |
| 319 EXPECT_EQ(0, result_reader_id); |
| 320 |
| 321 EXPECT_TRUE(RunReadLogSourceFunction(params_1st_read_repeated, |
| 322 &result_reader_id, &result_string)); |
| 323 EXPECT_GT(result_reader_id, 0); |
| 324 const int new_read_result_reader_id = result_reader_id; |
| 325 |
| 326 EXPECT_TRUE(RunReadLogSourceFunction(params_2nd_read_repeated, |
| 327 &result_reader_id, &result_string)); |
| 328 EXPECT_GT(result_reader_id, 0); |
| 329 EXPECT_NE(new_read_result_reader_id, result_reader_id); |
| 330 } |
| 331 |
| 332 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceWithAccessTimeouts) { |
| 333 const TimeDelta timeout(TimeDelta::FromMilliseconds(100)); |
| 334 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 335 |
| 336 base::SimpleTestTickClock* test_clock = new base::SimpleTestTickClock; |
| 337 FeedbackPrivateAPI::GetFactoryInstance() |
| 338 ->Get(profile()) |
| 339 ->GetLogSourceAccessManager() |
| 340 ->SetTickClockForTesting(std::unique_ptr<base::TickClock>(test_clock)); |
| 341 |
| 342 ReadLogSourceParams params; |
| 343 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 344 params.incremental = true; |
| 345 int result_reader_id = 0; |
| 346 std::string result_string; |
| 347 |
| 348 // |test_clock| must start out at something other than 0, which is interpreted |
| 349 // as an invalid value. |
| 350 test_clock->Advance(TimeDelta::FromMilliseconds(100)); |
| 351 |
| 352 EXPECT_TRUE( |
| 353 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 354 EXPECT_EQ(1, result_reader_id); |
| 355 params.reader_id.reset(new int(result_reader_id)); |
| 356 |
| 357 // Immediately perform another read. This is not allowed. (empty result) |
| 358 EXPECT_FALSE( |
| 359 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 360 |
| 361 // Advance to t=120, but it will not be allowed. (empty result) |
| 362 test_clock->Advance(TimeDelta::FromMilliseconds(20)); |
| 363 EXPECT_FALSE( |
| 364 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 365 |
| 366 // Advance to t=150, but still not allowed. |
| 367 test_clock->Advance(TimeDelta::FromMilliseconds(30)); |
| 368 EXPECT_FALSE( |
| 369 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 370 |
| 371 // Advance to t=199, but still not allowed. (empty result) |
| 372 test_clock->Advance(TimeDelta::FromMilliseconds(49)); |
| 373 EXPECT_FALSE( |
| 374 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 375 |
| 376 // Advance to t=210, annd the access is finally allowed. |
| 377 test_clock->Advance(TimeDelta::FromMilliseconds(11)); |
| 378 EXPECT_TRUE( |
| 379 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 380 |
| 381 // Advance to t=309, but it will not be allowed. (empty result) |
| 382 test_clock->Advance(TimeDelta::FromMilliseconds(99)); |
| 383 EXPECT_FALSE( |
| 384 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 385 |
| 386 // Another read is finally allowed at t=310. |
| 387 test_clock->Advance(TimeDelta::FromMilliseconds(1)); |
| 388 EXPECT_TRUE( |
| 389 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 390 } |
| 391 |
| 392 } // namespace extensions |
| OLD | NEW |