Skip to content

Commit

Permalink
Fix #75 and add tests (#86)
Browse files Browse the repository at this point in the history
* Fix #75 and abstract functions

* Add tests

* Add tests to .travis.yml
  • Loading branch information
Lanseuo authored and mike-grant committed Jan 5, 2019
1 parent d1b0f2e commit 9513a8a
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 40 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ language: python
python:
- "3.6"
install:
- "pip install flake8"
- "pip install flake8 pytest"
- "pip install -r requirements.txt"
script:
- "flake8 haaska.py"
- "python -m pytest test.py"
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# haaska: Home Assistant Alexa Skill Adapter

[![Build Status](https://travis-ci.org/mike-grant/haaska.svg?branch=master)](https://travis-ci.org/mike-grant/haaska)

---
Expand All @@ -10,6 +11,13 @@ This provides voice control for a connected home managed by Home Assistant, thro
### Getting Started
To get started, head over to the [haaska Wiki](https://github.com/mike-grant/haaska/wiki).

### Development

Run tests

```
python -m pytest test.py
```

### Thanks and Acknowledgement

Expand All @@ -22,4 +30,4 @@ This fork of haaska was created by [@mike-grant](https://github.com/mike-grant).
Documentation and additional maintenance is done by [@anthonylavado](https://github.com/anthonylavado), and contributors like you.

### License
haaska is provided under the [MIT License](license.md).
haaska is provided under the [MIT License](LICENSE).
78 changes: 40 additions & 38 deletions haaska.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,72 +32,74 @@
class HomeAssistant(object):
def __init__(self, config):
self.config = config
self.url = config.url.rstrip('/')
agent_str = 'Home Assistant Alexa Smart Home Skill - %s - %s'
agent_fmt = agent_str % (os.environ['AWS_DEFAULT_REGION'],
requests.utils.default_user_agent())

self.session = requests.Session()
self.session.headers = {'Authorization':
f'Bearer {config.bearer_token}',
'content-type': 'application/json',
'User-Agent': agent_fmt}
self.session.headers = {
'Authorization': f'Bearer {config.bearer_token}',
'content-type': 'application/json',
'User-Agent': self.get_user_agent()
}
self.session.verify = config.ssl_verify
self.session.cert = config.ssl_client

def build_url(self, relurl):
return '%s/%s' % (self.config.url, relurl)
def build_url(self, endpoint):
return f'{self.config.url}/api/{endpoint}'

def get_user_agent(self):
library = "Home Assistant Alexa Smart Home Skill"
aws_region = os.environ.get("AWS_DEFAULT_REGION")
default_user_agent = requests.utils.default_user_agent()
return f"{library} - {aws_region} - {default_user_agent}"

def get(self, relurl):
r = self.session.get(self.build_url(relurl))
def get(self, endpoint):
r = self.session.get(self.build_url(endpoint))
r.raise_for_status()
return r.json()

def post(self, relurl, d, wait=False):
def post(self, endpoint, data, wait=False):
read_timeout = None if wait else 0.01
r = None
try:
logger.debug('calling %s with %s', relurl, str(d))
r = self.session.post(self.build_url(relurl),
data=json.dumps(d),
logger.debug(f'calling {endpoint} with {data}')
r = self.session.post(self.build_url(endpoint),
data=json.dumps(data),
timeout=(None, read_timeout))
r.raise_for_status()
return r.json()
except requests.exceptions.ReadTimeout:
# Allow response timeouts after request was sent
logger.debug('request for %s sent without waiting for response',
relurl)
return r
logger.debug(
f'request for {endpoint} sent without waiting for response')
return None


class Configuration(object):
def __init__(self, filename=None, optsDict=None):
def __init__(self, filename=None, opts_dict=None):
self._json = {}
if filename is not None:
with open(filename) as f:
self._json = json.load(f)

if optsDict is not None:
self._json = optsDict
if opts_dict is not None:
self._json = opts_dict

opts = {}
opts['url'] = self.get(['url', 'ha_url'],
default='http://localhost:8123/api')
opts['ssl_verify'] = self.get(['ssl_verify', 'ha_cert'], default=True)
opts['bearer_token'] = self.get(['bearer_token'], default='')
opts['ssl_client'] = self.get(['ssl_client'], default='')
opts['debug'] = self.get(['debug'], default=False)
self.opts = opts
self.url = self.get_url(self.get(['url', 'ha_url']))
self.ssl_verify = self.get(['ssl_verify', 'ha_cert'], default=True)
self.bearer_token = self.get(['bearer_token'], default='')
self.ssl_client = self.get(['ssl_client'], default='')
self.debug = self.get(['debug'], default=False)

def __getattr__(self, name):
return self.opts[name]

def get(self, keys, default):
def get(self, keys, default=None):
for key in keys:
if key in self._json:
return self._json[key]
return default

def dump(self):
return json.dumps(self.opts, indent=2, separators=(',', ': '))
def get_url(self, url):
"""Returns Home Assistant base url without '/api' or trailing slash"""
if not url:
raise ValueError('Property "url" is missing in config')

return url.rstrip("/api").rstrip("/")


def event_handler(event, context):
Expand All @@ -106,4 +108,4 @@ def event_handler(event, context):
logger.setLevel(logging.DEBUG)
ha = HomeAssistant(config)

return ha.post('alexa/smart_home', event, wait=True).json()
return ha.post('alexa/smart_home', event, wait=True)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest==4.0.2
requests==2.21.0
38 changes: 38 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os
import pytest

from haaska import HomeAssistant, Configuration

@pytest.fixture
def configuration():
return Configuration(opts_dict={
"url": "http://localhost:8123",
"bearer_token": "",
"debug": False,
"ssl_verify": True,
"ssl_client": []
})

@pytest.fixture
def home_assistant(configuration):
return HomeAssistant(configuration)

def test_ha_build_url(home_assistant):
url = home_assistant.build_url("test")
assert url == "http://localhost:8123/api/test"

def test_get_user_agent(home_assistant):
os.environ["AWS_DEFAULT_REGION"] = "test"
user_agent = home_assistant.get_user_agent()
assert user_agent.startswith("Home Assistant Alexa Smart Home Skill - test - python-requests/")

def test_config_get(configuration):
assert configuration.get(["debug"]) == False
assert configuration.get(["test"]) == None
assert configuration.get(["test"], default="default") == "default"

def test_config_get_url(configuration):
expected = "http://hass.example.com:8123"
assert configuration.get_url("http://hass.example.com:8123/") == expected
assert configuration.get_url("http://hass.example.com:8123/api") == expected
assert configuration.get_url("http://hass.example.com:8123/api/") == expected

0 comments on commit 9513a8a

Please sign in to comment.