1 #include "dbus_environment.hpp" 2 #include "helpers.hpp" 3 #include "mocks/json_storage_mock.hpp" 4 #include "mocks/trigger_manager_mock.hpp" 5 #include "params/trigger_params.hpp" 6 #include "trigger.hpp" 7 #include "utils/set_exception.hpp" 8 9 using namespace testing; 10 using namespace std::literals::string_literals; 11 12 static constexpr size_t expectedTriggerVersion = 0; 13 14 class TestTrigger : public Test 15 { 16 public: 17 TriggerParams triggerParams; 18 19 std::unique_ptr<TriggerManagerMock> triggerManagerMockPtr = 20 std::make_unique<NiceMock<TriggerManagerMock>>(); 21 testing::NiceMock<StorageMock> storageMock; 22 std::unique_ptr<Trigger> sut; 23 24 void SetUp() override 25 { 26 sut = makeTrigger(triggerParams); 27 } 28 29 std::unique_ptr<Trigger> makeTrigger(const TriggerParams& params) 30 { 31 return std::make_unique<Trigger>( 32 DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(), 33 params.name(), params.isDiscrete(), params.logToJournal(), 34 params.logToRedfish(), params.updateReport(), params.sensors(), 35 params.reportNames(), params.thresholdParams(), 36 std::vector<std::shared_ptr<interfaces::Threshold>>{}, 37 *triggerManagerMockPtr, storageMock); 38 } 39 40 static interfaces::JsonStorage::FilePath to_file_path(std::string name) 41 { 42 return interfaces::JsonStorage::FilePath( 43 std::to_string(std::hash<std::string>{}(name))); 44 } 45 46 template <class T> 47 static T getProperty(const std::string& path, const std::string& property) 48 { 49 auto propertyPromise = std::promise<T>(); 50 auto propertyFuture = propertyPromise.get_future(); 51 sdbusplus::asio::getProperty<T>( 52 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path, 53 Trigger::triggerIfaceName, property, 54 [&propertyPromise](const boost::system::error_code& ec, T t) { 55 if (ec) 56 { 57 utils::setException(propertyPromise, "GetProperty failed"); 58 return; 59 } 60 propertyPromise.set_value(t); 61 }); 62 return DbusEnvironment::waitForFuture(std::move(propertyFuture)); 63 } 64 65 template <class T> 66 static boost::system::error_code setProperty(const std::string& path, 67 const std::string& property, 68 const T& newValue) 69 { 70 auto setPromise = std::promise<boost::system::error_code>(); 71 auto setFuture = setPromise.get_future(); 72 73 sdbusplus::asio::setProperty( 74 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path, 75 Trigger::triggerIfaceName, property, std::move(newValue), 76 [setPromise = 77 std::move(setPromise)](boost::system::error_code ec) mutable { 78 setPromise.set_value(ec); 79 }); 80 return DbusEnvironment::waitForFuture(std::move(setFuture)); 81 } 82 83 boost::system::error_code deleteTrigger(const std::string& path) 84 { 85 std::promise<boost::system::error_code> methodPromise; 86 DbusEnvironment::getBus()->async_method_call( 87 [&methodPromise](boost::system::error_code ec) { 88 methodPromise.set_value(ec); 89 }, 90 DbusEnvironment::serviceName(), path, Trigger::deleteIfaceName, 91 "Delete"); 92 return DbusEnvironment::waitForFuture(methodPromise.get_future()); 93 } 94 }; 95 96 TEST_F(TestTrigger, checkIfPropertiesAreSet) 97 { 98 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), Eq(true)); 99 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Discrete"), 100 Eq(triggerParams.isDiscrete())); 101 EXPECT_THAT(getProperty<bool>(sut->getPath(), "LogToJournal"), 102 Eq(triggerParams.logToJournal())); 103 EXPECT_THAT(getProperty<bool>(sut->getPath(), "LogToRedfish"), 104 Eq(triggerParams.logToRedfish())); 105 EXPECT_THAT(getProperty<bool>(sut->getPath(), "UpdateReport"), 106 Eq(triggerParams.updateReport())); 107 EXPECT_THAT((getProperty<std::vector< 108 std::pair<sdbusplus::message::object_path, std::string>>>( 109 sut->getPath(), "Sensors")), 110 Eq(triggerParams.sensors())); 111 EXPECT_THAT( 112 getProperty<std::vector<std::string>>(sut->getPath(), "ReportNames"), 113 Eq(triggerParams.reportNames())); 114 EXPECT_THAT( 115 getProperty<TriggerThresholdParams>(sut->getPath(), "Thresholds"), 116 Eq(triggerParams.thresholdParams())); 117 } 118 119 TEST_F(TestTrigger, deleteTrigger) 120 { 121 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName()))); 122 EXPECT_CALL(*triggerManagerMockPtr, removeTrigger(sut.get())); 123 auto ec = deleteTrigger(sut->getPath()); 124 EXPECT_THAT(ec, Eq(boost::system::errc::success)); 125 } 126 127 TEST_F(TestTrigger, deletingNonExistingTriggerReturnInvalidRequestDescriptor) 128 { 129 auto ec = deleteTrigger(Trigger::triggerDir + "NonExisting"s); 130 EXPECT_THAT(ec.value(), Eq(EBADR)); 131 } 132 133 TEST_F(TestTrigger, settingPersistencyToFalseRemovesReportFromStorage) 134 { 135 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName()))); 136 137 bool persistent = false; 138 EXPECT_THAT(setProperty(sut->getPath(), "Persistent", persistent).value(), 139 Eq(boost::system::errc::success)); 140 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), 141 Eq(persistent)); 142 } 143 144 class TestTriggerErrors : public TestTrigger 145 { 146 public: 147 void SetUp() override 148 {} 149 150 nlohmann::json storedConfiguration; 151 }; 152 153 TEST_F(TestTriggerErrors, throwingExceptionDoesNotStoreTriggerReportNames) 154 { 155 EXPECT_CALL(storageMock, store(_, _)) 156 .WillOnce(Throw(std::runtime_error("Generic error!"))); 157 158 sut = makeTrigger(triggerParams); 159 160 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), Eq(false)); 161 } 162 163 TEST_F(TestTriggerErrors, creatingTriggerThrowsExceptionWhenNameIsInvalid) 164 { 165 EXPECT_CALL(storageMock, store(_, _)).Times(0); 166 167 EXPECT_THROW(makeTrigger(triggerParams.name("inv?lidName")), 168 sdbusplus::exception::SdBusError); 169 } 170 171 class TestTriggerStore : public TestTrigger 172 { 173 public: 174 void SetUp() override 175 { 176 ON_CALL(storageMock, store(_, _)) 177 .WillByDefault(SaveArg<1>(&storedConfiguration)); 178 179 sut = makeTrigger(triggerParams); 180 } 181 182 nlohmann::json storedConfiguration; 183 }; 184 185 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerVersion) 186 { 187 ASSERT_THAT(storedConfiguration.at("Version"), Eq(expectedTriggerVersion)); 188 } 189 190 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerName) 191 { 192 ASSERT_THAT(storedConfiguration.at("Name"), Eq(triggerParams.name())); 193 } 194 195 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerIsDiscrete) 196 { 197 ASSERT_THAT(storedConfiguration.at("IsDiscrete"), 198 Eq(triggerParams.isDiscrete())); 199 } 200 201 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerLogToJournal) 202 { 203 ASSERT_THAT(storedConfiguration.at("LogToJournal"), 204 Eq(triggerParams.logToRedfish())); 205 } 206 207 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerLogToRedfish) 208 { 209 ASSERT_THAT(storedConfiguration.at("LogToRedfish"), 210 Eq(triggerParams.logToRedfish())); 211 } 212 213 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerUpdateReport) 214 { 215 ASSERT_THAT(storedConfiguration.at("UpdateReport"), 216 Eq(triggerParams.updateReport())); 217 } 218 219 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerReportNames) 220 { 221 ASSERT_THAT(storedConfiguration.at("ReportNames"), 222 Eq(triggerParams.reportNames())); 223 } 224 225 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerSensors) 226 { 227 nlohmann::json expectedItem; 228 expectedItem["sensorPath"] = 229 "/xyz/openbmc_project/sensors/temperature/BMC_Temp"; 230 expectedItem["sensorMetadata"] = ""; 231 232 ASSERT_THAT(storedConfiguration.at("Sensors"), ElementsAre(expectedItem)); 233 } 234 235 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerThresholdParams) 236 { 237 ASSERT_THAT(storedConfiguration.at("ThresholdParamsDiscriminator"), Eq(0)); 238 239 nlohmann::json expectedItem0; 240 expectedItem0["type"] = 0; 241 expectedItem0["dwellTime"] = 10; 242 expectedItem0["direction"] = 1; 243 expectedItem0["thresholdValue"] = 0.0; 244 245 nlohmann::json expectedItem1; 246 expectedItem1["type"] = 3; 247 expectedItem1["dwellTime"] = 10; 248 expectedItem1["direction"] = 2; 249 expectedItem1["thresholdValue"] = 90.0; 250 251 ASSERT_THAT(storedConfiguration.at("ThresholdParams"), 252 ElementsAre(expectedItem0, expectedItem1)); 253 } 254