From db232c63cb7fd2b2869b7b640129628f3aceb58b Mon Sep 17 00:00:00 2001 From: paetling Date: Mon, 8 Jun 2015 15:10:48 -0400 Subject: [PATCH 1/9] add in new files --- dusty/schemas/base_schema_class.py | 11 +++++ tests/unit/schemas/__init__.py | 0 tests/unit/schemas/test_base_schema_class.py | 45 ++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 dusty/schemas/base_schema_class.py create mode 100644 tests/unit/schemas/__init__.py create mode 100644 tests/unit/schemas/test_base_schema_class.py diff --git a/dusty/schemas/base_schema_class.py b/dusty/schemas/base_schema_class.py new file mode 100644 index 00000000..962d0462 --- /dev/null +++ b/dusty/schemas/base_schema_class.py @@ -0,0 +1,11 @@ +from copy import deepcopy + +# This is build on top of Schemer's functionality +class DustySchema(object): + def __init__(self, schema, document): + schema.validate(document) + self._document = deepcopy(document) + schema.apply_defaults(self._document) + + def __getitem__(self, name): + return self._document[name] diff --git a/tests/unit/schemas/__init__.py b/tests/unit/schemas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/schemas/test_base_schema_class.py b/tests/unit/schemas/test_base_schema_class.py new file mode 100644 index 00000000..d3d50d38 --- /dev/null +++ b/tests/unit/schemas/test_base_schema_class.py @@ -0,0 +1,45 @@ +from unittest import TestCase +from schemer import Schema, Array, ValidationException +from dusty.schemas.base_schema_class import DustySchema + + +class TestDustySchemaClass(TestCase): + def setUp(self): + self.base_schema = Schema({'street': {'type': basestring}, + 'house_number': {'type': int, 'default': 1}}) + self.bigger_schema = Schema({'address': {'type': self.base_schema, 'default': {}}, + 'first_name': {'type': basestring, 'required': True}, + 'last_name': {'type': basestring, 'default': 'johnson'}}) + + def test_init_invalid_doc(self): + doc = {'street': 'dogstoon', + 'house_number': '1'} + with self.assertRaises(ValidationException): + DustySchema(self.base_schema, doc) + + def test_valid_doc(self): + doc = {'street': 'dogstoon', + 'house_number': 1} + dusty_schema = DustySchema(self.base_schema, doc) + self.assertEquals(dusty_schema['street'], 'dogstoon') + self.assertEquals(dusty_schema['house_number'], 1) + + def test_setting_defaults(self): + doc = {'street': 'dogstoon'} + dusty_schema = DustySchema(self.base_schema, doc) + self.assertEquals(dusty_schema['street'], 'dogstoon') + self.assertEquals(dusty_schema['house_number'], 1) + + def test_setting_defaults_more_complicated_1(self): + doc = {'first_name': 'dusty'} + dusty_schema = DustySchema(self.bigger_schema, doc) + self.assertEquals(dusty_schema['first_name'], 'dusty') + self.assertEquals(dusty_schema['last_name'], 'johnson') + self.assertEquals(dusty_schema['address'], {}) + + def test_setting_defaults_more_complicated_2(self): + doc = {'first_name': 'dusty', + 'address': {'street': 'dogstoon'}} + dusty_schema = DustySchema(self.bigger_schema, doc) + self.assertEquals(dusty_schema['address']['street'], 'dogstoon') + self.assertEquals(dusty_schema['address']['house_number'], 1) From dce118f6b541dba7ed2fdcf8b0a0a27f434f9d17 Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 17:22:32 -0400 Subject: [PATCH 2/9] add in dusty specs class --- requirements.py | 2 +- tests/unit/schemas/test_base_schema_class.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.py b/requirements.py index f51f55a3..438cc22b 100644 --- a/requirements.py +++ b/requirements.py @@ -5,7 +5,7 @@ 'PrettyTable>=0.7.0', 'GitPython>=1.0.1', 'docopt==0.6.2', - 'schemer==0.2.7', + 'schemer==0.2.8', ] test_requires = [ diff --git a/tests/unit/schemas/test_base_schema_class.py b/tests/unit/schemas/test_base_schema_class.py index d3d50d38..a8579a86 100644 --- a/tests/unit/schemas/test_base_schema_class.py +++ b/tests/unit/schemas/test_base_schema_class.py @@ -35,7 +35,7 @@ def test_setting_defaults_more_complicated_1(self): dusty_schema = DustySchema(self.bigger_schema, doc) self.assertEquals(dusty_schema['first_name'], 'dusty') self.assertEquals(dusty_schema['last_name'], 'johnson') - self.assertEquals(dusty_schema['address'], {}) + self.assertEquals(dusty_schema['address'], {'house_number': 1}) def test_setting_defaults_more_complicated_2(self): doc = {'first_name': 'dusty', From c3a5075ad638444ee28c4d1b0e50ce0ef121f497 Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 17:45:50 -0400 Subject: [PATCH 3/9] start to change our schema --- dusty/schemas/app_schema.py | 32 ++++++++++++++++---------------- dusty/schemas/bundle_schema.py | 2 +- dusty/schemas/lib_schema.py | 8 ++++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dusty/schemas/app_schema.py b/dusty/schemas/app_schema.py index 64da6fbe..1fbc8532 100644 --- a/dusty/schemas/app_schema.py +++ b/dusty/schemas/app_schema.py @@ -2,14 +2,14 @@ app_depends_schema = Schema({ - 'services': {'type': Array(basestring)}, - 'apps': {'type': Array(basestring)}, - 'libs': {'type': Array(basestring)} + 'services': {'type': Array(basestring), 'default': []}, + 'apps': {'type': Array(basestring), 'default': []}, + 'libs': {'type': Array(basestring), 'default': []} }) conditional_links_schema = Schema({ - 'services': {'type': Array(basestring)}, - 'apps': {'type': Array(basestring)}, + 'services': {'type': Array(basestring), 'default': []}, + 'apps': {'type': Array(basestring), 'default': []}, }) host_forwarding_schema = Schema({ @@ -19,8 +19,8 @@ }) commands_schema = Schema({ - 'always': {'type': basestring, 'required': True}, - 'once': {'type': basestring} + 'always': {'type': basestring, 'required': True, 'default': ''}, + 'once': {'type': basestring, 'default': ''} }) script_schema = Schema({ @@ -32,13 +32,13 @@ app_schema = Schema({ 'repo': {'type': basestring, 'required': True}, - 'depends': {'type': app_depends_schema}, - 'conditional_links': {'type': conditional_links_schema}, - 'host_forwarding': {'type': Array(host_forwarding_schema)}, - 'image': {'type': basestring}, - 'build': {'type': basestring}, - 'mount': {'type': basestring}, - 'commands': {'type': commands_schema}, - 'scripts': {'type': Array(script_schema)}, - 'compose': {'type': dict}, + 'depends': {'type': app_depends_schema, 'default': {}}, + 'conditional_links': {'type': conditional_links_schema, 'default': {}}, + 'host_forwarding': {'type': Array(host_forwarding_schema), 'default': []}, + 'image': {'type': basestring, 'default': ''}, + 'build': {'type': basestring, 'default': ''}, + 'mount': {'type': basestring, 'default': ''}, + 'commands': {'type': commands_schema, 'default': {}}, + 'scripts': {'type': Array(script_schema), 'default': [], + 'compose': {'type': dict, 'default': {}} }) diff --git a/dusty/schemas/bundle_schema.py b/dusty/schemas/bundle_schema.py index 4c2f2d44..4ace6084 100644 --- a/dusty/schemas/bundle_schema.py +++ b/dusty/schemas/bundle_schema.py @@ -1,6 +1,6 @@ from schemer import Schema, Array bundle_schema = Schema({ - 'description': {'type': basestring}, + 'description': {'type': basestring, 'default': ''}, 'apps': {'type': Array(basestring), 'required': True} }) diff --git a/dusty/schemas/lib_schema.py b/dusty/schemas/lib_schema.py index 255d5bed..6e4c188d 100644 --- a/dusty/schemas/lib_schema.py +++ b/dusty/schemas/lib_schema.py @@ -1,12 +1,12 @@ from schemer import Schema, Array depends_schema = Schema({ - 'libs': {'type': Array(basestring)} + 'libs': {'type': Array(basestring), 'default': []} }) lib_schema = Schema({ 'repo': {'type': basestring, 'required': True}, - 'mount': {'type': basestring}, - 'install': {'type': basestring}, - 'depends': {'type': depends_schema} + 'mount': {'type': basestring, 'default': ''}, + 'install': {'type': basestring, 'default': ''}, + 'depends': {'type': depends_schema, 'default': {}} }) From b6a2cd6cf7bee02c95422de6bb5c9f0d6c9afd90 Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:11:33 -0400 Subject: [PATCH 4/9] fix bad rebase --- dusty/schemas/app_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dusty/schemas/app_schema.py b/dusty/schemas/app_schema.py index 1fbc8532..069f1268 100644 --- a/dusty/schemas/app_schema.py +++ b/dusty/schemas/app_schema.py @@ -39,6 +39,6 @@ 'build': {'type': basestring, 'default': ''}, 'mount': {'type': basestring, 'default': ''}, 'commands': {'type': commands_schema, 'default': {}}, - 'scripts': {'type': Array(script_schema), 'default': [], + 'scripts': {'type': Array(script_schema), 'default': []}, 'compose': {'type': dict, 'default': {}} }) From 05e92e12086b9b106a012a6a342eeab38728812e Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:16:25 -0400 Subject: [PATCH 5/9] add in validator --- dusty/schemas/app_schema.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dusty/schemas/app_schema.py b/dusty/schemas/app_schema.py index 069f1268..fba604ae 100644 --- a/dusty/schemas/app_schema.py +++ b/dusty/schemas/app_schema.py @@ -1,5 +1,11 @@ from schemer import Schema, Array +def image_build_isolation_validator(): + def validator(document): + if 'image' in document and 'build' in document: + return 'Only one of image and build is allowed in app_schema' + return validator + app_depends_schema = Schema({ 'services': {'type': Array(basestring), 'default': []}, @@ -41,4 +47,4 @@ 'commands': {'type': commands_schema, 'default': {}}, 'scripts': {'type': Array(script_schema), 'default': []}, 'compose': {'type': dict, 'default': {}} - }) + }, validates=[image_build_isolation_validator()]) From 060159024311dffc2c00504a41f0932e3f037e6e Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:24:21 -0400 Subject: [PATCH 6/9] remove no longer needed test from validation --- dusty/commands/validate.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dusty/commands/validate.py b/dusty/commands/validate.py index 7d3360bc..6ad89210 100644 --- a/dusty/commands/validate.py +++ b/dusty/commands/validate.py @@ -13,16 +13,9 @@ def _check_bare_minimum(specs): if not specs.get(constants.CONFIG_BUNDLES_KEY): raise ValidationException("No Bundles found - exiting") -def _ensure_app_build_or_image(app): - if 'image' in app and 'build' in app: - raise ValidationException("Keys `image` and `build` are mutually exclusive") - elif 'image' not in app and 'build' not in app: - raise ValidationException("Each app must contain either an `image` or a `build` field") - def _validate_fields_with_schemer(specs): for app in specs.get('apps', []).values(): app_schema.validate(app) - _ensure_app_build_or_image(app) for bundle in specs.get(constants.CONFIG_BUNDLES_KEY, []).values(): bundle_schema.validate(bundle) for lib in specs.get('libs', []).values(): From b7f20d464a860583f578e75f227f9b2a7fd5b31b Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:32:11 -0400 Subject: [PATCH 7/9] fix tests --- tests/unit/commands/validate_test.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/unit/commands/validate_test.py b/tests/unit/commands/validate_test.py index 8e22b3a2..cd27d89d 100644 --- a/tests/unit/commands/validate_test.py +++ b/tests/unit/commands/validate_test.py @@ -2,7 +2,7 @@ from schemer import ValidationException -from dusty.commands.validate import (_ensure_app_build_or_image, _validate_app_references, _validate_cycle_free, +from dusty.commands.validate import (_validate_app_references, _validate_cycle_free, _validate_fields_with_schemer) from dusty import constants @@ -45,10 +45,6 @@ def test_schemer_called(self): with self.assertRaises(ValidationException): _validate_fields_with_schemer(specs) - def test_only_build_or_image(self): - with self.assertRaises(ValidationException): - _ensure_app_build_or_image({'image': 'gcimage', 'build': 'build.sh'}) - def test_validate_app_with_bad_service(self): specs = {'apps': { 'app1': { From 2fa8027243316c0bd0353d0cf9f07a611d902bd8 Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:36:31 -0400 Subject: [PATCH 8/9] fix validator --- dusty/schemas/app_schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dusty/schemas/app_schema.py b/dusty/schemas/app_schema.py index fba604ae..5480f61b 100644 --- a/dusty/schemas/app_schema.py +++ b/dusty/schemas/app_schema.py @@ -3,7 +3,9 @@ def image_build_isolation_validator(): def validator(document): if 'image' in document and 'build' in document: - return 'Only one of image and build is allowed in app_schema' + return 'Only one of image and build is allowed in app schema' + elif 'image' not in document and 'build' not in document: + return 'Need to have at least one of `image` or `build` in app schema' return validator From 116f18993873a1bd26ed0ad460d7a1be1b06f59f Mon Sep 17 00:00:00 2001 From: paetling Date: Tue, 9 Jun 2015 18:37:01 -0400 Subject: [PATCH 9/9] update requirements --- requirements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.py b/requirements.py index 438cc22b..a15fbee2 100644 --- a/requirements.py +++ b/requirements.py @@ -5,7 +5,7 @@ 'PrettyTable>=0.7.0', 'GitPython>=1.0.1', 'docopt==0.6.2', - 'schemer==0.2.8', + 'Schemer==0.2.8', ] test_requires = [