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.
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
;
26 class DOMStorageAreaTest
: public testing::Test
{
29 : kOrigin(GURL("http://dom_storage/")),
30 kKey(ASCIIToUTF16("key")),
31 kValue(ASCIIToUTF16("value")),
32 kKey2(ASCIIToUTF16("key2")),
33 kValue2(ASCIIToUTF16("value2")) {
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
48 base::MessageLoop::current()->PostTask(
50 base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask2
,
51 base::Unretained(this),
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
{
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());
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.
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
159 scoped_refptr
<DOMStorageArea
> area(
160 new DOMStorageArea(kSessionStorageNamespaceId
, std::string(), kOrigin
,
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(
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
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(
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.
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.
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),
288 base::MessageLoop::current()->RunUntilIdle();
289 EXPECT_TRUE(area
->HasOneRef());
290 EXPECT_FALSE(area
->HasUncommittedChanges());
291 // Verify the changes made it to the database.
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(
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
319 base::MessageLoop::current()->RunUntilIdle();
320 EXPECT_TRUE(area
->HasOneRef());
321 EXPECT_FALSE(area
->backing_
.get());
322 // The VerifyChangesCommittedDatabase destructor verifies values
326 TEST_F(DOMStorageAreaTest
, DeleteOrigin
) {
327 base::ScopedTempDir temp_dir
;
328 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
329 scoped_refptr
<DOMStorageArea
> area(new DOMStorageArea(
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
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
));
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(
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_
);
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());
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.
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
) {
447 const char* file_name
;
448 const char* journal_file_name
;
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" },
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
);
469 DOMStorageArea::DatabaseFileNameFromOrigin(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");
479 parent
.AppendASCII("file-journal"),
480 DOMStorageDatabase::GetJournalFilePath(parent
.AppendASCII("file")));
482 base::FilePath().AppendASCII("-journal"),
483 DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
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