diff options
author | Edi Feschiyan <553226+refresher@users.noreply.github.com> | 2020-06-18 13:12:31 +0300 |
---|---|---|
committer | Edi Feschiyan <553226+refresher@users.noreply.github.com> | 2020-06-18 13:12:31 +0300 |
commit | 80159d8789fe2ea0b36d84b83348813f67e18652 (patch) | |
tree | a997c5013257bdb7d02518d86c21595c15a33ced | |
parent | 8a8b87e65c0b3d579f8ea420e23a9cd07528dfe1 (diff) |
Rearranging files for distribution, setup.py modifications
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | pyagl/services/audiomixer.py (renamed from services/audiomixer.py) | 10 | ||||
-rw-r--r-- | pyagl/services/base.py (renamed from services/base.py) | 2 | ||||
-rw-r--r-- | pyagl/services/bluetooth-map.py (renamed from services/bluetooth-map.py) | 0 | ||||
-rw-r--r-- | pyagl/services/bluetooth-pbap.py (renamed from services/bluetooth-pbap.py) | 0 | ||||
-rw-r--r-- | pyagl/services/bluetooth.py (renamed from services/bluetooth.py) | 8 | ||||
-rw-r--r-- | pyagl/services/geoclue.py (renamed from services/geoclue.py) | 10 | ||||
-rw-r--r-- | pyagl/services/gps.py (renamed from services/gps.py) | 10 | ||||
-rw-r--r-- | pyagl/services/mediaplayer.py (renamed from services/mediaplayer.py) | 36 | ||||
-rw-r--r-- | pyagl/services/network.py (renamed from services/network.py) | 0 | ||||
-rw-r--r-- | pyagl/services/nfc.py (renamed from services/nfc.py) | 10 | ||||
-rw-r--r-- | pyagl/services/taskmanager.py (renamed from services/taskmanager.py) | 0 | ||||
-rw-r--r-- | pyagl/services/weather.py (renamed from services/weather.py) | 10 | ||||
-rw-r--r-- | pyagl/tests/test_bluetooth.py | 105 | ||||
-rw-r--r-- | pyagl/tests/test_gps.py | 73 | ||||
-rw-r--r-- | pyagl/tests/test_weather.py (renamed from templates/test/{{cookiecutter.file_name}}.py) | 0 | ||||
-rw-r--r-- | setup.py | 26 | ||||
-rw-r--r-- | templates/cookiecutter.json | 8 | ||||
-rw-r--r-- | templates/service/cookiecutter.json | 6 | ||||
-rw-r--r-- | templates/service/{{cookiecutter.file_name}}.py | 9 | ||||
-rw-r--r-- | templates/{{cookiecutter.services_dir}}/{{cookiecutter.service_slug}}.py | 17 | ||||
-rw-r--r-- | templates/{{cookiecutter.tests_dir}}/test_{{cookiecutter.service_slug}}.py | 23 |
22 files changed, 298 insertions, 66 deletions
@@ -1,4 +1,3 @@ .idea/* -scratch __pycache__ downloads/ diff --git a/services/audiomixer.py b/pyagl/services/audiomixer.py index e594471..3f35bc8 100644 --- a/services/audiomixer.py +++ b/pyagl/services/audiomixer.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio import os @@ -73,15 +73,15 @@ async def main(): if args.subscribe: for event in args.subscribe: - id = await ams.subscribe(event) - print(f'Subscribing to {event} with id {id}') + msgid = await ams.subscribe(event) + print(f'Subscribing to {event} with id {msgid}') r = AFBResponse(await ams.response()) print(r) if args.unsubscribe: for event in args.unsubscribe: - id = await ams.unsubscribe(event) - print(f'Unsubscribing from {event} with id {id}') + msgid = await ams.unsubscribe(event) + print(f'Unsubscribing from {event} with id {msgid}') r = AFBResponse(await ams.response()) print(r) diff --git a/services/base.py b/pyagl/services/base.py index 03d4793..ce5c8c7 100644 --- a/services/base.py +++ b/pyagl/services/base.py @@ -80,8 +80,6 @@ class AFBResponse: self.msgid = int(data[1]) self.status = data[2]['request']['status'] self.info = data[2]['request']['info'] - # raise ValueError(f'AFB returned erroneous response {data}') - # if 'request' not in data[2] or 'response' not in data[2]: if 'response' in data[2]: self.data = data[2]['response'] diff --git a/services/bluetooth-map.py b/pyagl/services/bluetooth-map.py index e69de29..e69de29 100644 --- a/services/bluetooth-map.py +++ b/pyagl/services/bluetooth-map.py diff --git a/services/bluetooth-pbap.py b/pyagl/services/bluetooth-pbap.py index e69de29..e69de29 100644 --- a/services/bluetooth-pbap.py +++ b/pyagl/services/bluetooth-pbap.py diff --git a/services/bluetooth.py b/pyagl/services/bluetooth.py index b73f8a8..d111d09 100644 --- a/services/bluetooth.py +++ b/pyagl/services/bluetooth.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio import os @@ -23,8 +23,6 @@ class BluetoothService(AGLBaseService): parser.add_argument('--confirm_pairing', metavar='pincode') parser.add_argument('--remove_device', metavar='dev_88_0F_10_96_D3_20', help='Remove paired device') - - def __init__(self, ip, port=None, service='agl-service-bluetooth'): super().__init__(api='Bluetooth-Manager', ip=ip, port=port, service=service) @@ -75,8 +73,8 @@ async def main(loop): bts = await BluetoothService(ip=args.ipaddr, port=args.port) if args.default_adapter: - id = await bts.default_adapter() - print(f'Requesting default adapter with id {id}') + msgid = await bts.default_adapter() + print(f'Requesting default adapter with id {msgid}') r = AFBResponse(await bts.response()) print(r) diff --git a/services/geoclue.py b/pyagl/services/geoclue.py index df1afd6..c14c6db 100644 --- a/services/geoclue.py +++ b/pyagl/services/geoclue.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio import os @@ -26,14 +26,14 @@ async def main(loop): gcs = await GeoClueService(args.ipaddr) if args.location: - id = await gcs.location() - print(f'Sent location request with messageid {id}') + msgid = await gcs.location() + print(f'Sent location request with messageid {msgid}') print(AFBResponse(await gcs.response())) if args.subscribe: for event in args.subscribe: - id = await gcs.subscribe(event) - print(f"Subscribed for {event} with messageid {id}") + msgid = await gcs.subscribe(event) + print(f"Subscribed for {event} with messageid {msgid}") print(AFBResponse(await gcs.response())) if args.listener: async for response in gcs.listener(): diff --git a/services/gps.py b/pyagl/services/gps.py index 1905e0f..69c253e 100644 --- a/services/gps.py +++ b/pyagl/services/gps.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio import os @@ -33,8 +33,8 @@ async def main(loop): gpss.logger.setLevel(args.loglevel) if args.record: - id = await gpss.record(args.record) - print(f'Sent gps record request with value {args.record} with messageid {id}') + msgid = await gpss.record(args.record) + print(f'Sent gps record request with value {args.record} with messageid {msgid}') print(AFBResponse(await gpss.response())) if args.location: @@ -43,8 +43,8 @@ async def main(loop): if args.subscribe: for event in args.subscribe: - id = await gpss.subscribe(event) - print(f'Subscribed for event {event} with messageid {id}') + msgid = await gpss.subscribe(event) + print(f'Subscribed for event {event} with messageid {msgid}') print(AFBResponse(await gpss.response())) if args.listener: diff --git a/services/mediaplayer.py b/pyagl/services/mediaplayer.py index 9291981..4472531 100644 --- a/services/mediaplayer.py +++ b/pyagl/services/mediaplayer.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse from typing import Union import logging import asyncio @@ -91,49 +91,49 @@ async def main(loop): MPS = await MediaPlayerService(ip=args.ipaddr) if args.playlist: - id = await MPS.playlist() + msgid = await MPS.playlist() r = AFBResponse(await MPS.response()) for l in r.data['list']: print(l) if args.control: - id = await MPS.control(args.control) - print(f'Sent {args.control} request with messageid {id}') + msgid = await MPS.control(args.control) + print(f'Sent {args.control} request with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.seek: - id = await MPS.control('seek', args.seek) - print(f'Sent seek request to {args.seek} msec with messageid {id}') + msgid = await MPS.control('seek', args.seek) + print(f'Sent seek request to {args.seek} msec with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.fastforward: - id = await MPS.control('fast-forward', args.fastforward) - print(f'Sent fast-forward request for {args.fastforward} msec with messageid {id}') + msgid = await MPS.control('fast-forward', args.fastforward) + print(f'Sent fast-forward request for {args.fastforward} msec with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.rewind: - id = await MPS.control('rewind', -args.rewind) - print(f'Sent rewind request for {args.rewind} msec with messageid {id}') + msgid = await MPS.control('rewind', -args.rewind) + print(f'Sent rewind request for {args.rewind} msec with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.picktrack: - id = await MPS.control('pick-track', args.picktrack) - print(f'Sent pick-track request with index {args.rewind} with messageid {id}') + msgid = await MPS.control('pick-track', args.picktrack) + print(f'Sent pick-track request with index {args.rewind} with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.volume: - id = await MPS.control('volume', int(args.volume)) - print(f'Sent volume request: {args.rewind} with messageid {id}') + msgid = await MPS.control('volume', int(args.volume)) + print(f'Sent volume request: {args.rewind} with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) if args.loop: - id = await MPS.control('loop', args.loop) - print(f'Sent loop-state request: {args.loop} with messageid {id}') + msgid = await MPS.control('loop', args.loop) + print(f'Sent loop-state request: {args.loop} with messageid {msgid}') r = AFBResponse(await MPS.response()) print(r) @@ -145,8 +145,8 @@ async def main(loop): if args.subscribe: for event in args.subscribe: - id = await MPS.subscribe(event) - print(f"Subscribed for event {event} with messageid {id}") + msgid = await MPS.subscribe(event) + print(f"Subscribed for event {event} with messageid {msgid}") r = await MPS.response() print(r) diff --git a/services/network.py b/pyagl/services/network.py index e69de29..e69de29 100644 --- a/services/network.py +++ b/pyagl/services/network.py diff --git a/services/nfc.py b/pyagl/services/nfc.py index c966c4a..78f9b6e 100644 --- a/services/nfc.py +++ b/pyagl/services/nfc.py @@ -1,4 +1,4 @@ -from aglbaseservice import AGLBaseService, AFBResponse +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio class NFCService(AGLBaseService): @@ -21,15 +21,15 @@ async def main(loop): if args.subscribe: for event in args.subscribe: - id = await nfcs.subscribe(event) - print(f"Subscribing for event {event} with messageid {id}") + msgid = await nfcs.subscribe(event) + print(f"Subscribing for event {event} with messageid {msgid}") r = AFBResponse(await nfcs.response()) print(r) if args.unsubscribe: for event in args.unsubscribe: - id = await nfcs.unsubscribe(event) - print(f"Unsubscribing for event {event} with messageid {id}") + msgid = await nfcs.unsubscribe(event) + print(f"Unsubscribing for event {event} with messageid {msgid}") r = AFBResponse(await nfcs.response()) print(r) diff --git a/services/taskmanager.py b/pyagl/services/taskmanager.py index e69de29..e69de29 100644 --- a/services/taskmanager.py +++ b/pyagl/services/taskmanager.py diff --git a/services/weather.py b/pyagl/services/weather.py index f3c02d0..389be70 100644 --- a/services/weather.py +++ b/pyagl/services/weather.py @@ -1,6 +1,6 @@ +from pyagl.services.base import AGLBaseService, AFBResponse import asyncio import json -from aglbaseservice import AGLBaseService, AFBResponse class WeatherService(AGLBaseService): @@ -23,19 +23,19 @@ async def main(): args = WeatherService.parser.parse_args() aws = await WeatherService(ip=args.ipaddr, port=args.port) if args.current: - id = await aws.current_weather() + msgid = await aws.current_weather() resp = AFBResponse(await aws.response()) print(json.dumps(resp.data, indent=2)) if args.apikey: - id = await aws.apikey() + msgid = await aws.apikey() resp = AFBResponse(await aws.response()) print(resp.data['api_key']) if args.subscribe: for event in args.subscribe: - id = await aws.subscribe(event) - print(f'Subscribed for event {event} with messageid {id}') + msgid = await aws.subscribe(event) + print(f'Subscribed for event {event} with messageid {msgid}') resp = AFBResponse(await aws.response()) print(resp) diff --git a/pyagl/tests/test_bluetooth.py b/pyagl/tests/test_bluetooth.py new file mode 100644 index 0000000..0670f5e --- /dev/null +++ b/pyagl/tests/test_bluetooth.py @@ -0,0 +1,105 @@ +import asyncio +import os +import pytest + +from pyagl.services.base import AFBResponse, AFBT +from pyagl.services.bluetooth import BluetoothService as BTS +import logging + +logger = logging.getLogger(f'pytest-{BTS.service}') +logger.setLevel(logging.DEBUG) +pytestmark = pytest.mark.asyncio + + +@pytest.fixture(scope='module') +def event_loop(): + loop = asyncio.get_event_loop() + yield loop + loop.close() + + +@pytest.fixture(scope='module') +async def service(): + address = os.environ.get('AGL_TGT_IP', 'localhost') + port = os.environ.get('AGL_TGT_PORT', None) + + bts = await BTS(ip=address, port=port) + yield bts + await bts.websocket.close() + + +@pytest.mark.xfail +@pytest.fixture(scope='module') +def btaddr(): + bthtestaddr = os.environ.get('AGL_TEST_BT_ADDR', None) + if not bthtestaddr: + pytest.xfail('No test bluetooth test address set in environment variables') + + return bthtestaddr + + +@pytest.mark.dependency +async def test_default_adapter(event_loop, service: BTS): + msgid = await service.default_adapter() + resp = AFBResponse(await service.response()) + assert resp.status == 'success', resp + assert 'adapter' in resp.data.keys() + assert resp.data['adapter'] == 'hci0' + + +@pytest.mark.dependency(depends=['test_default_adapter']) +async def test_managed_objects(event_loop, service: BTS): + msgid = await service.managed_objects() + resp = AFBResponse(await service.response()) + assert resp.status == 'success', str(resp) + + +@pytest.mark.dependency(depends=['test_default_adapter']) +async def test_has_single_adapter(event_loop, service: BTS): + msgid = await service.managed_objects() + resp = AFBResponse(await service.response()) + assert len(resp.data['adapters']) == 1, \ + f'Detected {len(resp.data["adapters"])} adapters. Multiple adapters may also break testing' + + +@pytest.mark.dependency(depends=['test_default_adapter']) +async def test_adapter_state(event_loop, service: BTS): + msgid = await service.adapter_state('hci0') + resp = AFBResponse(await service.response()) + assert resp.status == 'success', 'adapter state verb failed' + + +async def test_pairing_verb(event_loop, service: BTS, btaddr): + msgid = await service.pair(btaddr) + resp = await service.afbresponse() + assert msgid == resp.msgid + assert resp.status == 'success', f'pair verb failed - {resp.info}' + + +async def test_connect_verb(event_loop, service: BTS, btaddr): + msgid = await service.connect(btaddr) + resp = await service.afbresponse() + assert msgid == resp.msgid + assert resp.status == 'success', f'connect verb failed - {resp.info}' + + +async def test_disconnect_verb(event_loop, service: BTS, btaddr): + msgid = await service.disconnect(btaddr) + resp = await service.afbresponse() + assert msgid == resp.msgid + assert resp.status == 'success', f'disconnect verb failed - {resp.info}' + + +async def test_remove_pairing_verb(event_loop, service: BTS, btaddr): + msgid = await service.remove_device(btaddr) + resp = await service.afbresponse() + assert msgid == resp.msgid + assert resp.status == 'success' + + +@pytest.mark.xfail(reason='This is expected to fail because there has to be an ongoing pairing attempt') +async def test_confirm_pairing_verb(event_loop, service: BTS, btaddr): + msgid = await service.confirm_pairing(pincode='123456') + resp = await service.afbresponse() + assert msgid == resp.msgid + assert resp.status == 'success', f'confirm_pairing verb failed - {resp.info}' diff --git a/pyagl/tests/test_gps.py b/pyagl/tests/test_gps.py new file mode 100644 index 0000000..7e56d1e --- /dev/null +++ b/pyagl/tests/test_gps.py @@ -0,0 +1,73 @@ +import asyncio +import os +import pytest +import logging +from pyagl.services.base import AFBResponse, AFBT +from pyagl.services.gps import GPSService as GPS +from concurrent.futures import TimeoutError + +pytestmark = pytest.mark.asyncio + +@pytest.fixture(scope='module') +def event_loop(): + loop = asyncio.get_event_loop() + yield loop + loop.close() + +@pytest.fixture(scope='module') +async def service(): + address = os.environ.get('AGL_TGT_IP', 'localhost') + port = os.environ.get('AGL_TGT_PORT', None) + gpss = await GPS(ip=address, port=port) + yield gpss + await gpss.websocket.close() + +# @pytest.fixture(scope='module') +# async def response(event_loop, service): +# async for _response in service.listener(): +# yield _response + +async def test_location_verb(event_loop, service: GPS): + msgid = await service.location() + resp = AFBResponse(await service.response()) + assert resp.msgid == msgid + +@pytest.mark.xfail # expecting this to fail because of "No 3D GNSS fix" and GPS is unavailable +async def test_location_result(event_loop, service: GPS): + msgid = await service.location() + resp = AFBResponse(await service.response()) + assert resp.status == 'success' + +async def test_subscribe_verb(event_loop, service: GPS): + msgid = await service.subscribe("") + resp = AFBResponse(await service.response()) + assert resp.msgid == msgid + assert resp.status == 'success' + +async def test_subscribe_location(event_loop, service: GPS): + msgid = await service.subscribe('location') + resp = AFBResponse(await service.response()) + assert resp.msgid == msgid + assert resp.status == 'success' + +async def test_unsubscribe(event_loop, service: GPS): + msgid = await service.unsubscribe('location') + resp = AFBResponse(await service.response()) + assert resp.msgid == msgid + assert resp.status == 'success' + +@pytest.mark.xfail # expecting this to fail because of "No 3D GNSS fix" and GPS is unavailable +async def test_location_events(event_loop, service: GPS): + msgid = await service.subscribe('location') + resp = AFBResponse(await service.response()) + assert resp.msgid == msgid + assert resp.status == 'success' # successful subscription + try: + resp = await asyncio.wait_for(service.afbresponse(), 10) + resp = AFBResponse(resp) + assert resp.type == AFBT.EVENT, f'Expected EVENT response, got {resp.type.name} instead' + # TODO one more assert for the actual received event, haven't received a location event yet + except TimeoutError: + pytest.xfail("Did not receive location event") + + diff --git a/templates/test/{{cookiecutter.file_name}}.py b/pyagl/tests/test_weather.py index e69de29..e69de29 100644 --- a/templates/test/{{cookiecutter.file_name}}.py +++ b/pyagl/tests/test_weather.py @@ -0,0 +1,26 @@ +import setuptools + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="pyagl", + version="0.0.1", + author="Edi Feschiyan", + author_email="edi.feschiyan@konsulko.com", + description="Python bindings and tests for Automotive Grade Linux services", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/refresher/pyagl", + packages=setuptools.find_packages(), + license="Apache 2.0", + install_requires=['websockets', 'parse', 'asyncssh', 'pytest', 'pytest-asyncio'], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: POSIX :: Linux", + ], + python_requires='>=3.6', +) diff --git a/templates/cookiecutter.json b/templates/cookiecutter.json new file mode 100644 index 0000000..c4afdd6 --- /dev/null +++ b/templates/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "services_dir": "services", + "tests_dir": "tests", + "service_slug": "service", + "aglsystemdservice": "agl-service-something", + "classname": "NewService", + "api": "serviceapi" +} diff --git a/templates/service/cookiecutter.json b/templates/service/cookiecutter.json deleted file mode 100644 index f37ea1f..0000000 --- a/templates/service/cookiecutter.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aglsystemdservice": "agl-service-something", - "classname": "NewService", - "api": "serviceapi", - "verblist": ["subscribe", "unsubscribe"] -}
\ No newline at end of file diff --git a/templates/service/{{cookiecutter.file_name}}.py b/templates/service/{{cookiecutter.file_name}}.py deleted file mode 100644 index 6defd28..0000000 --- a/templates/service/{{cookiecutter.file_name}}.py +++ /dev/null @@ -1,9 +0,0 @@ -from aglbaseservice import AGLBaseService, AFBResponse -import asyncio -import os - -class {{cookiecutter.classname}}(AGLBaseService): - - def __init__(self, ip, port=None, service='{{cookiecutter.aglsystemdservice}}'): - super().__init__(api='{{cookiecutter.api}}', ip=ip, port=port, service=service) - diff --git a/templates/{{cookiecutter.services_dir}}/{{cookiecutter.service_slug}}.py b/templates/{{cookiecutter.services_dir}}/{{cookiecutter.service_slug}}.py new file mode 100644 index 0000000..dab3a68 --- /dev/null +++ b/templates/{{cookiecutter.services_dir}}/{{cookiecutter.service_slug}}.py @@ -0,0 +1,17 @@ +from pyagl.services.base import AGLBaseService, AFBResponse +import asyncio +import os + + +class {{cookiecutter.classname}}(AGLBaseService): + service = '{{cookiecutter.aglsystemdservice}}' + parser = AGLBaseService.getparser() + + def __init__(self, ip, port=None, service='{{cookiecutter.aglsystemdservice}}'): + super().__init__(api='{{cookiecutter.api}}', ip=ip, port=port, service=service) + # more init stuff specific to the new service + +async def main(loop): + args = {{cookiecutter.classname}}.parser.parse_args() + svc = {{cookiecutter.classname}}(args.ipaddr) + diff --git a/templates/{{cookiecutter.tests_dir}}/test_{{cookiecutter.service_slug}}.py b/templates/{{cookiecutter.tests_dir}}/test_{{cookiecutter.service_slug}}.py new file mode 100644 index 0000000..e193205 --- /dev/null +++ b/templates/{{cookiecutter.tests_dir}}/test_{{cookiecutter.service_slug}}.py @@ -0,0 +1,23 @@ +import asyncio +import os +import pytest +import logging +from pyagl.services.base import AFBResponse, AFBT +from concurrent.futures import TimeoutError + +from pyagl.services.{{cookiecutter.service_slug}} import {{cookiecutter.classname}} +pytestmark = pytest.mark.asyncio + +@pytest.fixture(scope='module') +def event_loop(): + loop = asyncio.get_event_loop() + yield loop + loop.close() + +@pytest.fixture(scope='module') +async def service(): + address = os.environ.get('AGL_TGT_IP', 'localhost') + port = os.environ.get('AGL_TGT_PORT', None) + svc = await {{cookiecutter.classname}}(ip=address, port=port) + yield svc + await svc.websocket.close() |