389 lines
14 KiB
Python
389 lines
14 KiB
Python
#!/usr/bin/env python2
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import mock
|
|
try:
|
|
import unittest2 as unittest
|
|
except ImportError:
|
|
import unittest
|
|
import os
|
|
import sys
|
|
import StringIO
|
|
|
|
import kobo.conf
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
from pungi import checks
|
|
|
|
|
|
class CheckDependenciesTestCase(unittest.TestCase):
|
|
|
|
def dont_find(self, paths):
|
|
return lambda path: path not in paths
|
|
|
|
def test_all_deps_missing(self):
|
|
def custom_exists(path):
|
|
return False
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = custom_exists
|
|
result = checks.check({})
|
|
|
|
self.assertGreater(len(out.getvalue().strip().split('\n')), 1)
|
|
self.assertFalse(result)
|
|
|
|
def test_all_deps_ok(self):
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('platform.machine') as machine:
|
|
machine.return_value = 'x86_64'
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find([])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check({})
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_does_not_require_jigdo_if_not_configured(self):
|
|
conf = {
|
|
'create_jigdo': False
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('platform.machine') as machine:
|
|
machine.return_value = 'x86_64'
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/jigdo-lite'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_isohybrid_not_required_without_productimg_phase(self):
|
|
conf = {
|
|
'bootable': True,
|
|
'productimg': False,
|
|
'runroot': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/isohybrid'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_isohybrid_not_required_on_not_bootable(self):
|
|
conf = {
|
|
'bootable': False,
|
|
'runroot': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/isohybrid'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_isohybrid_not_required_on_arm(self):
|
|
conf = {
|
|
'bootable': True,
|
|
'productimg': True,
|
|
'runroot': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('platform.machine') as machine:
|
|
machine.return_value = 'armhfp'
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/isohybrid'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertRegexpMatches(out.getvalue(), r'^Not checking.*Expect failures.*$')
|
|
self.assertTrue(result)
|
|
|
|
def test_isohybrid_not_needed_in_runroot(self):
|
|
conf = {
|
|
'runroot': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/isohybrid'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_genisoimg_not_needed_in_runroot(self):
|
|
conf = {
|
|
'runroot': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/genisoimage'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertEqual('', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
def test_genisoimg_needed_for_productimg(self):
|
|
conf = {
|
|
'runroot': True,
|
|
'productimg': True,
|
|
'bootable': True,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/genisoimage'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertIn('genisoimage', out.getvalue())
|
|
self.assertFalse(result)
|
|
|
|
def test_requires_modifyrepo(self):
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/modifyrepo'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check({})
|
|
|
|
self.assertIn('createrepo', out.getvalue())
|
|
self.assertFalse(result)
|
|
|
|
def test_requires_createrepo_c(self):
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/createrepo_c'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check({})
|
|
|
|
self.assertIn('createrepo_c', out.getvalue())
|
|
self.assertFalse(result)
|
|
|
|
def test_doesnt_require_createrepo_c_if_configured(self):
|
|
conf = {
|
|
'createrepo_c': False,
|
|
}
|
|
|
|
with mock.patch('sys.stdout', new_callable=StringIO.StringIO) as out:
|
|
with mock.patch('os.path.exists') as exists:
|
|
exists.side_effect = self.dont_find(['/usr/bin/createrepo_c'])
|
|
with mock.patch('__builtin__.__import__'):
|
|
result = checks.check(conf)
|
|
|
|
self.assertNotIn('createrepo_c', out.getvalue())
|
|
self.assertTrue(result)
|
|
|
|
|
|
class TestSchemaValidator(unittest.TestCase):
|
|
def _load_conf_from_string(self, string):
|
|
conf = kobo.conf.PyConfigParser()
|
|
conf.load_from_string(string)
|
|
return conf
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_property(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["release_name"],
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
release_name = "dummy product"
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 0)
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(config.get("release_name", None), "dummy product")
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_alias_property(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
},
|
|
"additionalProperties": False,
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
product_name = "dummy product"
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 0)
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(config.get("release_name", None), "dummy product")
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_required_is_missing(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["release_name"],
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
name = "dummy product"
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 1)
|
|
self.assertIn("Failed validation in : 'release_name' is a required property", errors)
|
|
self.assertEqual(len(warnings), 1)
|
|
self.assertIn("WARNING: Unrecognized config option: name.", warnings)
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_required_is_in_alias(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["release_name"],
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
product_name = "dummy product"
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 0)
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(config.get("release_name", None), "dummy product")
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_redundant_alias(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["release_name"],
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
product_name = "dummy product"
|
|
release_name = "dummy product"
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 1)
|
|
self.assertIn('Failed validation in : product_name is an alias of release_name, only one can be used.', errors)
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(config.get("release_name", None), "dummy product")
|
|
|
|
@mock.patch('pungi.checks._make_schema')
|
|
def test_properties_in_deep(self, make_schema):
|
|
schema = {
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"title": "Pungi Configuration",
|
|
"type": "object",
|
|
"properties": {
|
|
"release_name": {"type": "string", "alias": "product_name"},
|
|
"keys": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
},
|
|
"foophase": {
|
|
"type": "object",
|
|
"properties": {
|
|
"repo": {"type": "string", "alias": "tree"},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["repo"],
|
|
},
|
|
},
|
|
"additionalProperties": False,
|
|
"required": ["release_name"],
|
|
}
|
|
make_schema.return_value = schema
|
|
|
|
string = """
|
|
product_name = "dummy product"
|
|
foophase = {
|
|
"tree": "http://www.exampe.com/os"
|
|
}
|
|
"""
|
|
config = self._load_conf_from_string(string)
|
|
errors, warnings = checks.validate(config)
|
|
self.assertEqual(len(errors), 0)
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(config.get("release_name", None), "dummy product")
|
|
self.assertEqual(config.get("foophase", {}).get("repo", None), "http://www.exampe.com/os")
|
|
|
|
|
|
class TestUmask(unittest.TestCase):
|
|
def setUp(self):
|
|
self.orig_umask = os.umask(0)
|
|
os.umask(self.orig_umask)
|
|
|
|
def tearDown(self):
|
|
os.umask(self.orig_umask)
|
|
|
|
def test_no_warning_with_0022(self):
|
|
os.umask(0o022)
|
|
logger = mock.Mock()
|
|
checks.check_umask(logger)
|
|
self.assertItemsEqual(logger.mock_calls, [])
|
|
|
|
def test_no_warning_with_0000(self):
|
|
os.umask(0o000)
|
|
logger = mock.Mock()
|
|
checks.check_umask(logger)
|
|
self.assertItemsEqual(logger.mock_calls, [])
|
|
|
|
def test_warning_with_0044(self):
|
|
os.umask(0o044)
|
|
logger = mock.Mock()
|
|
checks.check_umask(logger)
|
|
self.assertItemsEqual(
|
|
logger.mock_calls,
|
|
[mock.call.warning('Unusually strict umask detected (0%03o), '
|
|
'expect files with broken permissions.', 0o044)]
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|