1 //
2 // Copyright (C) 2022 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <unordered_set>
17 #include <vector>
18 
19 #include "common/libs/utils/contains.h"
20 #include "common/libs/utils/unique_resource_allocator.h"
21 #include "common/libs/utils/unique_resource_allocator_test.h"
22 
23 namespace cuttlefish {
24 
TEST_P(OneEachTest,GetAnyAvailableOne)25 TEST_P(OneEachTest, GetAnyAvailableOne) {
26   const auto resources = GetParam();
27   auto allocator = UniqueResourceAllocator<unsigned>::New(resources);
28   if (!allocator) {
29     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
30   }
31   std::unordered_set<unsigned> expected_ids{resources.cbegin(),
32                                             resources.cend()};
33   using Reservation = UniqueResourceAllocator<unsigned>::Reservation;
34 
35   std::vector<Reservation> allocated;
36   for (int i = 0; i < resources.size(); i++) {
37     auto id_opt = allocator->UniqueItem();
38     ASSERT_TRUE(id_opt);
39     ASSERT_TRUE(Contains(expected_ids, id_opt->Get()));
40     allocated.emplace_back(std::move(*id_opt));
41   }
42   ASSERT_FALSE(allocator->UniqueItem());
43 }
44 
45 INSTANTIATE_TEST_SUITE_P(
46     CvdIdAllocator, OneEachTest,
47     testing::Values(std::vector<unsigned>{}, std::vector<unsigned>{1},
48                     std::vector<unsigned>{1, 22, 3, 43, 5}));
49 
TEST_F(CvdIdAllocatorTest,ClaimAll)50 TEST_F(CvdIdAllocatorTest, ClaimAll) {
51   std::vector<unsigned> inputs{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
52   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
53   if (!allocator) {
54     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
55   }
56 
57   // request inputs.size() items
58   auto allocated_items_opt = allocator->UniqueItems(inputs.size());
59   ASSERT_TRUE(allocated_items_opt);
60   ASSERT_EQ(allocated_items_opt->size(), inputs.size());
61   // did it claim all?
62   ASSERT_FALSE(allocator->UniqueItem());
63 }
64 
TEST_F(CvdIdAllocatorTest,StrideBeyond)65 TEST_F(CvdIdAllocatorTest, StrideBeyond) {
66   std::vector<unsigned> inputs{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
67   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
68   if (!allocator) {
69     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
70   }
71 
72   auto three_opt = allocator->UniqueItems(3);
73   auto four_opt = allocator->UniqueItems(4);
74   auto five_opt = allocator->UniqueItems(5);
75   auto two_opt = allocator->UniqueItems(2);
76   auto another_two_opt = allocator->UniqueItems(2);
77 
78   ASSERT_TRUE(three_opt);
79   ASSERT_TRUE(four_opt);
80   ASSERT_FALSE(five_opt);
81   ASSERT_TRUE(two_opt);
82   ASSERT_FALSE(another_two_opt);
83 }
84 
TEST_F(CvdIdAllocatorTest,Consecutive)85 TEST_F(CvdIdAllocatorTest, Consecutive) {
86   std::vector<unsigned> inputs{1, 2, 4, 5, 6, 7, 9, 10, 11};
87   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
88   if (!allocator) {
89     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
90   }
91 
92   auto four_consecutive = allocator->UniqueConsecutiveItems(4);
93   auto three_consecutive = allocator->UniqueConsecutiveItems(3);
94   auto another_three_consecutive = allocator->UniqueConsecutiveItems(3);
95   auto two_consecutive = allocator->UniqueConsecutiveItems(2);
96 
97   ASSERT_TRUE(four_consecutive);
98   ASSERT_TRUE(three_consecutive);
99   ASSERT_FALSE(another_three_consecutive);
100   ASSERT_TRUE(two_consecutive);
101   // it's empty
102   ASSERT_FALSE(allocator->UniqueItem()) << "one or more left";
103 }
104 
TEST_F(CvdIdAllocatorTest,Take)105 TEST_F(CvdIdAllocatorTest, Take) {
106   std::vector<unsigned> inputs{4, 5, 9};
107   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
108   if (!allocator) {
109     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
110   }
111 
112   auto four = allocator->Take(4);
113   auto nine = allocator->Take(9);
114   // wrong
115   auto twenty = allocator->Take(20);
116 
117   ASSERT_TRUE(four);
118   ASSERT_TRUE(nine);
119   ASSERT_FALSE(twenty);
120 }
121 
TEST_F(CvdIdAllocatorTest,TakeAll)122 TEST_F(CvdIdAllocatorTest, TakeAll) {
123   std::vector<unsigned> inputs{4, 5, 9, 10};
124   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
125   if (!allocator) {
126     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
127   }
128 
129   auto take_4_5_11 = allocator->TakeAll<std::vector<unsigned>>({4, 5, 11});
130   auto take_4_5_10 = allocator->TakeAll<std::vector<unsigned>>({4, 5, 10});
131   auto take_9_10 = allocator->TakeAll<std::vector<unsigned>>({9, 10});
132   auto take_9 = allocator->TakeAll<std::vector<unsigned>>({9});
133 
134   ASSERT_FALSE(take_4_5_11);
135   ASSERT_TRUE(take_4_5_10);
136   ASSERT_FALSE(take_9_10);
137   ASSERT_TRUE(take_9);
138 }
139 
TEST_F(CvdIdAllocatorTest,TakeRange)140 TEST_F(CvdIdAllocatorTest, TakeRange) {
141   std::vector<unsigned> inputs{1, 2, 4, 5, 6, 7, 8, 9, 10, 11};
142   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
143   if (!allocator) {
144     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
145   }
146 
147   auto take_range_5_12 = allocator->TakeRange(5, 12);
148   // shall fail as 3 is missing
149   auto take_range_2_4 = allocator->TakeRange(2, 4);
150 
151   ASSERT_TRUE(take_range_5_12);
152   ASSERT_FALSE(take_range_2_4);
153 }
154 
TEST_F(CvdIdAllocatorTest,Reclaim)155 TEST_F(CvdIdAllocatorTest, Reclaim) {
156   std::vector<unsigned> inputs{1, 2, 4, 5, 6, 7, 8, 9, 10, 11};
157   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
158   if (!allocator) {
159     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
160   }
161   unsigned one_resource = 0;
162   {
163     auto take_range_5_12 = allocator->TakeRange(5, 12);
164     auto any_single_item = allocator->UniqueItem();
165 
166     ASSERT_TRUE(take_range_5_12);
167     ASSERT_TRUE(any_single_item);
168     one_resource = any_single_item->Get();
169 
170     ASSERT_FALSE(allocator->TakeRange(5, 12));
171     ASSERT_FALSE(allocator->Take(one_resource));
172   }
173   // take_range_5_12 went out of scope, so resources were reclaimed
174   ASSERT_TRUE(allocator->TakeRange(5, 12));
175   ASSERT_TRUE(allocator->Take(one_resource));
176 }
177 
TEST(CvdIdAllocatorExpandTest,Expand)178 TEST(CvdIdAllocatorExpandTest, Expand) {
179   std::vector<unsigned> inputs{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
180   auto allocator = UniqueResourceAllocator<unsigned>::New(inputs);
181   if (!allocator) {
182     GTEST_SKIP() << "Memory allocation failed but we aren't testing it.";
183   }
184   auto hold_6_to_10 = allocator->TakeRange(6, 11);
185   if (!hold_6_to_10) {
186     GTEST_SKIP() << "TakeRange(6, 11) failed but it's not what is tested here";
187   }
188 
189   auto expand =
190       allocator->ExpandPool(std::vector<unsigned>{2, 4, 6, 8, 12, 14});
191   auto take_12 = allocator->Take(12);
192   auto take_14 = allocator->Take(14);
193   auto take_6 = allocator->Take(6);
194 
195   std::vector<unsigned> expected_return_from_expand{2, 4, 6, 8};
196   ASSERT_EQ(expand, expected_return_from_expand);
197   ASSERT_TRUE(take_12);
198   ASSERT_TRUE(take_14);
199   ASSERT_FALSE(take_6);
200 }
201 
202 }  // namespace cuttlefish
203