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