Skip to content

Commit

Permalink
handle allocation wait timeout properly and run tests in py3.11
Browse files Browse the repository at this point in the history
  • Loading branch information
jupe committed Mar 23, 2024
1 parent 802ad67 commit e3df872
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 34 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: [ '3.7', '3.8', '3.9', '3.10' ]
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ]
name: ${{ matrix.os }}-Python-${{ matrix.python-version }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Setup Node.js
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10'
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '16'

Expand Down
6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:copyright: (c) 2021 by Jussi Vatjus-Anttila
:copyright: (c) 2024 by Jussi Vatjus-Anttila
:license: MIT, see LICENSE for more details.
"""
from setuptools import setup, find_packages
Expand All @@ -21,6 +21,7 @@
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Topic :: Software Development :: Testing
""".strip().splitlines()

Expand Down Expand Up @@ -55,7 +56,8 @@
},
keywords="OpenSTF appium robot-framework lockable resource android",
python_requires=">=3.7",
project_urls={ # Optionaly
project_urls={
'Homepage': 'https://github.com/OpenTMI/stf-appium-python-client',
'Bug Reports': 'https://github.com/OpenTMI/stf-appium-python-client/issues',
'Source': 'https://github.com/OpenTMI/stf-appium-python-client',
}
Expand Down
58 changes: 30 additions & 28 deletions stf_appium_client/StfClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,15 @@ def find_and_allocate(self, requirements: dict,
timeout_seconds: int = DEFAULT_ALLOCATION_TIMEOUT_SECONDS,
shuffle: bool = True) -> dict:
"""
Find device based on requirements and allocate first
Find device based on requirements and allocate first.
Note that this method doesn't wait for device to be free.
:param requirements: dictionary about requirements, e.g. `dict(platform='android')`
:param timeout_seconds: allocation timeout when idle, see more from allocation api.
:param shuffle: randomize allocation
:return: device dictionary
: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)
Expand All @@ -199,22 +203,20 @@ def find_and_allocate(self, requirements: dict,

self.logger.debug(f'Found {len(suitable_devices)} suitable devices, try to allocate one')

def allocate_first():
def try_allocate(device):
try:
return self.allocate(device, timeout_seconds=timeout_seconds)
except (AssertionError, ForbiddenException) as error:
self.logger.warning(f"{device.get('serial')}Allocation fails: {error}")
return None

tasks = map_(suitable_devices, lambda item: wrap(item, try_allocate))
return find(tasks, lambda allocFunc: allocFunc())

result = allocate_first()
if not result:
raise DeviceNotFound()
device = result.args[0]
return device
def try_allocate(device_candidate):
try:
return self.allocate(device_candidate, timeout_seconds=timeout_seconds)
except AssertionError as error:
self.logger.warning(f"{device_candidate.get('serial')} allocation fails: {error}")
return None

# generate try_allocate tasks for suitable devices
tasks = map_(suitable_devices, lambda item: wrap(item, try_allocate))
# find first successful allocation
result = find(tasks, lambda allocFunc: allocFunc())

DeviceNotFound.invariant(result, 'no suitable devices found')
return result.args[0]

def find_wait_and_allocate(self,
requirements: dict,
Expand All @@ -229,19 +231,20 @@ def find_wait_and_allocate(self,
:param shuffle: allocate suitable device randomly.
:return: device dictionary
"""
device = None
for i in range(wait_timeout): # try to allocate for 1 minute..
wait_until = time.time() + wait_timeout
while wait_until - time.time() > 0:
remaining_time = int(wait_until - time.time())
try:
device = self.find_and_allocate(requirements=requirements,
timeout_seconds=timeout_seconds,
shuffle=shuffle)
break
return self.find_and_allocate(requirements=requirements,
timeout_seconds=timeout_seconds,
shuffle=shuffle)
except DeviceNotFound:
# Wait a while
time.sleep(1)
pass
DeviceNotFound.invariant(device, 'Suitable device not found')
return device
self.logger.debug(f'Suitable device not available, '
f'wait a while and try again. Timeout in {remaining_time} seconds')
# Wait a while to avoid too frequent polling
time.sleep(1)
raise DeviceNotFound(f'Suitable device not found within timeout ({wait_timeout})')

@contextmanager
def allocation_context(self, requirements: dict,
Expand All @@ -267,4 +270,3 @@ def allocation_context(self, requirements: dict,
self.remote_connect(device)
yield device
self.release(device)

0 comments on commit e3df872

Please sign in to comment.