blob: 105813f1aea7600d32279489fd539f70d05ec96e [file] [log] [blame]
Chip Boling67b674a2019-02-08 11:42:18 -06001#
2# Copyright 2018 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
Zack Williams84a71e92019-11-15 09:00:19 -070016from __future__ import absolute_import
Chip Boling67b674a2019-02-08 11:42:18 -060017from unittest import TestCase, main
18from nose.tools import assert_raises
19from nose.twistedtools import deferred
20from copy import deepcopy
Zack Williams84a71e92019-11-15 09:00:19 -070021from .mock.mock_adapter_agent import MockAdapterAgent, MockCore
22from .mock.mock_onu_handler import MockOnuHandler
23from .mock.mock_olt_handler import MockOltHandler
24from .mock.mock_onu import MockOnu
Chip Boling67b674a2019-02-08 11:42:18 -060025from pyvoltha.adapters.extensions.omci.openomci_agent import OpenOMCIAgent, OpenOmciAgentDefaults
26from pyvoltha.adapters.extensions.omci.omci_defs import *
27from pyvoltha.common.utils.asleep import asleep
28from pyvoltha.adapters.extensions.omci.database.mib_db_api import DEVICE_ID_KEY, CLASS_ID_KEY, CREATED_KEY, \
29 MODIFIED_KEY, MDS_KEY, LAST_SYNC_KEY, VERSION_KEY, DatabaseStateError
30from pyvoltha.adapters.extensions.omci.database.mib_db_dict import MibDbVolatileDict
Zack Williams84a71e92019-11-15 09:00:19 -070031from six.moves import range
Chip Boling67b674a2019-02-08 11:42:18 -060032
33
34DEFAULT_OLT_DEVICE_ID = 'default_olt_mock'
35DEFAULT_ONU_DEVICE_ID = 'default_onu_mock'
36DEFAULT_PON_ID = 0
37DEFAULT_ONU_ID = 0
38DEFAULT_ONU_SN = 'TEST00000001'
39
40OP = EntityOperations
41RC = ReasonCodes
42
43
44def chunk(indexable, chunk_size):
45 for i in range(0, len(indexable), chunk_size):
46 yield indexable[i:i + chunk_size]
47
48
49def hex2raw(hex_string):
50 return ''.join(chr(int(byte, 16)) for byte in chunk(hex_string, 2))
51
52
53class TestOnuDeviceEntry(TestCase):
54 """
55 Test the ONU Device Entry methods
56 """
57 def setUp(self):
58 self.adapter_agent = MockAdapterAgent()
59
60 custom = deepcopy(OpenOmciAgentDefaults)
61 custom['mib-synchronizer']['database'] = MibDbVolatileDict
62
63 self.agent = OpenOMCIAgent(MockCore, support_classes=custom)
64 self.agent.start()
65
66 def tearDown(self):
67 if self.agent is not None:
68 self.agent.stop()
69
70 if self.adapter_agent is not None:
71 self.adapter_agent.tearDown()
72
73 def setup_mock_olt(self, device_id=DEFAULT_OLT_DEVICE_ID):
74 handler = MockOltHandler(self.adapter_agent, device_id)
75 self.adapter_agent.add_device(handler.device)
76 return handler
77
78 def setup_mock_onu(self, parent_id=DEFAULT_OLT_DEVICE_ID,
79 device_id=DEFAULT_ONU_DEVICE_ID,
80 pon_id=DEFAULT_PON_ID,
81 onu_id=DEFAULT_ONU_ID,
82 serial_no=DEFAULT_ONU_SN):
83 handler = MockOnuHandler(self.adapter_agent, parent_id, device_id, pon_id, onu_id)
84 handler.serial_number = serial_no
85 onu = MockOnu(serial_no, self.adapter_agent, handler.device_id) \
86 if serial_no is not None else None
87 handler.onu_mock = onu
88 return handler
89
90 def setup_one_of_each(self):
91 # Most tests will use at lease one or more OLT and ONU
92 self.olt_handler = self.setup_mock_olt()
93 self.onu_handler = self.setup_mock_onu(parent_id=self.olt_handler.device_id)
94 self.onu_device = self.onu_handler.onu_mock
95
96 self.adapter_agent.add_child_device(self.olt_handler.device,
97 self.onu_handler.device)
98
99 def test_add_remove_device(self):
100 self.setup_one_of_each()
101 self.assertEqual(len(self.agent.device_ids()), 0)
102
103 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
104 self.adapter_agent)
105 self.assertIsNotNone(onu_device)
106 self.assertEqual(len(self.agent.device_ids()), 1)
107 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
108
109 # No MIB if not started
110 assert_raises(KeyError, onu_device.query_mib)
111
112 self.agent.remove_device(DEFAULT_ONU_DEVICE_ID)
113 self.assertEqual(len(self.agent.device_ids()), 1)
114
115 def test_delete_device(self):
116 self.setup_one_of_each()
117 self.assertEqual(len(self.agent.device_ids()), 0)
118
119 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
120 self.adapter_agent)
121 self.assertIsNotNone(onu_device)
122 self.assertEqual(len(self.agent.device_ids()), 1)
123 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
124 # Can delete if it was not started
125 onu_device.delete()
126 self.assertEqual(len(self.agent.device_ids()), 0)
127
128 ##########################################
129 # Delete of ONU device okay if it is started
130 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
131 self.adapter_agent)
132 self.assertIsNotNone(onu_device)
133 self.assertEqual(len(self.agent.device_ids()), 1)
134 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
135
136 # Start it and then delete it
137 onu_device.start()
138 onu_device.delete()
139 self.assertEqual(len(self.agent.device_ids()), 0)
140
141 @deferred(timeout=5)
142 def test_mib_query_fails_if_dev_not_started(self):
143 self.setup_one_of_each()
144
145 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
146 self.adapter_agent)
147 self.assertIsNotNone(onu_device)
148 self.assertEqual(len(self.agent.device_ids()), 1)
149 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
150
151 def not_called(_reason):
152 assert False, 'Should never be called'
153
154 def check_status(_results):
155 # Device not yet started. Query should fail with KeyError since
156 # ONU is not in database yet
157 assert_raises(KeyError, onu_device.query_mib)
158
159 # Yield context so that MIB Database callLater runs. This is a waiting
160 # Async task from when the OpenOMCIAgent was started.
161 d = asleep(0.2)
162 d.addCallbacks(check_status, not_called)
163
164 return d
165
166 @deferred(timeout=5)
167 def test_mib_query_ok_if_dev_started(self):
168 self.setup_one_of_each()
169
170 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
171 self.adapter_agent)
172 self.assertIsNotNone(onu_device)
173 self.assertEqual(len(self.agent.device_ids()), 1)
174 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
175
176 def not_called(_reason):
177 onu_device.stop()
178 assert False, 'Should never be called'
179
180 def check_status(_results):
181 # Device started. Query will succeed but nothing should be populated
182 # but the most basic items
183
184 results = onu_device.query_mib()
185 self.assertTrue(isinstance(results, dict))
186 self.assertEqual(results.get(DEVICE_ID_KEY), DEFAULT_ONU_DEVICE_ID)
187
188 self.assertIsNotNone(results.get(VERSION_KEY))
189 self.assertIsNotNone(results.get(CREATED_KEY))
190 self.assertIsNone(results.get(MODIFIED_KEY)) # Created! but not yet modified
191
192 self.assertEqual(results.get(MDS_KEY), 0)
193 self.assertIsNone(results.get(LAST_SYNC_KEY))
194
195 self.assertIsNone(results.get(CLASS_ID_KEY))
196
197 # Stopping still allows a query. Note you just delete a device
198 # to clean up any associated databases
199 onu_device.stop()
200 results = onu_device.query_mib()
201 self.assertTrue(isinstance(results, dict))
202
203 # Yield context so that MIB Database callLater runs. This is a waiting
204 # Async task from when the OpenOMCIAgent was started. But also start the
205 # device so that it's queued async state machines can run as well
206 onu_device.start()
207 d = asleep(0.2)
208 d.addCallbacks(check_status, not_called)
209
210 return d
211
212 @deferred(timeout=5)
213 def test_delete_scrubs_mib(self):
214 self.setup_one_of_each()
215
216 onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
217 self.adapter_agent)
218 self.assertIsNotNone(onu_device)
219 self.assertEqual(len(self.agent.device_ids()), 1)
220 self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID), onu_device)
221
222 def not_called(_reason):
223 onu_device.stop()
224 assert False, 'Should never be called'
225
226 def check_status(_results):
227 # Device started. Query will succeed but nothing should be populated
228 # but the most basic items
229
230 results = onu_device.query_mib()
231 self.assertTrue(isinstance(results, dict))
232 self.assertEqual(results.get(DEVICE_ID_KEY), DEFAULT_ONU_DEVICE_ID)
233
234 # Delete should wipe out any MIB data. Note that a delete of a started
235 # or stopped ONU device is allowed. In this case we are deleting a
236 # started ONU Device
237
238 onu_device.delete()
239 assert_raises(Exception, onu_device.query_mib)
240 # TODO: When capabilities are supported, make sure capabilities get cleared as well
241
242 # Yield context so that MIB Database callLater runs. This is a waiting
243 # Async task from when the OpenOMCIAgent was started. But also start the
244 # device so that it's queued async state machines can run as well
245 onu_device.start()
246 d = asleep(0.2)
247 d.addCallbacks(check_status, not_called)
248
249 return d
250
251 # TODO: Test pub/sub interface if possible
252 # TODO: Test custom/vendor-specific ME support
253 # TODO: Test override of various state machines or OMCI tasks if possible
254
255
256if __name__ == '__main__':
257 main()
258