1 /**
2 * Copyright © 2020 IBM Corporation
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 "action_environment.hpp"
17 #include "action_error.hpp"
18 #include "device.hpp"
19 #include "i2c_compare_bytes_action.hpp"
20 #include "i2c_interface.hpp"
21 #include "id_map.hpp"
22 #include "mock_services.hpp"
23 #include "mocked_i2c_interface.hpp"
24
25 #include <cstdint>
26 #include <memory>
27 #include <stdexcept>
28 #include <string>
29 #include <utility>
30 #include <vector>
31
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34
35 using namespace phosphor::power::regulators;
36
37 using ::testing::NotNull;
38 using ::testing::Return;
39 using ::testing::SetArrayArgument;
40 using ::testing::Throw;
41 using ::testing::TypedEq;
42
43 // Test for I2CCompareBytesAction(uint8_t reg,
44 // const std::vector<uint8_t>& values)
TEST(I2CCompareBytesActionTests,Constructor1)45 TEST(I2CCompareBytesActionTests, Constructor1)
46 {
47 // Test where works
48 try
49 {
50 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
51 I2CCompareBytesAction action{0x7C, values};
52
53 EXPECT_EQ(action.getRegister(), 0x7C);
54
55 EXPECT_EQ(action.getValues().size(), 3);
56 EXPECT_EQ(action.getValues()[0], 0x56);
57 EXPECT_EQ(action.getValues()[1], 0x14);
58 EXPECT_EQ(action.getValues()[2], 0xDA);
59
60 EXPECT_EQ(action.getMasks().size(), 3);
61 EXPECT_EQ(action.getMasks()[0], 0xFF);
62 EXPECT_EQ(action.getMasks()[1], 0xFF);
63 EXPECT_EQ(action.getMasks()[2], 0xFF);
64 }
65 catch (...)
66 {
67 ADD_FAILURE() << "Should not have caught exception.";
68 }
69
70 // Test where fails: Values vector is empty
71 try
72 {
73 std::vector<uint8_t> values{};
74 I2CCompareBytesAction action{0x7C, values};
75 ADD_FAILURE() << "Should not have reached this line.";
76 }
77 catch (const std::invalid_argument& e)
78 {
79 EXPECT_STREQ(e.what(), "Values vector is empty");
80 }
81 catch (...)
82 {
83 ADD_FAILURE() << "Should not have caught exception.";
84 }
85 }
86
87 // Test for I2CCompareBytesAction(uint8_t reg,
88 // const std::vector<uint8_t>& values,
89 // const std::vector<uint8_t>& masks)
TEST(I2CCompareBytesActionTests,Constructor2)90 TEST(I2CCompareBytesActionTests, Constructor2)
91 {
92 // Test where works
93 try
94 {
95 std::vector<uint8_t> values{0x56, 0x14};
96 std::vector<uint8_t> masks{0x7E, 0x3C};
97 I2CCompareBytesAction action{0xA0, values, masks};
98
99 EXPECT_EQ(action.getRegister(), 0xA0);
100
101 EXPECT_EQ(action.getValues().size(), 2);
102 EXPECT_EQ(action.getValues()[0], 0x56);
103 EXPECT_EQ(action.getValues()[1], 0x14);
104
105 EXPECT_EQ(action.getMasks().size(), 2);
106 EXPECT_EQ(action.getMasks()[0], 0x7E);
107 EXPECT_EQ(action.getMasks()[1], 0x3C);
108 }
109 catch (...)
110 {
111 ADD_FAILURE() << "Should not have caught exception.";
112 }
113
114 // Test where fails: Values vector is empty
115 try
116 {
117 std::vector<uint8_t> values{};
118 std::vector<uint8_t> masks{};
119 I2CCompareBytesAction action{0xA0, values, masks};
120 ADD_FAILURE() << "Should not have reached this line.";
121 }
122 catch (const std::invalid_argument& e)
123 {
124 EXPECT_STREQ(e.what(), "Values vector is empty");
125 }
126 catch (...)
127 {
128 ADD_FAILURE() << "Should not have caught exception.";
129 }
130
131 // Test where fails: Masks vector different size than values vector
132 try
133 {
134 std::vector<uint8_t> values{0x56, 0x14, 0xFE};
135 std::vector<uint8_t> masks{0x7E, 0x3C};
136 I2CCompareBytesAction action{0x7C, values, masks};
137 ADD_FAILURE() << "Should not have reached this line.";
138 }
139 catch (const std::invalid_argument& e)
140 {
141 EXPECT_STREQ(e.what(), "Masks vector has invalid size");
142 }
143 catch (...)
144 {
145 ADD_FAILURE() << "Should not have caught exception.";
146 }
147 }
148
TEST(I2CCompareBytesActionTests,Execute)149 TEST(I2CCompareBytesActionTests, Execute)
150 {
151 // Test where works: Equal: Mask specified
152 try
153 {
154 // Create mock I2CInterface: read() returns values 0xD7, 0x96
155 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
156 std::make_unique<i2c::MockedI2CInterface>();
157 uint8_t actualValues[] = {0xD7, 0x96};
158 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
159 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(2), NotNull(),
160 i2c::I2CInterface::Mode::I2C))
161 .Times(1)
162 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 2));
163
164 // Create Device, IDMap, MockServices, and ActionEnvironment
165 Device device{
166 "reg1", true,
167 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
168 std::move(i2cInterface)};
169 IDMap idMap{};
170 idMap.addDevice(device);
171 MockServices services{};
172 ActionEnvironment env{idMap, "reg1", services};
173
174 // Actual values: 0xD7 = 1101 0111 0x96 = 1001 0110
175 // Masks : 0x7E = 0111 1110 0x3C = 0011 1100
176 // Results : 0x56 = 0101 0110 0x14 = 0001 0100
177 const std::vector<uint8_t> values{0x56, 0x14};
178 const std::vector<uint8_t> masks{0x7E, 0x3C};
179 I2CCompareBytesAction action{0xA0, values, masks};
180 EXPECT_EQ(action.execute(env), true);
181 }
182 catch (...)
183 {
184 ADD_FAILURE() << "Should not have caught exception.";
185 }
186
187 // Test where works: Equal: Mask not specified
188 try
189 {
190 // Create mock I2CInterface: read() returns values 0x56, 0x14, 0xDA
191 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
192 std::make_unique<i2c::MockedI2CInterface>();
193 uint8_t actualValues[] = {0x56, 0x14, 0xDA};
194 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
195 EXPECT_CALL(*i2cInterface, read(0x7C, TypedEq<uint8_t&>(3), NotNull(),
196 i2c::I2CInterface::Mode::I2C))
197 .Times(1)
198 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 3));
199
200 // Create Device, IDMap, MockServices, and ActionEnvironment
201 Device device{
202 "reg1", true,
203 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
204 std::move(i2cInterface)};
205 IDMap idMap{};
206 idMap.addDevice(device);
207 MockServices services{};
208 ActionEnvironment env{idMap, "reg1", services};
209
210 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
211 I2CCompareBytesAction action{0x7C, values};
212 EXPECT_EQ(action.execute(env), true);
213 }
214 catch (...)
215 {
216 ADD_FAILURE() << "Should not have caught exception.";
217 }
218
219 // Test where works: Not equal: Mask specified
220 try
221 {
222 // Create mock I2CInterface: read() returns values 0xD7, 0x96
223 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
224 std::make_unique<i2c::MockedI2CInterface>();
225 uint8_t actualValues[] = {0xD7, 0x96};
226 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
227 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(2), NotNull(),
228 i2c::I2CInterface::Mode::I2C))
229 .Times(1)
230 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 2));
231
232 // Create Device, IDMap, MockServices, and ActionEnvironment
233 Device device{
234 "reg1", true,
235 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
236 std::move(i2cInterface)};
237 IDMap idMap{};
238 idMap.addDevice(device);
239 MockServices services{};
240 ActionEnvironment env{idMap, "reg1", services};
241
242 // Actual values: 0xD7 = 1101 0111 0x96 = 1001 0110
243 // Masks : 0x7E = 0111 1110 0x3C = 0011 1100
244 // Results : 0x56 = 0101 0110 0x14 = 0001 0100
245 const std::vector<uint8_t> values{0x56, 0x13};
246 const std::vector<uint8_t> masks{0x7E, 0x3C};
247 I2CCompareBytesAction action{0xA0, values, masks};
248 EXPECT_EQ(action.execute(env), false);
249 }
250 catch (...)
251 {
252 ADD_FAILURE() << "Should not have caught exception.";
253 }
254
255 // Test where works: Not equal: Mask not specified
256 try
257 {
258 // Create mock I2CInterface: read() returns values 0x56, 0x14, 0xDA
259 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
260 std::make_unique<i2c::MockedI2CInterface>();
261 uint8_t actualValues[] = {0x56, 0x14, 0xDA};
262 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
263 EXPECT_CALL(*i2cInterface, read(0x7C, TypedEq<uint8_t&>(3), NotNull(),
264 i2c::I2CInterface::Mode::I2C))
265 .Times(1)
266 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 3));
267
268 // Create Device, IDMap, MockServices, and ActionEnvironment
269 Device device{
270 "reg1", true,
271 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
272 std::move(i2cInterface)};
273 IDMap idMap{};
274 idMap.addDevice(device);
275 MockServices services{};
276 ActionEnvironment env{idMap, "reg1", services};
277
278 std::vector<uint8_t> values{0x56, 0x14, 0xDB};
279 I2CCompareBytesAction action{0x7C, values};
280 EXPECT_EQ(action.execute(env), false);
281 }
282 catch (...)
283 {
284 ADD_FAILURE() << "Should not have caught exception.";
285 }
286
287 // Test where works: Single byte
288 try
289 {
290 // Create mock I2CInterface: read() returns value 0xD7
291 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
292 std::make_unique<i2c::MockedI2CInterface>();
293 uint8_t actualValues[] = {0xD7};
294 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
295 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(1), NotNull(),
296 i2c::I2CInterface::Mode::I2C))
297 .Times(1)
298 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 1));
299
300 // Create Device, IDMap, MockServices, and ActionEnvironment
301 Device device{
302 "reg1", true,
303 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
304 std::move(i2cInterface)};
305 IDMap idMap{};
306 idMap.addDevice(device);
307 MockServices services{};
308 ActionEnvironment env{idMap, "reg1", services};
309
310 // Actual values: 0xD7 = 1101 0111
311 // Masks : 0x7E = 0111 1110
312 // Results : 0x56 = 0101 0110
313 std::vector<uint8_t> values{0x56};
314 std::vector<uint8_t> masks{0x7E};
315 I2CCompareBytesAction action{0xA0, values, masks};
316 EXPECT_EQ(action.execute(env), true);
317 }
318 catch (...)
319 {
320 ADD_FAILURE() << "Should not have caught exception.";
321 }
322
323 // Test where fails: Getting I2CInterface fails
324 try
325 {
326 // Create IDMap, MockServices, and ActionEnvironment
327 IDMap idMap{};
328 MockServices services{};
329 ActionEnvironment env{idMap, "reg1", services};
330
331 std::vector<uint8_t> values{0x56, 0x14, 0xDB};
332 I2CCompareBytesAction action{0x7C, values};
333 action.execute(env);
334 ADD_FAILURE() << "Should not have reached this line.";
335 }
336 catch (const std::invalid_argument& e)
337 {
338 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
339 }
340 catch (...)
341 {
342 ADD_FAILURE() << "Should not have caught exception.";
343 }
344
345 // Test where fails: Reading bytes fails
346 try
347 {
348 // Create mock I2CInterface: read() throws an I2CException
349 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
350 std::make_unique<i2c::MockedI2CInterface>();
351 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
352 EXPECT_CALL(*i2cInterface, read(0x7C, TypedEq<uint8_t&>(2), NotNull(),
353 i2c::I2CInterface::Mode::I2C))
354 .Times(1)
355 .WillOnce(Throw(i2c::I2CException{"Failed to read i2c block data",
356 "/dev/i2c-1", 0x70}));
357
358 // Create Device, IDMap, MockServices, and ActionEnvironment
359 Device device{
360 "reg1", true,
361 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
362 std::move(i2cInterface)};
363 IDMap idMap{};
364 idMap.addDevice(device);
365 MockServices services{};
366 ActionEnvironment env{idMap, "reg1", services};
367
368 std::vector<uint8_t> values{0x56, 0x14};
369 I2CCompareBytesAction action{0x7C, values};
370 action.execute(env);
371 ADD_FAILURE() << "Should not have reached this line.";
372 }
373 catch (const ActionError& e)
374 {
375 EXPECT_STREQ(e.what(),
376 "ActionError: i2c_compare_bytes: { register: "
377 "0x7C, values: [ 0x56, 0x14 ], masks: [ 0xFF, 0xFF ] }");
378 try
379 {
380 // Re-throw inner I2CException
381 std::rethrow_if_nested(e);
382 ADD_FAILURE() << "Should not have reached this line.";
383 }
384 catch (const i2c::I2CException& ie)
385 {
386 EXPECT_STREQ(ie.what(),
387 "I2CException: Failed to read i2c block data: bus "
388 "/dev/i2c-1, addr 0x70");
389 }
390 catch (...)
391 {
392 ADD_FAILURE() << "Should not have caught exception.";
393 }
394 }
395 catch (...)
396 {
397 ADD_FAILURE() << "Should not have caught exception.";
398 }
399 }
400
TEST(I2CCompareBytesActionTests,GetRegister)401 TEST(I2CCompareBytesActionTests, GetRegister)
402 {
403 std::vector<uint8_t> values{0x56, 0x14};
404 I2CCompareBytesAction action{0xA0, values};
405 EXPECT_EQ(action.getRegister(), 0xA0);
406 }
407
TEST(I2CCompareBytesActionTests,GetValues)408 TEST(I2CCompareBytesActionTests, GetValues)
409 {
410 std::vector<uint8_t> values{0x56, 0x14};
411 std::vector<uint8_t> masks{0x7E, 0x3C};
412 I2CCompareBytesAction action{0xA0, values, masks};
413 EXPECT_EQ(action.getValues().size(), 2);
414 EXPECT_EQ(action.getValues()[0], 0x56);
415 EXPECT_EQ(action.getValues()[1], 0x14);
416 }
417
TEST(I2CCompareBytesActionTests,GetMasks)418 TEST(I2CCompareBytesActionTests, GetMasks)
419 {
420 // Test where masks were not specified
421 {
422 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
423 I2CCompareBytesAction action{0x7C, values};
424 EXPECT_EQ(action.getMasks().size(), 3);
425 EXPECT_EQ(action.getMasks()[0], 0xFF);
426 EXPECT_EQ(action.getMasks()[1], 0xFF);
427 EXPECT_EQ(action.getMasks()[2], 0xFF);
428 }
429
430 // Test where masks were specified
431 {
432 std::vector<uint8_t> values{0x56, 0x14};
433 std::vector<uint8_t> masks{0x7E, 0x3C};
434 I2CCompareBytesAction action{0xA0, values, masks};
435 EXPECT_EQ(action.getMasks().size(), 2);
436 EXPECT_EQ(action.getMasks()[0], 0x7E);
437 EXPECT_EQ(action.getMasks()[1], 0x3C);
438 }
439 }
440
TEST(I2CCompareBytesActionTests,ToString)441 TEST(I2CCompareBytesActionTests, ToString)
442 {
443 std::vector<uint8_t> values{0x56, 0x14};
444 std::vector<uint8_t> masks{0x7E, 0x3C};
445 I2CCompareBytesAction action{0xA0, values, masks};
446 EXPECT_EQ(action.toString(), "i2c_compare_bytes: { register: 0xA0, values: "
447 "[ 0x56, 0x14 ], masks: [ 0x7E, 0x3C ] }");
448 }
449