summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2018-04-20 20:25:48 -0400
committerScott Moser <smoser@brickies.net>2018-04-20 20:25:48 -0400
commit5037252ca5dc54c6d978b23dba063ac5fabc98fa (patch)
treed39ee7c87b9d471a10a300766570a838c04cbc24
parent4952a8545b61ceb2fe26a933d2f64020d0281703 (diff)
downloadvyos-cloud-init-5037252ca5dc54c6d978b23dba063ac5fabc98fa.tar.gz
vyos-cloud-init-5037252ca5dc54c6d978b23dba063ac5fabc98fa.zip
schema: in validation, raise ImportError if strict but no jsonschema.
validate_cloudconfig_schema with strict=True would not actually validate if there was no jsonschema available. That seems kind of strange. The change here is to make it raise an exception if strict was passed in. And then to fix the one test that needed a skipIfJsonSchema wrapper.
-rw-r--r--cloudinit/config/tests/test_snap.py41
-rw-r--r--cloudinit/config/tests/test_ubuntu_advantage.py30
-rw-r--r--cloudinit/tests/helpers.py19
-rw-r--r--tests/unittests/test_handler/test_handler_bootcmd.py42
-rw-r--r--tests/unittests/test_handler/test_handler_runcmd.py48
5 files changed, 104 insertions, 76 deletions
diff --git a/cloudinit/config/tests/test_snap.py b/cloudinit/config/tests/test_snap.py
index 492d2d46..34c80f1e 100644
--- a/cloudinit/config/tests/test_snap.py
+++ b/cloudinit/config/tests/test_snap.py
@@ -9,7 +9,7 @@ from cloudinit.config.cc_snap import (
from cloudinit.config.schema import validate_cloudconfig_schema
from cloudinit import util
from cloudinit.tests.helpers import (
- CiTestCase, mock, wrap_and_call, skipUnlessJsonSchema)
+ CiTestCase, SchemaTestCaseMixin, mock, wrap_and_call, skipUnlessJsonSchema)
SYSTEM_USER_ASSERTION = """\
@@ -245,9 +245,10 @@ class TestRunCommands(CiTestCase):
@skipUnlessJsonSchema()
-class TestSchema(CiTestCase):
+class TestSchema(CiTestCase, SchemaTestCaseMixin):
with_logs = True
+ schema = schema
def test_schema_warns_on_snap_not_as_dict(self):
"""If the snap configuration is not a dict, emit a warning."""
@@ -342,39 +343,27 @@ class TestSchema(CiTestCase):
def test_duplicates_are_fine_array_array(self):
"""Duplicated commands array/array entries are allowed."""
- byebye = ["echo", "bye"]
- try:
- cfg = {'snap': {'commands': [byebye, byebye]}}
- validate_cloudconfig_schema(cfg, schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("command entries can be duplicate.")
+ self.assertSchemaValid(
+ {'commands': [["echo", "bye"], ["echo" "bye"]]},
+ "command entries can be duplicate.")
def test_duplicates_are_fine_array_string(self):
"""Duplicated commands array/string entries are allowed."""
- byebye = "echo bye"
- try:
- cfg = {'snap': {'commands': [byebye, byebye]}}
- validate_cloudconfig_schema(cfg, schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("command entries can be duplicate.")
+ self.assertSchemaValid(
+ {'commands': ["echo bye", "echo bye"]},
+ "command entries can be duplicate.")
def test_duplicates_are_fine_dict_array(self):
"""Duplicated commands dict/array entries are allowed."""
- byebye = ["echo", "bye"]
- try:
- cfg = {'snap': {'commands': {'00': byebye, '01': byebye}}}
- validate_cloudconfig_schema(cfg, schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("command entries can be duplicate.")
+ self.assertSchemaValid(
+ {'commands': {'00': ["echo", "bye"], '01': ["echo", "bye"]}},
+ "command entries can be duplicate.")
def test_duplicates_are_fine_dict_string(self):
"""Duplicated commands dict/string entries are allowed."""
- byebye = "echo bye"
- try:
- cfg = {'snap': {'commands': {'00': byebye, '01': byebye}}}
- validate_cloudconfig_schema(cfg, schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("command entries can be duplicate.")
+ self.assertSchemaValid(
+ {'commands': {'00': "echo bye", '01': "echo bye"}},
+ "command entries can be duplicate.")
class TestHandle(CiTestCase):
diff --git a/cloudinit/config/tests/test_ubuntu_advantage.py b/cloudinit/config/tests/test_ubuntu_advantage.py
index f2a59faf..f1beeff8 100644
--- a/cloudinit/config/tests/test_ubuntu_advantage.py
+++ b/cloudinit/config/tests/test_ubuntu_advantage.py
@@ -7,7 +7,8 @@ from cloudinit.config.cc_ubuntu_advantage import (
handle, maybe_install_ua_tools, run_commands, schema)
from cloudinit.config.schema import validate_cloudconfig_schema
from cloudinit import util
-from cloudinit.tests.helpers import CiTestCase, mock, skipUnlessJsonSchema
+from cloudinit.tests.helpers import (
+ CiTestCase, mock, SchemaTestCaseMixin, skipUnlessJsonSchema)
# Module path used in mocks
@@ -105,9 +106,10 @@ class TestRunCommands(CiTestCase):
@skipUnlessJsonSchema()
-class TestSchema(CiTestCase):
+class TestSchema(CiTestCase, SchemaTestCaseMixin):
with_logs = True
+ schema = schema
def test_schema_warns_on_ubuntu_advantage_not_as_dict(self):
"""If ubuntu-advantage configuration is not a dict, emit a warning."""
@@ -169,6 +171,30 @@ class TestSchema(CiTestCase):
{'ubuntu-advantage': {'commands': {'01': 'also valid'}}}, schema)
self.assertEqual('', self.logs.getvalue())
+ def test_duplicates_are_fine_array_array(self):
+ """Duplicated commands array/array entries are allowed."""
+ self.assertSchemaValid(
+ {'commands': [["echo", "bye"], ["echo" "bye"]]},
+ "command entries can be duplicate.")
+
+ def test_duplicates_are_fine_array_string(self):
+ """Duplicated commands array/string entries are allowed."""
+ self.assertSchemaValid(
+ {'commands': ["echo bye", "echo bye"]},
+ "command entries can be duplicate.")
+
+ def test_duplicates_are_fine_dict_array(self):
+ """Duplicated commands dict/array entries are allowed."""
+ self.assertSchemaValid(
+ {'commands': {'00': ["echo", "bye"], '01': ["echo", "bye"]}},
+ "command entries can be duplicate.")
+
+ def test_duplicates_are_fine_dict_string(self):
+ """Duplicated commands dict/string entries are allowed."""
+ self.assertSchemaValid(
+ {'commands': {'00': "echo bye", '01': "echo bye"}},
+ "command entries can be duplicate.")
+
class TestHandle(CiTestCase):
diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py
index 5aada6e7..4999f1f6 100644
--- a/cloudinit/tests/helpers.py
+++ b/cloudinit/tests/helpers.py
@@ -24,6 +24,8 @@ try:
except ImportError:
from ConfigParser import ConfigParser
+from cloudinit.config.schema import (
+ SchemaValidationError, validate_cloudconfig_schema)
from cloudinit import helpers as ch
from cloudinit import util
@@ -312,6 +314,23 @@ class HttprettyTestCase(CiTestCase):
super(HttprettyTestCase, self).tearDown()
+class SchemaTestCaseMixin(unittest2.TestCase):
+
+ def assertSchemaValid(self, cfg, msg="Valid Schema failed validation."):
+ """Assert the config is valid per self.schema.
+
+ If there is only one top level key in the schema properties, then
+ the cfg will be put under that key."""
+ props = list(self.schema.get('properties'))
+ # put cfg under top level key if there is only one in the schema
+ if len(props) == 1:
+ cfg = {props[0]: cfg}
+ try:
+ validate_cloudconfig_schema(cfg, self.schema, strict=True)
+ except SchemaValidationError:
+ self.fail(msg)
+
+
def populate_dir(path, files):
if not os.path.exists(path):
os.makedirs(path)
diff --git a/tests/unittests/test_handler/test_handler_bootcmd.py b/tests/unittests/test_handler/test_handler_bootcmd.py
index c3abedde..b1375269 100644
--- a/tests/unittests/test_handler/test_handler_bootcmd.py
+++ b/tests/unittests/test_handler/test_handler_bootcmd.py
@@ -1,9 +1,10 @@
# This file is part of cloud-init. See LICENSE file for license information.
-from cloudinit.config import cc_bootcmd, schema
+from cloudinit.config.cc_bootcmd import handle, schema
from cloudinit.sources import DataSourceNone
from cloudinit import (distros, helpers, cloud, util)
-from cloudinit.tests.helpers import CiTestCase, mock, skipUnlessJsonSchema
+from cloudinit.tests.helpers import (
+ CiTestCase, mock, SchemaTestCaseMixin, skipUnlessJsonSchema)
import logging
import tempfile
@@ -50,7 +51,7 @@ class TestBootcmd(CiTestCase):
"""When the provided config doesn't contain bootcmd, skip it."""
cfg = {}
mycloud = self._get_cloud('ubuntu')
- cc_bootcmd.handle('notimportant', cfg, mycloud, LOG, None)
+ handle('notimportant', cfg, mycloud, LOG, None)
self.assertIn(
"Skipping module named notimportant, no 'bootcmd' key",
self.logs.getvalue())
@@ -60,7 +61,7 @@ class TestBootcmd(CiTestCase):
invalid_config = {'bootcmd': 1}
cc = self._get_cloud('ubuntu')
with self.assertRaises(TypeError) as context_manager:
- cc_bootcmd.handle('cc_bootcmd', invalid_config, cc, LOG, [])
+ handle('cc_bootcmd', invalid_config, cc, LOG, [])
self.assertIn('Failed to shellify bootcmd', self.logs.getvalue())
self.assertEqual(
"Input to shellify was type 'int'. Expected list or tuple.",
@@ -76,7 +77,7 @@ class TestBootcmd(CiTestCase):
invalid_config = {'bootcmd': 1}
cc = self._get_cloud('ubuntu')
with self.assertRaises(TypeError):
- cc_bootcmd.handle('cc_bootcmd', invalid_config, cc, LOG, [])
+ handle('cc_bootcmd', invalid_config, cc, LOG, [])
self.assertIn(
'Invalid config:\nbootcmd: 1 is not of type \'array\'',
self.logs.getvalue())
@@ -93,7 +94,7 @@ class TestBootcmd(CiTestCase):
'bootcmd': ['ls /', 20, ['wget', 'http://stuff/blah'], {'a': 'n'}]}
cc = self._get_cloud('ubuntu')
with self.assertRaises(TypeError) as context_manager:
- cc_bootcmd.handle('cc_bootcmd', invalid_config, cc, LOG, [])
+ handle('cc_bootcmd', invalid_config, cc, LOG, [])
expected_warnings = [
'bootcmd.1: 20 is not valid under any of the given schemas',
'bootcmd.3: {\'a\': \'n\'} is not valid under any of the given'
@@ -117,7 +118,7 @@ class TestBootcmd(CiTestCase):
'echo {0} $INSTANCE_ID > {1}'.format(my_id, out_file)]}
with mock.patch(self._etmpfile_path, FakeExtendedTempFile):
- cc_bootcmd.handle('cc_bootcmd', valid_config, cc, LOG, [])
+ handle('cc_bootcmd', valid_config, cc, LOG, [])
self.assertEqual(my_id + ' iid-datasource-none\n',
util.load_file(out_file))
@@ -128,7 +129,7 @@ class TestBootcmd(CiTestCase):
with mock.patch(self._etmpfile_path, FakeExtendedTempFile):
with self.assertRaises(util.ProcessExecutionError) as ctxt_manager:
- cc_bootcmd.handle('does-not-matter', valid_config, cc, LOG, [])
+ handle('does-not-matter', valid_config, cc, LOG, [])
self.assertIn(
'Unexpected error while running command.\n'
"Command: ['/bin/sh',",
@@ -138,26 +139,21 @@ class TestBootcmd(CiTestCase):
self.logs.getvalue())
-class TestSchema(CiTestCase):
+@skipUnlessJsonSchema()
+class TestSchema(CiTestCase, SchemaTestCaseMixin):
"""Directly test schema rather than through handle."""
+ schema = schema
+
def test_duplicates_are_fine_array_array(self):
- """Duplicated array entries are allowed."""
- try:
- byebye = ["echo", "bye"]
- schema.validate_cloudconfig_schema(
- {'bootcmd': [byebye, byebye]}, cc_bootcmd.schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("runcmd entries as list are allowed to be duplicates.")
+ """Duplicated commands array/array entries are allowed."""
+ self.assertSchemaValid(
+ ["byebye", "byebye"], 'command entries can be duplicate')
def test_duplicates_are_fine_array_string(self):
- """Duplicated array entries entries are allowed in values of array."""
- try:
- byebye = "echo bye"
- schema.validate_cloudconfig_schema(
- {'bootcmd': [byebye, byebye]}, cc_bootcmd.schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("runcmd entries are allowed to be duplicates.")
+ """Duplicated commands array/string entries are allowed."""
+ self.assertSchemaValid(
+ ["echo bye", "echo bye"], "command entries can be duplicate.")
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_handler/test_handler_runcmd.py b/tests/unittests/test_handler/test_handler_runcmd.py
index ee1981d1..9ce334ac 100644
--- a/tests/unittests/test_handler/test_handler_runcmd.py
+++ b/tests/unittests/test_handler/test_handler_runcmd.py
@@ -1,10 +1,11 @@
# This file is part of cloud-init. See LICENSE file for license information.
-from cloudinit.config import cc_runcmd, schema
+from cloudinit.config.cc_runcmd import handle, schema
from cloudinit.sources import DataSourceNone
from cloudinit import (distros, helpers, cloud, util)
from cloudinit.tests.helpers import (
- CiTestCase, FilesystemMockingTestCase, skipUnlessJsonSchema)
+ CiTestCase, FilesystemMockingTestCase, SchemaTestCaseMixin,
+ skipUnlessJsonSchema)
import logging
import os
@@ -35,7 +36,7 @@ class TestRuncmd(FilesystemMockingTestCase):
"""When the provided config doesn't contain runcmd, skip it."""
cfg = {}
mycloud = self._get_cloud('ubuntu')
- cc_runcmd.handle('notimportant', cfg, mycloud, LOG, None)
+ handle('notimportant', cfg, mycloud, LOG, None)
self.assertIn(
"Skipping module named notimportant, no 'runcmd' key",
self.logs.getvalue())
@@ -44,7 +45,7 @@ class TestRuncmd(FilesystemMockingTestCase):
"""Commands which can't be converted to shell will raise errors."""
invalid_config = {'runcmd': 1}
cc = self._get_cloud('ubuntu')
- cc_runcmd.handle('cc_runcmd', invalid_config, cc, LOG, [])
+ handle('cc_runcmd', invalid_config, cc, LOG, [])
self.assertIn(
'Failed to shellify 1 into file'
' /var/lib/cloud/instances/iid-datasource-none/scripts/runcmd',
@@ -59,7 +60,7 @@ class TestRuncmd(FilesystemMockingTestCase):
"""
invalid_config = {'runcmd': 1}
cc = self._get_cloud('ubuntu')
- cc_runcmd.handle('cc_runcmd', invalid_config, cc, LOG, [])
+ handle('cc_runcmd', invalid_config, cc, LOG, [])
self.assertIn(
'Invalid config:\nruncmd: 1 is not of type \'array\'',
self.logs.getvalue())
@@ -75,7 +76,7 @@ class TestRuncmd(FilesystemMockingTestCase):
invalid_config = {
'runcmd': ['ls /', 20, ['wget', 'http://stuff/blah'], {'a': 'n'}]}
cc = self._get_cloud('ubuntu')
- cc_runcmd.handle('cc_runcmd', invalid_config, cc, LOG, [])
+ handle('cc_runcmd', invalid_config, cc, LOG, [])
expected_warnings = [
'runcmd.1: 20 is not valid under any of the given schemas',
'runcmd.3: {\'a\': \'n\'} is not valid under any of the given'
@@ -90,7 +91,7 @@ class TestRuncmd(FilesystemMockingTestCase):
"""Valid runcmd schema is written to a runcmd shell script."""
valid_config = {'runcmd': [['ls', '/']]}
cc = self._get_cloud('ubuntu')
- cc_runcmd.handle('cc_runcmd', valid_config, cc, LOG, [])
+ handle('cc_runcmd', valid_config, cc, LOG, [])
runcmd_file = os.path.join(
self.new_root,
'var/lib/cloud/instances/iid-datasource-none/scripts/runcmd')
@@ -99,25 +100,22 @@ class TestRuncmd(FilesystemMockingTestCase):
self.assertEqual(0o700, stat.S_IMODE(file_stat.st_mode))
-class TestSchema(CiTestCase):
+@skipUnlessJsonSchema()
+class TestSchema(CiTestCase, SchemaTestCaseMixin):
"""Directly test schema rather than through handle."""
- def test_duplicates_are_fine_array(self):
- """Duplicated array entries are allowed."""
- try:
- byebye = ["echo", "bye"]
- schema.validate_cloudconfig_schema(
- {'runcmd': [byebye, byebye]}, cc_runcmd.schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("runcmd entries as list are allowed to be duplicates.")
-
- def test_duplicates_are_fine_string(self):
- """Duplicated string entries are allowed."""
- try:
- byebye = "echo bye"
- schema.validate_cloudconfig_schema(
- {'runcmd': [byebye, byebye]}, cc_runcmd.schema, strict=True)
- except schema.SchemaValidationError as e:
- self.fail("runcmd entries are allowed to be duplicates.")
+ schema = schema
+
+ def test_duplicates_are_fine_array_array(self):
+ """Duplicated commands array/array entries are allowed."""
+ self.assertSchemaValid(
+ [["echo", "bye"], ["echo", "bye"]],
+ "command entries can be duplicate.")
+
+ def test_duplicates_are_fine_array_string(self):
+ """Duplicated commands array/string entries are allowed."""
+ self.assertSchemaValid(
+ ["echo bye", "echo bye"],
+ "command entries can be duplicate.")
# vi: ts=4 expandtab