def assert_rule_valid(self, rule, exp_updated_rule=None,
                          exclude_keys=None):
        """Asserts that a rule passes validation.

        :param rule: Rule to validate.
        :param exp_updated_rule: Expected canonical version of the rule, after
               validation.
        :param exclude_keys: Set of keys to exclude from negation.
        """
        if exp_updated_rule is None:
            exp_updated_rule = copy.deepcopy(rule)
        rule = self.add_neg_pfx(rule, exclude_keys=exclude_keys)
        exp_updated_rule = self.add_neg_pfx(exp_updated_rule,
                                            exclude_keys=exclude_keys)

        rule_copy = copy.deepcopy(rule)
        issues = []
        common._validate_rules({"inbound_rules": [rule_copy],
                                "outbound_rules": []}, issues)
        self.assertFalse(issues, "Rule should have no issues, got %s" % issues)
        self.assertEqual(rule_copy, exp_updated_rule)

        rule_copy = copy.deepcopy(rule)
        common._validate_rules({"inbound_rules": [],
                                "outbound_rules": [rule_copy]}, issues)
        self.assertFalse(issues, "Rule should have no issues (outbound), "
                                 "got %s" % issues)
        self.assertEqual(rule_copy, exp_updated_rule)
    def assert_rule_issue(self, rule, exp_issue_re, exclude_keys=None):
        """assert_rule_issue

        Asserts that a rule fails validation with an issue matching
        the regex.
        :param rule: The rule to validate.
        :param str exp_issue_re: Regex to match the issues against.
        :param exclude_keys: set of keys to exclude from negation.
        """
        rule = self.add_neg_pfx(rule, exclude_keys=exclude_keys)
        issues = []
        common._validate_rules({"inbound_rules": [rule],
                                "outbound_rules": []}, issues)
        self.assertTrue(issues, "Rule should have had issues")
        for issue in issues:
            if re.match(exp_issue_re, issue):
                break
        else:
            self.fail("No issue in %s matched regex %s" %
                      (issues, exp_issue_re))