Skip to content

Commit

Permalink
Lock for API calls (#26)
Browse files Browse the repository at this point in the history
* add lock context manager and use it when allocating or releasing a device
* add unit tests
  • Loading branch information
lorjala authored Dec 2, 2022
1 parent 4c2bda8 commit 5fca4ba
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"stf-client==0.1.0",
"pydash",
"easyprocess",
"requests"
"requests",
"pid"
],
entry_points={
'console_scripts': [
Expand Down
7 changes: 5 additions & 2 deletions stf_appium_client/StfClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from stf_appium_client.Logger import Logger
from stf_appium_client.exceptions import DeviceNotFound, NotConnectedError
from stf_appium_client.tools import lock
from stf_client.api_client import ApiClient, Configuration
from stf_client.api.user_api import UserApi
from stf_client.api.devices_api import DevicesApi
Expand Down Expand Up @@ -77,7 +78,8 @@ def allocate(self, device: dict, timeout_seconds: int = DEFAULT_ALLOCATION_TIMEO
timeout = timeout_seconds * 1000

api_instance = UserApi(self._client)
api_response = api_instance.add_user_device_v2(serial, timeout=timeout)
with lock():
api_response = api_instance.add_user_device_v2(serial, timeout=timeout)
assert api_response.success, 'allocation fails'
self.logger.info(f'{serial}: Allocated (timeout: {timeout_seconds})')
device['owner'] = "me"
Expand Down Expand Up @@ -139,7 +141,8 @@ def release(self, device: dict) -> None:
self.logger.debug(f'{serial}: releasing..')

api_instance = UserApi(self._client)
api_response = api_instance.delete_user_device_by_serial(serial)
with lock():
api_response = api_instance.delete_user_device_by_serial(serial)
assert api_response.success, 'release fails'
device['owner'] = None
self.logger.info(f'{serial}: released')
Expand Down
18 changes: 17 additions & 1 deletion stf_appium_client/tools.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import socket
import json
import shutil
from contextlib import closing
import tempfile
from contextlib import closing, contextmanager
from pid import PidFile, PidFileError


def find_free_port() -> int:
Expand Down Expand Up @@ -53,3 +55,17 @@ def split(dest, subkey):
dest[subkey] = value
split(requirements, key)
return requirements

@contextmanager
def lock():
"""
Master lock
"""
try:
lockfile = PidFile(pidname='stf.pid', piddir=tempfile.gettempdir(), register_term_signal_handler=False)
lockfile.create()
yield lockfile
except PidFileError:
raise AssertionError('Lock in use')
finally:
lockfile.close()
26 changes: 25 additions & 1 deletion test/test_tools.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
from unittest.mock import patch, MagicMock
import pytest
from stf_appium_client.tools import find_free_port, parse_requirements
from stf_appium_client.tools import find_free_port, parse_requirements, lock
from pid import PidFileAlreadyLockedError


class TestTools:
Expand Down Expand Up @@ -28,3 +30,25 @@ def test_parse_requirements(self):
self.assertEqual(parse_requirements("key="), {})
with pytest.raises(ValueError):
self.assertEqual(parse_requirements("="), {})

@patch('stf_appium_client.tools.PidFile')
def test_lock(self, mock_pidfile):
with lock():
self.assertEqual(mock_pidfile.return_value.create.call_count, 1)
self.assertEqual(mock_pidfile.return_value.close.call_count, 0)
self.assertEqual(mock_pidfile.return_value.close.call_count, 1)

@patch('stf_appium_client.tools.PidFile')
def test_lock_is_released(self, mock_pidfile):
try:
with lock():
raise RuntimeError()
except RuntimeError:
self.assertEqual(mock_pidfile.return_value.close.call_count, 1)

@patch('stf_appium_client.tools.PidFile')
def test_lock_in_use(self, mock_pidfile):
mock_pidfile.return_value.create.side_effect = [PidFileAlreadyLockedError()]
with pytest.raises(AssertionError):
with lock():
pass

0 comments on commit 5fca4ba

Please sign in to comment.