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