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 "trigger_manager.hpp" 8 #include "utils/conversion_trigger.hpp" 9 #include "utils/transform.hpp" 10 #include "utils/tstring.hpp" 11 12 #include <boost/range/combine.hpp> 13 14 using namespace testing; 15 using namespace std::literals::string_literals; 16 17 static constexpr size_t expectedTriggerVersion = 0; 18 19 class TestTrigger : public Test 20 { 21 public: 22 TriggerParams triggerParams; 23 TriggerParams triggerDiscreteParams = 24 TriggerParams() 25 .id("DiscreteTrigger") 26 .name("My Discrete Trigger") 27 .thresholdParams(std::vector<discrete::LabeledThresholdParam>{ 28 discrete::LabeledThresholdParam{ 29 "userId", discrete::Severity::warning, 30 Milliseconds(10).count(), "15.2"}, 31 discrete::LabeledThresholdParam{ 32 "userId_2", discrete::Severity::critical, 33 Milliseconds(5).count(), "32.7"}, 34 }); 35 36 std::unique_ptr<TriggerManagerMock> triggerManagerMockPtr = 37 std::make_unique<NiceMock<TriggerManagerMock>>(); 38 testing::NiceMock<StorageMock> storageMock; 39 std::unique_ptr<Trigger> sut; 40 41 void SetUp() override 42 { 43 sut = makeTrigger(triggerParams); 44 } 45 46 static std::vector<LabeledSensorInfo> 47 convertToLabeledSensor(const SensorsInfo& sensorsInfo) 48 { 49 return utils::transform(sensorsInfo, [](const auto& sensorInfo) { 50 const auto& [sensorPath, sensorMetadata] = sensorInfo; 51 return LabeledSensorInfo("service1", sensorPath, sensorMetadata); 52 }); 53 } 54 55 std::unique_ptr<Trigger> makeTrigger(const TriggerParams& params) 56 { 57 return std::make_unique<Trigger>( 58 DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(), 59 params.id(), params.name(), params.triggerActions(), 60 params.reportNames(), params.sensors(), params.thresholdParams(), 61 std::vector<std::shared_ptr<interfaces::Threshold>>{}, 62 *triggerManagerMockPtr, storageMock); 63 } 64 65 static interfaces::JsonStorage::FilePath to_file_path(std::string name) 66 { 67 return interfaces::JsonStorage::FilePath( 68 std::to_string(std::hash<std::string>{}(name))); 69 } 70 71 template <class T> 72 static T getProperty(const std::string& path, const std::string& property) 73 { 74 return DbusEnvironment::getProperty<T>(path, Trigger::triggerIfaceName, 75 property); 76 } 77 78 template <class T> 79 static boost::system::error_code setProperty(const std::string& path, 80 const std::string& property, 81 const T& newValue) 82 { 83 return DbusEnvironment::setProperty<T>(path, Trigger::triggerIfaceName, 84 property, newValue); 85 } 86 87 boost::system::error_code deleteTrigger(const std::string& path) 88 { 89 std::promise<boost::system::error_code> methodPromise; 90 DbusEnvironment::getBus()->async_method_call( 91 [&methodPromise](boost::system::error_code ec) { 92 methodPromise.set_value(ec); 93 }, 94 DbusEnvironment::serviceName(), path, Trigger::deleteIfaceName, 95 "Delete"); 96 return DbusEnvironment::waitForFuture(methodPromise.get_future()); 97 } 98 }; 99 100 TEST_F(TestTrigger, checkIfPropertiesAreSet) 101 { 102 EXPECT_THAT(getProperty<std::string>(sut->getPath(), "Name"), 103 Eq(triggerParams.name())); 104 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), Eq(true)); 105 EXPECT_THAT( 106 getProperty<std::vector<std::string>>(sut->getPath(), "TriggerActions"), 107 Eq(triggerParams.triggerActions())); 108 EXPECT_THAT((getProperty<SensorsInfo>(sut->getPath(), "Sensors")), 109 Eq(utils::fromLabeledSensorsInfo(triggerParams.sensors()))); 110 EXPECT_THAT( 111 getProperty<std::vector<std::string>>(sut->getPath(), "ReportNames"), 112 Eq(triggerParams.reportNames())); 113 EXPECT_THAT( 114 getProperty<TriggerThresholdParams>(sut->getPath(), "Thresholds"), 115 Eq(std::visit(utils::FromLabeledThresholdParamConversion(), 116 triggerParams.thresholdParams()))); 117 } 118 119 TEST_F(TestTrigger, setPropertyNameToCorrectValue) 120 { 121 std::string name = "custom name 1234 %^#5"; 122 EXPECT_THAT(setProperty(sut->getPath(), "Name", name), 123 Eq(boost::system::errc::success)); 124 EXPECT_THAT(getProperty<std::string>(sut->getPath(), "Name"), Eq(name)); 125 } 126 127 TEST_F(TestTrigger, checkIfNumericCoversionsAreGood) 128 { 129 const auto& labeledParamsBase = 130 std::get<std::vector<numeric::LabeledThresholdParam>>( 131 triggerParams.thresholdParams()); 132 const auto paramsToCheck = 133 std::visit(utils::FromLabeledThresholdParamConversion(), 134 triggerParams.thresholdParams()); 135 const auto labeledParamsToCheck = 136 std::get<std::vector<numeric::LabeledThresholdParam>>(std::visit( 137 utils::ToLabeledThresholdParamConversion(), paramsToCheck)); 138 139 for (const auto& [tocheck, base] : 140 boost::combine(labeledParamsToCheck, labeledParamsBase)) 141 { 142 EXPECT_THAT(tocheck.at_label<utils::tstring::Type>(), 143 Eq(base.at_label<utils::tstring::Type>())); 144 EXPECT_THAT(tocheck.at_label<utils::tstring::Direction>(), 145 Eq(base.at_label<utils::tstring::Direction>())); 146 EXPECT_THAT(tocheck.at_label<utils::tstring::DwellTime>(), 147 Eq(base.at_label<utils::tstring::DwellTime>())); 148 EXPECT_THAT(tocheck.at_label<utils::tstring::ThresholdValue>(), 149 Eq(base.at_label<utils::tstring::ThresholdValue>())); 150 } 151 } 152 153 TEST_F(TestTrigger, checkIfDiscreteCoversionsAreGood) 154 { 155 const auto& labeledParamsBase = 156 std::get<std::vector<discrete::LabeledThresholdParam>>( 157 triggerDiscreteParams.thresholdParams()); 158 const auto paramsToCheck = 159 std::visit(utils::FromLabeledThresholdParamConversion(), 160 triggerDiscreteParams.thresholdParams()); 161 const auto labeledParamsToCheck = 162 std::get<std::vector<discrete::LabeledThresholdParam>>(std::visit( 163 utils::ToLabeledThresholdParamConversion(), paramsToCheck)); 164 165 for (const auto& [tocheck, base] : 166 boost::combine(labeledParamsToCheck, labeledParamsBase)) 167 { 168 EXPECT_THAT(tocheck.at_label<utils::tstring::UserId>(), 169 Eq(base.at_label<utils::tstring::UserId>())); 170 EXPECT_THAT(tocheck.at_label<utils::tstring::Severity>(), 171 Eq(base.at_label<utils::tstring::Severity>())); 172 EXPECT_THAT(tocheck.at_label<utils::tstring::DwellTime>(), 173 Eq(base.at_label<utils::tstring::DwellTime>())); 174 EXPECT_THAT(tocheck.at_label<utils::tstring::ThresholdValue>(), 175 Eq(base.at_label<utils::tstring::ThresholdValue>())); 176 } 177 } 178 179 TEST_F(TestTrigger, deleteTrigger) 180 { 181 EXPECT_CALL(storageMock, remove(to_file_path(sut->getId()))); 182 EXPECT_CALL(*triggerManagerMockPtr, removeTrigger(sut.get())); 183 auto ec = deleteTrigger(sut->getPath()); 184 EXPECT_THAT(ec, Eq(boost::system::errc::success)); 185 } 186 187 TEST_F(TestTrigger, deletingNonExistingTriggerReturnInvalidRequestDescriptor) 188 { 189 auto ec = deleteTrigger(Trigger::triggerDir + "NonExisting"s); 190 EXPECT_THAT(ec.value(), Eq(EBADR)); 191 } 192 193 TEST_F(TestTrigger, settingPersistencyToFalseRemovesTriggerFromStorage) 194 { 195 EXPECT_CALL(storageMock, remove(to_file_path(sut->getId()))); 196 197 bool persistent = false; 198 EXPECT_THAT(setProperty(sut->getPath(), "Persistent", persistent), 199 Eq(boost::system::errc::success)); 200 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), 201 Eq(persistent)); 202 } 203 204 class TestTriggerErrors : public TestTrigger 205 { 206 public: 207 void SetUp() override 208 {} 209 210 nlohmann::json storedConfiguration; 211 }; 212 213 TEST_F(TestTriggerErrors, exceptionDuringTriggerStoreDisablesPersistency) 214 { 215 EXPECT_CALL(storageMock, store(_, _)) 216 .WillOnce(Throw(std::runtime_error("Generic error!"))); 217 218 sut = makeTrigger(triggerParams); 219 220 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistent"), Eq(false)); 221 } 222 223 TEST_F(TestTriggerErrors, creatingTriggerThrowsExceptionWhenIdIsInvalid) 224 { 225 EXPECT_CALL(storageMock, store(_, _)).Times(0); 226 227 EXPECT_THROW(makeTrigger(triggerParams.id("inv?lidId")), 228 sdbusplus::exception::SdBusError); 229 } 230 231 class TestTriggerStore : public TestTrigger 232 { 233 public: 234 nlohmann::json storedConfiguration; 235 nlohmann::json storedDiscreteConfiguration; 236 std::unique_ptr<Trigger> sutDiscrete; 237 238 void SetUp() override 239 { 240 ON_CALL(storageMock, store(_, _)) 241 .WillByDefault(SaveArg<1>(&storedConfiguration)); 242 sut = makeTrigger(triggerParams); 243 244 ON_CALL(storageMock, store(_, _)) 245 .WillByDefault(SaveArg<1>(&storedDiscreteConfiguration)); 246 sutDiscrete = makeTrigger(triggerDiscreteParams); 247 } 248 }; 249 250 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerVersion) 251 { 252 ASSERT_THAT(storedConfiguration.at("Version"), Eq(expectedTriggerVersion)); 253 } 254 255 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerId) 256 { 257 ASSERT_THAT(storedConfiguration.at("Id"), Eq(triggerParams.id())); 258 } 259 260 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerName) 261 { 262 ASSERT_THAT(storedConfiguration.at("Name"), Eq(triggerParams.name())); 263 } 264 265 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerTriggerActions) 266 { 267 ASSERT_THAT(storedConfiguration.at("TriggerActions"), 268 Eq(triggerParams.triggerActions())); 269 } 270 271 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerReportNames) 272 { 273 ASSERT_THAT(storedConfiguration.at("ReportNames"), 274 Eq(triggerParams.reportNames())); 275 } 276 277 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerSensors) 278 { 279 nlohmann::json expectedItem; 280 expectedItem["service"] = "service1"; 281 expectedItem["sensorPath"] = 282 "/xyz/openbmc_project/sensors/temperature/BMC_Temp"; 283 expectedItem["sensorMetadata"] = "metadata1"; 284 285 ASSERT_THAT(storedConfiguration.at("Sensors"), ElementsAre(expectedItem)); 286 } 287 288 TEST_F(TestTriggerStore, settingPersistencyToTrueStoresTriggerThresholdParams) 289 { 290 nlohmann::json expectedItem0; 291 expectedItem0["type"] = 0; 292 expectedItem0["dwellTime"] = 10; 293 expectedItem0["direction"] = 1; 294 expectedItem0["thresholdValue"] = 0.5; 295 296 nlohmann::json expectedItem1; 297 expectedItem1["type"] = 3; 298 expectedItem1["dwellTime"] = 10; 299 expectedItem1["direction"] = 2; 300 expectedItem1["thresholdValue"] = 90.2; 301 302 ASSERT_THAT(storedConfiguration.at("ThresholdParamsDiscriminator"), Eq(0)); 303 ASSERT_THAT(storedConfiguration.at("ThresholdParams"), 304 ElementsAre(expectedItem0, expectedItem1)); 305 } 306 307 TEST_F(TestTriggerStore, 308 settingPersistencyToTrueStoresDiscreteTriggerThresholdParams) 309 { 310 nlohmann::json expectedItem0; 311 expectedItem0["userId"] = "userId"; 312 expectedItem0["severity"] = discrete::Severity::warning; 313 expectedItem0["dwellTime"] = 10; 314 expectedItem0["thresholdValue"] = "15.2"; 315 316 nlohmann::json expectedItem1; 317 expectedItem1["userId"] = "userId_2"; 318 expectedItem1["severity"] = discrete::Severity::critical; 319 expectedItem1["dwellTime"] = 5; 320 expectedItem1["thresholdValue"] = "32.7"; 321 322 ASSERT_THAT(storedDiscreteConfiguration.at("ThresholdParamsDiscriminator"), 323 Eq(1)); 324 ASSERT_THAT(storedDiscreteConfiguration.at("ThresholdParams"), 325 ElementsAre(expectedItem0, expectedItem1)); 326 } 327