Skip to content

Commit

Permalink
Reorganized testing
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Nov 23, 2014
1 parent ad16c32 commit bc4b81d
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 241 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ install:
script:
- flake8 homeassistant --exclude bower_components,external
- pylint homeassistant
- coverage run --source=homeassistant -m homeassistant -t test
- coverage run --source=homeassistant -m unittest discover test
after_success:
- coveralls
27 changes: 11 additions & 16 deletions homeassistant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
SERVICE_HOMEASSISTANT_STOP = "stop"

EVENT_HOMEASSISTANT_START = "homeassistant_start"
EVENT_HOMEASSISTANT_STOP = "homeassistant_stop"
EVENT_STATE_CHANGED = "state_changed"
EVENT_TIME_CHANGED = "time_changed"
EVENT_CALL_SERVICE = "call_service"
Expand Down Expand Up @@ -62,10 +63,6 @@ def __init__(self):
self.services = ServiceRegistry(self.bus, pool)
self.states = StateMachine(self.bus)

# Components in a thread we might want to stop later
self.timer = None
self.http = None

self.config_dir = os.getcwd()

def get_config_path(self, path):
Expand All @@ -74,7 +71,7 @@ def get_config_path(self, path):

def start(self):
""" Start home assistant. """
self.timer = Timer(self)
Timer(self)

self.bus.fire(EVENT_HOMEASSISTANT_START)

Expand Down Expand Up @@ -234,13 +231,12 @@ def stop(self):
""" Stops Home Assistant and shuts down all threads. """
_LOGGER.info("Stopping")

self._pool.stop()
self.bus.fire(EVENT_HOMEASSISTANT_STOP)

if self.http is not None:
self.http.shutdown()
# Wait till all responses to homeassistant_stop are done
self._pool.block_till_done()

if self.timer is not None:
self.timer.shutdown()
self._pool.stop()


def _process_match_param(parameter):
Expand All @@ -263,7 +259,7 @@ def _matcher(subject, pattern):

class JobPriority(util.OrderedEnum):
""" Provides priorities for bus events. """
# pylint: disable=no-init
# pylint: disable=no-init,too-few-public-methods

EVENT_SERVICE = 1
EVENT_STATE = 2
Expand Down Expand Up @@ -312,7 +308,7 @@ def busy_callback(current_jobs, pending_jobs_count):

class EventOrigin(enum.Enum):
""" Distinguish between origin of event. """
# pylint: disable=no-init
# pylint: disable=no-init,too-few-public-methods

local = "LOCAL"
remote = "REMOTE"
Expand Down Expand Up @@ -626,6 +622,9 @@ def __init__(self, hass, interval=None):
hass.listen_once_event(EVENT_HOMEASSISTANT_START,
lambda event: self.start())

hass.listen_once_event(EVENT_HOMEASSISTANT_STOP,
lambda event: self._stop.set())

def run(self):
""" Start the timer. """

Expand Down Expand Up @@ -661,10 +660,6 @@ def run(self):

self._bus.fire(EVENT_TIME_CHANGED, {ATTR_NOW: now})

def shutdown(self):
_LOGGER.info("Timer:Stopping")
self._stop.set()


class HomeAssistantError(Exception):
""" General Home Assistant exception occured. """
Expand Down
94 changes: 39 additions & 55 deletions homeassistant/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

def main():
""" Starts Home Assistant. Will create demo config if no config found. """
tasks = ['serve', 'test']

parser = argparse.ArgumentParser()
parser.add_argument(
Expand All @@ -29,64 +28,49 @@ def main():
default="config",
help="Directory that contains the Home Assistant configuration")

parser.add_argument(
'-t', '--task',
default=tasks[0],
choices=tasks,
help="Task to execute. Defaults to serve.")

args = parser.parse_args()

if args.task == tasks[1]:
# unittest does not like our command line arguments, remove them
sys.argv[1:] = []

import unittest

unittest.main(module='homeassistant.test')

else:
# Validate that all core dependencies are installed
import_fail = False

for module in ['requests']:
try:
importlib.import_module(module)
except ImportError:
import_fail = True
print(
'Fatal Error: Unable to find dependency {}'.format(module))

if import_fail:
print(("Install dependencies by running: "
"pip3 install -r requirements.txt"))
exit()

# Test if configuration directory exists
config_dir = os.path.join(os.getcwd(), args.config)

if not os.path.isdir(config_dir):
print(('Fatal Error: Unable to find specified configuration '
'directory {} ').format(config_dir))
# Validate that all core dependencies are installed
import_fail = False

for module in ['requests']:
try:
importlib.import_module(module)
except ImportError:
import_fail = True
print(
'Fatal Error: Unable to find dependency {}'.format(module))

if import_fail:
print(("Install dependencies by running: "
"pip3 install -r requirements.txt"))
exit()

# Test if configuration directory exists
config_dir = os.path.join(os.getcwd(), args.config)

if not os.path.isdir(config_dir):
print(('Fatal Error: Unable to find specified configuration '
'directory {} ').format(config_dir))
sys.exit()

config_path = os.path.join(config_dir, 'home-assistant.conf')

# Ensure a config file exists to make first time usage easier
if not os.path.isfile(config_path):
try:
with open(config_path, 'w') as conf:
conf.write("[http]\n")
conf.write("api_password=password\n\n")
conf.write("[demo]\n")
except IOError:
print(('Fatal Error: No configuration file found and unable '
'to write a default one to {}').format(config_path))
sys.exit()

config_path = os.path.join(config_dir, 'home-assistant.conf')

# Ensure a config file exists to make first time usage easier
if not os.path.isfile(config_path):
try:
with open(config_path, 'w') as conf:
conf.write("[http]\n")
conf.write("api_password=password\n\n")
conf.write("[demo]\n")
except IOError:
print(('Fatal Error: No configuration file found and unable '
'to write a default one to {}').format(config_path))
sys.exit()

hass = bootstrap.from_config_file(config_path)
hass.start()
hass.block_till_stopped()
hass = bootstrap.from_config_file(config_path)
hass.start()
hass.block_till_stopped()

if __name__ == "__main__":
main()
14 changes: 6 additions & 8 deletions homeassistant/components/device_tracker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,9 @@ def update_devices(self, found_devices=None):
is_new_file = not os.path.isfile(known_dev_path)

with open(known_dev_path, 'a') as outp:
_LOGGER.info((
"Found {} new devices,"
" updating {}").format(len(unknown_devices),
known_dev_path))
_LOGGER.info(
"Found %d new devices, updating %s",
len(unknown_devices), known_dev_path)

writer = csv.writer(outp)

Expand All @@ -197,10 +196,9 @@ def update_devices(self, found_devices=None):
'picture': ""}

except IOError:
_LOGGER.exception((
"Error updating {}"
"with {} new devices").format(known_dev_path,
len(unknown_devices)))
_LOGGER.exception(
"Error updating %s with %d new devices",
known_dev_path, len(unknown_devices))

self.lock.release()

Expand Down
10 changes: 7 additions & 3 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@

_LOGGER = logging.getLogger(__name__)

# TODO add shutdown https://docs.python.org/3.4/library/socketserver.html#socketserver.BaseServer.shutdown

def setup(hass, config):
""" Sets up the HTTP API and debug interface. """

Expand All @@ -136,20 +136,24 @@ def setup(hass, config):
lambda event:
threading.Thread(target=server.start, daemon=True).start())

hass.listen_once_event(
ha.EVENT_HOMEASSISTANT_STOP,
lambda event: server.shutdown())

# If no local api set, set one with known information
if isinstance(hass, rem.HomeAssistant) and hass.local_api is None:
hass.local_api = \
rem.API(util.get_local_ip(), api_password, server_port)

hass.server = server

return True


class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
""" Handle HTTP requests in a threaded fashion. """
# pylint: disable=too-few-public-methods

allow_reuse_address = True
daemon_threads = True

# pylint: disable=too-many-arguments
def __init__(self, server_address, RequestHandlerClass,
Expand Down
29 changes: 27 additions & 2 deletions homeassistant/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import requests

import homeassistant as ha
from homeassistant.remote_json import JSONEncoder

SERVER_PORT = 8123

Expand All @@ -39,9 +38,9 @@
_LOGGER = logging.getLogger(__name__)


# pylint: disable=no-init, invalid-name
class APIStatus(enum.Enum):
""" Represents API status. """
# pylint: disable=no-init,invalid-name,too-few-public-methods

OK = "ok"
INVALID_PASSWORD = "invalid_password"
Expand Down Expand Up @@ -135,9 +134,22 @@ def start(self):
self.bus.fire(ha.EVENT_HOMEASSISTANT_START,
origin=ha.EventOrigin.remote)

def stop(self):
""" Stops Home Assistant and shuts down all threads. """
_LOGGER.info("Stopping")

self.bus.fire(ha.EVENT_HOMEASSISTANT_STOP,
origin=ha.EventOrigin.remote)

# Wait till all responses to homeassistant_stop are done
self._pool.block_till_done()

self._pool.stop()


class EventBus(ha.EventBus):
""" EventBus implementation that forwards fire_event to remote API. """
# pylint: disable=too-few-public-methods

def __init__(self, api, pool=None):
super().__init__(pool)
Expand Down Expand Up @@ -239,6 +251,19 @@ def _state_changed_listener(self, event):
self._states[event.data['entity_id']] = event.data['new_state']


class JSONEncoder(json.JSONEncoder):
""" JSONEncoder that supports Home Assistant objects. """
# pylint: disable=too-few-public-methods,method-hidden

def default(self, obj):
""" Converts Home Assistant objects and hands
other objects to the original method. """
if isinstance(obj, ha.State):
return obj.as_dict()

return json.JSONEncoder.default(self, obj)


def validate_api(api):
""" Makes a call to validate API. """
try:
Expand Down
21 changes: 0 additions & 21 deletions homeassistant/remote_json.py

This file was deleted.

Loading

0 comments on commit bc4b81d

Please sign in to comment.