from __future__ import absolute_import import unittest import pytest import koji.policy class MyBoolTest(koji.policy.BoolTest): name = 'bool_check' field = 'bool_field' class MyMatchTest(koji.policy.MatchTest): name = 'match_check' field = 'match_field' class myvarTest(koji.policy.CompareTest): name = None field = 'myvar' allow_float = False class TestBasicTests(unittest.TestCase): def test_base_test(self): with pytest.raises(NotImplementedError): obj = koji.policy.BaseSimpleTest('something') obj.run({}) def test_true_test(self): obj = koji.policy.TrueTest('something') self.assertTrue(obj.run({})) def test_false_test(self): obj = koji.policy.FalseTest('something') self.assertFalse(obj.run({})) def test_all_test(self): obj = koji.policy.AllTest('something') self.assertTrue(obj.run({})) def test_none_test(self): obj = koji.policy.NoneTest('something') self.assertFalse(obj.run({})) def test_has_test(self): obj = koji.policy.HasTest('some thing') self.assertFalse(obj.run({})) self.assertFalse(obj.run({'blah': 'blah'})) self.assertTrue(obj.run({'thing': 'blah'})) self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something') def test_bool_test(self): obj = koji.policy.BoolTest('some thing') self.assertFalse(obj.run({'thing': None})) self.assertFalse(obj.run({'thing': []})) self.assertFalse(obj.run({})) self.assertTrue(obj.run({'thing': 'yes'})) def test_match_test(self): obj = koji.policy.MatchTest('some thing else') self.assertFalse(obj.run({'thing': 'elseplus'})) obj = koji.policy.MatchTest('some thing else*') self.assertTrue(obj.run({'thing': 'elseplus'})) self.assertFalse(obj.run({})) def test_target_test(self): obj = koji.policy.TargetTest('target valid') self.assertTrue(obj.run({'target': 'valid'})) self.assertFalse(obj.run({'target': 'else'})) obj = koji.policy.TargetTest('target valid else*') self.assertTrue(obj.run({'target': 'valid'})) self.assertTrue(obj.run({'target': 'elseplus'})) def test_compare_test(self): obj = koji.policy.CompareTest('compare thing > 2') self.assertFalse(obj.run({'thing': 1})) self.assertFalse(obj.run({'thing': 2})) self.assertTrue(obj.run({'thing': 3})) self.assertFalse(obj.run({})) obj = koji.policy.CompareTest('compare thing < 1.5') self.assertFalse(obj.run({'thing': 3.2})) self.assertTrue(obj.run({'thing': 1.0})) self.assertFalse(obj.run({})) obj = koji.policy.CompareTest('compare thing = 42') self.assertFalse(obj.run({'thing': 54})) self.assertTrue(obj.run({'thing': 42})) self.assertFalse(obj.run({})) obj = koji.policy.CompareTest('compare thing != 99') self.assertFalse(obj.run({'thing': 99})) self.assertTrue(obj.run({'thing': 100})) self.assertFalse(obj.run({})) obj = koji.policy.CompareTest('compare thing >= 2') self.assertFalse(obj.run({'thing': 1})) self.assertTrue(obj.run({'thing': 2})) self.assertTrue(obj.run({'thing': 3})) self.assertFalse(obj.run({})) obj = koji.policy.CompareTest('compare thing <= 5') self.assertFalse(obj.run({'thing': 23})) self.assertTrue(obj.run({'thing': 5})) self.assertTrue(obj.run({'thing': 0})) self.assertFalse(obj.run({})) def test_invalid_compare_test(self): with pytest.raises(koji.GenericError): koji.policy.CompareTest('some thing LOL 2') def test_match_any_test(self): obj = koji.policy.MatchAnyTest('not_important foo *bar* ext') self.assertTrue(obj.run({'foo': ['barrrr', 'any']})) self.assertTrue(obj.run({'foo': [None, 'bbbbbarrr', None]})) self.assertFalse(obj.run({'foo': ['nah....']})) self.assertFalse(obj.run({'foo': 'nah...'})) self.assertFalse(obj.run({'bar': ['any']})) def test_match_all_test(self): obj = koji.policy.MatchAllTest('not_important foo *bar* ext') self.assertTrue(obj.run({'foo': ['barrrr', 'bbbarrr']})) self.assertFalse(obj.run({'foo': ['barrrr', 'nah....']})) self.assertFalse(obj.run({'foo': [None, 'barrrr', None]})) self.assertFalse(obj.run({'foo': 'nah...'})) self.assertFalse(obj.run({'bar': ['any']})) class TestDiscovery(unittest.TestCase): def test_find_simple_tests(self): actual = koji.policy.findSimpleTests(koji.policy.__dict__) expected = { 'all': koji.policy.AllTest, 'bool': koji.policy.BoolTest, 'compare': koji.policy.CompareTest, 'false': koji.policy.FalseTest, 'has': koji.policy.HasTest, 'match': koji.policy.MatchTest, 'match_all': koji.policy.MatchAllTest, 'match_any': koji.policy.MatchAnyTest, 'none': koji.policy.NoneTest, 'target': koji.policy.TargetTest, 'true': koji.policy.TrueTest, } self.assertDictEqual(expected, actual) class TestRuleHandling(unittest.TestCase): def test_simple_rule_set_instantiation(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) rules = ['true :: allow'] koji.policy.SimpleRuleSet(rules, tests) def test_simple_rule_set_all_actions(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) rules = ['true :: allow'] obj = koji.policy.SimpleRuleSet(rules, tests) result = obj.all_actions() self.assertEqual(result, ['allow']) def test_simple_rule_set_apply(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} rules = ['true :: allow'] obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, 'allow') rules = ['false :: allow'] obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, None) def test_custom_rules(self): tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__]) rules = ['bool_check :: True', 'all :: False'] for val in True, False: data = {'bool_field': val} obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, str(val)) rules = ['match_check foo* :: foo', 'match_check * :: bar'] data = {'match_field': 'foo1234'} obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, 'foo') data = {'match_field': 'not foo'} obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, 'bar') data = {'myvar': 37} rules = ['myvar = 37 :: get back here'] obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(action, 'get back here') rules = ['myvar = 2.718281828 :: euler'] with self.assertRaises(ValueError): obj = koji.policy.SimpleRuleSet(rules, tests) def test_last_rule(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} # no match rules = ['none :: allow'] obj = koji.policy.SimpleRuleSet(rules, tests) self.assertEqual(obj.last_rule(), None) action = obj.apply(data) self.assertEqual(obj.last_rule(), '(no match)') # simple rule rules = ['all :: allow'] obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(obj.last_rule(), rules[0]) # negate rule rules = ['none !! allow'] obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) self.assertEqual(obj.last_rule(), rules[0]) # nested rule policy = ''' all :: { all :: { all :: allow } } ''' rules = policy.splitlines() obj = koji.policy.SimpleRuleSet(rules, tests) action = obj.apply(data) expected = 'all :: ... all :: ... all :: allow' self.assertEqual(obj.last_rule(), expected) def test_unclosed_brace(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} lines = ['true :: {'] with self.assertRaises(koji.GenericError): obj = koji.policy.SimpleRuleSet(lines, tests) def test_unmatched_brace(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} lines = ['true :: }'] with self.assertRaises(koji.GenericError): obj = koji.policy.SimpleRuleSet(lines, tests) def test_no_action(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} lines = ['true && true'] with self.assertRaises(Exception): obj = koji.policy.SimpleRuleSet(lines, tests) def test_missing_handler(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} lines = ['NOSUCHHANDLER && true :: allow'] with self.assertRaises(koji.GenericError): obj = koji.policy.SimpleRuleSet(lines, tests) def test_complex_policy(self): tests = koji.policy.findSimpleTests(koji.policy.__dict__) data = {} policy = ''' # This is a comment in the test policy #^blank line # commented test && true :: some result # First some rules that should never match false :: ERROR none :: ERROR true !! ERROR all !! ERROR false && true && true :: ERROR none && true && true :: ERROR has NOSUCHFIELD :: ERROR # nesting has DEPTH :: { match DEPTH 1 :: 1 all :: { match DEPTH 2 :: 2 all :: { match DEPTH 3 :: 3 all :: { match DEPTH 4 :: 4 all :: END } } } } ''' lines = policy.splitlines() for depth in ['1', '2', '3', '4']: data = {'DEPTH': depth} obj = koji.policy.SimpleRuleSet(lines, tests) action = obj.apply(data) self.assertEqual(action, depth) data = {'DEPTH': '99'} obj = koji.policy.SimpleRuleSet(lines, tests) action = obj.apply(data) self.assertEqual(action, 'END') actions = set(obj.all_actions()) self.assertEqual(actions, set(['1', '2', '3', '4', 'ERROR', 'END']))