Skip to content

Commit

Permalink
fail fast if no suitable devices found (#34)
Browse files Browse the repository at this point in the history
* fail fast if no suitable devices found
* drop py3.7 from CI and update node to 20
  • Loading branch information
jupe authored Sep 24, 2024
1 parent 1df94f6 commit 311a796
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ]
python-version: [ '3.8', '3.9', '3.10', '3.11' ]
name: ${{ matrix.os }}-Python-${{ matrix.python-version }}
steps:
- uses: actions/checkout@v4
Expand All @@ -32,7 +32,7 @@ jobs:
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10'
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: '20'

- name: Install appium and adb
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10'
Expand Down
37 changes: 26 additions & 11 deletions stf_appium_client/StfClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from stf_client.api.user_api import UserApi
from stf_client.api.devices_api import DevicesApi

STATUS_ONLINE = 3


class StfClient(Logger):
DEFAULT_ALLOCATION_TIMEOUT_SECONDS = 900
Expand Down Expand Up @@ -148,11 +150,12 @@ def release(self, device: dict) -> None:
device['owner'] = None
self.logger.info(f'{serial}: released')

def list_devices(self, requirements: dict, fields: str = "") -> list:
def list_devices(self, requirements: dict, fields: str = "", available_filter: bool = True) -> list:
"""
Get list of devices filtered by given requirements and optional extra fields
:param requirements: filter dictionary
:param fields: extra fields to include
:param available_filter: filter only available devices
:return: list of objects that represent devices
"""
req_keys = list(requirements.keys())
Expand All @@ -165,15 +168,15 @@ def list_devices(self, requirements: dict, fields: str = "") -> list:
fields = uniq(req_keys)

predicate = requirements.copy()

predicate.update(
dict(
present=True,
ready=True,
using=False,
owner=None,
status=3) # 3=Online
)
if available_filter:
predicate.update(
dict(
present=True,
ready=True,
using=False,
owner=None,
status=STATUS_ONLINE)
)

self.logger.debug(
f"Find devices with requirements: {json.dumps(requirements)}, using fields: {','.join(fields)}")
Expand All @@ -182,6 +185,12 @@ def list_devices(self, requirements: dict, fields: str = "") -> list:

return filter_(devices, predicate)

def list_online_devices(self, requirements: dict):
suitable_devices = self.list_devices(requirements=requirements)
online = filter(lambda device: device.get('status') == STATUS_ONLINE, suitable_devices)
return list(online)


def find_and_allocate(self, requirements: dict,
timeout_seconds: int = DEFAULT_ALLOCATION_TIMEOUT_SECONDS,
shuffle: bool = True) -> dict:
Expand All @@ -197,7 +206,7 @@ def find_and_allocate(self, requirements: dict,
:raises DeviceNotFound: suitable device not found or all devices are allocated already
"""
NotConnectedError.invariant(self._client, 'Not connected')
suitable_devices = self.list_devices(requirements=requirements)
suitable_devices = self.list_online_devices(requirements=requirements)
DeviceNotFound.invariant(len(suitable_devices), 'no suitable devices found')
if shuffle:
random.shuffle(suitable_devices)
Expand Down Expand Up @@ -233,6 +242,12 @@ def find_wait_and_allocate(self,
:return: device dictionary
"""
wait_until = time.time() + wait_timeout

# Fail fast if no suitable devices
suitable_devices = self.list_devices(requirements=requirements, available_filter=False)
if not suitable_devices:
raise DeviceNotFound(f'No suitable devices found ({json.dumps(requirements)})')

print(f'wait_until: {wait_until}')
while True:
remaining_time = int(wait_until - time.time())
Expand Down
10 changes: 9 additions & 1 deletion test/test_StfClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ class MockResp:
with self.assertRaises(DeviceNotFound):
self.client.find_and_allocate({})

def test_fail_fast(self):

class MockResp:
devices = [{'serial': 123, 'present': True, 'ready': True, 'using': False, 'owner': None, 'status': 1}]
self.DevicesApi.return_value.get_devices = MagicMock(return_value=MockResp())
with self.assertRaises(DeviceNotFound):
self.client.find_and_allocate({})

def test_list_devices(self):
available = {'serial': 123, 'present': True, 'ready': True, 'using': False, 'owner': None, 'status': 3}
self.client.get_devices = MagicMock(return_value=[available])
Expand Down Expand Up @@ -205,7 +213,7 @@ def test_allocation_context_first_success(self):
@patch('time.sleep', side_effect=MagicMock())
def test_allocation_context_wait_success(self, mock_sleep):
dev1 = {'serial': '123', 'present': True, 'ready': True, 'using': False, 'owner': None, 'status': 3}
self.client.get_devices = MagicMock(side_effect=[[], [dev1]])
self.client.get_devices = MagicMock(side_effect=[[dev1], [], [dev1]])
url = '123'

with self.client.allocation_context({"serial": '123'}) as device:
Expand Down

0 comments on commit 311a796

Please sign in to comment.