| /* |
| * Copyright 2018-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 devices |
| |
| import ( |
| "strconv" |
| "testing" |
| |
| "github.com/google/gopacket" |
| bbsim "github.com/opencord/bbsim/internal/bbsim/types" |
| omcilib "github.com/opencord/bbsim/internal/common/omci" |
| "github.com/opencord/omci-lib-go/v2" |
| me "github.com/opencord/omci-lib-go/v2/generated" |
| "github.com/opencord/voltha-protos/v5/go/openolt" |
| "gotest.tools/assert" |
| ) |
| |
| var mockAttr = me.AttributeValueMap{ |
| me.GemPortNetworkCtp_PortId: 0, |
| me.GemPortNetworkCtp_TContPointer: 0, |
| me.GemPortNetworkCtp_Direction: 0, |
| me.GemPortNetworkCtp_TrafficManagementPointerForUpstream: 0, |
| me.GemPortNetworkCtp_TrafficDescriptorProfilePointerForUpstream: 0, |
| me.GemPortNetworkCtp_PriorityQueuePointerForDownStream: 0, |
| me.GemPortNetworkCtp_TrafficDescriptorProfilePointerForDownstream: 0, |
| me.GemPortNetworkCtp_EncryptionKeyRing: 0, |
| } |
| |
| func makeOmciCreateRequest(t *testing.T) []byte { |
| omciReq := &omci.CreateRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.GemPortNetworkCtpClassID, |
| EntityInstance: 12, |
| }, |
| Attributes: mockAttr, |
| } |
| |
| omciPkt, err := omcilib.Serialize(omci.CreateRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciSetRequest(t *testing.T) []byte { |
| omciReq := &omci.SetRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.GemPortNetworkCtpClassID, |
| EntityInstance: 12, |
| }, |
| Attributes: mockAttr, |
| } |
| omciPkt, err := omcilib.Serialize(omci.SetRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciDeleteRequest(t *testing.T) []byte { |
| omciReq := &omci.DeleteRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.GemPortNetworkCtpClassID, |
| EntityInstance: 12, |
| }, |
| } |
| omciPkt, err := omcilib.Serialize(omci.DeleteRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciMibResetRequest(t *testing.T) []byte { |
| omciReq := &omci.MibResetRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.OnuDataClassID, |
| }, |
| } |
| omciPkt, err := omcilib.Serialize(omci.MibResetRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciStartSoftwareDownloadRequest(t *testing.T) []byte { |
| omciReq := &omci.StartSoftwareDownloadRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.SoftwareImageClassID, |
| }, |
| ImageSize: 31, |
| NumberOfCircuitPacks: 1, |
| WindowSize: 31, |
| CircuitPacks: []uint16{0}, |
| } |
| omciPkt, err := omcilib.Serialize(omci.StartSoftwareDownloadRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciEndSoftwareDownloadRequest(t *testing.T, imageSize uint32, imageCrc uint32) []byte { |
| omciReq := &omci.EndSoftwareDownloadRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.SoftwareImageClassID, |
| }, |
| NumberOfInstances: 1, |
| ImageInstances: []uint16{0}, |
| ImageSize: imageSize, |
| CRC32: imageCrc, |
| } |
| omciPkt, err := omcilib.Serialize(omci.EndSoftwareDownloadRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciActivateSoftwareRequest(t *testing.T) []byte { |
| omciReq := &omci.ActivateSoftwareRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.SoftwareImageClassID, |
| }, |
| } |
| omciPkt, err := omcilib.Serialize(omci.ActivateSoftwareRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciCommitSoftwareRequest(t *testing.T) []byte { |
| omciReq := &omci.CommitSoftwareRequest{ |
| MeBasePacket: omci.MeBasePacket{ |
| EntityClass: me.SoftwareImageClassID, |
| }, |
| } |
| omciPkt, err := omcilib.Serialize(omci.CommitSoftwareRequestType, omciReq, 66) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| |
| omciPkt, _ = omcilib.HexEncode(omciPkt) |
| |
| return omciPkt |
| } |
| |
| func makeOmciMessage(t *testing.T, onu *Onu, pkt []byte) bbsim.OmciMessage { |
| omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt) |
| if err != nil { |
| t.Fatal(err.Error()) |
| } |
| return bbsim.OmciMessage{ |
| OnuSN: onu.SerialNumber, |
| OnuID: onu.ID, |
| OmciPkt: omciPkt, |
| OmciMsg: omciMsg, |
| } |
| } |
| |
| func omciBytesToMsg(t *testing.T, data []byte) (*omci.OMCI, *gopacket.Packet) { |
| packet := gopacket.NewPacket(data, omci.LayerTypeOMCI, gopacket.NoCopy) |
| if packet == nil { |
| t.Fatal("could not decode rxMsg as OMCI") |
| } |
| omciLayer := packet.Layer(omci.LayerTypeOMCI) |
| if omciLayer == nil { |
| t.Fatal("could not decode omci layer") |
| } |
| omciMsg, ok := omciLayer.(*omci.OMCI) |
| if !ok { |
| t.Fatal("could not assign omci layer") |
| } |
| return omciMsg, &packet |
| } |
| |
| func omciToCreateResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.CreateResponse { |
| msgLayer := (*omciPkt).Layer(omci.LayerTypeCreateResponse) |
| if msgLayer == nil { |
| t.Fatal("omci Msg layer could not be detected for CreateResponse - handling of MibSyncChan stopped") |
| } |
| msgObj, msgOk := msgLayer.(*omci.CreateResponse) |
| if !msgOk { |
| t.Fatal("omci Msg layer could not be assigned for CreateResponse - handling of MibSyncChan stopped") |
| } |
| return msgObj |
| } |
| |
| func Test_MibDataSyncIncrease(t *testing.T) { |
| onu := createTestOnu() |
| |
| assert.Equal(t, onu.MibDataSync, uint8(0)) |
| |
| stream := &mockStream{ |
| Calls: make(map[int]*openolt.Indication), |
| } |
| |
| // send a Create and check that MDS has been increased |
| err := onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(1)) |
| |
| // send a Set and check that MDS has been increased |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciSetRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(2)) |
| |
| // send a Delete and check that MDS has been increased |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciDeleteRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(3)) |
| |
| // Start software download |
| onu.InternalState.SetState(OnuStateEnabled) |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciStartSoftwareDownloadRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(4)) |
| |
| // End software download |
| onu.ImageSoftwareExpectedSections = 31 |
| onu.ImageSoftwareReceivedSections = 31 // we fake that we have received all the download section we expect |
| onu.ImageSectionData = []byte{111, 114, 116, 116, 105, 116, 111, 114, 32, 113, 117, 105, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101} |
| onu.InternalState.SetState(OnuStateImageDownloadInProgress) |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 1523894119)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(5)) |
| |
| // Activate software |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciActivateSoftwareRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(6)) |
| |
| // Commit software |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCommitSoftwareRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(7)) |
| } |
| |
| func Test_MibDataSyncReset(t *testing.T) { |
| onu := createMockOnu(1, 1) |
| onu.MibDataSync = 192 |
| assert.Equal(t, onu.MibDataSync, uint8(192)) |
| |
| stream := &mockStream{ |
| Calls: make(map[int]*openolt.Indication), |
| } |
| |
| // create a GemPort and an AllocId for this ONU |
| onu.PonPort.storeGemPort(1024, onu.SerialNumber) |
| onu.PonPort.storeAllocId(1024, 1024, 0x8001, 1024, onu.SerialNumber) |
| |
| // send a MibReset |
| err := onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciMibResetRequest(t)), stream) |
| assert.NilError(t, err) |
| |
| // check that MDS has reset to 0 |
| assert.Equal(t, onu.MibDataSync, uint8(0)) |
| |
| // check that GemPort and AllocId have been removed |
| assert.Equal(t, len(onu.PonPort.AllocatedGemPorts), 0) |
| assert.Equal(t, len(onu.PonPort.AllocatedAllocIds), 0) |
| } |
| |
| func Test_MibDataSyncRotation(t *testing.T) { |
| onu := createMockOnu(1, 1) |
| onu.MibDataSync = 255 |
| assert.Equal(t, onu.MibDataSync, uint8(255)) |
| |
| stream := &mockStream{ |
| Calls: make(map[int]*openolt.Indication), |
| } |
| |
| // send a request that increases the MDS, but once we're at 255 we should go back to 0 (8bit) |
| err := onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciDeleteRequest(t)), stream) |
| assert.NilError(t, err) |
| assert.Equal(t, onu.MibDataSync, uint8(0)) |
| } |
| |
| func Test_MibDataSyncInvalidation(t *testing.T) { |
| onu := createMockOnu(1, 1) |
| onu.MibDataSync = 250 |
| assert.Equal(t, onu.MibDataSync, uint8(250)) |
| |
| onu.InvalidateMibDataSync() |
| |
| // check if the MDS has been changed |
| assert.Assert(t, onu.MibDataSync != uint8(250)) |
| |
| // the MDS has to be between 1 and 255, since 0 is valid for a reset |
| assert.Assert(t, onu.MibDataSync > 0) |
| // assert.Assert(t, onu.MibDataSync <= 255) // This is always true since 'MibDataSync' is uint8 |
| } |
| |
| func Test_GemPortValidation(t *testing.T) { |
| |
| // setup |
| onu := createMockOnu(1, 1) |
| |
| stream := &mockStream{ |
| Calls: make(map[int]*openolt.Indication), |
| } |
| |
| // create a gem port via OMCI (gemPortId 12) |
| err := onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream) |
| assert.NilError(t, err) |
| |
| // the first time we created the gemPort |
| // the MDS should be incremented |
| assert.Equal(t, stream.CallCount, 1) |
| assert.Equal(t, onu.MibDataSync, uint8(1)) |
| |
| // and the OMCI response status should be me.Success |
| indication := stream.Calls[1].GetOmciInd() |
| _, omciPkt := omciBytesToMsg(t, indication.Pkt) |
| responseLayer := omciToCreateResponse(t, omciPkt) |
| assert.Equal(t, responseLayer.Result, me.Success) |
| |
| // send a request to create the same gem port via OMCI (gemPortId 12) |
| err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream) |
| assert.NilError(t, err) |
| |
| // this time the MDS should not be incremented |
| assert.Equal(t, stream.CallCount, 2) |
| assert.Equal(t, onu.MibDataSync, uint8(1)) |
| |
| // and the OMCI response status should be me.ProcessingError |
| _, omciPkt = omciBytesToMsg(t, stream.Calls[2].GetOmciInd().Pkt) |
| responseLayer = omciToCreateResponse(t, omciPkt) |
| assert.Equal(t, responseLayer.Result, me.ProcessingError) |
| } |
| |
| func Test_OmciResponseRate(t *testing.T) { |
| |
| onu := createMockOnu(1, 1) |
| |
| for onu.OmciResponseRate = 0; onu.OmciResponseRate <= maxOmciMsgCounter; onu.OmciResponseRate++ { |
| stream := &mockStream{ |
| Calls: make(map[int]*openolt.Indication), |
| } |
| //send ten OMCI requests and check if number of responses is only equal to onu.OmciResponseRate |
| for i := 0; i < 10; i++ { |
| // we are not checking the error as we're expecting them (some messages should be skipped) |
| _ = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciSetRequest(t)), stream) |
| } |
| assert.Equal(t, stream.CallCount, int(onu.OmciResponseRate)) |
| } |
| } |
| |
| func Test_EndSoftwareDownloadRequestHandling(t *testing.T) { |
| onu := createTestOnu() |
| |
| // test EndSoftwareDownloadRequest in case of abort |
| onu.ImageSoftwareReceivedSections = 2 |
| imageCrc, _ := strconv.ParseInt("FFFFFFFF", 16, 64) |
| msg := makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 0, uint32(imageCrc))) |
| res := onu.handleEndSoftwareDownloadRequest(msg) |
| assert.Equal(t, res, true) |
| assert.Equal(t, onu.ImageSoftwareReceivedSections, uint32(0)) |
| |
| // test EndSoftwareDownloadRequest if we received less sections than expected |
| onu.ImageSoftwareExpectedSections = 2 |
| onu.ImageSoftwareReceivedSections = 1 |
| msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 2, 2)) |
| res = onu.handleEndSoftwareDownloadRequest(msg) |
| assert.Equal(t, res, false) |
| |
| // test CRC Mismatch |
| onu.ImageSectionData = []byte{111, 114, 116, 116, 105, 116, 111, 114, 32, 113, 117, 105, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101} |
| onu.ImageSoftwareExpectedSections = 2 |
| onu.ImageSoftwareReceivedSections = 2 |
| msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 12)) |
| res = onu.handleEndSoftwareDownloadRequest(msg) |
| assert.Equal(t, res, false) |
| |
| // if it's a valid case then set the StandbyImageVersion |
| onu.InDownloadImageVersion = "DownloadedImage" |
| msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 1523894119)) |
| res = onu.handleEndSoftwareDownloadRequest(msg) |
| assert.Equal(t, res, true) |
| assert.Equal(t, onu.StandbyImageVersion, "DownloadedImage") |
| } |