Chromium Code Reviews| Index: chrome/browser/extensions/api/feedback_private/feedback_private_api_chromeos_unittest.cc |
| diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api_chromeos_unittest.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api_chromeos_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a508c3bef405deff76d5071e21443452b01b00b5 |
| --- /dev/null |
| +++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api_chromeos_unittest.cc |
| @@ -0,0 +1,399 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
|
tbarzic
2017/06/01 19:23:46
nit: update the year
Simon Que
2017/06/01 21:49:09
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" |
| + |
| +#include "base/macros.h" |
| +#include "base/run_loop.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/task_scheduler/post_task.h" |
| +#include "base/test/scoped_task_environment.h" |
| +#include "base/test/simple_test_tick_clock.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/extensions/api/feedback_private/log_source_resource.h" |
| +#include "chrome/browser/extensions/api/feedback_private/single_log_source_factory.h" |
| +#include "extensions/browser/api_test_utils.h" |
| +#include "extensions/browser/api_unittest.h" |
| + |
| +namespace extensions { |
| + |
| +namespace { |
| + |
| +using api::feedback_private::ReadLogSourceParams; |
| +using system_logs::SingleLogSource; |
| +using system_logs::SystemLogsResponse; |
| +using SupportedSource = system_logs::SingleLogSource::SupportedSource; |
| + |
| +std::unique_ptr<KeyedService> ApiResourceManagerTestFactory( |
| + content::BrowserContext* context) { |
| + return base::MakeUnique<ApiResourceManager<LogSourceResource>>(context); |
| +} |
| + |
| +// A dummy SingleLogSource that does not require real system logs to be |
| +// available during testing. |
| +class TestSingleLogSource : public SingleLogSource { |
| + public: |
| + explicit TestSingleLogSource(SupportedSource type) |
| + : SingleLogSource(type), call_count_(0) {} |
| + |
| + ~TestSingleLogSource() override {} |
| + |
| + // Fetch() will return a single different string each time, in the following |
| + // sequence: "a", "bb", "ccc", until a string of 26 z's. Will never return an |
| + // empty result. |
| + void Fetch(const system_logs::SysLogsSourceCallback& callback) override { |
| + int count_modulus = call_count_ % kNumCharsToIterate; |
| + std::string result(count_modulus + 1, kInitialChar + count_modulus); |
| + CHECK_GT(result.size(), 0U); |
| + ++call_count_; |
| + |
| + SystemLogsResponse* result_map = new SystemLogsResponse; |
| + result_map->emplace("", result); |
| + |
| + // Do not directly pass the result to the callback, because that's not how |
| + // log sources actually work. Instead, simulate the asynchronous operation |
| + // of a SingleLogSource by invoking the callback separately. |
| + base::PostDelayedTaskWithTraits( |
| + FROM_HERE, base::TaskPriority::BACKGROUND, |
| + base::Bind(callback, base::Owned(result_map)), |
| + base::TimeDelta::FromMilliseconds(0)); |
| + } |
| + |
| + // Instantiates a new instance of this class. Does not retain ownership. Used |
| + // to create a Callback that can be used to override the default behavior of |
| + // SingleLogSourceFactory. |
| + static SingleLogSource* Create(SupportedSource type) { |
| + return new TestSingleLogSource(type); |
| + } |
| + |
| + private: |
| + // Iterate over the whole lowercase alphabet, starting from 'a'. |
| + const int kNumCharsToIterate = 26; |
| + const char kInitialChar = 'a'; |
| + |
| + // Keep track of how many times Fetch() has been called, in order to determine |
| + // its behavior each time. |
| + int call_count_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestSingleLogSource); |
| +}; |
| + |
| +} // namespace |
| + |
| +class FeedbackApiUnittest : public ApiUnitTest { |
| + public: |
| + FeedbackApiUnittest() |
| + : create_callback_(base::Bind(&TestSingleLogSource::Create)) {} |
| + ~FeedbackApiUnittest() override {} |
| + |
| + void SetUp() override { |
| + ApiUnitTest::SetUp(); |
| + |
| + // To avoid the ApiResourceManager being destroyed each time TearDown() is |
|
tbarzic
2017/06/01 19:23:46
Can you clarify the comment a little?
Destroying A
Simon Que
2017/06/01 21:49:09
Done.
|
| + // called. |
| + ApiResourceManager<LogSourceResource>::GetFactoryInstance() |
| + ->SetTestingFactoryAndUse(browser_context(), |
| + ApiResourceManagerTestFactory); |
| + |
| + SingleLogSourceFactory::InitForTesting(&create_callback_); |
| + } |
| + |
| + void TearDown() override { |
| + SingleLogSourceFactory::InitForTesting(nullptr); |
|
tbarzic
2017/06/01 19:23:46
nit: Can you rename this to |SetForTesting| - it s
Simon Que
2017/06/01 21:49:09
Done.
|
| + LogSourceAccessManager::SetRateLimitingTimeoutForTesting(nullptr); |
| + |
| + FeedbackPrivateAPI::GetFactoryInstance() |
| + ->Get(browser_context()) |
| + ->log_source_access_manager() |
| + ->set_tick_clock(nullptr); |
| + |
| + ApiUnitTest::TearDown(); |
| + } |
| + |
| + // Runs the feedbackPrivate.readLogSource() function. See API function |
| + // definition for argument descriptions. |
| + testing::AssertionResult RunReadLogSourceFunction( |
| + const ReadLogSourceParams& params, |
| + int* result_reader_id, |
| + std::string* result_string) { |
| + FeedbackPrivateReadLogSourceFunction* function = |
| + new FeedbackPrivateReadLogSourceFunction; |
| + std::unique_ptr<base::ListValue> result_list = |
| + RunFunctionAndReturnListValue(function, ParamsToJSON(params)); |
| + |
| + if (!result_list) |
| + return testing::AssertionFailure() << "No result"; |
| + |
| + return ParseReadLogSourceResult(*result_list, result_reader_id, |
| + result_string); |
| + } |
| + |
| + private: |
| + // Converts |params| to a string containing a JSON dictionary within an |
| + // argument list. |
| + std::string ParamsToJSON(const ReadLogSourceParams& params) { |
| + return base::StringPrintf( |
| + "[{\"source\": \"%s\"," |
| + " \"incremental\": %s," |
| + " \"readerId\": %u}]", |
| + api::feedback_private::ToString(params.source).c_str(), |
| + params.incremental ? "true" : "false", |
| + params.reader_id ? *params.reader_id : 0); |
| + } |
| + |
| + // Runs |function| with arguments |args| in JSON string format and returns the |
| + // result as a base::ListValue. |
| + std::unique_ptr<base::ListValue> RunFunctionAndReturnListValue( |
| + UIThreadExtensionFunction* function, |
| + const std::string& args) { |
| + function->set_extension(extension()); |
| + if (!api_test_utils::RunFunction(function, args, browser_context())) |
| + return nullptr; |
| + |
| + const base::ListValue* result_list = function->GetResultList(); |
| + return result_list ? result_list->CreateDeepCopy() : nullptr; |
| + } |
|
tbarzic
2017/06/01 19:23:46
can you add new lines around methods
Simon Que
2017/06/01 21:49:09
Done.
|
| + // Attempts to interpret the result as the following ListValue: |
| + // [ int result_reader_id, [ string result_string ] ]. |
| + // |
| + // Note that the second argument of the result is a list of strings, but the |
| + // test class TestSingleLogSource always returns a list containing a single |
| + // string. |
| + // |
| + // If the result does follow the above format, returns the reader ID and |
| + // string value in |*result_reader_id| and |*result_string|, respectively. |
| + // |
| + // Returns failure if the result does not conform to the above format, or is |
| + // otherwise invalid. |
| + testing::AssertionResult ParseReadLogSourceResult( |
| + const base::ListValue& result_list, |
| + int* result_reader_id, |
| + std::string* result_string) { |
| + if (result_list.GetSize() != 2) { |
| + return testing::AssertionFailure() |
| + << "Expected result length=2, actual=" << result_list.GetSize(); |
| + } |
| + if (!result_list.GetInteger(0, result_reader_id)) { |
| + return testing::AssertionFailure() << "Could not read argument 0 as int."; |
| + } |
| + |
| + const base::ListValue* string_list = nullptr; |
| + if (!result_list.GetList(1, &string_list)) { |
| + return testing::AssertionFailure() |
| + << "Could not read argument 1 as list."; |
| + } |
| + if (string_list->GetSize() != 1) { |
| + return testing::AssertionFailure() |
| + << "Argument 1 list expected to have size=1, actual=" |
| + << string_list->GetSize(); |
| + } |
| + if (!string_list->GetString(0, result_string)) { |
| + return testing::AssertionFailure() |
| + << "Could not read argument 1 list's argument 0 as string."; |
| + } |
| + |
| + return testing::AssertionSuccess(); |
| + } |
| + |
| + // Passed to SingleLogSourceFactory so that the API can create an instance of |
| + // TestSingleLogSource for testing. |
| + const SingleLogSourceFactory::CreateCallback create_callback_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FeedbackApiUnittest); |
| +}; |
| + |
| +TEST_F(FeedbackApiUnittest, ReadLogSourceNonIncremental) { |
| + const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0)); |
| + LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| + |
| + ReadLogSourceParams params; |
| + params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| + params.incremental = false; |
| + |
| + // Test multiple non-incremental reads. |
| + int result_reader_id = -1; |
| + std::string result_string; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + EXPECT_EQ("a", result_string); |
| + |
| + result_reader_id = -1; |
| + result_string.clear(); |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + EXPECT_EQ("a", result_string); |
| + |
| + result_reader_id = -1; |
| + result_string.clear(); |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + EXPECT_EQ("a", result_string); |
| +} |
| + |
| +TEST_F(FeedbackApiUnittest, ReadLogSourceIncremental) { |
| + const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0)); |
| + LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| + |
| + ReadLogSourceParams params; |
| + params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| + params.incremental = true; |
| + |
| + int result_reader_id = 0; |
| + std::string result_string; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(1, result_reader_id); |
| + EXPECT_EQ("a", result_string); |
| + params.reader_id.reset(new int(result_reader_id)); |
| + |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(1, result_reader_id); |
| + EXPECT_EQ("bb", result_string); |
| + |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(1, result_reader_id); |
| + EXPECT_EQ("ccc", result_string); |
| + |
| + // End the incremental read. |
| + params.incremental = false; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + EXPECT_EQ("dddd", result_string); |
| + |
| + // The log source will no longer be valid if we try to read it. |
| + params.incremental = true; |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| +} |
| + |
| +TEST_F(FeedbackApiUnittest, ReadLogSourceMultipleSources) { |
| + const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0)); |
| + LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| + |
| + int result_reader_id = 0; |
| + std::string result_string; |
| + |
| + // Attempt to open LOG_SOURCE_MESSAGES twice. |
| + ReadLogSourceParams params1a; |
| + params1a.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| + params1a.incremental = true; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params1a, &result_reader_id, &result_string)); |
| + EXPECT_EQ(1, result_reader_id); |
| + params1a.reader_id.reset(new int(result_reader_id)); |
| + |
| + // Cannot perform a second read from the same log source. |
| + ReadLogSourceParams params1b; |
| + params1b.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| + params1b.incremental = true; |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params1b, &result_reader_id, &result_string)); |
| + |
| + // Attempt to open LOG_SOURCE_UI_LATEST twice. |
| + ReadLogSourceParams params2a; |
| + params2a.source = api::feedback_private::LOG_SOURCE_UI_LATEST; |
| + params2a.incremental = true; |
| + result_reader_id = -1; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params2a, &result_reader_id, &result_string)); |
| + params2a.reader_id.reset(new int(result_reader_id)); |
| + EXPECT_EQ(2, result_reader_id); |
| + |
| + // Cannot perform a second read from the same log source. |
| + ReadLogSourceParams params2b; |
| + params2b.source = api::feedback_private::LOG_SOURCE_UI_LATEST; |
| + params2b.incremental = true; |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params2b, &result_reader_id, &result_string)); |
| + |
| + // Close the two open log source readers, and make sure new ones can be |
| + // opened. |
| + params1a.incremental = false; |
| + result_reader_id = -1; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params1a, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + |
| + params2a.incremental = false; |
| + result_reader_id = -1; |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params2a, &result_reader_id, &result_string)); |
| + EXPECT_EQ(0, result_reader_id); |
| + |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params1b, &result_reader_id, &result_string)); |
| + EXPECT_EQ(3, result_reader_id); |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params2b, &result_reader_id, &result_string)); |
| + EXPECT_EQ(4, result_reader_id); |
| +} |
| + |
| +TEST_F(FeedbackApiUnittest, ReadLogSourceWithAccessTimeouts) { |
| + const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(100)); |
| + LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| + |
| + base::SimpleTestTickClock* test_clock = new base::SimpleTestTickClock; |
| + FeedbackPrivateAPI::GetFactoryInstance() |
| + ->Get(browser_context()) |
| + ->log_source_access_manager() |
| + ->set_tick_clock(std::unique_ptr<base::TickClock>(test_clock)); |
| + |
| + ReadLogSourceParams params; |
| + params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| + params.incremental = true; |
| + int result_reader_id = 0; |
| + std::string result_string; |
| + |
| + auto FromMilliseconds = &base::TimeDelta::FromMilliseconds; |
| + // |test_clock| must start out at something other than 0, which is interpreted |
| + // as an invalid value. |
| + test_clock->Advance(FromMilliseconds(100)); |
| + |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + EXPECT_EQ(1, result_reader_id); |
| + params.reader_id.reset(new int(result_reader_id)); |
| + |
| + // Immediately perform another read. This is not allowed. |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Advance to t=120, but it will not be allowed. |
| + test_clock->Advance(FromMilliseconds(20)); |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Advance to t=150, but still not allowed. |
| + test_clock->Advance(FromMilliseconds(30)); |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Advance to t=199, but still not allowed. |
| + test_clock->Advance(FromMilliseconds(49)); |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Advance to t=210, annd the access is finally allowed. |
| + test_clock->Advance(FromMilliseconds(11)); |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Advance to t=309, but it will not be allowed. |
| + test_clock->Advance(FromMilliseconds(99)); |
| + EXPECT_FALSE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| + |
| + // Another read is finally allowed at t=310. |
| + test_clock->Advance(FromMilliseconds(1)); |
| + EXPECT_TRUE( |
| + RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| +} |
| + |
| +} // namespace extensions |