Skip to content

Commit

Permalink
Merge pull request #30 from PDXCapstoneF/bs-blackbox-schema
Browse files Browse the repository at this point in the history
Add Configuration validation using `schema` library
  • Loading branch information
mbottini authored Apr 18, 2018
2 parents 81ba264 + 68bfc9e commit d31eb60
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ name = "pypi"

[packages]
docopt = "*"
six = "*"
schema = "*"

[requires]
python_version = "3.6"
18 changes: 17 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 13 additions & 7 deletions mainCLI.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Usage:
mainCLI.py run <config> [--props <props>]
mainCLI.py validate <config>
mainCLI.py (-h | --help)
mainCLI.py --version
mainCLI.py dialogue
Expand All @@ -17,6 +18,7 @@

# source imports
import dialogue
from src import validate


def to_list(s):
Expand Down Expand Up @@ -92,28 +94,32 @@ def cleanup():
cleanup()


def do_validate(arguments):
"""
Validate a configuration based on the schema provided.
"""
with open(arguments['<config>'], 'r') as f:
args = json.loads(f.read())
return validate.validate(args) is None

def do_dialogue(arguments):
dialogue.dialogue()


# dictionary of runnables
# these are functions that take arguments from the
# command line and do something with them.
do = {
'run': do_run,
'validate': do_validate,
'dialogue' : do_dialogue
}

def main():
if __name__ == "__main__":
arguments = docopt(__doc__, version='SPECtate v0.1')

for key, func in do.items():
if arguments[key]:
r = func(arguments)

if r is None:
exit(1)

if __name__ == "__main__":
main()
if r is not None:
exit(r)
4 changes: 4 additions & 0 deletions src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from os.path import dirname, basename, isfile
import glob
modules = glob.glob(dirname(__file__)+"/*.py")
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
31 changes: 31 additions & 0 deletions src/validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from schema import Schema, And, Or, Optional

# used for python2 and python3 string types
from six import text_type

def is_stringy(v):
return type(v) is text_type

ConfigSchema = Schema({
Optional("meta"): {
object: object
},

"specjbb": {
"run_type": And(is_stringy,
lambda rt: rt.lower() in ["hbir", "hbir_rt", "preset", "loadlevel"]),
"kit_version": is_stringy,
"tag": is_stringy,
"jdk": is_stringy,
"numa_node": int,
"data": is_stringy,
"rt_start": int,
"duration": int,
"t": [int],
"jvm_options": [is_stringy],
},

})

def validate(unvalidated):
return ConfigSchema.validate(unvalidated)
36 changes: 36 additions & 0 deletions tests/fixtures/sample_config_invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"run_type": "i made my own run type and its cool",
"meta": {
"creation_date": "2012 23 1 1",
"name": "single run",
"company": "ACME"
},

"speccjbb": {
"injectors": 4,
"backends": 2,
"jvm_path": "/path/to/jvm",
"jar_path": "/path/to/specjbb/jar"
},

"jvm_options": [
"option 1",
"option 2",
"option 3"
],

"props": {
"specjbb.controller.type": "runtype",
"specjbb.controller.rtcurve.start": "0.0",
"specjbb.controller.type": "HBIR"
},

"other": {
"stuff": "we might decide to",
"add": "later"
},

"extra": {
"options": "we don't use yet"
}
}
21 changes: 21 additions & 0 deletions tests/test_validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from schema import SchemaError
from unittest import TestCase
import json
from src.validate import validate

class TestConfigValidator(TestCase):
def test_empty_config_does_not_validate(self):
with self.assertRaises(SchemaError):
validate({})

def test_example_config_does_validate(self):
with open('example_config.json') as f:
j = json.loads(f.read())
assert 'specjbb' in j
self.assertTrue(validate(j))

def test_invalid_config_does_not_validate(self):
with self.assertRaises(SchemaError):
with open('tests/fixtures/sample_config_invalid.json') as f:
j = json.loads(f.read())
self.assertFalse(validate(j))

0 comments on commit d31eb60

Please sign in to comment.