Skip to content

Commit

Permalink
improve documentation and basic validation for resources.json (#4)
Browse files Browse the repository at this point in the history
* update documentation and use resource_ prefix for suite properties
* add json basic validation
** doesn't allow duplicates id
** require id for each resource objects
  • Loading branch information
jupe authored Jun 17, 2020
1 parent 083b621 commit 1f92c5e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 10 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ Custom options:
--allocation_requirements=<requirements> Resource requirements to be allocate
--allocation_timeout=<timeout>, default=10 Allocation timeout in seconds
--allocation_resource_list_file=<filename>, default=resources.json
Resource to be allocate
--allocation_lock_folder=<folder>, default= os tmp path allocation lock folder
Available resorces list
--allocation_lock_folder=<folder>, default=<os-tmp-path> allocation lockfiles folder
```

*`<requirements>`* can be json-string or key-value pairs. requirements have to match available resources to make allocation possible. Key-value pairs example: `key=value&key2=value2`

Example:

See [example test](example/test_example.py). Usage:
```
cd example
pytest --allocation_hostname localhost -s --allocation_lock_folder . .
```


22 changes: 17 additions & 5 deletions lockable/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from contextlib import contextmanager
import tempfile
import pytest
from pydash import filter_, merge
from pydash import filter_, merge, count_by
from func_timeout import func_timeout, FunctionTimedOut
from filelock import Timeout, FileLock

Expand All @@ -21,18 +21,31 @@ def pytest_addoption(parser):
parser.addoption("--allocation_hostname", default=socket.gethostname(), help="Allocation host")
parser.addoption("--allocation_requirements", default=None, help="Resource requirements to be allocate")
parser.addoption("--allocation_timeout", default=10, help="Allocation timeout")
parser.addoption("--allocation_resource_list_file", default='resources.json', help="Resource to be allocate")
parser.addoption("--allocation_lock_folder", default=tempfile.gettempdir(), help="allocation lock folder")
parser.addoption("--allocation_resource_list_file", default='resources.json', help="Available resorces list")
parser.addoption("--allocation_lock_folder", default=tempfile.gettempdir(), help="Allocation lockfiles folder")


def read_resources_list(filename):
""" Read resources json file """
with open(filename) as json_file:
data = json.load(json_file)
assert isinstance(data, list), 'data is not an list'
validate_json(data)
return data


def validate_json(data):
counts = count_by(data, lambda obj: obj.get('id'))
no_ids = filter_(counts.keys(), lambda key: key is None)
if no_ids:
raise AssertionError('Invalid json, id property is missing')

duplicates = filter_(counts.keys(), lambda key: counts[key] > 1)
if duplicates:
print(duplicates)
raise AssertionError(f"Invalid json, duplicate ids in {duplicates}")


def parse_requirements(requirements_str):
""" Parse requirements """
if not requirements_str:
Expand Down Expand Up @@ -70,7 +83,6 @@ def release():
os.remove(lock_file)
except OSError as error:
print(error, file=sys.stderr)

return candidate, release
except Timeout:
raise AssertionError('not success')
Expand Down Expand Up @@ -135,5 +147,5 @@ def test_foo(lockable_resource):
print(f"Resource list: {json.dumps(resource_list)}")
with lock(predicate, resource_list, timeout_s, lock_folder) as resource:
for key, value in resource.items():
record_testsuite_property(key, value)
record_testsuite_property(f'resource_{key}', value)
yield resource
16 changes: 15 additions & 1 deletion tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import multiprocessing as mp
from tempfile import mktemp
from contextlib import contextmanager
from lockable.plugin import read_resources_list, parse_requirements, lock
from lockable.plugin import read_resources_list, parse_requirements, lock, validate_json


HOSTNAME = socket.gethostname()
Expand Down Expand Up @@ -135,3 +135,17 @@ def test_e2e(self):
"--allocation_hostname", "localhost",
join(example_root, "test_example.py")])
self.assertEqual(exit_code, 0)

def test_valid_json(self):
data = [{"id": "12345"}]
validate_json(data)

def test_duplicate_id_in_json(self):
data = [{"id": "1234"}, {"id": "12345"}, {"id": "12345"}]
with self.assertRaises(AssertionError):
validate_json(data)

def test_missing_id_in_json(self):
data = [{"a": "1234"}, {"id": "12345"}, {"id": "123456"}]
with self.assertRaises(AssertionError):
validate_json(data)

0 comments on commit 1f92c5e

Please sign in to comment.