blob: 9082dace7629db431827847c0e0b05aa4de39d12 [file] [log] [blame]
Wei-Yu Chenad55cb82022-02-15 20:07:01 +08001# SPDX-FileCopyrightText: 2020 The Magma Authors.
2# SPDX-FileCopyrightText: 2022 Open Networking Foundation <support@opennetworking.org>
3#
4# SPDX-License-Identifier: BSD-3-Clause
Wei-Yu Chen49950b92021-11-08 19:19:18 +08005
6# pylint: disable=protected-access
7from unittest import TestCase
8
9from state_machines.enb_acs_manager import StateMachineManager
10from tests.test_utils.enb_acs_builder import (
11 EnodebAcsStateMachineBuilder,
12)
13from tests.test_utils.spyne_builder import (
14 get_spyne_context_with_ip,
15)
16from tests.test_utils.tr069_msg_builder import Tr069MessageBuilder
17from tr069 import models
18
19
20class StateMachineManagerTests(TestCase):
21 def test_handle_one_ip(self):
22 manager = self._get_manager()
23
24 # Send in an Inform message, and we should get an InformResponse
25 ctx = get_spyne_context_with_ip()
26 inform = Tr069MessageBuilder.get_inform()
27 req = manager.handle_tr069_message(ctx, inform)
28 self.assertTrue(
29 isinstance(req, models.InformResponse),
30 'State machine handler should reply with an '
31 'InformResponse',
32 )
33
34 def test_serial_not_found(self):
35 """
36 Test that the SM manager doesn't crash if serial number is not found
37 in an Inform message under any expected param path.
38 """
39 manager = self._get_manager()
40 ctx = get_spyne_context_with_ip("192.168.60.145")
41 inform_msg = models.Inform(
42 DeviceId=models.DeviceIdStruct(
43 Manufacturer='Unused',
44 OUI='48BF74',
45 ProductClass='Unused',
46 ),
47 Event=models.EventList(EventStruct=[]),
48 ParameterList=models.ParameterValueList(
49 ParameterValueStruct=[
50 Tr069MessageBuilder.get_parameter_value_struct(
51 name='Device.DeviceInfo.HardwareVersion',
52 val_type='string',
53 data='VER.C',
54 ),
55 Tr069MessageBuilder.get_parameter_value_struct(
56 name='Device.DeviceInfo.ManufacturerOUI',
57 val_type='string',
58 data='48BF74',
59 ),
60 Tr069MessageBuilder.get_parameter_value_struct(
61 name='Device.DeviceInfo.SoftwareVersion',
62 val_type='string',
63 data='BaiBS_RTS_3.1.6',
64 ),
65 ],
66 ),
67 )
68
69 # No exception should be thrown, and we should return an empty response
70 resp = manager.handle_tr069_message(ctx, inform_msg)
71 self.assertTrue(isinstance(resp, models.DummyInput))
72
73 def test_handle_two_ips(self):
74 manager = self._get_manager()
75 ctx1 = get_spyne_context_with_ip("192.168.60.145")
76 ctx2 = get_spyne_context_with_ip("192.168.60.99")
77
78 ##### Start session for the first IP #####
79 # Send an Inform message, wait for an InformResponse
80 inform_msg = Tr069MessageBuilder.get_inform(
81 '48BF74',
82 'BaiBS_RTS_3.1.6',
83 '120200002618AGP0001',
84 )
85 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
86 self.assertTrue(
87 isinstance(resp1, models.InformResponse),
88 'Should respond with an InformResponse',
89 )
90
91 # Send an empty http request to kick off the rest of provisioning
92 req1 = models.DummyInput()
93 resp1 = manager.handle_tr069_message(ctx1, req1)
94
95 # Expect a request for an optional parameter, three times
96 self.assertTrue(
97 isinstance(resp1, models.GetParameterValues),
98 'State machine should be requesting param values',
99 )
100 req1 = Tr069MessageBuilder.get_fault()
101 resp1 = manager.handle_tr069_message(ctx1, req1)
102 self.assertTrue(
103 isinstance(resp1, models.GetParameterValues),
104 'State machine should be requesting param values',
105 )
106
107 ##### Start session for the second IP #####
108 # Send an Inform message, wait for an InformResponse
109 inform_msg = Tr069MessageBuilder.get_inform(
110 '48BF74',
111 'BaiBS_RTS_3.1.6',
112 '120200002618AGP0002',
113 )
114 resp2 = manager.handle_tr069_message(ctx2, inform_msg)
115 self.assertTrue(
116 isinstance(resp2, models.InformResponse),
117 'Should respond with an InformResponse',
118 )
119
120 ##### Continue session for the first IP #####
121 req1 = Tr069MessageBuilder.get_fault()
122 resp1 = manager.handle_tr069_message(ctx1, req1)
123 self.assertTrue(
124 isinstance(resp1, models.GetParameterValues),
125 'State machine should be requesting param values',
126 )
127 req1 = Tr069MessageBuilder.get_fault()
128 resp1 = manager.handle_tr069_message(ctx1, req1)
129 # Expect a request for read-only params
130 self.assertTrue(
131 isinstance(resp1, models.GetParameterValues),
132 'State machine should be requesting param values',
133 )
134
135 ##### Continue session for the second IP #####
136 # Send an empty http request to kick off the rest of provisioning
137 req2 = models.DummyInput()
138 resp2 = manager.handle_tr069_message(ctx2, req2)
139 # Expect a request for an optional parameter, three times
140 self.assertTrue(
141 isinstance(resp2, models.GetParameterValues),
142 'State machine should be requesting param values',
143 )
144 req2 = Tr069MessageBuilder.get_fault()
145 resp2 = manager.handle_tr069_message(ctx2, req2)
146 self.assertTrue(
147 isinstance(resp2, models.GetParameterValues),
148 'State machine should be requesting param values',
149 )
150 req2 = Tr069MessageBuilder.get_fault()
151 resp2 = manager.handle_tr069_message(ctx2, req2)
152 self.assertTrue(
153 isinstance(resp2, models.GetParameterValues),
154 'State machine should be requesting param values',
155 )
156 req2 = Tr069MessageBuilder.get_fault()
157 resp2 = manager.handle_tr069_message(ctx2, req2)
158 # Expect a request for read-only params
159 self.assertTrue(
160 isinstance(resp2, models.GetParameterValues),
161 'State machine should be requesting param values',
162 )
163
164 def test_handle_registered_enb(self):
165 """
166 When we have a config with eNB registered per serial, we should accept
167 TR-069 sessions from any registered eNB, and ereject from unregistered
168 eNB devices.
169 """
170 manager = self._get_manager_multi_enb()
171 ip1 = "192.168.60.145"
172 ctx1 = get_spyne_context_with_ip(ip1)
173 inform_msg = Tr069MessageBuilder.get_inform(
174 '48BF74',
175 'BaiBS_RTS_3.1.6',
176 '120200002618AGP0003',
177 )
178 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
179 self.assertTrue(
180 isinstance(resp1, models.InformResponse),
181 'Should respond with an InformResponse',
182 )
183
184 ip2 = "192.168.60.146"
185 ctx2 = get_spyne_context_with_ip(ip2)
186 inform_msg = Tr069MessageBuilder.get_inform(
187 '48BF74',
188 'BaiBS_RTS_3.1.6',
189 'unregistered_serial',
190 )
191
192 resp2 = manager.handle_tr069_message(ctx2, inform_msg)
193 self.assertTrue(
194 isinstance(resp2, models.DummyInput),
195 'Should respond with an empty HTTP response',
196 )
197
198 def test_ip_change(self) -> None:
199 manager = self._get_manager()
200
201 # Send an Inform
202 ip1 = "192.168.60.145"
203 ctx1 = get_spyne_context_with_ip(ip1)
204 inform_msg = Tr069MessageBuilder.get_inform(
205 '48BF74',
206 'BaiBS_RTS_3.1.6',
207 '120200002618AGP0003',
208 )
209 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
210 self.assertTrue(
211 isinstance(resp1, models.InformResponse),
212 'Should respond with an InformResponse',
213 )
214 handler1 = manager.get_handler_by_ip(ip1)
215
216 # Send an Inform from the same serial, but different IP
217 ip2 = "192.168.60.99"
218 ctx2 = get_spyne_context_with_ip(ip2)
219 inform_msg = Tr069MessageBuilder.get_inform(
220 '48BF74',
221 'BaiBS_RTS_3.1.6',
222 '120200002618AGP0003',
223 )
224 resp2 = manager.handle_tr069_message(ctx2, inform_msg)
225 self.assertTrue(
226 isinstance(resp2, models.InformResponse),
227 'Should respond with an InformResponse',
228 )
229 handler2 = manager.get_handler_by_ip(ip2)
230
231 # Now check that the serial is associated with the second ip
232 self.assertTrue(
233 (handler1 is handler2),
234 'After an IP switch, the manager should have moved '
235 'the handler to a new IP',
236 )
237
238 def test_serial_change(self) -> None:
239 manager = self._get_manager()
240 ip = "192.168.60.145"
241
242 # Send an Inform
243 ctx1 = get_spyne_context_with_ip(ip)
244 inform_msg = Tr069MessageBuilder.get_inform(
245 '48BF74',
246 'BaiBS_RTS_3.1.6',
247 '120200002618AGP0001',
248 )
249 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
250 self.assertTrue(
251 isinstance(resp1, models.InformResponse),
252 'Should respond with an InformResponse',
253 )
254 handler1 = manager.get_handler_by_ip(ip)
255
256 # Send an Inform from the same serial, but different IP
257 ctx2 = get_spyne_context_with_ip(ip)
258 inform_msg = Tr069MessageBuilder.get_inform(
259 '48BF74',
260 'BaiBS_RTS_3.1.6',
261 '120200002618AGP0002',
262 )
263 resp2 = manager.handle_tr069_message(ctx2, inform_msg)
264 self.assertTrue(
265 isinstance(resp2, models.InformResponse),
266 'Should respond with an InformResponse',
267 )
268 handler2 = manager.get_handler_by_ip(ip)
269
270 # Now check that the serial is associated with the second ip
271 self.assertTrue(
272 (handler1 is not handler2),
273 'After an IP switch, the manager should have moved '
274 'the handler to a new IP',
275 )
276
277 def test_inform_from_baicells_qafb(self) -> None:
278 manager = self._get_manager()
279 ip = "192.168.60.145"
280
281 # Send an Inform
282 ctx1 = get_spyne_context_with_ip(ip)
283 inform_msg = Tr069MessageBuilder.get_qafb_inform(
284 '48BF74',
285 'BaiBS_QAFB_v1234',
286 '120200002618AGP0001',
287 )
288 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
289 self.assertTrue(
290 isinstance(resp1, models.InformResponse),
291 'Should respond with an InformResponse',
292 )
293
294 def test_inform_from_unrecognized(self) -> None:
295 manager = self._get_manager()
296 ip = "192.168.60.145"
297
298 # Send an Inform
299 ctx1 = get_spyne_context_with_ip(ip)
300 inform_msg = Tr069MessageBuilder.get_qafb_inform(
301 '48BF74',
302 'Unrecognized device',
303 '120200002618AGP0001',
304 )
305 resp1 = manager.handle_tr069_message(ctx1, inform_msg)
306 self.assertTrue(
307 isinstance(resp1, models.DummyInput),
308 'Should end provisioninng session with empty response',
309 )
310
311 def _get_manager(self) -> StateMachineManager:
312 service = EnodebAcsStateMachineBuilder.build_magma_service()
313 return StateMachineManager(service)
314
315 def _get_manager_multi_enb(self) -> StateMachineManager:
316 service = EnodebAcsStateMachineBuilder.build_multi_enb_magma_service()
317 return StateMachineManager(service)