Replacing tempfile with mock_open in tests (#3753)

- test_bootstrap.py
- test_config.py
- components/test_init.py
- components/test_panel_custom.py
- components/test_api.py
- components/notify/test_file.py
- components/notify/test_demo.py
- components/camera/test_local_file.py
- helpers/test_config_validation.py
- util/test_package.py
- util/test_yaml.py

No changes needed in:
- components/cover/test_command_line.py
- components/switch/test_command_line.py
- components/rollershutter/test_command_line.py
- components/test_shell_command.py
- components/notify/test_command_line.py

Misc changes in:
- components/mqtt/test_server.py

Also, removed some unused mock parameters in tests/components/mqtt/test_server.py.
This commit is contained in:
Rob Capellini 2016-10-17 23:16:36 -04:00 committed by Paulus Schoutsen
parent 7d67017de7
commit 272539105f
12 changed files with 403 additions and 335 deletions

View File

@ -1,5 +1,4 @@
"""The tests for local file camera component.""" """The tests for local file camera component."""
from tempfile import NamedTemporaryFile
import unittest import unittest
from unittest import mock from unittest import mock
@ -26,45 +25,46 @@ class TestLocalCamera(unittest.TestCase):
def test_loading_file(self): def test_loading_file(self):
"""Test that it loads image from disk.""" """Test that it loads image from disk."""
test_string = 'hello'
self.hass.wsgi = mock.MagicMock() self.hass.wsgi = mock.MagicMock()
with NamedTemporaryFile() as fptr: with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \
fptr.write('hello'.encode('utf-8')) mock.patch('os.access', mock.Mock(return_value=True)):
fptr.flush()
assert setup_component(self.hass, 'camera', { assert setup_component(self.hass, 'camera', {
'camera': { 'camera': {
'name': 'config_test', 'name': 'config_test',
'platform': 'local_file', 'platform': 'local_file',
'file_path': fptr.name, 'file_path': 'mock.file',
}}) }})
image_view = self.hass.wsgi.mock_calls[0][1][0] image_view = self.hass.wsgi.mock_calls[0][1][0]
m_open = mock.mock_open(read_data=test_string)
with mock.patch(
'homeassistant.components.camera.local_file.open',
m_open, create=True
):
builder = EnvironBuilder(method='GET') builder = EnvironBuilder(method='GET')
Request = request_class() # pylint: disable=invalid-name Request = request_class() # pylint: disable=invalid-name
request = Request(builder.get_environ()) request = Request(builder.get_environ())
request.authenticated = True request.authenticated = True
resp = image_view.get(request, 'camera.config_test') resp = image_view.get(request, 'camera.config_test')
assert resp.status_code == 200, resp.response assert resp.status_code == 200, resp.response
assert resp.response[0].decode('utf-8') == 'hello' assert resp.response[0].decode('utf-8') == test_string
def test_file_not_readable(self): def test_file_not_readable(self):
"""Test local file will not setup when file is not readable.""" """Test local file will not setup when file is not readable."""
self.hass.wsgi = mock.MagicMock() self.hass.wsgi = mock.MagicMock()
with NamedTemporaryFile() as fptr: with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \
fptr.write('hello'.encode('utf-8')) mock.patch('os.access', return_value=False), \
fptr.flush() assert_setup_component(0):
assert setup_component(self.hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'local_file',
'file_path': 'mock.file',
}})
with mock.patch('os.access', return_value=False), \ assert [] == self.hass.states.all()
assert_setup_component(0):
assert setup_component(self.hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'local_file',
'file_path': fptr.name,
}})
assert [] == self.hass.states.all()

View File

@ -1,5 +1,5 @@
"""The tests for the MQTT component embedded server.""" """The tests for the MQTT component embedded server."""
from unittest.mock import MagicMock, patch from unittest.mock import Mock, MagicMock, patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import _setup_component
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
@ -18,14 +18,12 @@ class TestMQTT:
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
@patch('passlib.apps.custom_app_context', return_value='') @patch('passlib.apps.custom_app_context', Mock(return_value=''))
@patch('tempfile.NamedTemporaryFile', return_value=MagicMock()) @patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock()))
@patch('asyncio.new_event_loop', Mock())
@patch('homeassistant.components.mqtt.MQTT') @patch('homeassistant.components.mqtt.MQTT')
@patch('asyncio.gather') @patch('asyncio.gather')
@patch('asyncio.new_event_loop') def test_creating_config_with_http_pass(self, mock_gather, mock_mqtt):
def test_creating_config_with_http_pass(self, mock_new_loop, mock_gather,
mock_mqtt, mock_temp,
mock_context):
"""Test if the MQTT server gets started and subscribe/publish msg.""" """Test if the MQTT server gets started and subscribe/publish msg."""
self.hass.config.components.append('http') self.hass.config.components.append('http')
password = 'super_secret' password = 'super_secret'
@ -45,10 +43,10 @@ class TestMQTT:
assert mock_mqtt.mock_calls[0][1][5] is None assert mock_mqtt.mock_calls[0][1][5] is None
assert mock_mqtt.mock_calls[0][1][6] is None assert mock_mqtt.mock_calls[0][1][6] is None
@patch('tempfile.NamedTemporaryFile', return_value=MagicMock()) @patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock()))
@patch('asyncio.new_event_loop', Mock())
@patch('asyncio.gather') @patch('asyncio.gather')
@patch('asyncio.new_event_loop') def test_broker_config_fails(self, mock_gather):
def test_broker_config_fails(self, mock_new_loop, mock_gather, mock_temp):
"""Test if the MQTT component fails if server fails.""" """Test if the MQTT component fails if server fails."""
self.hass.config.components.append('http') self.hass.config.components.append('http')
from hbmqtt.broker import BrokerException from hbmqtt.broker import BrokerException

View File

@ -1,12 +1,10 @@
"""The tests for the notify demo platform.""" """The tests for the notify demo platform."""
import tempfile
import unittest import unittest
from homeassistant.bootstrap import setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.notify as notify import homeassistant.components.notify as notify
from homeassistant.components.notify import demo from homeassistant.components.notify import demo
from homeassistant.helpers import script from homeassistant.helpers import script
from homeassistant.util import yaml
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -70,21 +68,18 @@ class TestNotifyDemo(unittest.TestCase):
def test_calling_notify_from_script_loaded_from_yaml_without_title(self): def test_calling_notify_from_script_loaded_from_yaml_without_title(self):
"""Test if we can call a notify from a script.""" """Test if we can call a notify from a script."""
yaml_conf = """ conf = {
service: notify.notify 'service': 'notify.notify',
data: 'data': {
data: 'data': {
push: 'push': {
sound: US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav 'sound':
data_template: 'US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav'
message: > }
Test 123 {{ 2 + 2 }} }
""" },
'data_template': {'message': 'Test 123 {{ 2 + 2 }}\n'},
with tempfile.NamedTemporaryFile() as fp: }
fp.write(yaml_conf.encode('utf-8'))
fp.flush()
conf = yaml.load_yaml(fp.name)
script.call_from_config(self.hass, conf) script.call_from_config(self.hass, conf)
self.hass.block_till_done() self.hass.block_till_done()
@ -99,22 +94,21 @@ data_template:
def test_calling_notify_from_script_loaded_from_yaml_with_title(self): def test_calling_notify_from_script_loaded_from_yaml_with_title(self):
"""Test if we can call a notify from a script.""" """Test if we can call a notify from a script."""
yaml_conf = """ conf = {
service: notify.notify 'service': 'notify.notify',
data: 'data': {
data: 'data': {
push: 'push': {
sound: US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav 'sound':
data_template: 'US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav'
title: Test }
message: > }
Test 123 {{ 2 + 2 }} },
""" 'data_template': {
'message': 'Test 123 {{ 2 + 2 }}\n',
with tempfile.NamedTemporaryFile() as fp: 'title': 'Test'
fp.write(yaml_conf.encode('utf-8')) }
fp.flush() }
conf = yaml.load_yaml(fp.name)
script.call_from_config(self.hass, conf) script.call_from_config(self.hass, conf)
self.hass.pool.block_till_done() self.hass.pool.block_till_done()

View File

@ -1,8 +1,7 @@
"""The tests for the notify file platform.""" """The tests for the notify file platform."""
import os import os
import unittest import unittest
import tempfile from unittest.mock import call, mock_open, patch
from unittest.mock import patch
from homeassistant.bootstrap import setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.notify as notify import homeassistant.components.notify as notify
@ -34,13 +33,19 @@ class TestNotifyFile(unittest.TestCase):
}, },
})) }))
@patch('homeassistant.components.notify.file.os.stat')
@patch('homeassistant.util.dt.utcnow') @patch('homeassistant.util.dt.utcnow')
def test_notify_file(self, mock_utcnow): def test_notify_file(self, mock_utcnow, mock_stat):
"""Test the notify file output.""" """Test the notify file output."""
mock_utcnow.return_value = dt_util.as_utc(dt_util.now()) mock_utcnow.return_value = dt_util.as_utc(dt_util.now())
mock_stat.return_value.st_size = 0
with tempfile.TemporaryDirectory() as tempdirname: m_open = mock_open()
filename = os.path.join(tempdirname, 'notify.txt') with patch(
'homeassistant.components.notify.file.open',
m_open, create=True
):
filename = 'mock_file'
message = 'one, two, testing, testing' message = 'one, two, testing, testing'
self.assertTrue(setup_component(self.hass, notify.DOMAIN, { self.assertTrue(setup_component(self.hass, notify.DOMAIN, {
'notify': { 'notify': {
@ -58,5 +63,12 @@ class TestNotifyFile(unittest.TestCase):
self.hass.services.call('notify', 'test', {'message': message}, self.hass.services.call('notify', 'test', {'message': message},
blocking=True) blocking=True)
result = open(filename).read() full_filename = os.path.join(self.hass.config.path(), filename)
self.assertEqual(result, "{}{}\n".format(title, message)) self.assertEqual(m_open.call_count, 1)
self.assertEqual(m_open.call_args, call(full_filename, 'a'))
self.assertEqual(m_open.return_value.write.call_count, 2)
self.assertEqual(
m_open.return_value.write.call_args_list,
[call(title), call(message + '\n')]
)

View File

@ -2,10 +2,9 @@
# pylint: disable=protected-access,too-many-public-methods # pylint: disable=protected-access,too-many-public-methods
from contextlib import closing from contextlib import closing
import json import json
import tempfile
import time import time
import unittest import unittest
from unittest.mock import patch from unittest.mock import Mock, patch
import requests import requests
@ -244,15 +243,20 @@ class TestAPI(unittest.TestCase):
def test_api_get_error_log(self): def test_api_get_error_log(self):
"""Test the return of the error log.""" """Test the return of the error log."""
test_content = 'Test String°' test_string = 'Test String°'.encode('UTF-8')
with tempfile.NamedTemporaryFile() as log:
log.write(test_content.encode('utf-8'))
log.flush()
with patch.object(hass.config, 'path', return_value=log.name): # Can't use read_data with wsgiserver in Python 3.4.2. Due to a
req = requests.get(_url(const.URL_API_ERROR_LOG), # bug in read_data, it can't handle byte types ('Type str doesn't
headers=HA_HEADERS) # support the buffer API'), but wsgiserver requires byte types
self.assertEqual(test_content, req.text) # ('WSGI Applications must yield bytes'). So just mock our own
# read method.
m_open = Mock(return_value=Mock(
read=Mock(side_effect=[test_string]))
)
with patch('homeassistant.components.http.open', m_open, create=True):
req = requests.get(_url(const.URL_API_ERROR_LOG),
headers=HA_HEADERS)
self.assertEqual(test_string, req.text.encode('UTF-8'))
self.assertIsNone(req.headers.get('expires')) self.assertIsNone(req.headers.get('expires'))
def test_api_get_event_listeners(self): def test_api_get_event_listeners(self):

View File

@ -1,8 +1,7 @@
"""The testd for Core components.""" """The testd for Core components."""
# pylint: disable=protected-access,too-many-public-methods # pylint: disable=protected-access,too-many-public-methods
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch, Mock
from tempfile import TemporaryDirectory
import yaml import yaml
@ -13,7 +12,8 @@ from homeassistant.const import (
import homeassistant.components as comps import homeassistant.components as comps
from homeassistant.helpers import entity from homeassistant.helpers import entity
from tests.common import get_test_home_assistant, mock_service from tests.common import (
get_test_home_assistant, mock_service, patch_yaml_files)
class TestComponentsCore(unittest.TestCase): class TestComponentsCore(unittest.TestCase):
@ -89,6 +89,7 @@ class TestComponentsCore(unittest.TestCase):
('sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False), ('sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False),
mock_call.call_args_list[1][0]) mock_call.call_args_list[1][0])
@patch('homeassistant.config.os.path.isfile', Mock(return_value=True))
def test_reload_core_conf(self): def test_reload_core_conf(self):
"""Test reload core conf service.""" """Test reload core conf service."""
ent = entity.Entity() ent = entity.Entity()
@ -101,23 +102,20 @@ class TestComponentsCore(unittest.TestCase):
assert state.state == 'unknown' assert state.state == 'unknown'
assert state.attributes == {} assert state.attributes == {}
with TemporaryDirectory() as conf_dir: files = {
self.hass.config.config_dir = conf_dir config.YAML_CONFIG_FILE: yaml.dump({
conf_yaml = self.hass.config.path(config.YAML_CONFIG_FILE) ha.DOMAIN: {
'latitude': 10,
with open(conf_yaml, 'a') as fp: 'longitude': 20,
fp.write(yaml.dump({ 'customize': {
ha.DOMAIN: { 'test.Entity': {
'latitude': 10, 'hello': 'world'
'longitude': 20,
'customize': {
'test.Entity': {
'hello': 'world'
}
} }
} }
})) }
})
}
with patch_yaml_files(files, True):
comps.reload_core_config(self.hass) comps.reload_core_config(self.hass)
self.hass.block_till_done() self.hass.block_till_done()
@ -131,17 +129,15 @@ class TestComponentsCore(unittest.TestCase):
assert state.state == 'unknown' assert state.state == 'unknown'
assert state.attributes.get('hello') == 'world' assert state.attributes.get('hello') == 'world'
@patch('homeassistant.config.os.path.isfile', Mock(return_value=True))
@patch('homeassistant.components._LOGGER.error') @patch('homeassistant.components._LOGGER.error')
@patch('homeassistant.config.process_ha_core_config') @patch('homeassistant.config.process_ha_core_config')
def test_reload_core_with_wrong_conf(self, mock_process, mock_error): def test_reload_core_with_wrong_conf(self, mock_process, mock_error):
"""Test reload core conf service.""" """Test reload core conf service."""
with TemporaryDirectory() as conf_dir: files = {
self.hass.config.config_dir = conf_dir config.YAML_CONFIG_FILE: yaml.dump(['invalid', 'config'])
conf_yaml = self.hass.config.path(config.YAML_CONFIG_FILE) }
with patch_yaml_files(files, True):
with open(conf_yaml, 'a') as fp:
fp.write(yaml.dump(['invalid', 'config']))
comps.reload_core_config(self.hass) comps.reload_core_config(self.hass)
self.hass.block_till_done() self.hass.block_till_done()

View File

@ -1,9 +1,8 @@
"""The tests for the panel_custom component.""" """The tests for the panel_custom component."""
import os import os
import shutil import shutil
from tempfile import NamedTemporaryFile
import unittest import unittest
from unittest.mock import patch from unittest.mock import Mock, patch
from homeassistant import bootstrap from homeassistant import bootstrap
from homeassistant.components import panel_custom from homeassistant.components import panel_custom
@ -47,31 +46,40 @@ class TestPanelCustom(unittest.TestCase):
@patch('homeassistant.components.panel_custom.register_panel') @patch('homeassistant.components.panel_custom.register_panel')
def test_webcomponent_custom_path(self, mock_register, _mock_setup): def test_webcomponent_custom_path(self, mock_register, _mock_setup):
"""Test if a web component is found in config panels dir.""" """Test if a web component is found in config panels dir."""
with NamedTemporaryFile() as fp: filename = 'mock.file'
config = {
'panel_custom': {
'name': 'todomvc',
'webcomponent_path': fp.name,
'sidebar_title': 'Sidebar Title',
'sidebar_icon': 'mdi:iconicon',
'url_path': 'nice_url',
'config': 5,
}
}
with patch('os.path.isfile', return_value=False): config = {
assert not bootstrap.setup_component(self.hass, 'panel_custom', 'panel_custom': {
config) 'name': 'todomvc',
assert not mock_register.called 'webcomponent_path': filename,
'sidebar_title': 'Sidebar Title',
assert bootstrap.setup_component(self.hass, 'panel_custom', config)
assert mock_register.called
args = mock_register.mock_calls[0][1]
kwargs = mock_register.mock_calls[0][2]
assert args == (self.hass, 'todomvc', fp.name)
assert kwargs == {
'config': 5,
'url_path': 'nice_url',
'sidebar_icon': 'mdi:iconicon', 'sidebar_icon': 'mdi:iconicon',
'sidebar_title': 'Sidebar Title' 'url_path': 'nice_url',
'config': 5,
} }
}
with patch('os.path.isfile', Mock(return_value=False)):
assert not bootstrap.setup_component(
self.hass, 'panel_custom', config
)
assert not mock_register.called
with patch('os.path.isfile', Mock(return_value=True)):
with patch('os.access', Mock(return_value=True)):
assert bootstrap.setup_component(
self.hass, 'panel_custom', config
)
assert mock_register.called
args = mock_register.mock_calls[0][1]
assert args == (self.hass, 'todomvc', filename)
kwargs = mock_register.mock_calls[0][2]
assert kwargs == {
'config': 5,
'url_path': 'nice_url',
'sidebar_icon': 'mdi:iconicon',
'sidebar_title': 'Sidebar Title'
}

View File

@ -3,10 +3,10 @@ from collections import OrderedDict
from datetime import timedelta from datetime import timedelta
import enum import enum
import os import os
import tempfile
import pytest import pytest
import voluptuous as vol import voluptuous as vol
from unittest.mock import Mock, patch
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -68,18 +68,18 @@ def test_isfile():
"""Validate that the value is an existing file.""" """Validate that the value is an existing file."""
schema = vol.Schema(cv.isfile) schema = vol.Schema(cv.isfile)
with tempfile.NamedTemporaryFile() as fp: fake_file = 'this-file-does-not.exist'
pass assert not os.path.isfile(fake_file)
for value in ('invalid', None, -1, 0, 80000, fp.name): for value in ('invalid', None, -1, 0, 80000, fake_file):
with pytest.raises(vol.Invalid): with pytest.raises(vol.Invalid):
schema(value) schema(value)
with tempfile.TemporaryDirectory() as tmp_path: # patching methods that allow us to fake a file existing
tmp_file = os.path.join(tmp_path, "test.txt") # with write access
with open(tmp_file, "w") as tmp_handl: with patch('os.path.isfile', Mock(return_value=True)), \
tmp_handl.write("test file") patch('os.access', Mock(return_value=True)):
schema(tmp_file) schema('test.txt')
def test_url(): def test_url():

View File

@ -1,6 +1,5 @@
"""Test the bootstrapping.""" """Test the bootstrapping."""
# pylint: disable=too-many-public-methods,protected-access # pylint: disable=too-many-public-methods,protected-access
import tempfile
from unittest import mock from unittest import mock
import threading import threading
import logging import logging
@ -12,7 +11,8 @@ import homeassistant.util.dt as dt_util
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
from tests.common import \ from tests.common import \
get_test_home_assistant, MockModule, MockPlatform, assert_setup_component get_test_home_assistant, MockModule, MockPlatform, \
assert_setup_component, patch_yaml_files
ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE
@ -45,17 +45,27 @@ class TestBootstrap:
self.hass.stop() self.hass.stop()
loader._COMPONENT_CACHE = self.backup_cache loader._COMPONENT_CACHE = self.backup_cache
@mock.patch(
# prevent .HA_VERISON file from being written
'homeassistant.bootstrap.conf_util.process_ha_config_upgrade',
mock.Mock()
)
@mock.patch('homeassistant.util.location.detect_location_info', @mock.patch('homeassistant.util.location.detect_location_info',
return_value=None) return_value=None)
def test_from_config_file(self, mock_detect): def test_from_config_file(self, mock_detect):
"""Test with configuration file.""" """Test with configuration file."""
components = ['browser', 'conversation', 'script'] components = ['browser', 'conversation', 'script']
with tempfile.NamedTemporaryFile() as fp: files = {
for comp in components: 'config.yaml': ''.join(
fp.write('{}:\n'.format(comp).encode('utf-8')) '{}:\n'.format(comp)
fp.flush() for comp in components
)
}
self.hass = bootstrap.from_config_file(fp.name) with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \
mock.patch('os.access', mock.Mock(return_value=True)), \
patch_yaml_files(files, True):
self.hass = bootstrap.from_config_file('config.yaml')
components.append('group') components.append('group')
assert sorted(components) == sorted(self.hass.config.components) assert sorted(components) == sorted(self.hass.config.components)

View File

@ -1,7 +1,6 @@
"""Test config utils.""" """Test config utils."""
# pylint: disable=too-many-public-methods,protected-access # pylint: disable=too-many-public-methods,protected-access
import os import os
import tempfile
import unittest import unittest
import unittest.mock as mock import unittest.mock as mock
@ -212,49 +211,56 @@ class TestConfig(unittest.TestCase):
assert state.attributes['hidden'] assert state.attributes['hidden']
def test_remove_lib_on_upgrade(self): @mock.patch('homeassistant.config.shutil')
@mock.patch('homeassistant.config.os')
def test_remove_lib_on_upgrade(self, mock_os, mock_shutil):
"""Test removal of library on upgrade.""" """Test removal of library on upgrade."""
with tempfile.TemporaryDirectory() as config_dir: ha_version = '0.7.0'
version_path = os.path.join(config_dir, '.HA_VERSION')
lib_dir = os.path.join(config_dir, 'deps')
check_file = os.path.join(lib_dir, 'check')
with open(version_path, 'wt') as outp: mock_os.path.isdir = mock.Mock(return_value=True)
outp.write('0.7.0')
os.mkdir(lib_dir) mock_open = mock.mock_open()
with mock.patch('homeassistant.config.open', mock_open, create=True):
with open(check_file, 'w'): opened_file = mock_open.return_value
pass opened_file.readline.return_value = ha_version
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.hass.config.config_dir = config_dir self.hass.config.path = mock.Mock()
assert os.path.isfile(check_file)
config_util.process_ha_config_upgrade(self.hass) config_util.process_ha_config_upgrade(self.hass)
assert not os.path.isfile(check_file)
def test_not_remove_lib_if_not_upgrade(self): hass_path = self.hass.config.path.return_value
self.assertEqual(mock_os.path.isdir.call_count, 1)
self.assertEqual(
mock_os.path.isdir.call_args, mock.call(hass_path)
)
self.assertEqual(mock_shutil.rmtree.call_count, 1)
self.assertEqual(
mock_shutil.rmtree.call_args, mock.call(hass_path)
)
@mock.patch('homeassistant.config.shutil')
@mock.patch('homeassistant.config.os')
def test_not_remove_lib_if_not_upgrade(self, mock_os, mock_shutil):
"""Test removal of library with no upgrade.""" """Test removal of library with no upgrade."""
with tempfile.TemporaryDirectory() as config_dir: ha_version = __version__
version_path = os.path.join(config_dir, '.HA_VERSION')
lib_dir = os.path.join(config_dir, 'deps')
check_file = os.path.join(lib_dir, 'check')
with open(version_path, 'wt') as outp: mock_os.path.isdir = mock.Mock(return_value=True)
outp.write(__version__)
os.mkdir(lib_dir) mock_open = mock.mock_open()
with mock.patch('homeassistant.config.open', mock_open, create=True):
with open(check_file, 'w'): opened_file = mock_open.return_value
pass opened_file.readline.return_value = ha_version
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.hass.config.config_dir = config_dir self.hass.config.path = mock.Mock()
config_util.process_ha_config_upgrade(self.hass) config_util.process_ha_config_upgrade(self.hass)
assert os.path.isfile(check_file) assert mock_os.path.isdir.call_count == 0
assert mock_shutil.rmtree.call_count == 0
def test_loading_configuration(self): def test_loading_configuration(self):
"""Test loading core config onto hass object.""" """Test loading core config onto hass object."""

View File

@ -1,9 +1,12 @@
"""Test Home Assistant package util methods.""" """Test Home Assistant package util methods."""
import os import os
import tempfile import pkg_resources
import subprocess
import unittest import unittest
from homeassistant.bootstrap import mount_local_lib_path from distutils.sysconfig import get_python_lib
from unittest.mock import call, patch
import homeassistant.util.package as package import homeassistant.util.package as package
RESOURCE_DIR = os.path.abspath( RESOURCE_DIR = os.path.abspath(
@ -15,43 +18,114 @@ TEST_ZIP_REQ = 'file://{}#{}' \
.format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ) .format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ)
class TestPackageUtil(unittest.TestCase): @patch('homeassistant.util.package.subprocess.call')
@patch('homeassistant.util.package.check_package_exists')
class TestPackageUtilInstallPackage(unittest.TestCase):
"""Test for homeassistant.util.package module.""" """Test for homeassistant.util.package module."""
def setUp(self): def test_install_existing_package(self, mock_exists, mock_subprocess):
"""Create local library for testing."""
self.tmp_dir = tempfile.TemporaryDirectory()
self.lib_dir = mount_local_lib_path(self.tmp_dir.name)
def tearDown(self):
"""Stop everything that was started."""
self.tmp_dir.cleanup()
def test_install_existing_package(self):
"""Test an install attempt on an existing package.""" """Test an install attempt on an existing package."""
self.assertTrue(package.check_package_exists( mock_exists.return_value = True
TEST_EXIST_REQ, self.lib_dir))
self.assertTrue(package.install_package(TEST_EXIST_REQ)) self.assertTrue(package.install_package(TEST_EXIST_REQ))
def test_install_package_zip(self): self.assertEqual(mock_exists.call_count, 1)
"""Test an install attempt from a zip path.""" self.assertEqual(mock_exists.call_args, call(TEST_EXIST_REQ, None))
self.assertFalse(package.check_package_exists(
TEST_ZIP_REQ, self.lib_dir))
self.assertFalse(package.check_package_exists(
TEST_NEW_REQ, self.lib_dir))
self.assertTrue(package.install_package( self.assertEqual(mock_subprocess.call_count, 0)
TEST_ZIP_REQ, True, self.lib_dir))
self.assertTrue(package.check_package_exists( @patch('homeassistant.util.package.sys')
TEST_ZIP_REQ, self.lib_dir)) def test_install(self, mock_sys, mock_exists, mock_subprocess):
self.assertTrue(package.check_package_exists( """Test an install attempt on a package that doesn't exist."""
TEST_NEW_REQ, self.lib_dir)) mock_exists.return_value = False
mock_subprocess.return_value = 0
try: self.assertTrue(package.install_package(TEST_NEW_REQ, False))
import pyhelloworld3
except ImportError:
self.fail('Unable to import pyhelloworld3 after installing it.')
self.assertEqual(pyhelloworld3.__version__, '1.0.0') self.assertEqual(mock_exists.call_count, 1)
self.assertEqual(mock_subprocess.call_count, 1)
self.assertEqual(
mock_subprocess.call_args,
call([
mock_sys.executable, '-m', 'pip',
'install', '--quiet', TEST_NEW_REQ
])
)
@patch('homeassistant.util.package.sys')
def test_install_upgrade(self, mock_sys, mock_exists, mock_subprocess):
"""Test an upgrade attempt on a package."""
mock_exists.return_value = False
mock_subprocess.return_value = 0
self.assertTrue(package.install_package(TEST_NEW_REQ))
self.assertEqual(mock_exists.call_count, 1)
self.assertEqual(mock_subprocess.call_count, 1)
self.assertEqual(
mock_subprocess.call_args,
call([
mock_sys.executable, '-m', 'pip', 'install',
'--quiet', TEST_NEW_REQ, '--upgrade'
])
)
@patch('homeassistant.util.package.sys')
def test_install_target(self, mock_sys, mock_exists, mock_subprocess):
"""Test an install with a target."""
target = 'target_folder'
mock_exists.return_value = False
mock_subprocess.return_value = 0
self.assertTrue(
package.install_package(TEST_NEW_REQ, False, target=target)
)
self.assertEqual(mock_exists.call_count, 1)
self.assertEqual(mock_subprocess.call_count, 1)
self.assertEqual(
mock_subprocess.call_args,
call([
mock_sys.executable, '-m', 'pip', 'install', '--quiet',
TEST_NEW_REQ, '--target', os.path.abspath(target)
])
)
@patch('homeassistant.util.package._LOGGER')
@patch('homeassistant.util.package.sys')
def test_install_error(
self, mock_sys, mock_logger, mock_exists, mock_subprocess
):
"""Test an install with a target."""
mock_exists.return_value = False
mock_subprocess.side_effect = [subprocess.SubprocessError]
self.assertFalse(package.install_package(TEST_NEW_REQ))
self.assertEqual(mock_logger.exception.call_count, 1)
class TestPackageUtilCheckPackageExists(unittest.TestCase):
"""Test for homeassistant.util.package module."""
def test_check_package_global(self):
"""Test for a globally-installed package"""
installed_package = list(pkg_resources.working_set)[0].project_name
self.assertTrue(package.check_package_exists(installed_package, None))
def test_check_package_local(self):
"""Test for a locally-installed package"""
lib_dir = get_python_lib()
installed_package = list(pkg_resources.working_set)[0].project_name
self.assertTrue(
package.check_package_exists(installed_package, lib_dir)
)
def test_check_package_zip(self):
"""Test for an installed zip package"""
self.assertFalse(package.check_package_exists(TEST_ZIP_REQ, None))

View File

@ -2,7 +2,6 @@
import io import io
import unittest import unittest
import os import os
import tempfile
from unittest.mock import patch from unittest.mock import patch
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -68,146 +67,116 @@ class TestYaml(unittest.TestCase):
def test_include_yaml(self): def test_include_yaml(self):
"""Test include yaml.""" """Test include yaml."""
with tempfile.NamedTemporaryFile() as include_file: with patch_yaml_files({'test.yaml': 'value'}):
include_file.write(b"value") conf = 'key: !include test.yaml'
include_file.seek(0)
conf = "key: !include {}".format(include_file.name)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert doc["key"] == "value" assert doc["key"] == "value"
def test_include_dir_list(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_list(self, mock_walk):
"""Test include dir list yaml.""" """Test include dir list yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [['/tmp', [], ['one.yaml', 'two.yaml']]]
file_1 = tempfile.NamedTemporaryFile(dir=include_dir,
suffix=".yaml", delete=False) with patch_yaml_files({
file_1.write(b"one") '/tmp/one.yaml': 'one', '/tmp/two.yaml': 'two'
file_1.close() }):
file_2 = tempfile.NamedTemporaryFile(dir=include_dir, conf = "key: !include_dir_list /tmp"
suffix=".yaml", delete=False)
file_2.write(b"two")
file_2.close()
conf = "key: !include_dir_list {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert sorted(doc["key"]) == sorted(["one", "two"]) assert sorted(doc["key"]) == sorted(["one", "two"])
def test_include_dir_list_recursive(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_list_recursive(self, mock_walk):
"""Test include dir recursive list yaml.""" """Test include dir recursive list yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [
file_0 = tempfile.NamedTemporaryFile(dir=include_dir, ['/tmp', ['tmp2'], ['zero.yaml']],
suffix=".yaml", delete=False) ['/tmp/tmp2', [], ['one.yaml', 'two.yaml']],
file_0.write(b"zero") ]
file_0.close()
temp_dir = tempfile.TemporaryDirectory(dir=include_dir) with patch_yaml_files({
file_1 = tempfile.NamedTemporaryFile(dir=temp_dir.name, '/tmp/zero.yaml': 'zero', '/tmp/tmp2/one.yaml': 'one',
suffix=".yaml", delete=False) '/tmp/tmp2/two.yaml': 'two'
file_1.write(b"one") }):
file_1.close() conf = "key: !include_dir_list /tmp"
file_2 = tempfile.NamedTemporaryFile(dir=temp_dir.name,
suffix=".yaml", delete=False)
file_2.write(b"two")
file_2.close()
conf = "key: !include_dir_list {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert sorted(doc["key"]) == sorted(["zero", "one", "two"]) assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
def test_include_dir_named(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_named(self, mock_walk):
"""Test include dir named yaml.""" """Test include dir named yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
file_1 = tempfile.NamedTemporaryFile(dir=include_dir,
suffix=".yaml", delete=False) with patch_yaml_files({
file_1.write(b"one") '/tmp/first.yaml': 'one', '/tmp/second.yaml': 'two'
file_1.close() }):
file_2 = tempfile.NamedTemporaryFile(dir=include_dir, conf = "key: !include_dir_named /tmp"
suffix=".yaml", delete=False) correct = {'first': 'one', 'second': 'two'}
file_2.write(b"two")
file_2.close()
conf = "key: !include_dir_named {}".format(include_dir)
correct = {}
correct[os.path.splitext(os.path.basename(file_1.name))[0]] = "one"
correct[os.path.splitext(os.path.basename(file_2.name))[0]] = "two"
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert doc["key"] == correct assert doc["key"] == correct
def test_include_dir_named_recursive(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_named_recursive(self, mock_walk):
"""Test include dir named yaml.""" """Test include dir named yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [
file_0 = tempfile.NamedTemporaryFile(dir=include_dir, ['/tmp', ['tmp2'], ['first.yaml']],
suffix=".yaml", delete=False) ['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
file_0.write(b"zero") ]
file_0.close()
temp_dir = tempfile.TemporaryDirectory(dir=include_dir) with patch_yaml_files({
file_1 = tempfile.NamedTemporaryFile(dir=temp_dir.name, '/tmp/first.yaml': 'one', '/tmp/tmp2/second.yaml': 'two',
suffix=".yaml", delete=False) '/tmp/tmp2/third.yaml': 'three'
file_1.write(b"one") }):
file_1.close() conf = "key: !include_dir_named /tmp"
file_2 = tempfile.NamedTemporaryFile(dir=temp_dir.name, correct = {'first': 'one', 'second': 'two', 'third': 'three'}
suffix=".yaml", delete=False)
file_2.write(b"two")
file_2.close()
conf = "key: !include_dir_named {}".format(include_dir)
correct = {}
correct[os.path.splitext(
os.path.basename(file_0.name))[0]] = "zero"
correct[os.path.splitext(os.path.basename(file_1.name))[0]] = "one"
correct[os.path.splitext(os.path.basename(file_2.name))[0]] = "two"
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert doc["key"] == correct assert doc["key"] == correct
def test_include_dir_merge_list(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_merge_list(self, mock_walk):
"""Test include dir merge list yaml.""" """Test include dir merge list yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
file_1 = tempfile.NamedTemporaryFile(dir=include_dir,
suffix=".yaml", delete=False) with patch_yaml_files({
file_1.write(b"- one") '/tmp/first.yaml': '- one',
file_1.close() '/tmp/second.yaml': '- two\n- three'
file_2 = tempfile.NamedTemporaryFile(dir=include_dir, }):
suffix=".yaml", delete=False) conf = "key: !include_dir_merge_list /tmp"
file_2.write(b"- two\n- three")
file_2.close()
conf = "key: !include_dir_merge_list {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert sorted(doc["key"]) == sorted(["one", "two", "three"]) assert sorted(doc["key"]) == sorted(["one", "two", "three"])
def test_include_dir_merge_list_recursive(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_merge_list_recursive(self, mock_walk):
"""Test include dir merge list yaml.""" """Test include dir merge list yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [
file_0 = tempfile.NamedTemporaryFile(dir=include_dir, ['/tmp', ['tmp2'], ['first.yaml']],
suffix=".yaml", delete=False) ['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
file_0.write(b"- zero") ]
file_0.close()
temp_dir = tempfile.TemporaryDirectory(dir=include_dir) with patch_yaml_files({
file_1 = tempfile.NamedTemporaryFile(dir=temp_dir.name, '/tmp/first.yaml': '- one', '/tmp/tmp2/second.yaml': '- two',
suffix=".yaml", delete=False) '/tmp/tmp2/third.yaml': '- three\n- four'
file_1.write(b"- one") }):
file_1.close() conf = "key: !include_dir_merge_list /tmp"
file_2 = tempfile.NamedTemporaryFile(dir=temp_dir.name,
suffix=".yaml", delete=False)
file_2.write(b"- two\n- three")
file_2.close()
conf = "key: !include_dir_merge_list {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert sorted(doc["key"]) == sorted(["zero", "one", "two", assert sorted(doc["key"]) == sorted(["one", "two",
"three"]) "three", "four"])
def test_include_dir_merge_named(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_merge_named(self, mock_walk):
"""Test include dir merge named yaml.""" """Test include dir merge named yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
file_1 = tempfile.NamedTemporaryFile(dir=include_dir,
suffix=".yaml", delete=False) with patch_yaml_files({
file_1.write(b"key1: one") '/tmp/first.yaml': 'key1: one',
file_1.close() '/tmp/second.yaml': 'key2: two\nkey3: three'
file_2 = tempfile.NamedTemporaryFile(dir=include_dir, }):
suffix=".yaml", delete=False) conf = "key: !include_dir_merge_named /tmp"
file_2.write(b"key2: two\nkey3: three")
file_2.close()
conf = "key: !include_dir_merge_named {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert doc["key"] == { assert doc["key"] == {
@ -216,30 +185,27 @@ class TestYaml(unittest.TestCase):
"key3": "three" "key3": "three"
} }
def test_include_dir_merge_named_recursive(self): @patch('homeassistant.util.yaml.os.walk')
def test_include_dir_merge_named_recursive(self, mock_walk):
"""Test include dir merge named yaml.""" """Test include dir merge named yaml."""
with tempfile.TemporaryDirectory() as include_dir: mock_walk.return_value = [
file_0 = tempfile.NamedTemporaryFile(dir=include_dir, ['/tmp', ['tmp2'], ['first.yaml']],
suffix=".yaml", delete=False) ['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
file_0.write(b"key0: zero") ]
file_0.close()
temp_dir = tempfile.TemporaryDirectory(dir=include_dir) with patch_yaml_files({
file_1 = tempfile.NamedTemporaryFile(dir=temp_dir.name, '/tmp/first.yaml': 'key1: one',
suffix=".yaml", delete=False) '/tmp/tmp2/second.yaml': 'key2: two',
file_1.write(b"key1: one") '/tmp/tmp2/third.yaml': 'key3: three\nkey4: four'
file_1.close() }):
file_2 = tempfile.NamedTemporaryFile(dir=temp_dir.name, conf = "key: !include_dir_merge_named /tmp"
suffix=".yaml", delete=False)
file_2.write(b"key2: two\nkey3: three")
file_2.close()
conf = "key: !include_dir_merge_named {}".format(include_dir)
with io.StringIO(conf) as file: with io.StringIO(conf) as file:
doc = yaml.yaml.safe_load(file) doc = yaml.yaml.safe_load(file)
assert doc["key"] == { assert doc["key"] == {
"key0": "zero",
"key1": "one", "key1": "one",
"key2": "two", "key2": "two",
"key3": "three" "key3": "three",
"key4": "four"
} }
FILES = {} FILES = {}