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/location.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "base/time/time.h"
15 #include "content/browser/dom_storage/dom_storage_area.h"
16 #include "content/browser/dom_storage/dom_storage_database.h"
17 #include "content/browser/dom_storage/dom_storage_database_adapter.h"
18 #include "content/browser/dom_storage/dom_storage_task_runner.h"
19 #include "content/browser/dom_storage/local_storage_database_adapter.h"
20 #include "content/common/dom_storage/dom_storage_types.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::ASCIIToUTF16
;
28 class DOMStorageAreaTest
: public testing::Test
{
31 : kOrigin(GURL("http://dom_storage/")),
32 kKey(ASCIIToUTF16("key")),
33 kValue(ASCIIToUTF16("value")),
34 kKey2(ASCIIToUTF16("key2")),
35 kValue2(ASCIIToUTF16("value2")) {
39 const base::string16 kKey
;
40 const base::string16 kValue
;
41 const base::string16 kKey2
;
42 const base::string16 kValue2
;
44 // Method used in the CommitTasks test case.
45 void InjectedCommitSequencingTask1(
46 const scoped_refptr
<DOMStorageArea
>& area
) {
47 // At this point the StartCommitTimer task has run and
48 // the OnCommitTimer task is queued. We want to inject after
50 base::ThreadTaskRunnerHandle::Get()->PostTask(
52 base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask2
,
53 base::Unretained(this), area
));
56 void InjectedCommitSequencingTask2(
57 const scoped_refptr
<DOMStorageArea
>& area
) {
58 // At this point the OnCommitTimer has run.
59 // Verify that it put a commit in flight.
60 EXPECT_EQ(1, area
->commit_batches_in_flight_
);
61 EXPECT_FALSE(area
->commit_batch_
.get());
62 EXPECT_TRUE(area
->HasUncommittedChanges());
63 // Make additional change and verify that a new commit batch
64 // is created for that change.
65 base::NullableString16 old_value
;
66 EXPECT_TRUE(area
->SetItem(kKey2
, kValue2
, &old_value
));
67 EXPECT_TRUE(area
->commit_batch_
.get());
68 EXPECT_EQ(1, area
->commit_batches_in_flight_
);
69 EXPECT_TRUE(area
->HasUncommittedChanges());
72 // Class used in the CommitChangesAtShutdown test case.
73 class VerifyChangesCommittedDatabase
: public DOMStorageDatabase
{
75 VerifyChangesCommittedDatabase() {}
76 ~VerifyChangesCommittedDatabase() override
{
77 const base::string16
kKey(ASCIIToUTF16("key"));
78 const base::string16
kValue(ASCIIToUTF16("value"));
79 DOMStorageValuesMap values
;
80 ReadAllValues(&values
);
81 EXPECT_EQ(1u, values
.size());
82 EXPECT_EQ(kValue
, values
[kKey
].string());
87 base::MessageLoop message_loop_
;
90 TEST_F(DOMStorageAreaTest
, DOMStorageAreaBasics
) {
91 scoped_refptr
<DOMStorageArea
> area(
92 new DOMStorageArea(1, std::string(), kOrigin
, NULL
, NULL
));
93 base::string16 old_value
;
94 base::NullableString16 old_nullable_value
;
95 scoped_refptr
<DOMStorageArea
> copy
;
97 // We don't focus on the underlying DOMStorageMap functionality
98 // since that's covered by seperate unit tests.
99 EXPECT_EQ(kOrigin
, area
->origin());
100 EXPECT_EQ(1, area
->namespace_id());
101 EXPECT_EQ(0u, area
->Length());
102 EXPECT_TRUE(area
->SetItem(kKey
, kValue
, &old_nullable_value
));
103 EXPECT_TRUE(area
->SetItem(kKey2
, kValue2
, &old_nullable_value
));
104 EXPECT_FALSE(area
->HasUncommittedChanges());
106 // Verify that a copy shares the same map.
107 copy
= area
->ShallowCopy(2, std::string());
108 EXPECT_EQ(kOrigin
, copy
->origin());
109 EXPECT_EQ(2, copy
->namespace_id());
110 EXPECT_EQ(area
->Length(), copy
->Length());
111 EXPECT_EQ(area
->GetItem(kKey
).string(), copy
->GetItem(kKey
).string());
112 EXPECT_EQ(area
->Key(0).string(), copy
->Key(0).string());
113 EXPECT_EQ(copy
->map_
.get(), area
->map_
.get());
115 // But will deep copy-on-write as needed.
116 EXPECT_TRUE(area
->RemoveItem(kKey
, &old_value
));
117 EXPECT_NE(copy
->map_
.get(), area
->map_
.get());
118 copy
= area
->ShallowCopy(2, std::string());
119 EXPECT_EQ(copy
->map_
.get(), area
->map_
.get());
120 EXPECT_TRUE(area
->SetItem(kKey
, kValue
, &old_nullable_value
));
121 EXPECT_NE(copy
->map_
.get(), area
->map_
.get());
122 copy
= area
->ShallowCopy(2, std::string());
123 EXPECT_EQ(copy
->map_
.get(), area
->map_
.get());
124 EXPECT_NE(0u, area
->Length());
125 EXPECT_TRUE(area
->Clear());
126 EXPECT_EQ(0u, area
->Length());
127 EXPECT_NE(copy
->map_
.get(), area
->map_
.get());
129 // Verify that once Shutdown(), behaves that way.
131 EXPECT_TRUE(area
->is_shutdown_
);
132 EXPECT_FALSE(area
->map_
.get());
133 EXPECT_EQ(0u, area
->Length());
134 EXPECT_TRUE(area
->Key(0).is_null());
135 EXPECT_TRUE(area
->GetItem(kKey
).is_null());
136 EXPECT_FALSE(area
->SetItem(kKey
, kValue
, &old_nullable_value
));
137 EXPECT_FALSE(area
->RemoveItem(kKey
, &old_value
));
138 EXPECT_FALSE(area
->Clear());
141 TEST_F(DOMStorageAreaTest
, BackingDatabaseOpened
) {
142 const int64 kSessionStorageNamespaceId
= kLocalStorageNamespaceId
+ 1;
143 base::ScopedTempDir temp_dir
;
144 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
145 const base::FilePath kExpectedOriginFilePath
= temp_dir
.path().Append(
146 DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin
));
148 // No directory, backing should be null.
150 scoped_refptr
<DOMStorageArea
> area(
151 new DOMStorageArea(kOrigin
, base::FilePath(), NULL
));
152 EXPECT_EQ(NULL
, area
->backing_
.get());
153 EXPECT_TRUE(area
->is_initial_import_done_
);
154 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath
));
157 // Valid directory and origin but no session storage backing. Backing should
160 scoped_refptr
<DOMStorageArea
> area(
161 new DOMStorageArea(kSessionStorageNamespaceId
, std::string(), kOrigin
,
163 EXPECT_EQ(NULL
, area
->backing_
.get());
164 EXPECT_TRUE(area
->is_initial_import_done_
);
166 base::NullableString16 old_value
;
167 EXPECT_TRUE(area
->SetItem(kKey
, kValue
, &old_value
));
168 ASSERT_TRUE(old_value
.is_null());
170 // Check that saving a value has still left us without a backing database.
171 EXPECT_EQ(NULL
, area
->backing_
.get());
172 EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath
));
175 // This should set up a DOMStorageArea that is correctly backed to disk.
177 scoped_refptr
<DOMStorageArea
> area(
178 new DOMStorageArea(kOrigin
, temp_dir
.path(),
179 new MockDOMStorageTaskRunner(
180 base::ThreadTaskRunnerHandle::Get().get())));
182 EXPECT_TRUE(area
->backing_
.get());
183 DOMStorageDatabase
* database
= static_cast<LocalStorageDatabaseAdapter
*>(
184 area
->backing_
.get())->db_
.get();
185 EXPECT_FALSE(database
->IsOpen());
186 EXPECT_FALSE(area
->is_initial_import_done_
);
188 // Inject an in-memory db to speed up the test.
189 // We will verify that something is written into the database but not
190 // that a file is written to disk - DOMStorageDatabase unit tests cover
192 area
->backing_
.reset(new LocalStorageDatabaseAdapter());
194 // Need to write something to ensure that the database is created.
195 base::NullableString16 old_value
;
196 EXPECT_TRUE(area
->SetItem(kKey
, kValue
, &old_value
));
197 ASSERT_TRUE(old_value
.is_null());
198 EXPECT_TRUE(area
->is_initial_import_done_
);
199 EXPECT_TRUE(area
->commit_batch_
.get());
200 EXPECT_EQ(0, area
->commit_batches_in_flight_
);
202 base::MessageLoop::current()->RunUntilIdle();
204 EXPECT_FALSE(area
->commit_batch_
.get());
205 EXPECT_EQ(0, area
->commit_batches_in_flight_
);
206 database
= static_cast<LocalStorageDatabaseAdapter
*>(
207 area
->backing_
.get())->db_
.get();
208 EXPECT_TRUE(database
->IsOpen());
209 EXPECT_EQ(1u, area
->Length());
210 EXPECT_EQ(kValue
, area
->GetItem(kKey
).string());
212 // Verify the content made it to the in memory database.
213 DOMStorageValuesMap values
;
214 area
->backing_
->ReadAllValues(&values
);
215 EXPECT_EQ(1u, values
.size());
216 EXPECT_EQ(kValue
, values
[kKey
].string());
220 TEST_F(DOMStorageAreaTest
, CommitTasks
) {
221 base::ScopedTempDir temp_dir
;
222 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
224 scoped_refptr
<DOMStorageArea
> area(new DOMStorageArea(
225 kOrigin
, temp_dir
.path(),
226 new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().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(
303 kOrigin
, temp_dir
.path(),
304 new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
306 // Inject an in-memory db to speed up the test and also to verify
307 // the final changes are commited in it's dtor.
308 static_cast<LocalStorageDatabaseAdapter
*>(area
->backing_
.get())->db_
.reset(
309 new VerifyChangesCommittedDatabase());
311 DOMStorageValuesMap values
;
312 base::NullableString16 old_value
;
313 EXPECT_TRUE(area
->SetItem(kKey
, kValue
, &old_value
));
314 EXPECT_TRUE(area
->HasUncommittedChanges());
315 area
->backing_
->ReadAllValues(&values
);
316 EXPECT_TRUE(values
.empty()); // not committed yet
318 base::MessageLoop::current()->RunUntilIdle();
319 EXPECT_TRUE(area
->HasOneRef());
320 EXPECT_FALSE(area
->backing_
.get());
321 // The VerifyChangesCommittedDatabase destructor verifies values
325 TEST_F(DOMStorageAreaTest
, DeleteOrigin
) {
326 base::ScopedTempDir temp_dir
;
327 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
328 scoped_refptr
<DOMStorageArea
> area(new DOMStorageArea(
329 kOrigin
, temp_dir
.path(),
330 new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
332 // This test puts files on disk.
333 base::FilePath db_file_path
= static_cast<LocalStorageDatabaseAdapter
*>(
334 area
->backing_
.get())->db_
->file_path();
335 base::FilePath db_journal_file_path
=
336 DOMStorageDatabase::GetJournalFilePath(db_file_path
);
338 // Nothing bad should happen when invoked w/o any files on disk.
339 area
->DeleteOrigin();
340 EXPECT_FALSE(base::PathExists(db_file_path
));
342 // Commit something in the database and then delete.
343 base::NullableString16 old_value
;
344 area
->SetItem(kKey
, kValue
, &old_value
);
345 base::MessageLoop::current()->RunUntilIdle();
346 EXPECT_TRUE(base::PathExists(db_file_path
));
347 area
->DeleteOrigin();
348 EXPECT_EQ(0u, area
->Length());
349 EXPECT_FALSE(base::PathExists(db_file_path
));
350 EXPECT_FALSE(base::PathExists(db_journal_file_path
));
352 // Put some uncommitted changes to a non-existing database in
353 // and then delete. No file ever gets created in this case.
354 area
->SetItem(kKey
, kValue
, &old_value
);
355 EXPECT_TRUE(area
->HasUncommittedChanges());
356 EXPECT_EQ(1u, area
->Length());
357 area
->DeleteOrigin();
358 EXPECT_TRUE(area
->HasUncommittedChanges());
359 EXPECT_EQ(0u, area
->Length());
360 base::MessageLoop::current()->RunUntilIdle();
361 EXPECT_FALSE(area
->HasUncommittedChanges());
362 EXPECT_FALSE(base::PathExists(db_file_path
));
364 // Put some uncommitted changes to a an existing database in
366 area
->SetItem(kKey
, kValue
, &old_value
);
367 base::MessageLoop::current()->RunUntilIdle();
368 EXPECT_TRUE(base::PathExists(db_file_path
));
369 area
->SetItem(kKey2
, kValue2
, &old_value
);
370 EXPECT_TRUE(area
->HasUncommittedChanges());
371 EXPECT_EQ(2u, area
->Length());
372 area
->DeleteOrigin();
373 EXPECT_TRUE(area
->HasUncommittedChanges());
374 EXPECT_EQ(0u, area
->Length());
375 base::MessageLoop::current()->RunUntilIdle();
376 EXPECT_FALSE(area
->HasUncommittedChanges());
377 // Since the area had uncommitted changes at the time delete
378 // was called, the file will linger until the shutdown time.
379 EXPECT_TRUE(base::PathExists(db_file_path
));
381 base::MessageLoop::current()->RunUntilIdle();
382 EXPECT_FALSE(base::PathExists(db_file_path
));
385 TEST_F(DOMStorageAreaTest
, PurgeMemory
) {
386 base::ScopedTempDir temp_dir
;
387 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
388 scoped_refptr
<DOMStorageArea
> area(new DOMStorageArea(
389 kOrigin
, temp_dir
.path(),
390 new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
392 // Inject an in-memory db to speed up the test.
393 area
->backing_
.reset(new LocalStorageDatabaseAdapter());
395 // Unowned ptrs we use to verify that 'purge' has happened.
396 DOMStorageDatabase
* original_backing
=
397 static_cast<LocalStorageDatabaseAdapter
*>(
398 area
->backing_
.get())->db_
.get();
399 DOMStorageMap
* original_map
= area
->map_
.get();
401 // Should do no harm when called on a newly constructed object.
402 EXPECT_FALSE(area
->is_initial_import_done_
);
404 EXPECT_FALSE(area
->is_initial_import_done_
);
405 DOMStorageDatabase
* new_backing
= static_cast<LocalStorageDatabaseAdapter
*>(
406 area
->backing_
.get())->db_
.get();
407 EXPECT_EQ(original_backing
, new_backing
);
408 EXPECT_EQ(original_map
, area
->map_
.get());
410 // Should not do anything when commits are pending.
411 base::NullableString16 old_value
;
412 area
->SetItem(kKey
, kValue
, &old_value
);
413 EXPECT_TRUE(area
->is_initial_import_done_
);
414 EXPECT_TRUE(area
->HasUncommittedChanges());
416 EXPECT_TRUE(area
->is_initial_import_done_
);
417 EXPECT_TRUE(area
->HasUncommittedChanges());
418 new_backing
= static_cast<LocalStorageDatabaseAdapter
*>(
419 area
->backing_
.get())->db_
.get();
420 EXPECT_EQ(original_backing
, new_backing
);
421 EXPECT_EQ(original_map
, area
->map_
.get());
423 // Commit the changes from above,
424 base::MessageLoop::current()->RunUntilIdle();
425 EXPECT_FALSE(area
->HasUncommittedChanges());
426 new_backing
= static_cast<LocalStorageDatabaseAdapter
*>(
427 area
->backing_
.get())->db_
.get();
428 EXPECT_EQ(original_backing
, new_backing
);
429 EXPECT_EQ(original_map
, area
->map_
.get());
431 // Should drop caches and reset database connections
432 // when invoked on an area that's loaded up primed.
434 EXPECT_FALSE(area
->is_initial_import_done_
);
435 new_backing
= static_cast<LocalStorageDatabaseAdapter
*>(
436 area
->backing_
.get())->db_
.get();
437 EXPECT_NE(original_backing
, new_backing
);
438 EXPECT_NE(original_map
, area
->map_
.get());
441 TEST_F(DOMStorageAreaTest
, DatabaseFileNames
) {
444 const char* file_name
;
445 const char* journal_file_name
;
447 { "https://www.google.com/",
448 "https_www.google.com_0.localstorage",
449 "https_www.google.com_0.localstorage-journal" },
450 { "http://www.google.com:8080/",
451 "http_www.google.com_8080.localstorage",
452 "http_www.google.com_8080.localstorage-journal" },
454 "file__0.localstorage",
455 "file__0.localstorage-journal" },
458 for (size_t i
= 0; i
< arraysize(kCases
); ++i
) {
459 GURL origin
= GURL(kCases
[i
].origin
).GetOrigin();
460 base::FilePath file_name
=
461 base::FilePath().AppendASCII(kCases
[i
].file_name
);
462 base::FilePath journal_file_name
=
463 base::FilePath().AppendASCII(kCases
[i
].journal_file_name
);
466 DOMStorageArea::DatabaseFileNameFromOrigin(origin
));
468 DOMStorageArea::OriginFromDatabaseFileName(file_name
));
469 EXPECT_EQ(journal_file_name
,
470 DOMStorageDatabase::GetJournalFilePath(file_name
));
473 // Also test some DOMStorageDatabase::GetJournalFilePath cases here.
474 base::FilePath parent
= base::FilePath().AppendASCII("a").AppendASCII("b");
476 parent
.AppendASCII("file-journal"),
477 DOMStorageDatabase::GetJournalFilePath(parent
.AppendASCII("file")));
479 base::FilePath().AppendASCII("-journal"),
480 DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
482 base::FilePath().AppendASCII(".extensiononly-journal"),
483 DOMStorageDatabase::GetJournalFilePath(
484 base::FilePath().AppendASCII(".extensiononly")));
487 TEST_F(DOMStorageAreaTest
, RateLimiter
) {
488 // Limit to 1000 samples per second
489 DOMStorageArea::RateLimiter
rate_limiter(
490 1000, base::TimeDelta::FromSeconds(1));
492 // No samples have been added so no time/delay should be needed.
493 EXPECT_EQ(base::TimeDelta(),
494 rate_limiter
.ComputeTimeNeeded());
495 EXPECT_EQ(base::TimeDelta(),
496 rate_limiter
.ComputeDelayNeeded(base::TimeDelta()));
497 EXPECT_EQ(base::TimeDelta(),
498 rate_limiter
.ComputeDelayNeeded(base::TimeDelta::FromDays(1)));
500 // Add a seconds worth of samples.
501 rate_limiter
.add_samples(1000);
502 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
503 rate_limiter
.ComputeTimeNeeded());
504 EXPECT_EQ(base::TimeDelta::FromSeconds(1),
505 rate_limiter
.ComputeDelayNeeded(base::TimeDelta()));
506 EXPECT_EQ(base::TimeDelta(),
507 rate_limiter
.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
508 EXPECT_EQ(base::TimeDelta::FromMilliseconds(250),
509 rate_limiter
.ComputeDelayNeeded(
510 base::TimeDelta::FromMilliseconds(750)));
511 EXPECT_EQ(base::TimeDelta(),
512 rate_limiter
.ComputeDelayNeeded(
513 base::TimeDelta::FromDays(1)));
515 // And another half seconds worth.
516 rate_limiter
.add_samples(500);
517 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
518 rate_limiter
.ComputeTimeNeeded());
519 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
520 rate_limiter
.ComputeDelayNeeded(base::TimeDelta()));
521 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
522 rate_limiter
.ComputeDelayNeeded(base::TimeDelta::FromSeconds(1)));
523 EXPECT_EQ(base::TimeDelta::FromMilliseconds(750),
524 rate_limiter
.ComputeDelayNeeded(
525 base::TimeDelta::FromMilliseconds(750)));
526 EXPECT_EQ(base::TimeDelta(),
527 rate_limiter
.ComputeDelayNeeded(
528 base::TimeDelta::FromMilliseconds(1500)));
529 EXPECT_EQ(base::TimeDelta(),
530 rate_limiter
.ComputeDelayNeeded(
531 base::TimeDelta::FromDays(1)));
534 } // namespace content