Skip to content

Commit 868246c

Browse files
committed
added tests for apps, modules and importing
1 parent 125bd84 commit 868246c

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

tests/test_apps_modules.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""Test the pyscript apps, modules and import features."""
2+
3+
from ast import literal_eval
4+
import asyncio
5+
import re
6+
7+
from custom_components.pyscript.const import DOMAIN, FOLDER
8+
from mock_open import MockOpen
9+
from pytest_homeassistant_custom_component.async_mock import patch
10+
11+
from homeassistant.const import EVENT_STATE_CHANGED
12+
from homeassistant.setup import async_setup_component
13+
14+
15+
async def wait_until_done(notify_q):
16+
"""Wait for the done handshake."""
17+
return await asyncio.wait_for(notify_q.get(), timeout=4)
18+
19+
20+
async def test_service_exists(hass, caplog):
21+
"""Test importing a pyscript module."""
22+
23+
conf_dir = hass.config.path(FOLDER)
24+
25+
file_contents = {
26+
f"{conf_dir}/hello.py": """
27+
import xyz2
28+
from xyz2 import f_minus
29+
30+
@service
31+
def func1():
32+
pyscript.done = [xyz2.f_add(1, 2), xyz2.f_mult(3, 4), xyz2.f_add(10, 20), f_minus(50, 20)]
33+
""",
34+
#
35+
# this will fail to load since import doesn't exist
36+
#
37+
f"{conf_dir}/bad_import.py": """
38+
import no_such_package
39+
40+
@service
41+
def func10():
42+
pass
43+
""",
44+
#
45+
# this will fail to load since import has a syntax error
46+
#
47+
f"{conf_dir}/bad_import2.py": """
48+
import bad_module
49+
50+
@service
51+
def func11():
52+
pass
53+
""",
54+
#
55+
# This will load, since there is an apps/world config entry
56+
#
57+
f"{conf_dir}/apps/world.py": """
58+
from xyz2 import *
59+
60+
@service
61+
def func2():
62+
pyscript.done = [get_x(), get_name(), other_name(), f_add(1, 5), f_mult(3, 6), f_add(10, 30), f_minus(50, 30)]
63+
""",
64+
#
65+
# This will not load, since there is no apps/world2 config entry
66+
#
67+
f"{conf_dir}/apps/world2.py": """
68+
from xyz2 import *
69+
70+
@service
71+
def func10():
72+
pass
73+
""",
74+
f"{conf_dir}/modules/xyz2/__init__.py": """
75+
from .other import f_minus, other_name
76+
77+
x = 99
78+
79+
def f_add(a, b):
80+
return a + b
81+
82+
def f_mult(a, b):
83+
return a * b
84+
85+
def get_x():
86+
return x
87+
88+
def get_name():
89+
return __name__
90+
""",
91+
f"{conf_dir}/modules/xyz2/other.py": """
92+
def f_minus(a, b):
93+
return a - b
94+
95+
def other_name():
96+
return __name__
97+
""",
98+
#
99+
# this module has a syntax error (missing :)
100+
#
101+
f"{conf_dir}/modules/bad_module.py": """
102+
def func12()
103+
pass
104+
""",
105+
}
106+
107+
mock_open = MockOpen()
108+
for key, value in file_contents.items():
109+
mock_open[key].read_data = value
110+
111+
def isfile_side_effect(arg):
112+
return arg in file_contents
113+
114+
def glob_side_effect(path, recursive=None):
115+
result = []
116+
path_re = path.replace("*", "[^/]*").replace(".", "\\.")
117+
for this_path in file_contents:
118+
if re.match(path_re, this_path):
119+
result.append(this_path)
120+
print(f"glob_side_effect: path={path}, path_re={path_re}, result={result}")
121+
return result
122+
123+
with patch("custom_components.pyscript.os.path.isdir", return_value=True), patch(
124+
"custom_components.pyscript.glob.iglob"
125+
) as mock_glob, patch("builtins.open", mock_open), patch(
126+
"homeassistant.config.load_yaml_config_file", return_value={}
127+
), patch(
128+
"os.path.isfile"
129+
) as mock_isfile:
130+
mock_isfile.side_effect = isfile_side_effect
131+
mock_glob.side_effect = glob_side_effect
132+
conf = {"apps": {"world": {}}}
133+
assert await async_setup_component(hass, "pyscript", {DOMAIN: conf})
134+
135+
notify_q = asyncio.Queue(0)
136+
137+
async def state_changed(event):
138+
var_name = event.data["entity_id"]
139+
if var_name != "pyscript.done":
140+
return
141+
value = event.data["new_state"].state
142+
await notify_q.put(value)
143+
144+
hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)
145+
146+
assert not hass.services.has_service("pyscript", "func10")
147+
assert not hass.services.has_service("pyscript", "func11")
148+
assert not hass.services.has_service("pyscript", "func12")
149+
150+
await hass.services.async_call("pyscript", "func1", {})
151+
ret = await wait_until_done(notify_q)
152+
assert literal_eval(ret) == [1 + 2, 3 * 4, 10 + 20, 50 - 20]
153+
154+
await hass.services.async_call("pyscript", "func2", {})
155+
ret = await wait_until_done(notify_q)
156+
assert literal_eval(ret) == [99, "xyz2", "xyz2.other", 1 + 5, 3 * 6, 10 + 30, 50 - 30]
157+
158+
assert "ModuleNotFoundError: import of no_such_package not allowed" in caplog.text
159+
assert "SyntaxError: invalid syntax (bad_module.py, line 2)" in caplog.text

0 commit comments

Comments
 (0)