Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / dom_storage / dom_storage_area_unittest.cc
blob1115590996b515bab42baf391acafcefc4c60dea
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/message_loop/message_loop_proxy.h"
10 #include "base/strings/utf_string_conversions.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 "testing/gtest/include/gtest/gtest.h"
21 using base::ASCIIToUTF16;
23 namespace content {
25 class DOMStorageAreaTest : public testing::Test {
26 public:
27 DOMStorageAreaTest()
28 : kOrigin(GURL("http://dom_storage/")),
29 kKey(ASCIIToUTF16("key")),
30 kValue(ASCIIToUTF16("value")),
31 kKey2(ASCIIToUTF16("key2")),
32 kValue2(ASCIIToUTF16("value2")) {
35 const GURL kOrigin;
36 const base::string16 kKey;
37 const base::string16 kValue;
38 const base::string16 kKey2;
39 const base::string16 kValue2;
41 // Method used in the CommitTasks test case.
42 void InjectedCommitSequencingTask(DOMStorageArea* area) {
43 // At this point the OnCommitTimer has run.
44 // Verify that it put a commit in flight.
45 EXPECT_EQ(1, area->commit_batches_in_flight_);
46 EXPECT_FALSE(area->commit_batch_.get());
47 EXPECT_TRUE(area->HasUncommittedChanges());
48 // Make additional change and verify that a new commit batch
49 // is created for that change.
50 base::NullableString16 old_value;
51 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
52 EXPECT_TRUE(area->commit_batch_.get());
53 EXPECT_EQ(1, area->commit_batches_in_flight_);
54 EXPECT_TRUE(area->HasUncommittedChanges());
57 // Class used in the CommitChangesAtShutdown test case.
58 class VerifyChangesCommittedDatabase : public DOMStorageDatabase {
59 public:
60 VerifyChangesCommittedDatabase() {}
61 ~VerifyChangesCommittedDatabase() override {
62 const base::string16 kKey(ASCIIToUTF16("key"));
63 const base::string16 kValue(ASCIIToUTF16("value"));
64 DOMStorageValuesMap values;
65 ReadAllValues(&values);
66 EXPECT_EQ(1u, values.size());
67 EXPECT_EQ(kValue, values[kKey].string());
71 private:
72 base::MessageLoop message_loop_;
75 TEST_F(DOMStorageAreaTest, DOMStorageAreaBasics) {
76 scoped_refptr<DOMStorageArea> area(
77 new DOMStorageArea(1, std::string(), kOrigin, NULL, NULL));
78 base::string16 old_value;
79 base::NullableString16 old_nullable_value;
80 scoped_refptr<DOMStorageArea> copy;
82 // We don't focus on the underlying DOMStorageMap functionality
83 // since that's covered by seperate unit tests.
84 EXPECT_EQ(kOrigin, area->origin());
85 EXPECT_EQ(1, area->namespace_id());
86 EXPECT_EQ(0u, area->Length());
87 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
88 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_nullable_value));
89 EXPECT_FALSE(area->HasUncommittedChanges());
91 // Verify that a copy shares the same map.
92 copy = area->ShallowCopy(2, std::string());
93 EXPECT_EQ(kOrigin, copy->origin());
94 EXPECT_EQ(2, copy->namespace_id());
95 EXPECT_EQ(area->Length(), copy->Length());
96 EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string());
97 EXPECT_EQ(area->Key(0).string(), copy->Key(0).string());
98 EXPECT_EQ(copy->map_.get(), area->map_.get());
100 // But will deep copy-on-write as needed.
101 EXPECT_TRUE(area->RemoveItem(kKey, &old_value));
102 EXPECT_NE(copy->map_.get(), area->map_.get());
103 copy = area->ShallowCopy(2, std::string());
104 EXPECT_EQ(copy->map_.get(), area->map_.get());
105 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
106 EXPECT_NE(copy->map_.get(), area->map_.get());
107 copy = area->ShallowCopy(2, std::string());
108 EXPECT_EQ(copy->map_.get(), area->map_.get());
109 EXPECT_NE(0u, area->Length());
110 EXPECT_TRUE(area->Clear());
111 EXPECT_EQ(0u, area->Length());
112 EXPECT_NE(copy->map_.get(), area->map_.get());
114 // Verify that once Shutdown(), behaves that way.
115 area->Shutdown();
116 EXPECT_TRUE(area->is_shutdown_);
117 EXPECT_FALSE(area->map_.get());
118 EXPECT_EQ(0u, area->Length());
119 EXPECT_TRUE(area->Key(0).is_null());
120 EXPECT_TRUE(area->GetItem(kKey).is_null());
121 EXPECT_FALSE(area->SetItem(kKey, kValue, &old_nullable_value));
122 EXPECT_FALSE(area->RemoveItem(kKey, &old_value));
123 EXPECT_FALSE(area->Clear());
126 TEST_F(DOMStorageAreaTest, BackingDatabaseOpened) {
127 const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1;
128 base::ScopedTempDir temp_dir;
129 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
130 const base::FilePath kExpectedOriginFilePath = temp_dir.path().Append(
131 DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin));
133 // No directory, backing should be null.
135 scoped_refptr<DOMStorageArea> area(
136 new DOMStorageArea(kOrigin, base::FilePath(), NULL));
137 EXPECT_EQ(NULL, area->backing_.get());
138 EXPECT_TRUE(area->is_initial_import_done_);
139 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
142 // Valid directory and origin but no session storage backing. Backing should
143 // be null.
145 scoped_refptr<DOMStorageArea> area(
146 new DOMStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
147 NULL, NULL));
148 EXPECT_EQ(NULL, area->backing_.get());
149 EXPECT_TRUE(area->is_initial_import_done_);
151 base::NullableString16 old_value;
152 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
153 ASSERT_TRUE(old_value.is_null());
155 // Check that saving a value has still left us without a backing database.
156 EXPECT_EQ(NULL, area->backing_.get());
157 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
160 // This should set up a DOMStorageArea that is correctly backed to disk.
162 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
163 kOrigin,
164 temp_dir.path(),
165 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
167 EXPECT_TRUE(area->backing_.get());
168 DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
169 area->backing_.get())->db_.get();
170 EXPECT_FALSE(database->IsOpen());
171 EXPECT_FALSE(area->is_initial_import_done_);
173 // Inject an in-memory db to speed up the test.
174 // We will verify that something is written into the database but not
175 // that a file is written to disk - DOMStorageDatabase unit tests cover
176 // that.
177 area->backing_.reset(new LocalStorageDatabaseAdapter());
179 // Need to write something to ensure that the database is created.
180 base::NullableString16 old_value;
181 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
182 ASSERT_TRUE(old_value.is_null());
183 EXPECT_TRUE(area->is_initial_import_done_);
184 EXPECT_TRUE(area->commit_batch_.get());
185 EXPECT_EQ(0, area->commit_batches_in_flight_);
187 base::MessageLoop::current()->RunUntilIdle();
189 EXPECT_FALSE(area->commit_batch_.get());
190 EXPECT_EQ(0, area->commit_batches_in_flight_);
191 database = static_cast<LocalStorageDatabaseAdapter*>(
192 area->backing_.get())->db_.get();
193 EXPECT_TRUE(database->IsOpen());
194 EXPECT_EQ(1u, area->Length());
195 EXPECT_EQ(kValue, area->GetItem(kKey).string());
197 // Verify the content made it to the in memory database.
198 DOMStorageValuesMap values;
199 area->backing_->ReadAllValues(&values);
200 EXPECT_EQ(1u, values.size());
201 EXPECT_EQ(kValue, values[kKey].string());
205 TEST_F(DOMStorageAreaTest, CommitTasks) {
206 base::ScopedTempDir temp_dir;
207 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
209 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
210 kOrigin,
211 temp_dir.path(),
212 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
213 // Inject an in-memory db to speed up the test.
214 area->backing_.reset(new LocalStorageDatabaseAdapter());
216 // Unrelated to commits, but while we're here, see that querying Length()
217 // causes the backing database to be opened and presumably read from.
218 EXPECT_FALSE(area->is_initial_import_done_);
219 EXPECT_EQ(0u, area->Length());
220 EXPECT_TRUE(area->is_initial_import_done_);
222 DOMStorageValuesMap values;
223 base::NullableString16 old_value;
225 // See that changes are batched up.
226 EXPECT_FALSE(area->commit_batch_.get());
227 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
228 EXPECT_TRUE(area->HasUncommittedChanges());
229 EXPECT_TRUE(area->commit_batch_.get());
230 EXPECT_FALSE(area->commit_batch_->clear_all_first);
231 EXPECT_EQ(1u, area->commit_batch_->changed_values.size());
232 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
233 EXPECT_TRUE(area->commit_batch_.get());
234 EXPECT_FALSE(area->commit_batch_->clear_all_first);
235 EXPECT_EQ(2u, area->commit_batch_->changed_values.size());
236 base::MessageLoop::current()->RunUntilIdle();
237 EXPECT_FALSE(area->HasUncommittedChanges());
238 EXPECT_FALSE(area->commit_batch_.get());
239 EXPECT_EQ(0, area->commit_batches_in_flight_);
240 // Verify the changes made it to the database.
241 values.clear();
242 area->backing_->ReadAllValues(&values);
243 EXPECT_EQ(2u, values.size());
244 EXPECT_EQ(kValue, values[kKey].string());
245 EXPECT_EQ(kValue2, values[kKey2].string());
247 // See that clear is handled properly.
248 EXPECT_TRUE(area->Clear());
249 EXPECT_TRUE(area->commit_batch_.get());
250 EXPECT_TRUE(area->commit_batch_->clear_all_first);
251 EXPECT_TRUE(area->commit_batch_->changed_values.empty());
252 base::MessageLoop::current()->RunUntilIdle();
253 EXPECT_FALSE(area->commit_batch_.get());
254 EXPECT_EQ(0, area->commit_batches_in_flight_);
255 // Verify the changes made it to the database.
256 values.clear();
257 area->backing_->ReadAllValues(&values);
258 EXPECT_TRUE(values.empty());
260 // See that if changes accrue while a commit is "in flight"
261 // those will also get committed.
262 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
263 EXPECT_TRUE(area->HasUncommittedChanges());
264 // At this point the OnCommitTimer task has been posted. We inject
265 // another task in the queue that will execute after the timer task,
266 // but before the CommitChanges task. From within our injected task,
267 // we'll make an additional SetItem() call.
268 base::MessageLoop::current()->PostTask(
269 FROM_HERE,
270 base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask,
271 base::Unretained(this),
272 area));
273 base::MessageLoop::current()->RunUntilIdle();
274 EXPECT_TRUE(area->HasOneRef());
275 EXPECT_FALSE(area->HasUncommittedChanges());
276 // Verify the changes made it to the database.
277 values.clear();
278 area->backing_->ReadAllValues(&values);
279 EXPECT_EQ(2u, values.size());
280 EXPECT_EQ(kValue, values[kKey].string());
281 EXPECT_EQ(kValue2, values[kKey2].string());
284 TEST_F(DOMStorageAreaTest, CommitChangesAtShutdown) {
285 base::ScopedTempDir temp_dir;
286 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
287 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
288 kOrigin,
289 temp_dir.path(),
290 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
292 // Inject an in-memory db to speed up the test and also to verify
293 // the final changes are commited in it's dtor.
294 static_cast<LocalStorageDatabaseAdapter*>(area->backing_.get())->db_.reset(
295 new VerifyChangesCommittedDatabase());
297 DOMStorageValuesMap values;
298 base::NullableString16 old_value;
299 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
300 EXPECT_TRUE(area->HasUncommittedChanges());
301 area->backing_->ReadAllValues(&values);
302 EXPECT_TRUE(values.empty()); // not committed yet
303 area->Shutdown();
304 base::MessageLoop::current()->RunUntilIdle();
305 EXPECT_TRUE(area->HasOneRef());
306 EXPECT_FALSE(area->backing_.get());
307 // The VerifyChangesCommittedDatabase destructor verifies values
308 // were committed.
311 TEST_F(DOMStorageAreaTest, DeleteOrigin) {
312 base::ScopedTempDir temp_dir;
313 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
314 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
315 kOrigin,
316 temp_dir.path(),
317 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
319 // This test puts files on disk.
320 base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
321 area->backing_.get())->db_->file_path();
322 base::FilePath db_journal_file_path =
323 DOMStorageDatabase::GetJournalFilePath(db_file_path);
325 // Nothing bad should happen when invoked w/o any files on disk.
326 area->DeleteOrigin();
327 EXPECT_FALSE(base::PathExists(db_file_path));
329 // Commit something in the database and then delete.
330 base::NullableString16 old_value;
331 area->SetItem(kKey, kValue, &old_value);
332 base::MessageLoop::current()->RunUntilIdle();
333 EXPECT_TRUE(base::PathExists(db_file_path));
334 area->DeleteOrigin();
335 EXPECT_EQ(0u, area->Length());
336 EXPECT_FALSE(base::PathExists(db_file_path));
337 EXPECT_FALSE(base::PathExists(db_journal_file_path));
339 // Put some uncommitted changes to a non-existing database in
340 // and then delete. No file ever gets created in this case.
341 area->SetItem(kKey, kValue, &old_value);
342 EXPECT_TRUE(area->HasUncommittedChanges());
343 EXPECT_EQ(1u, area->Length());
344 area->DeleteOrigin();
345 EXPECT_TRUE(area->HasUncommittedChanges());
346 EXPECT_EQ(0u, area->Length());
347 base::MessageLoop::current()->RunUntilIdle();
348 EXPECT_FALSE(area->HasUncommittedChanges());
349 EXPECT_FALSE(base::PathExists(db_file_path));
351 // Put some uncommitted changes to a an existing database in
352 // and then delete.
353 area->SetItem(kKey, kValue, &old_value);
354 base::MessageLoop::current()->RunUntilIdle();
355 EXPECT_TRUE(base::PathExists(db_file_path));
356 area->SetItem(kKey2, kValue2, &old_value);
357 EXPECT_TRUE(area->HasUncommittedChanges());
358 EXPECT_EQ(2u, 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 // Since the area had uncommitted changes at the time delete
365 // was called, the file will linger until the shutdown time.
366 EXPECT_TRUE(base::PathExists(db_file_path));
367 area->Shutdown();
368 base::MessageLoop::current()->RunUntilIdle();
369 EXPECT_FALSE(base::PathExists(db_file_path));
372 TEST_F(DOMStorageAreaTest, PurgeMemory) {
373 base::ScopedTempDir temp_dir;
374 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
375 scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
376 kOrigin,
377 temp_dir.path(),
378 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
380 // Inject an in-memory db to speed up the test.
381 area->backing_.reset(new LocalStorageDatabaseAdapter());
383 // Unowned ptrs we use to verify that 'purge' has happened.
384 DOMStorageDatabase* original_backing =
385 static_cast<LocalStorageDatabaseAdapter*>(
386 area->backing_.get())->db_.get();
387 DOMStorageMap* original_map = area->map_.get();
389 // Should do no harm when called on a newly constructed object.
390 EXPECT_FALSE(area->is_initial_import_done_);
391 area->PurgeMemory();
392 EXPECT_FALSE(area->is_initial_import_done_);
393 DOMStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
394 area->backing_.get())->db_.get();
395 EXPECT_EQ(original_backing, new_backing);
396 EXPECT_EQ(original_map, area->map_.get());
398 // Should not do anything when commits are pending.
399 base::NullableString16 old_value;
400 area->SetItem(kKey, kValue, &old_value);
401 EXPECT_TRUE(area->is_initial_import_done_);
402 EXPECT_TRUE(area->HasUncommittedChanges());
403 area->PurgeMemory();
404 EXPECT_TRUE(area->is_initial_import_done_);
405 EXPECT_TRUE(area->HasUncommittedChanges());
406 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
407 area->backing_.get())->db_.get();
408 EXPECT_EQ(original_backing, new_backing);
409 EXPECT_EQ(original_map, area->map_.get());
411 // Commit the changes from above,
412 base::MessageLoop::current()->RunUntilIdle();
413 EXPECT_FALSE(area->HasUncommittedChanges());
414 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
415 area->backing_.get())->db_.get();
416 EXPECT_EQ(original_backing, new_backing);
417 EXPECT_EQ(original_map, area->map_.get());
419 // Should drop caches and reset database connections
420 // when invoked on an area that's loaded up primed.
421 area->PurgeMemory();
422 EXPECT_FALSE(area->is_initial_import_done_);
423 new_backing = static_cast<LocalStorageDatabaseAdapter*>(
424 area->backing_.get())->db_.get();
425 EXPECT_NE(original_backing, new_backing);
426 EXPECT_NE(original_map, area->map_.get());
429 TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
430 struct {
431 const char* origin;
432 const char* file_name;
433 const char* journal_file_name;
434 } kCases[] = {
435 { "https://www.google.com/",
436 "https_www.google.com_0.localstorage",
437 "https_www.google.com_0.localstorage-journal" },
438 { "http://www.google.com:8080/",
439 "http_www.google.com_8080.localstorage",
440 "http_www.google.com_8080.localstorage-journal" },
441 { "file:///",
442 "file__0.localstorage",
443 "file__0.localstorage-journal" },
446 for (size_t i = 0; i < arraysize(kCases); ++i) {
447 GURL origin = GURL(kCases[i].origin).GetOrigin();
448 base::FilePath file_name =
449 base::FilePath().AppendASCII(kCases[i].file_name);
450 base::FilePath journal_file_name =
451 base::FilePath().AppendASCII(kCases[i].journal_file_name);
453 EXPECT_EQ(file_name,
454 DOMStorageArea::DatabaseFileNameFromOrigin(origin));
455 EXPECT_EQ(origin,
456 DOMStorageArea::OriginFromDatabaseFileName(file_name));
457 EXPECT_EQ(journal_file_name,
458 DOMStorageDatabase::GetJournalFilePath(file_name));
461 // Also test some DOMStorageDatabase::GetJournalFilePath cases here.
462 base::FilePath parent = base::FilePath().AppendASCII("a").AppendASCII("b");
463 EXPECT_EQ(
464 parent.AppendASCII("file-journal"),
465 DOMStorageDatabase::GetJournalFilePath(parent.AppendASCII("file")));
466 EXPECT_EQ(
467 base::FilePath().AppendASCII("-journal"),
468 DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
469 EXPECT_EQ(
470 base::FilePath().AppendASCII(".extensiononly-journal"),
471 DOMStorageDatabase::GetJournalFilePath(
472 base::FilePath().AppendASCII(".extensiononly")));
475 TEST_F(DOMStorageAreaTest, RateLimiter) {
476 // Limit to 1000 samples per second
477 DOMStorageArea::RateLimiter rate_limiter(
478 1000, base::TimeDelta::FromSeconds(1));
480 // No samples have been added so no time/delay should be needed.
481 EXPECT_EQ(base::TimeDelta(),
482 rate_limiter.ComputeTimeNeeded());
483 EXPECT_EQ(base::TimeDelta(),
484 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
485 EXPECT_EQ(base::TimeDelta(),
486 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromDays(1)));
488 // Add a seconds worth of samples.
489 rate_limiter.add_samples(1000);
490 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
491 rate_limiter.ComputeTimeNeeded());
492 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
493 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
494 EXPECT_EQ(base::TimeDelta(),
495 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
496 EXPECT_EQ(base::TimeDelta::FromMilliseconds(250),
497 rate_limiter.ComputeDelayNeeded(
498 base::TimeDelta::FromMilliseconds(750)));
499 EXPECT_EQ(base::TimeDelta(),
500 rate_limiter.ComputeDelayNeeded(
501 base::TimeDelta::FromDays(1)));
503 // And another half seconds worth.
504 rate_limiter.add_samples(500);
505 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
506 rate_limiter.ComputeTimeNeeded());
507 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
508 rate_limiter.ComputeDelayNeeded(base::TimeDelta()));
509 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
510 rate_limiter.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
511 EXPECT_EQ(base::TimeDelta::FromMilliseconds(750),
512 rate_limiter.ComputeDelayNeeded(
513 base::TimeDelta::FromMilliseconds(750)));
514 EXPECT_EQ(base::TimeDelta(),
515 rate_limiter.ComputeDelayNeeded(
516 base::TimeDelta::FromMilliseconds(1500)));
517 EXPECT_EQ(base::TimeDelta(),
518 rate_limiter.ComputeDelayNeeded(
519 base::TimeDelta::FromDays(1)));
522 } // namespace content