-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into bgpIsisRedist
Showing
6 changed files
with
639 additions
and
2 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
...platform/transceiver/logical_channels/tests/zrp_logical_channels_test/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
.../platform/transceiver/logical_channels/tests/zrp_logical_channels_test/metadata.textproto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto | ||
# proto-message: Metadata | ||
uuid: "e5b469c9-f765-4f95-b3dc-af4c926309f5" | ||
plan_id: "TRANSCEIVER-11 (400ZR_PLUS)" | ||
description: "Telemetry: 400ZR_PLUS Optics logical channels provisioning and related telemetry." | ||
testbed: TESTBED_DUT_400ZR_PLUS | ||
platform_exceptions: { | ||
platform: { | ||
vendor: ARISTA | ||
} | ||
deviations: { | ||
interface_enabled: true | ||
default_network_instance: "default" | ||
missing_port_to_optical_channel_component_mapping: true | ||
channel_assignment_rate_class_parameters_unsupported: true | ||
} | ||
} | ||
platform_exceptions: { | ||
platform: { | ||
vendor: CISCO | ||
} | ||
deviations: { | ||
otn_channel_trib_unsupported: true | ||
eth_channel_ingress_parameters_unsupported: true | ||
eth_channel_assignment_cisco_numbering: true | ||
otn_channel_assignment_cisco_numbering: true | ||
} | ||
} |
280 changes: 280 additions & 0 deletions
280
...transceiver/logical_channels/tests/zrp_logical_channels_test/zrp_logical_channels_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
package zrp_logical_channels_test | ||
|
||
import ( | ||
"flag" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/openconfig/featureprofiles/internal/attrs" | ||
"github.com/openconfig/featureprofiles/internal/cfgplugins" | ||
"github.com/openconfig/featureprofiles/internal/components" | ||
"github.com/openconfig/featureprofiles/internal/deviations" | ||
"github.com/openconfig/featureprofiles/internal/fptest" | ||
"github.com/openconfig/featureprofiles/internal/samplestream" | ||
"github.com/openconfig/ondatra" | ||
"github.com/openconfig/ondatra/gnmi" | ||
"github.com/openconfig/ondatra/gnmi/oc" | ||
) | ||
|
||
const ( | ||
targetOutputPower = -3 | ||
frequency = 193100000 | ||
samplingInterval = 10 * time.Second | ||
timeout = 10 * time.Minute | ||
otnIndex1 = uint32(4001) | ||
otnIndex2 = uint32(4002) | ||
ethernetIndex1 = uint32(40001) | ||
ethernetIndex2 = uint32(40002) | ||
) | ||
|
||
var ( | ||
dutPort1 = attrs.Attributes{ | ||
Desc: "dutPort1", | ||
IPv4: "192.0.2.1", | ||
IPv4Len: 30, | ||
} | ||
dutPort2 = attrs.Attributes{ | ||
Desc: "dutPort2", | ||
IPv4: "192.0.2.5", | ||
IPv4Len: 30, | ||
} | ||
operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") | ||
operationalMode uint16 | ||
) | ||
|
||
type testcase struct { | ||
desc string | ||
got any | ||
want any | ||
} | ||
|
||
func TestMain(m *testing.M) { | ||
fptest.RunTests(m) | ||
} | ||
|
||
func Test400ZRLogicalChannels(t *testing.T) { | ||
dut := ondatra.DUT(t, "dut") | ||
if operationalModeFlag != nil { | ||
operationalMode = uint16(*operationalModeFlag) | ||
} else { | ||
t.Fatalf("Please specify the vendor-specific operational-mode flag") | ||
} | ||
p1 := dut.Port(t, "port1") | ||
p2 := dut.Port(t, "port2") | ||
|
||
fptest.ConfigureDefaultNetworkInstance(t, dut) | ||
|
||
gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) | ||
|
||
oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) | ||
oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) | ||
tr1 := gnmi.Get(t, dut, gnmi.OC().Interface(p1.Name()).Transceiver().State()) | ||
tr2 := gnmi.Get(t, dut, gnmi.OC().Interface(p2.Name()).Transceiver().State()) | ||
|
||
cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetOutputPower, operationalMode) | ||
cfgplugins.ConfigOTNChannel(t, dut, oc1, otnIndex1, ethernetIndex1) | ||
cfgplugins.ConfigETHChannel(t, dut, p1.Name(), tr1, otnIndex1, ethernetIndex1) | ||
cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, operationalMode) | ||
cfgplugins.ConfigOTNChannel(t, dut, oc2, otnIndex2, ethernetIndex2) | ||
cfgplugins.ConfigETHChannel(t, dut, p2.Name(), tr2, otnIndex2, ethernetIndex2) | ||
|
||
ethChan1 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(ethernetIndex1).State(), samplingInterval) | ||
defer ethChan1.Close() | ||
ethChan2 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(ethernetIndex2).State(), samplingInterval) | ||
defer ethChan2.Close() | ||
otnChan1 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex1).State(), samplingInterval) | ||
defer otnChan1.Close() | ||
otnChan2 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex2).State(), samplingInterval) | ||
defer otnChan2.Close() | ||
|
||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
|
||
validateEthernetChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, ethChan1) | ||
validateEthernetChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, ethChan2) | ||
validateOTNChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, oc1, otnChan1) | ||
validateOTNChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, oc2, otnChan2) | ||
} | ||
|
||
func validateEthernetChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx, ethernetChIdx uint32, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { | ||
val := stream.Next() // value received in the gnmi subscription within 10 seconds | ||
if val == nil { | ||
t.Fatalf("Ethernet Channel telemetry stream not received in last 10 seconds") | ||
} | ||
ec, ok := val.Val() | ||
if !ok { | ||
t.Fatalf("Ethernet Channel telemetry stream empty in last 10 seconds") | ||
} | ||
tcs := []testcase{ | ||
{ | ||
desc: "Index", | ||
got: ec.GetIndex(), | ||
want: ethernetChIdx, | ||
}, | ||
{ | ||
desc: "Description", | ||
got: ec.GetDescription(), | ||
want: "ETH Logical Channel", | ||
}, | ||
{ | ||
desc: "Logical Channel Type", | ||
got: ec.GetLogicalChannelType().String(), | ||
want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_ETHERNET.String(), | ||
}, | ||
{ | ||
desc: "Trib Protocol", | ||
got: ec.GetTribProtocol().String(), | ||
want: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE.String(), | ||
}, | ||
} | ||
var assignmentIndexTestcases []testcase | ||
|
||
index := 0 | ||
if deviations.EthChannelAssignmentCiscoNumbering(dut) { | ||
index = 1 | ||
} | ||
|
||
assignment := ec.GetAssignment(uint32(index)) | ||
assignmentIndexTestcases = []testcase{ | ||
{ | ||
desc: "Assignment: Index", | ||
got: assignment.GetIndex(), | ||
want: uint32(index), | ||
}, | ||
{ | ||
desc: "Assignment: Logical Channel", | ||
got: assignment.GetLogicalChannel(), | ||
want: otnChIdx, | ||
}, | ||
{ | ||
desc: "Assignment: Description", | ||
got: assignment.GetDescription(), | ||
want: "ETH to OTN", | ||
}, | ||
{ | ||
desc: "Assignment: Allocation", | ||
got: assignment.GetAllocation(), | ||
want: float64(400), | ||
}, | ||
{ | ||
desc: "Assignment: Type", | ||
got: assignment.GetAssignmentType().String(), | ||
want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), | ||
}, | ||
} | ||
tcs = append(tcs, assignmentIndexTestcases...) | ||
for _, tc := range tcs { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
if diff := cmp.Diff(tc.got, tc.want); diff != "" { | ||
t.Errorf("Ethernet Logical Channel: %s, diff (-got +want):\n%s", tc.desc, diff) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func validateOTNChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx uint32, ethChIdx uint32, opticalChannel string, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { | ||
val := stream.Next() // value received in the gnmi subscription within 10 seconds | ||
if val == nil { | ||
t.Fatalf("OTN Channel telemetry stream not received in last 10 seconds") | ||
} | ||
cc, ok := val.Val() | ||
if !ok { | ||
t.Fatalf("OTN Channel telemetry stream empty in last 10 seconds") | ||
} | ||
tcs := []testcase{ | ||
{ | ||
desc: "Description", | ||
got: cc.GetDescription(), | ||
want: "OTN Logical Channel", | ||
}, | ||
{ | ||
desc: "Index", | ||
got: cc.GetIndex(), | ||
want: otnChIdx, | ||
}, | ||
{ | ||
desc: "Logical Channel Type", | ||
got: cc.GetLogicalChannelType().String(), | ||
want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN.String(), | ||
}, | ||
} | ||
var opticalChannelAssignmentIndexTestcases []testcase | ||
|
||
index := 0 | ||
if deviations.OTNChannelAssignmentCiscoNumbering(dut) { | ||
opticalChannel = strings.ReplaceAll(opticalChannel, "/", "_") // Ex: ciscoOpticalChannelFormat is OpticalChannel0_0_0_18 | ||
index = 1 | ||
} | ||
|
||
assignment := cc.GetAssignment(uint32(index)) | ||
opticalChannelAssignmentIndexTestcases = []testcase{ | ||
{ | ||
desc: "Assignment: Index", | ||
got: assignment.GetIndex(), | ||
want: uint32(index), | ||
}, | ||
{ | ||
desc: "Optical Channel Assignment: Optical Channel", | ||
got: assignment.GetOpticalChannel(), | ||
want: opticalChannel, | ||
}, | ||
{ | ||
desc: "Optical Channel Assignment: Description", | ||
got: assignment.GetDescription(), | ||
want: "OTN to Optical Channel", | ||
}, | ||
{ | ||
desc: "Optical Channel Assignment: Allocation", | ||
got: assignment.GetAllocation(), | ||
want: float64(400), | ||
}, | ||
{ | ||
desc: "Optical Channel Assignment: Type", | ||
got: assignment.GetAssignmentType().String(), | ||
want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), | ||
}, | ||
} | ||
tcs = append(tcs, opticalChannelAssignmentIndexTestcases...) | ||
|
||
if !deviations.OTNChannelTribUnsupported(dut) { | ||
logicalChannelAssignmentTestcases := []testcase{ | ||
{ | ||
desc: "Ethernet Assignment: Index", | ||
got: cc.GetAssignment(1).GetIndex(), | ||
want: uint32(1), | ||
}, | ||
{ | ||
desc: "Ethernet Assignment: Logical Channel", | ||
got: cc.GetAssignment(1).GetLogicalChannel(), | ||
want: ethChIdx, | ||
}, | ||
{ | ||
desc: "Ethernet Assignment: Description", | ||
got: cc.GetAssignment(1).GetDescription(), | ||
want: "OTN to ETH", | ||
}, | ||
{ | ||
desc: "Ethernet Assignment: Allocation", | ||
got: cc.GetAssignment(1).GetAllocation(), | ||
want: float64(400), | ||
}, | ||
{ | ||
desc: "Ethernet Assignment: Type", | ||
got: cc.GetAssignment(1).GetAssignmentType().String(), | ||
want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), | ||
}, | ||
} | ||
tcs = append(tcs, logicalChannelAssignmentTestcases...) | ||
} | ||
|
||
for _, tc := range tcs { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
if diff := cmp.Diff(tc.got, tc.want); diff != "" { | ||
t.Errorf("OTN Logical Channel: %s, diff (-got +want):\n%s", tc.desc, diff) | ||
} | ||
}) | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...form/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
...tform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/metadata.textproto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto | ||
# proto-message: Metadata | ||
uuid: "0ff18ddb-5333-4fc3-a2fb-5ac6d372a88f" | ||
plan_id: "TRANSCEIVER-5 (400ZR_PLUS)" | ||
description: "Configuration: 400ZR_PLUS channel frequency, output TX launch power and operational mode setting." | ||
testbed: TESTBED_DUT_400ZR_PLUS | ||
platform_exceptions: { | ||
platform: { | ||
vendor: ARISTA | ||
} | ||
deviations: { | ||
interface_enabled: true | ||
default_network_instance: "default" | ||
missing_zr_optical_channel_tunable_parameters_telemetry: true | ||
} | ||
} | ||
platform_exceptions: { | ||
platform: { | ||
vendor: JUNIPER | ||
} | ||
deviations: { | ||
operational_mode_unsupported: true | ||
} | ||
} |
305 changes: 305 additions & 0 deletions
305
...eiver/tunable_parameters/tests/zrp_tunable_parameters_test/zrp_tunable_parameters_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,305 @@ | ||
package zrp_tunable_parameters_test | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"math" | ||
"reflect" | ||
"testing" | ||
"time" | ||
|
||
"github.com/openconfig/featureprofiles/internal/attrs" | ||
"github.com/openconfig/featureprofiles/internal/cfgplugins" | ||
"github.com/openconfig/featureprofiles/internal/components" | ||
"github.com/openconfig/featureprofiles/internal/deviations" | ||
"github.com/openconfig/featureprofiles/internal/fptest" | ||
"github.com/openconfig/featureprofiles/internal/samplestream" | ||
"github.com/openconfig/ondatra" | ||
"github.com/openconfig/ondatra/gnmi" | ||
"github.com/openconfig/ondatra/gnmi/oc" | ||
) | ||
|
||
const ( | ||
samplingInterval = 10 * time.Second | ||
frequencyTolerance = 1800 | ||
timeout = 10 * time.Minute | ||
) | ||
|
||
var ( | ||
dutPort1 = attrs.Attributes{ | ||
Desc: "dutPort1", | ||
IPv4: "192.0.2.1", | ||
IPv4Len: 30, | ||
} | ||
dutPort2 = attrs.Attributes{ | ||
Desc: "dutPort2", | ||
IPv4: "192.0.2.5", | ||
IPv4Len: 30, | ||
} | ||
operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") | ||
operationalMode uint16 | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
fptest.RunTests(m) | ||
} | ||
|
||
func Test400ZRPlusTunableFrequency(t *testing.T) { | ||
if operationalModeFlag != nil { | ||
operationalMode = uint16(*operationalModeFlag) | ||
} else { | ||
t.Fatalf("Please specify the vendor-specific operational-mode flag") | ||
} | ||
dut := ondatra.DUT(t, "dut") | ||
p1 := dut.Port(t, "port1") | ||
p2 := dut.Port(t, "port2") | ||
fptest.ConfigureDefaultNetworkInstance(t, dut) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) | ||
oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) | ||
oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) | ||
streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) | ||
defer streamOC1.Close() | ||
streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) | ||
defer streamOC2.Close() | ||
tests := []struct { | ||
description string | ||
startFreq uint64 | ||
endFreq uint64 | ||
freqStep uint64 | ||
targetOutputPower float64 | ||
}{ | ||
{ | ||
// Validate setting 400ZR++ optics module tunable laser center frequency | ||
// across frequency range 196.100 - 191.375 THz for 75GHz grid. | ||
description: "75GHz grid", | ||
startFreq: 191375000, | ||
endFreq: 196100000, | ||
freqStep: 75000 * 6, | ||
targetOutputPower: -3, | ||
}, | ||
} | ||
for _, tc := range tests { | ||
t.Run(tc.description, func(t *testing.T) { | ||
for freq := tc.startFreq; freq <= tc.endFreq; freq += tc.freqStep { | ||
t.Run(fmt.Sprintf("Freq: %v", freq), func(t *testing.T) { | ||
if deviations.OperationalModeUnsupported(dut) { | ||
operationalMode = 0 | ||
} | ||
cfgplugins.ConfigOpticalChannel(t, dut, oc1, freq, tc.targetOutputPower, operationalMode) | ||
cfgplugins.ConfigOpticalChannel(t, dut, oc2, freq, tc.targetOutputPower, operationalMode) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, freq, tc.targetOutputPower, oc.Interface_OperStatus_UP) | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
} | ||
func Test400ZRPlusTunableOutputPower(t *testing.T) { | ||
if operationalModeFlag != nil { | ||
operationalMode = uint16(*operationalModeFlag) | ||
} else { | ||
t.Fatalf("Please specify the vendor-specific operational-mode flag") | ||
} | ||
dut := ondatra.DUT(t, "dut") | ||
p1 := dut.Port(t, "port1") | ||
p2 := dut.Port(t, "port2") | ||
fptest.ConfigureDefaultNetworkInstance(t, dut) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) | ||
oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) | ||
oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) | ||
streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) | ||
defer streamOC1.Close() | ||
streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) | ||
defer streamOC2.Close() | ||
tests := []struct { | ||
description string | ||
frequency uint64 | ||
startTargetOutputPower float64 | ||
endTargetOutputPower float64 | ||
targetOutputPowerStep float64 | ||
}{ | ||
{ | ||
// Validate adjustable range of transmit output power across -7 to 0 dBm | ||
// range in steps of 1dB. So the module’s output power will be set to -7, | ||
// -6,-5, -4, -3, -2, -1, 0 dBm in each step. | ||
description: "adjustable range of transmit output power across -7 to 0 dBm range in steps of 1dB", | ||
frequency: 193100000, | ||
startTargetOutputPower: -7, | ||
endTargetOutputPower: 0, | ||
targetOutputPowerStep: 1, | ||
}, | ||
} | ||
for _, tc := range tests { | ||
for top := tc.startTargetOutputPower; top <= tc.endTargetOutputPower; top += tc.targetOutputPowerStep { | ||
t.Run(fmt.Sprintf("Target Power: %v", top), func(t *testing.T) { | ||
if deviations.OperationalModeUnsupported(dut) { | ||
operationalMode = 0 | ||
} | ||
|
||
cfgplugins.ConfigOpticalChannel(t, dut, oc1, tc.frequency, top, operationalMode) | ||
cfgplugins.ConfigOpticalChannel(t, dut, oc2, tc.frequency, top, operationalMode) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, tc.frequency, top, oc.Interface_OperStatus_UP) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
func Test400ZRPlusInterfaceFlap(t *testing.T) { | ||
if operationalModeFlag != nil { | ||
operationalMode = uint16(*operationalModeFlag) | ||
} else { | ||
t.Fatalf("Please specify the vendor-specific operational-mode flag") | ||
} | ||
dut := ondatra.DUT(t, "dut") | ||
p1 := dut.Port(t, "port1") | ||
p2 := dut.Port(t, "port2") | ||
fptest.ConfigureDefaultNetworkInstance(t, dut) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) | ||
gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) | ||
oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) | ||
oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) | ||
streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) | ||
defer streamOC1.Close() | ||
streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) | ||
defer streamOC2.Close() | ||
targetPower := float64(-3) | ||
frequency := uint64(193100000) | ||
|
||
if deviations.OperationalModeUnsupported(dut) { | ||
operationalMode = 0 | ||
} | ||
|
||
cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetPower, operationalMode) | ||
cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetPower, operationalMode) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
t.Run("Telemetry before flap", func(t *testing.T) { | ||
validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, targetPower, oc.Interface_OperStatus_UP) | ||
}) | ||
// Disable or shut down the interface on the DUT. | ||
cfgplugins.ToggleInterface(t, dut, p1.Name(), false) | ||
cfgplugins.ToggleInterface(t, dut, p2.Name(), false) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) | ||
|
||
// Verify with interfaces in down state both optics are still streaming | ||
// configured value for frequency. | ||
// Verify for the TX output power with interface in down state a decimal64 | ||
// value of -40 dB is streamed. | ||
t.Run("Telemetry during interface disabled", func(t *testing.T) { | ||
validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, -40, oc.Interface_OperStatus_DOWN) | ||
}) | ||
// Re-enable the interfaces on the DUT. | ||
cfgplugins.ToggleInterface(t, dut, p1.Name(), true) | ||
cfgplugins.ToggleInterface(t, dut, p2.Name(), true) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) | ||
// Verify the ZR optics tune back to the correct frequency and TX output | ||
// power as per the configuration and related telemetry values are updated | ||
// to the value in the normal range again. | ||
t.Run("Telemetry after flap", func(t *testing.T) { | ||
validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, targetPower, oc.Interface_OperStatus_UP) | ||
}) | ||
} | ||
|
||
func validateOpticsTelemetry(t *testing.T, streams []*samplestream.SampleStream[*oc.Component], frequency uint64, outputPower float64, operStatus oc.E_Interface_OperStatus) { | ||
dut := ondatra.DUT(t, "dut") | ||
var ocs []*oc.Component_OpticalChannel | ||
for _, s := range streams { | ||
val := s.Next() | ||
if val == nil { | ||
t.Fatal("Optical channel streaming telemetry not received") | ||
} | ||
v, ok := val.Val() | ||
if !ok { | ||
t.Fatal("Optical channel streaming telemetry empty") | ||
} | ||
ocs = append(ocs, v.GetOpticalChannel()) | ||
} | ||
|
||
for _, _oc := range ocs { | ||
opm := _oc.GetOperationalMode() | ||
inst := _oc.GetCarrierFrequencyOffset().GetInstant() | ||
avg := _oc.GetCarrierFrequencyOffset().GetAvg() | ||
min := _oc.GetCarrierFrequencyOffset().GetMin() | ||
max := _oc.GetCarrierFrequencyOffset().GetMax() | ||
if got, want := opm, uint16(operationalMode); got != want && !deviations.OperationalModeUnsupported(dut) { | ||
t.Errorf("Optical-Channel: operational-mode: got %v, want %v", got, want) | ||
} | ||
// Laser frequency offset should not be more than +/- 1.8 GHz max from the | ||
// configured centre frequency. | ||
if inst < -1*frequencyTolerance || inst > frequencyTolerance { | ||
t.Errorf("Optical-Channel: carrier-frequency-offset not in tolerable range, got: %v, want: (+/-)%v", inst, frequencyTolerance) | ||
} | ||
for _, ele := range []any{inst, min, max, avg} { | ||
if reflect.TypeOf(ele).Kind() != reflect.Float64 { | ||
t.Fatalf("Value %v is not type float64", ele) | ||
} | ||
} | ||
if deviations.MissingZROpticalChannelTunableParametersTelemetry(dut) { | ||
t.Log("Skipping Min/Max/Avg Tunable Parameters Telemetry validation. Deviation MissingZROpticalChannelTunableParametersTelemetry enabled.") | ||
} else { | ||
// For reported data check for validity: min <= avg/instant <= max | ||
if min > math.Round(inst) { | ||
t.Errorf("Optical-Channel: carrier-frequency-offset min: %v greater than carrier-frequency-offset instant: %v", min, inst) | ||
} | ||
if max < math.Round(inst) { | ||
t.Errorf("Optical-Channel: carrier-frequency-offset max: %v less than carrier-frequency-offset instant: %v", max, inst) | ||
} | ||
if min > math.Round(avg) { | ||
t.Errorf("Optical-Channel: carrier-frequency-offset min: %v greater than carrier-frequency-offset avg: %v", min, avg) | ||
} | ||
if max < math.Round(avg) { | ||
t.Errorf("Optical-Channel: carrier-frequency-offset max: %v less than carrier-frequency-offset avg: %v", max, avg) | ||
} | ||
} | ||
inst = _oc.GetOutputPower().GetInstant() | ||
avg = _oc.GetOutputPower().GetAvg() | ||
min = _oc.GetOutputPower().GetMin() | ||
max = _oc.GetOutputPower().GetMax() | ||
// When set to a specific target output power, transmit power control | ||
// absolute accuracy should be within +/- 1 dBm of the target configured | ||
// output power. | ||
switch operStatus { | ||
case oc.Interface_OperStatus_UP: | ||
if inst < outputPower-1 || inst > outputPower+1 { | ||
t.Errorf("Optical-Channel: output-power not in tolerable range, got: %v, want: %v", inst, outputPower) | ||
} | ||
case oc.Interface_OperStatus_DOWN: | ||
if inst != -40 { | ||
t.Errorf("Optical-Channel: output-power not in tolerable range, got: %v, want: %v", inst, -40) | ||
} | ||
} | ||
for _, ele := range []any{inst, min, max, avg} { | ||
if reflect.TypeOf(ele).Kind() != reflect.Float64 { | ||
t.Fatalf("Value %v is not type float64", ele) | ||
} | ||
} | ||
if deviations.MissingZROpticalChannelTunableParametersTelemetry(dut) { | ||
t.Log("Skipping Min/Max/Avg Tunable Parameters Telemetry validation. Deviation MissingZROpticalChannelTunableParametersTelemetry enabled.") | ||
} else { | ||
// For reported data check for validity: min <= avg/instant <= max | ||
if min > math.Round(inst) { | ||
t.Errorf("Optical-Channel: output-power min: %v greater than output-power instant: %v", min, inst) | ||
} | ||
if max < math.Round(inst) { | ||
t.Errorf("Optical-Channel: output-power max: %v less than output-power instant: %v", max, inst) | ||
} | ||
if min > math.Round(avg) { | ||
t.Errorf("Optical-Channel: output-power min: %v greater than output-power avg: %v", min, avg) | ||
} | ||
if max < math.Round(avg) { | ||
t.Errorf("Optical-Channel: output-power max: %v less than output-power avg: %v", max, avg) | ||
} | ||
} | ||
if got, want := _oc.GetFrequency(), frequency; got != want { | ||
t.Errorf("Optical-Channel: frequency: %v, want: %v", got, want) | ||
} | ||
} | ||
} |