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