1 #include "dbus_environment.hpp" 2 #include "helpers.hpp" 3 #include "mocks/json_storage_mock.hpp" 4 #include "mocks/trigger_factory_mock.hpp" 5 #include "mocks/trigger_mock.hpp" 6 #include "params/trigger_params.hpp" 7 #include "trigger.hpp" 8 #include "trigger_manager.hpp" 9 #include "utils/conversion_trigger.hpp" 10 #include "utils/transform.hpp" 11 12 using namespace testing; 13 14 class TestTriggerManager : public Test 15 { 16 public: 17 std::pair<boost::system::error_code, std::string> 18 addTrigger(const TriggerParams& params) 19 { 20 const auto sensorInfos = 21 utils::fromLabeledSensorsInfo(params.sensors()); 22 23 std::promise<std::pair<boost::system::error_code, std::string>> 24 addTriggerPromise; 25 DbusEnvironment::getBus()->async_method_call( 26 [&addTriggerPromise](boost::system::error_code ec, 27 const std::string& path) { 28 addTriggerPromise.set_value({ec, path}); 29 }, 30 DbusEnvironment::serviceName(), TriggerManager::triggerManagerPath, 31 TriggerManager::triggerManagerIfaceName, "AddTrigger", 32 params.name(), params.triggerActions(), sensorInfos, 33 params.reportNames(), 34 std::visit(utils::FromLabeledThresholdParamConversion(), 35 params.thresholdParams())); 36 return DbusEnvironment::waitForFuture(addTriggerPromise.get_future()); 37 } 38 39 std::unique_ptr<TriggerManager> makeTriggerManager() 40 { 41 return std::make_unique<TriggerManager>( 42 std::move(triggerFactoryMockPtr), std::move(storageMockPtr), 43 DbusEnvironment::getObjServer()); 44 } 45 46 void SetUp() override 47 { 48 sut = makeTriggerManager(); 49 } 50 51 std::unique_ptr<StorageMock> storageMockPtr = 52 std::make_unique<NiceMock<StorageMock>>(); 53 StorageMock& storageMock = *storageMockPtr; 54 std::unique_ptr<TriggerFactoryMock> triggerFactoryMockPtr = 55 std::make_unique<NiceMock<TriggerFactoryMock>>(); 56 TriggerFactoryMock& triggerFactoryMock = *triggerFactoryMockPtr; 57 std::unique_ptr<TriggerMock> triggerMockPtr = 58 std::make_unique<NiceMock<TriggerMock>>(TriggerParams().name()); 59 TriggerMock& triggerMock = *triggerMockPtr; 60 std::unique_ptr<TriggerManager> sut; 61 MockFunction<void(std::string)> checkPoint; 62 }; 63 64 TEST_F(TestTriggerManager, addTrigger) 65 { 66 triggerFactoryMock.expectMake(TriggerParams(), Ref(*sut), Ref(storageMock)) 67 .WillOnce(Return(ByMove(std::move(triggerMockPtr)))); 68 69 auto [ec, path] = addTrigger(TriggerParams()); 70 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 71 EXPECT_THAT(path, Eq(triggerMock.getPath())); 72 } 73 74 TEST_F(TestTriggerManager, addTriggerWithDiscreteThresholds) 75 { 76 TriggerParams triggerParamsDiscrete; 77 auto thresholds = std::vector<discrete::LabeledThresholdParam>{ 78 {"discrete_threshold1", discrete::Severity::ok, 10, "11.0"}, 79 {"discrete_threshold2", discrete::Severity::warning, 10, "12.0"}, 80 {"discrete_threshold3", discrete::Severity::critical, 10, "13.0"}}; 81 82 triggerParamsDiscrete.thresholdParams(thresholds); 83 84 auto [ec, path] = addTrigger(triggerParamsDiscrete); 85 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 86 EXPECT_THAT(path, Eq(triggerMock.getPath())); 87 } 88 89 TEST_F(TestTriggerManager, addDiscreteTriggerWithoutThresholds) 90 { 91 TriggerParams triggerParamsDiscrete; 92 auto thresholds = std::vector<discrete::LabeledThresholdParam>(); 93 94 triggerParamsDiscrete.thresholdParams(thresholds); 95 96 auto [ec, path] = addTrigger(triggerParamsDiscrete); 97 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 98 EXPECT_THAT(path, Eq(triggerMock.getPath())); 99 } 100 101 TEST_F(TestTriggerManager, DISABLED_failToAddTriggerTwice) 102 { 103 triggerFactoryMock.expectMake(TriggerParams(), Ref(*sut), Ref(storageMock)) 104 .WillOnce(Return(ByMove(std::move(triggerMockPtr)))); 105 106 addTrigger(TriggerParams()); 107 108 auto [ec, path] = addTrigger(TriggerParams()); 109 EXPECT_THAT(ec.value(), Eq(boost::system::errc::file_exists)); 110 EXPECT_THAT(path, Eq(std::string())); 111 } 112 113 TEST_F(TestTriggerManager, DISABLED_failToAddTriggerWhenMaxTriggerIsReached) 114 { 115 auto triggerParams = TriggerParams(); 116 117 triggerFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 118 .Times(TriggerManager::maxTriggers); 119 120 for (size_t i = 0; i < TriggerManager::maxTriggers; i++) 121 { 122 triggerParams.name(TriggerParams().name() + std::to_string(i)); 123 124 auto [ec, path] = addTrigger(triggerParams); 125 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 126 } 127 128 triggerParams.name(TriggerParams().name() + 129 std::to_string(TriggerManager::maxTriggers)); 130 auto [ec, path] = addTrigger(triggerParams); 131 EXPECT_THAT(ec.value(), Eq(boost::system::errc::too_many_files_open)); 132 EXPECT_THAT(path, Eq(std::string())); 133 } 134 135 TEST_F(TestTriggerManager, removeTrigger) 136 { 137 { 138 InSequence seq; 139 triggerFactoryMock 140 .expectMake(TriggerParams(), Ref(*sut), Ref(storageMock)) 141 .WillOnce(Return(ByMove(std::move(triggerMockPtr)))); 142 EXPECT_CALL(triggerMock, Die()); 143 EXPECT_CALL(checkPoint, Call("end")); 144 } 145 146 addTrigger(TriggerParams()); 147 sut->removeTrigger(&triggerMock); 148 checkPoint.Call("end"); 149 } 150 151 TEST_F(TestTriggerManager, removingTriggerThatIsNotInContainerHasNoEffect) 152 { 153 { 154 InSequence seq; 155 EXPECT_CALL(checkPoint, Call("end")); 156 EXPECT_CALL(triggerMock, Die()); 157 } 158 159 sut->removeTrigger(&triggerMock); 160 checkPoint.Call("end"); 161 } 162 163 TEST_F(TestTriggerManager, removingSameTriggerTwiceHasNoSideEffect) 164 { 165 { 166 InSequence seq; 167 triggerFactoryMock 168 .expectMake(TriggerParams(), Ref(*sut), Ref(storageMock)) 169 .WillOnce(Return(ByMove(std::move(triggerMockPtr)))); 170 EXPECT_CALL(triggerMock, Die()); 171 EXPECT_CALL(checkPoint, Call("end")); 172 } 173 174 addTrigger(TriggerParams()); 175 sut->removeTrigger(&triggerMock); 176 sut->removeTrigger(&triggerMock); 177 checkPoint.Call("end"); 178 } 179 180 class TestTriggerManagerStorage : public TestTriggerManager 181 { 182 public: 183 using FilePath = interfaces::JsonStorage::FilePath; 184 using DirectoryPath = interfaces::JsonStorage::DirectoryPath; 185 186 void SetUp() override 187 { 188 ON_CALL(storageMock, list()) 189 .WillByDefault(Return(std::vector<FilePath>{ 190 {FilePath("trigger1")}, {FilePath("trigger2")}})); 191 192 ON_CALL(storageMock, load(FilePath("trigger1"))) 193 .WillByDefault(InvokeWithoutArgs([this] { return data1; })); 194 195 data2["Name"] = "Trigger2"; 196 ON_CALL(storageMock, load(FilePath("trigger2"))) 197 .WillByDefault(InvokeWithoutArgs([this] { return data2; })); 198 } 199 200 nlohmann::json data1 = nlohmann::json{ 201 {"Version", Trigger::triggerVersion}, 202 {"Name", TriggerParams().name()}, 203 {"ThresholdParamsDiscriminator", 204 TriggerParams().thresholdParams().index()}, 205 {"TriggerActions", TriggerParams().triggerActions()}, 206 {"ThresholdParams", utils::labeledThresholdParamsToJson( 207 TriggerParams().thresholdParams())}, 208 {"ReportNames", TriggerParams().reportNames()}, 209 {"Sensors", TriggerParams().sensors()}}; 210 211 nlohmann::json data2 = data1; 212 }; 213 214 TEST_F(TestTriggerManagerStorage, triggerManagerCtorAddTriggerFromStorage) 215 { 216 triggerFactoryMock.expectMake(TriggerParams(), _, Ref(storageMock)); 217 triggerFactoryMock.expectMake(TriggerParams().name("Trigger2"), _, 218 Ref(storageMock)); 219 EXPECT_CALL(storageMock, remove(_)).Times(0); 220 221 sut = makeTriggerManager(); 222 } 223 224 TEST_F(TestTriggerManagerStorage, 225 triggerManagerCtorRemoveDiscreteTriggerFromStorage) 226 { 227 LabeledTriggerThresholdParams thresholdParams = 228 std::vector<discrete::LabeledThresholdParam>{ 229 {"userId1", discrete::Severity::warning, 15, "10.0"}, 230 {"userId2", discrete::Severity::critical, 5, "20.0"}}; 231 232 data1["ThresholdParamsDiscriminator"] = thresholdParams.index(); 233 234 data1["ThresholdParams"] = 235 utils::labeledThresholdParamsToJson(thresholdParams); 236 237 EXPECT_CALL(storageMock, remove(FilePath("trigger1"))).Times(0); 238 239 sut = makeTriggerManager(); 240 } 241 242 TEST_F(TestTriggerManagerStorage, 243 triggerManagerCtorRemoveDiscreteTriggerFromStorage2) 244 { 245 data1["IsDiscrete"] = true; 246 247 EXPECT_CALL(storageMock, remove(FilePath("trigger1"))).Times(0); 248 249 sut = makeTriggerManager(); 250 } 251 252 TEST_F(TestTriggerManagerStorage, 253 triggerManagerCtorAddProperRemoveInvalidTriggerFromStorage) 254 { 255 data1["Version"] = Trigger::triggerVersion - 1; 256 257 triggerFactoryMock.expectMake(TriggerParams().name("Trigger2"), _, 258 Ref(storageMock)); 259 EXPECT_CALL(storageMock, remove(FilePath("trigger1"))); 260 261 sut = makeTriggerManager(); 262 } 263