Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: chrome/browser/extensions/api/feedback_private/feedback_private_api_chromeos_unittest.cc

Issue 2840103002: Add new API function: feedbackPrivate.readLogSource (Closed)
Patch Set: Refactor passing of params from API into Log Source Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/test/simple_test_tick_clock.h"
10 #include "base/threading/thread_task_runner_handle.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 #include "extensions/browser/api_unittest.h"
17
18 namespace extensions {
19
20 namespace {
21
22 using api::feedback_private::ReadLogSourceResult;
23 using api::feedback_private::ReadLogSourceParams;
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 // A dummy SingleLogSource that does not require real system logs to be
34 // available during testing.
35 class TestSingleLogSource : public SingleLogSource {
36 public:
37 explicit TestSingleLogSource(SupportedSource type)
38 : SingleLogSource(type), call_count_(0) {}
39
40 ~TestSingleLogSource() override {}
tbarzic 2017/06/06 20:27:25 = default
Simon Que 2017/06/06 22:29:14 Done.
41
42 // Fetch() will return a single different string each time, in the following
43 // sequence: "a", "bb", "ccc", until a string of 26 z's. Will never return an
44 // empty result.
45 void Fetch(const system_logs::SysLogsSourceCallback& callback) override {
46 int count_modulus = call_count_ % kNumCharsToIterate;
47 std::string result(count_modulus + 1, kInitialChar + count_modulus);
48 CHECK_GT(result.size(), 0U);
tbarzic 2017/06/06 20:27:25 ASSERT_GT
Simon Que 2017/06/06 22:29:14 Done.
49 ++call_count_;
50
51 SystemLogsResponse* result_map = new SystemLogsResponse;
52 result_map->emplace("", result);
53
54 // Do not directly pass the result to the callback, because that's not how
55 // log sources actually work. Instead, simulate the asynchronous operation
56 // of a SingleLogSource by invoking the callback separately.
57 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tbarzic 2017/06/06 20:27:25 You can use PostTask instead PostDelayedTask(...,
Simon Que 2017/06/06 22:29:14 Done.
58 FROM_HERE, base::Bind(callback, base::Owned(result_map)),
59 base::TimeDelta::FromMilliseconds(0));
60 }
61
62 // Instantiates a new instance of this class. Does not retain ownership. Used
63 // to create a Callback that can be used to override the default behavior of
64 // SingleLogSourceFactory.
65 static SingleLogSource* Create(SupportedSource type) {
66 return new TestSingleLogSource(type);
67 }
68
69 private:
70 // Iterate over the whole lowercase alphabet, starting from 'a'.
71 const int kNumCharsToIterate = 26;
72 const char kInitialChar = 'a';
73
74 // Keep track of how many times Fetch() has been called, in order to determine
75 // its behavior each time.
76 int call_count_;
77
78 DISALLOW_COPY_AND_ASSIGN(TestSingleLogSource);
79 };
80
81 } // namespace
82
83 class FeedbackApiUnittest : public ExtensionApiUnittest {
84 public:
85 FeedbackApiUnittest()
86 : create_callback_(base::Bind(&TestSingleLogSource::Create)) {}
87 ~FeedbackApiUnittest() override {}
88
89 void SetUp() override {
90 ExtensionApiUnittest::SetUp();
91
92 // The ApiResourceManager used for LogSourceResource is destroyed every time
93 // a unit test finishes, during TearDown(). There is no way to re-create it
94 // normally. The below code forces it to be re-created during SetUp(), so
95 // that there is always a valid ApiResourceManager<LogSourceResource> when
96 // subsequent unit tests are running.
97 ApiResourceManager<LogSourceResource>::GetFactoryInstance()
98 ->SetTestingFactoryAndUse(browser()->profile(),
tbarzic 2017/06/07 03:39:02 use profile() instead of browser()->profile()
Simon Que 2017/06/07 18:25:58 Done.
99 ApiResourceManagerTestFactory);
100
101 SingleLogSourceFactory::SetForTesting(&create_callback_);
102 }
103
104 void TearDown() override {
105 SingleLogSourceFactory::SetForTesting(nullptr);
106 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(nullptr);
107
108 FeedbackPrivateAPI::GetFactoryInstance()
109 ->Get(browser()->profile())
110 ->log_source_access_manager()
111 ->set_tick_clock(nullptr);
112
113 ExtensionApiUnittest::TearDown();
114 }
115
116 // Runs the feedbackPrivate.readLogSource() function. See API function
117 // definition for argument descriptions.
118 //
119 // Note that the second argument of the result is a list of strings, but the
120 // test class TestSingleLogSource always returns a list containing a single
121 // string. To simplify things, the single string result will be returned in
122 // |*result_string|, while the reader ID is returned in |*result_reader_id|.
123 testing::AssertionResult RunReadLogSourceFunction(
124 const ReadLogSourceParams& params,
125 int* result_reader_id,
126 std::string* result_string) {
127 scoped_refptr<FeedbackPrivateReadLogSourceFunction> function =
128 new FeedbackPrivateReadLogSourceFunction;
129
130 std::unique_ptr<base::ListValue> result_list =
131 RunFunctionAndReturnValue(function.get(), ParamsToJSON(params));
132 if (!result_list)
133 return testing::AssertionFailure() << "No result";
134
135 ReadLogSourceResult result;
136 testing::AssertionResult parse_result =
137 ParseReadLogSourceResult(*result_list, &result);
138 if (!parse_result)
139 return parse_result;
140
141 if (result.log_lines.size() != 1) {
142 return testing::AssertionFailure()
143 << "Expected |log_lines| to contain 1 string, actual number: "
144 << result.log_lines.size();
145 }
146
147 *result_reader_id = result.reader_id;
148 *result_string = result.log_lines[0];
149
150 return testing::AssertionSuccess();
151 }
152
153 private:
154 // Converts |params| to a string containing a JSON dictionary within an
155 // argument list.
156 std::string ParamsToJSON(const ReadLogSourceParams& params) {
157 base::ListValue params_value;
158 params_value.Append(params.ToValue());
159 std::string params_json_string;
160 EXPECT_TRUE(base::JSONWriter::Write(params_value, &params_json_string));
161
162 return params_json_string;
163 }
164
165 // Runs |function| with arguments |args| in JSON string format and returns the
166 // result as a base::ListValue.
167 std::unique_ptr<base::ListValue> RunFunctionAndReturnValue(
tbarzic 2017/06/06 20:27:25 I think you can use RunFunctionAndReturnValue inst
Simon Que 2017/06/06 22:29:14 That function still ends up with an EXPECT that th
Simon Que 2017/06/07 01:43:24 When ApiUnitTest and api_test_utils get refactored
Simon Que 2017/06/07 01:57:51 *If that feature were added, we can remove the loc
tbarzic 2017/06/07 03:39:02 That feature kinda already exists - instead of usi
Simon Que 2017/06/07 18:25:58 Done.
168 UIThreadExtensionFunction* function,
169 const std::string& args) {
170 function->set_extension(extension());
171 if (!api_test_utils::RunFunction(function, args, browser()->profile()))
172 return nullptr;
173
174 const base::ListValue* result_list = function->GetResultList();
175 if (!result_list)
176 return nullptr;
177
178 return result_list->CreateDeepCopy();
179 }
180
181 // Attempts to interpret the result as a ReadLogSourceResult. Returns failure
182 // if |value| does not conform to the format of a list containing a single
183 // element that is a ReadLogSourceResult object.
184 testing::AssertionResult ParseReadLogSourceResult(
185 const base::ListValue& list_value,
186 ReadLogSourceResult* result) {
187 if (list_value.empty())
188 return testing::AssertionFailure() << "Result is empty.";
189
190 const base::Value* result_value = nullptr;
191 if (!list_value.Get(0, &result_value)) {
192 return testing::AssertionFailure()
193 << "Unable to get first element of result list.";
194 }
195
196 if (!ReadLogSourceResult::Populate(*result_value, result)) {
197 std::string json_string;
198 if (!base::JSONWriter::Write(*result_value, &json_string)) {
199 return testing::AssertionFailure()
200 << "Unable to parse result object as JSON.";
201 }
202
203 return testing::AssertionFailure()
204 << "Result not in valid ReadLogSourceResult format: "
tbarzic 2017/06/06 20:27:25 I think you can use base::Value directly for loggi
Simon Que 2017/06/06 22:29:14 Done.
205 << json_string;
206 }
207
208 return testing::AssertionSuccess();
209 }
210
211 // Passed to SingleLogSourceFactory so that the API can create an instance of
212 // TestSingleLogSource for testing.
213 const SingleLogSourceFactory::CreateCallback create_callback_;
214
215 // content::TestBrowserThreadBundle browser_thread_bundle_;
216
217 DISALLOW_COPY_AND_ASSIGN(FeedbackApiUnittest);
218 };
219
220 TEST_F(FeedbackApiUnittest, ReadLogSourceInvalidId) {
221 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
222 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
223
224 ReadLogSourceParams params;
225 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
226 params.incremental = true;
227 params.reader_id.reset(new int(9999));
228
229 int result_reader_id;
230 std::string result_string;
231 EXPECT_FALSE(
232 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
233 }
234
235 TEST_F(FeedbackApiUnittest, ReadLogSourceNonIncremental) {
236 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
237 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
238
239 ReadLogSourceParams params;
240 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
241 params.incremental = false;
242
243 // Test multiple non-incremental reads.
244 int result_reader_id = -1;
245 std::string result_string;
246 EXPECT_TRUE(
247 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
248 EXPECT_EQ(0, result_reader_id);
249 EXPECT_EQ("a", result_string);
250
251 result_reader_id = -1;
252 result_string.clear();
253 EXPECT_TRUE(
254 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
255 EXPECT_EQ(0, result_reader_id);
256 EXPECT_EQ("a", result_string);
257
258 result_reader_id = -1;
259 result_string.clear();
260 EXPECT_TRUE(
261 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
262 EXPECT_EQ(0, result_reader_id);
263 EXPECT_EQ("a", result_string);
264 }
265
266 TEST_F(FeedbackApiUnittest, ReadLogSourceIncremental) {
267 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
268 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
269
270 ReadLogSourceParams params;
271 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
272 params.incremental = true;
273
274 int result_reader_id = 0;
275 std::string result_string;
276 EXPECT_TRUE(
277 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
278 EXPECT_EQ(1, result_reader_id);
279 EXPECT_EQ("a", result_string);
280 params.reader_id.reset(new int(result_reader_id));
281
282 EXPECT_TRUE(
283 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
284 EXPECT_EQ(1, result_reader_id);
285 EXPECT_EQ("bb", result_string);
286
287 EXPECT_TRUE(
288 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
289 EXPECT_EQ(1, result_reader_id);
290 EXPECT_EQ("ccc", result_string);
291
292 // End the incremental read.
293 params.incremental = false;
294 EXPECT_TRUE(
295 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
296 EXPECT_EQ(0, result_reader_id);
297 EXPECT_EQ("dddd", result_string);
298
299 // The log source will no longer be valid if we try to read it.
300 params.incremental = true;
301 EXPECT_FALSE(
302 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
303 }
304
305 TEST_F(FeedbackApiUnittest, ReadLogSourceMultipleSources) {
306 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
307 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
308
309 int result_reader_id = 0;
310 std::string result_string;
311
312 // Attempt to open LOG_SOURCE_MESSAGES twice.
313 ReadLogSourceParams params1a;
314 params1a.source = api::feedback_private::LOG_SOURCE_MESSAGES;
315 params1a.incremental = true;
316 EXPECT_TRUE(
317 RunReadLogSourceFunction(params1a, &result_reader_id, &result_string));
318 EXPECT_EQ(1, result_reader_id);
319 params1a.reader_id.reset(new int(result_reader_id));
320
321 // Cannot perform a second read from the same log source.
322 ReadLogSourceParams params1b;
323 params1b.source = api::feedback_private::LOG_SOURCE_MESSAGES;
324 params1b.incremental = true;
325 EXPECT_FALSE(
326 RunReadLogSourceFunction(params1b, &result_reader_id, &result_string));
327
328 // Attempt to open LOG_SOURCE_UI_LATEST twice.
329 ReadLogSourceParams params2a;
330 params2a.source = api::feedback_private::LOG_SOURCE_UILATEST;
331 params2a.incremental = true;
332 result_reader_id = -1;
333 EXPECT_TRUE(
334 RunReadLogSourceFunction(params2a, &result_reader_id, &result_string));
335 params2a.reader_id.reset(new int(result_reader_id));
336 EXPECT_EQ(2, result_reader_id);
337
338 // Cannot perform a second read from the same log source.
339 ReadLogSourceParams params2b;
340 params2b.source = api::feedback_private::LOG_SOURCE_UILATEST;
341 params2b.incremental = true;
342 EXPECT_FALSE(
343 RunReadLogSourceFunction(params2b, &result_reader_id, &result_string));
344
345 // Close the two open log source readers, and make sure new ones can be
346 // opened.
347 params1a.incremental = false;
348 result_reader_id = -1;
349 EXPECT_TRUE(
350 RunReadLogSourceFunction(params1a, &result_reader_id, &result_string));
351 EXPECT_EQ(0, result_reader_id);
352
353 params2a.incremental = false;
354 result_reader_id = -1;
355 EXPECT_TRUE(
356 RunReadLogSourceFunction(params2a, &result_reader_id, &result_string));
357 EXPECT_EQ(0, result_reader_id);
358
359 EXPECT_TRUE(
360 RunReadLogSourceFunction(params1b, &result_reader_id, &result_string));
361 EXPECT_EQ(3, result_reader_id);
362 EXPECT_TRUE(
363 RunReadLogSourceFunction(params2b, &result_reader_id, &result_string));
364 EXPECT_EQ(4, result_reader_id);
365 }
366
367 TEST_F(FeedbackApiUnittest, ReadLogSourceWithAccessTimeouts) {
368 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(100));
369 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
370
371 base::SimpleTestTickClock* test_clock = new base::SimpleTestTickClock;
372 FeedbackPrivateAPI::GetFactoryInstance()
373 ->Get(browser()->profile())
374 ->log_source_access_manager()
375 ->set_tick_clock(std::unique_ptr<base::TickClock>(test_clock));
376
377 ReadLogSourceParams params;
378 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
379 params.incremental = true;
380 int result_reader_id = 0;
381 std::string result_string;
382
383 auto FromMilliseconds = &base::TimeDelta::FromMilliseconds;
384 // |test_clock| must start out at something other than 0, which is interpreted
385 // as an invalid value.
386 test_clock->Advance(FromMilliseconds(100));
387
388 EXPECT_TRUE(
389 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
390 EXPECT_EQ(1, result_reader_id);
391 params.reader_id.reset(new int(result_reader_id));
392
393 // Immediately perform another read. This is not allowed.
394 EXPECT_FALSE(
395 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
396
397 // Advance to t=120, but it will not be allowed.
398 test_clock->Advance(FromMilliseconds(20));
399 EXPECT_FALSE(
400 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
401
402 // Advance to t=150, but still not allowed.
403 test_clock->Advance(FromMilliseconds(30));
404 EXPECT_FALSE(
405 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
406
407 // Advance to t=199, but still not allowed.
408 test_clock->Advance(FromMilliseconds(49));
409 EXPECT_FALSE(
410 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
411
412 // Advance to t=210, annd the access is finally allowed.
413 test_clock->Advance(FromMilliseconds(11));
414 EXPECT_TRUE(
415 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
416
417 // Advance to t=309, but it will not be allowed.
418 test_clock->Advance(FromMilliseconds(99));
419 EXPECT_FALSE(
420 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
421
422 // Another read is finally allowed at t=310.
423 test_clock->Advance(FromMilliseconds(1));
424 EXPECT_TRUE(
425 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
426 }
427
428 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698