Convert some tests to async and drop usage get_test_home_assistant (#64394)

* Fix some tests

* Update MS tests

* Convert last logbook tests to async
This commit is contained in:
Paulus Schoutsen 2022-01-18 19:37:17 -08:00 committed by GitHub
parent 394c6850a3
commit 08083f399e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 532 additions and 610 deletions

View File

@ -951,10 +951,11 @@ async def async_handle_snapshot_service(
image = await camera.async_camera_image() image = await camera.async_camera_image()
def _write_image(to_file: str, image_data: bytes | None) -> None: if image is None:
return
def _write_image(to_file: str, image_data: bytes) -> None:
"""Executor helper to write image.""" """Executor helper to write image."""
if image_data is None:
return
os.makedirs(os.path.dirname(to_file), exist_ok=True) os.makedirs(os.path.dirname(to_file), exist_ok=True)
with open(to_file, "wb") as img_file: with open(to_file, "wb") as img_file:
img_file.write(image_data) img_file.write(image_data)

View File

@ -4,9 +4,6 @@ from unittest.mock import Mock, patch
import aprslib import aprslib
import homeassistant.components.aprs.device_tracker as device_tracker import homeassistant.components.aprs.device_tracker as device_tracker
from homeassistant.const import EVENT_HOMEASSISTANT_START
from tests.common import get_test_home_assistant
DEFAULT_PORT = 14580 DEFAULT_PORT = 14580
@ -299,14 +296,11 @@ def test_aprs_listener_rx_msg_no_position():
see.assert_not_called() see.assert_not_called()
def test_setup_scanner(): async def test_setup_scanner(hass):
"""Test setup_scanner.""" """Test setup_scanner."""
with patch( with patch(
"homeassistant.components.aprs.device_tracker.AprsListenerThread" "homeassistant.components.aprs.device_tracker.AprsListenerThread"
) as listener: ) as listener:
hass = get_test_home_assistant()
hass.start()
config = { config = {
"username": TEST_CALLSIGN, "username": TEST_CALLSIGN,
"password": TEST_PASSWORD, "password": TEST_PASSWORD,
@ -316,9 +310,9 @@ def test_setup_scanner():
} }
see = Mock() see = Mock()
res = device_tracker.setup_scanner(hass, config, see) res = await hass.async_add_executor_job(
hass.bus.fire(EVENT_HOMEASSISTANT_START) device_tracker.setup_scanner, hass, config, see
hass.stop() )
assert res assert res
listener.assert_called_with( listener.assert_called_with(
@ -326,12 +320,9 @@ def test_setup_scanner():
) )
def test_setup_scanner_timeout(): async def test_setup_scanner_timeout(hass):
"""Test setup_scanner failure from timeout.""" """Test setup_scanner failure from timeout."""
with patch("aprslib.IS.connect", side_effect=TimeoutError): with patch("aprslib.IS.connect", side_effect=TimeoutError):
hass = get_test_home_assistant()
hass.start()
config = { config = {
"username": TEST_CALLSIGN, "username": TEST_CALLSIGN,
"password": TEST_PASSWORD, "password": TEST_PASSWORD,
@ -341,5 +332,6 @@ def test_setup_scanner_timeout():
} }
see = Mock() see = Mock()
assert not device_tracker.setup_scanner(hass, config, see) assert not await hass.async_add_executor_job(
hass.stop() device_tracker.setup_scanner, hass, config, see
)

View File

@ -279,8 +279,7 @@ async def test_snapshot_service(hass, mock_camera):
mopen = mock_open() mopen = mock_open()
with patch("homeassistant.components.camera.open", mopen, create=True), patch( with patch("homeassistant.components.camera.open", mopen, create=True), patch(
"homeassistant.components.camera.os.path.exists", "homeassistant.components.camera.os.makedirs",
Mock(spec="os.path.exists", return_value=True),
), patch.object(hass.config, "is_allowed_path", return_value=True): ), patch.object(hass.config, "is_allowed_path", return_value=True):
await hass.services.async_call( await hass.services.async_call(
camera.DOMAIN, camera.DOMAIN,

View File

@ -35,37 +35,32 @@ from homeassistant.const import (
import homeassistant.core as ha import homeassistant.core as ha
from homeassistant.helpers.entityfilter import CONF_ENTITY_GLOBS from homeassistant.helpers.entityfilter import CONF_ENTITY_GLOBS
from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers.json import JSONEncoder
from homeassistant.setup import async_setup_component, setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from tests.common import get_test_home_assistant, init_recorder_component, mock_platform from tests.common import (
async_capture_events,
async_init_recorder_component,
mock_platform,
)
from tests.components.recorder.common import trigger_db_commit from tests.components.recorder.common import trigger_db_commit
EMPTY_CONFIG = logbook.CONFIG_SCHEMA({logbook.DOMAIN: {}}) EMPTY_CONFIG = logbook.CONFIG_SCHEMA({logbook.DOMAIN: {}})
@pytest.fixture @pytest.fixture
def hass_(): async def hass_(hass):
"""Set up things to be run when tests are started.""" """Set up things to be run when tests are started."""
hass = get_test_home_assistant() await async_init_recorder_component(hass) # Force an in memory DB
init_recorder_component(hass) # Force an in memory DB assert await async_setup_component(hass, logbook.DOMAIN, EMPTY_CONFIG)
with patch("homeassistant.components.http.start_http_server_and_save_config"): return hass
assert setup_component(hass, logbook.DOMAIN, EMPTY_CONFIG)
yield hass
hass.stop()
def test_service_call_create_logbook_entry(hass_): async def test_service_call_create_logbook_entry(hass_):
"""Test if service call create log book entry.""" """Test if service call create log book entry."""
calls = [] calls = async_capture_events(hass_, logbook.EVENT_LOGBOOK_ENTRY)
@ha.callback await hass_.services.async_call(
def event_listener(event):
"""Append on event."""
calls.append(event)
hass_.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener)
hass_.services.call(
logbook.DOMAIN, logbook.DOMAIN,
"log", "log",
{ {
@ -76,7 +71,7 @@ def test_service_call_create_logbook_entry(hass_):
}, },
True, True,
) )
hass_.services.call( await hass_.services.async_call(
logbook.DOMAIN, logbook.DOMAIN,
"log", "log",
{ {
@ -88,9 +83,11 @@ def test_service_call_create_logbook_entry(hass_):
# Logbook entry service call results in firing an event. # Logbook entry service call results in firing an event.
# Our service call will unblock when the event listeners have been # Our service call will unblock when the event listeners have been
# scheduled. This means that they may not have been processed yet. # scheduled. This means that they may not have been processed yet.
trigger_db_commit(hass_) await hass_.async_add_executor_job(trigger_db_commit, hass_)
hass_.block_till_done() await hass_.async_block_till_done()
hass_.data[recorder.DATA_INSTANCE].block_till_done() await hass_.async_add_executor_job(
hass_.data[recorder.DATA_INSTANCE].block_till_done
)
events = list( events = list(
logbook._get_events( logbook._get_events(
@ -116,24 +113,17 @@ def test_service_call_create_logbook_entry(hass_):
assert last_call.data.get(logbook.ATTR_DOMAIN) == "logbook" assert last_call.data.get(logbook.ATTR_DOMAIN) == "logbook"
def test_service_call_create_log_book_entry_no_message(hass_): async def test_service_call_create_log_book_entry_no_message(hass_):
"""Test if service call create log book entry without message.""" """Test if service call create log book entry without message."""
calls = [] calls = async_capture_events(hass_, logbook.EVENT_LOGBOOK_ENTRY)
@ha.callback
def event_listener(event):
"""Append on event."""
calls.append(event)
hass_.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener)
with pytest.raises(vol.Invalid): with pytest.raises(vol.Invalid):
hass_.services.call(logbook.DOMAIN, "log", {}, True) await hass_.services.async_call(logbook.DOMAIN, "log", {}, True)
# Logbook entry service call results in firing an event. # Logbook entry service call results in firing an event.
# Our service call will unblock when the event listeners have been # Our service call will unblock when the event listeners have been
# scheduled. This means that they may not have been processed yet. # scheduled. This means that they may not have been processed yet.
hass_.block_till_done() await hass_.async_block_till_done()
assert len(calls) == 0 assert len(calls) == 0
@ -310,7 +300,7 @@ def create_state_changed_event_from_old_new(
async def test_logbook_view(hass, hass_client): async def test_logbook_view(hass, hass_client):
"""Test the logbook view.""" """Test the logbook view."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await hass_client() client = await hass_client()
@ -320,7 +310,7 @@ async def test_logbook_view(hass, hass_client):
async def test_logbook_view_period_entity(hass, hass_client): async def test_logbook_view_period_entity(hass, hass_client):
"""Test the logbook view with period and entity.""" """Test the logbook view with period and entity."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -404,7 +394,7 @@ async def test_logbook_view_period_entity(hass, hass_client):
async def test_logbook_describe_event(hass, hass_client): async def test_logbook_describe_event(hass, hass_client):
"""Test teaching logbook about a new event.""" """Test teaching logbook about a new event."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
def _describe(event): def _describe(event):
"""Describe an event.""" """Describe an event."""
@ -471,7 +461,7 @@ async def test_exclude_described_event(hass, hass_client):
Mock(async_describe_events=async_describe_events), Mock(async_describe_events=async_describe_events),
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
assert await async_setup_component( assert await async_setup_component(
hass, hass,
logbook.DOMAIN, logbook.DOMAIN,
@ -515,7 +505,7 @@ async def test_exclude_described_event(hass, hass_client):
async def test_logbook_view_end_time_entity(hass, hass_client): async def test_logbook_view_end_time_entity(hass, hass_client):
"""Test the logbook view with end_time and entity.""" """Test the logbook view with end_time and entity."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -573,7 +563,7 @@ async def test_logbook_view_end_time_entity(hass, hass_client):
async def test_logbook_entity_filter_with_automations(hass, hass_client): async def test_logbook_entity_filter_with_automations(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts.""" """Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await async_setup_component(hass, "automation", {}) await async_setup_component(hass, "automation", {})
await async_setup_component(hass, "script", {}) await async_setup_component(hass, "script", {})
@ -648,7 +638,7 @@ async def test_logbook_entity_filter_with_automations(hass, hass_client):
async def test_filter_continuous_sensor_values(hass, hass_client): async def test_filter_continuous_sensor_values(hass, hass_client):
"""Test remove continuous sensor events from logbook.""" """Test remove continuous sensor events from logbook."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -684,7 +674,7 @@ async def test_filter_continuous_sensor_values(hass, hass_client):
async def test_exclude_new_entities(hass, hass_client): async def test_exclude_new_entities(hass, hass_client):
"""Test if events are excluded on first update.""" """Test if events are excluded on first update."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -719,7 +709,7 @@ async def test_exclude_new_entities(hass, hass_client):
async def test_exclude_removed_entities(hass, hass_client): async def test_exclude_removed_entities(hass, hass_client):
"""Test if events are excluded on last update.""" """Test if events are excluded on last update."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -761,7 +751,7 @@ async def test_exclude_removed_entities(hass, hass_client):
async def test_exclude_attribute_changes(hass, hass_client): async def test_exclude_attribute_changes(hass, hass_client):
"""Test if events of attribute changes are filtered.""" """Test if events of attribute changes are filtered."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -799,7 +789,7 @@ async def test_exclude_attribute_changes(hass, hass_client):
async def test_logbook_entity_context_id(hass, hass_client): async def test_logbook_entity_context_id(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts.""" """Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await async_setup_component(hass, "automation", {}) await async_setup_component(hass, "automation", {})
await async_setup_component(hass, "script", {}) await async_setup_component(hass, "script", {})
@ -951,7 +941,7 @@ async def test_logbook_entity_context_id(hass, hass_client):
async def test_logbook_entity_context_parent_id(hass, hass_client): async def test_logbook_entity_context_parent_id(hass, hass_client):
"""Test the logbook view links events via context parent_id.""" """Test the logbook view links events via context parent_id."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await async_setup_component(hass, "automation", {}) await async_setup_component(hass, "automation", {})
await async_setup_component(hass, "script", {}) await async_setup_component(hass, "script", {})
@ -1132,7 +1122,7 @@ async def test_logbook_entity_context_parent_id(hass, hass_client):
async def test_logbook_context_from_template(hass, hass_client): async def test_logbook_context_from_template(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts.""" """Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -1218,7 +1208,7 @@ async def test_logbook_context_from_template(hass, hass_client):
async def test_logbook_entity_matches_only(hass, hass_client): async def test_logbook_entity_matches_only(hass, hass_client):
"""Test the logbook view with a single entity and entity_matches_only.""" """Test the logbook view with a single entity and entity_matches_only."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -1292,7 +1282,7 @@ async def test_logbook_entity_matches_only(hass, hass_client):
async def test_custom_log_entry_discoverable_via_entity_matches_only(hass, hass_client): async def test_custom_log_entry_discoverable_via_entity_matches_only(hass, hass_client):
"""Test if a custom log entry is later discoverable via entity_matches_only.""" """Test if a custom log entry is later discoverable via entity_matches_only."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1331,7 +1321,7 @@ async def test_custom_log_entry_discoverable_via_entity_matches_only(hass, hass_
async def test_logbook_entity_matches_only_multiple(hass, hass_client): async def test_logbook_entity_matches_only_multiple(hass, hass_client):
"""Test the logbook view with a multiple entities and entity_matches_only.""" """Test the logbook view with a multiple entities and entity_matches_only."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -1415,7 +1405,7 @@ async def test_logbook_entity_matches_only_multiple(hass, hass_client):
async def test_logbook_invalid_entity(hass, hass_client): async def test_logbook_invalid_entity(hass, hass_client):
"""Test the logbook view with requesting an invalid entity.""" """Test the logbook view with requesting an invalid entity."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_block_till_done() await hass.async_block_till_done()
client = await hass_client() client = await hass_client()
@ -1434,7 +1424,7 @@ async def test_logbook_invalid_entity(hass, hass_client):
async def test_icon_and_state(hass, hass_client): async def test_icon_and_state(hass, hass_client):
"""Test to ensure state and custom icons are returned.""" """Test to ensure state and custom icons are returned."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", {}) await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1481,7 +1471,7 @@ async def test_exclude_events_domain(hass, hass_client):
logbook.DOMAIN: {CONF_EXCLUDE: {CONF_DOMAINS: ["switch", "alexa"]}}, logbook.DOMAIN: {CONF_EXCLUDE: {CONF_DOMAINS: ["switch", "alexa"]}},
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1521,7 +1511,7 @@ async def test_exclude_events_domain_glob(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1561,7 +1551,7 @@ async def test_include_events_entity(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1594,7 +1584,7 @@ async def test_exclude_events_entity(hass, hass_client):
logbook.DOMAIN: {CONF_EXCLUDE: {CONF_ENTITIES: [entity_id]}}, logbook.DOMAIN: {CONF_EXCLUDE: {CONF_ENTITIES: [entity_id]}},
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1628,7 +1618,7 @@ async def test_include_events_domain(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1672,7 +1662,7 @@ async def test_include_events_domain_glob(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1724,7 +1714,7 @@ async def test_include_exclude_events(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1778,7 +1768,7 @@ async def test_include_exclude_events_with_glob_filters(hass, hass_client):
}, },
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1821,7 +1811,7 @@ async def test_empty_config(hass, hass_client):
logbook.DOMAIN: {}, logbook.DOMAIN: {},
} }
) )
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
await async_setup_component(hass, "logbook", config) await async_setup_component(hass, "logbook", config)
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
@ -1843,7 +1833,7 @@ async def test_empty_config(hass, hass_client):
async def test_context_filter(hass, hass_client): async def test_context_filter(hass, hass_client):
"""Test we can filter by context.""" """Test we can filter by context."""
await hass.async_add_executor_job(init_recorder_component, hass) await async_init_recorder_component(hass)
assert await async_setup_component(hass, "logbook", {}) assert await async_setup_component(hass, "logbook", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done) await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)

View File

@ -2,6 +2,8 @@
import asyncio import asyncio
from unittest.mock import patch from unittest.mock import patch
import pytest
from homeassistant.components import camera, microsoft_face as mf from homeassistant.components import camera, microsoft_face as mf
from homeassistant.components.microsoft_face import ( from homeassistant.components.microsoft_face import (
ATTR_CAMERA_ENTITY, ATTR_CAMERA_ENTITY,
@ -16,9 +18,9 @@ from homeassistant.components.microsoft_face import (
SERVICE_TRAIN_GROUP, SERVICE_TRAIN_GROUP,
) )
from homeassistant.const import ATTR_NAME from homeassistant.const import ATTR_NAME
from homeassistant.setup import setup_component from homeassistant.setup import async_setup_component
from tests.common import assert_setup_component, get_test_home_assistant, load_fixture from tests.common import assert_setup_component, load_fixture
def create_group(hass, name): def create_group(hass, name):
@ -27,7 +29,7 @@ def create_group(hass, name):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_NAME: name} data = {ATTR_NAME: name}
hass.services.call(DOMAIN, SERVICE_CREATE_GROUP, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_CREATE_GROUP, data))
def delete_group(hass, name): def delete_group(hass, name):
@ -36,7 +38,7 @@ def delete_group(hass, name):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_NAME: name} data = {ATTR_NAME: name}
hass.services.call(DOMAIN, SERVICE_DELETE_GROUP, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_DELETE_GROUP, data))
def train_group(hass, group): def train_group(hass, group):
@ -45,7 +47,7 @@ def train_group(hass, group):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_GROUP: group} data = {ATTR_GROUP: group}
hass.services.call(DOMAIN, SERVICE_TRAIN_GROUP, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_TRAIN_GROUP, data))
def create_person(hass, group, name): def create_person(hass, group, name):
@ -54,7 +56,7 @@ def create_person(hass, group, name):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_GROUP: group, ATTR_NAME: name} data = {ATTR_GROUP: group, ATTR_NAME: name}
hass.services.call(DOMAIN, SERVICE_CREATE_PERSON, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_CREATE_PERSON, data))
def delete_person(hass, group, name): def delete_person(hass, group, name):
@ -63,7 +65,7 @@ def delete_person(hass, group, name):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_GROUP: group, ATTR_NAME: name} data = {ATTR_GROUP: group, ATTR_NAME: name}
hass.services.call(DOMAIN, SERVICE_DELETE_PERSON, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_DELETE_PERSON, data))
def face_person(hass, group, person, camera_entity): def face_person(hass, group, person, camera_entity):
@ -72,285 +74,254 @@ def face_person(hass, group, person, camera_entity):
This is a legacy helper method. Do not use it for new tests. This is a legacy helper method. Do not use it for new tests.
""" """
data = {ATTR_GROUP: group, ATTR_PERSON: person, ATTR_CAMERA_ENTITY: camera_entity} data = {ATTR_GROUP: group, ATTR_PERSON: person, ATTR_CAMERA_ENTITY: camera_entity}
hass.services.call(DOMAIN, SERVICE_FACE_PERSON, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_FACE_PERSON, data))
class TestMicrosoftFaceSetup: CONFIG = {mf.DOMAIN: {"api_key": "12345678abcdef"}}
"""Test the microsoft face component.""" ENDPOINT_URL = f"https://westus.{mf.FACE_API_URL}"
def setup_method(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.config = {mf.DOMAIN: {"api_key": "12345678abcdef"}} @pytest.fixture
def mock_update():
self.endpoint_url = f"https://westus.{mf.FACE_API_URL}" """Mock update store."""
with patch(
def teardown_method(self):
"""Stop everything that was started."""
self.hass.stop()
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store", "homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None, return_value=None,
) as mock_update_store:
yield mock_update_store
async def test_setup_component(hass, mock_update):
"""Set up component."""
with assert_setup_component(3, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, CONFIG)
async def test_setup_component_wrong_api_key(hass, mock_update):
"""Set up component without api key."""
with assert_setup_component(0, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, {mf.DOMAIN: {}})
async def test_setup_component_test_service(hass, mock_update):
"""Set up component."""
with assert_setup_component(3, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, CONFIG)
assert hass.services.has_service(mf.DOMAIN, "create_group")
assert hass.services.has_service(mf.DOMAIN, "delete_group")
assert hass.services.has_service(mf.DOMAIN, "train_group")
assert hass.services.has_service(mf.DOMAIN, "create_person")
assert hass.services.has_service(mf.DOMAIN, "delete_person")
assert hass.services.has_service(mf.DOMAIN, "face_person")
async def test_setup_component_test_entities(hass, aioclient_mock):
"""Set up component."""
aioclient_mock.get(
ENDPOINT_URL.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
) )
def test_setup_component(self, mock_update): aioclient_mock.get(
"""Set up component.""" ENDPOINT_URL.format("persongroups/test_group1/persons"),
with assert_setup_component(3, mf.DOMAIN): text=load_fixture("microsoft_face_persons.json"),
setup_component(self.hass, mf.DOMAIN, self.config)
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None,
) )
def test_setup_component_wrong_api_key(self, mock_update): aioclient_mock.get(
"""Set up component without api key.""" ENDPOINT_URL.format("persongroups/test_group2/persons"),
with assert_setup_component(0, mf.DOMAIN): text=load_fixture("microsoft_face_persons.json"),
setup_component(self.hass, mf.DOMAIN, {mf.DOMAIN: {}})
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None,
) )
def test_setup_component_test_service(self, mock_update):
"""Set up component."""
with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config)
assert self.hass.services.has_service(mf.DOMAIN, "create_group") with assert_setup_component(3, mf.DOMAIN):
assert self.hass.services.has_service(mf.DOMAIN, "delete_group") await async_setup_component(hass, mf.DOMAIN, CONFIG)
assert self.hass.services.has_service(mf.DOMAIN, "train_group")
assert self.hass.services.has_service(mf.DOMAIN, "create_person")
assert self.hass.services.has_service(mf.DOMAIN, "delete_person")
assert self.hass.services.has_service(mf.DOMAIN, "face_person")
def test_setup_component_test_entities(self, aioclient_mock): assert len(aioclient_mock.mock_calls) == 3
"""Set up component."""
aioclient_mock.get(
self.endpoint_url.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
with assert_setup_component(3, mf.DOMAIN): entity_group1 = hass.states.get("microsoft_face.test_group1")
setup_component(self.hass, mf.DOMAIN, self.config) entity_group2 = hass.states.get("microsoft_face.test_group2")
assert len(aioclient_mock.mock_calls) == 3 assert entity_group1 is not None
assert entity_group2 is not None
entity_group1 = self.hass.states.get("microsoft_face.test_group1") assert entity_group1.attributes["Ryan"] == "25985303-c537-4467-b41d-bdb45cd95ca1"
entity_group2 = self.hass.states.get("microsoft_face.test_group2") assert entity_group1.attributes["David"] == "2ae4935b-9659-44c3-977f-61fac20d0538"
assert entity_group1 is not None assert entity_group2.attributes["Ryan"] == "25985303-c537-4467-b41d-bdb45cd95ca1"
assert entity_group2 is not None assert entity_group2.attributes["David"] == "2ae4935b-9659-44c3-977f-61fac20d0538"
assert (
entity_group1.attributes["Ryan"] == "25985303-c537-4467-b41d-bdb45cd95ca1"
)
assert (
entity_group1.attributes["David"] == "2ae4935b-9659-44c3-977f-61fac20d0538"
)
assert ( async def test_service_groups(hass, mock_update, aioclient_mock):
entity_group2.attributes["Ryan"] == "25985303-c537-4467-b41d-bdb45cd95ca1" """Set up component, test groups services."""
) aioclient_mock.put(
assert ( ENDPOINT_URL.format("persongroups/service_group"),
entity_group2.attributes["David"] == "2ae4935b-9659-44c3-977f-61fac20d0538" status=200,
) text="{}",
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None,
) )
def test_service_groups(self, mock_update, aioclient_mock): aioclient_mock.delete(
"""Set up component, test groups services.""" ENDPOINT_URL.format("persongroups/service_group"),
aioclient_mock.put( status=200,
self.endpoint_url.format("persongroups/service_group"), text="{}",
status=200,
text="{}",
)
aioclient_mock.delete(
self.endpoint_url.format("persongroups/service_group"),
status=200,
text="{}",
)
with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config)
create_group(self.hass, "Service Group")
self.hass.block_till_done()
entity = self.hass.states.get("microsoft_face.service_group")
assert entity is not None
assert len(aioclient_mock.mock_calls) == 1
delete_group(self.hass, "Service Group")
self.hass.block_till_done()
entity = self.hass.states.get("microsoft_face.service_group")
assert entity is None
assert len(aioclient_mock.mock_calls) == 2
def test_service_person(self, aioclient_mock):
"""Set up component, test person services."""
aioclient_mock.get(
self.endpoint_url.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config)
assert len(aioclient_mock.mock_calls) == 3
aioclient_mock.post(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_create_person.json"),
)
aioclient_mock.delete(
self.endpoint_url.format(
"persongroups/test_group1/persons/"
"25985303-c537-4467-b41d-bdb45cd95ca1"
),
status=200,
text="{}",
)
create_person(self.hass, "test group1", "Hans")
self.hass.block_till_done()
entity_group1 = self.hass.states.get("microsoft_face.test_group1")
assert len(aioclient_mock.mock_calls) == 4
assert entity_group1 is not None
assert (
entity_group1.attributes["Hans"] == "25985303-c537-4467-b41d-bdb45cd95ca1"
)
delete_person(self.hass, "test group1", "Hans")
self.hass.block_till_done()
entity_group1 = self.hass.states.get("microsoft_face.test_group1")
assert len(aioclient_mock.mock_calls) == 5
assert entity_group1 is not None
assert "Hans" not in entity_group1.attributes
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None,
) )
def test_service_train(self, mock_update, aioclient_mock):
"""Set up component, test train groups services."""
with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config)
aioclient_mock.post( with assert_setup_component(3, mf.DOMAIN):
self.endpoint_url.format("persongroups/service_group/train"), await async_setup_component(hass, mf.DOMAIN, CONFIG)
status=200,
text="{}",
)
train_group(self.hass, "Service Group") create_group(hass, "Service Group")
self.hass.block_till_done() await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 1 entity = hass.states.get("microsoft_face.service_group")
assert entity is not None
assert len(aioclient_mock.mock_calls) == 1
@patch( delete_group(hass, "Service Group")
await hass.async_block_till_done()
entity = hass.states.get("microsoft_face.service_group")
assert entity is None
assert len(aioclient_mock.mock_calls) == 2
async def test_service_person(hass, aioclient_mock):
"""Set up component, test person services."""
aioclient_mock.get(
ENDPOINT_URL.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
with assert_setup_component(3, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, CONFIG)
assert len(aioclient_mock.mock_calls) == 3
aioclient_mock.post(
ENDPOINT_URL.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_create_person.json"),
)
aioclient_mock.delete(
ENDPOINT_URL.format(
"persongroups/test_group1/persons/" "25985303-c537-4467-b41d-bdb45cd95ca1"
),
status=200,
text="{}",
)
create_person(hass, "test group1", "Hans")
await hass.async_block_till_done()
entity_group1 = hass.states.get("microsoft_face.test_group1")
assert len(aioclient_mock.mock_calls) == 4
assert entity_group1 is not None
assert entity_group1.attributes["Hans"] == "25985303-c537-4467-b41d-bdb45cd95ca1"
delete_person(hass, "test group1", "Hans")
await hass.async_block_till_done()
entity_group1 = hass.states.get("microsoft_face.test_group1")
assert len(aioclient_mock.mock_calls) == 5
assert entity_group1 is not None
assert "Hans" not in entity_group1.attributes
async def test_service_train(hass, mock_update, aioclient_mock):
"""Set up component, test train groups services."""
with assert_setup_component(3, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, CONFIG)
aioclient_mock.post(
ENDPOINT_URL.format("persongroups/service_group/train"),
status=200,
text="{}",
)
train_group(hass, "Service Group")
await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 1
async def test_service_face(hass, aioclient_mock):
"""Set up component, test person face services."""
aioclient_mock.get(
ENDPOINT_URL.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
CONFIG["camera"] = {"platform": "demo"}
with assert_setup_component(3, mf.DOMAIN):
await async_setup_component(hass, mf.DOMAIN, CONFIG)
assert len(aioclient_mock.mock_calls) == 3
aioclient_mock.post(
ENDPOINT_URL.format(
"persongroups/test_group2/persons/"
"2ae4935b-9659-44c3-977f-61fac20d0538/persistedFaces"
),
status=200,
text="{}",
)
with patch(
"homeassistant.components.camera.async_get_image", "homeassistant.components.camera.async_get_image",
return_value=camera.Image("image/jpeg", b"Test"), return_value=camera.Image("image/jpeg", b"Test"),
):
face_person(hass, "test_group2", "David", "camera.demo_camera")
await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 4
assert aioclient_mock.mock_calls[3][2] == b"Test"
async def test_service_status_400(hass, mock_update, aioclient_mock):
"""Set up component, test groups services with error."""
aioclient_mock.put(
ENDPOINT_URL.format("persongroups/service_group"),
status=400,
text="{'error': {'message': 'Error'}}",
) )
def test_service_face(self, camera_mock, aioclient_mock):
"""Set up component, test person face services."""
aioclient_mock.get(
self.endpoint_url.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
self.config["camera"] = {"platform": "demo"} with assert_setup_component(3, mf.DOMAIN):
with assert_setup_component(3, mf.DOMAIN): await async_setup_component(hass, mf.DOMAIN, CONFIG)
setup_component(self.hass, mf.DOMAIN, self.config)
assert len(aioclient_mock.mock_calls) == 3 create_group(hass, "Service Group")
await hass.async_block_till_done()
aioclient_mock.post( entity = hass.states.get("microsoft_face.service_group")
self.endpoint_url.format( assert entity is None
"persongroups/test_group2/persons/" assert len(aioclient_mock.mock_calls) == 1
"2ae4935b-9659-44c3-977f-61fac20d0538/persistedFaces"
),
status=200,
text="{}",
)
face_person(self.hass, "test_group2", "David", "camera.demo_camera")
self.hass.block_till_done()
assert len(aioclient_mock.mock_calls) == 4 async def test_service_status_timeout(hass, mock_update, aioclient_mock):
assert aioclient_mock.mock_calls[3][2] == b"Test" """Set up component, test groups services with timeout."""
aioclient_mock.put(
@patch( ENDPOINT_URL.format("persongroups/service_group"),
"homeassistant.components.microsoft_face.MicrosoftFace.update_store", status=400,
return_value=None, exc=asyncio.TimeoutError(),
) )
def test_service_status_400(self, mock_update, aioclient_mock):
"""Set up component, test groups services with error."""
aioclient_mock.put(
self.endpoint_url.format("persongroups/service_group"),
status=400,
text="{'error': {'message': 'Error'}}",
)
with assert_setup_component(3, mf.DOMAIN): with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config) await async_setup_component(hass, mf.DOMAIN, CONFIG)
create_group(self.hass, "Service Group") create_group(hass, "Service Group")
self.hass.block_till_done() await hass.async_block_till_done()
entity = self.hass.states.get("microsoft_face.service_group") entity = hass.states.get("microsoft_face.service_group")
assert entity is None assert entity is None
assert len(aioclient_mock.mock_calls) == 1 assert len(aioclient_mock.mock_calls) == 1
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=None,
)
def test_service_status_timeout(self, mock_update, aioclient_mock):
"""Set up component, test groups services with timeout."""
aioclient_mock.put(
self.endpoint_url.format("persongroups/service_group"),
status=400,
exc=asyncio.TimeoutError(),
)
with assert_setup_component(3, mf.DOMAIN):
setup_component(self.hass, mf.DOMAIN, self.config)
create_group(self.hass, "Service Group")
self.hass.block_till_done()
entity = self.hass.states.get("microsoft_face.service_group")
assert entity is None
assert len(aioclient_mock.mock_calls) == 1

View File

@ -1,171 +1,155 @@
"""The tests for the microsoft face detect platform.""" """The tests for the microsoft face detect platform."""
from unittest.mock import PropertyMock, patch from unittest.mock import PropertyMock, patch
import pytest
import homeassistant.components.image_processing as ip import homeassistant.components.image_processing as ip
import homeassistant.components.microsoft_face as mf import homeassistant.components.microsoft_face as mf
from homeassistant.const import ATTR_ENTITY_PICTURE from homeassistant.const import ATTR_ENTITY_PICTURE
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.setup import setup_component from homeassistant.setup import async_setup_component
from tests.common import ( from tests.common import assert_setup_component, load_fixture
assert_setup_component,
get_test_home_assistant,
load_fixture,
mock_coro,
)
from tests.components.image_processing import common from tests.components.image_processing import common
CONFIG = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"attributes": ["age", "gender"],
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
class TestMicrosoftFaceDetectSetup: ENDPOINT_URL = f"https://westus.{mf.FACE_API_URL}"
"""Test class for image processing."""
def setup_method(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
def teardown_method(self): @pytest.fixture
"""Stop everything that was started.""" def store_mock():
self.hass.stop() """Mock update store."""
with patch(
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store", "homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=mock_coro(), return_value=None,
) ) as mock_update_store:
def test_setup_platform(self, store_mock): yield mock_update_store
"""Set up platform with one entity."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera"},
"attributes": ["age", "gender"],
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
setup_component(self.hass, ip.DOMAIN, config)
self.hass.block_till_done()
assert self.hass.states.get("image_processing.microsoftface_demo_camera")
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=mock_coro(),
)
def test_setup_platform_name(self, store_mock):
"""Set up platform with one entity and set name."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
setup_component(self.hass, ip.DOMAIN, config)
self.hass.block_till_done()
assert self.hass.states.get("image_processing.test_local")
class TestMicrosoftFaceDetect: @pytest.fixture
"""Test class for image processing.""" def poll_mock():
"""Disable polling."""
def setup_method(self): with patch(
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.config = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"attributes": ["age", "gender"],
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
self.endpoint_url = f"https://westus.{mf.FACE_API_URL}"
def teardown_method(self):
"""Stop everything that was started."""
self.hass.stop()
@patch(
"homeassistant.components.microsoft_face_detect.image_processing." "homeassistant.components.microsoft_face_detect.image_processing."
"MicrosoftFaceDetectEntity.should_poll", "MicrosoftFaceDetectEntity.should_poll",
new_callable=PropertyMock(return_value=False), new_callable=PropertyMock(return_value=False),
):
yield
async def test_setup_platform(hass, store_mock):
"""Set up platform with one entity."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera"},
"attributes": ["age", "gender"],
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
await async_setup_component(hass, ip.DOMAIN, config)
await hass.async_block_till_done()
assert hass.states.get("image_processing.microsoftface_demo_camera")
async def test_setup_platform_name(hass, store_mock):
"""Set up platform with one entity and set name."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_detect",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
await async_setup_component(hass, ip.DOMAIN, config)
await hass.async_block_till_done()
assert hass.states.get("image_processing.test_local")
async def test_ms_detect_process_image(hass, poll_mock, aioclient_mock):
"""Set up and scan a picture and test plates from event."""
aioclient_mock.get(
ENDPOINT_URL.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
) )
def test_ms_detect_process_image(self, poll_mock, aioclient_mock):
"""Set up and scan a picture and test plates from event."""
aioclient_mock.get(
self.endpoint_url.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
setup_component(self.hass, ip.DOMAIN, self.config) await async_setup_component(hass, ip.DOMAIN, CONFIG)
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("camera.demo_camera") state = hass.states.get("camera.demo_camera")
url = f"{self.hass.config.internal_url}{state.attributes.get(ATTR_ENTITY_PICTURE)}" url = f"{hass.config.internal_url}{state.attributes.get(ATTR_ENTITY_PICTURE)}"
face_events = [] face_events = []
@callback @callback
def mock_face_event(event): def mock_face_event(event):
"""Mock event.""" """Mock event."""
face_events.append(event) face_events.append(event)
self.hass.bus.listen("image_processing.detect_face", mock_face_event) hass.bus.async_listen("image_processing.detect_face", mock_face_event)
aioclient_mock.get(url, content=b"image") aioclient_mock.get(url, content=b"image")
aioclient_mock.post( aioclient_mock.post(
self.endpoint_url.format("detect"), ENDPOINT_URL.format("detect"),
text=load_fixture("microsoft_face_detect.json"), text=load_fixture("microsoft_face_detect.json"),
params={"returnFaceAttributes": "age,gender"}, params={"returnFaceAttributes": "age,gender"},
) )
common.scan(self.hass, entity_id="image_processing.test_local") common.async_scan(hass, entity_id="image_processing.test_local")
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("image_processing.test_local") state = hass.states.get("image_processing.test_local")
assert len(face_events) == 1 assert len(face_events) == 1
assert state.attributes.get("total_faces") == 1 assert state.attributes.get("total_faces") == 1
assert state.state == "1" assert state.state == "1"
assert face_events[0].data["age"] == 71.0 assert face_events[0].data["age"] == 71.0
assert face_events[0].data["gender"] == "male" assert face_events[0].data["gender"] == "male"
assert face_events[0].data["entity_id"] == "image_processing.test_local" assert face_events[0].data["entity_id"] == "image_processing.test_local"
# Test that later, if a request is made that results in no face # Test that later, if a request is made that results in no face
# being detected, that this is reflected in the state object # being detected, that this is reflected in the state object
aioclient_mock.clear_requests() aioclient_mock.clear_requests()
aioclient_mock.post( aioclient_mock.post(
self.endpoint_url.format("detect"), ENDPOINT_URL.format("detect"),
text="[]", text="[]",
params={"returnFaceAttributes": "age,gender"}, params={"returnFaceAttributes": "age,gender"},
) )
common.scan(self.hass, entity_id="image_processing.test_local") common.async_scan(hass, entity_id="image_processing.test_local")
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("image_processing.test_local") state = hass.states.get("image_processing.test_local")
# No more face events were fired # No more face events were fired
assert len(face_events) == 1 assert len(face_events) == 1
# Total faces and actual qualified number of faces reset to zero # Total faces and actual qualified number of faces reset to zero
assert state.attributes.get("total_faces") == 0 assert state.attributes.get("total_faces") == 0
assert state.state == "0" assert state.state == "0"

View File

@ -1,171 +1,156 @@
"""The tests for the microsoft face identify platform.""" """The tests for the microsoft face identify platform."""
from unittest.mock import PropertyMock, patch from unittest.mock import PropertyMock, patch
import pytest
import homeassistant.components.image_processing as ip import homeassistant.components.image_processing as ip
import homeassistant.components.microsoft_face as mf import homeassistant.components.microsoft_face as mf
from homeassistant.const import ATTR_ENTITY_PICTURE, STATE_UNKNOWN from homeassistant.const import ATTR_ENTITY_PICTURE, STATE_UNKNOWN
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.setup import setup_component from homeassistant.setup import async_setup_component
from tests.common import ( from tests.common import assert_setup_component, load_fixture
assert_setup_component,
get_test_home_assistant,
load_fixture,
mock_coro,
)
from tests.components.image_processing import common from tests.components.image_processing import common
class TestMicrosoftFaceIdentifySetup: @pytest.fixture
"""Test class for image processing.""" def store_mock():
"""Mock update store."""
def setup_method(self): with patch(
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
def teardown_method(self):
"""Stop everything that was started."""
self.hass.stop()
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store", "homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=mock_coro(), return_value=None,
) ) as mock_update_store:
def test_setup_platform(self, store_mock): yield mock_update_store
"""Set up platform with one entity."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
setup_component(self.hass, ip.DOMAIN, config)
self.hass.block_till_done()
assert self.hass.states.get("image_processing.microsoftface_demo_camera")
@patch(
"homeassistant.components.microsoft_face.MicrosoftFace.update_store",
return_value=mock_coro(),
)
def test_setup_platform_name(self, store_mock):
"""Set up platform with one entity and set name."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
setup_component(self.hass, ip.DOMAIN, config)
self.hass.block_till_done()
assert self.hass.states.get("image_processing.test_local")
class TestMicrosoftFaceIdentify: @pytest.fixture
"""Test class for image processing.""" def poll_mock():
"""Disable polling."""
def setup_method(self): with patch(
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.config = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
self.endpoint_url = f"https://westus.{mf.FACE_API_URL}"
def teardown_method(self):
"""Stop everything that was started."""
self.hass.stop()
@patch(
"homeassistant.components.microsoft_face_identify.image_processing." "homeassistant.components.microsoft_face_identify.image_processing."
"MicrosoftFaceIdentifyEntity.should_poll", "MicrosoftFaceIdentifyEntity.should_poll",
new_callable=PropertyMock(return_value=False), new_callable=PropertyMock(return_value=False),
):
yield
CONFIG = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
ENDPOINT_URL = f"https://westus.{mf.FACE_API_URL}"
async def test_setup_platform(hass, store_mock):
"""Set up platform with one entity."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
await async_setup_component(hass, ip.DOMAIN, config)
await hass.async_block_till_done()
assert hass.states.get("image_processing.microsoftface_demo_camera")
async def test_setup_platform_name(hass, store_mock):
"""Set up platform with one entity and set name."""
config = {
ip.DOMAIN: {
"platform": "microsoft_face_identify",
"source": {"entity_id": "camera.demo_camera", "name": "test local"},
"group": "Test Group1",
},
"camera": {"platform": "demo"},
mf.DOMAIN: {"api_key": "12345678abcdef6"},
}
with assert_setup_component(1, ip.DOMAIN):
await async_setup_component(hass, ip.DOMAIN, config)
await hass.async_block_till_done()
assert hass.states.get("image_processing.test_local")
async def test_ms_identify_process_image(hass, poll_mock, aioclient_mock):
"""Set up and scan a picture and test plates from event."""
aioclient_mock.get(
ENDPOINT_URL.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
ENDPOINT_URL.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
) )
def test_ms_identify_process_image(self, poll_mock, aioclient_mock):
"""Set up and scan a picture and test plates from event."""
aioclient_mock.get(
self.endpoint_url.format("persongroups"),
text=load_fixture("microsoft_face_persongroups.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group1/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
aioclient_mock.get(
self.endpoint_url.format("persongroups/test_group2/persons"),
text=load_fixture("microsoft_face_persons.json"),
)
setup_component(self.hass, ip.DOMAIN, self.config) await async_setup_component(hass, ip.DOMAIN, CONFIG)
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("camera.demo_camera") state = hass.states.get("camera.demo_camera")
url = f"{self.hass.config.internal_url}{state.attributes.get(ATTR_ENTITY_PICTURE)}" url = f"{hass.config.internal_url}{state.attributes.get(ATTR_ENTITY_PICTURE)}"
face_events = [] face_events = []
@callback @callback
def mock_face_event(event): def mock_face_event(event):
"""Mock event.""" """Mock event."""
face_events.append(event) face_events.append(event)
self.hass.bus.listen("image_processing.detect_face", mock_face_event) hass.bus.async_listen("image_processing.detect_face", mock_face_event)
aioclient_mock.get(url, content=b"image") aioclient_mock.get(url, content=b"image")
aioclient_mock.post( aioclient_mock.post(
self.endpoint_url.format("detect"), ENDPOINT_URL.format("detect"),
text=load_fixture("microsoft_face_detect.json"), text=load_fixture("microsoft_face_detect.json"),
) )
aioclient_mock.post( aioclient_mock.post(
self.endpoint_url.format("identify"), ENDPOINT_URL.format("identify"),
text=load_fixture("microsoft_face_identify.json"), text=load_fixture("microsoft_face_identify.json"),
) )
common.scan(self.hass, entity_id="image_processing.test_local") common.async_scan(hass, entity_id="image_processing.test_local")
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("image_processing.test_local") state = hass.states.get("image_processing.test_local")
assert len(face_events) == 1 assert len(face_events) == 1
assert state.attributes.get("total_faces") == 2 assert state.attributes.get("total_faces") == 2
assert state.state == "David" assert state.state == "David"
assert face_events[0].data["name"] == "David" assert face_events[0].data["name"] == "David"
assert face_events[0].data["confidence"] == float(92) assert face_events[0].data["confidence"] == float(92)
assert face_events[0].data["entity_id"] == "image_processing.test_local" assert face_events[0].data["entity_id"] == "image_processing.test_local"
# Test that later, if a request is made that results in no face # Test that later, if a request is made that results in no face
# being detected, that this is reflected in the state object # being detected, that this is reflected in the state object
aioclient_mock.clear_requests() aioclient_mock.clear_requests()
aioclient_mock.post(self.endpoint_url.format("detect"), text="[]") aioclient_mock.post(ENDPOINT_URL.format("detect"), text="[]")
common.scan(self.hass, entity_id="image_processing.test_local") common.async_scan(hass, entity_id="image_processing.test_local")
self.hass.block_till_done() await hass.async_block_till_done()
state = self.hass.states.get("image_processing.test_local") state = hass.states.get("image_processing.test_local")
# No more face events were fired # No more face events were fired
assert len(face_events) == 1 assert len(face_events) == 1
# Total faces and actual qualified number of faces reset to zero # Total faces and actual qualified number of faces reset to zero
assert state.attributes.get("total_faces") == 0 assert state.attributes.get("total_faces") == 0
assert state.state == STATE_UNKNOWN assert state.state == STATE_UNKNOWN