API
 
Loading...
Searching...
No Matches
indiCompRuleConfig_test.cpp
Go to the documentation of this file.
1/** \file indiCompRuleConfig_test.cpp
2 * \brief Catch2 tests for stateRuleEngine rule-configuration helpers.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup stateRuleEngine_files
6 */
7
8#include "../../../tests/testXWC.hpp"
9
10#include "../indiCompRuleConfig.hpp"
11
12namespace libXWCTest
13{
14
15/** \defgroup stateRuleEngine_unit_test stateRuleEngine Unit Tests
16 * \brief Unit tests for the stateRuleEngine application.
17 *
18 * \ingroup application_unit_test
19 */
20
21/// Namespace for `stateRuleEngine` unit tests.
22/** \ingroup stateRuleEngine_unit_test
23 */
24namespace stateRuleEngineTest
25{
26
27SCENARIO( "configuring basic rules", "[stateRuleEngine::ruleConfig]" )
28{
29 // clang-format off
30 #ifdef STATERULEENGINE_TEST_DOXYGEN_REF
31 loadRuleConfig( *(indiRuleMaps *)nullptr, *(std::map<std::string, ruleRuleKeys> *)nullptr, *(mx::app::appConfigurator *)nullptr );
32 #endif
33 // clang-format on
34
35 GIVEN( "single rules in a config file" )
36 {
37 WHEN( "a numValRule using defaults" )
38 {
39 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
40 { "rule1", "rule1", "rule1", "rule1" },
41 { "ruleType", "property", "element", "target" },
42 { "numVal", "dev.prop", "elem", "1.234" } );
43 mx::app::appConfigurator config;
44 config.readConfig( "/tmp/ruleConfig_test.conf" );
45
46 indiRuleMaps maps;
47 std::map<std::string, ruleRuleKeys> rrkMap;
48
49 loadRuleConfig( maps, rrkMap, config );
50
51 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
52 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
53 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
54 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
55 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->target() == 1.234 );
56 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->tol() == 1e-6 );
57 }
58
59 WHEN( "a numValRule changing defaults" )
60 {
61 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
62 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
63 { "ruleType", "priority", "comp", "property", "element", "target", "tol" },
64 { "numVal", "warning", "GtEq", "dev.prop", "elem", "1.234", "1e-8" } );
65 mx::app::appConfigurator config;
66 config.readConfig( "/tmp/ruleConfig_test.conf" );
67
68 indiRuleMaps maps;
69 std::map<std::string, ruleRuleKeys> rrkMap;
70
71 loadRuleConfig( maps, rrkMap, config );
72
73 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::warning );
74 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::GtEq );
75 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
76 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
77 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->target() == 1.234 );
78 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->tol() == 1e-8 );
79 }
80
81 WHEN( "a txtValRule using defaults" )
82 {
83 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
84 { "rule1", "rule1", "rule1", "rule1" },
85 { "ruleType", "property", "element", "target" },
86 { "txtVal", "dev.prop", "elem", "xxx" } );
87 mx::app::appConfigurator config;
88 config.readConfig( "/tmp/ruleConfig_test.conf" );
89
90 indiRuleMaps maps;
91 std::map<std::string, ruleRuleKeys> rrkMap;
92
93 loadRuleConfig( maps, rrkMap, config );
94
95 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
96 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
97 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
98 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
99 REQUIRE( static_cast<txtValRule *>( maps.rules["rule1"] )->target() == "xxx" );
100 }
101
102 WHEN( "a txtValRule changing defaults" )
103 {
104 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
105 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
106 { "ruleType", "priority", "comp", "property", "element", "target" },
107 { "txtVal", "alert", "Neq", "dev.prop", "elem", "xxx" } );
108 mx::app::appConfigurator config;
109 config.readConfig( "/tmp/ruleConfig_test.conf" );
110
111 indiRuleMaps maps;
112 std::map<std::string, ruleRuleKeys> rrkMap;
113
114 loadRuleConfig( maps, rrkMap, config );
115
116 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::alert );
117 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Neq );
118 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
119 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
120 REQUIRE( static_cast<txtValRule *>( maps.rules["rule1"] )->target() == "xxx" );
121 }
122
123 WHEN( "a swValRule using defaults" )
124 {
125 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
126 { "rule1", "rule1", "rule1" },
127 { "ruleType", "property", "element" },
128 { "swVal", "dev.prop", "elem" } );
129 mx::app::appConfigurator config;
130 config.readConfig( "/tmp/ruleConfig_test.conf" );
131
132 indiRuleMaps maps;
133 std::map<std::string, ruleRuleKeys> rrkMap;
134
135 loadRuleConfig( maps, rrkMap, config );
136
137 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
138 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
139 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
140 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
141 REQUIRE( static_cast<swValRule *>( maps.rules["rule1"] )->target() == pcf::IndiElement::On );
142 }
143
144 WHEN( "a swValRule changing defaults" )
145 {
146 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
147 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
148 { "ruleType", "priority", "comp", "property", "element", "target" },
149 { "swVal", "info", "Neq", "dev.prop", "elem", "Off" } );
150 mx::app::appConfigurator config;
151 config.readConfig( "/tmp/ruleConfig_test.conf" );
152
153 indiRuleMaps maps;
154 std::map<std::string, ruleRuleKeys> rrkMap;
155
156 loadRuleConfig( maps, rrkMap, config );
157
158 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::info );
159 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Neq );
160 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
161 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
162 REQUIRE( static_cast<swValRule *>( maps.rules["rule1"] )->target() == pcf::IndiElement::Off );
163 }
164
165 WHEN( "a timeDiffRule using defaults" )
166 {
167 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
168 { "rule1", "rule1", "rule1", "rule1" },
169 { "ruleType", "property", "element", "target" },
170 { "timeDiff", "dev.prop", "elem", "1.234" } );
171 mx::app::appConfigurator config;
172 config.readConfig( "/tmp/ruleConfig_test.conf" );
173
174 indiRuleMaps maps;
175 std::map<std::string, ruleRuleKeys> rrkMap;
176
177 loadRuleConfig( maps, rrkMap, config );
178
179 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
180 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
181 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
182 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
183 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->target() == 1.234 );
184 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->tol() == 1e-6 );
185 }
186
187 WHEN( "a timeDiffRule changing defaults" )
188 {
189 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
190 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
191 { "ruleType", "priority", "comp", "property", "element", "target", "tol" },
192 { "timeDiff", "warning", "GtEq", "dev.prop", "elem", "1.234", "1e-8" } );
193 mx::app::appConfigurator config;
194 config.readConfig( "/tmp/ruleConfig_test.conf" );
195
196 indiRuleMaps maps;
197 std::map<std::string, ruleRuleKeys> rrkMap;
198
199 loadRuleConfig( maps, rrkMap, config );
200
201 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::warning );
202 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::GtEq );
203 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->property() == maps.props["dev.prop"] );
204 REQUIRE( static_cast<onePropRule *>( maps.rules["rule1"] )->element() == "elem" );
205 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->target() == 1.234 );
206 REQUIRE( static_cast<numValRule *>( maps.rules["rule1"] )->tol() == 1e-8 );
207 }
208
209 WHEN( "an elCompNumRule using defaults" )
210 {
211 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
212 { "rule1", "rule1", "rule1", "rule1", "rule1" },
213 { "ruleType", "property1", "element1", "property2", "element2" },
214 { "elCompNum", "dev1.prop1", "elem1", "dev2.prop2", "elem2" } );
215 mx::app::appConfigurator config;
216 config.readConfig( "/tmp/ruleConfig_test.conf" );
217
218 indiRuleMaps maps;
219 std::map<std::string, ruleRuleKeys> rrkMap;
220
221 loadRuleConfig( maps, rrkMap, config );
222
223 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
224 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
225 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property1() == maps.props["dev1.prop1"] );
226 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element1() == "elem1" );
227 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property2() == maps.props["dev2.prop2"] );
228 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element2() == "elem2" );
229 }
230
231 WHEN( "an elCompTxtRule using defaults" )
232 {
233 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
234 { "rule1", "rule1", "rule1", "rule1", "rule1" },
235 { "ruleType", "property1", "element1", "property2", "element2" },
236 { "elCompTxt", "dev1.prop1", "elem1", "dev2.prop2", "elem2" } );
237 mx::app::appConfigurator config;
238 config.readConfig( "/tmp/ruleConfig_test.conf" );
239
240 indiRuleMaps maps;
241 std::map<std::string, ruleRuleKeys> rrkMap;
242
243 loadRuleConfig( maps, rrkMap, config );
244
245 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
246 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
247 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property1() == maps.props["dev1.prop1"] );
248 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element1() == "elem1" );
249 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property2() == maps.props["dev2.prop2"] );
250 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element2() == "elem2" );
251 }
252
253 WHEN( "an elCompSwRule using defaults" )
254 {
255 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
256 { "rule1", "rule1", "rule1", "rule1", "rule1" },
257 { "ruleType", "property1", "element1", "property2", "element2" },
258 { "elCompSw", "dev1.prop1", "elem1", "dev2.prop2", "elem2" } );
259 mx::app::appConfigurator config;
260 config.readConfig( "/tmp/ruleConfig_test.conf" );
261
262 indiRuleMaps maps;
263 std::map<std::string, ruleRuleKeys> rrkMap;
264
265 loadRuleConfig( maps, rrkMap, config );
266
267 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
268 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
269 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property1() == maps.props["dev1.prop1"] );
270 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element1() == "elem1" );
271 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->property2() == maps.props["dev2.prop2"] );
272 REQUIRE( static_cast<twoPropRule *>( maps.rules["rule1"] )->element2() == "elem2" );
273 }
274
275 WHEN( "a ruleCompRule using defaults" )
276 {
277 // This requires configuring the other rules too
278 mx::app::writeConfigFile(
279 "/tmp/ruleConfig_test.conf",
280 { "ruleA", "ruleA", "ruleA", "rule3", "rule3", "rule3", "rule3", "rule4", "rule4", "rule4", "rule4" },
281 { "ruleType",
282 "rule1",
283 "rule2",
284 "ruleType",
285 "property",
286 "element",
287 "target",
288 "ruleType",
289 "property",
290 "element",
291 "target" },
292 { "ruleComp",
293 "rule3",
294 "rule4",
295 "txtVal",
296 "dev3.propQ",
297 "elem",
298 "xxx",
299 "txtVal",
300 "dev4.propR",
301 "mele",
302 "yyy" } );
303 mx::app::appConfigurator config;
304 config.readConfig( "/tmp/ruleConfig_test.conf" );
305
306 indiRuleMaps maps;
307 std::map<std::string, ruleRuleKeys> rrkMap;
308
309 loadRuleConfig( maps, rrkMap, config );
310 finalizeRuleValRules( maps, rrkMap );
311
312 REQUIRE( maps.rules["ruleA"]->priority() == rulePriority::none );
313 REQUIRE( maps.rules["ruleA"]->comparison() == ruleComparison::And );
314
315 REQUIRE( static_cast<ruleCompRule *>( maps.rules["ruleA"] )->rule1() == maps.rules["rule3"] );
316 REQUIRE( static_cast<ruleCompRule *>( maps.rules["ruleA"] )->rule2() == maps.rules["rule4"] );
317 }
318
319 WHEN( "a multiSwitchComboRule using defaults" )
320 {
321 mx::app::writeConfigFile(
322 "/tmp/ruleConfig_test.conf",
323 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
324 { "ruleType", "numSwitches", "property1", "property2", "format", "targetProperty" },
325 { "multiSwitchCombo", "2", "dev1.prop1", "dev2.prop2", "{}-{}", "dev3.prop3" } );
326 mx::app::appConfigurator config;
327 config.readConfig( "/tmp/ruleConfig_test.conf" );
328
329 indiRuleMaps maps;
330 std::map<std::string, ruleRuleKeys> rrkMap;
331
332 loadRuleConfig( maps, rrkMap, config );
333
334 multiSwitchComboRule *mscr = dynamic_cast<multiSwitchComboRule *>( maps.rules["rule1"] );
335
336 REQUIRE( mscr != nullptr );
337 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::none );
338 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Neq );
339 REQUIRE( mscr->ruleName() == "rule1" );
340 REQUIRE( mscr->numSwitches() == 2 );
341 REQUIRE( mscr->property( 0 ) == maps.props["dev1.prop1"] );
342 REQUIRE( mscr->propertyKey( 0 ) == "dev1.prop1" );
343 REQUIRE( mscr->property( 1 ) == maps.props["dev2.prop2"] );
344 REQUIRE( mscr->propertyKey( 1 ) == "dev2.prop2" );
345 REQUIRE( mscr->format() == "{}-{}" );
346 REQUIRE( mscr->targetProperty() == maps.props["dev3.prop3"] );
347 REQUIRE( mscr->targetPropertyKey() == "dev3.prop3" );
348 }
349
350 WHEN( "a multiSwitchComboRule changing defaults" )
351 {
352 mx::app::writeConfigFile(
353 "/tmp/ruleConfig_test.conf",
354 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
355 { "ruleType", "priority", "comp", "numSwitches", "property1", "property2", "format", "targetProperty" },
356 { "multiSwitchCombo", "warning", "Eq", "2", "dev1.prop1", "dev2.prop2", "\"{}:{}\"", "dev3.prop3" } );
357 mx::app::appConfigurator config;
358 config.readConfig( "/tmp/ruleConfig_test.conf" );
359
360 indiRuleMaps maps;
361 std::map<std::string, ruleRuleKeys> rrkMap;
362
363 loadRuleConfig( maps, rrkMap, config );
364
365 multiSwitchComboRule *mscr = dynamic_cast<multiSwitchComboRule *>( maps.rules["rule1"] );
366
367 REQUIRE( mscr != nullptr );
368 REQUIRE( maps.rules["rule1"]->priority() == rulePriority::warning );
369 REQUIRE( maps.rules["rule1"]->comparison() == ruleComparison::Eq );
370 REQUIRE( mscr->format() == "{}:{}" );
371 }
372 }
373}
374
375SCENARIO( "configuring the demo", "[stateRuleEngine::ruleConfig]" )
376{
377 GIVEN( "the demo" )
378 {
379 WHEN( "the demo as writen" )
380 {
381 std::ofstream fout;
382 fout.open( "/tmp/ruleConfig_test.conf" );
383 fout << "[fwfpm-fpm]\n";
384 fout << "ruleType=swVal\n";
385 fout << "priority=none\n";
386 fout << "comp=Eq\n";
387 fout << "property=fwfpm.filterName\n";
388 fout << "element=fpm\n";
389 fout << "target=On\n";
390 fout << "\n";
391 fout << "[fwfpm-READY]\n";
392 fout << "ruleType=txtVal\n";
393 fout << "property=fwfpm.fsm_state\n";
394 fout << "element=state\n";
395 fout << "target=READY\n";
396 fout << "\n";
397 fout << "[fwfpm-fpm-READY]\n";
398 fout << "ruleType=ruleComp\n";
399 fout << "comp=And\n";
400 fout << "rule1=fwfpm-READY\n";
401 fout << "rule2=fwfpm-fpm\n";
402 fout << "\n";
403 fout << "[fwfpm-stagesci1-neq]\n";
404 fout << "ruleType=elCompSw\n";
405 fout << "property1=fwfpm.filterName\n";
406 fout << "element1=fpm\n";
407 fout << "property2=stagesci1.presetName\n";
408 fout << "element2=fpm\n";
409 fout << "comp=Neq\n";
410 fout << "\n";
411 fout << "[fwfpm-fpm-stagesci-fpm]\n";
412 fout << "ruleType=ruleComp\n";
413 fout << "priority=caution\n";
414 fout << "rule1=fwfpm-fpm-READY\n";
415 fout << "rule2=fwfpm-stagesci1-neq\n";
416 fout << "comp=And\n";
417 fout.close();
418
419 mx::app::appConfigurator config;
420 config.readConfig( "/tmp/ruleConfig_test.conf" );
421
422 indiRuleMaps maps;
423 std::map<std::string, ruleRuleKeys> rrkMap;
424
425 loadRuleConfig( maps, rrkMap, config );
426 finalizeRuleValRules( maps, rrkMap );
427
428 ruleCompRule *rcr = dynamic_cast<ruleCompRule *>( maps.rules["fwfpm-fpm-stagesci-fpm"] );
429
430 const indiCompRule *r1 = rcr->rule1();
431 const indiCompRule *r2 = rcr->rule2();
432
433 REQUIRE( r1 == maps.rules["fwfpm-fpm-READY"] );
434 REQUIRE( r2 == maps.rules["fwfpm-stagesci1-neq"] );
435 }
436 }
437}
438
439SCENARIO( "rule configurations with errors", "[stateRuleEngine::ruleConfig]" )
440{
441 GIVEN( "single rules in a config file" )
442 {
443 WHEN( "no rule sections given" )
444 {
445 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf", { "rule1" }, { "property" }, { "dev.prop" } );
446 mx::app::appConfigurator config;
447 // By adding this to the config list we remove if from the "unused" so it won't get detected by
448 // loadRuleConfig
449 config.add( "rule1.prop", "", "", argType::Required, "rule1", "property", false, "string", "" );
450 config.readConfig( "/tmp/ruleConfig_test.conf" );
451
452 indiRuleMaps maps;
453 std::map<std::string, ruleRuleKeys> rrkMap;
454
455 bool caught = false;
456 try
457 {
458 loadRuleConfig( maps, rrkMap, config );
459 }
460 catch( const mx::exception<mx::verbose::d> &e )
461 {
462 caught = true;
463 }
464 catch( ... )
465 {
466 }
467
468 REQUIRE( caught == true );
469 }
470
471 WHEN( "an invalid rule" )
472 {
473 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
474 { "rule1", "rule1", "rule1", "rule1" },
475 { "ruleType", "property", "element", "target" },
476 { "badRule", "dev.prop", "elem", "1.234" } );
477 mx::app::appConfigurator config;
478 config.readConfig( "/tmp/ruleConfig_test.conf" );
479
480 indiRuleMaps maps;
481 std::map<std::string, ruleRuleKeys> rrkMap;
482
483 bool caught = false;
484 try
485 {
486 loadRuleConfig( maps, rrkMap, config );
487 }
488 catch( const mx::exception<mx::verbose::d> &e )
489 {
490 caught = true;
491 }
492 catch( ... )
493 {
494 }
495
496 REQUIRE( caught == true );
497 }
498 }
499 GIVEN( "ruleComp rules with errors" )
500 {
501 WHEN( "a ruleCompRule with rule1 not found" )
502 {
503 // This requires configuring the other rules too
504 mx::app::writeConfigFile(
505 "/tmp/ruleConfig_test.conf",
506 { "ruleA", "ruleA", "ruleA", "rule3", "rule3", "rule3", "rule3", "rule4", "rule4", "rule4", "rule4" },
507 { "ruleType",
508 "rule1",
509 "rule2",
510 "ruleType",
511 "property",
512 "element",
513 "target",
514 "ruleType",
515 "property",
516 "element",
517 "target" },
518 { "ruleComp",
519 "rule6",
520 "rule4",
521 "txtVal",
522 "dev3.propQ",
523 "elem",
524 "xxx",
525 "txtVal",
526 "dev4.propR",
527 "mele",
528 "yyy" } );
529 mx::app::appConfigurator config;
530 config.readConfig( "/tmp/ruleConfig_test.conf" );
531
532 indiRuleMaps maps;
533 std::map<std::string, ruleRuleKeys> rrkMap;
534
535 bool caught = false;
536 try
537 {
538 loadRuleConfig( maps, rrkMap, config );
539 finalizeRuleValRules( maps, rrkMap );
540 }
541 catch( ... )
542 {
543 caught = true;
544 }
545
546 REQUIRE( caught == true );
547 }
548
549 WHEN( "a ruleCompRule with rule1 self-referencing" )
550 {
551 // This requires configuring the other rules too
552 mx::app::writeConfigFile(
553 "/tmp/ruleConfig_test.conf",
554 { "ruleA", "ruleA", "ruleA", "rule3", "rule3", "rule3", "rule3", "rule4", "rule4", "rule4", "rule4" },
555 { "ruleType",
556 "rule1",
557 "rule2",
558 "ruleType",
559 "property",
560 "element",
561 "target",
562 "ruleType",
563 "property",
564 "element",
565 "target" },
566 { "ruleComp",
567 "ruleA",
568 "rule4",
569 "txtVal",
570 "dev3.propQ",
571 "elem",
572 "xxx",
573 "txtVal",
574 "dev4.propR",
575 "mele",
576 "yyy" } );
577 mx::app::appConfigurator config;
578 config.readConfig( "/tmp/ruleConfig_test.conf" );
579
580 indiRuleMaps maps;
581 std::map<std::string, ruleRuleKeys> rrkMap;
582
583 bool caught = false;
584 try
585 {
586 loadRuleConfig( maps, rrkMap, config );
587 }
588 catch( ... )
589 {
590 caught = true;
591 }
592
593 REQUIRE( caught == true );
594 }
595 WHEN( "a ruleCompRule with rule2 not found" )
596 {
597 // This requires configuring the other rules too
598 mx::app::writeConfigFile(
599 "/tmp/ruleConfig_test.conf",
600 { "ruleA", "ruleA", "ruleA", "rule3", "rule3", "rule3", "rule3", "rule4", "rule4", "rule4", "rule4" },
601 { "ruleType",
602 "rule1",
603 "rule2",
604 "ruleType",
605 "property",
606 "element",
607 "target",
608 "ruleType",
609 "property",
610 "element",
611 "target" },
612 { "ruleComp",
613 "rule3",
614 "rule5",
615 "txtVal",
616 "dev3.propQ",
617 "elem",
618 "xxx",
619 "txtVal",
620 "dev4.propR",
621 "mele",
622 "yyy" } );
623 mx::app::appConfigurator config;
624 config.readConfig( "/tmp/ruleConfig_test.conf" );
625
626 indiRuleMaps maps;
627 std::map<std::string, ruleRuleKeys> rrkMap;
628
629 bool caught = false;
630 try
631 {
632 loadRuleConfig( maps, rrkMap, config );
633 finalizeRuleValRules( maps, rrkMap );
634 }
635 catch( ... )
636 {
637 caught = true;
638 }
639
640 REQUIRE( caught == true );
641 }
642
643 WHEN( "a ruleCompRule with rule2 self-referencing" )
644 {
645 // This requires configuring the other rules too
646 mx::app::writeConfigFile(
647 "/tmp/ruleConfig_test.conf",
648 { "ruleA", "ruleA", "ruleA", "rule3", "rule3", "rule3", "rule3", "rule4", "rule4", "rule4", "rule4" },
649 { "ruleType",
650 "rule1",
651 "rule2",
652 "ruleType",
653 "property",
654 "element",
655 "target",
656 "ruleType",
657 "property",
658 "element",
659 "target" },
660 { "ruleComp",
661 "rule3",
662 "ruleA",
663 "txtVal",
664 "dev3.propQ",
665 "elem",
666 "xxx",
667 "txtVal",
668 "dev4.propR",
669 "mele",
670 "yyy" } );
671 mx::app::appConfigurator config;
672 config.readConfig( "/tmp/ruleConfig_test.conf" );
673
674 indiRuleMaps maps;
675 std::map<std::string, ruleRuleKeys> rrkMap;
676
677 bool caught = false;
678 try
679 {
680 loadRuleConfig( maps, rrkMap, config );
681 finalizeRuleValRules( maps, rrkMap );
682 }
683 catch( ... )
684 {
685 caught = true;
686 }
687
688 REQUIRE( caught == true );
689 }
690 }
691
692 GIVEN( "multiSwitchCombo rules with errors" )
693 {
694 WHEN( "numSwitches is zero" )
695 {
696 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
697 { "rule1", "rule1", "rule1", "rule1", "rule1" },
698 { "ruleType", "numSwitches", "property1", "format", "targetProperty" },
699 { "multiSwitchCombo", "0", "dev1.prop1", "{}", "dev2.prop2" } );
700 mx::app::appConfigurator config;
701 config.readConfig( "/tmp/ruleConfig_test.conf" );
702
703 indiRuleMaps maps;
704 std::map<std::string, ruleRuleKeys> rrkMap;
705
706 bool caught = false;
707 try
708 {
709 loadRuleConfig( maps, rrkMap, config );
710 }
711 catch( ... )
712 {
713 caught = true;
714 }
715
716 REQUIRE( caught == true );
717 }
718
719 WHEN( "a required propertyK is missing" )
720 {
721 mx::app::writeConfigFile( "/tmp/ruleConfig_test.conf",
722 { "rule1", "rule1", "rule1", "rule1", "rule1" },
723 { "ruleType", "numSwitches", "property1", "format", "targetProperty" },
724 { "multiSwitchCombo", "2", "dev1.prop1", "{}-{}", "dev2.prop2" } );
725 mx::app::appConfigurator config;
726 config.readConfig( "/tmp/ruleConfig_test.conf" );
727
728 indiRuleMaps maps;
729 std::map<std::string, ruleRuleKeys> rrkMap;
730
731 bool caught = false;
732 try
733 {
734 loadRuleConfig( maps, rrkMap, config );
735 }
736 catch( ... )
737 {
738 caught = true;
739 }
740
741 REQUIRE( caught == true );
742 }
743
744 WHEN( "a source property conflicts with a non-switch rule type" )
745 {
746 mx::app::writeConfigFile(
747 "/tmp/ruleConfig_test.conf",
748 { "ruleText",
749 "ruleText",
750 "ruleText",
751 "ruleText",
752 "ruleCombo",
753 "ruleCombo",
754 "ruleCombo",
755 "ruleCombo",
756 "ruleCombo" },
757 { "ruleType",
758 "property",
759 "element",
760 "target",
761 "ruleType",
762 "numSwitches",
763 "property1",
764 "format",
765 "targetProperty" },
766 { "txtVal", "dev1.prop1", "elem", "xxx", "multiSwitchCombo", "1", "dev1.prop1", "{}", "dev2.prop2" } );
767 mx::app::appConfigurator config;
768 config.readConfig( "/tmp/ruleConfig_test.conf" );
769
770 indiRuleMaps maps;
771 std::map<std::string, ruleRuleKeys> rrkMap;
772
773 bool caught = false;
774 try
775 {
776 loadRuleConfig( maps, rrkMap, config );
777 }
778 catch( ... )
779 {
780 caught = true;
781 }
782
783 REQUIRE( caught == true );
784 }
785
786 WHEN( "the comparison operator is not valid" )
787 {
788 mx::app::writeConfigFile(
789 "/tmp/ruleConfig_test.conf",
790 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
791 { "ruleType", "comp", "numSwitches", "property1", "property2", "format", "targetProperty" },
792 { "multiSwitchCombo", "And", "2", "dev1.prop1", "dev2.prop2", "{}-{}", "dev3.prop3" } );
793 mx::app::appConfigurator config;
794 config.readConfig( "/tmp/ruleConfig_test.conf" );
795
796 indiRuleMaps maps;
797 std::map<std::string, ruleRuleKeys> rrkMap;
798
799 bool caught = false;
800 try
801 {
802 loadRuleConfig( maps, rrkMap, config );
803 }
804 catch( ... )
805 {
806 caught = true;
807 }
808
809 REQUIRE( caught == true );
810 }
811
812 WHEN( "the format placeholder count does not match numSwitches" )
813 {
814 mx::app::writeConfigFile(
815 "/tmp/ruleConfig_test.conf",
816 { "rule1", "rule1", "rule1", "rule1", "rule1", "rule1" },
817 { "ruleType", "numSwitches", "property1", "property2", "format", "targetProperty" },
818 { "multiSwitchCombo", "2", "dev1.prop1", "dev2.prop2", "{}", "dev3.prop3" } );
819 mx::app::appConfigurator config;
820 config.readConfig( "/tmp/ruleConfig_test.conf" );
821
822 indiRuleMaps maps;
823 std::map<std::string, ruleRuleKeys> rrkMap;
824
825 bool caught = false;
826 try
827 {
828 loadRuleConfig( maps, rrkMap, config );
829 }
830 catch( ... )
831 {
832 caught = true;
833 }
834
835 REQUIRE( caught == true );
836 }
837 }
838}
839
840} // namespace stateRuleEngineTest
841
842} // namespace libXWCTest
void loadRuleConfig(indiRuleMaps &maps, std::map< std::string, ruleRuleKeys > &rrkMap, mx::app::appConfigurator &config)
Load the rule and properties maps for a rule engine from a configuration file.
void finalizeRuleValRules(indiRuleMaps &maps, std::map< std::string, ruleRuleKeys > &rrkMap)
Finalize ruleVal rules.
@ GtEq
Greater than or equal to.
@ And
boolean and
@ Neq
Not equal.
@ none
Don't publish.
@ warning
Warning – something is probably wrong, you should check.
@ alert
Alert – something is definitely wrong, you should take action.
@ info
For information only.
SCENARIO("configuring basic rules", "[stateRuleEngine::ruleConfig]")
Namespace for all libXWC tests.
Virtual base-class for all rules.
Structure to provide management of the rule and property maps.
Build and compare a switch-name combination against a target switch vector.
const std::string & propertyKey(size_t n)
Get a source property key by index.
void targetProperty(pcf::IndiProperty *property)
Set the target switch property.
void property(pcf::IndiProperty *property, const std::string &propertyKey)
Append one source switch property.
void format(const std::string &format)
Set the literal format string for the source switch names.
size_t numSwitches()
Get the number of configured source switch properties.
void targetPropertyKey(const std::string &propertyKey)
Set the target property key used in diagnostics.
void ruleName(const std::string &ruleName)
Set the rule name used in diagnostics.
Compare the value of a number element to a target.
void target(const double &tgt)
Set the target for the comparison.
void tol(const double &t)
Set the tolerance.
A rule base class for testing an element in one property.
void property(pcf::IndiProperty *property)
Set the property pointer.
void element(const std::string &el)
Set the element name.
A rule to compare two rules.
void rule2(indiCompRule *r)
Set the pointer to the second rule.
void rule1(indiCompRule *r)
Set the pointer to the first rule.
Compare the value of a switch to a target value.
void target(const pcf::IndiElement::SwitchStateType &ss)
Set the target for the comparison.
A rule base class for testing elements in two properties.
void property1(pcf::IndiProperty *property)
Set the first property pointer.
void element2(const std::string &el)
Set the second element name.
void element1(const std::string &el)
Set the first element name.
void property2(pcf::IndiProperty *property)
Set the second property pointer.
Compare the value of a text element to a target value.
void target(const std::string &target)
Set the target for the comparison.