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

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: Responded to comments from Patch Set 14 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/memory/ptr_util.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/feedback_private/log_source_resource.h"
14 #include "chrome/browser/extensions/api/feedback_private/single_log_source_facto ry.h"
15 #include "chrome/browser/extensions/extension_api_unittest.h"
16 #include "extensions/browser/api_test_utils.h"
17 #include "extensions/browser/api_unittest.h"
18
19 namespace extensions {
20
21 namespace {
22
23 using api::feedback_private::ReadLogSourceResult;
24 using api::feedback_private::ReadLogSourceParams;
25 using system_logs::SingleLogSource;
26 using system_logs::SystemLogsResponse;
27 using SupportedSource = system_logs::SingleLogSource::SupportedSource;
28
29 std::unique_ptr<KeyedService> ApiResourceManagerTestFactory(
30 content::BrowserContext* context) {
31 return base::MakeUnique<ApiResourceManager<LogSourceResource>>(context);
32 }
33
34 // A dummy SingleLogSource that does not require real system logs to be
35 // available during testing.
36 class TestSingleLogSource : public SingleLogSource {
37 public:
38 explicit TestSingleLogSource(SupportedSource type)
39 : SingleLogSource(type), call_count_(0) {}
40
41 ~TestSingleLogSource() override = default;
42
43 // Fetch() will return a single different string each time, in the following
44 // sequence: "a", "bb", "ccc", until a string of 26 z's. Will never return an
45 // empty result.
46 void Fetch(const system_logs::SysLogsSourceCallback& callback) override {
47 int count_modulus = call_count_ % kNumCharsToIterate;
48 std::string result(count_modulus + 1, kInitialChar + count_modulus);
49 ASSERT_GT(result.size(), 0U);
50 ++call_count_;
51
52 SystemLogsResponse* result_map = new SystemLogsResponse;
53 result_map->emplace("", result);
54
55 // Do not directly pass the result to the callback, because that's not how
56 // log sources actually work. Instead, simulate the asynchronous operation
57 // of a SingleLogSource by invoking the callback separately.
58 base::ThreadTaskRunnerHandle::Get()->PostTask(
59 FROM_HERE, base::Bind(callback, base::Owned(result_map)));
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 std::unique_ptr<SingleLogSource> Create(SupportedSource type) {
66 return base::MakeUnique<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 {
tbarzic 2017/06/07 03:39:02 nit: I'd rename this to FeedbackPrivateApiTest
Simon Que 2017/06/07 18:25:58 Done.
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(),
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 ->GetLogSourceAccessManager()
111 ->SetTickClockForTesting(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(
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 return testing::AssertionFailure()
198 << "Invalid ReadLogSourceResult format: " << *result_value;
199 }
200
201 return testing::AssertionSuccess();
202 }
203
204 // Passed to SingleLogSourceFactory so that the API can create an instance of
205 // TestSingleLogSource for testing.
206 SingleLogSourceFactory::CreateCallback create_callback_;
207
208 // content::TestBrowserThreadBundle browser_thread_bundle_;
209
210 DISALLOW_COPY_AND_ASSIGN(FeedbackApiUnittest);
211 };
212
213 TEST_F(FeedbackApiUnittest, ReadLogSourceInvalidId) {
214 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
215 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
216
217 ReadLogSourceParams params;
218 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
219 params.incremental = true;
220 params.reader_id.reset(new int(9999));
221
222 int result_reader_id;
223 std::string result_string;
224 EXPECT_FALSE(
225 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
226 }
227
228 TEST_F(FeedbackApiUnittest, ReadLogSourceNonIncremental) {
229 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
230 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
231
232 ReadLogSourceParams params;
233 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
234 params.incremental = false;
235
236 // Test multiple non-incremental reads.
237 int result_reader_id = -1;
238 std::string result_string;
239 EXPECT_TRUE(
240 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
241 EXPECT_EQ(0, result_reader_id);
242 EXPECT_EQ("a", result_string);
243
244 result_reader_id = -1;
245 result_string.clear();
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
259 TEST_F(FeedbackApiUnittest, ReadLogSourceIncremental) {
260 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
261 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
262
263 ReadLogSourceParams params;
264 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
265 params.incremental = true;
266
267 int result_reader_id = 0;
268 std::string result_string;
269 EXPECT_TRUE(
270 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
271 EXPECT_EQ(1, result_reader_id);
tbarzic 2017/06/07 17:58:38 reader IDs being incremental seems like implementa
Simon Que 2017/06/07 18:25:58 Done.
272 EXPECT_EQ("a", result_string);
273 params.reader_id.reset(new int(result_reader_id));
274
275 EXPECT_TRUE(
276 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
277 EXPECT_EQ(1, result_reader_id);
278 EXPECT_EQ("bb", result_string);
279
280 EXPECT_TRUE(
281 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
282 EXPECT_EQ(1, result_reader_id);
283 EXPECT_EQ("ccc", result_string);
284
285 // End the incremental read.
286 params.incremental = false;
287 EXPECT_TRUE(
288 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
289 EXPECT_EQ(0, result_reader_id);
290 EXPECT_EQ("dddd", result_string);
291
292 // The log source will no longer be valid if we try to read it.
293 params.incremental = true;
294 EXPECT_FALSE(
295 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
296 }
297
298 TEST_F(FeedbackApiUnittest, ReadLogSourceMultipleSources) {
299 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(0));
300 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
301
302 int result_reader_id = 0;
303 std::string result_string;
304
305 // Attempt to open LOG_SOURCE_MESSAGES twice.
306 ReadLogSourceParams params1a;
tbarzic 2017/06/07 17:58:38 Can you make the param var names more meaningful?
Simon Que 2017/06/07 18:25:58 Done.
307 params1a.source = api::feedback_private::LOG_SOURCE_MESSAGES;
308 params1a.incremental = true;
309 EXPECT_TRUE(
310 RunReadLogSourceFunction(params1a, &result_reader_id, &result_string));
311 EXPECT_EQ(1, result_reader_id);
312 params1a.reader_id.reset(new int(result_reader_id));
tbarzic 2017/06/07 17:58:38 nit: use base::MakeUnique here. though, I'd prefe
Simon Que 2017/06/07 18:25:58 Done. This needs to be stored back into the param
313
314 // Cannot perform a second read from the same log source.
315 ReadLogSourceParams params1b;
316 params1b.source = api::feedback_private::LOG_SOURCE_MESSAGES;
317 params1b.incremental = true;
318 EXPECT_FALSE(
319 RunReadLogSourceFunction(params1b, &result_reader_id, &result_string));
320
321 // Attempt to open LOG_SOURCE_UI_LATEST twice.
322 ReadLogSourceParams params2a;
323 params2a.source = api::feedback_private::LOG_SOURCE_UILATEST;
324 params2a.incremental = true;
325 result_reader_id = -1;
326 EXPECT_TRUE(
327 RunReadLogSourceFunction(params2a, &result_reader_id, &result_string));
328 params2a.reader_id.reset(new int(result_reader_id));
329 EXPECT_EQ(2, result_reader_id);
330
331 // Cannot perform a second read from the same log source.
332 ReadLogSourceParams params2b;
333 params2b.source = api::feedback_private::LOG_SOURCE_UILATEST;
334 params2b.incremental = true;
335 EXPECT_FALSE(
336 RunReadLogSourceFunction(params2b, &result_reader_id, &result_string));
337
338 // Close the two open log source readers, and make sure new ones can be
339 // opened.
340 params1a.incremental = false;
341 result_reader_id = -1;
342 EXPECT_TRUE(
343 RunReadLogSourceFunction(params1a, &result_reader_id, &result_string));
344 EXPECT_EQ(0, result_reader_id);
345
346 params2a.incremental = false;
347 result_reader_id = -1;
348 EXPECT_TRUE(
349 RunReadLogSourceFunction(params2a, &result_reader_id, &result_string));
350 EXPECT_EQ(0, result_reader_id);
351
352 EXPECT_TRUE(
353 RunReadLogSourceFunction(params1b, &result_reader_id, &result_string));
354 EXPECT_EQ(3, result_reader_id);
355 EXPECT_TRUE(
356 RunReadLogSourceFunction(params2b, &result_reader_id, &result_string));
357 EXPECT_EQ(4, result_reader_id);
358 }
359
360 TEST_F(FeedbackApiUnittest, ReadLogSourceWithAccessTimeouts) {
361 const base::TimeDelta timeout(base::TimeDelta::FromMilliseconds(100));
362 LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
363
364 base::SimpleTestTickClock* test_clock = new base::SimpleTestTickClock;
365 FeedbackPrivateAPI::GetFactoryInstance()
366 ->Get(browser()->profile())
367 ->GetLogSourceAccessManager()
368 ->SetTickClockForTesting(std::unique_ptr<base::TickClock>(test_clock));
369
370 ReadLogSourceParams params;
371 params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
372 params.incremental = true;
373 int result_reader_id = 0;
374 std::string result_string;
375
376 auto FromMilliseconds = &base::TimeDelta::FromMilliseconds;
tbarzic 2017/06/07 17:58:38 I'd prefer using TimeDelta::FromMilliseconds. (wit
Simon Que 2017/06/07 18:25:58 Done.
377 // |test_clock| must start out at something other than 0, which is interpreted
378 // as an invalid value.
379 test_clock->Advance(FromMilliseconds(100));
380
381 EXPECT_TRUE(
382 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
383 EXPECT_EQ(1, result_reader_id);
384 params.reader_id.reset(new int(result_reader_id));
385
386 // Immediately perform another read. This is not allowed.
387 EXPECT_FALSE(
388 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
389
390 // Advance to t=120, but it will not be allowed.
391 test_clock->Advance(FromMilliseconds(20));
392 EXPECT_FALSE(
393 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
394
395 // Advance to t=150, but still not allowed.
396 test_clock->Advance(FromMilliseconds(30));
397 EXPECT_FALSE(
tbarzic 2017/06/07 03:39:02 it would be nice if the test distinguished between
Simon Que 2017/06/07 18:25:58 Done.
398 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
399
400 // Advance to t=199, but still not allowed.
401 test_clock->Advance(FromMilliseconds(49));
402 EXPECT_FALSE(
403 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
404
405 // Advance to t=210, annd the access is finally allowed.
406 test_clock->Advance(FromMilliseconds(11));
407 EXPECT_TRUE(
408 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
409
410 // Advance to t=309, but it will not be allowed.
411 test_clock->Advance(FromMilliseconds(99));
412 EXPECT_FALSE(
413 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
414
415 // Another read is finally allowed at t=310.
416 test_clock->Advance(FromMilliseconds(1));
417 EXPECT_TRUE(
418 RunReadLogSourceFunction(params, &result_reader_id, &result_string));
419 }
420
421 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698