def test_loading_file(hass, test_client):
    """Test that it loads image from disk."""
    hass.allow_pool = True

    @mock.patch('os.path.isfile', mock.Mock(return_value=True))
    @mock.patch('os.access', mock.Mock(return_value=True))
    def setup_platform():
        """Setup platform inside callback."""
        assert setup_component(
            hass, 'camera', {
                'camera': {
                    'name': 'config_test',
                    'platform': 'local_file',
                    'file_path': 'mock.file',
                }
            })

    yield from hass.loop.run_in_executor(None, setup_platform)

    client = yield from test_client(hass.http.app)

    m_open = MockOpen(read_data=b'hello')
    with mock.patch('homeassistant.components.camera.local_file.open',
                    m_open,
                    create=True):
        resp = yield from client.get('/api/camera_proxy/camera.config_test')

    assert resp.status == 200
    body = yield from resp.text()
    assert body == 'hello'
Example #2
0
def test_get_part_of_log_next_line(offset, json, valid):
    m = MockOpen()
    m[LOG_FILE_PATH].read_data = json

    with mock.patch('__builtin__.open', new=m):
        assert get_part_of_log(offset, 1)['next_offset'] == valid
        assert get_part_of_log(offset, 1)['total_size'] == len(LINE_FOR_TEST)
Example #3
0
def test_loading_file(hass, aiohttp_client):
    """Test that it loads image from disk."""
    mock_registry(hass)

    with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \
            mock.patch('os.access', mock.Mock(return_value=True)):
        yield from async_setup_component(
            hass, 'camera', {
                'camera': {
                    'name': 'config_test',
                    'platform': 'local_file',
                    'file_path': 'mock.file',
                }
            })

    client = yield from aiohttp_client(hass.http.app)

    m_open = MockOpen(read_data=b'hello')
    with mock.patch('homeassistant.components.camera.local_file.open',
                    m_open,
                    create=True):
        resp = yield from client.get('/api/camera_proxy/camera.config_test')

    assert resp.status == 200
    body = yield from resp.text()
    assert body == 'hello'
Example #4
0
def test_camera_content_type(hass, test_client):
    """Test local_file camera content_type."""
    cam_config_jpg = {
        'name': 'test_jpg',
        'platform': 'local_file',
        'file_path': '/path/to/image.jpg',
    }
    cam_config_png = {
        'name': 'test_png',
        'platform': 'local_file',
        'file_path': '/path/to/image.png',
    }
    cam_config_svg = {
        'name': 'test_svg',
        'platform': 'local_file',
        'file_path': '/path/to/image.svg',
    }
    cam_config_noext = {
        'name': 'test_no_ext',
        'platform': 'local_file',
        'file_path': '/path/to/image',
    }

    yield from async_setup_component(hass, 'camera', {
        'camera': [cam_config_jpg, cam_config_png,
                   cam_config_svg, cam_config_noext]})

    client = yield from test_client(hass.http.app)

    image = 'hello'
    m_open = MockOpen(read_data=image.encode())
    with mock.patch('homeassistant.components.camera.local_file.open',
                    m_open, create=True):
        resp_1 = yield from client.get('/api/camera_proxy/camera.test_jpg')
        resp_2 = yield from client.get('/api/camera_proxy/camera.test_png')
        resp_3 = yield from client.get('/api/camera_proxy/camera.test_svg')
        resp_4 = yield from client.get('/api/camera_proxy/camera.test_no_ext')

    assert resp_1.status == 200
    assert resp_1.content_type == 'image/jpeg'
    body = yield from resp_1.text()
    assert body == image

    assert resp_2.status == 200
    assert resp_2.content_type == 'image/png'
    body = yield from resp_2.text()
    assert body == image

    assert resp_3.status == 200
    assert resp_3.content_type == 'image/svg+xml'
    body = yield from resp_3.text()
    assert body == image

    # default mime type
    assert resp_4.status == 200
    assert resp_4.content_type == 'image/jpeg'
    body = yield from resp_4.text()
    assert body == image
Example #5
0
 def test_setup(self):
     """Test that sensor can be setup."""
     config = {"sensor": {"platform": "fail2ban", "jails": ["jail_one"]}}
     mock_fh = MockOpen()
     with patch("homeassistant.components.fail2ban.sensor.open",
                mock_fh,
                create=True):
         assert setup_component(self.hass, "sensor", config)
         self.hass.block_till_done()
     assert_setup_component(1, "sensor")
    def _mock_call(self, path: str, mode: str = "r", *args, **kws):
        original_side_effect = self._mock_side_effect

        if path not in self._MockOpen__files:
            self._mock_side_effect = FileNotFoundError

        child = MockOpen._mock_call(self, path, mode, *args, **kws)

        self._mock_side_effect = original_side_effect
        return child
Example #7
0
 def test_setup(self):
     """Test that sensor can be setup."""
     config = {'sensor': {'platform': 'fail2ban', 'jails': ['jail_one']}}
     mock_fh = MockOpen()
     with patch('homeassistant.components.sensor.fail2ban.open',
                mock_fh,
                create=True):
         assert setup_component(self.hass, 'sensor', config)
         self.hass.block_till_done()
     assert_setup_component(1, 'sensor')
Example #8
0
def test_get_part_of_log_read(offset, lines, json, valid):
    """
    Первые две цифры кортежа задают  offset и lines
    offset == 0 lines == 1 читаем первую строчку
    offset == 2 lines == 10 так как смещение указаывает не на первый байт в новой строке, возвращаем следующую строку.
    """
    m = MockOpen()
    m[LOG_FILE_PATH].read_data = json

    with mock.patch('__builtin__.open', new=m):
        assert get_part_of_log(offset, lines)['messages'] == valid
Example #9
0
    def _check_bank_splitting(expected, contents, is_fresh, is_done):
        """Compare two bank splits by their structure."""
        (expected_header, expected_feature, expected_scenarios) = expected

        mocked_open = MockOpen()
        mocked_open[BANK_PATH_1].read_data = contents
        with patch("bddbot.bank.open", mocked_open):
            bank = Bank(BANK_PATH_1)

        mocked_open.assert_called_once_with(BANK_PATH_1, "r")
        mocked_open[BANK_PATH_1].read.assert_called_once_with()

        assert_equal(is_fresh, bank.is_fresh())
        assert_equal(is_done, bank.is_done())
        assert_equal(FEATURE_PATH_1, bank.output_path)
        assert_multi_line_equal(expected_header, bank.header)
        assert_multi_line_equal(expected_feature, bank.feature)

        all_scenarios = list(iter(bank.get_next_scenario, None))
        for (expected_scenario, actual_scenario) in zip(expected_scenarios, all_scenarios):
            assert_multi_line_equal(expected_scenario, actual_scenario)
Example #10
0
    def test_file_value(self):
        """Test the File sensor."""
        config = {
            "sensor": {"platform": "file", "name": "file1", "file_path": "mock.file1"}
        }

        m_open = MockOpen(read_data="43\n45\n21")
        with patch("homeassistant.components.file.sensor.open", m_open, create=True):
            assert setup_component(self.hass, "sensor", config)
            self.hass.block_till_done()

        state = self.hass.states.get("sensor.file1")
        assert state.state == "21"
Example #11
0
    def test_file_empty(self):
        """Test the File sensor with an empty file."""
        config = {
            "sensor": {"platform": "file", "name": "file3", "file_path": "mock.file"}
        }

        m_open = MockOpen(read_data="")
        with patch("homeassistant.components.file.sensor.open", m_open, create=True):
            assert setup_component(self.hass, "sensor", config)
            self.hass.block_till_done()

        state = self.hass.states.get("sensor.file3")
        assert state.state == STATE_UNKNOWN
    def test_ipv6_ban(self):
        """Test that log is parsed correctly for IPV6 bans."""
        log_parser = BanLogParser("/test/fail2ban.log")
        sensor = BanSensor("fail2ban", "jail_one", log_parser)
        assert sensor.name == "fail2ban jail_one"
        mock_fh = MockOpen(read_data=fake_log("ipv6_ban"))
        with patch(
            "homeassistant.components.fail2ban.sensor.open", mock_fh, create=True
        ):
            sensor.update()

        assert sensor.state == "2607:f0d0:1002:51::4"
        assert sensor.state_attributes[STATE_CURRENT_BANS] == ["2607:f0d0:1002:51::4"]
        assert sensor.state_attributes[STATE_ALL_BANS] == ["2607:f0d0:1002:51::4"]
Example #13
0
    def test_unban_all(self):
        """Test that log is parsed correctly when unbanning."""
        log_parser = BanLogParser('/tmp')
        sensor = BanSensor('fail2ban', 'jail_one', log_parser)
        assert sensor.name == 'fail2ban jail_one'
        mock_fh = MockOpen(read_data=fake_log('unban_all'))
        with patch('homeassistant.components.sensor.fail2ban.open', mock_fh,
                   create=True):
            sensor.update()

        assert sensor.state == 'None'
        assert sensor.state_attributes[STATE_CURRENT_BANS] == []
        assert sensor.state_attributes[STATE_ALL_BANS] == \
            ['111.111.111.111', '222.222.222.222']
Example #14
0
    def test_single_ban(self):
        """Test that log is parsed correctly for single ban."""
        log_parser = BanLogParser("/tmp")
        sensor = BanSensor("fail2ban", "jail_one", log_parser)
        assert sensor.name == "fail2ban jail_one"
        mock_fh = MockOpen(read_data=fake_log("single_ban"))
        with patch(
            "homeassistant.components.fail2ban.sensor.open", mock_fh, create=True
        ):
            sensor.update()

        assert sensor.state == "111.111.111.111"
        assert sensor.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
        assert sensor.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]
Example #15
0
 def test_ban_active_after_update(self):
     """Test that ban persists after subsequent update."""
     log_parser = BanLogParser('/tmp')
     sensor = BanSensor('fail2ban', 'jail_one', log_parser)
     assert sensor.name == 'fail2ban jail_one'
     mock_fh = MockOpen(read_data=fake_log('single_ban'))
     with patch('homeassistant.components.sensor.fail2ban.open', mock_fh,
                create=True):
         sensor.update()
         assert sensor.state == '111.111.111.111'
         sensor.update()
         assert sensor.state == '111.111.111.111'
     assert \
         sensor.state_attributes[STATE_CURRENT_BANS] == ['111.111.111.111']
     assert sensor.state_attributes[STATE_ALL_BANS] == ['111.111.111.111']
Example #16
0
    def test_multiple_ban(self):
        """Test that log is parsed correctly for multiple ban."""
        log_parser = BanLogParser(timedelta(seconds=-1), '/tmp')
        sensor = BanSensor('fail2ban', 'jail_one', log_parser)
        assert sensor.name == 'fail2ban jail_one'
        mock_fh = MockOpen(read_data=fake_log('multi_ban'))
        with patch('homeassistant.components.sensor.fail2ban.open', mock_fh,
                   create=True):
            sensor.update()

        assert sensor.state == '222.222.222.222'
        assert sensor.state_attributes[STATE_CURRENT_BANS] == \
            ['111.111.111.111', '222.222.222.222']
        assert sensor.state_attributes[STATE_ALL_BANS] == \
            ['111.111.111.111', '222.222.222.222']
Example #17
0
    def test_single_ban(self):
        """Test that log is parsed correctly for single ban."""
        log_parser = BanLogParser('/tmp')
        sensor = BanSensor('fail2ban', 'jail_one', log_parser)
        assert sensor.name == 'fail2ban jail_one'
        mock_fh = MockOpen(read_data=fake_log('single_ban'))
        with patch('homeassistant.components.fail2ban.sensor.open', mock_fh,
                   create=True):
            sensor.update()

        assert sensor.state == '111.111.111.111'
        assert \
            sensor.state_attributes[STATE_CURRENT_BANS] == ['111.111.111.111']
        assert \
            sensor.state_attributes[STATE_ALL_BANS] == ['111.111.111.111']
 def test_ban_active_after_update(self):
     """Test that ban persists after subsequent update."""
     log_parser = BanLogParser("/test/fail2ban.log")
     sensor = BanSensor("fail2ban", "jail_one", log_parser)
     assert sensor.name == "fail2ban jail_one"
     mock_fh = MockOpen(read_data=fake_log("single_ban"))
     with patch(
         "homeassistant.components.fail2ban.sensor.open", mock_fh, create=True
     ):
         sensor.update()
         assert sensor.state == "111.111.111.111"
         sensor.update()
         assert sensor.state == "111.111.111.111"
     assert sensor.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
     assert sensor.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]
Example #19
0
    def test_unban_all(self):
        """Test that log is parsed correctly when unbanning."""
        log_parser = BanLogParser(timedelta(seconds=-1), '/tmp')
        sensor = BanSensor('fail2ban', 'jail_one', log_parser)
        self.assertEqual(sensor.name, 'fail2ban jail_one')
        mock_fh = MockOpen(read_data=fake_log('unban_all'))
        with patch('homeassistant.components.sensor.fail2ban.open',
                   mock_fh,
                   create=True):
            sensor.update()

        self.assertEqual(sensor.state, 'None')
        self.assertEqual(sensor.state_attributes[STATE_CURRENT_BANS], [])
        self.assertEqual(sensor.state_attributes[STATE_ALL_BANS],
                         ['111.111.111.111', '222.222.222.222'])
Example #20
0
    def test_ipv6_ban(self):
        """Test that log is parsed correctly for IPV6 bans."""
        log_parser = BanLogParser('/tmp')
        sensor = BanSensor('fail2ban', 'jail_one', log_parser)
        assert sensor.name == 'fail2ban jail_one'
        mock_fh = MockOpen(read_data=fake_log('ipv6_ban'))
        with patch('homeassistant.components.sensor.fail2ban.open', mock_fh,
                   create=True):
            sensor.update()

        assert sensor.state == '2607:f0d0:1002:51::4'
        assert \
            sensor.state_attributes[STATE_CURRENT_BANS] == \
            ['2607:f0d0:1002:51::4']
        assert \
            sensor.state_attributes[STATE_ALL_BANS] == ['2607:f0d0:1002:51::4']
Example #21
0
 def test_ban_active_after_update(self):
     """Test that ban persists after subsequent update."""
     log_parser = BanLogParser(timedelta(seconds=-1), '/tmp')
     sensor = BanSensor('fail2ban', 'jail_one', log_parser)
     self.assertEqual(sensor.name, 'fail2ban jail_one')
     mock_fh = MockOpen(read_data=fake_log('single_ban'))
     with patch('homeassistant.components.sensor.fail2ban.open',
                mock_fh,
                create=True):
         sensor.update()
         self.assertEqual(sensor.state, '111.111.111.111')
         sensor.update()
         self.assertEqual(sensor.state, '111.111.111.111')
     self.assertEqual(sensor.state_attributes[STATE_CURRENT_BANS],
                      ['111.111.111.111'])
     self.assertEqual(sensor.state_attributes[STATE_ALL_BANS],
                      ['111.111.111.111'])
Example #22
0
    def test_unban_all(self):
        """Test that log is parsed correctly when unbanning."""
        log_parser = BanLogParser("/test/fail2ban.log")
        sensor = BanSensor("fail2ban", "jail_one", log_parser)
        assert sensor.name == "fail2ban jail_one"
        mock_fh = MockOpen(read_data=fake_log("unban_all"))
        with patch("homeassistant.components.fail2ban.sensor.open",
                   mock_fh,
                   create=True):
            sensor.update()

        assert sensor.state == "None"
        assert sensor.state_attributes[STATE_CURRENT_BANS] == []
        assert sensor.state_attributes[STATE_ALL_BANS] == [
            "111.111.111.111",
            "222.222.222.222",
        ]
Example #23
0
    def test_file_value(self):
        """Test the File sensor."""
        config = {
            'sensor': {
                'platform': 'file',
                'name': 'file1',
                'file_path': 'mock.file1',
            }
        }

        m_open = MockOpen(read_data='43\n45\n21')
        with patch('homeassistant.components.sensor.file.open',
                   m_open,
                   create=True):
            assert setup_component(self.hass, 'sensor', config)
            self.hass.block_till_done()

        state = self.hass.states.get('sensor.file1')
        self.assertEqual(state.state, '21')
Example #24
0
    def test_file_empty(self):
        """Test the File sensor with an empty file."""
        config = {
            'sensor': {
                'platform': 'file',
                'name': 'file3',
                'file_path': 'mock.file',
            }
        }

        m_open = MockOpen(read_data='')
        with patch('homeassistant.components.sensor.file.open',
                   m_open,
                   create=True):
            assert setup_component(self.hass, 'sensor', config)
            self.hass.block_till_done()

        state = self.hass.states.get('sensor.file3')
        self.assertEqual(state.state, STATE_UNKNOWN)
Example #25
0
    def test_multi_jail(self):
        """Test that log is parsed correctly when using multiple jails."""
        log_parser = BanLogParser("/tmp")
        sensor1 = BanSensor("fail2ban", "jail_one", log_parser)
        sensor2 = BanSensor("fail2ban", "jail_two", log_parser)
        assert sensor1.name == "fail2ban jail_one"
        assert sensor2.name == "fail2ban jail_two"
        mock_fh = MockOpen(read_data=fake_log("multi_jail"))
        with patch(
            "homeassistant.components.fail2ban.sensor.open", mock_fh, create=True
        ):
            sensor1.update()
            sensor2.update()

        assert sensor1.state == "111.111.111.111"
        assert sensor1.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
        assert sensor1.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]
        assert sensor2.state == "222.222.222.222"
        assert sensor2.state_attributes[STATE_CURRENT_BANS] == ["222.222.222.222"]
        assert sensor2.state_attributes[STATE_ALL_BANS] == ["222.222.222.222"]
Example #26
0
    def test_multi_jail(self):
        """Test that log is parsed correctly when using multiple jails."""
        log_parser = BanLogParser('/tmp')
        sensor1 = BanSensor('fail2ban', 'jail_one', log_parser)
        sensor2 = BanSensor('fail2ban', 'jail_two', log_parser)
        assert sensor1.name == 'fail2ban jail_one'
        assert sensor2.name == 'fail2ban jail_two'
        mock_fh = MockOpen(read_data=fake_log('multi_jail'))
        with patch('homeassistant.components.sensor.fail2ban.open', mock_fh,
                   create=True):
            sensor1.update()
            sensor2.update()

        assert sensor1.state == '111.111.111.111'
        assert \
            sensor1.state_attributes[STATE_CURRENT_BANS] == ['111.111.111.111']
        assert sensor1.state_attributes[STATE_ALL_BANS] == ['111.111.111.111']
        assert sensor2.state == '222.222.222.222'
        assert \
            sensor2.state_attributes[STATE_CURRENT_BANS] == ['222.222.222.222']
        assert sensor2.state_attributes[STATE_ALL_BANS] == ['222.222.222.222']
Example #27
0
    def test_file_value_template(self):
        """Test the File sensor with JSON entries."""
        config = {
            'sensor': {
                'platform': 'file',
                'name': 'file2',
                'file_path': 'mock.file2',
                'value_template': '{{ value_json.temperature }}',
            }
        }

        data = '{"temperature": 29, "humidity": 31}\n' \
               '{"temperature": 26, "humidity": 36}'

        m_open = MockOpen(read_data=data)
        with patch('homeassistant.components.sensor.file.open',
                   m_open,
                   create=True):
            assert setup_component(self.hass, 'sensor', config)
            self.hass.block_till_done()

        state = self.hass.states.get('sensor.file2')
        self.assertEqual(state.state, '26')
Example #28
0
    def test_file_value_template(self):
        """Test the File sensor with JSON entries."""
        config = {
            "sensor": {
                "platform": "file",
                "name": "file2",
                "file_path": "mock.file2",
                "value_template": "{{ value_json.temperature }}",
            }
        }

        data = (
            '{"temperature": 29, "humidity": 31}\n'
            '{"temperature": 26, "humidity": 36}'
        )

        m_open = MockOpen(read_data=data)
        with patch("homeassistant.components.file.sensor.open", m_open, create=True):
            assert setup_component(self.hass, "sensor", config)
            self.hass.block_till_done()

        state = self.hass.states.get("sensor.file2")
        assert state.state == "26"
Example #29
0
 def __init__(self):
     super(BaseDealerTest, self).__init__()
     self.dealer = None
     self.mocked_open = MockOpen()
     self.mocked_popen = create_autospec(Popen)
     self.mocked_mkdir = Mock()
Example #30
0
async def test_service_exists(hass, caplog):
    """Test importing a pyscript module."""

    conf_dir = hass.config.path(FOLDER)

    file_contents = {
        f"{conf_dir}/hello.py":
        """
import xyz2
from xyz2 import f_minus

@service
def func1():
    pyscript.done = [xyz2.f_add(1, 2), xyz2.f_mult(3, 4), xyz2.f_add(10, 20), f_minus(50, 20)]
""",
        #
        # this will fail to load since import doesn't exist
        #
        f"{conf_dir}/bad_import.py":
        """
import no_such_package

@service
def func10():
    pass
""",
        #
        # this will fail to load since import has a syntax error
        #
        f"{conf_dir}/bad_import2.py":
        """
import bad_module

@service
def func11():
    pass
""",
        #
        # This will load, since there is an apps/world config entry
        #
        f"{conf_dir}/apps/world.py":
        """
from xyz2 import *

@service
def func2():
    pyscript.done = [get_x(), get_name(), other_name(), f_add(1, 5), f_mult(3, 6), f_add(10, 30), f_minus(50, 30)]
""",
        #
        # This will not load, since there is no apps/world2 config entry
        #
        f"{conf_dir}/apps/world2.py":
        """
from xyz2 import *

@service
def func10():
    pass
""",
        f"{conf_dir}/modules/xyz2/__init__.py":
        """
from .other import f_minus, other_name

log.info(f"modules/xyz2 global_ctx={pyscript.get_global_ctx()};")

x = 99

def f_add(a, b):
    return a + b

def f_mult(a, b):
    return a * b

def get_x():
    return x

def get_name():
    return __name__
""",
        f"{conf_dir}/modules/xyz2/other.py":
        """
def f_minus(a, b):
    return a - b

def other_name():
    return __name__
""",
        #
        # this module has a syntax error (missing :)
        #
        f"{conf_dir}/modules/bad_module.py":
        """
def func12()
    pass
""",
        #
        # this script file should auto-load
        #
        f"{conf_dir}/scripts/func13.py":
        """
@service
def func13():
    pass
""",
        #
        # this script file should auto-load
        #
        f"{conf_dir}/scripts/a/b/c/d/func14.py":
        """
@service
def func14():
    pass

log.info(f"func14 global_ctx={pyscript.get_global_ctx()};")

""",
        #
        # this script file should not auto-load
        #
        f"{conf_dir}/scripts/a/b/c/d/#func15.py":
        """
@service
def func15():
    pass
""",
        #
        # this script file should not auto-load
        #
        f"{conf_dir}/scripts/#a/b/c/d/func15.py":
        """
@service
def func15():
    pass
""",
    }

    mock_open = MockOpen()
    for key, value in file_contents.items():
        mock_open[key].read_data = value

    def isfile_side_effect(arg):
        return arg in file_contents

    def glob_side_effect(path, recursive=None):
        result = []
        path_re = path.replace("*", "[^/]*").replace(".", "\\.")
        path_re = path_re.replace("[^/]*[^/]*/", ".*")
        for this_path in file_contents:
            if re.match(path_re, this_path):
                result.append(this_path)
        return result

    conf = {"apps": {"world": {}}}
    with patch(
            "custom_components.pyscript.os.path.isdir", return_value=True
    ), patch("custom_components.pyscript.glob.iglob") as mock_glob, patch(
            "custom_components.pyscript.global_ctx.open", mock_open
    ), patch("custom_components.pyscript.open", mock_open), patch(
            "homeassistant.config.load_yaml_config_file",
            return_value={"pyscript": conf}
    ), patch("custom_components.pyscript.watchdog_start",
             return_value=None), patch(
                 "custom_components.pyscript.os.path.getmtime",
                 return_value=1000), patch(
                     "custom_components.pyscript.global_ctx.os.path.getmtime",
                     return_value=1000), patch(
                         "custom_components.pyscript.os.path.isfile"
                     ) as mock_isfile:
        mock_isfile.side_effect = isfile_side_effect
        mock_glob.side_effect = glob_side_effect
        assert await async_setup_component(hass, "pyscript", {DOMAIN: conf})

    notify_q = asyncio.Queue(0)

    async def state_changed(event):
        var_name = event.data["entity_id"]
        if var_name != "pyscript.done":
            return
        value = event.data["new_state"].state
        await notify_q.put(value)

    hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)

    assert not hass.services.has_service("pyscript", "func10")
    assert not hass.services.has_service("pyscript", "func11")
    assert hass.services.has_service("pyscript", "func13")
    assert hass.services.has_service("pyscript", "func14")
    assert not hass.services.has_service("pyscript", "func15")

    await hass.services.async_call("pyscript", "func1", {})
    ret = await wait_until_done(notify_q)
    assert literal_eval(ret) == [1 + 2, 3 * 4, 10 + 20, 50 - 20]

    await hass.services.async_call("pyscript", "func2", {})
    ret = await wait_until_done(notify_q)
    assert literal_eval(ret) == [
        99, "xyz2", "xyz2.other", 1 + 5, 3 * 6, 10 + 30, 50 - 30
    ]

    assert "modules/xyz2 global_ctx=modules.xyz2;" in caplog.text
    assert "func14 global_ctx=scripts.a.b.c.d.func14;" in caplog.text
    assert "ModuleNotFoundError: import of no_such_package not allowed" in caplog.text
    assert "SyntaxError: invalid syntax (bad_module.py, line 2)" in caplog.text
Example #31
0
class BaseDealerTest(BankMockerTest):
    # pylint: disable=too-few-public-methods
    """A container for utility classes common when testing the Dealer class."""
    FEATURES = {
        BANK_PATH_1: (FEATURE_PATH_1, "", FEATURE_1 + "\n"),
        BANK_PATH_2: (FEATURE_PATH_2, "", FEATURE_2 + "\n"),
    }

    def __init__(self):
        super(BaseDealerTest, self).__init__()
        self.dealer = None
        self.mocked_open = MockOpen()
        self.mocked_popen = create_autospec(Popen)
        self.mocked_mkdir = Mock()

    def teardown(self):
        super(BaseDealerTest, self).teardown()
        patch.stopall()

        # Reset dealer instance.
        self.dealer = None

    def _mock_dealer_functions(self):
        """Mock out standard library functions used by the dealer module."""
        self._reset_mocks()

        patcher = patch.multiple(
            "bddbot.dealer",
            open = self.mocked_open,
            Bank = self.mock_bank_class,
            RemoteBank = self.mock_bank_class,
            Popen = self.mocked_popen,
            mkdir = self.mocked_mkdir)

        patcher.start()

    def _create_dealer(self, banks, tests, name = ""):
        """Create a new dealer instance without loading state."""
        if tests is None:
            tests = DEFAULT_TEST_COMMANDS

        self.mocked_open[STATE_PATH].side_effect = IOError()
        self.dealer = Dealer(banks, tests, name = name)

        self.mocked_open.assert_called_once_with(STATE_PATH, "rb")

        self._reset_mocks()

    def _load_dealer(self, banks = None, tests = None, name = ""):
        """Simulate a call to load() and verify success."""
        if banks is None:
            banks = [BANK_PATH_1, ]
        if not tests:
            tests = DEFAULT_TEST_COMMANDS

        if self.dealer is None:
            self._create_dealer(banks, tests, name = name)

        # pylint: disable=bad-continuation
        with patch.multiple("bddbot.dealer",
             Bank = self.mock_bank_class,
             RemoteBank = self.mock_bank_class):
            self.dealer.load()

        # Verify calls to mocks.
        self.mocked_open.assert_not_called()
        self.mocked_popen.assert_not_called()

        for path in banks:
            if not path.startswith("@"):
                self.mock_bank_class.assert_any_call(path)
            else:
                (host, port) = path[1:].split(":")
                self.mock_bank_class.assert_called_with(name, host, int(port))

        self._reset_mocks()

    def _deal(self, expected_feature, expected_scenario, bank_path = None, feature_path = None):
        # pylint: disable=too-many-arguments
        """Simulate dealing a scenario and verify success.

        If `expected_feature` is specified, simulate the first time a scenario is dealt from
        the features bank. Otherwise, simulate a consecutive deal from a previous bank.

        Return the commands passed to `Popen()` to verify outside of this function.
        """
        if not bank_path:
            bank_path = BANK_PATH_1

        if not feature_path:
            feature_path = bank_path.replace("bank", "feature")

        self.mocked_popen.return_value.returncode = 0
        self.mocked_popen.return_value.communicate.return_value = ("", "")

        self.dealer.deal()

        # If feature is specified, simulate the first deal from the features bank.
        if expected_feature is not None:
            self.mocked_open.assert_called_once_with(feature_path, "w")

            self._assert_writes(
                ["", expected_feature + "\n", expected_scenario, ],
                path = feature_path)

            self.mocked_mkdir.assert_called_once_with(dirname(feature_path))

        # If feature isn't specified, simulate a consecutive deal.
        # Note that calls to Popen should be verified outside of this function in this case.
        else:
            self.mocked_open.assert_called_once_with(feature_path, "ab")
            self.mocked_open[feature_path].write.assert_called_once_with(expected_scenario)
            self.mocked_popen.return_value.communicate.assert_called_with()
            self.mocked_mkdir.assert_not_called()

        self.mock_banks[bank_path].is_fresh.assert_called_with()
        self.mock_banks[bank_path].is_done.assert_called_with()
        self.mock_banks[bank_path].get_next_scenario.assert_called_once_with()

        # We return the commands because we reset the mocks at the end of the function.
        # The stdout/stderr values aren't important, we only care about the commands.
        popen_calls = [command for ((command, ), _) in self.mocked_popen.call_args_list]

        # Reset mocks.
        self._reset_mocks()

        return popen_calls

    def _assert_writes(self, chunks, path = FEATURE_PATH_1):
        """Verify all calls to write()."""
        assert_equal([call(chunk) for chunk in chunks], self.mocked_open[path].write.mock_calls)

    def _reset_mocks(self):
        """Reset all mocks."""
        self.mocked_open.reset_mock()
        self.mocked_popen.reset_mock()
        self.mock_bank_class.reset_mock()
        self.mocked_mkdir.reset_mock()

        for mock_bank in self.mock_banks.itervalues():
            mock_bank.reset_mock()
Example #32
0
    def test_valid_upload_recording(self):
        """Test UserAPI.upload_recordings ( parameters passed: groupname, devicename, filename, props) to mocked CacophonyServer object.


        # Range of expectedResult

        'expectedResult':{'outcome':'success',
                                'validator':lambda test: test},
        'expectedResult':{'outcome':'failurePreRequest',
                                'validator':lambda test: test},
        'expectedResult':{'outcome':'failureOnRequest',
                                'validator':lambda test: test},



        """
        # TODO: Construct the data to pass in the post
        mock_apiPath = lambda devicename, groupname: "/api/v1/recordings/device/{devicename}/group/{groupname}".format(
            devicename=devicename, groupname=groupname)

        # TODO: construct the success validatior
        # TODO: construct the failure validtor
        testcases = [
            {
                "filename": "test1.cptv",
                "mock_file.side_effect": None,
                "devicename": "deviceTEST1234",
                "groupname": "groupTEST1234",
                "prop": None,
                "expectedProp": {
                    "type": "thermalRaw"
                },
                "expectedResult": {
                    "outcome": "success",
                    "validator": lambda test: test,
                },
                "mockRequestJsonResponse": {
                    "success": True
                },
                "mockRequestStatusCode": 200,
            },
            # TODO: adjust test mock/asserts to handle IOError
            # {'filename':"test1.cptv",
            #   'mock_file.side_effect':IOError(),
            #   'devicename':'deviceTEST1234',
            #   'groupname':'groupTEST1234',
            #   'prop':None,
            #   'expectedProp':{'type':'thermalRaw'},
            #   'mockRequestStatusCode':200
            #  },
            {
                "filename": "test2.mp3",
                "mock_file.side_effect": None,
                "devicename": "deviceTEST1234",
                "groupname": "groupTEST1234",
                "prop": None,
                "expectedProp": {
                    "type": "audio"
                },
                "expectedResult": {
                    "outcome": "success",
                    "validator": lambda test: test,
                },
                "mockRequestJsonResponse": {
                    "success": True
                },
                "mockRequestStatusCode": 200,
            },
            # TODO: what assert/mock to do for unknown file type
            {
                "filename": "test3.xyz",
                "mock_file.side_effect": None,
                "devicename": "deviceTEST1234",
                "groupname": "groupTEST1234",
                "prop": None,
                "expectedProp": None,
                "expectedResult": {
                    "outcome": "failurePreRequest",
                    "validator": lambda test: test,
                },
                "mockRequestJsonResponse": None,
                "mockRequestStatusCode": None,
            },
        ]

        for tc in testcases:
            # TODO: pretty print
            print(tc)
            """
                This Test is tough to design/debug
                made easier by using mock-open module https://github.com/nivbend/mock-open

                mock the file to upload
                Last, you also need to mock os.fstat() so that permissions are correct
                (Clues in https://gist.github.com/dmerejkowsky/d11e3c68be6a96387dea3d8b6a409b40#file-test_netrc-py-L17)
            """

            mock_open = MockOpen(read_data="0123456789012345678901234")
            # mock_open = MockOpen(read_data='',side_effect=IOError('no file'))

            mock_open[os.path.join(
                os.path.dirname(__file__),
                tc["filename"])].read_data = "0123456789012345678901234"
            mock_open[os.path.join(
                os.path.dirname(__file__),
                tc["filename"])].side_effect = tc["mock_file.side_effect"]
            fake_stat = mock.MagicMock("fstat")
            # fake_stat.st_uid = # os.getuid()
            fake_stat.st_mode = 0o600
            fake_stat.st_size = 25

            with patch("builtins.open",
                       mock_open), patch("os.fstat") as mock_fstat:
                mock_fstat.return_value = fake_stat

                with requests_mock.Mocker() as m:
                    m.register_uri(
                        requests_mock.POST,
                        "{apiURL}{apiPath}".format(
                            apiURL=defaults["apiURL"],
                            apiPath=mock_apiPath(tc["devicename"],
                                                 tc["groupname"]),
                        ),
                        json=tc["mockRequestJsonResponse"],
                        status_code=tc["mockRequestStatusCode"],
                    )
                    if tc["expectedResult"]["outcome"] == "success":
                        # ----------------------- API call UNDERTEST ------------------
                        result = self.cli.upload_recording(
                            tc["groupname"],
                            tc["devicename"],
                            tc["filename"],
                            tc["prop"],
                        )
                        # ----------------------------------------------------------------
                        print(result)
                        # TODO: FILL in the TEST assertions in place of the following
                        self.assertEqual(result, tc["mockRequestJsonResponse"])
                        self.assertTrue(
                            tc["expectedResult"]["validator"](True))

                    elif tc["expectedResult"][
                            "outcome"] == "failurePreRequest":
                        with self.assertRaises(ValueError):
                            # ----------------------- API call UNDERTEST ------------------
                            result = self.cli.upload_recording(
                                tc["groupname"],
                                tc["devicename"],
                                tc["filename"],
                                tc["prop"],
                            )
                    # ----------------------------------------------------------------
                    else:
                        # TODO: Check the mockrequest was called, and mockfile
                        self.assertTrue(
                            False,
                            "Something not being checked ----------------------------",
                        )
Example #33
0
async def test_reload(hass, caplog):
    """Test reload a pyscript module."""

    conf_dir = hass.config.path(FOLDER)

    file_contents = {
        f"{conf_dir}/hello.py":
        """
import xyz2
from xyz2 import xyz

#
# ensure a regular script doesn't have pyscript.app_config set
#
try:
    x = pyscript.app_config
    assert False
except NameError:
    pass

log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()} xyz={xyz} xyz2.xyz={xyz2.xyz}")

@service
def func1():
    pass
""",
        #
        # This will load, since there is an apps/world config entry
        #
        f"{conf_dir}/apps/world.py":
        """
from xyz2 import *

log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()} xyz={xyz}")

@service
def func2():
    pass
""",
        #
        # This will load, since there is an apps/world2 config entry
        #
        f"{conf_dir}/apps/world2/__init__.py":
        """
from .other import *

assert pyscript.config['apps']['world2'] == pyscript.app_config

log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()} var1={pyscript.config['apps']['world2']['var1']}, other_abc={other_abc}")

@service
def func3():
    pass
""",
        f"{conf_dir}/apps/world2/other.py":
        """
other_abc = 987

log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()}")

#
# ensure a sub file in the app doesn't have pyscript.app_config set
#
try:
    x = pyscript.app_config
    assert False
except NameError:
    pass

@time_trigger("shutdown")
def shutdown(trigger_time=None):
    log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()} shutdown trigger_time={trigger_time}")
""",
        f"{conf_dir}/modules/xyz2/__init__.py":
        """
from .other import xyz

#
# ensure a module doesn't have pyscript.app_config set
#
try:
    x = pyscript.app_config
    assert False
except NameError:
    pass

log.info(f"modules/xyz2 global_ctx={pyscript.get_global_ctx()};")
""",
        f"{conf_dir}/modules/xyz2/other.py":
        """
log.info(f"modules/xyz2/other global_ctx={pyscript.get_global_ctx()};")

xyz = 123
""",
        #
        # these shouldn't load since the package takes precedence
        #
        f"{conf_dir}/modules/xyz2.py":
        """
log.info(f"BOTCH shouldn't load {__name__}")
""",
        f"{conf_dir}/apps/world2.py":
        """
log.info(f"BOTCH shouldn't load {__name__}")
""",
    }

    mock_open = MockOpen()
    for key, value in file_contents.items():
        mock_open[key].read_data = value

    def isfile_side_effect(arg):
        return arg in file_contents

    def glob_side_effect(path, recursive=None):
        result = []
        path_re = path.replace("*", "[^/]*").replace(".", "\\.")
        path_re = path_re.replace("[^/]*[^/]*/", ".*")
        for this_path in file_contents:
            if re.match(path_re, this_path):
                result.append(this_path)
        return result

    conf = {"apps": {"world": {}, "world2": {"var1": 100}}}
    with patch(
            "custom_components.pyscript.os.path.isdir", return_value=True
    ), patch("custom_components.pyscript.glob.iglob") as mock_glob, patch(
            "custom_components.pyscript.global_ctx.open", mock_open
    ), patch("custom_components.pyscript.open", mock_open), patch(
            "homeassistant.util.yaml.loader.open", mock_open
    ), patch("homeassistant.config.load_yaml_config_file",
             return_value={"pyscript": conf}), patch(
                 "custom_components.pyscript.watchdog_start",
                 return_value=None), patch(
                     "custom_components.pyscript.os.path.getmtime",
                     return_value=1000
                 ), patch(
                     "custom_components.pyscript.global_ctx.os.path.getmtime",
                     return_value=1000), patch(
                         "custom_components.pyscript.os.path.isfile"
                     ) as mock_isfile:
        mock_isfile.side_effect = isfile_side_effect
        mock_glob.side_effect = glob_side_effect
        assert await async_setup_component(hass, "pyscript", {DOMAIN: conf})

        notify_q = asyncio.Queue(0)

        async def state_changed(event):
            var_name = event.data["entity_id"]
            if var_name != "pyscript.done":
                return
            value = event.data["new_state"].state
            await notify_q.put(value)

        hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)

        assert hass.services.has_service("pyscript", "func1")
        assert hass.services.has_service("pyscript", "func2")
        assert hass.services.has_service("pyscript", "func3")

        assert "modules/xyz2 global_ctx=modules.xyz2;" in caplog.text
        assert "modules/xyz2/other global_ctx=modules.xyz2.other;" in caplog.text
        assert "hello global_ctx=file.hello xyz=123 xyz2.xyz=123" in caplog.text
        assert "world2.other global_ctx=apps.world2.other" in caplog.text
        assert "world2 global_ctx=apps.world2 var1=100, other_abc=987" in caplog.text

        #
        # add a new script file
        #
        file_contents[f"{conf_dir}/hello2.py"] = """
log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()};")

@service
def func20():
    pass
"""
        mock_open[f"{conf_dir}/hello2.py"].read_data = file_contents[
            f"{conf_dir}/hello2.py"]

        #
        # should not load the new script if we reload something else
        #
        await hass.services.async_call("pyscript",
                                       "reload", {"global_ctx": "file.hello"},
                                       blocking=True)
        assert not hass.services.has_service("pyscript", "func20")
        assert "hello2 global_ctx=file.hello2;" not in caplog.text

        #
        # should load new file
        #
        await hass.services.async_call("pyscript", "reload", {}, blocking=True)
        assert hass.services.has_service("pyscript", "func20")
        assert "hello2 global_ctx=file.hello2;" in caplog.text

        #
        # delete the script file
        #
        del file_contents[f"{conf_dir}/hello2.py"]

        #
        # should not delete the script file if we reload something else
        #
        await hass.services.async_call("pyscript",
                                       "reload", {"global_ctx": "file.hello"},
                                       blocking=True)
        assert hass.services.has_service("pyscript", "func20")

        #
        # should delete the script file
        #
        await hass.services.async_call("pyscript", "reload", {}, blocking=True)
        assert not hass.services.has_service("pyscript", "func20")

        #
        # change a module file and confirm the parent script is reloaded too
        #
        file_contents[f"{conf_dir}/modules/xyz2/other.py"] = """
log.info(f"modules/xyz2/other global_ctx={pyscript.get_global_ctx()};")

xyz = 456
"""
        mock_open[
            f"{conf_dir}/modules/xyz2/other.py"].read_data = file_contents[
                f"{conf_dir}/modules/xyz2/other.py"]

        await hass.services.async_call("pyscript", "reload", {}, blocking=True)
        assert "hello global_ctx=file.hello xyz=456 xyz2.xyz=456" in caplog.text

        #
        # change the app config
        #
        conf["apps"]["world2"]["var1"] = 200
        await hass.services.async_call("pyscript", "reload", {}, blocking=True)
        assert "world2 global_ctx=apps.world2 var1=200, other_abc=987" in caplog.text
        assert "world2.other global_ctx=apps.world2.other shutdown trigger_time=shutdown" in caplog.text

        #
        # change a module inside an app
        #
        file_contents[f"{conf_dir}/apps/world2/other.py"] = """
other_abc = 654

log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()}")

@time_trigger("shutdown")
def shutdown(trigger_time=None):
    log.info(f"{__name__} global_ctx={pyscript.get_global_ctx()} shutdown_new trigger_time={trigger_time}")
"""
        mock_open[
            f"{conf_dir}/apps/world2/other.py"].read_data = file_contents[
                f"{conf_dir}/apps/world2/other.py"]
        await hass.services.async_call("pyscript", "reload", {}, blocking=True)
        assert "world2 global_ctx=apps.world2 var1=200, other_abc=654" in caplog.text
        assert "world2.other global_ctx=apps.world2.other shutdown trigger_time=shutdown" in caplog.text

        #
        # now confirm certain files reloaded the correct number of times,
        # and reload everything a few times
        #
        for i in range(3):
            assert caplog.text.count(
                "world global_ctx=apps.world xyz=") == 2 + i
            assert caplog.text.count(
                "world2 global_ctx=apps.world2 var1=") == 3 + i
            assert caplog.text.count(
                "hello global_ctx=file.hello xyz=") == 4 + i
            assert caplog.text.count(
                "modules/xyz2/other global_ctx=modules.xyz2.other") == 2 + i
            assert caplog.text.count(
                "modules/xyz2 global_ctx=modules.xyz2") == 2 + i
            assert (caplog.text.count(
                "world2.other global_ctx=apps.world2.other shutdown trigger_time=shutdown"
            ) == 2)
            assert (caplog.text.count(
                "world2.other global_ctx=apps.world2.other shutdown_new trigger_time=shutdown"
            ) == i)
            if i < 2:
                await hass.services.async_call("pyscript",
                                               "reload", {"global_ctx": "*"},
                                               blocking=True)

        #
        # make sure files that shouldn't load were not loaded
        #
        assert "BOTCH shouldn't load" not in caplog.text