blob: e8043da54905227156055e8fbc8721df4df8eea6 [file] [log] [blame]
#!/usr/bin/env vpython
# Copyright 2015 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
import logging
import re
import sys
import unittest
from test_support import test_env
test_env.setup_test_env()
import mock
import yaml
from components.config import test_config_pb2
from components.config import validation
from test_support import test_case
class ValidationTestCase(test_case.TestCase):
def setUp(self):
super(ValidationTestCase, self).setUp()
self.rule_set = validation.RuleSet()
def test_rule(self):
validating_func = mock.Mock()
rule = validation.rule(
'projects/foo', 'bar.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
rule(validating_func)
self.rule_set.validate('projects/foo', 'bar.cfg', 'param: "valid config"')
with self.assertRaises(ValueError):
self.rule_set.validate('projects/foo', 'bar.cfg', 'wrong123')
self.assertEqual(validating_func.call_count, 1)
validating_func.side_effect = lambda cfg, ctx: ctx.error('bad')
with self.assertRaises(ValueError):
self.rule_set.validate('projects/foo', 'bar.cfg', 'param: "valid config"')
# Different config_set/path
self.rule_set.validate('projects/foo', 'baz.cfg', 'wrong')
self.rule_set.validate('projects/baz', 'bar.cfg', 'wrong')
def test_patterns(self):
validation.rule(
'projects/foo', 'bar.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
validation.rule(
'services/foo', 'foo.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
validation.rule(
'services/foo', 'foo.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
self.assertEqual(
self.rule_set.patterns(),
{
validation.ConfigPattern('projects/foo', 'bar.cfg'),
validation.ConfigPattern('services/foo', 'foo.cfg'),
validation.ConfigPattern('services/foo', 'foo.cfg'),
}
)
def test_context_metadata(self):
ctx = validation.Context()
ctx.config_set = 'services/foo'
self.assertEqual(ctx.service_id, 'foo')
self.assertEqual(ctx.project_id, None)
self.assertEqual(ctx.ref, None)
ctx.config_set = 'projects/foo'
self.assertEqual(ctx.service_id, None)
self.assertEqual(ctx.project_id, 'foo')
self.assertEqual(ctx.ref, None)
ctx.config_set = 'projects/foo/refs/a'
self.assertEqual(ctx.service_id, None)
self.assertEqual(ctx.project_id, 'foo')
self.assertEqual(ctx.ref, 'refs/a')
def test_regex_pattern_and_no_dest_type(self):
rule = validation.rule(
config_set='regex:projects/f[^/]+',
path='regex:.+.yaml',
rule_set=self.rule_set)
def validate_yaml(cfg, ctx):
try:
yaml.safe_load(cfg)
except Exception as ex:
ctx.error('%s', ex)
rule(validate_yaml)
self.rule_set.validate('projects/foo', 'bar.cfg', '}{')
self.rule_set.validate('projects/bar', 'bar.yaml', '}{')
self.rule_set.validate('projects/foo', 'bar.yaml', '{}')
with self.assertRaises(ValueError):
self.rule_set.validate('projects/foo', 'bar.yaml', '}{')
def test_project_config_rule(self):
validation.project_config_rule(
'bar.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
self.assertTrue(self.rule_set.is_defined_for('projects/foo', 'bar.cfg'))
self.assertTrue(self.rule_set.is_defined_for('projects/baz', 'bar.cfg'))
self.assertFalse(self.rule_set.is_defined_for('projects/x/huh', 'bar.cfg'))
self.assertFalse(self.rule_set.is_defined_for('services/baz', 'bar.cfg'))
self.assertFalse(self.rule_set.is_defined_for('projects/baz', 'notbar.cfg'))
def test_ref_config_rule(self):
validation.ref_config_rule(
'bar.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
self.assertTrue(
self.rule_set.is_defined_for(
'projects/baz/refs/heads/main', 'bar.cfg'))
self.assertFalse(
self.rule_set.is_defined_for(
'projects/baz/refs/heads/main', 'nonbar.cfg'))
self.assertFalse(self.rule_set.is_defined_for('services/foo', 'bar.cfg'))
self.assertFalse(self.rule_set.is_defined_for('projects/baz', 'bar.cfg'))
def test_remove_rule(self):
rule = validation.rule(
'projects/foo', 'bar.cfg', test_config_pb2.Config,
rule_set=self.rule_set)
with self.assertRaises(ValueError):
self.rule_set.validate('projects/foo', 'bar.cfg', 'invalid config')
rule.remove()
self.rule_set.validate('projects/foo', 'bar.cfg', 'invalid config')
def test_compile_pattern(self):
self.assertTrue(validation.compile_pattern('abc')('abc'))
self.assertTrue(validation.compile_pattern('text:abc')('abc'))
self.assertFalse(validation.compile_pattern('text:abc')('abcd'))
self.assertTrue(validation.compile_pattern('regex:abc')('abc'))
self.assertTrue(validation.compile_pattern('regex:\w+')('abc'))
self.assertTrue(validation.compile_pattern('regex:^(\w+)c$')('abc'))
self.assertFalse(validation.compile_pattern('regex:\d+')('a123b'))
def test_is_valid_secure_url(self):
true = [
'http://localhost',
'http://localhost/',
'http://localhost/yo',
'http://localhost:1',
'http://localhost:1/yo',
'https://localhost',
'https://localhost/',
'https://localhost/yo',
'https://localhost:1',
'https://localhost:1/yo',
'https://user@bar.com',
'https://user:pass@bar.com',
]
for i in true:
self.assertTrue(validation.is_valid_secure_url(i), i)
false = [
'http://',
'http://#yo',
'http://evil.com',
'http://localhost:pwd@evil.com',
'https://',
]
for i in false:
self.assertFalse(validation.is_valid_secure_url(i), i)
if __name__ == '__main__':
if '-v' in sys.argv:
unittest.TestCase.maxDiff = None
unittest.main()