test_config_flow.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. """Tests for the config flow."""
  2. from unittest.mock import ANY, AsyncMock, MagicMock, patch
  3. import pytest
  4. import voluptuous as vol
  5. from homeassistant.const import CONF_HOST, CONF_NAME
  6. from homeassistant.data_entry_flow import FlowResultType
  7. from pytest_homeassistant_custom_component.common import MockConfigEntry
  8. from custom_components.tuya_local import (
  9. async_migrate_entry,
  10. config_flow,
  11. )
  12. from custom_components.tuya_local.const import (
  13. CONF_DEVICE_CID,
  14. CONF_DEVICE_ID,
  15. CONF_LOCAL_KEY,
  16. CONF_POLL_ONLY,
  17. CONF_PROTOCOL_VERSION,
  18. CONF_TYPE,
  19. DOMAIN,
  20. )
  21. @pytest.fixture(autouse=True)
  22. def auto_enable_custom_integrations(enable_custom_integrations):
  23. yield
  24. @pytest.fixture(autouse=True)
  25. def prevent_task_creation():
  26. with patch(
  27. "custom_components.tuya_local.device.TuyaLocalDevice.register_entity",
  28. ):
  29. yield
  30. @pytest.fixture
  31. def bypass_setup():
  32. """Prevent actual setup of the integration after config flow."""
  33. with patch(
  34. "custom_components.tuya_local.async_setup_entry",
  35. return_value=True,
  36. ):
  37. yield
  38. @pytest.mark.asyncio
  39. async def test_init_entry(hass):
  40. """Test initialisation of the config flow."""
  41. entry = MockConfigEntry(
  42. domain=DOMAIN,
  43. version=11,
  44. title="test",
  45. data={
  46. CONF_DEVICE_ID: "deviceid",
  47. CONF_HOST: "hostname",
  48. CONF_LOCAL_KEY: "localkey",
  49. CONF_POLL_ONLY: False,
  50. CONF_PROTOCOL_VERSION: "auto",
  51. CONF_TYPE: "kogan_kahtp_heater",
  52. CONF_DEVICE_CID: None,
  53. },
  54. options={},
  55. )
  56. entry.add_to_hass(hass)
  57. await hass.config_entries.async_setup(entry.entry_id)
  58. await hass.async_block_till_done()
  59. assert hass.states.get("climate.test")
  60. assert hass.states.get("lock.test_child_lock")
  61. @pytest.mark.asyncio
  62. @patch("custom_components.tuya_local.setup_device")
  63. async def test_migrate_entry(mock_setup, hass):
  64. """Test migration from old entry format."""
  65. mock_device = MagicMock()
  66. mock_device.async_inferred_type = AsyncMock(return_value="goldair_gpph_heater")
  67. mock_setup.return_value = mock_device
  68. entry = MockConfigEntry(
  69. domain=DOMAIN,
  70. version=1,
  71. title="test",
  72. data={
  73. CONF_DEVICE_ID: "deviceid",
  74. CONF_HOST: "hostname",
  75. CONF_LOCAL_KEY: "localkey",
  76. CONF_TYPE: "auto",
  77. "climate": True,
  78. "child_lock": True,
  79. "display_light": True,
  80. },
  81. )
  82. entry.add_to_hass(hass)
  83. assert await async_migrate_entry(hass, entry)
  84. mock_device.async_inferred_type = AsyncMock(return_value=None)
  85. mock_device.reset_mock()
  86. entry = MockConfigEntry(
  87. domain=DOMAIN,
  88. version=1,
  89. title="test2",
  90. data={
  91. CONF_DEVICE_ID: "deviceid",
  92. CONF_HOST: "hostname",
  93. CONF_LOCAL_KEY: "localkey",
  94. CONF_TYPE: "unknown",
  95. "climate": False,
  96. },
  97. )
  98. entry.add_to_hass(hass)
  99. assert not await async_migrate_entry(hass, entry)
  100. mock_device.reset_mock()
  101. entry = MockConfigEntry(
  102. domain=DOMAIN,
  103. version=2,
  104. title="test3",
  105. data={
  106. CONF_DEVICE_ID: "deviceid",
  107. CONF_HOST: "hostname",
  108. CONF_LOCAL_KEY: "localkey",
  109. CONF_TYPE: "auto",
  110. },
  111. options={
  112. "climate": False,
  113. },
  114. )
  115. entry.add_to_hass(hass)
  116. assert not await async_migrate_entry(hass, entry)
  117. mock_device.async_inferred_type = AsyncMock(return_value="smartplugv1")
  118. mock_device.reset_mock()
  119. entry = MockConfigEntry(
  120. domain=DOMAIN,
  121. version=3,
  122. title="test4",
  123. data={
  124. CONF_DEVICE_ID: "deviceid",
  125. CONF_HOST: "hostname",
  126. CONF_LOCAL_KEY: "localkey",
  127. CONF_TYPE: "smartplugv1",
  128. },
  129. options={
  130. "switch": True,
  131. },
  132. )
  133. entry.add_to_hass(hass)
  134. assert await async_migrate_entry(hass, entry)
  135. mock_device.async_inferred_type = AsyncMock(return_value="smartplugv2")
  136. mock_device.reset_mock()
  137. entry = MockConfigEntry(
  138. domain=DOMAIN,
  139. version=3,
  140. title="test5",
  141. data={
  142. CONF_DEVICE_ID: "deviceid",
  143. CONF_HOST: "hostname",
  144. CONF_LOCAL_KEY: "localkey",
  145. CONF_TYPE: "smartplugv1",
  146. },
  147. options={
  148. "switch": True,
  149. },
  150. )
  151. entry.add_to_hass(hass)
  152. assert await async_migrate_entry(hass, entry)
  153. mock_device.async_inferred_type = AsyncMock(return_value="goldair_dehumidifier")
  154. mock_device.reset_mock()
  155. entry = MockConfigEntry(
  156. domain=DOMAIN,
  157. version=4,
  158. title="test6",
  159. data={
  160. CONF_DEVICE_ID: "deviceid",
  161. CONF_HOST: "hostname",
  162. CONF_LOCAL_KEY: "localkey",
  163. CONF_TYPE: "goldair_dehumidifier",
  164. },
  165. options={
  166. "humidifier": True,
  167. "fan": True,
  168. "light": True,
  169. "lock": False,
  170. "switch": True,
  171. },
  172. )
  173. entry.add_to_hass(hass)
  174. assert await async_migrate_entry(hass, entry)
  175. mock_device.async_inferred_type = AsyncMock(
  176. return_value="grid_connect_usb_double_power_point"
  177. )
  178. mock_device.reset_mock()
  179. entry = MockConfigEntry(
  180. domain=DOMAIN,
  181. version=6,
  182. title="test7",
  183. data={
  184. CONF_DEVICE_ID: "deviceid",
  185. CONF_HOST: "hostname",
  186. CONF_LOCAL_KEY: "localkey",
  187. CONF_TYPE: "grid_connect_usb_double_power_point",
  188. },
  189. options={
  190. "switch_main_switch": True,
  191. "switch_left_outlet": True,
  192. "switch_right_outlet": True,
  193. },
  194. )
  195. entry.add_to_hass(hass)
  196. assert await async_migrate_entry(hass, entry)
  197. @pytest.mark.asyncio
  198. async def test_flow_user_init(hass):
  199. """Test the initialisation of the form in the first page of the manual config flow path."""
  200. result = await hass.config_entries.flow.async_init(
  201. DOMAIN, context={"source": "local"}
  202. )
  203. expected = {
  204. "data_schema": ANY,
  205. "description_placeholders": None,
  206. "errors": {},
  207. "flow_id": ANY,
  208. "handler": DOMAIN,
  209. "step_id": "local",
  210. "type": "form",
  211. "last_step": ANY,
  212. "preview": ANY,
  213. }
  214. assert expected == result
  215. # Check the schema. Simple comparison does not work since they are not
  216. # the same object
  217. try:
  218. result["data_schema"](
  219. {CONF_DEVICE_ID: "test", CONF_LOCAL_KEY: "test", CONF_HOST: "test"}
  220. )
  221. except vol.MultipleInvalid:
  222. assert False
  223. try:
  224. result["data_schema"]({CONF_DEVICE_ID: "missing_some"})
  225. assert False
  226. except vol.MultipleInvalid:
  227. pass
  228. @pytest.mark.asyncio
  229. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  230. async def test_async_test_connection_valid(mock_device, hass):
  231. """Test that device is returned when connection is valid."""
  232. mock_instance = AsyncMock()
  233. mock_instance.has_returned_state = True
  234. mock_instance.pause = MagicMock()
  235. mock_instance.resume = MagicMock()
  236. mock_device.return_value = mock_instance
  237. hass.data[DOMAIN] = {"deviceid": {"device": mock_instance}}
  238. device = await config_flow.async_test_connection(
  239. {
  240. CONF_DEVICE_ID: "deviceid",
  241. CONF_LOCAL_KEY: "localkey",
  242. CONF_HOST: "hostname",
  243. CONF_PROTOCOL_VERSION: "auto",
  244. },
  245. hass,
  246. )
  247. assert device == mock_instance
  248. mock_instance.pause.assert_called_once()
  249. mock_instance.resume.assert_called_once()
  250. @pytest.mark.asyncio
  251. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  252. async def test_async_test_connection_for_subdevice_valid(mock_device, hass):
  253. """Test that subdevice is returned when connection is valid."""
  254. mock_instance = AsyncMock()
  255. mock_instance.has_returned_state = True
  256. mock_instance.pause = MagicMock()
  257. mock_instance.resume = MagicMock()
  258. mock_device.return_value = mock_instance
  259. hass.data[DOMAIN] = {"subdeviceid": {"device": mock_instance}}
  260. device = await config_flow.async_test_connection(
  261. {
  262. CONF_DEVICE_ID: "deviceid",
  263. CONF_LOCAL_KEY: "localkey",
  264. CONF_HOST: "hostname",
  265. CONF_PROTOCOL_VERSION: "auto",
  266. CONF_DEVICE_CID: "subdeviceid",
  267. },
  268. hass,
  269. )
  270. assert device == mock_instance
  271. mock_instance.pause.assert_called_once()
  272. mock_instance.resume.assert_called_once()
  273. @pytest.mark.asyncio
  274. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  275. async def test_async_test_connection_invalid(mock_device, hass):
  276. """Test that None is returned when connection is invalid."""
  277. mock_instance = AsyncMock()
  278. mock_instance.has_returned_state = False
  279. mock_device.return_value = mock_instance
  280. device = await config_flow.async_test_connection(
  281. {
  282. CONF_DEVICE_ID: "deviceid",
  283. CONF_LOCAL_KEY: "localkey",
  284. CONF_HOST: "hostname",
  285. CONF_PROTOCOL_VERSION: "auto",
  286. },
  287. hass,
  288. )
  289. assert device is None
  290. @pytest.mark.asyncio
  291. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  292. async def test_flow_user_init_invalid_config(mock_test, hass):
  293. """Test errors populated when config is invalid."""
  294. mock_test.return_value = None
  295. flow = await hass.config_entries.flow.async_init(
  296. DOMAIN, context={"source": "local"}
  297. )
  298. result = await hass.config_entries.flow.async_configure(
  299. flow["flow_id"],
  300. user_input={
  301. CONF_DEVICE_ID: "deviceid",
  302. CONF_HOST: "hostname",
  303. CONF_LOCAL_KEY: "badkey",
  304. CONF_PROTOCOL_VERSION: "auto",
  305. CONF_POLL_ONLY: False,
  306. },
  307. )
  308. assert {"base": "connection"} == result["errors"]
  309. def setup_device_mock(mock, failure=False, type="test"):
  310. mock_type = MagicMock()
  311. mock_type.legacy_type = type
  312. mock_type.config_type = type
  313. mock_type.match_quality.return_value = 100
  314. mock_iter = MagicMock()
  315. mock_iter.__aiter__.return_value = [mock_type] if not failure else []
  316. mock.async_possible_types = MagicMock(return_value=mock_iter)
  317. @pytest.mark.asyncio
  318. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  319. async def test_flow_user_init_data_valid(mock_test, hass):
  320. """Test we advance to the next step when connection config is valid."""
  321. mock_device = MagicMock()
  322. setup_device_mock(mock_device)
  323. mock_test.return_value = mock_device
  324. flow = await hass.config_entries.flow.async_init(
  325. DOMAIN, context={"source": "local"}
  326. )
  327. result = await hass.config_entries.flow.async_configure(
  328. flow["flow_id"],
  329. user_input={
  330. CONF_DEVICE_ID: "deviceid",
  331. CONF_HOST: "hostname",
  332. CONF_LOCAL_KEY: "localkey",
  333. },
  334. )
  335. assert "form" == result["type"]
  336. assert "select_type" == result["step_id"]
  337. @pytest.mark.asyncio
  338. @patch.object(config_flow.ConfigFlowHandler, "device")
  339. async def test_flow_select_type_init(mock_device, hass):
  340. """Test the initialisation of the form in the 2nd step of the config flow."""
  341. setup_device_mock(mock_device)
  342. result = await hass.config_entries.flow.async_init(
  343. DOMAIN, context={"source": "select_type"}
  344. )
  345. expected = {
  346. "data_schema": ANY,
  347. "description_placeholders": None,
  348. "errors": None,
  349. "flow_id": ANY,
  350. "handler": DOMAIN,
  351. "step_id": "select_type",
  352. "type": "form",
  353. "last_step": ANY,
  354. "preview": ANY,
  355. }
  356. assert expected == result
  357. # Check the schema. Simple comparison does not work since they are not
  358. # the same object
  359. try:
  360. result["data_schema"]({CONF_TYPE: "test"})
  361. except vol.MultipleInvalid:
  362. assert False
  363. try:
  364. result["data_schema"]({CONF_TYPE: "not_test"})
  365. assert False
  366. except vol.MultipleInvalid:
  367. pass
  368. @pytest.mark.asyncio
  369. @patch.object(config_flow.ConfigFlowHandler, "device")
  370. async def test_flow_select_type_aborts_when_no_match(mock_device, hass):
  371. """Test the flow aborts when an unsupported device is used."""
  372. setup_device_mock(mock_device, failure=True)
  373. result = await hass.config_entries.flow.async_init(
  374. DOMAIN, context={"source": "select_type"}
  375. )
  376. assert result["type"] == "abort"
  377. assert result["reason"] == "not_supported"
  378. @pytest.mark.asyncio
  379. @patch.object(config_flow.ConfigFlowHandler, "device")
  380. async def test_flow_select_type_data_valid(mock_device, hass):
  381. """Test the flow continues when valid data is supplied."""
  382. setup_device_mock(mock_device, type="smartplugv1")
  383. flow = await hass.config_entries.flow.async_init(
  384. DOMAIN, context={"source": "select_type"}
  385. )
  386. result = await hass.config_entries.flow.async_configure(
  387. flow["flow_id"],
  388. user_input={CONF_TYPE: "smartplugv1"},
  389. )
  390. assert "form" == result["type"]
  391. assert "choose_entities" == result["step_id"]
  392. @pytest.mark.asyncio
  393. async def test_flow_choose_entities_init(hass):
  394. """Test the initialisation of the form in the 3rd step of the config flow."""
  395. with patch.dict(config_flow.ConfigFlowHandler.data, {CONF_TYPE: "smartplugv1"}):
  396. result = await hass.config_entries.flow.async_init(
  397. DOMAIN, context={"source": "choose_entities"}
  398. )
  399. expected = {
  400. "data_schema": ANY,
  401. "description_placeholders": None,
  402. "errors": None,
  403. "flow_id": ANY,
  404. "handler": DOMAIN,
  405. "step_id": "choose_entities",
  406. "type": "form",
  407. "last_step": ANY,
  408. "preview": ANY,
  409. }
  410. assert expected == result
  411. # Check the schema. Simple comparison does not work since they are not
  412. # the same object
  413. try:
  414. result["data_schema"]({CONF_NAME: "test"})
  415. except vol.MultipleInvalid:
  416. assert False
  417. try:
  418. result["data_schema"]({"climate": True})
  419. assert False
  420. except vol.MultipleInvalid:
  421. pass
  422. @pytest.mark.asyncio
  423. async def test_flow_choose_entities_creates_config_entry(hass, bypass_setup):
  424. """Test the flow ends when data is valid."""
  425. with patch.dict(
  426. config_flow.ConfigFlowHandler.data,
  427. {
  428. CONF_DEVICE_ID: "deviceid",
  429. CONF_LOCAL_KEY: "localkey",
  430. CONF_HOST: "hostname",
  431. CONF_POLL_ONLY: False,
  432. CONF_PROTOCOL_VERSION: "auto",
  433. CONF_TYPE: "kogan_kahtp_heater",
  434. CONF_DEVICE_CID: None,
  435. },
  436. ):
  437. flow = await hass.config_entries.flow.async_init(
  438. DOMAIN, context={"source": "choose_entities"}
  439. )
  440. result = await hass.config_entries.flow.async_configure(
  441. flow["flow_id"],
  442. user_input={
  443. CONF_NAME: "test",
  444. },
  445. )
  446. expected = {
  447. "version": 13,
  448. "minor_version": ANY,
  449. "context": {"source": "choose_entities"},
  450. "type": FlowResultType.CREATE_ENTRY,
  451. "flow_id": ANY,
  452. "handler": DOMAIN,
  453. "title": "test",
  454. "description": None,
  455. "description_placeholders": None,
  456. "result": ANY,
  457. "options": {},
  458. "data": {
  459. CONF_DEVICE_ID: "deviceid",
  460. CONF_HOST: "hostname",
  461. CONF_LOCAL_KEY: "localkey",
  462. CONF_POLL_ONLY: False,
  463. CONF_PROTOCOL_VERSION: "auto",
  464. CONF_TYPE: "kogan_kahtp_heater",
  465. CONF_DEVICE_CID: None,
  466. },
  467. }
  468. assert expected == result
  469. @pytest.mark.asyncio
  470. async def test_options_flow_init(hass):
  471. """Test config flow options."""
  472. config_entry = MockConfigEntry(
  473. domain=DOMAIN,
  474. version=13,
  475. unique_id="uniqueid",
  476. data={
  477. CONF_DEVICE_ID: "deviceid",
  478. CONF_HOST: "hostname",
  479. CONF_LOCAL_KEY: "localkey",
  480. CONF_NAME: "test",
  481. CONF_POLL_ONLY: False,
  482. CONF_PROTOCOL_VERSION: "auto",
  483. CONF_TYPE: "smartplugv1",
  484. CONF_DEVICE_CID: "",
  485. },
  486. )
  487. config_entry.add_to_hass(hass)
  488. assert await hass.config_entries.async_setup(config_entry.entry_id)
  489. await hass.async_block_till_done()
  490. # show initial form
  491. result = await hass.config_entries.options.async_init(config_entry.entry_id)
  492. assert "form" == result["type"]
  493. assert "user" == result["step_id"]
  494. assert {} == result["errors"]
  495. assert result["data_schema"](
  496. {
  497. CONF_HOST: "hostname",
  498. CONF_LOCAL_KEY: "localkey",
  499. }
  500. )
  501. @pytest.mark.asyncio
  502. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  503. async def test_options_flow_modifies_config(mock_test, hass, bypass_setup):
  504. mock_device = MagicMock()
  505. mock_test.return_value = mock_device
  506. config_entry = MockConfigEntry(
  507. domain=DOMAIN,
  508. version=13,
  509. unique_id="uniqueid",
  510. data={
  511. CONF_DEVICE_ID: "deviceid",
  512. CONF_HOST: "hostname",
  513. CONF_LOCAL_KEY: "localkey",
  514. CONF_NAME: "test",
  515. CONF_POLL_ONLY: False,
  516. CONF_PROTOCOL_VERSION: "auto",
  517. CONF_TYPE: "ble_pt216_temp_humidity",
  518. CONF_DEVICE_CID: "subdeviceid",
  519. },
  520. )
  521. config_entry.add_to_hass(hass)
  522. assert await hass.config_entries.async_setup(config_entry.entry_id)
  523. await hass.async_block_till_done()
  524. # show initial form
  525. form = await hass.config_entries.options.async_init(config_entry.entry_id)
  526. # submit updated config
  527. result = await hass.config_entries.options.async_configure(
  528. form["flow_id"],
  529. user_input={
  530. CONF_HOST: "new_hostname",
  531. CONF_LOCAL_KEY: "new_key",
  532. CONF_POLL_ONLY: False,
  533. CONF_PROTOCOL_VERSION: 3.3,
  534. CONF_DEVICE_CID: "subdeviceid",
  535. },
  536. )
  537. expected = {
  538. CONF_HOST: "new_hostname",
  539. CONF_LOCAL_KEY: "new_key",
  540. CONF_POLL_ONLY: False,
  541. CONF_PROTOCOL_VERSION: 3.3,
  542. CONF_DEVICE_CID: "subdeviceid",
  543. }
  544. assert "create_entry" == result["type"]
  545. assert "" == result["title"]
  546. assert result["result"] is True
  547. assert expected == result["data"]
  548. @pytest.mark.asyncio
  549. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  550. async def test_options_flow_fails_when_connection_fails(mock_test, hass):
  551. mock_test.return_value = None
  552. config_entry = MockConfigEntry(
  553. domain=DOMAIN,
  554. version=13,
  555. unique_id="uniqueid",
  556. data={
  557. CONF_DEVICE_ID: "deviceid",
  558. CONF_HOST: "hostname",
  559. CONF_LOCAL_KEY: "localkey",
  560. CONF_NAME: "test",
  561. CONF_POLL_ONLY: False,
  562. CONF_PROTOCOL_VERSION: "auto",
  563. CONF_TYPE: "smartplugv1",
  564. CONF_DEVICE_CID: "",
  565. },
  566. )
  567. config_entry.add_to_hass(hass)
  568. assert await hass.config_entries.async_setup(config_entry.entry_id)
  569. await hass.async_block_till_done()
  570. # show initial form
  571. form = await hass.config_entries.options.async_init(config_entry.entry_id)
  572. # submit updated config
  573. result = await hass.config_entries.options.async_configure(
  574. form["flow_id"],
  575. user_input={
  576. CONF_HOST: "new_hostname",
  577. CONF_LOCAL_KEY: "new_key",
  578. },
  579. )
  580. assert "form" == result["type"]
  581. assert "user" == result["step_id"]
  582. assert {"base": "connection"} == result["errors"]
  583. @pytest.mark.asyncio
  584. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  585. async def test_options_flow_fails_when_config_is_missing(mock_test, hass):
  586. mock_device = MagicMock()
  587. mock_test.return_value = mock_device
  588. config_entry = MockConfigEntry(
  589. domain=DOMAIN,
  590. version=13,
  591. unique_id="uniqueid",
  592. data={
  593. CONF_DEVICE_ID: "deviceid",
  594. CONF_HOST: "hostname",
  595. CONF_LOCAL_KEY: "localkey",
  596. CONF_NAME: "test",
  597. CONF_POLL_ONLY: False,
  598. CONF_PROTOCOL_VERSION: "auto",
  599. CONF_TYPE: "non_existing",
  600. },
  601. )
  602. config_entry.add_to_hass(hass)
  603. await hass.config_entries.async_setup(config_entry.entry_id)
  604. await hass.async_block_till_done()
  605. # show initial form
  606. result = await hass.config_entries.options.async_init(config_entry.entry_id)
  607. assert result["type"] == "abort"
  608. assert result["reason"] == "not_supported"