| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/reporting/resources/resource_interface.h" |
| |
| #include <cstdint> |
| #include <utility> |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "base/task/task_runner.h" |
| #include "base/task/thread_pool.h" |
| #include "base/test/task_environment.h" |
| #include "components/reporting/resources/disk_resource_impl.h" |
| #include "components/reporting/resources/memory_resource_impl.h" |
| #include "components/reporting/util/test_support_callbacks.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::Eq; |
| |
| namespace reporting { |
| namespace { |
| |
| class ResourceInterfaceTest |
| : public ::testing::TestWithParam<scoped_refptr<ResourceInterface>> { |
| protected: |
| void SetUp() override { |
| // Make sure parameters define reasonably large total resource size. |
| ASSERT_GE(resource_interface()->GetTotal(), 1u * 1024LLu * 1024LLu); |
| } |
| |
| scoped_refptr<ResourceInterface> resource_interface() const { |
| return GetParam(); |
| } |
| |
| void TearDown() override { |
| EXPECT_THAT(resource_interface()->GetUsed(), Eq(0u)); |
| } |
| |
| private: |
| base::test::TaskEnvironment task_environment_; |
| }; |
| |
| TEST_P(ResourceInterfaceTest, NestedReservationTest) { |
| uint64_t size = resource_interface()->GetTotal(); |
| while ((size / 2) > 0u) { |
| size /= 2; |
| EXPECT_TRUE(resource_interface()->Reserve(size)); |
| } |
| |
| for (; size < resource_interface()->GetTotal(); size *= 2) { |
| resource_interface()->Discard(size); |
| } |
| } |
| |
| TEST_P(ResourceInterfaceTest, SimultaneousReservationTest) { |
| uint64_t size = resource_interface()->GetTotal(); |
| |
| // Schedule reservations. |
| test::TestCallbackWaiter reserve_waiter; |
| while ((size / 2) > 0u) { |
| size /= 2; |
| reserve_waiter.Attach(); |
| base::ThreadPool::PostTask( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT}, |
| base::BindOnce( |
| [](size_t size, scoped_refptr<ResourceInterface> resource_interface, |
| test::TestCallbackWaiter* waiter) { |
| EXPECT_TRUE(resource_interface->Reserve(size)); |
| waiter->Signal(); |
| }, |
| size, resource_interface(), &reserve_waiter)); |
| } |
| reserve_waiter.Wait(); |
| |
| // Schedule discards. |
| test::TestCallbackWaiter discard_waiter; |
| for (; size < resource_interface()->GetTotal(); size *= 2) { |
| discard_waiter.Attach(); |
| base::ThreadPool::PostTask( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT}, |
| base::BindOnce( |
| [](size_t size, scoped_refptr<ResourceInterface> resource_interface, |
| test::TestCallbackWaiter* waiter) { |
| resource_interface->Discard(size); |
| waiter->Signal(); |
| }, |
| size, resource_interface(), &discard_waiter)); |
| } |
| discard_waiter.Wait(); |
| } |
| |
| TEST_P(ResourceInterfaceTest, SimultaneousScopedReservationTest) { |
| uint64_t size = resource_interface()->GetTotal(); |
| test::TestCallbackWaiter waiter; |
| while ((size / 2) > 0u) { |
| size /= 2; |
| waiter.Attach(); |
| base::ThreadPool::PostTask( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT}, |
| base::BindOnce( |
| [](size_t size, scoped_refptr<ResourceInterface> resource_interface, |
| test::TestCallbackWaiter* waiter) { |
| { ScopedReservation(size, resource_interface); } |
| waiter->Signal(); |
| }, |
| size, resource_interface(), &waiter)); |
| } |
| waiter.Wait(); |
| } |
| |
| TEST_P(ResourceInterfaceTest, MoveScopedReservationTest) { |
| uint64_t size = resource_interface()->GetTotal(); |
| ScopedReservation scoped_reservation(size / 2, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| { |
| ScopedReservation moved_scoped_reservation(std::move(scoped_reservation)); |
| EXPECT_TRUE(moved_scoped_reservation.reserved()); |
| EXPECT_FALSE(scoped_reservation.reserved()); |
| } |
| EXPECT_FALSE(scoped_reservation.reserved()); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationBasicReduction) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| EXPECT_TRUE(scoped_reservation.Reduce(size / 2)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationReductionWithLargerNewSize) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| EXPECT_FALSE(scoped_reservation.Reduce(size + 1)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationReductionWithNegativeNewSize) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| EXPECT_FALSE(scoped_reservation.Reduce(-(size / 2))); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationRepeatingReductions) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| |
| for (; size >= 2; size /= 2) { |
| EXPECT_TRUE(scoped_reservation.Reduce(size / 2)); |
| } |
| EXPECT_TRUE(scoped_reservation.Reduce(size / 2)); |
| EXPECT_FALSE(scoped_reservation.reserved()); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationBasicHandOver) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| ASSERT_TRUE(scoped_reservation.reserved()); |
| { |
| ScopedReservation another_reservation(size - 1, resource_interface()); |
| ASSERT_TRUE(another_reservation.reserved()); |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| EXPECT_TRUE(another_reservation.reserved()); |
| scoped_reservation.HandOver(another_reservation); |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| } |
| // Destruction of |anoter_reservation| does not change the amount used. |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationRepeatingHandOvers) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| |
| for (; size >= 2; size /= 2) { |
| ScopedReservation another_reservation(size / 2, resource_interface()); |
| scoped_reservation.HandOver(another_reservation); |
| } |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationRepeatingHandOversToEmpty) { |
| ScopedReservation scoped_reservation; |
| EXPECT_FALSE(scoped_reservation.reserved()); |
| |
| uint64_t size = resource_interface()->GetTotal(); |
| for (; size >= 2; size /= 2) { |
| ScopedReservation another_reservation(size / 2, resource_interface()); |
| scoped_reservation.HandOver(another_reservation); |
| } |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ScopedReservationEmptyHandOver) { |
| uint64_t size = resource_interface()->GetTotal() / 2; |
| ScopedReservation scoped_reservation(size, resource_interface()); |
| |
| ASSERT_TRUE(scoped_reservation.reserved()); |
| { |
| ScopedReservation another_reservation(size - 1, resource_interface()); |
| ASSERT_TRUE(another_reservation.reserved()); |
| |
| EXPECT_THAT(resource_interface()->GetUsed(), |
| Eq(resource_interface()->GetTotal() - 1)); |
| EXPECT_TRUE(scoped_reservation.reserved()); |
| EXPECT_TRUE(another_reservation.reserved()); |
| |
| another_reservation.Reduce(0); |
| ASSERT_FALSE(another_reservation.reserved()); |
| |
| scoped_reservation.HandOver(another_reservation); |
| EXPECT_THAT(resource_interface()->GetUsed(), Eq(size)); |
| } |
| // Destruction of |anoter_reservation| does not change the amount used. |
| EXPECT_THAT(resource_interface()->GetUsed(), Eq(size)); |
| } |
| |
| TEST_P(ResourceInterfaceTest, ReservationOverMaxTest) { |
| EXPECT_FALSE( |
| resource_interface()->Reserve(resource_interface()->GetTotal() + 1)); |
| EXPECT_TRUE(resource_interface()->Reserve(resource_interface()->GetTotal())); |
| resource_interface()->Discard(resource_interface()->GetTotal()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| VariousResources, |
| ResourceInterfaceTest, |
| testing::Values( |
| base::MakeRefCounted<DiskResourceImpl>(16u * 1024LLu * 1024LLu), |
| base::MakeRefCounted<MemoryResourceImpl>(4u * 1024LLu * 1024LLu))); |
| } // namespace |
| } // namespace reporting |