Skip to content

Commit

Permalink
allow to allocate any lockable during test case (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
jupe authored Jul 20, 2020
1 parent 887fa73 commit 213d923
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 20 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ Custom options:

Example:

Use shared lockable resource
``` python
def test_example(lockable_resource):
""" Simple test """
print(f'Testing with resource: {lockable_resource}')
```

Allocate lockable resource during test with given requirements
``` python
def test_example(lockable):
""" Simple test """
with lockable({"my": "requirements"}) as resource:
print(f'Testing with resource#: {resource}')
```

See [example test](example/test_example.py). Usage:
```
cd example
Expand Down
5 changes: 5 additions & 0 deletions example/resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@
"id": "1235",
"online": true,
"hostname": "localhost"
},
{
"id": "1236",
"online": true,
"hostname": "localhost"
}
]
6 changes: 4 additions & 2 deletions example/test_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ def test_example1(lockable_resource):
sleep(1)


def test_example2(lockable_resource):
def test_example2(lockable_resource, lockable):
""" Simple test """
print(f'Testing with resource: {lockable_resource}')
sleep(1)
with lockable({}) as resource:
print(f'Testing with resource#2: {resource}')
sleep(1)
58 changes: 40 additions & 18 deletions lockable/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ def _try_lock(candidate, lock_folder):
resource_id = candidate.get("id")
try:
lock_file = os.path.join(lock_folder, f"{resource_id}.lock")
lockable = FileLock(lock_file)
lockable.acquire(timeout=0)
_lockable = FileLock(lock_file)
_lockable.acquire(timeout=0)
print(f'Allocated resource: {resource_id}')

def release():
nonlocal _lockable
print(f'Release resource: {resource_id}')
lockable.release()
_lockable.release()
try:
os.remove(lock_file)
except OSError as error:
Expand Down Expand Up @@ -138,7 +139,40 @@ def _get_requirements(requirements, hostname):


@pytest.fixture(scope="session", autouse=True)
def lockable_resource(pytestconfig, record_testsuite_property):
def lockable(pytestconfig, record_testsuite_property):
"""
pytest fixture that yields function for allocate any resource
.. code-block:: python
def test_foo(lockable_allocate):
with lockable({my: "resource}) as resource:
print(resource)
"""
resource_list = read_resources_list(pytestconfig.getoption('allocation_resource_list_file'))
timeout_s = pytestconfig.getoption('allocation_timeout')
lock_folder = pytestconfig.getoption('allocation_lock_folder')

@contextmanager
def _lock(requirements, prefix='resource'):
nonlocal resource_list, timeout_s, lock_folder
requirements = parse_requirements(requirements)
predicate = _get_requirements(requirements, pytestconfig.getoption('allocation_hostname'))
print(f"Use lock folder: {lock_folder}")
print(f"Requirements: {json.dumps(predicate)}")
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(f'resource_{key}', value)
if pytestconfig.pluginmanager.hasplugin('metadata'):
# pylint: disable=protected-access
pytestconfig._metadata[f'{prefix}_{key}'] = value
yield resource

yield _lock


@pytest.fixture(scope="session", autouse=True)
def lockable_resource(pytestconfig, lockable): # pylint: disable=redefined-outer-name
"""
pytest fixture that lock suitable resource and yield it
Expand All @@ -148,18 +182,6 @@ def test_foo(lockable_resource):
print(f'Testing with resource: {lockable_resource}')
"""
requirements = parse_requirements(pytestconfig.getoption('allocation_requirements'))
predicate = _get_requirements(requirements, pytestconfig.getoption('allocation_hostname'))
resource_list = read_resources_list(pytestconfig.getoption('allocation_resource_list_file'))
timeout_s = pytestconfig.getoption('allocation_timeout')
lock_folder = pytestconfig.getoption('allocation_lock_folder')
print(f"Use lock folder: {lock_folder}")
print(f"Requirements: {json.dumps(predicate)}")
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(f'resource_{key}', value)
if pytestconfig.pluginmanager.hasplugin('metadata'):
# pylint: disable=protected-access
pytestconfig._metadata[f'resource_{key}'] = value
requirements = pytestconfig.getoption('allocation_requirements')
with lockable(requirements) as resource:
yield resource

0 comments on commit 213d923

Please sign in to comment.