1b38da99fSShawn McCarney /**
2b38da99fSShawn McCarney  * Copyright © 2020 IBM Corporation
3b38da99fSShawn McCarney  *
4b38da99fSShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
5b38da99fSShawn McCarney  * you may not use this file except in compliance with the License.
6b38da99fSShawn McCarney  * You may obtain a copy of the License at
7b38da99fSShawn McCarney  *
8b38da99fSShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
9b38da99fSShawn McCarney  *
10b38da99fSShawn McCarney  * Unless required by applicable law or agreed to in writing, software
11b38da99fSShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
12b38da99fSShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b38da99fSShawn McCarney  * See the License for the specific language governing permissions and
14b38da99fSShawn McCarney  * limitations under the License.
15b38da99fSShawn McCarney  */
16b38da99fSShawn McCarney #include "action_environment.hpp"
17b38da99fSShawn McCarney #include "device.hpp"
18b38da99fSShawn McCarney #include "i2c_action.hpp"
19b38da99fSShawn McCarney #include "i2c_interface.hpp"
20b38da99fSShawn McCarney #include "id_map.hpp"
21*73eaceebSBob King #include "mock_services.hpp"
22b38da99fSShawn McCarney #include "mocked_i2c_interface.hpp"
23b38da99fSShawn McCarney 
24b38da99fSShawn McCarney #include <memory>
25b38da99fSShawn McCarney #include <stdexcept>
26b38da99fSShawn McCarney #include <string>
27b38da99fSShawn McCarney #include <utility>
28b38da99fSShawn McCarney 
29b38da99fSShawn McCarney #include <gmock/gmock.h>
30b38da99fSShawn McCarney #include <gtest/gtest.h>
31b38da99fSShawn McCarney 
32b38da99fSShawn McCarney using namespace phosphor::power::regulators;
33b38da99fSShawn McCarney 
34b38da99fSShawn McCarney using ::testing::Return;
35b38da99fSShawn McCarney using ::testing::Throw;
36b38da99fSShawn McCarney 
37b38da99fSShawn McCarney /**
38b38da99fSShawn McCarney  * Define a test implementation of the I2CAction abstract base class.
39b38da99fSShawn McCarney  */
40b38da99fSShawn McCarney class I2CActionImpl : public I2CAction
41b38da99fSShawn McCarney {
42b38da99fSShawn McCarney   public:
execute(ActionEnvironment &)43b38da99fSShawn McCarney     virtual bool execute(ActionEnvironment& /* environment */) override
44b38da99fSShawn McCarney     {
45b38da99fSShawn McCarney         return true;
46b38da99fSShawn McCarney     }
47b38da99fSShawn McCarney 
toString() const48b38da99fSShawn McCarney     virtual std::string toString() const override
49b38da99fSShawn McCarney     {
50b38da99fSShawn McCarney         return "i2c_action_impl: {}";
51b38da99fSShawn McCarney     }
52b38da99fSShawn McCarney 
53b38da99fSShawn McCarney     // Make test a friend so it can access protected getI2CInterface() method
54b38da99fSShawn McCarney     FRIEND_TEST(I2CActionTests, GetI2CInterface);
55b38da99fSShawn McCarney };
56b38da99fSShawn McCarney 
TEST(I2CActionTests,GetI2CInterface)57b38da99fSShawn McCarney TEST(I2CActionTests, GetI2CInterface)
58b38da99fSShawn McCarney {
59b38da99fSShawn McCarney     // Test where works: device was not open
60b38da99fSShawn McCarney     try
61b38da99fSShawn McCarney     {
62b38da99fSShawn McCarney         // Create mock I2CInterface
63b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
64b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
65b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
66b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open).Times(1);
67b38da99fSShawn McCarney 
68*73eaceebSBob King         // Create Device, IDMap, MockServices, ActionEnvironment, and I2CAction
69a76898f1SBob King         Device device{
70a76898f1SBob King             "reg1", true,
71a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
72b38da99fSShawn McCarney             std::move(i2cInterface)};
73b38da99fSShawn McCarney         IDMap idMap{};
74b38da99fSShawn McCarney         idMap.addDevice(device);
75*73eaceebSBob King         MockServices services{};
76*73eaceebSBob King         ActionEnvironment env{idMap, "reg1", services};
77b38da99fSShawn McCarney         I2CActionImpl action{};
78b38da99fSShawn McCarney 
79b38da99fSShawn McCarney         // Get I2CInterface.  Should succeed without an exception.
80b38da99fSShawn McCarney         action.getI2CInterface(env);
81b38da99fSShawn McCarney     }
82b38da99fSShawn McCarney     catch (...)
83b38da99fSShawn McCarney     {
84b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
85b38da99fSShawn McCarney     }
86b38da99fSShawn McCarney 
87b38da99fSShawn McCarney     // Test where works: device was already open
88b38da99fSShawn McCarney     try
89b38da99fSShawn McCarney     {
90b38da99fSShawn McCarney         // Create mock I2CInterface
91b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
92b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
93b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
94b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open).Times(0);
95b38da99fSShawn McCarney 
96*73eaceebSBob King         // Create Device, IDMap, MockServices, ActionEnvironment, and I2CAction
97a76898f1SBob King         Device device{
98a76898f1SBob King             "reg1", true,
99a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
100b38da99fSShawn McCarney             std::move(i2cInterface)};
101b38da99fSShawn McCarney         IDMap idMap{};
102b38da99fSShawn McCarney         idMap.addDevice(device);
103*73eaceebSBob King         MockServices services{};
104*73eaceebSBob King         ActionEnvironment env{idMap, "reg1", services};
105b38da99fSShawn McCarney         I2CActionImpl action{};
106b38da99fSShawn McCarney 
107b38da99fSShawn McCarney         // Get I2CInterface.  Should succeed without an exception.
108b38da99fSShawn McCarney         action.getI2CInterface(env);
109b38da99fSShawn McCarney     }
110b38da99fSShawn McCarney     catch (...)
111b38da99fSShawn McCarney     {
112b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
113b38da99fSShawn McCarney     }
114b38da99fSShawn McCarney 
115b38da99fSShawn McCarney     // Test where fails: getting current device fails
116b38da99fSShawn McCarney     try
117b38da99fSShawn McCarney     {
118*73eaceebSBob King         // Create IDMap, MockServices, ActionEnvironment, and I2CAction
119b38da99fSShawn McCarney         IDMap idMap{};
120*73eaceebSBob King         MockServices services{};
121*73eaceebSBob King         ActionEnvironment env{idMap, "reg1", services};
122b38da99fSShawn McCarney         I2CActionImpl action{};
123b38da99fSShawn McCarney 
124b38da99fSShawn McCarney         // Get I2CInterface.  Should throw an exception since "reg1" is not a
125b38da99fSShawn McCarney         // valid device in the IDMap.
126b38da99fSShawn McCarney         action.getI2CInterface(env);
127b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
128b38da99fSShawn McCarney     }
129b38da99fSShawn McCarney     catch (const std::invalid_argument& e)
130b38da99fSShawn McCarney     {
131b38da99fSShawn McCarney         EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
132b38da99fSShawn McCarney     }
133b38da99fSShawn McCarney     catch (...)
134b38da99fSShawn McCarney     {
135b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
136b38da99fSShawn McCarney     }
137b38da99fSShawn McCarney 
138b38da99fSShawn McCarney     // Test where fails: opening interface fails
139b38da99fSShawn McCarney     try
140b38da99fSShawn McCarney     {
141b38da99fSShawn McCarney         // Create mock I2CInterface
142b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
143b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
144b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
145b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open)
146b38da99fSShawn McCarney             .Times(1)
147b38da99fSShawn McCarney             .WillOnce(
148b38da99fSShawn McCarney                 Throw(i2c::I2CException{"Failed to open", "/dev/i2c-1", 0x70}));
149b38da99fSShawn McCarney 
150b38da99fSShawn McCarney         // Create Device, IDMap, ActionEnvironment, and I2CAction
151a76898f1SBob King         Device device{
152a76898f1SBob King             "reg1", true,
153a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
154b38da99fSShawn McCarney             std::move(i2cInterface)};
155b38da99fSShawn McCarney         IDMap idMap{};
156b38da99fSShawn McCarney         idMap.addDevice(device);
157*73eaceebSBob King         MockServices services{};
158*73eaceebSBob King         ActionEnvironment env{idMap, "reg1", services};
159b38da99fSShawn McCarney         I2CActionImpl action{};
160b38da99fSShawn McCarney 
161b38da99fSShawn McCarney         // Get I2CInterface.  Should throw an exception from the open() call.
162b38da99fSShawn McCarney         action.getI2CInterface(env);
163b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
164b38da99fSShawn McCarney     }
165b38da99fSShawn McCarney     catch (const i2c::I2CException& e)
166b38da99fSShawn McCarney     {
167b38da99fSShawn McCarney         EXPECT_STREQ(e.what(),
168b38da99fSShawn McCarney                      "I2CException: Failed to open: bus /dev/i2c-1, addr 0x70");
169b38da99fSShawn McCarney     }
170b38da99fSShawn McCarney     catch (...)
171b38da99fSShawn McCarney     {
172b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
173b38da99fSShawn McCarney     }
174b38da99fSShawn McCarney }
175