blob: 482c0b86eeed0d83584d28af3644b85a3b7c419a [file] [log] [blame]
/*
* Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
* Copyright 2020-present Open Networking Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package omci_test
import (
"github.com/google/gopacket"
. "github.com/opencord/omci-lib-go/v2"
me "github.com/opencord/omci-lib-go/v2/generated"
"github.com/stretchr/testify/assert"
"testing"
)
var relaxDecodeSupportedResponses = []me.MsgType{
// me.Get,
me.MibUploadNext,
}
func canRelax(arr []me.MsgType, msgType me.MsgType) bool {
for _, item := range arr {
if item == msgType {
return true
}
}
return false
}
func TestAllTypesRelaxedDecodeSupport(t *testing.T) {
// Requests (none are supported yet)
for _, msgType := range allMsgTypes {
assert.Error(t, me.SetRelaxedDecode(msgType, true, true))
assert.False(t, me.GetRelaxedDecode(msgType, true))
}
// Responses (only a couple are supported at this time)
for _, msgType := range allMsgTypes {
if canRelax(relaxDecodeSupportedResponses, msgType) {
// Default is True if it is supported
assert.True(t, me.GetRelaxedDecode(msgType, false))
// Set False
assert.NoError(t, me.SetRelaxedDecode(msgType, false, false))
assert.False(t, me.GetRelaxedDecode(msgType, false))
// Set back to True
assert.NoError(t, me.SetRelaxedDecode(msgType, false, true))
assert.True(t, me.GetRelaxedDecode(msgType, false))
} else {
// Default is False
assert.False(t, me.GetRelaxedDecode(msgType, false))
assert.Error(t, me.SetRelaxedDecode(msgType, false, true))
assert.Error(t, me.SetRelaxedDecode(msgType, false, false))
}
}
}
// TestMibUploadNextResponseRelaxedDecode will decode a frame with 'new' unknown
// attributes at the end (fake ones for this test) and should fail. Then it will
// enable relax decode and should be able to successfully decode the parts that
// it knows and have access to the rest.
func TestMibUploadNextResponseRelaxedDecode(t *testing.T) {
// Test msg has OLT-G ME that normally only has 4 attributes defined. Since several are
// pretty big and would normally take at least 3 MIB upload next frames. So in
// this one it has the last 'known' one, plus two new ones.
extraTrailer := "123400001234000000000000"
goodAttribute := "123456780a090807060504030201"
mibUploadNextLayer := "00020000008300001c00" + goodAttribute + extraTrailer
goodMessage := "02862e0a" + mibUploadNextLayer + "00000028"
data, err := stringToPacket(goodMessage)
assert.NoError(t, err)
extraTrailerData, _ := stringToPacket(extraTrailer)
assert.NotNil(t, extraTrailerData)
mibUploadNextLayerData, _ := stringToPacket(mibUploadNextLayer)
assert.NotNil(t, mibUploadNextLayerData)
goodAttributeData, _ := stringToPacket(goodAttribute)
assert.NotNil(t, goodAttributeData)
// Make sure relaxed decode is disabled
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, false))
assert.False(t, me.GetRelaxedDecode(me.MibUploadNext, false))
// Should get a packet but there should also be an error layer after the OMCI layer
packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
assert.Equal(t, LayerTypeOMCI, omciMsg.LayerType())
assert.Equal(t, LayerTypeOMCI, omciMsg.CanDecode())
assert.Equal(t, LayerTypeMibUploadNextResponse, omciMsg.NextLayerType())
assert.Equal(t, uint16(0x0286), omciMsg.TransactionID)
assert.Equal(t, MibUploadNextResponseType, omciMsg.MessageType)
assert.Equal(t, BaselineIdent, omciMsg.DeviceIdentifier)
assert.Equal(t, uint16(40), omciMsg.Length)
// Without relaxed decode, the MIB Upload Next Response cannot be decoded further
// but can get the error layer and it's contents (which is the entire MIB Upload Response data
msgLayer := packet.Layer(LayerTypeMibUploadNextResponse)
assert.Nil(t, msgLayer)
errLayer := packet.Layer(gopacket.LayerTypeDecodeFailure)
assert.NotNil(t, errLayer)
assert.Nil(t, errLayer.LayerPayload())
errContents := errLayer.LayerContents()
assert.NotNil(t, errContents)
assert.Equal(t, mibUploadNextLayerData, errContents)
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Now turn on relaxed decode and you can now go further into the packet
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, true))
assert.True(t, me.GetRelaxedDecode(me.MibUploadNext, false))
packet = gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer = packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok = omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
// Skipping the test of OMCI layer values. It is same as above
//
// Get that message layer that has data that could be decoded. If relaxed decode was
// not enable, this would have returned a 'nil' value
msgLayer = packet.Layer(LayerTypeMibUploadNextResponse)
assert.NotNil(t, msgLayer)
response, ok2 := msgLayer.(*MibUploadNextResponse)
assert.True(t, ok2)
assert.NotNil(t, response)
assert.Equal(t, LayerTypeMibUploadNextResponse, response.LayerType())
assert.Equal(t, LayerTypeMibUploadNextResponse, response.CanDecode())
assert.Equal(t, me.OltGClassID, response.ReportedME.GetClassID())
assert.Equal(t, uint16(0), response.ReportedME.GetEntityID())
// The attribute mask decoded at this layer only contains the attributes we
// could successfully decode
assert.Equal(t, uint16(0x1000), response.ReportedME.GetAttributeMask())
attributes := me.AttributeValueMap{
"TimeOfDayInformation": goodAttributeData, // NOTE: This is binary data for the comparison below
}
for name, value := range attributes {
pktValue, err := response.ReportedME.GetAttribute(name)
assert.Nil(t, err)
assert.Equal(t, pktValue, value)
}
assert.Nil(t, response.AdditionalMEs)
////////////////////////////////////////////////////////////////////////////
// Here is the new functionality. In order to store both a well decoded
// MIB UPLOAD NEXT response layer, along with a relaxed decode error, the
// layer addition has to be done in a specific way and an error returned.
//
// Note that the previous line (below) worked in the code above
//
// response, ok2 := msgLayer.(*MibUploadNextResponse)
//
// If you did not care about what the relaxed decode found out, just proceed
// on as normal. However, since you enabled relaxed decoding of the unknown
// attributes, here is where you can pull extra information from.
//
// The first way is to just try and see if that error layer was decoded
//
// if unknownAttrLayer = packet.Layer(LayerTypeUnknownAttributes); unknownAttrLayer != nil {
// log.warning(HEY! Got some unknown attributes to this ME: '%v', unknownAttrLayer)
//
// unknownAttributes, ok2 := msgLayer.(*UnknownAttributes); ok {
// //
// // Since some extended messages can actually return multiple managed entities,
// // all ME's with unknown attributes need to be uniquely identified
// //
// for _, unknown := range unknownAttibutes.Attributes {
// whichME := unknown.EntityClass // ClassID
// whichInst := unknown.EntityInstance // uint16
// unknownMask := unknown.AttributeMask // uint16
// unknownBlob := unknown.Attributes // []byte
//
// // Unless this is the extended message set and only a single attribute
// // mask bit is set, you really do not know what possible kind of data
// // type the attribute is...
// }
// }
// }
/////////////////////////////////////
assert.NotEqual(t, gopacket.LayerTypePayload, response.NextLayerType())
assert.Equal(t, LayerTypeUnknownAttributes, response.NextLayerType())
unknownAttrLayer := packet.Layer(LayerTypeUnknownAttributes)
assert.NotNil(t, unknownAttrLayer)
unknown, ok2 := unknownAttrLayer.(*UnknownAttributes)
assert.True(t, ok2)
assert.NotNil(t, unknown)
assert.Equal(t, LayerTypeUnknownAttributes, unknown.LayerType())
assert.Equal(t, LayerTypeUnknownAttributes, unknown.CanDecode())
assert.Equal(t, gopacket.LayerTypeZero, unknown.NextLayerType())
// Only one Managed entity was in this response and had a bad attribute
assert.Equal(t, 1, len(unknown.Attributes))
assert.Equal(t, me.OltGClassID, unknown.Attributes[0].EntityClass)
assert.Equal(t, uint16(0), unknown.Attributes[0].EntityInstance)
assert.Equal(t, uint16(0x0c00), unknown.Attributes[0].AttributeMask)
assert.Equal(t, extraTrailerData, unknown.Attributes[0].AttributeData)
}
// TestMibUploadNextResponseExtendedRelaxedDecode is the extended message
// set test of the test above (just one Managed Entity)
func TestMibUploadNextResponseExtendedRelaxedDecode(t *testing.T) {
// Test msg has OLT-G ME that normally only has 4 attributes defined. Since several are
// pretty big and would normally take at least 3 MIB upload next frames. So in
// this one it has the last 'known' one, plus two new ones.
extraTrailer := "123400001234" // 6 octets
goodAttribute := "123456780a090807060504030201" // 14 octets
mibUploadNextLayer := "00020000" + "001c" +
"0014" +
"008300001c00" + // 6 octets
goodAttribute + extraTrailer // 14 + 6 octets
goodMessage := "02862e0b" + mibUploadNextLayer
data, err := stringToPacket(goodMessage)
assert.NoError(t, err)
extraTrailerData, _ := stringToPacket(extraTrailer)
assert.NotNil(t, extraTrailerData)
mibUploadNextLayerData, _ := stringToPacket(mibUploadNextLayer)
assert.NotNil(t, mibUploadNextLayerData)
goodAttributeData, _ := stringToPacket(goodAttribute)
assert.NotNil(t, goodAttributeData)
// Make sure relaxed decode is disabled
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, false))
assert.False(t, me.GetRelaxedDecode(me.MibUploadNext, false))
// Should get a packet but there should also be an error layer after the OMCI layer
packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
assert.Equal(t, LayerTypeOMCI, omciMsg.LayerType())
assert.Equal(t, LayerTypeOMCI, omciMsg.CanDecode())
assert.Equal(t, LayerTypeMibUploadNextResponse, omciMsg.NextLayerType())
assert.Equal(t, uint16(0x0286), omciMsg.TransactionID)
assert.Equal(t, MibUploadNextResponseType, omciMsg.MessageType)
assert.Equal(t, ExtendedIdent, omciMsg.DeviceIdentifier)
assert.Equal(t, uint16(28), omciMsg.Length)
// Without relaxed decode, the MIB Upload Next Response cannot be decoded further
// but can get the error layer and it's contents (which is the entire MIB Upload Response data
msgLayer := packet.Layer(LayerTypeMibUploadNextResponse)
assert.Nil(t, msgLayer)
errLayer := packet.Layer(gopacket.LayerTypeDecodeFailure)
assert.NotNil(t, errLayer)
assert.Nil(t, errLayer.LayerPayload())
errContents := errLayer.LayerContents()
assert.NotNil(t, errContents)
assert.Equal(t, mibUploadNextLayerData, errContents)
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Now turn on relaxed decode and you can now go further into the packet
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, true))
assert.True(t, me.GetRelaxedDecode(me.MibUploadNext, false))
packet = gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer = packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok = omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
// Skipping the test of OMCI layer values. It is same as above
//
// Get that message layer that has data that could be decoded
msgLayer = packet.Layer(LayerTypeMibUploadNextResponse)
assert.NotNil(t, msgLayer)
response, ok2 := msgLayer.(*MibUploadNextResponse)
assert.True(t, ok2)
assert.NotNil(t, response)
assert.Equal(t, LayerTypeMibUploadNextResponse, response.LayerType())
assert.Equal(t, LayerTypeMibUploadNextResponse, response.CanDecode())
assert.Equal(t, me.OltGClassID, response.ReportedME.GetClassID())
assert.Equal(t, uint16(0), response.ReportedME.GetEntityID())
// The attribute mask decoded at this layer only contains the attributes we
// could successfully decode
assert.Equal(t, uint16(0x1000), response.ReportedME.GetAttributeMask())
attributes := me.AttributeValueMap{
"TimeOfDayInformation": goodAttributeData, // NOTE: This is binary data for the comparison below
}
for name, value := range attributes {
pktValue, err := response.ReportedME.GetAttribute(name)
assert.Nil(t, err)
assert.Equal(t, pktValue, value)
}
////////////////////////////////////////////////////////////////////////////
// Here is the new functionality. In order to store both a well decoded
// MIB UPLOAD NEXT response layer, along with a relaxed decode error, the
// layer addition has to be done in a specific way and an error returned.
//
// Note that the previous line (below) worked in the code above
//
// response, ok2 := msgLayer.(*MibUploadNextResponse)
//
// If you did not care about what the relaxed decode found out, just proceed
// on as normal. However, since you enabled relaxed decoding of the unknown
// attributes, here is where you can pull extra information from.
//
// The first way is to just try and see if that error layer was decoded
//
// if unknownAttrLayer = packet.Layer(LayerTypeUnknownAttributes); unknownAttrLayer != nil {
// log.warning(HEY! Got some unknown attributes to this ME: '%v', unknownAttrLayer)
//
// unknownAttributes, ok2 := msgLayer.(*UnknownAttributes); ok {
// //
// // Since some extended messages can actually return multiple managed entities,
// // all ME's with unknown attributes need to be uniquely identified
// //
// for _, unknown := range unknownAttibutes.Attributes {
// whichME := unknown.EntityClass // ClassID
// whichInst := unknown.EntityInstance // uint16
// unknownMask := unknown.AttributeMask // uint16
// unknownBlob := unknown.Attributes // []byte
//
// // Unless this is the extended message set and only a single attribute
// // mask bit is set, you really do not know what possible kind of data
// // type the attribute is...
// }
// }
// }
/////////////////////////////////////
assert.NotEqual(t, gopacket.LayerTypePayload, response.NextLayerType())
assert.Equal(t, LayerTypeUnknownAttributes, response.NextLayerType())
unknownAttrLayer := packet.Layer(LayerTypeUnknownAttributes)
assert.NotNil(t, unknownAttrLayer)
unknown, ok2 := unknownAttrLayer.(*UnknownAttributes)
assert.True(t, ok2)
assert.NotNil(t, unknown)
assert.Equal(t, LayerTypeUnknownAttributes, unknown.LayerType())
assert.Equal(t, LayerTypeUnknownAttributes, unknown.CanDecode())
assert.Equal(t, gopacket.LayerTypeZero, unknown.NextLayerType())
// Only one Managed entity was in this response and had a bad attribute
assert.Equal(t, 1, len(unknown.Attributes))
assert.Equal(t, me.OltGClassID, unknown.Attributes[0].EntityClass)
assert.Equal(t, uint16(0), unknown.Attributes[0].EntityInstance)
assert.Equal(t, uint16(0x0c00), unknown.Attributes[0].AttributeMask)
assert.Equal(t, uint16(0x0c00), unknown.Attributes[0].AttributeMask)
assert.Equal(t, extraTrailerData, unknown.Attributes[0].AttributeData)
}
// TestMibUploadNextResponseExtendedRelaxedDecode is the extended message
// set test of the test above (with two Managed Entity where both have bad attributes)
func TestMibUploadNextResponseExtendedRelaxedDecodeTwoMEs(t *testing.T) {
// Test msg has OLT-G ME that normally only has 4 attributes defined. Since several are
// pretty big and would normally take at least 3 MIB upload next frames. So in
// this one it has the last 'known' one, plus two new ones.
extraTrailer1 := "123400001234" // 6 octets
extraTrailer2 := "432100004321" // 6 octets
goodAttribute := "123456780a090807060504030201" // 14 octets
mibUploadNextLayer := "00020000" + "0038" +
"0014" +
"008300001c00" + // 6 octets
goodAttribute + extraTrailer1 + // 14 + 6 octets
"0014" +
"008300011c00" + // 6 octets (entity ID 1 which is invalid for OLT-g, but this is a test)
goodAttribute + extraTrailer2 // 14 + 6 octets
goodMessage := "02862e0b" + mibUploadNextLayer
data, err := stringToPacket(goodMessage)
assert.NoError(t, err)
extraTrailerData1, _ := stringToPacket(extraTrailer1)
assert.NotNil(t, extraTrailerData1)
extraTrailerData2, _ := stringToPacket(extraTrailer2)
assert.NotNil(t, extraTrailerData2)
mibUploadNextLayerData, _ := stringToPacket(mibUploadNextLayer)
assert.NotNil(t, mibUploadNextLayerData)
goodAttributeData, _ := stringToPacket(goodAttribute)
assert.NotNil(t, goodAttributeData)
// Make sure relaxed decode is disabled
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, false))
assert.False(t, me.GetRelaxedDecode(me.MibUploadNext, false))
// Should get a packet but there should also be an error layer after the OMCI layer
packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
assert.Equal(t, LayerTypeOMCI, omciMsg.LayerType())
assert.Equal(t, LayerTypeOMCI, omciMsg.CanDecode())
assert.Equal(t, LayerTypeMibUploadNextResponse, omciMsg.NextLayerType())
assert.Equal(t, uint16(0x0286), omciMsg.TransactionID)
assert.Equal(t, MibUploadNextResponseType, omciMsg.MessageType)
assert.Equal(t, ExtendedIdent, omciMsg.DeviceIdentifier)
assert.Equal(t, uint16(56), omciMsg.Length)
// Without relaxed decode, the MIB Upload Next Response cannot be decoded further
// but can get the error layer and it's contents (which is the entire MIB Upload Response data
msgLayer := packet.Layer(LayerTypeMibUploadNextResponse)
assert.Nil(t, msgLayer)
errLayer := packet.Layer(gopacket.LayerTypeDecodeFailure)
assert.NotNil(t, errLayer)
assert.Nil(t, errLayer.LayerPayload())
errContents := errLayer.LayerContents()
assert.NotNil(t, errContents)
assert.Equal(t, mibUploadNextLayerData, errContents)
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Now turn on relaxed decode and you can now go further into the packet
assert.NoError(t, me.SetRelaxedDecode(me.MibUploadNext, false, true))
assert.True(t, me.GetRelaxedDecode(me.MibUploadNext, false))
packet = gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
assert.NotNil(t, packet)
omciLayer = packet.Layer(LayerTypeOMCI)
assert.NotNil(t, omciLayer)
omciMsg, ok = omciLayer.(*OMCI)
assert.True(t, ok)
assert.NotNil(t, omciMsg)
// Skipping the test of OMCI layer values. It is same as above
//
// Get that message layer that has data that could be decoded
msgLayer = packet.Layer(LayerTypeMibUploadNextResponse)
assert.NotNil(t, msgLayer)
response, ok2 := msgLayer.(*MibUploadNextResponse)
assert.True(t, ok2)
assert.NotNil(t, response)
assert.Equal(t, LayerTypeMibUploadNextResponse, response.LayerType())
assert.Equal(t, LayerTypeMibUploadNextResponse, response.CanDecode())
assert.Equal(t, me.OltGClassID, response.ReportedME.GetClassID())
assert.Equal(t, uint16(0), response.ReportedME.GetEntityID())
// The attribute mask decoded at this layer only contains the attributes we
// could successfully decode
assert.Equal(t, uint16(0x1000), response.ReportedME.GetAttributeMask())
attributes := me.AttributeValueMap{
"TimeOfDayInformation": goodAttributeData, // NOTE: This is binary data for the comparison below
}
for name, value := range attributes {
pktValue, err := response.ReportedME.GetAttribute(name)
assert.Nil(t, err)
assert.Equal(t, pktValue, value)
}
// Now the second ME in the response
assert.NotNil(t, response.AdditionalMEs)
assert.Equal(t, 1, len(response.AdditionalMEs))
////////////////////////////////////////////////////////////////////////////
// Here is the new functionality. In order to store both a well decoded
// MIB UPLOAD NEXT response layer, along with a relaxed decode error, the
// layer addition has to be done in a specific way and an error returned.
//
// Note that the previous line (below) worked in the code above
//
// response, ok2 := msgLayer.(*MibUploadNextResponse)
//
// If you did not care about what the relaxed decode found out, just proceed
// on as normal. However, since you enabled relaxed decoding of the unknown
// attributes, here is where you can pull extra information from.
//
// The first way is to just try and see if that error layer was decoded
//
// if unknownAttrLayer = packet.Layer(LayerTypeUnknownAttributes); unknownAttrLayer != nil {
// log.warning(HEY! Got some unknown attributes to this ME: '%v', unknownAttrLayer)
//
// unknownAttributes, ok2 := msgLayer.(*UnknownAttributes); ok {
// //
// // Since some extended messages can actually return multiple managed entities,
// // all ME's with unknown attributes need to be uniquely identified
// //
// for _, unknown := range unknownAttibutes.Attributes {
// whichME := unknown.EntityClass // ClassID
// whichInst := unknown.EntityInstance // uint16
// unknownMask := unknown.AttributeMask // uint16
// unknownBlob := unknown.Attributes // []byte
//
// // Unless this is the extended message set and only a single attribute
// // mask bit is set, you really do not know what possible kind of data
// // type the attribute is...
// }
// }
// }
/////////////////////////////////////
assert.NotEqual(t, gopacket.LayerTypePayload, response.NextLayerType())
assert.Equal(t, LayerTypeUnknownAttributes, response.NextLayerType())
unknownAttrLayer := packet.Layer(LayerTypeUnknownAttributes)
assert.NotNil(t, unknownAttrLayer)
unknown, ok2 := unknownAttrLayer.(*UnknownAttributes)
assert.True(t, ok2)
assert.NotNil(t, unknown)
assert.Equal(t, LayerTypeUnknownAttributes, unknown.LayerType())
assert.Equal(t, LayerTypeUnknownAttributes, unknown.CanDecode())
assert.Equal(t, gopacket.LayerTypeZero, unknown.NextLayerType())
// Only one Managed entity was in this response and had a bad attribute
assert.Equal(t, 2, len(unknown.Attributes))
assert.Equal(t, me.OltGClassID, unknown.Attributes[0].EntityClass)
assert.Equal(t, uint16(0), unknown.Attributes[0].EntityInstance)
assert.Equal(t, uint16(0x0c00), unknown.Attributes[0].AttributeMask)
assert.Equal(t, extraTrailerData1, unknown.Attributes[0].AttributeData)
assert.Equal(t, me.OltGClassID, unknown.Attributes[1].EntityClass)
assert.Equal(t, uint16(1), unknown.Attributes[1].EntityInstance)
assert.Equal(t, uint16(0x0c00), unknown.Attributes[1].AttributeMask)
assert.Equal(t, extraTrailerData2, unknown.Attributes[1].AttributeData)
errStr := unknown.Error()
assert.NotNil(t, errStr)
assert.Greater(t, len(errStr.Error()), 0)
}