def test_expr_1(self): self.assert_cib( BoolExpr( BOOL_AND, [ BoolExpr( BOOL_OR, [ RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("start", None), RscExpr("systemd", None, "pcsd"), RscExpr("ocf", "heartbeat", "Dummy"), ], ), BoolExpr( BOOL_OR, [ OpExpr("monitor", "30s"), RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("start", None), OpExpr("monitor", "2min"), ], ), ], ), """ <rule id="X-rule" boolean-op="and" score="INFINITY"> <rule id="X-rule-rule" boolean-op="or" score="0"> <rsc_expression id="X-rule-rule-rsc-ocf-pacemaker-Dummy" class="ocf" provider="pacemaker" type="Dummy" /> <op_expression id="X-rule-rule-op-start" name="start" /> <rsc_expression id="X-rule-rule-rsc-systemd-pcsd" class="systemd" type="pcsd" /> <rsc_expression id="X-rule-rule-rsc-ocf-heartbeat-Dummy" class="ocf" provider="heartbeat" type="Dummy" /> </rule> <rule id="X-rule-rule-1" boolean-op="or" score="0"> <op_expression id="X-rule-rule-1-op-monitor" name="monitor" interval="30s" /> <rsc_expression id="X-rule-rule-1-rsc-ocf-pacemaker-Dummy" class="ocf" provider="pacemaker" type="Dummy" /> <op_expression id="X-rule-rule-1-op-start" name="start" /> <op_expression id="X-rule-rule-1-op-monitor-1" name="monitor" interval="2min" /> </rule> </rule> """, )
def test_propagate_errors_from_subexpressions(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr( BOOL_OR, [ BoolExpr( BOOL_AND, [ RscExpr(None, None, "Dummy"), OpExpr("stop", None), ], ), BoolExpr( BOOL_AND, [ DateUnaryExpr(DATE_OP_GT, "a date"), NodeAttrExpr( NODE_ATTR_OP_EQ, "attr", "10", NODE_ATTR_TYPE_INTEGER, ), ], ), ], ), ).get_reports(), [ fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="date", option_value="a date", allowed_values="ISO 8601 date", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.RULE_EXPRESSION_NOT_ALLOWED, expression_type=CibRuleExpressionType.OP_EXPRESSION, ), fixture.error( reports.codes.RULE_EXPRESSION_NOT_ALLOWED, expression_type=CibRuleExpressionType.RSC_EXPRESSION, ), fixture.error( reports.codes.RULE_EXPRESSION_NOT_ALLOWED, expression_type=CibRuleExpressionType.EXPRESSION, ), ], )
def test_dates_bad(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr(BOOL_AND, [DateInRangeExpr("date1", "date2", None) ]), ).get_reports(), [ fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="date", option_value="date1", allowed_values="ISO 8601 date", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="date", option_value="date2", allowed_values="ISO 8601 date", cannot_be_empty=False, forbidden_characters=None, ), ], )
def setUp(self): self.report_op = fixture.error( reports.codes.RULE_EXPRESSION_NOT_ALLOWED, expression_type=CibRuleExpressionType.OP_EXPRESSION, ) self.report_rsc = fixture.error( reports.codes.RULE_EXPRESSION_NOT_ALLOWED, expression_type=CibRuleExpressionType.RSC_EXPRESSION, ) self.rule_rsc = BoolExpr( BOOL_OR, [RscExpr(None, None, "a"), RscExpr(None, None, "b")]) self.rule_op = BoolExpr(BOOL_OR, [OpExpr("start", None), OpExpr("stop", None)]) self.rule = BoolExpr(BOOL_AND, [self.rule_rsc, self.rule_op])
def test_no_children(self): self.assert_cib( BoolExpr(BOOL_AND, []), """ <rule id="X-rule" boolean-op="and" score="INFINITY" /> """, )
def test_rule(self): context_element = etree.fromstring("""<context id="a" />""") id_provider = IdProvider(context_element) nvpair_multi.nvset_append_new( context_element, id_provider, nvpair_multi.NVSET_META, {}, {}, nvset_rule=BoolExpr( BOOL_AND, [RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("start", None)], ), ) assert_xml_equal( """ <context id="a"> <meta_attributes id="a-meta_attributes"> <rule id="a-meta_attributes-rule" boolean-op="and" score="INFINITY" > <rsc_expression id="a-meta_attributes-rule-rsc-ocf-pacemaker-Dummy" class="ocf" provider="pacemaker" type="Dummy" /> <op_expression id="a-meta_attributes-rule-op-start" name="start" /> </rule> </meta_attributes> </context> """, etree_to_str(context_element), )
def test_date_ok(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr(BOOL_AND, [DateUnaryExpr(DATE_OP_GT, "2020-02-03")]) ).get_reports(), [], )
def test_date_ok(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr(BOOL_AND, [DateInRangeExpr(None, "2020-02-01", None) ]), ).get_reports(), [], )
def test_one_child(self): self.assert_cib( BoolExpr(BOOL_AND, [OpExpr("start", None)]), """ <rule id="X-rule" boolean-op="and" score="INFINITY"> <op_expression id="X-rule-op-start" name="start" /> </rule> """, )
def fixture_expr_unary(operator): return BoolExpr( BOOL_AND, [ RscExpr(None, None, "Dummy"), NodeAttrExpr(operator, "name", None, None), OpExpr("stop", None), ], )
def fixture_expr_binary(operator): return BoolExpr( BOOL_AND, [ RscExpr(None, None, "Dummy"), NodeAttrExpr(operator, "name", "10", NODE_ATTR_TYPE_INTEGER), OpExpr("stop", None), ], )
def test_range_ok(self): assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [DatespecExpr([(name, "3-5") for name in self.part_list])], ), ).get_reports(), [], )
def test_no_node_attr(self): self.assertFalse( tools.has_node_attr_expr_with_type_integer( BoolExpr( BOOL_OR, [ RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("stop", None), ], )))
def fixture_rule(attr_type): return BoolExpr( BOOL_OR, [ BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "A", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "B", attr_type), ], ), BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "aa", None), RscExpr("ocf", "pacemaker", "Dummy"), ], ), NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "1", None), OpExpr("stop", None), ], )
def test_bad_name(self): assert_report_item_list_equal( Validator(BoolExpr( BOOL_AND, [DatespecExpr([("name", "5-3")])]), ).get_reports(), [ fixture.error( reports.codes.INVALID_OPTIONS, option_names=["name"], allowed=sorted(self.part_list), option_type="datespec", allowed_patterns=[], ), ], )
def test_everything(self): context_element = etree.fromstring("""<context id="a" />""") id_provider = IdProvider(context_element) nvpair_multi.nvset_append_new( context_element, id_provider, Version(3, 5, 0), nvpair_multi.NVSET_META, { "attr1": "value1", "attr-empty": "", "attr2": "value2" }, { "id": "custom-id", "score": "INFINITY", "empty-attr": "" }, nvset_rule=BoolExpr( BOOL_AND, [RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("start", None)], ), ) assert_xml_equal( """ <context id="a"> <meta_attributes id="custom-id" score="INFINITY"> <rule id="custom-id-rule" boolean-op="and" score="INFINITY" > <rsc_expression id="custom-id-rule-rsc-ocf-pacemaker-Dummy" class="ocf" provider="pacemaker" type="Dummy" /> <op_expression id="custom-id-rule-op-start" name="start" /> </rule> <nvpair id="custom-id-attr1" name="attr1" value="value1" /> <nvpair id="custom-id-attr2" name="attr2" value="value2" /> </meta_attributes> </context> """, etree_to_str(context_element), )
def test_no_rsc_op(self): self.assertFalse( tools.has_rsc_or_op_expression( BoolExpr( BOOL_OR, [ BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "A", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "B", None), ], ), BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "aa", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "bb", None), ], ), NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "1", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "2", None), ], )))
def test_op_present(self): self.assertTrue( tools.has_rsc_or_op_expression( BoolExpr( BOOL_OR, [ BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "A", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "B", None), ], ), BoolExpr( BOOL_AND, [ OpExpr("stop", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "bb", None), ], ), NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "1", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "2", None), ], )))
def test_rsc_present(self): self.assertTrue( tools.has_rsc_or_op_expression( BoolExpr( BOOL_OR, [ BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "A", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "B", None), ], ), BoolExpr( BOOL_AND, [ NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "aa", None), RscExpr("ocf", "pacemaker", "Dummy"), ], ), NodeAttrExpr(NODE_ATTR_OP_EQ, "a", "1", None), NodeAttrExpr(NODE_ATTR_OP_EQ, "b", "2", None), ], )))
def test_date_duration_ok(self): assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [ DateInRangeExpr( "2020-01-01T01:01:01+01:00", None, [(name, "3") for name in self.part_list], ) ], ), ).get_reports(), [], )
def test_until_greater_than_since(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [DateInRangeExpr("2020-02-01", "2020-01-01", None)], ), ).get_reports(), [ fixture.error( reports.codes.RULE_EXPRESSION_SINCE_GREATER_THAN_UNTIL, since="2020-02-01", until="2020-01-01", ) ], )
def test_date_bad(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr(BOOL_AND, [DateUnaryExpr(DATE_OP_GT, "a date")])).get_reports(), [ fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="date", option_value="a date", allowed_values="ISO 8601 date", cannot_be_empty=False, forbidden_characters=None, ) ], )
def test_duplicate_names(self): # pylint: disable=no-self-use assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [ DatespecExpr([ ("hours", "10-12"), ("weekdays", "6-7"), ("hours", "13-14"), ]) ], ), ).get_reports(), [ fixture.error( reports.codes.RULE_EXPRESSION_OPTIONS_DUPLICATION, duplicate_option_list=["hours"], ), ], )
def test_two_children(self): operators = [ (BOOL_OR, "or"), (BOOL_AND, "and"), ] for op_in, op_out in operators: with self.subTest(op_in=op_in, op_out=op_out): self.assert_cib( BoolExpr( op_in, [ OpExpr("start", None), RscExpr("systemd", None, "pcsd"), ], ), f""" <rule id="X-rule" boolean-op="{op_out}" score="INFINITY"> <op_expression id="X-rule-op-start" name="start" /> <rsc_expression id="X-rule-rsc-systemd-pcsd" class="systemd" type="pcsd" /> </rule> """, )
def test_duration_bad(self): assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [ DateInRangeExpr( "2020-01-01", None, [(name, "0") for name in self.part_list] + [("hours", "foo"), ("bad", "something")], ) ], ), ).get_reports(), [ fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="hours", option_value="foo", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="monthdays", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="months", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="moon", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weekdays", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weeks", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weekyears", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="years", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="yearsdays", option_value="0", allowed_values="a positive integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTIONS, option_names=["bad"], allowed=sorted(self.part_list), option_type="duration", allowed_patterns=[], ), fixture.error( reports.codes.RULE_EXPRESSION_OPTIONS_DUPLICATION, duplicate_option_list=["hours"], ), ], )
def fixture_expr(type_, value): return BoolExpr(BOOL_AND, [NodeAttrExpr(NODE_ATTR_OP_EQ, "name", value, type_)])
def test_bad_value(self): assert_report_item_list_equal( Validator( BoolExpr( BOOL_AND, [DatespecExpr([(name, "5-3") for name in self.part_list])], ), ).get_reports(), [ fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="hours", option_value="5-3", allowed_values="0..23 or 0..22-1..23", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="monthdays", option_value="5-3", allowed_values="1..31 or 1..30-2..31", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="months", option_value="5-3", allowed_values="1..12 or 1..11-2..12", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="moon", option_value="5-3", allowed_values="0..7 or 0..6-1..7", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weekdays", option_value="5-3", allowed_values="1..7 or 1..6-2..7", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weeks", option_value="5-3", allowed_values="1..53 or 1..52-2..53", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="weekyears", option_value="5-3", allowed_values="an integer or integer-integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="years", option_value="5-3", allowed_values="an integer or integer-integer", cannot_be_empty=False, forbidden_characters=None, ), fixture.error( reports.codes.INVALID_OPTION_VALUE, option_name="yearsdays", option_value="5-3", allowed_values="1..366 or 1..365-2..366", cannot_be_empty=False, forbidden_characters=None, ), ], )
def test_rule(self): context_element = etree.fromstring("""<context id="a" />""") id_provider = IdProvider(context_element) nvpair_multi.nvset_append_new( context_element, id_provider, Version(3, 5, 0), nvpair_multi.NVSET_META, {}, {}, nvset_rule=BoolExpr( BOOL_AND, [ RscExpr("ocf", "pacemaker", "Dummy"), OpExpr("start", None), BoolExpr( BOOL_OR, [ NodeAttrExpr( NODE_ATTR_OP_DEFINED, "attr1", None, None ), NodeAttrExpr( NODE_ATTR_OP_GT, "attr2", "5", NODE_ATTR_TYPE_NUMBER, ), ], ), ], ), ) assert_xml_equal( """ <context id="a"> <meta_attributes id="a-meta_attributes"> <rule id="a-meta_attributes-rule" boolean-op="and" score="INFINITY" > <rsc_expression id="a-meta_attributes-rule-rsc-ocf-pacemaker-Dummy" class="ocf" provider="pacemaker" type="Dummy" /> <op_expression id="a-meta_attributes-rule-op-start" name="start" /> <rule id="a-meta_attributes-rule-rule" boolean-op="or" score="0" > <expression id="a-meta_attributes-rule-rule-expr" operation="defined" attribute="attr1" /> <expression id="a-meta_attributes-rule-rule-expr-1" attribute="attr2" operation="gt" type="number" value="5" /> </rule> </rule> </meta_attributes> </context> """, etree_to_str(context_element), )