Skip to content

Commit

Permalink
test(devices): Automatic check to device mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
xaviml committed Feb 1, 2020
1 parent 96e9277 commit e3c540b
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 58 deletions.
1 change: 1 addition & 0 deletions apps/controllerx/controllerx.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
"""
from devices.ikea import *
from devices.philips import *
from devices.aqara import *
2 changes: 1 addition & 1 deletion apps/controllerx/core/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def get_zha_actions_mapping(self):
"""
return None

async def get_attr_value(self, entity, attribute):
async def get_entity_state(self, entity, attribute=None):
if "group." in entity:
entities = await self.get_state(entity, attribute="entity_id")
entity = entities[0]
Expand Down
29 changes: 6 additions & 23 deletions apps/controllerx/core/type/light_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ async def on_full(self, attribute):

async def get_attribute(self, attribute):
if attribute == self.ATTRIBUTE_COLOR:
entity_states = await self.get_state(self.light["name"], attribute="all")
entity_states = await self.get_entity_state(
self.light["name"], attribute="all"
)
entity_attributes = entity_states["attributes"]
if self.light["color_mode"] == "auto":
if "xy_color" in entity_attributes:
Expand All @@ -134,7 +136,7 @@ async def get_value_attribute(self, attribute):
if attribute == "xy_color":
return None
else:
return await self.get_attr_value(self.light["name"], attribute)
return await self.get_entity_state(self.light["name"], attribute)

def check_smooth_power_on(self, attribute, direction, light_state):
return (
Expand All @@ -148,7 +150,7 @@ async def before_action(self, action, *args, **kwargs):
to_return = True
if action == "click" or action == "hold":
attribute, direction = args
light_state = await self.get_state(self.light["name"])
light_state = await self.get_entity_state(self.light["name"])
to_return = light_state == "on" or self.check_smooth_power_on(
attribute, direction, light_state
)
Expand Down Expand Up @@ -199,7 +201,7 @@ async def change_light_state(self, old, attribute, direction, stepper):
self.log(f"Attribute: {attribute}; Current value: {old}", level="DEBUG")
new_state_attribute, exceeded = stepper.step(old, direction)
if self.check_smooth_power_on(
attribute, direction, await self.get_state(self.light["name"])
attribute, direction, await self.get_entity_state(self.light["name"])
):
new_state_attribute = stepper.minmax.min
exceeded = False
Expand All @@ -221,22 +223,3 @@ def supports_smooth_power_on(self):
The behaviour can be overridden by the user with the 'smooth_power_on' option in app configuration.
"""
return False


# class CustomLightController(LightController):
#
# CUSTOM_LIGHT_ACTIONS = {
# "click_on", self.on,
# "click_off", self.off
# "click_brightness_up", self.
# }
# def initialize(self):
# self.custom_mapping = self.args["mapping"]
# self.log(self.custom_mapping)
# super().initialize()
#
# def get_state_actions_mapping(self):
# return {}
#
# def get_event_actions_mapping(self):
# return {}
Empty file.
28 changes: 10 additions & 18 deletions apps/controllerx/devices/ikea.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ def get_z2m_actions_mapping(self):
"brightness_down_click": self.volume_down,
"arrow_left_click": self.previous_track,
"arrow_right_click": self.next_track,
"brightness_up_hold": (self.hold, Controller.UP),
"brightness_up_hold": (self.hold, Stepper.UP),
"brightness_up_release": self.release,
"brightness_down_hold": (self.hold, Controller.DOWN),
"brightness_down_hold": (self.hold, Stepper.DOWN),
"brightness_down_release": self.release,
}

Expand All @@ -104,9 +104,9 @@ def get_deconz_actions_mapping(self):
3002: self.volume_down,
4002: self.previous_track,
5002: self.next_track,
2001: (self.hold, Controller.UP),
2001: (self.hold, Stepper.UP),
2003: self.release,
3001: (self.hold, Controller.DOWN),
3001: (self.hold, Stepper.DOWN),
3003: self.release,
}

Expand Down Expand Up @@ -136,16 +136,8 @@ def get_deconz_actions_mapping(self):
return {
1002: self.on,
2002: self.off,
1001: (
self.hold,
LightController.ATTRIBUTE_BRIGHTNESS,
LightController.DIRECTION_UP,
),
2001: (
self.hold,
LightController.ATTRIBUTE_BRIGHTNESS,
LightController.DIRECTION_DOWN,
),
1001: (self.hold, LightController.ATTRIBUTE_BRIGHTNESS, Stepper.UP),
2001: (self.hold, LightController.ATTRIBUTE_BRIGHTNESS, Stepper.DOWN),
1003: self.release,
2003: self.release,
}
Expand Down Expand Up @@ -241,8 +233,8 @@ class E1744MediaPlayerController(MediaPlayerController):

def get_z2m_actions_mapping(self):
return {
"rotate_left": (self.hold, Controller.DOWN),
"rotate_right": (self.hold, Controller.UP),
"rotate_left": (self.hold, Stepper.DOWN),
"rotate_right": (self.hold, Stepper.UP),
"rotate_stop": self.release,
"play_pause": self.play_pause,
"skip_forward": self.next_track,
Expand All @@ -251,8 +243,8 @@ def get_z2m_actions_mapping(self):

def get_deconz_actions_mapping(self):
return {
2001: (self.hold, Controller.DOWN),
3001: (self.hold, Controller.UP),
2001: (self.hold, Stepper.DOWN),
3001: (self.hold, Stepper.UP),
2003: self.release,
3003: self.release,
1002: self.play_pause,
Expand Down
6 changes: 3 additions & 3 deletions tests/core/controller_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import appdaemon.plugins.hass.hassapi as hass
import pytest

from core import integration as integration_module
from core.controller import Controller, action

from tests.utils import IntegrationMock, hass_mock


Expand Down Expand Up @@ -235,7 +235,7 @@ def test_get_action(sut, test_input, expected):
"entity_input, expected_calls", [("light.kitchen", 1), ("group.lights", 2),],
)
@pytest.mark.asyncio
async def test_get_attr_value(sut, mocker, monkeypatch, entity_input, expected_calls):
async def test_get_entity_state(sut, mocker, monkeypatch, entity_input, expected_calls):
stub_get_state = mocker.stub()

async def fake_get_state(entity, attribute=None):
Expand All @@ -245,7 +245,7 @@ async def fake_get_state(entity, attribute=None):
monkeypatch.setattr(sut, "get_state", fake_get_state)

# SUT
await sut.get_attr_value(entity_input, "attribute_test")
await sut.get_entity_state(entity_input, "attribute_test")

# Checks
if expected_calls == 1:
Expand Down
Empty file.
19 changes: 19 additions & 0 deletions tests/core/integration/integration_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pytest

from core import integration as integration_module
from core.controller import Controller
from tests.utils import IntegrationMock, hass_mock


@pytest.fixture
def controller(hass_mock):
c = Controller()
c.args = {}
return c


def test_get_integrations(controller):
integrations = integration_module.get_integrations(controller)
integrations.sort(key=lambda integration: integration.name)
inteagration_names = [i.name for i in integrations]
assert inteagration_names == sorted(["z2m", "zha", "deconz"])
26 changes: 13 additions & 13 deletions tests/core/type/light_controller_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ async def test_get_attribute(
attribute_expected,
throws_error,
):
async def fake_get_state(entity, attribute=None):
async def fake_get_entity_state(entity, attribute=None):
return {"attributes": set(light_attributes)}

sut.light = {"name": "light", "color_mode": color_mode}
monkeypatch.setattr(sut, "get_state", fake_get_state)
monkeypatch.setattr(sut, "get_entity_state", fake_get_entity_state)
# SUT
if throws_error:
with pytest.raises(ValueError) as e:
Expand All @@ -85,16 +85,16 @@ async def fake_get_state(entity, attribute=None):
"attribute_input, expected_output",
[
("xy_color", None),
("brightness", "return_from_fake_get_attr_value"),
("color_temp", "return_from_fake_get_attr_value"),
("brightness", "return_from_fake_get_entity_state"),
("color_temp", "return_from_fake_get_entity_state"),
],
)
@pytest.mark.asyncio
async def test_get_value_attribute(sut, monkeypatch, attribute_input, expected_output):
async def fake_get_attr_value(entity, attribute):
return "return_from_fake_get_attr_value"
async def fake_get_entity_state(entity, attribute):
return "return_from_fake_get_entity_state"

monkeypatch.setattr(sut, "get_attr_value", fake_get_attr_value)
monkeypatch.setattr(sut, "get_entity_state", fake_get_entity_state)

# SUT
output = await sut.get_value_attribute(attribute_input)
Expand Down Expand Up @@ -152,13 +152,13 @@ async def test_change_light_state(
expected_stop,
expected_value_attribute,
):
async def fake_get_state(*args, **kwargs):
async def fake_get_entity_state(*args, **kwargs):
return light_state

called_service_patch = mocker.patch.object(sut, "call_service")
sut.smooth_power_on = smooth_power_on
sut.value_attribute = old
monkeypatch.setattr(sut, "get_state", fake_get_state)
monkeypatch.setattr(sut, "get_entity_state", fake_get_entity_state)

# SUT
stop = await sut.change_light_state(old, attribute, direction, stepper)
Expand Down Expand Up @@ -231,7 +231,7 @@ async def test_click(
):
value_attribute = 10

async def fake_get_state(*args, **kwargs):
async def fake_get_entity_state(*args, **kwargs):
return light_state

async def fake_get_value_attribute(*args, **kwargs):
Expand All @@ -240,7 +240,7 @@ async def fake_get_value_attribute(*args, **kwargs):
async def fake_get_attribute(*args, **kwargs):
return attribute_input

monkeypatch.setattr(sut, "get_state", fake_get_state)
monkeypatch.setattr(sut, "get_entity_state", fake_get_entity_state)
monkeypatch.setattr(sut, "get_value_attribute", fake_get_value_attribute)
monkeypatch.setattr(sut, "get_attribute", fake_get_attribute)
change_light_state_patch = mocker.patch.object(sut, "change_light_state")
Expand Down Expand Up @@ -287,7 +287,7 @@ async def test_hold(
):
value_attribute = 10

async def fake_get_state(*args, **kwargs):
async def fake_get_entity_state(*args, **kwargs):
return light_state

async def fake_get_value_attribute(*args, **kwargs):
Expand All @@ -296,7 +296,7 @@ async def fake_get_value_attribute(*args, **kwargs):
async def fake_get_attribute(*args, **kwargs):
return attribute_input

monkeypatch.setattr(sut, "get_state", fake_get_state)
monkeypatch.setattr(sut, "get_entity_state", fake_get_entity_state)
monkeypatch.setattr(sut, "get_value_attribute", fake_get_value_attribute)
monkeypatch.setattr(sut, "get_attribute", fake_get_attribute)
sut.smooth_power_on = smooth_power_on
Expand Down
85 changes: 85 additions & 0 deletions tests/core/type/media_player_controller_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,89 @@ def sut(hass_mock):
c = MediaPlayerController()
c.args = {}
c.delay = 0
c.media_player = "test"
c.on_hold = False
return c


def test_initialize(sut, mocker):
mocker.patch.object(ReleaseHoldController, "initialize")
sut.args["media_player"] = "media_player.test"
sut.initialize()
assert sut.media_player == "media_player.test"


@pytest.mark.asyncio
async def test_play_pause(sut, mocker):
called_service_patch = mocker.patch.object(sut, "call_service")
await sut.play_pause()
called_service_patch.assert_called_once_with(
"media_player/media_play_pause", entity_id=sut.media_player
)


@pytest.mark.asyncio
async def test_previous_track(sut, mocker):
called_service_patch = mocker.patch.object(sut, "call_service")
await sut.previous_track()
called_service_patch.assert_called_once_with(
"media_player/media_previous_track", entity_id=sut.media_player
)


@pytest.mark.asyncio
async def test_next_track(sut, mocker):
called_service_patch = mocker.patch.object(sut, "call_service")
await sut.next_track()
called_service_patch.assert_called_once_with(
"media_player/media_next_track", entity_id=sut.media_player
)


@pytest.mark.asyncio
async def test_volume_up(sut, mocker):
called_service_patch = mocker.patch.object(sut, "call_service")
await sut.volume_up()
called_service_patch.assert_called_once_with(
"media_player/volume_up", entity_id=sut.media_player
)


@pytest.mark.asyncio
async def test_volume_down(sut, mocker):
called_service_patch = mocker.patch.object(sut, "call_service")
await sut.volume_down()
called_service_patch.assert_called_once_with(
"media_player/volume_down", entity_id=sut.media_player
)


@pytest.mark.asyncio
async def test_hold(sut, mocker):
direction = "test_direction"
super_hold_patch = mocker.patch.object(ReleaseHoldController, "hold")
await sut.hold(direction)
super_hold_patch.assert_called_once_with(direction)
assert sut.hold_loop_times == 0


@pytest.mark.parametrize(
"direction_input, hold_loop_times, expected_called_with, expected_output",
[
(Stepper.UP, 0, "media_player/volume_up", False),
(Stepper.DOWN, 0, "media_player/volume_down", False),
(Stepper.DOWN, 10, "media_player/volume_down", True),
],
)
@pytest.mark.asyncio
async def test_hold_loop(
sut, mocker, direction_input, hold_loop_times, expected_called_with, expected_output
):
called_service_patch = mocker.patch.object(sut, "call_service")
sut.hold_loop_times = hold_loop_times
output = await sut.hold_loop(direction_input)
called_service_patch.assert_called_once_with(
expected_called_with, entity_id=sut.media_player
)
assert sut.hold_loop_times == hold_loop_times + 1
assert output == expected_output
Loading

0 comments on commit e3c540b

Please sign in to comment.