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 "device.hpp"
18 #include "i2c_action.hpp"
19 #include "i2c_interface.hpp"
20 #include "id_map.hpp"
21 #include "mock_services.hpp"
22 #include "mocked_i2c_interface.hpp"
23
24 #include <memory>
25 #include <stdexcept>
26 #include <string>
27 #include <utility>
28
29 #include <gmock/gmock.h>
30 #include <gtest/gtest.h>
31
32 using namespace phosphor::power::regulators;
33
34 using ::testing::Return;
35 using ::testing::Throw;
36
37 /**
38 * Define a test implementation of the I2CAction abstract base class.
39 */
40 class I2CActionImpl : public I2CAction
41 {
42 public:
execute(ActionEnvironment &)43 virtual bool execute(ActionEnvironment& /* environment */) override
44 {
45 return true;
46 }
47
toString() const48 virtual std::string toString() const override
49 {
50 return "i2c_action_impl: {}";
51 }
52
53 // Make test a friend so it can access protected getI2CInterface() method
54 FRIEND_TEST(I2CActionTests, GetI2CInterface);
55 };
56
TEST(I2CActionTests,GetI2CInterface)57 TEST(I2CActionTests, GetI2CInterface)
58 {
59 // Test where works: device was not open
60 try
61 {
62 // Create mock I2CInterface
63 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
64 std::make_unique<i2c::MockedI2CInterface>();
65 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
66 EXPECT_CALL(*i2cInterface, open).Times(1);
67
68 // Create Device, IDMap, MockServices, ActionEnvironment, and I2CAction
69 Device device{
70 "reg1", true,
71 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
72 std::move(i2cInterface)};
73 IDMap idMap{};
74 idMap.addDevice(device);
75 MockServices services{};
76 ActionEnvironment env{idMap, "reg1", services};
77 I2CActionImpl action{};
78
79 // Get I2CInterface. Should succeed without an exception.
80 action.getI2CInterface(env);
81 }
82 catch (...)
83 {
84 ADD_FAILURE() << "Should not have caught exception.";
85 }
86
87 // Test where works: device was already open
88 try
89 {
90 // Create mock I2CInterface
91 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
92 std::make_unique<i2c::MockedI2CInterface>();
93 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
94 EXPECT_CALL(*i2cInterface, open).Times(0);
95
96 // Create Device, IDMap, MockServices, ActionEnvironment, and I2CAction
97 Device device{
98 "reg1", true,
99 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
100 std::move(i2cInterface)};
101 IDMap idMap{};
102 idMap.addDevice(device);
103 MockServices services{};
104 ActionEnvironment env{idMap, "reg1", services};
105 I2CActionImpl action{};
106
107 // Get I2CInterface. Should succeed without an exception.
108 action.getI2CInterface(env);
109 }
110 catch (...)
111 {
112 ADD_FAILURE() << "Should not have caught exception.";
113 }
114
115 // Test where fails: getting current device fails
116 try
117 {
118 // Create IDMap, MockServices, ActionEnvironment, and I2CAction
119 IDMap idMap{};
120 MockServices services{};
121 ActionEnvironment env{idMap, "reg1", services};
122 I2CActionImpl action{};
123
124 // Get I2CInterface. Should throw an exception since "reg1" is not a
125 // valid device in the IDMap.
126 action.getI2CInterface(env);
127 ADD_FAILURE() << "Should not have reached this line.";
128 }
129 catch (const std::invalid_argument& e)
130 {
131 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
132 }
133 catch (...)
134 {
135 ADD_FAILURE() << "Should not have caught exception.";
136 }
137
138 // Test where fails: opening interface fails
139 try
140 {
141 // Create mock I2CInterface
142 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
143 std::make_unique<i2c::MockedI2CInterface>();
144 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
145 EXPECT_CALL(*i2cInterface, open)
146 .Times(1)
147 .WillOnce(
148 Throw(i2c::I2CException{"Failed to open", "/dev/i2c-1", 0x70}));
149
150 // Create Device, IDMap, ActionEnvironment, and I2CAction
151 Device device{
152 "reg1", true,
153 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
154 std::move(i2cInterface)};
155 IDMap idMap{};
156 idMap.addDevice(device);
157 MockServices services{};
158 ActionEnvironment env{idMap, "reg1", services};
159 I2CActionImpl action{};
160
161 // Get I2CInterface. Should throw an exception from the open() call.
162 action.getI2CInterface(env);
163 ADD_FAILURE() << "Should not have reached this line.";
164 }
165 catch (const i2c::I2CException& e)
166 {
167 EXPECT_STREQ(e.what(),
168 "I2CException: Failed to open: bus /dev/i2c-1, addr 0x70");
169 }
170 catch (...)
171 {
172 ADD_FAILURE() << "Should not have caught exception.";
173 }
174 }
175