Exemple #1
0
class TestOmciMibDbExt(TestCase):
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()
        self.adapter_agent.add_device(
            MockDevice(_DEVICE_ID))  # For Entity class lookups
        self.db = MibDbExternal(self.adapter_agent)

    def tearDown(self):
        self.db.stop()

    def test_start_stop(self):
        # Simple start stop
        self.assertFalse(self.db.active)
        self.db.start()
        self.assertTrue(self.db.active)
        self.db.stop()
        self.assertFalse(self.db.active)

        # Start after start still okay
        self.db.start()
        self.db.start()
        self.assertTrue(self.db.active)

        self.db.stop()
        self.db.stop()
        self.assertFalse(self.db.active)

    @raises(DatabaseStateError)
    def test_bad_state_add(self):
        self.db.add(_DEVICE_ID)

    @raises(DatabaseStateError)
    def test_bad_state_remove(self):
        self.db.remove(_DEVICE_ID)

    @raises(DatabaseStateError)
    def test_bad_state_query_1(self):
        self.db.query(_DEVICE_ID, 0)

    @raises(DatabaseStateError)
    def test_bad_state_query_2(self):
        self.db.query(_DEVICE_ID, 0, 0)

    @raises(DatabaseStateError)
    def test_bad_state_query_3(self):
        self.db.query(_DEVICE_ID, 0, 0, 'test')

    @raises(DatabaseStateError)
    def test_bad_state_set(self):
        self.db.set(_DEVICE_ID, 0, 0, {'test': 123})

    @raises(DatabaseStateError)
    def test_bad_state_delete(self):
        self.db.delete(_DEVICE_ID, 0, 0)

    @raises(KeyError)
    def test_no_device_query(self):
        self.db.start()
        self.db.query(_DEVICE_ID)

    def test_no_device_last_sync(self):
        self.db.start()
        # Returns None, not a KeyError
        value = self.db.get_last_sync(_DEVICE_ID)
        self.assertIsNone(value)

    def test_no_device_mds(self):
        self.db.start()
        # Returns None, not a KeyError
        value = self.db.get_mib_data_sync(_DEVICE_ID)
        self.assertIsNone(value)

    @raises(KeyError)
    def test_no_device_save_last_sync(self):
        self.db.start()
        self.db.save_last_sync(_DEVICE_ID, datetime.utcnow())

    @raises(KeyError)
    def test_no_device_save_mds(self):
        self.db.start()
        self.db.save_mib_data_sync(_DEVICE_ID, 123)

    def test_param_types(self):
        self.db.start()
        assert_raises(TypeError, self.db.add, 123)
        assert_raises(TypeError, self.db.remove, 123)
        assert_raises(TypeError, self.db.query, 123)

        assert_raises(TypeError, self.db.get_mib_data_sync, 123)
        assert_raises(TypeError, self.db.save_mib_data_sync, 123, 0)
        assert_raises(TypeError, self.db.save_mib_data_sync, _DEVICE_ID,
                      'zero')

        assert_raises(TypeError, self.db.get_last_sync, 123)
        assert_raises(TypeError, self.db.save_last_sync, 123,
                      datetime.utcnow())
        assert_raises(TypeError, self.db.save_last_sync, _DEVICE_ID,
                      'bad-date')

        assert_raises(TypeError, self.db.set, 123, 0, 0, {'test': 0})
        assert_raises(TypeError, self.db.set, None, 0, 0, {'test': 0})
        assert_raises(ValueError, self.db.set, _DEVICE_ID, None, 0,
                      {'test': 0})
        assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, None,
                      {'test': 0})
        assert_raises(TypeError, self.db.set, _DEVICE_ID, 0, 0, None)
        assert_raises(TypeError, self.db.set, _DEVICE_ID, 0, 0, 'not-a-dict')

        assert_raises(ValueError, self.db.set, _DEVICE_ID, -1, 0, {'test': 0})
        assert_raises(ValueError, self.db.set, _DEVICE_ID, 0x10000, 0,
                      {'test': 0})
        assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, -1, {'test': 0})
        assert_raises(ValueError, self.db.set, _DEVICE_ID, 0, 0x10000,
                      {'test': 0})

        assert_raises(TypeError, self.db.delete, 123, 0, 0)
        assert_raises(ValueError, self.db.delete, _DEVICE_ID, -1, 0)
        assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0x10000, 0)
        assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0, -1)
        assert_raises(ValueError, self.db.delete, _DEVICE_ID, 0, 0x10000)

    def test_add_remove_device(self):
        self.db.start()

        # Remove of non-existent device is not an error
        assert_raises(KeyError, self.db.query, _DEVICE_ID)
        self.db.remove(_DEVICE_ID)

        start_time = datetime.utcnow()
        self.db.add(_DEVICE_ID)
        dev_data = self.db.query(_DEVICE_ID)

        self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)
        self.assertEquals(dev_data[MDS_KEY], 0)
        self.assertIsNone(dev_data[LAST_SYNC_KEY])
        self.assertEqual(dev_data[VERSION_KEY], MibDbExternal.CURRENT_VERSION)

        self.assertGreaterEqual(self.db.created, start_time)

        # Remove it
        self.db.remove(_DEVICE_ID)
        assert_raises(KeyError, self.db.query, _DEVICE_ID)

        # Remove of non-existant dev okay
        self.db.remove(_DEVICE_ID + 'abcd')

        # Overwrite tests
        self.db.add(_DEVICE_ID)
        assert_raises(KeyError, self.db.add, _DEVICE_ID)
        self.db.add(_DEVICE_ID, overwrite=True)  # This is okay

    def test_mib_data_sync(self):
        self.db.start()
        self.db.add(_DEVICE_ID)
        self.assertEquals(self.db.get_mib_data_sync(_DEVICE_ID), 0)

        self.db.save_mib_data_sync(_DEVICE_ID, 100)
        self.assertEqual(self.db.get_mib_data_sync(_DEVICE_ID), 100)

        assert_raises(ValueError, self.db.save_mib_data_sync, _DEVICE_ID, -1)
        assert_raises(ValueError, self.db.save_mib_data_sync, _DEVICE_ID, 256)

    def test_last_sync(self):
        self.db.start()
        self.assertIsNone(self.db.get_last_sync(_DEVICE_ID))

        self.db.add(_DEVICE_ID)
        self.assertIsNone(self.db.get_last_sync(_DEVICE_ID))

        now = datetime.utcnow()

        self.db.save_last_sync(_DEVICE_ID, now)
        self.assertEqual(self.db.get_last_sync(_DEVICE_ID), now)

        assert_raises(TypeError, self.db.save_last_sync, _DEVICE_ID, 'hello')

    def test_set_and_query(self):
        self.db.start()
        self.db.add(_DEVICE_ID)  # Base device DB created here
        time.sleep(0.1)

        class_id = OntG.class_id
        inst_id = 0
        attributes = {'vendor_id': 'ABCD'}

        start_time = datetime.utcnow()
        set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.assertTrue(set_occurred)
        end_time = datetime.utcnow()

        dev_data = self.db.query(_DEVICE_ID)
        self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)

        dev_classes = [v for k, v in dev_data.items() if isinstance(k, int)]

        self.assertEqual(len(dev_classes), 1)
        class_data = dev_classes[0]

        self.assertEqual(class_data[CLASS_ID_KEY], class_id)

        class_insts = [v for k, v in class_data.items() if isinstance(k, int)]

        self.assertEqual(len(class_insts), 1)
        inst_data = class_insts[0]

        self.assertEqual(inst_data[INSTANCE_ID_KEY], inst_id)
        self.assertGreaterEqual(inst_data[MODIFIED_KEY], start_time)
        self.assertLessEqual(inst_data[MODIFIED_KEY], end_time)
        self.assertLessEqual(inst_data[CREATED_KEY], inst_data[MODIFIED_KEY])

        inst_attributes = inst_data[ATTRIBUTES_KEY]
        self.assertEqual(len(inst_attributes), 1)

        self.assertTrue('vendor_id' in inst_attributes)
        self.assertEqual(inst_attributes['vendor_id'], attributes['vendor_id'])

        ########################################
        # Query with device and class. Should be same as from full device query
        cls_2_data = self.db.query(_DEVICE_ID, class_id)

        self.assertEqual(class_data[CLASS_ID_KEY], cls_2_data[CLASS_ID_KEY])

        cl2_insts = {k: v for k, v in cls_2_data.items() if isinstance(k, int)}
        self.assertEqual(len(cl2_insts), len(class_insts))

        # Bad class id query
        cls_no_data = self.db.query(_DEVICE_ID, class_id + 1)
        self.assertTrue(isinstance(cls_no_data, dict))
        self.assertEqual(len(cls_no_data), 0)

        ########################################
        # Query with device, class, instance
        inst_2_data = self.db.query(_DEVICE_ID, class_id, inst_id)

        self.assertEqual(inst_data[INSTANCE_ID_KEY],
                         inst_2_data[INSTANCE_ID_KEY])
        self.assertEqual(inst_data[MODIFIED_KEY], inst_2_data[MODIFIED_KEY])
        self.assertEqual(inst_data[CREATED_KEY], inst_2_data[CREATED_KEY])

        inst2_attr = inst_2_data[ATTRIBUTES_KEY]
        self.assertEqual(len(inst2_attr), len(inst_attributes))

        # Bad instance id query
        inst_no_data = self.db.query(_DEVICE_ID, class_id, inst_id + 100)
        self.assertTrue(isinstance(inst_no_data, dict))
        self.assertEqual(len(inst_no_data), 0)

        ########################################
        # Attribute queries
        attr_2_data = self.db.query(_DEVICE_ID, class_id, inst_id, 'vendor_id')
        self.assertEqual(attr_2_data['vendor_id'], attributes['vendor_id'])

        attr_3_data = self.db.query(_DEVICE_ID, class_id, inst_id,
                                    ['vendor_id'])
        self.assertEqual(attr_3_data['vendor_id'], attributes['vendor_id'])

        attr_4_data = self.db.query(_DEVICE_ID, class_id, inst_id,
                                    {'vendor_id'})
        self.assertEqual(attr_4_data['vendor_id'], attributes['vendor_id'])

        attr_no_data = self.db.query(_DEVICE_ID, class_id, inst_id,
                                     'no_such_thing')
        self.assertTrue(isinstance(attr_no_data, dict))
        self.assertEqual(len(attr_no_data), 0)

        # Set to same value does not change modified data.  The modified is
        # at the instance level

        class_id = OntG.class_id
        inst_id = 0
        attributes = {'vendor_id': 'ABCD'}
        set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.assertFalse(set_occurred)

        inst_3_data = self.db.query(_DEVICE_ID, class_id, inst_id)
        self.assertEqual(inst_data[MODIFIED_KEY], inst_3_data[MODIFIED_KEY])
        self.assertEqual(inst_data[CREATED_KEY], inst_3_data[CREATED_KEY])

        # But set to new value does
        time.sleep(0.1)
        attributes = {'vendor_id': 'WXYZ'}
        set_occurred = self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.assertTrue(set_occurred)

        inst_4_data = self.db.query(_DEVICE_ID, class_id, inst_id)
        self.assertLess(inst_3_data[MODIFIED_KEY], inst_4_data[MODIFIED_KEY])
        self.assertEqual(inst_3_data[CREATED_KEY], inst_4_data[CREATED_KEY])

    def test_delete_instances(self):
        self.db.start()
        self.db.add(_DEVICE_ID)
        create_time = datetime.utcnow()

        class_id = GalEthernetProfile.class_id
        inst_id_1 = 0x100
        inst_id_2 = 0x200
        attributes = {'max_gem_payload_size': 1500}

        self.db.set(_DEVICE_ID, class_id, inst_id_1, attributes)
        self.db.set(_DEVICE_ID, class_id, inst_id_2, attributes)
        time.sleep(0.1)

        dev_data = self.db.query(_DEVICE_ID)
        cls_data = self.db.query(_DEVICE_ID, class_id)
        inst_data = {k: v for k, v in cls_data.items() if isinstance(k, int)}
        self.assertEqual(len(inst_data), 2)

        self.assertLessEqual(dev_data[CREATED_KEY], create_time)
        self.assertLessEqual(self.db.created, create_time)

        # Delete one instance
        time.sleep(0.1)
        result = self.db.delete(_DEVICE_ID, class_id, inst_id_1)
        self.assertTrue(result)  # True returned if a del actually happened

        dev_data = self.db.query(_DEVICE_ID)
        cls_data = self.db.query(_DEVICE_ID, class_id)
        inst_data = {k: v for k, v in cls_data.items() if isinstance(k, int)}
        self.assertEqual(len(inst_data), 1)

        self.assertLessEqual(dev_data[CREATED_KEY], create_time)
        self.assertLessEqual(self.db.created, create_time)

        # Delete remaining instance
        time.sleep(0.1)
        result = self.db.delete(_DEVICE_ID, class_id, inst_id_2)
        self.assertTrue(result)  # True returned if a del actually happened

        dev_data = self.db.query(_DEVICE_ID)
        cls_data = {k: v for k, v in dev_data.items() if isinstance(k, int)}
        self.assertEqual(len(cls_data), 0)
        self.assertLessEqual(dev_data[CREATED_KEY], create_time)

        # Delete returns false if not instance
        self.assertFalse(self.db.delete(_DEVICE_ID, class_id, inst_id_1))
        self.assertFalse(self.db.delete(_DEVICE_ID, class_id, inst_id_2))

    def test_on_mib_reset_listener(self):
        self.db.start()
        self.db.add(_DEVICE_ID)
        time.sleep(0.1)

        class_id = OntG.class_id
        inst_id = 0
        attributes = {'vendor_id': 'ABCD'}

        set_time = datetime.utcnow()
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)

        time.sleep(0.1)
        self.db.on_mib_reset(_DEVICE_ID)

        dev_data = self.db.query(_DEVICE_ID)
        self.assertEqual(dev_data[DEVICE_ID_KEY], _DEVICE_ID)
        self.assertLessEqual(dev_data[CREATED_KEY], set_time)
        self.assertLessEqual(self.db.created, set_time)

        self.assertFalse(
            any(isinstance(cls, int) for cls in dev_data.iterkeys()))

    def test_str_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = OltG.class_id
        inst_id = 0
        attributes = {
            'olt_vendor_id': 'ABCD',  # StrFixedLenField(4)
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(isinstance(data[k], basestring) for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_mac_address_ip_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = IpHostConfigData.class_id
        inst_id = 0
        attributes = {
            'mac_address': '00:01:02:03:04:05',  # MACField
            'ip_address': '1.2.3.4',  # IPField
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(isinstance(data[k], basestring) for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_byte_and_short_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = UniG.class_id
        inst_id = 0
        attributes = {
            'administrative_state': int(1),  # ByteField
            'non_omci_management_identifier': int(12345)  # IPField
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(
                isinstance(data[k], type(attributes[k]))
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_int_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes = {
            'related_port': int(1234567)  # IntField
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(
                isinstance(data[k], type(attributes[k]))
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_long_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes = {
            'packet_drop_queue_thresholds': int(0x1234)  # LongField
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(
                isinstance(data[k], type(attributes[k]))
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_bit_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = OntG.class_id
        inst_id = 0
        attributes = {
            'extended_tc_layer_options': long(0x1234),  # BitField(16)
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(
                isinstance(data[k], type(attributes[k]))
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_list_field_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = VlanTaggingFilterData.class_id
        inst_id = 0
        vlan_filter_list = [0] * 12
        vlan_filter_list[0] = 0x1234

        attributes = {
            'vlan_filter_list': vlan_filter_list,  # FieldListField
            'forward_operation': 0,
            'number_of_entries': 1
        }
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(
            all(
                isinstance(data[k], type(attributes[k]))
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))

    def test_complex_json_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        class_id = ExtendedVlanTaggingOperationConfigurationData.class_id
        inst_id = 0x202
        table_data = VlanTaggingOperation(filter_outer_priority=15,
                                          filter_inner_priority=8,
                                          filter_inner_vid=1024,
                                          filter_inner_tpid_de=5,
                                          filter_ether_type=0,
                                          treatment_tags_to_remove=1,
                                          pad3=2,
                                          treatment_outer_priority=15,
                                          treatment_inner_priority=8,
                                          treatment_inner_vid=1024,
                                          treatment_inner_tpid_de=4)
        attributes = dict(
            received_frame_vlan_tagging_operation_table=table_data)
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)

        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        table_as_dict = json.loads(table_data.to_json())

        self.assertTrue(
            all(
                isinstance(
                    data['received_frame_vlan_tagging_operation_table'][k],
                    type(attributes[
                        'received_frame_vlan_tagging_operation_table'].
                         fields[k])) for k in
                attributes['received_frame_vlan_tagging_operation_table'].
                fields.keys()))
        self.assertTrue(
            all(data['received_frame_vlan_tagging_operation_table'][k] ==
                attributes['received_frame_vlan_tagging_operation_table'].
                fields[k] for k in
                attributes['received_frame_vlan_tagging_operation_table'].
                fields.keys()))
        self.assertTrue(
            all(data['received_frame_vlan_tagging_operation_table'][k] ==
                table_as_dict[k] for k in table_as_dict.keys()))

    def test_unknown_me_serialization(self):
        self.db.start()
        self.db.add(_DEVICE_ID)

        blob = '00010000000c0000000000000000000000000000000000000000'
        class_id = 0xff78
        inst_id = 0x101
        attributes = {UNKNOWN_CLASS_ATTRIBUTE_KEY: blob}
        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)

        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
        self.assertTrue(isinstance(UNKNOWN_CLASS_ATTRIBUTE_KEY, basestring))
        self.assertTrue(
            all(
                isinstance(attributes[k], basestring)
                for k in attributes.keys()))
        self.assertTrue(
            all(data[k] == attributes[k] for k in attributes.keys()))
class TestOmciConfiguration(TestCase):
    """
    Test the OMCI read-only Configuration library methods
    """
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()

        custom = deepcopy(OpenOmciAgentDefaults)
        custom['mib-synchronizer']['database'] = MibDbVolatileDict

        self.omci_agent = OpenOMCIAgent(MockCore, support_classes=custom)
        self.omci_agent.start()

    def tearDown(self):
        if self.omci_agent is not None:
            self.omci_agent.stop()

        if self.adapter_agent is not None:
            self.adapter_agent.tearDown()

    def setup_mock_olt(self, device_id=DEFAULT_OLT_DEVICE_ID):
        handler = MockOltHandler(self.adapter_agent, device_id)
        self.adapter_agent.add_device(handler.device)
        return handler

    def setup_mock_onu(self,
                       parent_id=DEFAULT_OLT_DEVICE_ID,
                       device_id=DEFAULT_ONU_DEVICE_ID,
                       pon_id=DEFAULT_PON_ID,
                       onu_id=DEFAULT_ONU_ID,
                       serial_no=DEFAULT_ONU_SN):
        handler = MockOnuHandler(self.adapter_agent, parent_id, device_id,
                                 pon_id, onu_id)
        handler.serial_number = serial_no
        onu = MockOnu(serial_no, self.adapter_agent, handler.device_id) \
            if serial_no is not None else None
        handler.onu_mock = onu
        return handler

    def setup_one_of_each(self):
        # Most tests will use at lease one or more OLT and ONU
        self.olt_handler = self.setup_mock_olt()
        self.onu_handler = self.setup_mock_onu(
            parent_id=self.olt_handler.device_id)
        self.onu_device = self.onu_handler.onu_mock

        self.adapter_agent.add_child_device(self.olt_handler.device,
                                            self.onu_handler.device)
        # Add device to OpenOMCI
        self.onu_device = self.omci_agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                                     self.adapter_agent)

        # Allow timeout trigger support while in disabled state for mib sync
        # to make tests run cleanly while profiling.
        self.onu_device.mib_synchronizer.machine.add_transition(
            'timeout', 'disabled', 'disabled')

    def not_called(self, _reason):
        assert False, 'Should never be called'

    def _stuff_database(self, entries):
        """
        Stuff the MIB database with some entries that we will use during tests
        """
        database = self.onu_device.mib_synchronizer._database

        # Stuff a value into last in sync. This makes it look like
        # the ONU has been in in-sync at least once.
        self.onu_device.mib_synchronizer.last_mib_db_sync = datetime.utcnow()

        # Entry is a tuple of (class_id, instance_id, {attributes})
        for entry in entries:
            database.set(DEFAULT_ONU_DEVICE_ID, entry[0], entry[1], entry[2])

    def test_OMCCVersion(self):
        for key, value in OMCCVersion.__members__.items():
            self.assertEqual(OMCCVersion.to_enum(OMCCVersion[key].value),
                             value)

        self.assertEqual(OMCCVersion.to_enum(-1), OMCCVersion.Unknown)

    @deferred(timeout=50000)
    def test_defaults(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        @raises(AssertionError)
        def do_my_tests(_results):
            config = self.onu_device.configuration
            # Should raise assertion if never been synchronized
            config.version

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs. This is a waiting
        # Async task from when the OpenOMCIAgent was started. But also start the
        # device so that it's queued async state machines can run as well
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_but_empty(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        def stuff_db(_results):
            self._stuff_database([])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            # On no Class ID for requested property, None should be
            # returned
            self.assertIsNone(config.version)
            self.assertIsNone(config.traffic_management_option)
            self.assertIsNone(config.onu_survival_time)
            self.assertIsNone(config.equipment_id)
            self.assertIsNone(config.omcc_version)
            self.assertIsNone(config.vendor_product_code)
            self.assertIsNone(config.total_priority_queues)
            self.assertIsNone(config.total_traffic_schedulers)
            self.assertIsNone(config.total_gem_ports)
            self.assertIsNone(config.uptime)
            self.assertIsNone(config.connectivity_capability)
            self.assertIsNone(config.qos_configuration_flexibility)
            self.assertIsNone(config.priority_queue_scale_factor)
            self.assertIsNone(config.cardholder_entities)
            self.assertIsNone(config.circuitpack_entities)
            self.assertIsNone(config.software_images)
            self.assertIsNone(config.ani_g_entities)
            self.assertIsNone(config.uni_g_entities)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_ont_g_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        version = 'abcDEF'
        tm_opt = 2
        onu_survival = 123

        def stuff_db(_results):
            self._stuff_database([(OntG.class_id, 0, {
                'version': version,
                'traffic_management_options': tm_opt,
                'ont_survival_time': onu_survival
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            # On no Class ID for requested property, None should be
            # returned
            self.assertEqual(config.version, version)
            self.assertEqual(config.traffic_management_option, tm_opt)
            self.assertEqual(config.onu_survival_time, onu_survival)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_ont_2g_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        equip_id = 'br-549'
        omcc_ver = OMCCVersion.G_988_2012
        vend_code = 0x1234
        queues = 64
        scheds = 8
        gem_ports = 24
        uptime = 12345
        conn_capp = 0x00aa
        qos_flex = 0x001b
        queue_scale = 1

        def stuff_db(_results):
            self._stuff_database([(Ont2G.class_id, 0, {
                'equipment_id': equip_id,
                'omcc_version': omcc_ver.value,
                'vendor_product_code': vend_code,
                'total_priority_queue_number': queues,
                'total_traffic_scheduler_number': scheds,
                'total_gem_port_id_number': gem_ports,
                'sys_uptime': uptime,
                'connectivity_capability': conn_capp,
                'qos_configuration_flexibility': qos_flex,
                'priority_queue_scale_factor': queue_scale
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            self.assertEqual(config.equipment_id, equip_id)
            self.assertEqual(config.omcc_version, omcc_ver)
            self.assertEqual(config.vendor_product_code, vend_code)
            self.assertEqual(config.total_priority_queues, queues)
            self.assertEqual(config.total_traffic_schedulers, scheds)
            self.assertEqual(config.total_gem_ports, gem_ports)
            self.assertEqual(config.uptime, uptime)
            self.assertEqual(config.connectivity_capability, conn_capp)
            self.assertEqual(config.qos_configuration_flexibility, qos_flex)
            self.assertEqual(config.priority_queue_scale_factor, queue_scale)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_cardholder_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        ch_entity = 0x102
        unit_type = 255
        clie_code = 'abc123'
        prot_ptr = 0

        def stuff_db(_results):
            self._stuff_database([(Cardholder.class_id, ch_entity, {
                'actual_plugin_unit_type': unit_type,
                'actual_equipment_id': clie_code,
                'protection_profile_pointer': prot_ptr,
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            cardholder = config.cardholder_entities
            self.assertTrue(isinstance(cardholder, dict))
            self.assertEqual(len(cardholder), 1)
            self.assertEqual(cardholder[ch_entity]['entity-id'], ch_entity)
            self.assertEqual(cardholder[ch_entity]['is-single-piece'],
                             ch_entity >= 256)
            self.assertEqual(cardholder[ch_entity]['slot-number'],
                             ch_entity & 0xFF)
            self.assertEqual(cardholder[ch_entity]['actual-plug-in-type'],
                             unit_type)
            self.assertEqual(cardholder[ch_entity]['actual-equipment-id'],
                             clie_code)
            self.assertEqual(cardholder[ch_entity]['protection-profile-ptr'],
                             prot_ptr)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_circuitpack_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        cp_entity = 0x100
        num_ports = 1
        serial_num = 'ABCD01234'
        cp_version = '1234ABCD'
        vendor_id = 'AB-9876'
        tconts = 2
        pqueues = 64
        sched_count = 8

        def stuff_db(_results):
            self._stuff_database([(CircuitPack.class_id, cp_entity, {
                'number_of_ports':
                num_ports,
                'serial_number':
                serial_num,
                'version':
                cp_version,
                'vendor_id':
                vendor_id,
                'total_tcont_buffer_number':
                tconts,
                'total_priority_queue_number':
                pqueues,
                'total_traffic_scheduler_number':
                sched_count,
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            circuitpack = config.circuitpack_entities
            self.assertTrue(isinstance(circuitpack, dict))
            self.assertEqual(len(circuitpack), 1)
            self.assertEqual(circuitpack[cp_entity]['entity-id'], cp_entity)
            self.assertEqual(circuitpack[cp_entity]['number-of-ports'],
                             num_ports)
            self.assertEqual(circuitpack[cp_entity]['serial-number'],
                             serial_num)
            self.assertEqual(circuitpack[cp_entity]['version'], cp_version)
            self.assertEqual(circuitpack[cp_entity]['vendor-id'], vendor_id)
            self.assertEqual(circuitpack[cp_entity]['total-tcont-count'],
                             tconts)
            self.assertEqual(
                circuitpack[cp_entity]['total-priority-queue-count'], pqueues)
            self.assertEqual(
                circuitpack[cp_entity]['total-traffic-sched-count'],
                sched_count)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_software_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        sw_entity = 0x200
        sw_version = 'Beta-0.0.2'
        sw_hash = md5("just_a_test").hexdigest()
        prod_code = 'MySoftware'
        sw_active = True
        sw_committed = True
        sw_valid = True

        def stuff_db(_results):
            self._stuff_database([(SoftwareImage.class_id, sw_entity, {
                'version': sw_version,
                'is_committed': sw_committed,
                'is_active': sw_active,
                'is_valid': sw_valid,
                'product_code': prod_code,
                'image_hash': sw_hash,
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            images = config.software_images
            self.assertTrue(isinstance(images, list))
            self.assertEqual(len(images), 1)
            self.assertEqual(
                images[0].name,
                'running-revision' if sw_active else 'candidate-revision')
            self.assertEqual(images[0].version, sw_version)
            self.assertEqual(images[0].is_active, 1 if sw_active else 0)
            self.assertEqual(images[0].is_committed, 1 if sw_committed else 0)
            self.assertEqual(images[0].is_valid, 1 if sw_valid else 0)
            self.assertEqual(images[0].hash, sw_hash)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_ani_g_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        entity_id = 0x0106
        tconts = 4
        dba_report = 4

        def stuff_db(_results):
            self._stuff_database([(AniG.class_id, entity_id, {
                'total_tcont_number': tconts,
                'piggyback_dba_reporting': dba_report
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            anig = config.ani_g_entities
            self.assertTrue(isinstance(anig, dict))
            self.assertEqual(len(anig), 1)

            self.assertEqual(anig[entity_id]['entity-id'], entity_id)
            self.assertEqual(anig[entity_id]['slot-number'],
                             (entity_id >> 8) & 0xff)
            self.assertEqual(anig[entity_id]['port-number'], entity_id & 0xff)
            self.assertEqual(anig[entity_id]['total-tcont-count'], tconts)
            self.assertEqual(anig[entity_id]['piggyback-dba-reporting'],
                             dba_report)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d

    @deferred(timeout=5)
    def test_in_sync_with_uni_g_values(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.omci_agent.device_ids()), 1)

        entity_id = 0x4321
        mgmt_cap = 0

        def stuff_db(_results):
            self._stuff_database([(UniG.class_id, entity_id, {
                'management_capability': mgmt_cap
            })])

        def do_my_tests(_results):
            config = self.onu_device.configuration

            unig = config.uni_g_entities
            self.assertTrue(isinstance(unig, dict))
            self.assertEqual(len(unig), 1)

            self.assertEqual(unig[entity_id]['entity-id'], entity_id)
            self.assertEqual(unig[entity_id]['management-capability'],
                             mgmt_cap)

        # No capabilities available until started
        self.assertIsNone(self.onu_device.configuration)

        # Yield context so that MIB Database callLater runs.
        self.onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(stuff_db, self.not_called)
        d.addCallbacks(do_my_tests, self.not_called)
        return d
Exemple #3
0
class TestOmciCc(TestCase):
    """
    Test the Open OMCI Communication channels

    Note also added some testing of MockOnu behaviour since its behaviour during more
    complicated unit/integration tests may be performed in the future.
    """
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()

    def tearDown(self):
        if self.adapter_agent is not None:
            self.adapter_agent.tearDown()

    def setup_mock_olt(self, device_id=DEFAULT_OLT_DEVICE_ID):
        handler = MockOltHandler(self.adapter_agent, device_id)
        self.adapter_agent.add_device(handler.device)
        return handler

    def setup_mock_onu(self, parent_id=DEFAULT_OLT_DEVICE_ID,
                       device_id=DEFAULT_ONU_DEVICE_ID,
                       pon_id=DEFAULT_PON_ID,
                       onu_id=DEFAULT_ONU_ID,
                       serial_no=DEFAULT_ONU_SN):
        handler = MockOnuHandler(self.adapter_agent, parent_id, device_id, pon_id, onu_id)
        handler.serial_number = serial_no
        onu = MockOnu(serial_no, self.adapter_agent, handler.device_id) \
            if serial_no is not None else None
        handler.onu_mock = onu
        return handler

    def setup_one_of_each(self):
        # Most tests will use at lease one or more OLT and ONU
        self.olt_handler = self.setup_mock_olt()
        self.onu_handler = self.setup_mock_onu(parent_id=self.olt_handler.device_id)
        self.onu_device = self.onu_handler.onu_mock

        self.adapter_agent.add_child_device(self.olt_handler.device,
                                            self.onu_handler.device)

    def _is_omci_frame(self, results):
        assert isinstance(results, OmciFrame), 'Not OMCI Frame'
        return results

    def _check_status(self, results, value):
        status = results.fields['omci_message'].fields['success_code']
        assert status == value,\
            'Unexpected Status Code. Got {}, Expected: {}'.format(status, value)
        return results

    def _check_mib_sync(self, results, value):
        assert self.onu_device.mib_data_sync == value, \
            'Unexpected MIB DATA Sync value. Got {}, Expected: {}'.format(
                self.onu_device.mib_data_sync, value)
        return results

    def _check_stats(self, results, snapshot, stat, expected):
        assert snapshot[stat] == expected, \
            'Invalid statistic "{}". Got {}, Expected: {}'.format(stat,
                                                                  snapshot[stat],
                                                                  expected)
        return results

    def _check_value_equal(self, results, name, value, expected):
        assert value == expected, \
            'Value "{}" not equal. Got {}, Expected: {}'.format(name, value,
                                                                expected)
        return results

    def _default_errback(self, _failure):
        assert False

    def _snapshot_stats(self):
        omci_cc = self.onu_handler.omci_cc
        return {
            'tx_frames': omci_cc.tx_frames,
            'rx_frames': omci_cc.rx_frames,
            'rx_unknown_tid': omci_cc.rx_unknown_tid,
            'rx_onu_frames': omci_cc.rx_onu_frames,
            'rx_alarm_overflow': omci_cc.rx_alarm_overflow,
            'rx_avc_overflow': omci_cc.rx_avc_overflow,
            'rx_onu_discards': omci_cc.rx_onu_discards,
            'rx_timeouts': omci_cc.rx_timeouts,
            'rx_unknown_me': omci_cc.rx_unknown_me,
            'tx_errors': omci_cc.tx_errors,
            'consecutive_errors': omci_cc.consecutive_errors,
            'reply_min': omci_cc.reply_min,
            'reply_max': omci_cc.reply_max,
            'reply_average': omci_cc.reply_average
        }

    def test_default_init(self):
        self.setup_one_of_each()
        # Test default construction of OMCI_CC as well as
        # various other parameter settings
        omci_cc = self.onu_handler.omci_cc

        # No device directly associated
        self.assertIsNotNone(omci_cc._adapter_agent)
        self.assertIsNone(omci_cc._proxy_address)

        # No outstanding requests
        self.assertEqual(len(omci_cc._requests), 0)

        # Flags/properties
        self.assertFalse(omci_cc.enabled)

        # Statistics
        self.assertEqual(omci_cc.tx_frames, 0)
        self.assertEqual(omci_cc.rx_frames, 0)
        self.assertEqual(omci_cc.rx_unknown_tid, 0)
        self.assertEqual(omci_cc.rx_onu_frames, 0)
        self.assertEqual(omci_cc.rx_alarm_overflow, 0)
        self.assertEqual(omci_cc.rx_avc_overflow, 0)
        self.assertEqual(omci_cc.rx_onu_discards, 0)
        self.assertEqual(omci_cc.rx_unknown_me, 0)
        self.assertEqual(omci_cc.rx_timeouts, 0)
        self.assertEqual(omci_cc.tx_errors, 0)
        self.assertEqual(omci_cc.consecutive_errors, 0)
        self.assertNotEquals(omci_cc.reply_min, 0.0)
        self.assertEqual(omci_cc.reply_max, 0.0)
        self.assertEqual(omci_cc.reply_average, 0.0)

    def test_enable_disable(self):
        self.setup_one_of_each()

        # Test enable property
        omci_cc = self.onu_handler.omci_cc

        # Initially disabled
        self.assertFalse(omci_cc.enabled)
        omci_cc.enabled = False
        self.assertFalse(omci_cc.enabled)

        omci_cc.enabled = True
        self.assertTrue(omci_cc.enabled)
        self.assertIsNotNone(omci_cc._proxy_address)
        self.assertEqual(len(omci_cc._requests), 0)

        omci_cc.enabled = True      # Should be a NOP
        self.assertTrue(omci_cc.enabled)
        self.assertIsNotNone(omci_cc._proxy_address)
        self.assertEqual(len(omci_cc._requests), 0)

        omci_cc.enabled = False
        self.assertFalse(omci_cc.enabled)
        self.assertIsNone(omci_cc._proxy_address)

    def test_rx_discard_if_disabled(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = False
        snapshot = self._snapshot_stats()

        msg = '00fc2e0a00020000ff780000e00000010000000c' \
              '0000000000000000000000000000000000000000' \
              '00000028105a86ef'

        omci_cc.receive_message(hex2raw(msg))

        # Note: No counter increments
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'])
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])

    def test_message_send_get(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # GET
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_set(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # SET
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d
        #
        # # Also test mib_data_sync rollover.  255 -> 1  (zero reserved)
        #
        # self.onu_device.mib_data_sync = 255
        # # SET
        # self.assertTrue(True)  # TODO: Implement (copy previous one here)
        # self.assertEqual(1, self.onu_device.mib_data_sync)

    def test_message_send_create(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # Create
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_delete(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # Delete
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_mib_reset(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        self.onu_device.mib_data_sync = 10
        snapshot = self._snapshot_stats()

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)
        d.addCallback(self._check_mib_sync, 0)

        d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)
        return d

    def test_message_send_mib_upload(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # MIB Upload
        d = omci_cc.send_mib_upload(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)
        d.addCallback(self._check_mib_sync, mib_data_sync)

        # TODO: MIB Upload Results specific tests here

        d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)
        return d

    def test_message_send_mib_upload_next(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # # MIB Upload Next
        # d = omci_cc.send_mib_upload_next(0, timeout=1.0)
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success)
        # d.addCallback(self._check_mib_sync, mib_data_sync)
        #
        # # TODO: MIB Upload Next Results specific tests here
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)
        # return d

    def test_message_send_reboot(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # ONU Reboot
        d = omci_cc.send_reboot(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)

        d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_alarm_overflow', snapshot['rx_alarm_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_avc_overflow', snapshot['rx_avc_overflow'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)
        return d

    def test_message_send_with_omci_disabled(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        self.assertFalse(omci_cc.enabled)

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        def success_is_bad(_results):
            assert False, 'This test should throw a failure/error'

        def fail_fast(_failure):
            pass
            return None

        d.addCallbacks(success_is_bad, fail_fast)
        return d

    def test_message_send_get_with_latency(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()
        self.olt_handler.latency = 0.500    # 1/2 second

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)

        def check_latency_values(_):
            self.assertGreaterEqual(omci_cc.reply_min, self.olt_handler.latency)
            self.assertGreaterEqual(omci_cc.reply_max, self.olt_handler.latency)
            self.assertGreaterEqual(omci_cc.reply_average, self.olt_handler.latency)

        d.addCallback(check_latency_values)
        return d

    def test_message_failures(self):
        # Various tests of sending an OMCI message and it fails
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        self.assertEqual(omci_cc.tx_frames, 0)
        self.assertEqual(omci_cc.rx_frames, 0)
        self.assertEqual(omci_cc.rx_unknown_tid, 0)
        self.assertEqual(omci_cc.rx_timeouts, 0)
        self.assertEqual(omci_cc.tx_errors, 0)

        # # Class ID not found
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # Instance ID not found
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # PON is disabled
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # ONU is disabled
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # ONU is not activated
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors

        # TODO: make OLT send back an unknown TID (

        # todo: Test non-zero consecutive errors
        # todo: Send a good frame
        # todo: Test zero consecutive errors
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

    def test_rx_unknown_me(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # This is the ID ------+
        #                      v
        msg = '00fc2e0a00020000ff780000e00000010000000c' \
              '0000000000000000000000000000000000000000' \
              '00000028'

        omci_cc.receive_message(hex2raw(msg))

        # Note: After successful frame decode, a lookup of the corresponding request by
        #       TID is performed. None should be found, so we should see the Rx Unknown TID
        #       increment.
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'])
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'] + 1)
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'] + 1)
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])
        self.assertEqual(omci_cc.consecutive_errors, 0)

    def test_rx_decode_unknown_me(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # This is a MIB Upload Next Response. Where we would probably first see an
        # unknown Class ID
        #
        # This is the ID ------+
        #                      v
        msg = '00fc2e0a00020000ff780001e000'
        blob = '00010000000c0000000000000000000000000000000000000000'
        msg += blob + '00000028'

        # Dig into the internal method so we can get the returned frame
        frame = omci_cc._decode_unknown_me(hex2raw(msg))

        self.assertEqual(frame.fields['transaction_id'], 0x00fc)
        self.assertEqual(frame.fields['message_type'], 0x2e)

        omci_fields = frame.fields['omci_message'].fields

        self.assertEqual(omci_fields['entity_class'], 0x0002)
        self.assertEqual(omci_fields['entity_id'], 0x00)
        self.assertEqual(omci_fields['object_entity_class'], 0x0ff78)
        self.assertEqual(omci_fields['object_entity_id'], 0x01)
        self.assertEqual(omci_fields['object_attributes_mask'], 0xe000)

        data_fields = omci_fields['object_data']

        decoded_blob = data_fields.get(UNKNOWN_CLASS_ATTRIBUTE_KEY)
        self.assertIsNotNone(decoded_blob)
        self.assertEqual(decoded_blob, blob)

    def test_flush(self):
        # Test flush of autonomous ONU queues
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # TODO: add more
        self.assertTrue(True)  # TODO: Implement

    def test_avc_rx(self):
        # Test flush of autonomous ONU queues
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # TODO: add more
        self.assertTrue(True)  # TODO: Implement
class TestOnuDeviceEntry(TestCase):
    """
    Test the ONU Device Entry methods
    """
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()

        custom = deepcopy(OpenOmciAgentDefaults)
        custom['mib-synchronizer']['database'] = MibDbVolatileDict

        self.agent = OpenOMCIAgent(MockCore, support_classes=custom)
        self.agent.start()

    def tearDown(self):
        if self.agent is not None:
            self.agent.stop()

        if self.adapter_agent is not None:
            self.adapter_agent.tearDown()

    def setup_mock_olt(self, device_id=DEFAULT_OLT_DEVICE_ID):
        handler = MockOltHandler(self.adapter_agent, device_id)
        self.adapter_agent.add_device(handler.device)
        return handler

    def setup_mock_onu(self,
                       parent_id=DEFAULT_OLT_DEVICE_ID,
                       device_id=DEFAULT_ONU_DEVICE_ID,
                       pon_id=DEFAULT_PON_ID,
                       onu_id=DEFAULT_ONU_ID,
                       serial_no=DEFAULT_ONU_SN):
        handler = MockOnuHandler(self.adapter_agent, parent_id, device_id,
                                 pon_id, onu_id)
        handler.serial_number = serial_no
        onu = MockOnu(serial_no, self.adapter_agent, handler.device_id) \
            if serial_no is not None else None
        handler.onu_mock = onu
        return handler

    def setup_one_of_each(self):
        # Most tests will use at lease one or more OLT and ONU
        self.olt_handler = self.setup_mock_olt()
        self.onu_handler = self.setup_mock_onu(
            parent_id=self.olt_handler.device_id)
        self.onu_device = self.onu_handler.onu_mock

        self.adapter_agent.add_child_device(self.olt_handler.device,
                                            self.onu_handler.device)

    def test_add_remove_device(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.agent.device_ids()), 0)

        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)

        # No MIB if not started
        assert_raises(KeyError, onu_device.query_mib)

        self.agent.remove_device(DEFAULT_ONU_DEVICE_ID)
        self.assertEqual(len(self.agent.device_ids()), 1)

    def test_delete_device(self):
        self.setup_one_of_each()
        self.assertEqual(len(self.agent.device_ids()), 0)

        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)
        # Can delete if it was not started
        onu_device.delete()
        self.assertEqual(len(self.agent.device_ids()), 0)

        ##########################################
        # Delete of ONU device okay if it is started
        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)

        # Start it and then delete it
        onu_device.start()
        onu_device.delete()
        self.assertEqual(len(self.agent.device_ids()), 0)

    @deferred(timeout=5)
    def test_mib_query_fails_if_dev_not_started(self):
        self.setup_one_of_each()

        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)

        def not_called(_reason):
            assert False, 'Should never be called'

        def check_status(_results):
            # Device not yet started. Query should fail with KeyError since
            # ONU is not in database yet
            assert_raises(KeyError, onu_device.query_mib)

        # Yield context so that MIB Database callLater runs. This is a waiting
        # Async task from when the OpenOMCIAgent was started.
        d = asleep(0.2)
        d.addCallbacks(check_status, not_called)

        return d

    @deferred(timeout=5)
    def test_mib_query_ok_if_dev_started(self):
        self.setup_one_of_each()

        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)

        def not_called(_reason):
            onu_device.stop()
            assert False, 'Should never be called'

        def check_status(_results):
            # Device started. Query will succeed but nothing should be populated
            # but the most basic items

            results = onu_device.query_mib()
            self.assertTrue(isinstance(results, dict))
            self.assertEqual(results.get(DEVICE_ID_KEY), DEFAULT_ONU_DEVICE_ID)

            self.assertIsNotNone(results.get(VERSION_KEY))
            self.assertIsNotNone(results.get(CREATED_KEY))
            self.assertIsNone(
                results.get(MODIFIED_KEY))  # Created! but not yet modified

            self.assertEqual(results.get(MDS_KEY), 0)
            self.assertIsNone(results.get(LAST_SYNC_KEY))

            self.assertIsNone(results.get(CLASS_ID_KEY))

            # Stopping still allows a query.  Note you just delete a device
            # to clean up any associated databases
            onu_device.stop()
            results = onu_device.query_mib()
            self.assertTrue(isinstance(results, dict))

        # Yield context so that MIB Database callLater runs. This is a waiting
        # Async task from when the OpenOMCIAgent was started. But also start the
        # device so that it's queued async state machines can run as well
        onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(check_status, not_called)

        return d

    @deferred(timeout=5)
    def test_delete_scrubs_mib(self):
        self.setup_one_of_each()

        onu_device = self.agent.add_device(DEFAULT_ONU_DEVICE_ID,
                                           self.adapter_agent)
        self.assertIsNotNone(onu_device)
        self.assertEqual(len(self.agent.device_ids()), 1)
        self.assertEqual(self.agent.get_device(DEFAULT_ONU_DEVICE_ID),
                         onu_device)

        def not_called(_reason):
            onu_device.stop()
            assert False, 'Should never be called'

        def check_status(_results):
            # Device started. Query will succeed but nothing should be populated
            # but the most basic items

            results = onu_device.query_mib()
            self.assertTrue(isinstance(results, dict))
            self.assertEqual(results.get(DEVICE_ID_KEY), DEFAULT_ONU_DEVICE_ID)

            # Delete should wipe out any MIB data. Note that a delete of a started
            # or stopped ONU device is allowed.  In this case we are deleting a
            # started ONU Device

            onu_device.delete()
            assert_raises(Exception, onu_device.query_mib)
            # TODO: When capabilities are supported, make sure capabilities get cleared as well

        # Yield context so that MIB Database callLater runs. This is a waiting
        # Async task from when the OpenOMCIAgent was started. But also start the
        # device so that it's queued async state machines can run as well
        onu_device.start()
        d = asleep(0.2)
        d.addCallbacks(check_status, not_called)

        return d
class TestOmciMibResyncTask(TestCase):
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()
        self.adapter_agent.add_device(
            MockDevice(_DEVICE_ID))  # For Entity class lookups

        self.onu_db = OnuDB(self.adapter_agent)
        self.olt_db = OltDB(self.adapter_agent)

        self.onu_db.start()
        self.olt_db.start()

        self.olt_db.add(_DEVICE_ID)
        self.onu_db.add(_DEVICE_ID)

        self.task = MibResyncTask(self.adapter_agent, _DEVICE_ID)

    def tearDown(self):
        self.onu_db.stop()
        self.olt_db.stop()

    def test_not_same_type_dbs(self):
        #
        # OLT DB is a copy of the 'external' DB, ONU is a volatile DB
        #
        self.assertNotEqual(type(self.olt_db), type(self.onu_db))

    def test_db_same_format_str_field_serialization(self):
        class_id = OltG.class_id
        inst_id = 0
        attributes = {
            'olt_vendor_id': 'ABCD',  # StrFixedLenField(4)
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_mac_address_ip_field_serialization(self):
        class_id = IpHostConfigData.class_id
        inst_id = 0
        attributes = {
            'mac_address': '00:01:02:03:04:05',  # MACField
            'ip_address': '1.2.3.4',  # IPField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_byte_and_short_field_serialization(self):
        class_id = UniG.class_id
        inst_id = 0
        attributes = {
            'administrative_state': int(1),  # ByteField
            'non_omci_management_identifier': int(12345)  # IPField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_int_field_serialization(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes = {
            'related_port': int(1234567)  # IntField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_long_field_serialization(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes = {
            'packet_drop_queue_thresholds': int(0x1234)  # LongField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_bit_field_serialization(self):
        class_id = OntG.class_id
        inst_id = 0
        attributes = {
            'extended_tc_layer_options': long(0x1234),  # BitField(16)
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_list_field_serialization(self):
        class_id = VlanTaggingFilterData.class_id
        inst_id = 0
        vlan_filter_list = [0] * 12
        vlan_filter_list[0] = 0x1234

        attributes = {
            'vlan_filter_list': vlan_filter_list,  # FieldListField
            'forward_operation': 0,
            'number_of_entries': 1
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_db_same_format_complex_json_serialization(self):
        class_id = ExtendedVlanTaggingOperationConfigurationData.class_id
        inst_id = 0x202
        table_data = VlanTaggingOperation(filter_outer_priority=15,
                                          filter_inner_priority=8,
                                          filter_inner_vid=1024,
                                          filter_inner_tpid_de=5,
                                          filter_ether_type=0,
                                          treatment_tags_to_remove=1,
                                          pad3=2,
                                          treatment_outer_priority=15,
                                          treatment_inner_priority=8,
                                          treatment_inner_vid=1024,
                                          treatment_inner_tpid_de=4)
        attributes = dict(
            received_frame_vlan_tagging_operation_table=table_data)
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_on_olt_only(self):
        class_id = GemInterworkingTp.class_id
        inst_id = 0
        attributes = {'gal_loopback_configuration': int(1)}
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 1)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)
        self.assertEqual(olt_only, [(class_id, inst_id)])

        # Now a little more complex (extra instance on the OLT
        self.olt_db.set(_DEVICE_ID, class_id, inst_id + 1, attributes)
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 1)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)
        self.assertEqual(olt_only, [(class_id, inst_id + 1)])

    def test_on_onu_only(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes = {
            'related_port': int(1234567)  # IntField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 1)
        self.assertEqual(len(attr_diffs), 0)
        self.assertEqual(
            onu_only,
            [(class_id, inst_id)])  # Test contents of what was returned

        # Now a little more complex (extra instance on the ONU
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes)
        self.onu_db.set(_DEVICE_ID, class_id, inst_id + 1, attributes)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 1)
        self.assertEqual(len(attr_diffs), 0)
        self.assertEqual(
            onu_only,
            [(class_id, inst_id + 1)])  # Test contents of what was returned

    def test_on_attr_different_value(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes_olt = {
            'weight': int(12)  # ByteField
        }
        attributes_onu = {
            'weight': int(34)  # ByteField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes_onu)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes_olt)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 1)
        self.assertEqual(attr_diffs, [(class_id, inst_id, 'weight')])

    def test_ignore_read_only_attribute_differences(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes_olt = {
            'related_port': int(1234),  # IntField (R/O)
            'maximum_queue_size': int(222)  # Only on OLT but read-only
        }
        attributes_onu = {
            'related_port': int(5678)  # IntField (R/O)
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes_onu)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes_olt)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 0)

    def test_on_attr_more_on_olt(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes_olt = {
            'related_port': int(1234),  # IntField
            'back_pressure_time': int(1234)  # IntField
        }
        attributes_onu = {
            'related_port': int(1234)  # IntField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes_onu)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes_olt)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 1)
        self.assertEqual(attr_diffs,
                         [(class_id, inst_id, 'back_pressure_time')])

    def test_on_attr_more_on_onu(self):
        class_id = PriorityQueueG.class_id
        inst_id = 0
        attributes_olt = {
            'related_port': int(1234)  # IntField
        }
        attributes_onu = {
            'related_port': int(1234),  # IntField
            'back_pressure_time': int(5678)  # IntField
        }
        self.onu_db.set(_DEVICE_ID, class_id, inst_id, attributes_onu)
        self.olt_db.set(_DEVICE_ID, class_id, inst_id, attributes_olt)

        db_copy = self.olt_db.query(_DEVICE_ID)
        db_active = self.onu_db.query(_DEVICE_ID)

        olt_only, onu_only, attr_diffs = self.task.compare_mibs(
            db_copy, db_active)

        self.assertEqual(len(olt_only), 0)
        self.assertEqual(len(onu_only), 0)
        self.assertEqual(len(attr_diffs), 1)
        self.assertEqual(attr_diffs,
                         [(class_id, inst_id, 'back_pressure_time')])
Exemple #6
0
class TestOmciCc(TestCase):
    """
    Test the Open OMCI Communication channels

    Note also added some testing of MockOnu behaviour since its behaviour during more
    complicated unit/integration tests may be performed in the future.
    """
    def setUp(self):
        self.adapter_agent = MockAdapterAgent()

    def tearDown(self):
        if self.adapter_agent is not None:
            self.adapter_agent.tearDown()

    def setup_mock_olt(self, device_id=DEFAULT_OLT_DEVICE_ID):
        handler = MockOltHandler(self.adapter_agent, device_id)
        self.adapter_agent.add_device(handler.device)
        return handler

    def setup_mock_onu(self,
                       parent_id=DEFAULT_OLT_DEVICE_ID,
                       device_id=DEFAULT_ONU_DEVICE_ID,
                       pon_id=DEFAULT_PON_ID,
                       onu_id=DEFAULT_ONU_ID,
                       serial_no=DEFAULT_ONU_SN):
        handler = MockOnuHandler(self.adapter_agent, parent_id, device_id,
                                 pon_id, onu_id)
        handler.serial_number = serial_no
        onu = MockOnu(serial_no, self.adapter_agent, handler.device_id) \
            if serial_no is not None else None
        handler.onu_mock = onu
        return handler

    def setup_one_of_each(self):
        # Most tests will use at lease one or more OLT and ONU
        self.olt_handler = self.setup_mock_olt()
        self.onu_handler = self.setup_mock_onu(
            parent_id=self.olt_handler.device_id)
        self.onu_device = self.onu_handler.onu_mock

        self.adapter_agent.add_child_device(self.olt_handler.device,
                                            self.onu_handler.device)

    def _is_omci_frame(self, results, omci_msg_type):
        assert isinstance(results, OmciFrame), 'Not OMCI Frame'
        assert 'omci_message' in results.fields, 'Not OMCI Frame'
        if omci_msg_type is not None:
            assert isinstance(results.fields['omci_message'], omci_msg_type)
        return results

    def _check_status(self, results, value):
        if value is not None:
            assert results is not None, 'unexpected emtpy message'
        status = results.fields['omci_message'].fields['success_code']
        assert status == value,\
            'Unexpected Status Code. Got {}, Expected: {}'.format(status, value)
        return results

    def _check_mib_sync(self, results, value):
        assert self.onu_device.mib_data_sync == value, \
            'Unexpected MIB DATA Sync value. Got {}, Expected: {}'.format(
                self.onu_device.mib_data_sync, value)
        return results

    def _check_stats(self, results, _, stat, expected):
        snapshot = self._snapshot_stats()
        assert snapshot[stat] == expected, \
            'Invalid statistic "{}". Got {}, Expected: {}'.format(stat,
                                                                  snapshot[stat],
                                                                  expected)
        return results

    def _check_value_equal(self, results, name, value, expected):
        assert value == expected, \
            'Value "{}" not equal. Got {}, Expected: {}'.format(name, value,
                                                                expected)
        return results

    def _default_errback(self, failure):
        from twisted.internet.defer import TimeoutError
        assert isinstance(failure.type, type(TimeoutError))
        return None

    def _snapshot_stats(self):
        omci_cc = self.onu_handler.omci_cc
        return {
            'tx_frames': omci_cc.tx_frames,
            'rx_frames': omci_cc.rx_frames,
            'rx_unknown_tid': omci_cc.rx_unknown_tid,
            'rx_onu_frames': omci_cc.rx_onu_frames,
            'rx_onu_discards': omci_cc.rx_onu_discards,
            'rx_timeouts': omci_cc.rx_timeouts,
            'rx_unknown_me': omci_cc.rx_unknown_me,
            'tx_errors': omci_cc.tx_errors,
            'consecutive_errors': omci_cc.consecutive_errors,
            'reply_min': omci_cc.reply_min,
            'reply_max': omci_cc.reply_max,
            'reply_average': omci_cc.reply_average
        }

    def test_default_init(self):
        self.setup_one_of_each()
        # Test default construction of OMCI_CC as well as
        # various other parameter settings
        omci_cc = self.onu_handler.omci_cc

        # No device directly associated
        self.assertIsNotNone(omci_cc._adapter_agent)
        self.assertIsNone(omci_cc._proxy_address)

        # No outstanding requests
        self.assertEqual(len(omci_cc._requests), 0)

        # Flags/properties
        self.assertFalse(omci_cc.enabled)

        # Statistics
        self.assertEqual(omci_cc.tx_frames, 0)
        self.assertEqual(omci_cc.rx_frames, 0)
        self.assertEqual(omci_cc.rx_unknown_tid, 0)
        self.assertEqual(omci_cc.rx_onu_frames, 0)
        self.assertEqual(omci_cc.rx_onu_discards, 0)
        self.assertEqual(omci_cc.rx_unknown_me, 0)
        self.assertEqual(omci_cc.rx_timeouts, 0)
        self.assertEqual(omci_cc.tx_errors, 0)
        self.assertEqual(omci_cc.consecutive_errors, 0)
        self.assertNotEquals(omci_cc.reply_min, 0.0)
        self.assertEqual(omci_cc.reply_max, 0.0)
        self.assertEqual(omci_cc.reply_average, 0.0)

    def test_enable_disable(self):
        self.setup_one_of_each()

        # Test enable property
        omci_cc = self.onu_handler.omci_cc

        # Initially disabled
        self.assertFalse(omci_cc.enabled)
        omci_cc.enabled = False
        self.assertFalse(omci_cc.enabled)

        omci_cc.enabled = True
        self.assertTrue(omci_cc.enabled)
        self.assertIsNotNone(omci_cc._proxy_address)
        self.assertEqual(len(omci_cc._requests), 0)

        omci_cc.enabled = True  # Should be a NOP
        self.assertTrue(omci_cc.enabled)
        self.assertIsNotNone(omci_cc._proxy_address)
        self.assertEqual(len(omci_cc._requests), 0)

        omci_cc.enabled = False
        self.assertFalse(omci_cc.enabled)
        self.assertIsNone(omci_cc._proxy_address)

    def test_rx_discard_if_disabled(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = False
        snapshot = self._snapshot_stats()

        msg = '00fc2e0a00020000ff780000e00000010000000c' \
              '0000000000000000000000000000000000000000' \
              '00000028105a86ef'

        omci_cc.receive_message(hex2raw(msg))

        # Note: No counter increments
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'])
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])

    def test_message_send_get(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # GET
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_set(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # SET
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d
        #
        # # Also test mib_data_sync rollover.  255 -> 1  (zero reserved)
        #
        # self.onu_device.mib_data_sync = 255
        # # SET
        # self.assertTrue(True)  # TODO: Implement (copy previous one here)
        # self.assertEqual(1, self.onu_device.mib_data_sync)

    def test_message_send_create(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # Create
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_delete(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # Delete
        # d = omci_cc.send()  # TODO: Implement
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success.value)
        # d.addCallback(self._check_mib_sync, mib_data_sync + 1 if mib_data_sync < 255 else 1)
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

        # return d

    def test_message_send_mib_reset(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        self.onu_device.mib_data_sync = 10
        snapshot = self._snapshot_stats()

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)
        d.addCallback(self._check_mib_sync, 0)

        d.addCallback(self._check_stats, snapshot, 'tx_frames',
                      snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames',
                      snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid',
                      snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames',
                      snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards',
                      snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me',
                      snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts',
                      snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors',
                      snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0,
                      omci_cc.consecutive_errors)
        return d

    def test_message_send_mib_upload(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # MIB Upload
        d = omci_cc.send_mib_upload(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)
        d.addCallback(self._check_mib_sync, mib_data_sync)

        # TODO: MIB Upload Results specific tests here

        d.addCallback(self._check_stats, snapshot, 'tx_frames',
                      snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames',
                      snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid',
                      snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames',
                      snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards',
                      snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me',
                      snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts',
                      snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors',
                      snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0,
                      omci_cc.consecutive_errors)
        return d

    def test_message_send_mib_upload_next(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()
        mib_data_sync = self.onu_device.mib_data_sync

        # # MIB Upload Next
        # d = omci_cc.send_mib_upload_next(0, timeout=1.0)
        #
        # d.addCallbacks(self._is_omci_frame, self._default_errback)
        # d.addCallback(self._check_status, RC.Success)
        # d.addCallback(self._check_mib_sync, mib_data_sync)
        #
        # # TODO: MIB Upload Next Results specific tests here
        #
        # d.addCallback(self._check_stats, snapshot, 'tx_frames', snapshot['tx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_frames', snapshot['rx_frames'] + 1)
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid', snapshot['rx_unknown_tid'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_frames', snapshot['rx_onu_frames'])
        # d.addCallback(self._check_stats, snapshot, 'rx_onu_discards', snapshot['rx_onu_discards'])
        # d.addCallback(self._check_stats, snapshot, 'rx_unknown_me', snapshot['rx_unknown_me'])
        # d.addCallback(self._check_stats, snapshot, 'rx_timeouts', snapshot['rx_timeouts'])
        # d.addCallback(self._check_stats, snapshot, 'tx_errors', snapshot['tx_errors'])
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)
        # return d

    def test_message_send_reboot(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # ONU Reboot
        d = omci_cc.send_reboot(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)

        d.addCallback(self._check_stats, snapshot, 'tx_frames',
                      snapshot['tx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_frames',
                      snapshot['rx_frames'] + 1)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid',
                      snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames',
                      snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards',
                      snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me',
                      snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts',
                      snapshot['rx_timeouts'])
        d.addCallback(self._check_stats, snapshot, 'tx_errors',
                      snapshot['tx_errors'])
        d.addCallback(self._check_value_equal, 'consecutive_errors', 0,
                      omci_cc.consecutive_errors)
        return d

    def test_message_send_with_omci_disabled(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        self.assertFalse(omci_cc.enabled)

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        def success_is_bad(_results):
            assert False, 'This test should throw a failure/error'

        def fail_fast(_failure):
            pass
            return None

        d.addCallbacks(success_is_bad, fail_fast)
        return d

    def test_message_send_get_with_latency(self):
        # Various tests of sending an OMCI message and it either
        # getting a response or send catching some errors of
        # importance
        self.setup_one_of_each()
        self.olt_handler.latency = 0.500  # 1/2 second

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True

        # Successful MIB Reset
        d = omci_cc.send_mib_reset(timeout=1.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback)
        d.addCallback(self._check_status, RC.Success)

        def check_latency_values(_):
            self.assertGreaterEqual(omci_cc.reply_min,
                                    self.olt_handler.latency)
            self.assertGreaterEqual(omci_cc.reply_max,
                                    self.olt_handler.latency)
            self.assertGreaterEqual(omci_cc.reply_average,
                                    self.olt_handler.latency)

        d.addCallback(check_latency_values)
        return d

    def test_message_failures(self):
        # Various tests of sending an OMCI message and it fails
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        self.assertEqual(omci_cc.tx_frames, 0)
        self.assertEqual(omci_cc.rx_frames, 0)
        self.assertEqual(omci_cc.rx_unknown_tid, 0)
        self.assertEqual(omci_cc.rx_timeouts, 0)
        self.assertEqual(omci_cc.tx_errors, 0)

        # # Class ID not found
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # Instance ID not found
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # PON is disabled
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # ONU is disabled
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors
        #
        # # ONU is not activated
        # d = omci_cc.send_mib_reset(timeout=1.0)
        # self.assertTrue(True)  # TODO: Implement
        # todo: Test non-zero consecutive errors

        # TODO: make OLT send back an unknown TID (

        # todo: Test non-zero consecutive errors
        # todo: Send a good frame
        # todo: Test zero consecutive errors
        # d.addCallback(self._check_value_equal, 'consecutive_errors', 0, omci_cc.consecutive_errors)

    def test_rx_unknown_me(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # This is the ID ------+
        #                      v
        msg = '00fc2e0a00020000ff780000e00000010000000c' \
              '0000000000000000000000000000000000000000' \
              '00000028'

        omci_cc.receive_message(hex2raw(msg))

        # Note: After successful frame decode, a lookup of the corresponding request by
        #       TID is performed. None should be found, so we should see the Rx Unknown TID
        #       increment.
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'])
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'] + 1)
        self.assertEqual(omci_cc.rx_unknown_tid,
                         snapshot['rx_unknown_tid'] + 1)
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])
        self.assertEqual(omci_cc.consecutive_errors, 0)

    def test_rx_decode_unknown_me(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # This is a MIB Upload Next Response. Where we would probably first see an
        # unknown Class ID
        #
        # This is the ID ------+
        #                      v
        msg = '00fc2e0a00020000ff780001e000'
        blob = '00010000000c0000000000000000000000000000000000000000'
        msg += blob + '00000028'

        # Dig into the internal method so we can get the returned frame
        frame = omci_cc._decode_unknown_me(hex2raw(msg))

        self.assertEqual(frame.fields['transaction_id'], 0x00fc)
        self.assertEqual(frame.fields['message_type'], 0x2e)

        omci_fields = frame.fields['omci_message'].fields

        self.assertEqual(omci_fields['entity_class'], 0x0002)
        self.assertEqual(omci_fields['entity_id'], 0x00)
        self.assertEqual(omci_fields['object_entity_class'], 0x0ff78)
        self.assertEqual(omci_fields['object_entity_id'], 0x01)
        self.assertEqual(omci_fields['object_attributes_mask'], 0xe000)

        data_fields = omci_fields['object_data']

        decoded_blob = data_fields.get(UNKNOWN_CLASS_ATTRIBUTE_KEY)
        self.assertIsNotNone(decoded_blob)
        self.assertEqual(decoded_blob, blob)

    def test_flush(self):
        # Test flush of autonomous ONU queues
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # TODO: add more
        self.assertTrue(True)  # TODO: Implement

    def test_avc_rx(self):
        # Test flush of autonomous ONU queues
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        # TODO: add more
        self.assertTrue(True)  # TODO: Implement

    def test_rx_discard_if_disabled(self):
        # ME without a known decoder
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = False
        snapshot = self._snapshot_stats()

        msg = '00fc2e0a00020000ff780000e00000010000000c' \
              '0000000000000000000000000000000000000000' \
              '00000028105a86ef'

        omci_cc.receive_message(hex2raw(msg))

        # Note: No counter increments
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'])
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])
        self.assertEqual(omci_cc.rx_unknown_tid, snapshot['rx_unknown_tid'])

    def test_omci_alarm_decode(self):
        """
        This test covers an issue discovered in Sept 2018 (JIRA-1213).  It was
        an exception during frame decode.
        """
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True

        # Frame from the JIRA issue
        msg = '0000100a000b0102800000000000000000000000' \
              '0000000000000000000000000000000000000015' \
              '000000282d3ae0a6'

        results = omci_cc.receive_message(hex2raw(msg))

        self.assertTrue(True, 'Truth is the truth')

    def test_rx_decode_onu_g(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        msg = '001e2e0a0002000001000000e000424657530000' \
              '0000000000000000000000324246575300107496' \
              '00000028e7fb4a91'

        omci_cc.receive_message(hex2raw(msg))

        # Note: No counter increments
        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'] + 1)
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'])
        self.assertEqual(omci_cc.rx_unknown_tid,
                         snapshot['rx_unknown_tid'] + 1)
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])

    def test_rx_decode_extvlantagging(self):
        self.setup_one_of_each()

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True
        snapshot = self._snapshot_stats()

        msg = '030a290a00ab0201000d00000000001031323334' \
              '3536373839303132333435363738393031323334' \
              '000000281166d283'

        omci_cc.receive_message(hex2raw(msg))

        self.assertEqual(omci_cc.rx_frames, snapshot['rx_frames'] + 1)
        self.assertEqual(omci_cc.rx_unknown_me, snapshot['rx_unknown_me'])
        self.assertEqual(omci_cc.rx_unknown_tid,
                         snapshot['rx_unknown_tid'] + 1)
        self.assertEqual(omci_cc.rx_onu_frames, snapshot['rx_onu_frames'])

    def _check_vlan_tag_op(self, results, attr, expected):
        omci_msg = results.fields['omci_message']
        data = omci_msg.fields['data']
        val = data[attr]
        self.assertEqual(expected, val)
        return results

    @skip('for unknow omci failure')
    #@deferred()
    def test_rx_table_get_extvlantagging(self):
        self.setup_one_of_each()

        onu = self.onu_handler.onu_mock
        entity_id = 1
        vlan_tag_op1 = VlanTaggingOperation(
            filter_outer_priority=15,
            filter_outer_vid=4096,
            filter_outer_tpid_de=2,
            filter_inner_priority=15,
            filter_inner_vid=4096,
            filter_inner_tpid_de=0,
            filter_ether_type=0,
            treatment_tags_to_remove=0,
            treatment_outer_priority=15,
            treatment_outer_vid=1234,
            treatment_outer_tpid_de=0,
            treatment_inner_priority=0,
            treatment_inner_vid=4091,
            treatment_inner_tpid_de=4,
        )
        vlan_tag_op2 = VlanTaggingOperation(
            filter_outer_priority=14,
            filter_outer_vid=1234,
            filter_outer_tpid_de=5,
            filter_inner_priority=1,
            filter_inner_vid=2345,
            filter_inner_tpid_de=1,
            filter_ether_type=0,
            treatment_tags_to_remove=1,
            treatment_outer_priority=15,
            treatment_outer_vid=2222,
            treatment_outer_tpid_de=1,
            treatment_inner_priority=1,
            treatment_inner_vid=3333,
            treatment_inner_tpid_de=5,
        )
        vlan_tag_op3 = VlanTaggingOperation(
            filter_outer_priority=13,
            filter_outer_vid=55,
            filter_outer_tpid_de=1,
            filter_inner_priority=7,
            filter_inner_vid=4567,
            filter_inner_tpid_de=1,
            filter_ether_type=0,
            treatment_tags_to_remove=1,
            treatment_outer_priority=2,
            treatment_outer_vid=1111,
            treatment_outer_tpid_de=1,
            treatment_inner_priority=1,
            treatment_inner_vid=3131,
            treatment_inner_tpid_de=5,
        )
        tbl = [vlan_tag_op1, vlan_tag_op2, vlan_tag_op3]
        tblstr = str(vlan_tag_op1) + str(vlan_tag_op2) + str(vlan_tag_op3)

        onu._omci_response[OP.Get.value][
            ExtendedVlanTaggingOperationConfigurationData.class_id] = {
                entity_id:
                OmciFrame(
                    transaction_id=0,
                    message_type=OmciGetResponse.message_id,
                    omci_message=OmciGetResponse(
                        entity_class=
                        ExtendedVlanTaggingOperationConfigurationData.class_id,
                        entity_id=1,
                        success_code=RC.Success.value,
                        attributes_mask=
                        ExtendedVlanTaggingOperationConfigurationData.mask_for(
                            'received_frame_vlan_tagging_operation_table'),
                        data={
                            'received_frame_vlan_tagging_operation_table':
                            16 * len(tbl)
                        }))
            }

        rsp1 = binascii.a2b_hex(hexify(tblstr[0:OmciTableField.PDU_SIZE]))
        rsp2 = binascii.a2b_hex(hexify(tblstr[OmciTableField.PDU_SIZE:]))
        onu._omci_response[OP.GetNext.value][
            ExtendedVlanTaggingOperationConfigurationData.class_id] = {
                entity_id: {
                    0: {
                        'failures':
                        2,
                        'frame':
                        OmciFrame(
                            transaction_id=0,
                            message_type=OmciGetNextResponse.message_id,
                            omci_message=OmciGetNextResponse(
                                entity_class=
                                ExtendedVlanTaggingOperationConfigurationData.
                                class_id,
                                entity_id=1,
                                success_code=RC.Success.value,
                                attributes_mask=
                                ExtendedVlanTaggingOperationConfigurationData.
                                mask_for(
                                    'received_frame_vlan_tagging_operation_table'
                                ),
                                data={
                                    'received_frame_vlan_tagging_operation_table':
                                    rsp1
                                }))
                    },
                    1:
                    OmciFrame(
                        transaction_id=0,
                        message_type=OmciGetNextResponse.message_id,
                        omci_message=OmciGetNextResponse(
                            entity_class=
                            ExtendedVlanTaggingOperationConfigurationData.
                            class_id,
                            entity_id=1,
                            success_code=RC.Success.value,
                            attributes_mask=
                            ExtendedVlanTaggingOperationConfigurationData.
                            mask_for(
                                'received_frame_vlan_tagging_operation_table'),
                            data={
                                'received_frame_vlan_tagging_operation_table':
                                rsp2
                            }))
                }
            }

        omci_cc = self.onu_handler.omci_cc
        omci_cc.enabled = True

        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
            entity_id,
            attributes={'received_frame_vlan_tagging_operation_table': True})

        snapshot = self._snapshot_stats()

        frame = msg.get()
        d = omci_cc.send(frame, timeout=5.0)

        d.addCallbacks(self._is_omci_frame, self._default_errback,
                       [OmciGetResponse])
        d.addCallback(self._check_status, RC.Success)

        d.addCallback(self._check_stats, snapshot, 'tx_frames',
                      snapshot['tx_frames'] + 5)
        d.addCallback(self._check_stats, snapshot, 'rx_frames',
                      snapshot['rx_frames'] + 3)
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_tid',
                      snapshot['rx_unknown_tid'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_frames',
                      snapshot['rx_onu_frames'])
        d.addCallback(self._check_stats, snapshot, 'rx_onu_discards',
                      snapshot['rx_onu_discards'])
        d.addCallback(self._check_stats, snapshot, 'rx_unknown_me',
                      snapshot['rx_unknown_me'])
        d.addCallback(self._check_stats, snapshot, 'rx_timeouts',
                      snapshot['rx_timeouts'] + 2)
        d.addCallback(self._check_stats, snapshot, 'tx_errors',
                      snapshot['tx_errors'])
        d.addCallback(self._check_stats, snapshot, 'consecutive_errors', 0)
        d.addCallback(self._check_vlan_tag_op,
                      'received_frame_vlan_tagging_operation_table', tbl)

        return d