Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / dom_storage / dom_storage_area_unittest.cc
blobaa5653da319a55db2730d0a8c3d5bee8b0727886
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.
5 #include "base/bind.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "base/time/time.h"
13 #include "content/browser/dom_storage/dom_storage_area.h"
14 #include "content/browser/dom_storage/dom_storage_database.h"
15 #include "content/browser/dom_storage/dom_storage_database_adapter.h"
16 #include "content/browser/dom_storage/dom_storage_task_runner.h"
17 #include "content/browser/dom_storage/local_storage_database_adapter.h"
18 #include "content/common/dom_storage/dom_storage_types.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using base::ASCIIToUTF16;
24 namespace content {
26 class DOMStorageAreaTest : public testing::Test {
27 public:
28 DOMStorageAreaTest()
29 : kOrigin(GURL("http://dom_storage/")),
30 kKey(ASCIIToUTF16("key")),
31 kValue(ASCIIToUTF16("value")),
32 kKey2(ASCIIToUTF16("key2")),
33 kValue2(ASCIIToUTF16("value2")) {
36 const GURL kOrigin;
37 const base::string16 kKey;
38 const base::string16 kValue;
39 const base::string16 kKey2;
40 const base::string16 kValue2;
42 // Method used in the CommitTasks test case.
43 void InjectedCommitSequencingTask1(
44 const scoped_refptr<DOMStorageArea>& area) {
45 // At this point the StartCommitTimer task has run and
46 // the OnCommitTimer task is queued. We want to inject after
47 // that.
48 base::MessageLoop::current()->PostTask(
49 FROM_HERE,
50 base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask2,
51 base::Unretained(this),
52 area));
55 void InjectedCommitSequencingTask2(
56 const scoped_refptr<DOMStorageArea>& area) {
57 // At this point the OnCommitTimer has run.
58 // Verify that it put a commit in flight.
59 EXPECT_EQ(1, area->commit_batches_in_flight_);
60 EXPECT_FALSE(area->commit_batch_.get());
61 EXPECT_TRUE(area->HasUncommittedChanges());
62 // Make additional change and verify that a new commit batch
63 // is created for that change.
64 base::NullableString16 old_value;
65 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
66 EXPECT_TRUE(area->commit_batch_.get());
67 EXPECT_EQ(1, area->commit_batches_in_flight_);
68 EXPECT_TRUE(area->HasUncommittedChanges());
71 // Class used in the CommitChangesAtShutdown test case.
72 class VerifyChangesCommittedDatabase : public DOMStorageDatabase {
73 public:
74 VerifyChangesCommittedDatabase() {}
75 ~VerifyChangesCommittedDatabase() override {
76 const base::string16 kKey(ASCIIToUTF16("key"));
77 const base::string16 kValue(ASCIIToUTF16("value"));
78 DOMStorageValuesMap values;
79 ReadAllValues(&values);
80 EXPECT_EQ(1u, values.size());
81 EXPECT_EQ(kValue, values[kKey].string());
85 private:
86 base::MessageLoop message_loop_;
89 TEST_F(DOMStorageAreaTest, DOMStorageAreaBasics) {
90 scoped_refptr<DOMStorageArea> area(
91 new DOMStorageArea(1, std::string(), kOrigin, NULL, NULL));
92 base::string16 old_value;
93 base::NullableString16 old_nullable_value;
94 scoped_refptr<DOMStorageArea> copy;
96 // We don't focus on the underlying DOMStorageMap functionality
97 // since that's covered by seperate unit tests.
98 EXPECT_EQ(kOrigin, area->origin());
99 EXPECT_EQ(1, area->namespace_id());
100 EXPECT_EQ(0u, area->Length());
101 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
102 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_nullable_value));
103 EXPECT_FALSE(area->HasUncommittedChanges());
105 // Verify that a copy shares the same map.
106 copy = area->ShallowCopy(2, std::string());
107 EXPECT_EQ(kOrigin, copy->origin());
108 EXPECT_EQ(2, copy->namespace_id());
109 EXPECT_EQ(area->Length(), copy->Length());
110 EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string());
111 EXPECT_EQ(area->Key(0).string(), copy->Key(0).string());
112 EXPECT_EQ(copy->map_.get(), area->map_.get());
114 // But will deep copy-on-write as needed.
115 EXPECT_TRUE(area->RemoveItem(kKey, &old_value));
116 EXPECT_NE(copy->map_.get(), area->map_.get());
117 copy = area->ShallowCopy(2, std::string());
118 EXPECT_EQ(copy->map_.get(), area->map_.get());
119 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
120 EXPECT_NE(copy->map_.get(), area->map_.get());
121 copy = area->ShallowCopy(2, std::string());
122 EXPECT_EQ(copy->map_.get(), area->map_.get());
123 EXPECT_NE(0u, area->Length());
124 EXPECT_TRUE(area->Clear());
125 EXPECT_EQ(0u, area->Length());
126 EXPECT_NE(copy->map_.get(), area->map_.get());
128 // Verify that once Shutdown(), behaves that way.
129 area->Shutdown();
130 EXPECT_TRUE(area->is_shutdown_);
131 EXPECT_FALSE(area->map_.get());
132 EXPECT_EQ(0u, area->Length());
133 EXPECT_TRUE(area->Key(0).is_null());
134 EXPECT_TRUE(area->GetItem(kKey).is_null());
135 EXPECT_FALSE(area->SetItem(kKey, kValue, &old_nullable_value));
136 EXPECT_FALSE(area->RemoveItem(kKey, &old_value));
137 EXPECT_FALSE(area->Clear());
140 TEST_F(DOMStorageAreaTest, BackingDatabaseOpened) {
141 const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1;
142 base::ScopedTempDir temp_dir;
143 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
144 const base::FilePath kExpectedOriginFilePath = temp_dir.path().Append(
145 DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin));
147 // No directory, backing should be null.
149 scoped_refptr<DOMStorageArea> area(
150 new DOMStorageArea(kOrigin, base::FilePath(), NULL));
151 EXPECT_EQ(NULL, area->backing_.get());
152 EXPECT_TRUE(area->is_initial_import_done_);
153 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
156 // Valid directory and origin but no session storage backing. Backing should
157 // be null.
159 scoped_refptr<DOMStorageArea> area(
160 new DOMStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
161 NULL, NULL));
162 EXPECT_EQ(NULL, area->backing_.get());
163 EXPECT_TRUE(area->is_initial_import_done_);
165 base::NullableString16 old_value;
166 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
167 ASSERT_TRUE(old_value.is_null());
169 // Check that saving a value has still left us without a backing database.
170 EXPECT_EQ(NULL, area->backing_.get());
171 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
174 // This should set up a DOMStorageArea that is correctly backed to disk.
176 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
177 kOrigin,
178 temp_dir.path(),
179 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
181 EXPECT_TRUE(area->backing_.get());
182 DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
183 area->backing_.get())->db_.get();
184 EXPECT_FALSE(database->IsOpen());
185 EXPECT_FALSE(area->is_initial_import_done_);
187 // Inject an in-memory db to speed up the test.
188 // We will verify that something is written into the database but not
189 // that a file is written to disk - DOMStorageDatabase unit tests cover
190 // that.
191 area->backing_.reset(new LocalStorageDatabaseAdapter());
193 // Need to write something to ensure that the database is created.
194 base::NullableString16 old_value;
195 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
196 ASSERT_TRUE(old_value.is_null());
197 EXPECT_TRUE(area->is_initial_import_done_);
198 EXPECT_TRUE(area->commit_batch_.get());
199 EXPECT_EQ(0, area->commit_batches_in_flight_);
201 base::MessageLoop::current()->RunUntilIdle();
203 EXPECT_FALSE(area->commit_batch_.get());
204 EXPECT_EQ(0, area->commit_batches_in_flight_);
205 database = static_cast<LocalStorageDatabaseAdapter*>(
206 area->backing_.get())->db_.get();
207 EXPECT_TRUE(database->IsOpen());
208 EXPECT_EQ(1u, area->Length());
209 EXPECT_EQ(kValue, area->GetItem(kKey).string());
211 // Verify the content made it to the in memory database.
212 DOMStorageValuesMap values;
213 area->backing_->ReadAllValues(&values);
214 EXPECT_EQ(1u, values.size());
215 EXPECT_EQ(kValue, values[kKey].string());
219 TEST_F(DOMStorageAreaTest, CommitTasks) {
220 base::ScopedTempDir temp_dir;
221 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
223 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
224 kOrigin,
225 temp_dir.path(),
226 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
227 // Inject an in-memory db to speed up the test.
228 area->backing_.reset(new LocalStorageDatabaseAdapter());
230 // Unrelated to commits, but while we're here, see that querying Length()
231 // causes the backing database to be opened and presumably read from.
232 EXPECT_FALSE(area->is_initial_import_done_);
233 EXPECT_EQ(0u, area->Length());
234 EXPECT_TRUE(area->is_initial_import_done_);
236 DOMStorageValuesMap values;
237 base::NullableString16 old_value;
239 // See that changes are batched up.
240 EXPECT_FALSE(area->commit_batch_.get());
241 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
242 EXPECT_TRUE(area->HasUncommittedChanges());
243 EXPECT_TRUE(area->commit_batch_.get());
244 EXPECT_FALSE(area->commit_batch_->clear_all_first);
245 EXPECT_EQ(1u, area->commit_batch_->changed_values.size());
246 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
247 EXPECT_TRUE(area->commit_batch_.get());
248 EXPECT_FALSE(area->commit_batch_->clear_all_first);
249 EXPECT_EQ(2u, area->commit_batch_->changed_values.size());
250 base::MessageLoop::current()->RunUntilIdle();
251 EXPECT_FALSE(area->HasUncommittedChanges());
252 EXPECT_FALSE(area->commit_batch_.get());
253 EXPECT_EQ(0, area->commit_batches_in_flight_);
254 // Verify the changes made it to the database.
255 values.clear();
256 area->backing_->ReadAllValues(&values);
257 EXPECT_EQ(2u, values.size());
258 EXPECT_EQ(kValue, values[kKey].string());
259 EXPECT_EQ(kValue2, values[kKey2].string());
261 // See that clear is handled properly.
262 EXPECT_TRUE(area->Clear());
263 EXPECT_TRUE(area->commit_batch_.get());
264 EXPECT_TRUE(area->commit_batch_->clear_all_first);
265 EXPECT_TRUE(area->commit_batch_->changed_values.empty());
266 base::MessageLoop::current()->RunUntilIdle();
267 EXPECT_FALSE(area->commit_batch_.get());
268 EXPECT_EQ(0, area->commit_batches_in_flight_);
269 // Verify the changes made it to the database.
270 values.clear();
271 area->backing_->ReadAllValues(&values);
272 EXPECT_TRUE(values.empty());
274 // See that if changes accrue while a commit is "in flight"
275 // those will also get committed.
276 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
277 EXPECT_TRUE(area->HasUncommittedChanges());
278 // At this point the StartCommitTimer task has been posted to the after
279 // startup task queue. We inject another task in the queue that will
280 // execute when the CommitChanges task is inflight. From within our
281 // injected task, we'll make an additional SetItem() call and verify
282 // that a new commit batch is created for that additional change.
283 BrowserThread::PostAfterStartupTask(
284 FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
285 base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask1,
286 base::Unretained(this),
287 area));
288 base::MessageLoop::current()->RunUntilIdle();
289 EXPECT_TRUE(area->HasOneRef());
290 EXPECT_FALSE(area->HasUncommittedChanges());
291 // Verify the changes made it to the database.
292 values.clear();
293 area->backing_->ReadAllValues(&values);
294 EXPECT_EQ(2u, values.size());
295 EXPECT_EQ(kValue, values[kKey].string());
296 EXPECT_EQ(kValue2, values[kKey2].string());
299 TEST_F(DOMStorageAreaTest, CommitChangesAtShutdown) {
300 base::ScopedTempDir temp_dir;
301 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
302 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
303 kOrigin,
304 temp_dir.path(),
305 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
307 // Inject an in-memory db to speed up the test and also to verify
308 // the final changes are commited in it's dtor.
309 static_cast<LocalStorageDatabaseAdapter*>(area->backing_.get())->db_.reset(
310 new VerifyChangesCommittedDatabase());
312 DOMStorageValuesMap values;
313 base::NullableString16 old_value;
314 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
315 EXPECT_TRUE(area->HasUncommittedChanges());
316 area->backing_->ReadAllValues(&values);
317 EXPECT_TRUE(values.empty()); // not committed yet
318 area->Shutdown();
319 base::MessageLoop::current()->RunUntilIdle();
320 EXPECT_TRUE(area->HasOneRef());
321 EXPECT_FALSE(area->backing_.get());
322 // The VerifyChangesCommittedDatabase destructor verifies values
323 // were committed.
326 TEST_F(DOMStorageAreaTest, DeleteOrigin) {
327 base::ScopedTempDir temp_dir;
328 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
329 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
330 kOrigin,
331 temp_dir.path(),
332 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
334 // This test puts files on disk.
335 base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
336 area->backing_.get())->db_->file_path();
337 base::FilePath db_journal_file_path =
338 DOMStorageDatabase::GetJournalFilePath(db_file_path);
340 // Nothing bad should happen when invoked w/o any files on disk.
341 area->DeleteOrigin();
342 EXPECT_FALSE(base::PathExists(db_file_path));
344 // Commit something in the database and then delete.
345 base::NullableString16 old_value;
346 area->SetItem(kKey, kValue, &old_value);
347 base::MessageLoop::current()->RunUntilIdle();
348 EXPECT_TRUE(base::PathExists(db_file_path));
349 area->DeleteOrigin();
350 EXPECT_EQ(0u, area->Length());
351 EXPECT_FALSE(base::PathExists(db_file_path));
352 EXPECT_FALSE(base::PathExists(db_journal_file_path));
354 // Put some uncommitted changes to a non-existing database in
355 // and then delete. No file ever gets created in this case.
356 area->SetItem(kKey, kValue, &old_value);
357 EXPECT_TRUE(area->HasUncommittedChanges());
358 EXPECT_EQ(1u, area->Length());
359 area->DeleteOrigin();
360 EXPECT_TRUE(area->HasUncommittedChanges());
361 EXPECT_EQ(0u, area->Length());
362 base::MessageLoop::current()->RunUntilIdle();
363 EXPECT_FALSE(area->HasUncommittedChanges());
364 EXPECT_FALSE(base::PathExists(db_file_path));
366 // Put some uncommitted changes to a an existing database in
367 // and then delete.
368 area->SetItem(kKey, kValue, &old_value);
369 base::MessageLoop::current()->RunUntilIdle();
370 EXPECT_TRUE(base::PathExists(db_file_path));
371 area->SetItem(kKey2, kValue2, &old_value);
372 EXPECT_TRUE(area->HasUncommittedChanges());
373 EXPECT_EQ(2u, area->Length());
374 area->DeleteOrigin();
375 EXPECT_TRUE(area->HasUncommittedChanges());
376 EXPECT_EQ(0u, area->Length());
377 base::MessageLoop::current()->RunUntilIdle();
378 EXPECT_FALSE(area->HasUncommittedChanges());
379 // Since the area had uncommitted changes at the time delete
380 // was called, the file will linger until the shutdown time.
381 EXPECT_TRUE(base::PathExists(db_file_path));
382 area->Shutdown();
383 base::MessageLoop::current()->RunUntilIdle();
384 EXPECT_FALSE(base::PathExists(db_file_path));
387 TEST_F(DOMStorageAreaTest, PurgeMemory) {
388 base::ScopedTempDir temp_dir;
389 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
390 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
391 kOrigin,
392 temp_dir.path(),
393 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
395 // Inject an in-memory db to speed up the test.
396 area->backing_.reset(new LocalStorageDatabaseAdapter());
398 // Unowned ptrs we use to verify that 'purge' has happened.
399 DOMStorageDatabase* original_backing =
400 static_cast<LocalStorageDatabaseAdapter*>(
401 area->backing_.get())->db_.get();
402 DOMStorageMap* original_map = area->map_.get();
404 // Should do no harm when called on a newly constructed object.
405 EXPECT_FALSE(area->is_initial_import_done_);
406 area->PurgeMemory();
407 EXPECT_FALSE(area->is_initial_import_done_);
408 DOMStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
409 area->backing_.get())->db_.get();
410 EXPECT_EQ(original_backing, new_backing);
411 EXPECT_EQ(original_map, area->map_.get());
413 // Should not do anything when commits are pending.
414 base::NullableString16 old_value;
415 area->SetItem(kKey, kValue, &old_value);
416 EXPECT_TRUE(area->is_initial_import_done_);
417 EXPECT_TRUE(area->HasUncommittedChanges());
418 area->PurgeMemory();
419 EXPECT_TRUE(area->is_initial_import_done_);
420 EXPECT_TRUE(area->HasUncommittedChanges());
421 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
422 area->backing_.get())->db_.get();
423 EXPECT_EQ(original_backing, new_backing);
424 EXPECT_EQ(original_map, area->map_.get());
426 // Commit the changes from above,
427 base::MessageLoop::current()->RunUntilIdle();
428 EXPECT_FALSE(area->HasUncommittedChanges());
429 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
430 area->backing_.get())->db_.get();
431 EXPECT_EQ(original_backing, new_backing);
432 EXPECT_EQ(original_map, area->map_.get());
434 // Should drop caches and reset database connections
435 // when invoked on an area that's loaded up primed.
436 area->PurgeMemory();
437 EXPECT_FALSE(area->is_initial_import_done_);
438 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
439 area->backing_.get())->db_.get();
440 EXPECT_NE(original_backing, new_backing);
441 EXPECT_NE(original_map, area->map_.get());
444 TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
445 struct {
446 const char* origin;
447 const char* file_name;
448 const char* journal_file_name;
449 } kCases[] = {
450 { "https://www.google.com/",
451 "https_www.google.com_0.localstorage",
452 "https_www.google.com_0.localstorage-journal" },
453 { "http://www.google.com:8080/",
454 "http_www.google.com_8080.localstorage",
455 "http_www.google.com_8080.localstorage-journal" },
456 { "file:///",
457 "file__0.localstorage",
458 "file__0.localstorage-journal" },
461 for (size_t i = 0; i < arraysize(kCases); ++i) {
462 GURL origin = GURL(kCases[i].origin).GetOrigin();
463 base::FilePath file_name =
464 base::FilePath().AppendASCII(kCases[i].file_name);
465 base::FilePath journal_file_name =
466 base::FilePath().AppendASCII(kCases[i].journal_file_name);
468 EXPECT_EQ(file_name,
469 DOMStorageArea::DatabaseFileNameFromOrigin(origin));
470 EXPECT_EQ(origin,
471 DOMStorageArea::OriginFromDatabaseFileName(file_name));
472 EXPECT_EQ(journal_file_name,
473 DOMStorageDatabase::GetJournalFilePath(file_name));
476 // Also test some DOMStorageDatabase::GetJournalFilePath cases here.
477 base::FilePath parent = base::FilePath().AppendASCII("a").AppendASCII("b");
478 EXPECT_EQ(
479 parent.AppendASCII("file-journal"),
480 DOMStorageDatabase::GetJournalFilePath(parent.AppendASCII("file")));
481 EXPECT_EQ(
482 base::FilePath().AppendASCII("-journal"),
483 DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
484 EXPECT_EQ(
485 base::FilePath().AppendASCII(".extensiononly-journal"),
486 DOMStorageDatabase::GetJournalFilePath(
487 base::FilePath().AppendASCII(".extensiononly")));
490 TEST_F(DOMStorageAreaTest, RateLimiter) {
491 // Limit to 1000 samples per second
492 DOMStorageArea::RateLimiter rate_limiter(
493 1000, base::TimeDelta::FromSeconds(1));
495 // No samples have been added so no time/delay should be needed.
496 EXPECT_EQ(base::TimeDelta(),
497 rate_limiter.ComputeTimeNeeded());
498 EXPECT_EQ(base::TimeDelta(),
499 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
500 EXPECT_EQ(base::TimeDelta(),
501 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromDays(1)));
503 // Add a seconds worth of samples.
504 rate_limiter.add_samples(1000);
505 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
506 rate_limiter.ComputeTimeNeeded());
507 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
508 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
509 EXPECT_EQ(base::TimeDelta(),
510 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
511 EXPECT_EQ(base::TimeDelta::FromMilliseconds(250),
512 rate_limiter.ComputeDelayNeeded(
513 base::TimeDelta::FromMilliseconds(750)));
514 EXPECT_EQ(base::TimeDelta(),
515 rate_limiter.ComputeDelayNeeded(
516 base::TimeDelta::FromDays(1)));
518 // And another half seconds worth.
519 rate_limiter.add_samples(500);
520 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
521 rate_limiter.ComputeTimeNeeded());
522 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
523 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
524 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
525 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
526 EXPECT_EQ(base::TimeDelta::FromMilliseconds(750),
527 rate_limiter.ComputeDelayNeeded(
528 base::TimeDelta::FromMilliseconds(750)));
529 EXPECT_EQ(base::TimeDelta(),
530 rate_limiter.ComputeDelayNeeded(
531 base::TimeDelta::FromMilliseconds(1500)));
532 EXPECT_EQ(base::TimeDelta(),
533 rate_limiter.ComputeDelayNeeded(
534 base::TimeDelta::FromDays(1)));
537 } // namespace content