diff --git a/.travis.yml b/.travis.yml index e15564b2b0f779..ff38ef3ced1684 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/homeassistant/__init__.py b/homeassistant/__init__.py index 1372f86b3b4a7e..39980937bc0700 100644 --- a/homeassistant/__init__.py +++ b/homeassistant/__init__.py @@ -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" @@ -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): @@ -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) @@ -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): @@ -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 @@ -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" @@ -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. """ @@ -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. """ diff --git a/homeassistant/__main__.py b/homeassistant/__main__.py index 7e8952f55eb803..c8d50151cea78f 100644 --- a/homeassistant/__main__.py +++ b/homeassistant/__main__.py @@ -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( @@ -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() diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 277bdd17468d67..85e7d206e3e562 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -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) @@ -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() diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index ecf83f06c7dd29..8c6ddc1e5e0dbb 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -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. """ @@ -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, diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 6c48cb96b0a458..3ee38d15af86a1 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -18,7 +18,6 @@ import requests import homeassistant as ha -from homeassistant.remote_json import JSONEncoder SERVER_PORT = 8123 @@ -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" @@ -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) @@ -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: diff --git a/homeassistant/remote_json.py b/homeassistant/remote_json.py deleted file mode 100644 index ca540ac34caeb0..00000000000000 --- a/homeassistant/remote_json.py +++ /dev/null @@ -1,21 +0,0 @@ -# pylint: skip-file -""" -Helper methods for using JSON. - -This used to be in homeassistant.remote but has been moved -to this module because of a bug in PyLint that would make it crash. -""" -import homeassistant as ha -import json - - -class JSONEncoder(json.JSONEncoder): - """ JSONEncoder that supports Home Assistant objects. """ - - def default(self, obj): - """ Checks if Home Assistat object and encodes if possible. - Else hand it off to original method. """ - if isinstance(obj, ha.State): - return obj.as_dict() - - return json.JSONEncoder.default(self, obj) diff --git a/homeassistant/util.py b/homeassistant/util.py index 69cfd52b3cd189..b4c7966baa3063 100644 --- a/homeassistant/util.py +++ b/homeassistant/util.py @@ -153,7 +153,7 @@ def get_local_ip(): class OrderedEnum(enum.Enum): """ Taken from Python 3.4.0 docs. """ - # pylint: disable=no-init + # pylint: disable=no-init, too-few-public-methods def __ge__(self, other): if self.__class__ is other.__class__: @@ -215,8 +215,8 @@ class ThreadPool(object): """ A simple queue-based thread pool. Will initiate it's workers using worker(queue).start() """ + # pylint: disable=too-many-instance-attributes - # pylint: disable=too-few-public-methods def __init__(self, worker_count, job_handler, busy_callback=None): """ worker_count: number of threads to run that handle jobs @@ -224,8 +224,8 @@ def __init__(self, worker_count, job_handler, busy_callback=None): busy_callback: method to be called when queue gets too big. Parameters: list_of_current_jobs, number_pending_jobs """ - work_queue = self.work_queue = queue.PriorityQueue() - current_jobs = self.current_jobs = [] + self.work_queue = work_queue = queue.PriorityQueue() + self.current_jobs = current_jobs = [] self.worker_count = worker_count self.busy_callback = busy_callback self.busy_warning_limit = worker_count**2 @@ -260,19 +260,21 @@ def add_job(self, priority, job): def block_till_done(self): """ Blocks till all work is done. """ - with self._lock: - self.work_queue.join() + self.work_queue.join() def stop(self): """ Stops all the threads. """ with self._lock: + if not self.running: + return + # Clear the queue while self.work_queue.qsize() > 0: self.work_queue.get() self.work_queue.task_done() # Tell the workers to quit - for i in range(self.worker_count): + for _ in range(self.worker_count): self.add_job(1000, self._quit_task) self.running = False diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 00000000000000..26934d045d4c24 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +pylint homeassistant +flake8 homeassistant --exclude bower_components,external +python3 -m unittest discover test diff --git a/test/components/__init__.py b/test/test_component_core.py similarity index 91% rename from test/components/__init__.py rename to test/test_component_core.py index 32a6d5d32e64e3..eb56112f906b71 100644 --- a/test/components/__init__.py +++ b/test/test_component_core.py @@ -1,9 +1,8 @@ """ -homeassistant.test -~~~~~~~~~~~~~~~~~~ - -Provides tests to verify that Home Assistant modules do what they should do. +test.test_component_core +~~~~~~~~~~~~~~~~~~~~~~~~ +Tests core compoments. """ # pylint: disable=protected-access,too-many-public-methods import unittest @@ -25,6 +24,10 @@ def setUp(self): # pylint: disable=invalid-name self.hass.states.set('light.Bowl', comps.STATE_ON) self.hass.states.set('light.Ceiling', comps.STATE_OFF) + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass._pool.stop() + def test_is_on(self): """ Test is_on method. """ self.assertTrue(comps.is_on(self.hass, 'light.Bowl')) diff --git a/test/components/http.py b/test/test_component_http.py similarity index 79% rename from test/components/http.py rename to test/test_component_http.py index 22144704a525ca..047e77bcfbf6ad 100644 --- a/test/components/http.py +++ b/test/test_component_http.py @@ -1,14 +1,14 @@ """ -homeassistant.test -~~~~~~~~~~~~~~~~~~ - -Provides tests to verify that Home Assistant modules do what they should do. +test.test_component_http +~~~~~~~~~~~~~~~~~~~~~~~~ +Tests Home Assistant HTTP component does what it should do. """ # pylint: disable=protected-access,too-many-public-methods import re import unittest import json +import logging import requests @@ -16,21 +16,49 @@ import homeassistant.remote as remote import homeassistant.components.http as http -from test.remote import _url, ensure_homeassistant_started - API_PASSWORD = "test1234" +# Somehow the socket that holds the default port does not get released +# when we close down HA in a different test case. Until I have figured +# out what is going on, let's run this test on a different port. +SERVER_PORT = 8120 + +HTTP_BASE_URL = "http://127.0.0.1:{}".format(SERVER_PORT) + HA_HEADERS = {remote.AUTH_HEADER: API_PASSWORD} +def _url(path=""): + """ Helper method to generate urls. """ + return HTTP_BASE_URL + path + + +def setUpModule(): + """ Initalizes a Home Assistant server. """ + global hass + + hass = ha.HomeAssistant() + + hass.bus.listen('test_event', lambda _: _) + hass.states.set('test.test', 'a_state') + + http.setup(hass, + {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD, + http.CONF_SERVER_PORT: SERVER_PORT}}) + + hass.start() + + +def tearDownModule(): + """ Stops the Home Assistant server. """ + global hass + + hass.stop() + + class TestHTTP(unittest.TestCase): """ Test the HTTP debug interface and API. """ - @classmethod - def setUpClass(cls): # pylint: disable=invalid-name - """ things to be run when tests are started. """ - cls.hass = ensure_homeassistant_started() - def test_get_frontend(self): """ Tests if we can get the frontend. """ req = requests.get(_url("")) @@ -68,7 +96,7 @@ def test_api_list_state_entities(self): remote_data = [ha.State.from_dict(item) for item in req.json()] - self.assertEqual(self.hass.states.all(), remote_data) + self.assertEqual(hass.states.all(), remote_data) def test_api_get_state(self): """ Test if the debug interface allows us to get a state. """ @@ -78,7 +106,7 @@ def test_api_get_state(self): data = ha.State.from_dict(req.json()) - state = self.hass.states.get("test.test") + state = hass.states.get("test.test") self.assertEqual(state.state, data.state) self.assertEqual(state.last_changed, data.last_changed) @@ -95,14 +123,14 @@ def test_api_get_non_existing_state(self): def test_api_state_change(self): """ Test if we can change the state of an entity that exists. """ - self.hass.states.set("test.test", "not_to_be_set") + hass.states.set("test.test", "not_to_be_set") requests.post(_url(remote.URL_API_STATES_ENTITY.format("test.test")), data=json.dumps({"state": "debug_state_change2", "api_password": API_PASSWORD})) self.assertEqual("debug_state_change2", - self.hass.states.get("test.test").state) + hass.states.get("test.test").state) # pylint: disable=invalid-name def test_api_state_change_of_non_existing_entity(self): @@ -117,7 +145,7 @@ def test_api_state_change_of_non_existing_entity(self): data=json.dumps({"state": new_state, "api_password": API_PASSWORD})) - cur_state = (self.hass.states. + cur_state = (hass.states. get("test_entity.that_does_not_exist").state) self.assertEqual(201, req.status_code) @@ -132,13 +160,13 @@ def listener(event): # pylint: disable=unused-argument """ Helper method that will verify our event got called. """ test_value.append(1) - self.hass.listen_once_event("test.event_no_data", listener) + hass.listen_once_event("test.event_no_data", listener) requests.post( _url(remote.URL_API_EVENTS_EVENT.format("test.event_no_data")), headers=HA_HEADERS) - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) @@ -153,14 +181,14 @@ def listener(event): # pylint: disable=unused-argument if "test" in event.data: test_value.append(1) - self.hass.listen_once_event("test_event_with_data", listener) + hass.listen_once_event("test_event_with_data", listener) requests.post( _url(remote.URL_API_EVENTS_EVENT.format("test_event_with_data")), data=json.dumps({"test": 1}), headers=HA_HEADERS) - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) @@ -173,14 +201,14 @@ def listener(event): # pylint: disable=unused-argument """ Helper method that will verify our event got called. """ test_value.append(1) - self.hass.listen_once_event("test_event_bad_data", listener) + hass.listen_once_event("test_event_bad_data", listener) req = requests.post( _url(remote.URL_API_EVENTS_EVENT.format("test_event_bad_data")), data=json.dumps('not an object'), headers=HA_HEADERS) - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(422, req.status_code) self.assertEqual(0, len(test_value)) @@ -190,7 +218,7 @@ def test_api_get_event_listeners(self): req = requests.get(_url(remote.URL_API_EVENTS), headers=HA_HEADERS) - local = self.hass.bus.listeners + local = hass.bus.listeners for event in req.json(): self.assertEqual(event["listener_count"], @@ -203,7 +231,7 @@ def test_api_get_services(self): req = requests.get(_url(remote.URL_API_SERVICES), headers=HA_HEADERS) - local_services = self.hass.services.services + local_services = hass.services.services for serv_domain in req.json(): local = local_services.pop(serv_domain["domain"]) @@ -218,14 +246,14 @@ def listener(service_call): # pylint: disable=unused-argument """ Helper method that will verify that our service got called. """ test_value.append(1) - self.hass.services.register("test_domain", "test_service", listener) + hass.services.register("test_domain", "test_service", listener) requests.post( _url(remote.URL_API_SERVICES_SERVICE.format( "test_domain", "test_service")), headers=HA_HEADERS) - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) @@ -239,7 +267,7 @@ def listener(service_call): # pylint: disable=unused-argument if "test" in service_call.data: test_value.append(1) - self.hass.services.register("test_domain", "test_service", listener) + hass.services.register("test_domain", "test_service", listener) requests.post( _url(remote.URL_API_SERVICES_SERVICE.format( @@ -247,6 +275,6 @@ def listener(service_call): # pylint: disable=unused-argument data=json.dumps({"test": 1}), headers=HA_HEADERS) - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) diff --git a/test/__init__.py b/test/test_core.py similarity index 92% rename from test/__init__.py rename to test/test_core.py index 0c08ea7c0e7381..5b94e7c9833791 100644 --- a/test/__init__.py +++ b/test/test_core.py @@ -1,9 +1,8 @@ """ -homeassistant.test -~~~~~~~~~~~~~~~~~~ - -Provides tests to verify that Home Assistant modules do what they should do. +test.test_core +~~~~~~~~~~~~~~ +Provides tests to verify that Home Assistant core works. """ # pylint: disable=protected-access,too-many-public-methods import os @@ -28,6 +27,10 @@ def setUp(self): # pylint: disable=invalid-name self.hass.states.set("light.Bowl", "on") self.hass.states.set("switch.AC", "off") + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass._pool.stop() + def test_get_config_path(self): """ Test get_config_path method. """ self.assertEqual(os.getcwd(), self.hass.config_dir) @@ -43,7 +46,7 @@ def test_block_till_stoped(self): blocking_thread.start() # Python will now give attention to the other thread - time.sleep(.01) + time.sleep(1) self.assertTrue(blocking_thread.is_alive()) @@ -205,6 +208,10 @@ def setUp(self): # pylint: disable=invalid-name self.bus = ha.EventBus() self.bus.listen('test_event', lambda x: len) + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.bus._pool.stop() + def test_add_remove_listener(self): """ Test remove_listener method. """ old_count = len(self.bus.listeners) @@ -257,6 +264,10 @@ def setUp(self): # pylint: disable=invalid-name self.states.set("light.Bowl", "on") self.states.set("switch.AC", "off") + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.bus._pool.stop() + def test_is_state(self): """ Test is_state method. """ self.assertTrue(self.states.is_state('light.Bowl', 'on')) @@ -291,11 +302,15 @@ class TestServiceRegistry(unittest.TestCase): def setUp(self): # pylint: disable=invalid-name """ things to be run when tests are started. """ - pool = ha.create_worker_pool() - self.bus = ha.EventBus(pool) - self.services = ha.ServiceRegistry(self.bus, pool) + self.pool = ha.create_worker_pool() + self.bus = ha.EventBus(self.pool) + self.services = ha.ServiceRegistry(self.bus, self.pool) self.services.register("test_domain", "test_service", lambda x: len) + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.pool.stop() + def test_has_service(self): """ Test has_service method. """ self.assertTrue( diff --git a/test/loader.py b/test/test_loader.py similarity index 72% rename from test/loader.py rename to test/test_loader.py index 5f13e5f87adf86..fb0a698280c12e 100644 --- a/test/loader.py +++ b/test/test_loader.py @@ -1,9 +1,8 @@ """ -homeassistant.test +test.test_loader ~~~~~~~~~~~~~~~~~~ -Provides tests to verify that Home Assistant modules do what they should do. - +Provides tests to verify that we can load components. """ # pylint: disable=too-many-public-methods import unittest @@ -19,6 +18,10 @@ def setUp(self): # pylint: disable=invalid-name self.hass = ha.HomeAssistant() loader.prepare(self.hass) + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass._pool.stop() + def test_get_component(self): """ Test if get_component works. """ self.assertEqual(http, loader.get_component('http')) diff --git a/test/remote.py b/test/test_remote.py similarity index 50% rename from test/remote.py rename to test/test_remote.py index c39adb20bac411..d5e77c80ac9466 100644 --- a/test/remote.py +++ b/test/test_remote.py @@ -1,12 +1,12 @@ """ -homeassistant.test -~~~~~~~~~~~~~~~~~~ - -Provides tests to verify that Home Assistant modules do what they should do. +test.remote +~~~~~~~~~~~ +Tests Home Assistant remote methods and classes. """ # pylint: disable=protected-access,too-many-public-methods import unittest +import logging import homeassistant as ha import homeassistant.remote as remote @@ -24,66 +24,47 @@ def _url(path=""): return HTTP_BASE_URL + path -class HAHelper(object): # pylint: disable=too-few-public-methods - """ Helper class to keep track of current running HA instance. """ - hass = None - slave = None - - -def ensure_homeassistant_started(): - """ Ensures home assistant is started. """ - - if not HAHelper.hass: - print("Setting up new HA") - hass = ha.HomeAssistant() - - hass.bus.listen('test_event', lambda _: _) - hass.states.set('test.test', 'a_state') +def setUpModule(): + """ Initalizes a Home Assistant server and Slave instance. """ + global hass, slave, master_api - http.setup(hass, - {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD}}) + hass = ha.HomeAssistant() - hass.start() + hass.bus.listen('test_event', lambda _: _) + hass.states.set('test.test', 'a_state') - HAHelper.hass = hass + http.setup(hass, + {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD}}) - return HAHelper.hass + hass.start() + master_api = remote.API("127.0.0.1", API_PASSWORD) -def ensure_slave_started(): - """ Ensure a home assistant slave is started. """ + # Start slave + local_api = remote.API("127.0.0.1", API_PASSWORD, 8124) + slave = remote.HomeAssistant(master_api, local_api) - ensure_homeassistant_started() + http.setup(slave, + {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD, + http.CONF_SERVER_PORT: 8124}}) - if not HAHelper.slave: - local_api = remote.API("127.0.0.1", API_PASSWORD, 8124) - remote_api = remote.API("127.0.0.1", API_PASSWORD) - slave = remote.HomeAssistant(remote_api, local_api) + slave.start() - http.setup(slave, - {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD, - http.CONF_SERVER_PORT: 8124}}) - slave.start() +def tearDownModule(): + """ Stops the Home Assistant server and slave. """ + global hass, slave - HAHelper.slave = slave - - return HAHelper.slave + hass.stop() + slave.stop() class TestRemoteMethods(unittest.TestCase): """ Test the homeassistant.remote module. """ - @classmethod - def setUpClass(cls): # pylint: disable=invalid-name - """ things to be run when tests are started. """ - cls.hass = ensure_homeassistant_started() - - cls.api = remote.API("127.0.0.1", API_PASSWORD) - def test_validate_api(self): """ Test Python API validate_api. """ - self.assertEqual(remote.APIStatus.OK, remote.validate_api(self.api)) + self.assertEqual(remote.APIStatus.OK, remote.validate_api(master_api)) self.assertEqual(remote.APIStatus.INVALID_PASSWORD, remote.validate_api( @@ -91,8 +72,8 @@ def test_validate_api(self): def test_get_event_listeners(self): """ Test Python API get_event_listeners. """ - local_data = self.hass.bus.listeners - remote_data = remote.get_event_listeners(self.api) + local_data = hass.bus.listeners + remote_data = remote.get_event_listeners(master_api) for event in remote_data: self.assertEqual(local_data.pop(event["event"]), @@ -108,11 +89,11 @@ def listener(event): # pylint: disable=unused-argument """ Helper method that will verify our event got called. """ test_value.append(1) - self.hass.listen_once_event("test.event_no_data", listener) + hass.listen_once_event("test.event_no_data", listener) - remote.fire_event(self.api, "test.event_no_data") + remote.fire_event(master_api, "test.event_no_data") - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) @@ -120,34 +101,34 @@ def test_get_state(self): """ Test Python API get_state. """ self.assertEqual( - self.hass.states.get('test.test'), - remote.get_state(self.api, 'test.test')) + hass.states.get('test.test'), + remote.get_state(master_api, 'test.test')) def test_get_states(self): """ Test Python API get_state_entity_ids. """ self.assertEqual( - remote.get_states(self.api), self.hass.states.all()) + remote.get_states(master_api), hass.states.all()) def test_set_state(self): """ Test Python API set_state. """ - self.assertTrue(remote.set_state(self.api, 'test.test', 'set_test')) + self.assertTrue(remote.set_state(master_api, 'test.test', 'set_test')) - self.assertEqual('set_test', self.hass.states.get('test.test').state) + self.assertEqual('set_test', hass.states.get('test.test').state) def test_is_state(self): """ Test Python API is_state. """ self.assertTrue( - remote.is_state(self.api, 'test.test', - self.hass.states.get('test.test').state)) + remote.is_state(master_api, 'test.test', + hass.states.get('test.test').state)) def test_get_services(self): """ Test Python API get_services. """ - local_services = self.hass.services.services + local_services = hass.services.services - for serv_domain in remote.get_services(self.api): + for serv_domain in remote.get_services(master_api): local = local_services.pop(serv_domain["domain"]) self.assertEqual(local, serv_domain["services"]) @@ -160,11 +141,11 @@ def listener(service_call): # pylint: disable=unused-argument """ Helper method that will verify that our service got called. """ test_value.append(1) - self.hass.services.register("test_domain", "test_service", listener) + hass.services.register("test_domain", "test_service", listener) - remote.call_service(self.api, "test_domain", "test_service") + remote.call_service(master_api, "test_domain", "test_service") - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) @@ -172,12 +153,6 @@ def listener(service_call): # pylint: disable=unused-argument class TestRemoteClasses(unittest.TestCase): """ Test the homeassistant.remote module. """ - @classmethod - def setUpClass(cls): # pylint: disable=invalid-name - """ things to be run when tests are started. """ - cls.hass = ensure_homeassistant_started() - cls.slave = ensure_slave_started() - def test_home_assistant_init(self): """ Test HomeAssistant init. """ self.assertRaises( @@ -186,24 +161,24 @@ def test_home_assistant_init(self): def test_statemachine_init(self): """ Tests if remote.StateMachine copies all states on init. """ - self.assertEqual(len(self.hass.states.all()), - len(self.slave.states.all())) + self.assertEqual(len(hass.states.all()), + len(slave.states.all())) - for state in self.hass.states.all(): + for state in hass.states.all(): self.assertEqual( - state, self.slave.states.get(state.entity_id)) + state, slave.states.get(state.entity_id)) def test_statemachine_set(self): """ Tests if setting the state on a slave is recorded. """ - self.slave.states.set("remote.test", "remote.statemachine test") + slave.states.set("remote.test", "remote.statemachine test") # Wait till slave tells master - self.slave._pool.block_till_done() + slave._pool.block_till_done() # Wait till master gives updated state - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual("remote.statemachine test", - self.slave.states.get("remote.test").state) + slave.states.get("remote.test").state) def test_eventbus_fire(self): """ Test if events fired from the eventbus get fired. """ @@ -213,13 +188,13 @@ def listener(event): # pylint: disable=unused-argument """ Helper method that will verify our event got called. """ test_value.append(1) - self.slave.listen_once_event("test.event_no_data", listener) + slave.listen_once_event("test.event_no_data", listener) - self.slave.bus.fire("test.event_no_data") + slave.bus.fire("test.event_no_data") # Wait till slave tells master - self.slave._pool.block_till_done() + slave._pool.block_till_done() # Wait till master gives updated event - self.hass._pool.block_till_done() + hass._pool.block_till_done() self.assertEqual(1, len(test_value)) diff --git a/test/util.py b/test/test_util.py similarity index 96% rename from test/util.py rename to test/test_util.py index 8c1c02e5c39142..727034ac409915 100644 --- a/test/util.py +++ b/test/test_util.py @@ -1,9 +1,8 @@ """ -homeassistant.test -~~~~~~~~~~~~~~~~~~ - -Provides tests to verify that Home Assistant modules do what they should do. +test.test_util +~~~~~~~~~~~~~~ +Tests Home Assistant util methods. """ # pylint: disable=too-many-public-methods import unittest