blob: 925e81f2b5cac02f181c2b537c8e8225d614d00c [file] [log] [blame]
Chip Boling67b674a2019-02-08 11:42:18 -06001#
2# Copyright 2017 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#
16from unittest import main, TestCase
17
18from pyvoltha.adapters.extensions.omci.database.mib_db_ext import *
19from pyvoltha.adapters.extensions.omci.database.mib_db_api import MODIFIED_KEY, CREATED_KEY,\
20 DEVICE_ID_KEY, MDS_KEY, LAST_SYNC_KEY
21from pyvoltha.adapters.extensions.omci.omci_cc import UNKNOWN_CLASS_ATTRIBUTE_KEY
22from mock.mock_adapter_agent import MockAdapterAgent, MockDevice
23from nose.tools import raises, assert_raises
24import time
25
26_DEVICE_ID = 'br-549'
27
28
29class TestOmciMibDbExt(TestCase):
30
31 def setUp(self):
32 self.adapter_agent = MockAdapterAgent()
33 self.adapter_agent.add_device(MockDevice(_DEVICE_ID)) # For Entity class lookups
34 self.db = MibDbExternal(self.adapter_agent)
35
36 def tearDown(self):
37 self.db.stop()
38
39 def test_start_stop(self):
40 # Simple start stop
41 self.assertFalse(self.db.active)
42 self.db.start()
43 self.assertTrue(self.db.active)
44 self.db.stop()
45 self.assertFalse(self.db.active)
46
47 # Start after start still okay
48 self.db.start()
49 self.db.start()
50 self.assertTrue(self.db.active)
51
52 self.db.stop()
53 self.db.stop()
54 self.assertFalse(self.db.active)
55
56 @raises(DatabaseStateError)
57 def test_bad_state_add(self):
58 self.db.add(_DEVICE_ID)
59
60 @raises(DatabaseStateError)
61 def test_bad_state_remove(self):
62 self.db.remove(_DEVICE_ID)
63
64 @raises(DatabaseStateError)
65 def test_bad_state_query_1(self):
66 self.db.query(_DEVICE_ID, 0)
67
68 @raises(DatabaseStateError)
69 def test_bad_state_query_2(self):
70 self.db.query(_DEVICE_ID, 0, 0)
71
72 @raises(DatabaseStateError)
73 def test_bad_state_query_3(self):
74 self.db.query(_DEVICE_ID, 0, 0, 'test')
75
76 @raises(DatabaseStateError)
77 def test_bad_state_set(self):
78 self.db.set(_DEVICE_ID, 0, 0, {'test': 123})
79
80 @raises(DatabaseStateError)
81 def test_bad_state_delete(self):
82 self.db.delete(_DEVICE_ID, 0, 0)
83
84 @raises(KeyError)
85 def test_no_device_query(self):
86 self.db.start()
87 self.db.query(_DEVICE_ID)
88
89 def test_no_device_last_sync(self):
90 self.db.start()
91 # Returns None, not a KeyError
92 value = self.db.get_last_sync(_DEVICE_ID)
93 self.assertIsNone(value)
94
95 def test_no_device_mds(self):
96 self.db.start()
97 # Returns None, not a KeyError
98 value = self.db.get_mib_data_sync(_DEVICE_ID)
99 self.assertIsNone(value)
100
101 @raises(KeyError)
102 def test_no_device_save_last_sync(self):
103 self.db.start()
104 self.db.save_last_sync(_DEVICE_ID, datetime.utcnow())
105
106 @raises(KeyError)
107 def test_no_device_save_mds(self):
108 self.db.start()
109 self.db.save_mib_data_sync(_DEVICE_ID, 123)
110
111 def test_param_types(self):
112 self.db.start()
113 assert_raises(TypeError, self.db.add, 123)
114 assert_raises(TypeError, self.db.remove, 123)
115 assert_raises(TypeError, self.db.query, 123)
116
117 assert_raises(TypeError, self.db.get_mib_data_sync, 123)
118 assert_raises(TypeError, self.db.save_mib_data_sync, 123, 0)
119 assert_raises(TypeError, self.db.save_mib_data_sync, _DEVICE_ID, 'zero')
120
121 assert_raises(TypeError, self.db.get_last_sync, 123)
122 assert_raises(TypeError, self.db.save_last_sync, 123, datetime.utcnow())
123 assert_raises(TypeError, self.db.save_last_sync, _DEVICE_ID, 'bad-date')
124
125 assert_raises(TypeError, self.db.set, 123, 0, 0, {'test': 0})
126 assert_raises(TypeError, self.db.set, None, 0, 0, {'test': 0})
127 assert_raises(ValueError, self.db.set, _DEVICE_ID, None, 0, {'test': 0})
128 assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, None, {'test': 0})
129 assert_raises(TypeError, self.db.set, _DEVICE_ID, 0, 0, None)
130 assert_raises(TypeError, self.db.set, _DEVICE_ID, 0, 0, 'not-a-dict')
131
132 assert_raises(ValueError, self.db.set, _DEVICE_ID, -1, 0, {'test': 0})
133 assert_raises(ValueError, self.db.set, _DEVICE_ID, 0x10000, 0, {'test': 0})
134 assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, -1, {'test': 0})
135 assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, 0x10000, {'test': 0})
136
137 assert_raises(TypeError, self.db.delete, 123, 0, 0)
138 assert_raises(ValueError, self.db.delete, _DEVICE_ID, -1, 0)
139 assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0x10000, 0)
140 assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0, -1)
141 assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0, 0x10000)
142
143 def test_add_remove_device(self):
144 self.db.start()
145
146 # Remove of non-existent device is not an error
147 assert_raises(KeyError, self.db.query, _DEVICE_ID)
148 self.db.remove(_DEVICE_ID)
149
150 start_time = datetime.utcnow()
151 self.db.add(_DEVICE_ID)
152 dev_data = self.db.query(_DEVICE_ID)
153
154 self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)
155 self.assertEquals(dev_data[MDS_KEY], 0)
156 self.assertIsNone(dev_data[LAST_SYNC_KEY])
157 self.assertEqual(dev_data[VERSION_KEY], MibDbExternal.CURRENT_VERSION)
158
159 self.assertGreaterEqual(self.db.created, start_time)
160
161 # Remove it
162 self.db.remove(_DEVICE_ID)
163 assert_raises(KeyError, self.db.query, _DEVICE_ID)
164
165 # Remove of non-existant dev okay
166 self.db.remove(_DEVICE_ID +'abcd')
167
168 # Overwrite tests
169 self.db.add(_DEVICE_ID)
170 assert_raises(KeyError, self.db.add, _DEVICE_ID)
171 self.db.add(_DEVICE_ID, overwrite=True) # This is okay
172
173 def test_mib_data_sync(self):
174 self.db.start()
175 self.db.add(_DEVICE_ID)
176 self.assertEquals(self.db.get_mib_data_sync(_DEVICE_ID), 0)
177
178 self.db.save_mib_data_sync(_DEVICE_ID, 100)
179 self.assertEqual(self.db.get_mib_data_sync(_DEVICE_ID), 100)
180
181 assert_raises(ValueError, self.db.save_mib_data_sync, _DEVICE_ID, -1)
182 assert_raises(ValueError, self.db.save_mib_data_sync, _DEVICE_ID, 256)
183
184 def test_last_sync(self):
185 self.db.start()
186 self.assertIsNone(self.db.get_last_sync(_DEVICE_ID))
187
188 self.db.add(_DEVICE_ID)
189 self.assertIsNone(self.db.get_last_sync(_DEVICE_ID))
190
191 now = datetime.utcnow()
192
193 self.db.save_last_sync(_DEVICE_ID, now)
194 self.assertEqual(self.db.get_last_sync(_DEVICE_ID), now)
195
196 assert_raises(TypeError, self.db.save_last_sync, _DEVICE_ID, 'hello')
197
198 def test_set_and_query(self):
199 self.db.start()
200 self.db.add(_DEVICE_ID) # Base device DB created here
201 time.sleep(0.1)
202
203 class_id = OntG.class_id
204 inst_id = 0
205 attributes = {'vendor_id': 'ABCD'}
206
207 start_time = datetime.utcnow()
208 set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
209 self.assertTrue(set_occurred)
210 end_time = datetime.utcnow()
211
212 dev_data = self.db.query(_DEVICE_ID)
213 self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)
214
215 dev_classes = [v for k, v in dev_data.items() if isinstance(k, int)]
216
217 self.assertEqual(len(dev_classes), 1)
218 class_data = dev_classes[0]
219
220 self.assertEqual(class_data[CLASS_ID_KEY], class_id)
221
222 class_insts = [v for k, v in class_data.items() if isinstance(k, int)]
223
224 self.assertEqual(len(class_insts), 1)
225 inst_data = class_insts[0]
226
227 self.assertEqual(inst_data[INSTANCE_ID_KEY], inst_id)
228 self.assertGreaterEqual(inst_data[MODIFIED_KEY], start_time)
229 self.assertLessEqual(inst_data[MODIFIED_KEY], end_time)
230 self.assertLessEqual(inst_data[CREATED_KEY], inst_data[MODIFIED_KEY])
231
232 inst_attributes = inst_data[ATTRIBUTES_KEY]
233 self.assertEqual(len(inst_attributes), 1)
234
235 self.assertTrue('vendor_id' in inst_attributes)
236 self.assertEqual(inst_attributes['vendor_id'], attributes['vendor_id'])
237
238 ########################################
239 # Query with device and class. Should be same as from full device query
240 cls_2_data = self.db.query(_DEVICE_ID, class_id)
241
242 self.assertEqual(class_data[CLASS_ID_KEY], cls_2_data[CLASS_ID_KEY])
243
244 cl2_insts = {k:v for k, v in cls_2_data.items() if isinstance(k, int)}
245 self.assertEqual(len(cl2_insts), len(class_insts))
246
247 # Bad class id query
248 cls_no_data = self.db.query(_DEVICE_ID, class_id + 1)
249 self.assertTrue(isinstance(cls_no_data, dict))
250 self.assertEqual(len(cls_no_data), 0)
251
252 ########################################
253 # Query with device, class, instance
254 inst_2_data = self.db.query(_DEVICE_ID, class_id, inst_id)
255
256 self.assertEqual(inst_data[INSTANCE_ID_KEY], inst_2_data[INSTANCE_ID_KEY])
257 self.assertEqual(inst_data[MODIFIED_KEY], inst_2_data[MODIFIED_KEY])
258 self.assertEqual(inst_data[CREATED_KEY], inst_2_data[CREATED_KEY])
259
260 inst2_attr = inst_2_data[ATTRIBUTES_KEY]
261 self.assertEqual(len(inst2_attr), len(inst_attributes))
262
263 # Bad instance id query
264 inst_no_data = self.db.query(_DEVICE_ID, class_id, inst_id + 100)
265 self.assertTrue(isinstance(inst_no_data, dict))
266 self.assertEqual(len(inst_no_data), 0)
267
268 ########################################
269 # Attribute queries
270 attr_2_data = self.db.query(_DEVICE_ID, class_id, inst_id, 'vendor_id')
271 self.assertEqual(attr_2_data['vendor_id'], attributes['vendor_id'])
272
273 attr_3_data = self.db.query(_DEVICE_ID, class_id, inst_id, ['vendor_id'])
274 self.assertEqual(attr_3_data['vendor_id'], attributes['vendor_id'])
275
276 attr_4_data = self.db.query(_DEVICE_ID, class_id, inst_id, {'vendor_id'})
277 self.assertEqual(attr_4_data['vendor_id'], attributes['vendor_id'])
278
279 attr_no_data = self.db.query(_DEVICE_ID, class_id, inst_id, 'no_such_thing')
280 self.assertTrue(isinstance(attr_no_data, dict))
281 self.assertEqual(len(attr_no_data), 0)
282
283 # Set to same value does not change modified data. The modified is
284 # at the instance level
285
286 class_id = OntG.class_id
287 inst_id = 0
288 attributes = {'vendor_id': 'ABCD'}
289 set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
290 self.assertFalse(set_occurred)
291
292 inst_3_data = self.db.query(_DEVICE_ID, class_id, inst_id)
293 self.assertEqual(inst_data[MODIFIED_KEY], inst_3_data[MODIFIED_KEY])
294 self.assertEqual(inst_data[CREATED_KEY], inst_3_data[CREATED_KEY])
295
296 # But set to new value does
297 time.sleep(0.1)
298 attributes = {'vendor_id': 'WXYZ'}
299 set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
300 self.assertTrue(set_occurred)
301
302 inst_4_data = self.db.query(_DEVICE_ID, class_id, inst_id)
303 self.assertLess(inst_3_data[MODIFIED_KEY], inst_4_data[MODIFIED_KEY])
304 self.assertEqual(inst_3_data[CREATED_KEY], inst_4_data[CREATED_KEY])
305
306 def test_delete_instances(self):
307 self.db.start()
308 self.db.add(_DEVICE_ID)
309 create_time = datetime.utcnow()
310
311 class_id = GalEthernetProfile.class_id
312 inst_id_1 = 0x100
313 inst_id_2 = 0x200
314 attributes = {'max_gem_payload_size': 1500}
315
316 self.db.set(_DEVICE_ID, class_id, inst_id_1, attributes)
317 self.db.set(_DEVICE_ID, class_id, inst_id_2, attributes)
318 time.sleep(0.1)
319
320 dev_data = self.db.query(_DEVICE_ID)
321 cls_data = self.db.query(_DEVICE_ID, class_id)
322 inst_data = {k: v for k, v in cls_data.items() if isinstance(k, int)}
323 self.assertEqual(len(inst_data), 2)
324
325 self.assertLessEqual(dev_data[CREATED_KEY], create_time)
326 self.assertLessEqual(self.db.created, create_time)
327
328 # Delete one instance
329 time.sleep(0.1)
330 result = self.db.delete(_DEVICE_ID, class_id, inst_id_1)
331 self.assertTrue(result) # True returned if a del actually happened
332
333 dev_data = self.db.query(_DEVICE_ID)
334 cls_data = self.db.query(_DEVICE_ID, class_id)
335 inst_data = {k: v for k, v in cls_data.items() if isinstance(k, int)}
336 self.assertEqual(len(inst_data), 1)
337
338 self.assertLessEqual(dev_data[CREATED_KEY], create_time)
339 self.assertLessEqual(self.db.created, create_time)
340
341 # Delete remaining instance
342 time.sleep(0.1)
343 result = self.db.delete(_DEVICE_ID, class_id, inst_id_2)
344 self.assertTrue(result) # True returned if a del actually happened
345
346 dev_data = self.db.query(_DEVICE_ID)
347 cls_data = {k: v for k, v in dev_data.items() if isinstance(k, int)}
348 self.assertEqual(len(cls_data), 0)
349 self.assertLessEqual(dev_data[CREATED_KEY], create_time)
350
351 # Delete returns false if not instance
352 self.assertFalse(self.db.delete(_DEVICE_ID, class_id, inst_id_1))
353 self.assertFalse(self.db.delete(_DEVICE_ID, class_id, inst_id_2))
354
355 def test_on_mib_reset_listener(self):
356 self.db.start()
357 self.db.add(_DEVICE_ID)
358 time.sleep(0.1)
359
360 class_id = OntG.class_id
361 inst_id = 0
362 attributes = {'vendor_id': 'ABCD'}
363
364 set_time = datetime.utcnow()
365 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
366
367 time.sleep(0.1)
368 self.db.on_mib_reset(_DEVICE_ID)
369
370 dev_data = self.db.query(_DEVICE_ID)
371 self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)
372 self.assertLessEqual(dev_data[CREATED_KEY], set_time)
373 self.assertLessEqual(self.db.created, set_time)
374
375 self.assertFalse(any(isinstance(cls, int) for cls in dev_data.iterkeys()))
376
377 def test_str_field_serialization(self):
378 self.db.start()
379 self.db.add(_DEVICE_ID)
380
381 class_id = OltG.class_id
382 inst_id = 0
383 attributes = {
384 'olt_vendor_id': 'ABCD', # StrFixedLenField(4)
385 }
386 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
387 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
388 self.assertTrue(all(isinstance(data[k], basestring) for k in attributes.keys()))
389 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
390
391 def test_mac_address_ip_field_serialization(self):
392 self.db.start()
393 self.db.add(_DEVICE_ID)
394
395 class_id = IpHostConfigData.class_id
396 inst_id = 0
397 attributes = {
398 'mac_address': '00:01:02:03:04:05', # MACField
399 'ip_address': '1.2.3.4', # IPField
400 }
401 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
402 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
403 self.assertTrue(all(isinstance(data[k], basestring) for k in attributes.keys()))
404 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
405
406 def test_byte_and_short_field_serialization(self):
407 self.db.start()
408 self.db.add(_DEVICE_ID)
409
410 class_id = UniG.class_id
411 inst_id = 0
412 attributes = {
413 'administrative_state': int(1), # ByteField
414 'non_omci_management_identifier': int(12345) # IPField
415 }
416 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
417 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
418 self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
419 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
420
421 def test_int_field_serialization(self):
422 self.db.start()
423 self.db.add(_DEVICE_ID)
424
425 class_id = PriorityQueueG.class_id
426 inst_id = 0
427 attributes = {
428 'related_port': int(1234567) # IntField
429 }
430 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
431 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
432 self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
433 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
434
435 def test_long_field_serialization(self):
436 self.db.start()
437 self.db.add(_DEVICE_ID)
438
439 class_id = PriorityQueueG.class_id
440 inst_id = 0
441 attributes = {
442 'packet_drop_queue_thresholds': int(0x1234) # LongField
443 }
444 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
445 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
446 self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
447 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
448
449 def test_bit_field_serialization(self):
450 self.db.start()
451 self.db.add(_DEVICE_ID)
452
453 class_id = OntG.class_id
454 inst_id = 0
455 attributes = {
456 'extended_tc_layer_options': long(0x1234), # BitField(16)
457 }
458 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
459 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
460 self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
461 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
462
463 def test_list_field_serialization(self):
464 self.db.start()
465 self.db.add(_DEVICE_ID)
466
467 class_id = VlanTaggingFilterData.class_id
468 inst_id = 0
469 vlan_filter_list = [0] * 12
470 vlan_filter_list[0] = 0x1234
471
472 attributes = {
473 'vlan_filter_list': vlan_filter_list, # FieldListField
474 'forward_operation': 0,
475 'number_of_entries': 1
476 }
477 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
478 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
479 self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
480 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
481
482 def test_complex_json_serialization(self):
483 self.db.start()
484 self.db.add(_DEVICE_ID)
485
486 class_id = ExtendedVlanTaggingOperationConfigurationData.class_id
487 inst_id = 0x202
488 table_data = VlanTaggingOperation(
489 filter_outer_priority=15,
490 filter_inner_priority=8,
491 filter_inner_vid=1024,
492 filter_inner_tpid_de=5,
493 filter_ether_type=0,
494 treatment_tags_to_remove=1,
495 pad3=2,
496 treatment_outer_priority=15,
497 treatment_inner_priority=8,
498 treatment_inner_vid=1024,
499 treatment_inner_tpid_de=4
500 )
501 attributes = dict(
502 received_frame_vlan_tagging_operation_table=table_data
503 )
504 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
505
506 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
507 table_as_dict = json.loads(table_data.to_json())
508
509 self.assertTrue(all(isinstance(data['received_frame_vlan_tagging_operation_table'][0].fields[k],
510 type(attributes['received_frame_vlan_tagging_operation_table'].fields[k]))
511 for k in attributes['received_frame_vlan_tagging_operation_table'].fields.keys()))
512 self.assertTrue(all(data['received_frame_vlan_tagging_operation_table'][0].fields[k] ==
513 attributes['received_frame_vlan_tagging_operation_table'].fields[k]
514 for k in attributes['received_frame_vlan_tagging_operation_table'].fields.keys()))
515 self.assertTrue(all(data['received_frame_vlan_tagging_operation_table'][0].fields[k] == table_as_dict[k]
516 for k in table_as_dict.keys()))
517
518 def test_unknown_me_serialization(self):
519 self.db.start()
520 self.db.add(_DEVICE_ID)
521
522 blob = '00010000000c0000000000000000000000000000000000000000'
523 class_id = 0xff78
524 inst_id = 0x101
525 attributes = {
526 UNKNOWN_CLASS_ATTRIBUTE_KEY: blob
527 }
528 self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
529
530 data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
531 self.assertTrue(isinstance(UNKNOWN_CLASS_ATTRIBUTE_KEY, basestring))
532 self.assertTrue(all(isinstance(attributes[k], basestring) for k in attributes.keys()))
533 self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
534
535
536if __name__ == '__main__':
537 main()