| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2013 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/macros.h" |
| 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/task_scheduler/post_task.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 "extensions/browser/api_unittest.h" |
| 15 |
| 16 namespace extensions { |
| 17 |
| 18 namespace { |
| 19 |
| 20 using api::feedback_private::ReadLogSourceParams; |
| 21 using system_logs::SingleLogSource; |
| 22 using system_logs::SystemLogsResponse; |
| 23 using SupportedSource = system_logs::SingleLogSource::SupportedSource; |
| 24 |
| 25 // A dummy SingleLogSource that does not require real system logs to be |
| 26 // available during testing. |
| 27 class TestSingleLogSource : public SingleLogSource { |
| 28 public: |
| 29 explicit TestSingleLogSource(SupportedSource type) |
| 30 : SingleLogSource(type), call_count_(0) {} |
| 31 |
| 32 ~TestSingleLogSource() override {} |
| 33 |
| 34 // Fetch() will return a single different string each time, in the following |
| 35 // sequence: "a", "bb", "ccc", until a string of 26 z's. Will never return an |
| 36 // empty result. |
| 37 void Fetch(const system_logs::SysLogsSourceCallback& callback) override { |
| 38 int count_modulus = call_count_ % kNumCharsToIterate; |
| 39 std::string result(count_modulus + 1, kInitialChar + count_modulus); |
| 40 CHECK_GT(result.size(), 0U); |
| 41 ++call_count_; |
| 42 |
| 43 SystemLogsResponse* result_map = new SystemLogsResponse; |
| 44 result_map->emplace("", result); |
| 45 |
| 46 // Do not directly pass the result to the callback, because that's not how |
| 47 // log sources actually work. Instead, simulate the asynchronous operation |
| 48 // of a SingleLogSource by invoking the callback separately. |
| 49 base::PostDelayedTaskWithTraits( |
| 50 FROM_HERE, base::TaskPriority::BACKGROUND, |
| 51 base::Bind(callback, base::Owned(result_map)), |
| 52 base::TimeDelta::FromMilliseconds(0)); |
| 53 } |
| 54 |
| 55 // Instantiates a new instance of this class. Does not retain ownership. Used |
| 56 // to create a Callback that can be used to override the default behavior of |
| 57 // SingleLogSourceFactory. |
| 58 static SingleLogSource* Create(SupportedSource type) { |
| 59 return new TestSingleLogSource(type); |
| 60 } |
| 61 |
| 62 private: |
| 63 // Iterate over the whole lowercase alphabet, starting from 'a'. |
| 64 const int kNumCharsToIterate = 26; |
| 65 const char kInitialChar = 'a'; |
| 66 |
| 67 // Keep track of how many times Fetch() has been called, in order to determine |
| 68 // its behavior each time. |
| 69 int call_count_; |
| 70 |
| 71 DISALLOW_COPY_AND_ASSIGN(TestSingleLogSource); |
| 72 }; |
| 73 |
| 74 } // namespace |
| 75 |
| 76 class FeedbackApiUnittest : public ApiUnitTest { |
| 77 public: |
| 78 FeedbackApiUnittest() |
| 79 : create_callback_(base::Bind(&TestSingleLogSource::Create)) {} |
| 80 ~FeedbackApiUnittest() override {} |
| 81 |
| 82 void SetUp() override { |
| 83 ApiUnitTest::SetUp(); |
| 84 |
| 85 SingleLogSourceFactory::InitForTesting(&create_callback_); |
| 86 } |
| 87 |
| 88 void TearDown() override { |
| 89 SingleLogSourceFactory::InitForTesting(nullptr); |
| 90 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(nullptr); |
| 91 |
| 92 ApiUnitTest::TearDown(); |
| 93 } |
| 94 |
| 95 // Runs the feedbackPrivate.readLogSource() function. See API function |
| 96 // definition for argument descriptions. Attempts to interpret the result as |
| 97 // the following ListValue: |
| 98 // [ int result_reader_id, [ string result_string ] ]. |
| 99 // |
| 100 // Note that the second argument of the result is a list of strings, but the |
| 101 // test class TestSingleLogSource always returns a list containing a single |
| 102 // string. |
| 103 // |
| 104 // If the result does follow the above format, returns the reader ID and |
| 105 // string value. |
| 106 // |
| 107 // Returns failure if the result does not conform to the above format, or is |
| 108 // otherwise invalid. |
| 109 testing::AssertionResult RunReadLogSourceFunction( |
| 110 const ReadLogSourceParams& params, |
| 111 int* result_reader_id, |
| 112 std::string* result_string) { |
| 113 std::unique_ptr<base::Value> result = RunFunctionAndReturnValue( |
| 114 new FeedbackPrivateReadLogSourceFunction(), |
| 115 ParamsToJSON(params)); |
| 116 |
| 117 if (!result) |
| 118 return testing::AssertionFailure() << "No result"; |
| 119 |
| 120 base::ListValue* list = nullptr; |
| 121 if (!result->GetAsList(&list)) { |
| 122 return testing::AssertionFailure() << "Result was not a list."; |
| 123 } |
| 124 if (list->GetSize() != 2) { |
| 125 return testing::AssertionFailure() << "Expected result length=2, actual=" |
| 126 << list->GetSize(); |
| 127 } |
| 128 if (!list->GetInteger(0, result_reader_id)) { |
| 129 return testing::AssertionFailure() << "Could not read argument 0 as int."; |
| 130 } |
| 131 |
| 132 base::ListValue* string_list = nullptr; |
| 133 if (!list->GetList(1, &string_list)) { |
| 134 return testing::AssertionFailure() |
| 135 << "Could not read argument 1 as list."; |
| 136 } |
| 137 if (string_list->GetSize() != 1) { |
| 138 return testing::AssertionFailure() |
| 139 << "Argument 1 list expected to have size=1, actual=" |
| 140 << string_list->GetSize(); |
| 141 } |
| 142 if (!string_list->GetString(0, result_string)) { |
| 143 return testing::AssertionFailure() |
| 144 << "Could not read argument 1 list's argument 0 as string."; |
| 145 } |
| 146 |
| 147 return testing::AssertionSuccess(); |
| 148 } |
| 149 |
| 150 private: |
| 151 // Converts |params| to a string containing a JSON dictionary within an |
| 152 // argument list. |
| 153 std::string ParamsToJSON(const ReadLogSourceParams& params) { |
| 154 return base::StringPrintf( |
| 155 "[{\"source\": \"%s\"," |
| 156 " \"incremental\": %s," |
| 157 " \"readerId\": %u}]", |
| 158 api::feedback_private::ToString(params.source).c_str(), |
| 159 params.incremental ? "true" : "false", |
| 160 params.reader_id ? *params.reader_id : 0); |
| 161 } |
| 162 |
| 163 SingleLogSourceFactory::CreateCallback create_callback_; |
| 164 |
| 165 DISALLOW_COPY_AND_ASSIGN(FeedbackApiUnittest); |
| 166 }; |
| 167 |
| 168 TEST_F(FeedbackApiUnittest, ReadLogSourceNonIncremental) { |
| 169 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0)); |
| 170 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 171 |
| 172 ReadLogSourceParams params; |
| 173 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 174 params.incremental = false; |
| 175 |
| 176 // Test multiple non-incremental reads. |
| 177 int result_reader_id = -1; |
| 178 std::string result_string; |
| 179 EXPECT_TRUE( |
| 180 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 181 EXPECT_EQ(0, result_reader_id); |
| 182 EXPECT_EQ("a", result_string); |
| 183 |
| 184 result_reader_id = -1; |
| 185 result_string.clear(); |
| 186 EXPECT_TRUE( |
| 187 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 188 EXPECT_EQ(0, result_reader_id); |
| 189 EXPECT_EQ("a", result_string); |
| 190 |
| 191 result_reader_id = -1; |
| 192 result_string.clear(); |
| 193 EXPECT_TRUE( |
| 194 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 195 EXPECT_EQ(0, result_reader_id); |
| 196 EXPECT_EQ("a", result_string); |
| 197 } |
| 198 |
| 199 TEST_F(FeedbackApiUnittest, ReadLogSourceIncremental) { |
| 200 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0)); |
| 201 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout); |
| 202 |
| 203 ReadLogSourceParams params; |
| 204 params.source = api::feedback_private::LOG_SOURCE_MESSAGES; |
| 205 params.incremental = true; |
| 206 |
| 207 int result_reader_id = 0; |
| 208 std::string result_string; |
| 209 EXPECT_TRUE( |
| 210 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 211 EXPECT_EQ(1, result_reader_id); |
| 212 EXPECT_EQ("a", result_string); |
| 213 params.reader_id.reset(new int(result_reader_id)); |
| 214 |
| 215 EXPECT_TRUE( |
| 216 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 217 EXPECT_EQ(1, result_reader_id); |
| 218 EXPECT_EQ("bb", result_string); |
| 219 |
| 220 EXPECT_TRUE( |
| 221 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 222 EXPECT_EQ(1, result_reader_id); |
| 223 EXPECT_EQ("ccc", result_string); |
| 224 |
| 225 // End the incremental read. |
| 226 params.incremental = false; |
| 227 EXPECT_TRUE( |
| 228 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 229 EXPECT_EQ(0, result_reader_id); |
| 230 EXPECT_EQ("dddd", result_string); |
| 231 |
| 232 // Start a new incremental read. |
| 233 params.incremental = true; |
| 234 *params.reader_id = 0; |
| 235 EXPECT_TRUE( |
| 236 RunReadLogSourceFunction(params, &result_reader_id, &result_string)); |
| 237 // The reader ID should be incremented. |
| 238 EXPECT_EQ(2, result_reader_id); |
| 239 EXPECT_EQ("a", result_string); |
| 240 } |
| 241 |
| 242 } // namespace extensions |
| OLD | NEW |