blob: 22c7b7fc9e57118deea33be130b95ac621892031 [file] [log] [blame]
Gilad Arnold4d740eb2012-05-15 08:48:13 -07001// Copyright (c) 2012 The Chromium OS 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.
4
5#include "update_engine/gpio_mock_udev_interface.h"
6
7#include <string>
8
9#include <base/stringprintf.h>
10#include <gtest/gtest.h>
11
12#include "gpio_handler_unittest.h"
13
14namespace chromeos_update_engine {
15
16const char* StandardGpioMockUdevInterface::kUdevGpioSubsystem = "gpio";
17const char* StandardGpioMockUdevInterface::kUdevGpioChipSysname = "gpiochip*";
18
19const StandardGpioMockUdevInterface::GpioDescriptor
20 StandardGpioMockUdevInterface::gpio_descriptors_[kMockGpioIdMax] = {
21 { "ID_GPIO_DUTFLAGA", MOCK_DUTFLAGA_GPIO_ID },
22 { "ID_GPIO_DUTFLAGB", MOCK_DUTFLAGB_GPIO_ID },
23};
24
25const char* StandardGpioMockUdevInterface::enum_gpio_chip_dev_list_[] = {
26 "gpiochip" MOCK_GPIO_CHIP_ID,
27 NULL
28};
29const char* StandardGpioMockUdevInterface::enum_dutflaga_gpio_dev_list_[] = {
30 "gpio" MOCK_DUTFLAGA_GPIO_ID,
31 NULL
32};
33const char* StandardGpioMockUdevInterface::enum_dutflagb_gpio_dev_list_[] = {
34 "gpio" MOCK_DUTFLAGB_GPIO_ID,
35 NULL
36};
37
38StandardGpioMockUdevInterface::StandardGpioMockUdevInterface()
39 : udev_id_(0), udev_enum_id_(0), num_discovered_(0) {
40 std::fill_n(used_udev_ids_, MAX_UDEV_OBJECTS, false);
41 std::fill_n(used_udev_enum_ids_, MAX_UDEV_ENUM_OBJECTS, false);
42
43 gpio_chip_dev_ = (MockDevice) {
44 MOCK_SYSFS_PREFIX "/gpiochip" MOCK_GPIO_CHIP_ID,
45 gpio_descriptors_, kMockGpioIdMax, false, false
46 };
47 dutflaga_gpio_dev_ = (MockDevice) {
48 MOCK_SYSFS_PREFIX "/gpio" MOCK_DUTFLAGA_GPIO_ID, NULL, 0, true, false
49 };
50 dutflagb_gpio_dev_ = (MockDevice) {
51 MOCK_SYSFS_PREFIX "/gpio" MOCK_DUTFLAGB_GPIO_ID, NULL, 0, true, false
52 };
53}
54
55// Device lists are simply null-terminated arrays of strings.
56const char* StandardGpioMockUdevInterface::ListEntryGetName(
57 struct udev_list_entry* list_entry) {
58 const char** mock_list_entry = reinterpret_cast<const char**>(list_entry);
59 EXPECT_TRUE(mock_list_entry && *mock_list_entry);
60 if (!mock_list_entry)
61 return NULL;
62 // The mock list entry is the name string itself...
63 return *mock_list_entry;
64}
65
66struct udev_list_entry* StandardGpioMockUdevInterface::ListEntryGetNext(
67 struct udev_list_entry* list_entry) {
68 char** mock_list_entry = reinterpret_cast<char**>(list_entry);
69 EXPECT_TRUE(mock_list_entry && *mock_list_entry);
70 if (!mock_list_entry)
71 return NULL;
72 // Advance to the next element in the array.
73 mock_list_entry++;
74 return (*mock_list_entry ?
75 reinterpret_cast<struct udev_list_entry*>(mock_list_entry) : NULL);
76}
77
78struct udev_device* StandardGpioMockUdevInterface::DeviceNewFromSyspath(
79 struct udev* udev, const char* syspath) {
80 const size_t udev_id = UdevToId(udev);
81 if (udev_id >= MAX_UDEV_OBJECTS)
82 return NULL;
83 MockDevice* mock_dev;
84
85 // Generate the desired mock device based on the provided syspath.
86 if (!strcmp(syspath, enum_gpio_chip_dev_list_[0])) {
87 mock_dev = const_cast<MockDevice*>(&gpio_chip_dev_);
88 } else if (!strcmp(syspath, enum_dutflaga_gpio_dev_list_[0])) {
89 mock_dev = const_cast<MockDevice*>(&dutflaga_gpio_dev_);
90 } else if (!strcmp(syspath, enum_dutflagb_gpio_dev_list_[0])) {
91 mock_dev = const_cast<MockDevice*>(&dutflagb_gpio_dev_);
92 } else {
93 ADD_FAILURE();
94 return NULL;
95 }
96
97 EXPECT_FALSE(mock_dev->is_used);
98 if (mock_dev->is_used)
99 return NULL;
100 mock_dev->is_used = true;
101
102 return reinterpret_cast<struct udev_device*>(mock_dev);
103}
104
105const char* StandardGpioMockUdevInterface::DeviceGetPropertyValue(
106 struct udev_device* udev_device, const char* key) {
107 const MockDevice* mock_dev = UdevDeviceToMock(udev_device);
108 EXPECT_TRUE(mock_dev->properties);
109 if (!mock_dev->properties)
110 return NULL;
111 for (size_t i = 0; i < mock_dev->num_properties; i++)
112 if (!strcmp(key, mock_dev->properties[i].property))
113 return mock_dev->properties[i].value;
114 return NULL;
115}
116
117const char* StandardGpioMockUdevInterface::DeviceGetSyspath(
118 struct udev_device* udev_device) {
119 const MockDevice* mock_dev = UdevDeviceToMock(udev_device);
120 if (mock_dev->is_gpio)
121 num_discovered_++;
122 return mock_dev->syspath;
123}
124
125void StandardGpioMockUdevInterface::DeviceUnref(
126 struct udev_device* udev_device) {
127 MockDevice* mock_dev = UdevDeviceToMock(udev_device);
128 mock_dev->is_used = false;
129}
130
131struct udev_enumerate* StandardGpioMockUdevInterface::EnumerateNew(
132 struct udev* udev) {
133 const size_t udev_id = UdevToId(udev);
134 if (udev_id >= MAX_UDEV_OBJECTS)
135 return NULL;
136 // A new enumeration "pointer" is cast for an integer identifier.
137 EXPECT_LT(udev_enum_id_, MAX_UDEV_ENUM_OBJECTS);
138 if (udev_enum_id_ >= MAX_UDEV_ENUM_OBJECTS)
139 return NULL;
140 used_udev_enum_ids_[udev_enum_id_] = true;
141 return reinterpret_cast<struct udev_enumerate*>(++udev_enum_id_);
142}
143
144int StandardGpioMockUdevInterface::EnumerateAddMatchSubsystem(
145 struct udev_enumerate* udev_enum, const char* subsystem) {
146 const size_t udev_enum_id = UdevEnumToId(udev_enum);
147 if (udev_enum_id >= MAX_UDEV_ENUM_OBJECTS)
148 return -1;
149
150 // Ensure client is correctly requesting the GPIO subsystem.
151 EXPECT_STREQ(subsystem, kUdevGpioSubsystem);
152 if (strcmp(subsystem, kUdevGpioSubsystem))
153 return -1;
154
155 return 0;
156}
157
158int StandardGpioMockUdevInterface::EnumerateAddMatchSysname(
159 struct udev_enumerate* udev_enum, const char* sysname) {
160 const size_t udev_enum_id = UdevEnumToId(udev_enum);
161 if (udev_enum_id >= MAX_UDEV_ENUM_OBJECTS)
162 return -1;
163
164 // Ensure client is requesting the correct sysnamem, depending on the correct
165 // phase in the detection process.
166 switch (udev_enum_id) {
167 case 0: // looking for a GPIO chip
168 EXPECT_STREQ(sysname, kUdevGpioChipSysname);
169 if (strcmp(sysname, kUdevGpioChipSysname))
170 return -1;
171 break;
172 case 1: // looking for dut_flaga/b
173 case 2: {
174 const int gpio_id = udev_enum_id - 1;
175 const std::string gpio_pattern =
176 StringPrintf("*%s", gpio_descriptors_[gpio_id].value);
177 EXPECT_STREQ(sysname, gpio_pattern.c_str());
178 if (strcmp(sysname, gpio_pattern.c_str()))
179 return -1;
180 break;
181 }
182 default:
183 ADD_FAILURE(); // can't get here
184 return -1;
185 }
186
187 return 0;
188}
189
190int StandardGpioMockUdevInterface::EnumerateScanDevices(
191 struct udev_enumerate* udev_enum) {
192 const size_t udev_enum_id = UdevEnumToId(udev_enum);
193 if (udev_enum_id >= MAX_UDEV_ENUM_OBJECTS)
194 return -1;
195 return 0; // nothing to do, really
196}
197
198struct udev_list_entry* StandardGpioMockUdevInterface::EnumerateGetListEntry(
199 struct udev_enumerate* udev_enum) {
200 const size_t udev_enum_id = UdevEnumToId(udev_enum);
201 if (udev_enum_id >= MAX_UDEV_ENUM_OBJECTS)
202 return NULL;
203
204 // Return a list of devices corresponding to the provided enumeration.
205 switch (udev_enum_id) {
206 case 0:
207 return reinterpret_cast<struct udev_list_entry*>(
208 enum_gpio_chip_dev_list_);
209 case 1:
210 return reinterpret_cast<struct udev_list_entry*>(
211 enum_dutflaga_gpio_dev_list_);
212 case 2:
213 return reinterpret_cast<struct udev_list_entry*>(
214 enum_dutflagb_gpio_dev_list_);
215 }
216
217 ADD_FAILURE(); // can't get here
218 return NULL;
219}
220
221void StandardGpioMockUdevInterface::EnumerateUnref(
222 struct udev_enumerate* udev_enum) {
223 const size_t udev_enum_id = UdevEnumToId(udev_enum);
224 if (udev_enum_id >= MAX_UDEV_ENUM_OBJECTS)
225 return;
226 used_udev_enum_ids_[udev_enum_id] = false; // make sure it's freed just once
227}
228
229struct udev* StandardGpioMockUdevInterface::New() {
230 // The returned "pointer" is cast from an integer identifier.
231 EXPECT_LT(udev_id_, MAX_UDEV_OBJECTS);
232 if (udev_id_ >= MAX_UDEV_OBJECTS)
233 return NULL;
234 used_udev_ids_[udev_id_] = true;
235 return reinterpret_cast<struct udev*>(++udev_id_);
236}
237
238void StandardGpioMockUdevInterface::Unref(struct udev* udev) {
239 // Convert to object identifier, ensuring the object has been "allocated".
240 const size_t udev_id = UdevToId(udev);
241 if (udev_id >= MAX_UDEV_OBJECTS)
242 return;
243 used_udev_ids_[udev_id] = false; // make sure it's freed just once
244}
245
246void StandardGpioMockUdevInterface::ExpectAllResourcesDeallocated() const {
247 // Make sure that all handles were released.
248 for (size_t i = 0; i < MAX_UDEV_OBJECTS; i++)
249 EXPECT_FALSE(used_udev_ids_[i]);
250 for (size_t i = 0; i < MAX_UDEV_ENUM_OBJECTS; i++)
251 EXPECT_FALSE(used_udev_enum_ids_[i]);
252 EXPECT_FALSE(gpio_chip_dev_.is_used);
253 EXPECT_FALSE(dutflaga_gpio_dev_.is_used);
254 EXPECT_FALSE(dutflagb_gpio_dev_.is_used);
255}
256
257void StandardGpioMockUdevInterface::ExpectDiscoverySuccess() const {
258 EXPECT_EQ(num_discovered_, kMockGpioIdMax);
259}
260
261void StandardGpioMockUdevInterface::ExpectDiscoveryFail() const {
262 EXPECT_LT(num_discovered_, kMockGpioIdMax);
263}
264
265StandardGpioMockUdevInterface::MockDevice*
266StandardGpioMockUdevInterface::UdevDeviceToMock(
267 struct udev_device* udev_dev) const {
268 EXPECT_TRUE(udev_dev);
269 if (!udev_dev)
270 return NULL;
271 MockDevice* mock_dev = reinterpret_cast<MockDevice*>(udev_dev);
272 EXPECT_TRUE(mock_dev->is_used);
273 if (!mock_dev->is_used)
274 return NULL;
275 return mock_dev;
276}
277
278size_t StandardGpioMockUdevInterface::UdevEnumToId(
279 struct udev_enumerate* udev_enum) const {
280 EXPECT_TRUE(udev_enum);
281 size_t udev_enum_id = reinterpret_cast<size_t>(udev_enum) - 1;
282 EXPECT_LT(udev_enum_id, MAX_UDEV_ENUM_OBJECTS);
283 EXPECT_TRUE(used_udev_enum_ids_[udev_enum_id]);
284 if (!(udev_enum && udev_enum_id < MAX_UDEV_ENUM_OBJECTS &&
285 used_udev_enum_ids_[udev_enum_id]))
286 return MAX_UDEV_ENUM_OBJECTS;
287 return udev_enum_id;
288}
289
290size_t StandardGpioMockUdevInterface::UdevToId(struct udev* udev) const {
291 EXPECT_TRUE(udev);
292 size_t udev_id = reinterpret_cast<size_t>(udev) - 1;
293 EXPECT_LT(udev_id, MAX_UDEV_OBJECTS);
294 EXPECT_TRUE(used_udev_ids_[udev_id]);
295 if (!(udev && udev_id < MAX_UDEV_OBJECTS && used_udev_ids_[udev_id]))
296 return MAX_UDEV_OBJECTS;
297 return udev_id;
298}
299
300#define MOCK_GPIO_CHIP1_ID "200"
301#define MOCK_GPIO_CHIP2_ID "201"
302
303const char* MultiChipGpioMockUdevInterface::enum_gpio_chip_dev_list_[] = {
304 "gpiochip" MOCK_GPIO_CHIP1_ID,
305 "gpiochip" MOCK_GPIO_CHIP2_ID,
306 NULL
307};
308
309MultiChipGpioMockUdevInterface::MultiChipGpioMockUdevInterface() {
310 gpio_chip1_dev_ = (MockDevice) {
311 MOCK_SYSFS_PREFIX "/gpiochip" MOCK_GPIO_CHIP1_ID,
312 gpio_descriptors_, kMockGpioIdMax, false, false
313 };
314 gpio_chip2_dev_ = (MockDevice) {
315 MOCK_SYSFS_PREFIX "/gpiochip" MOCK_GPIO_CHIP2_ID,
316 gpio_descriptors_, kMockGpioIdMax, false, false
317 };
318}
319
320struct udev_device* MultiChipGpioMockUdevInterface::DeviceNewFromSyspath(
321 struct udev* udev, const char* syspath) {
322 const size_t udev_id = UdevToId(udev);
323 if (udev_id >= MAX_UDEV_OBJECTS)
324 return NULL;
325 MockDevice* mock_dev;
326
327 // Generate the desired mock device based on the provided syspath.
328 if (!strcmp(syspath, enum_gpio_chip_dev_list_[0])) {
329 mock_dev = const_cast<MockDevice*>(&gpio_chip1_dev_);
330 } else if (!strcmp(syspath, enum_gpio_chip_dev_list_[1])) {
331 mock_dev = const_cast<MockDevice*>(&gpio_chip2_dev_);
332 } else if (!strcmp(syspath, enum_dutflaga_gpio_dev_list_[0])) {
333 mock_dev = const_cast<MockDevice*>(&dutflaga_gpio_dev_);
334 } else if (!strcmp(syspath, enum_dutflagb_gpio_dev_list_[0])) {
335 mock_dev = const_cast<MockDevice*>(&dutflagb_gpio_dev_);
336 } else {
337 ADD_FAILURE();
338 return NULL;
339 }
340
341 EXPECT_FALSE(mock_dev->is_used);
342 if (mock_dev->is_used)
343 return NULL;
344 mock_dev->is_used = true;
345
346 return reinterpret_cast<struct udev_device*>(mock_dev);
347}
348
349struct udev_list_entry* MultiChipGpioMockUdevInterface::EnumerateGetListEntry(
350 struct udev_enumerate* udev_enum) {
351 const size_t udev_enum_id = UdevEnumToId(udev_enum);
352
353 // Return a list of devices corresponding to the provided enumeration.
354 switch (udev_enum_id) {
355 case 0:
356 return reinterpret_cast<struct udev_list_entry*>(
357 enum_gpio_chip_dev_list_);
358 case 1:
359 return reinterpret_cast<struct udev_list_entry*>(
360 enum_dutflaga_gpio_dev_list_);
361 case 2:
362 return reinterpret_cast<struct udev_list_entry*>(
363 enum_dutflagb_gpio_dev_list_);
364 }
365
366 ADD_FAILURE(); // can't get here
367 return NULL;
368}
369
370
371} // namespace chromeos_update_engine