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: 43 virtual bool execute(ActionEnvironment& /* environment */) override 44 { 45 return true; 46 } 47 48 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 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