Coverage for tests/tests_rf/test_create_stack.py: 0%

1#!/usr/bin/env python3

2"""RAMSES RF - Test the binding protocol with a virtual RF

3

4 NB: This test will likely fail with pytest -n x, because of the protocol's throttle

5 limits.

6"""

7

8 import asyncio

9 from collections.abc import Callable

10 from typing import Any

11

12 import pytest

13 import serial # type: ignore[import-untyped]

14

15 from ramses_rf import Message

16 from ramses_tx.const import SZ_ACTIVE_HGI, SZ_IS_EVOFW3, Code

17 from ramses_tx.protocol import RamsesProtocolT, create_stack, protocol_factory

18 from ramses_tx.schemas import DeviceIdT

19 from ramses_tx.transport import RamsesTransportT, transport_factory

20

21 from .virtual_rf import HgiFwTypes, VirtualRf

22

23# ######################################################################################

24

25

26 async def assert_stack_state(

27 protocol: RamsesProtocolT, transport: RamsesTransportT

28) -> None:

29 assert transport._this_pkt and transport._this_pkt.code == Code._PUZZ

30 assert transport._this_pkt and transport._this_pkt.src.id == GWY_ID

31 assert transport._prev_pkt is None

32

33 assert transport.get_extra_info(SZ_ACTIVE_HGI) == GWY_ID

34 assert transport.get_extra_info(SZ_IS_EVOFW3) is True

35

36 assert protocol._active_hgi == GWY_ID

37 assert protocol._is_evofw3 is True

38

39

40 def _msg_handler(msg: Message) -> None:

41 pass

42

43

44# ### TESTS ############################################################################

45

46

47 async def _test_create_stack(

48 rf: VirtualRf,

49 /,

50 *,

51 protocol_factory_: Callable | None = None,

52 transport_factory_: Callable | None = None,

53 disable_qos: bool | None = False,

54 disable_sending: bool | None = False,

55 enforce_include_list: bool = False,

56 exclude_list: dict[DeviceIdT, dict] | None = None,

57 include_list: dict[DeviceIdT, dict] | None = None,

58 **kwargs: Any, # TODO: these are for the transport_factory

59) -> None:

60 protocol: RamsesProtocolT

61 transport: RamsesTransportT

62

63 protocol, transport = await create_stack(

64 _msg_handler,

65 disable_qos=disable_qos,

66 disable_sending=disable_sending,

67 enforce_include_list=enforce_include_list,

68 exclude_list=exclude_list,

69 include_list=include_list,

70 **kwargs,

71 )

72

73 try:

74 await assert_stack_state(protocol, transport)

75 except serial.SerialException as err:

76 transport._close(exc=err)

77 raise

78 except (AssertionError, asyncio.InvalidStateError, TimeoutError):

79 transport.close()

80 raise

81 else:

82 transport.close()

83

84

85 async def _test_factories(

86 rf: VirtualRf,

87 /,

88 *,

89 protocol_factory_: Callable | None = None,

90 transport_factory_: Callable | None = None,

91 disable_qos: bool | None = False,

92 disable_sending: bool | None = False,

93 enforce_include_list: bool = False,

94 exclude_list: dict[DeviceIdT, dict] | None = None,

95 include_list: dict[DeviceIdT, dict] | None = None,

96 **kwargs: Any, # TODO: these are for the transport_factory

97) -> None:

98 protocol: RamsesProtocolT = protocol_factory(

99 _msg_handler,

100 disable_qos=disable_qos,

101 disable_sending=disable_sending,

102 enforce_include_list=enforce_include_list,

103 exclude_list=exclude_list,

104 include_list=include_list,

105 )

106 transport: RamsesTransportT = await transport_factory(

107 protocol,

108 disable_sending=disable_sending,

109 **kwargs,

110 )

111

112 try:

113 await assert_stack_state(protocol, transport)

114 except serial.SerialException as err:

115 transport._close(exc=err)

116 raise

117 except (AssertionError, asyncio.InvalidStateError, TimeoutError):

118 transport.close()

119 raise

120 else:

121 transport.close()

122

123

124# ######################################################################################

125

126

127 GWY_ID = "18:111111"

128 OTH_ID = "18:123456"

129

130 TEST_SUITE_GOOD = {

131 "00": {

132 "include_list": {},

133 },

134 "01": {

135 "enforce_include_list": True,

136 "include_list": {GWY_ID: {"class": "HGI"}},

137 },

138 "02": {

139 "enforce_include_list": True,

140 "include_list": {GWY_ID: {"class": "HGI"}, OTH_ID: {"class": "HGI"}},

141 },

142 "03": {

143 "enforce_include_list": True,

144 "include_list": {OTH_ID: {"class": "HGI"}, GWY_ID: {"class": "HGI"}},

145 },

146 "04": {

147 "enforce_include_list": True,

148 "include_list": {OTH_ID: {"class": "HGI"}},

149 },

150}

151 TEST_SUITE_FAIL = { # fails because exclude_list is checked before active_hgi

152 "10": {

153 "exclude_list": {GWY_ID: {"class": "HGI"}},

154 },

155 "11": {

156 "enforce_include_list": True,

157 "exclude_list": {GWY_ID: {"class": "HGI"}},

158 "include_list": {GWY_ID: {"class": "HGI"}},

159 },

160}

161

162

163@pytest.mark.xdist_group(name="virt_serial")

164@pytest.mark.parametrize("idx", TEST_SUITE_GOOD)

165 async def test_create_stack(idx: str) -> None:

166 """Check that Transport calls Protocol.connection_made() correctly."""

167

168 rf = VirtualRf(2, start=True)

169 rf.set_gateway(rf.ports[0], GWY_ID, fw_type=HgiFwTypes.EVOFW3)

170

171 kwargs = {

172 "port_name": rf.ports[0],

173 "port_config": {},

174 "extra": {"virtual_rf": rf},

175 }

176

177 try:

178 await _test_create_stack(rf, **TEST_SUITE_GOOD[idx], **kwargs)

179 finally:

180 await rf.stop()

181

182

183@pytest.mark.xdist_group(name="virt_serial")

184@pytest.mark.parametrize("idx", TEST_SUITE_GOOD)

185 async def test_create_s_alt(idx: str) -> None:

186 """Check that Transport calls Protocol.connection_made() correctly."""

187

188 rf = VirtualRf(2, start=True)

189 rf.set_gateway(rf.ports[0], GWY_ID, fw_type=HgiFwTypes.EVOFW3)

190

191 kwargs = {

192 "port_name": rf.ports[0],

193 "port_config": {},

194 "protocol_factory_": protocol_factory,

195 "transport_factory_": transport_factory,

196 "extra": {"virtual_rf": rf},

197 }

198

199 try:

200 await _test_create_stack(rf, **TEST_SUITE_GOOD[idx], **kwargs)

201 finally:

202 await rf.stop()

203

204

205@pytest.mark.xdist_group(name="virt_serial")

206@pytest.mark.parametrize("idx", TEST_SUITE_GOOD)

207 async def test_factories_01(idx: str) -> None:

208 """Check that Transport calls Protocol.connection_made() correctly.

209

210 This is the method used by ramses_tf.gateway.py.

211 """

212

213 rf = VirtualRf(2, start=True)

214 rf.set_gateway(rf.ports[0], GWY_ID, fw_type=HgiFwTypes.EVOFW3)

215

216 kwargs = {

217 "port_name": rf.ports[0],

218 "port_config": {},

219 "extra": {"virtual_rf": rf},

220 }

221

222 try:

223 await _test_factories(rf, **TEST_SUITE_GOOD[idx], **kwargs)

224 finally:

225 await rf.stop()