diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md index 38d2a7baa9c..34a200dd80c 100644 --- a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-1: Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming +# TRANSCEIVER-1 (400ZR_PLUS): Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming ## Summary diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto new file mode 100644 index 00000000000..cca50bb884c --- /dev/null +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto @@ -0,0 +1,15 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata +uuid: "6ee614f9-efa6-4d1c-bdea-b15332feedc7" +plan_id: "TRANSCEIVER-1 (400ZR_PLUS)" +description: "Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming" +testbed: TESTBED_DUT_400ZR_PLUS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + } +} diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go new file mode 100644 index 00000000000..e093b1675ab --- /dev/null +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go @@ -0,0 +1,172 @@ +package zrp_cd_test + +import ( + "flag" + "reflect" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/components" + "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 + minCDValue = -200 + maxCDValue = 2400 + inActiveCDValue = 0.0 + timeout = 10 * time.Minute + flapInterval = 30 * time.Second +) + +var ( + frequencies = []uint64{191400000, 196100000} + targetOutputPowers = []float64{-7, 0} + operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") + operationalMode uint16 +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func verifyCDValue(t *testing.T, dut1 *ondatra.DUTDevice, pStream *samplestream.SampleStream[float64], sensorName string, operStatus oc.E_Interface_OperStatus) float64 { + cdSampleNexts := pStream.Nexts(2) + cdSample := cdSampleNexts[1] + t.Logf("CDSampleNexts %v", cdSampleNexts) + if cdSample == nil { + t.Fatalf("CD telemetry %s was not streamed in the most recent subscription interval", sensorName) + } + cdVal, ok := cdSample.Val() + if !ok { + t.Fatalf("CD %q telemetry is not present", cdSample) + } + if reflect.TypeOf(cdVal).Kind() != reflect.Float64 { + t.Fatalf("CD value is not type float64") + } + // Check CD return value of correct type + switch operStatus { + case oc.Interface_OperStatus_DOWN: + if cdVal != inActiveCDValue { + t.Fatalf("The inactive CD is %v, expected %v", cdVal, inActiveCDValue) + } + case oc.Interface_OperStatus_UP: + if cdVal < minCDValue || cdVal > maxCDValue { + t.Fatalf("The variable CD is %v, expected range (%v, %v)", cdVal, minCDValue, maxCDValue) + } + default: + t.Fatalf("Invalid status %v", operStatus) + } + // Get current time + now := time.Now() + // Format the time string + formattedTime := now.Format("2006-01-02 15:04:05") + t.Logf("%s Device %v CD %s value at status %v: %v", formattedTime, dut1.Name(), sensorName, operStatus, cdVal) + + return cdVal +} + +// TODO: Avg and Instant value checks are not available. Need to align their sample streaming windows. +func verifyAllCDValues(t *testing.T, dut1 *ondatra.DUTDevice, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg *samplestream.SampleStream[float64], operStatus oc.E_Interface_OperStatus) { + tests := []struct { + desc string + stream *samplestream.SampleStream[float64] + streamType string + operStatus oc.E_Interface_OperStatus + }{ + { + desc: "Instant", + stream: p1StreamInstant, + operStatus: operStatus, + }, + { + desc: "Max", + stream: p1StreamMax, + operStatus: operStatus, + }, + { + desc: "Min", + stream: p1StreamMin, + operStatus: operStatus, + }, + { + desc: "Avg", + stream: p1StreamAvg, + operStatus: operStatus, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + verifyCDValue(t, dut1, tt.stream, tt.desc, tt.operStatus) + }) + } +} + +func TestCDValue(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") + } + fptest.ConfigureDefaultNetworkInstance(t, dut) + + dp1 := dut.Port(t, "port1") + dp2 := dut.Port(t, "port2") + + och1 := components.OpticalChannelComponentFromPort(t, dut, dp1) + och2 := components.OpticalChannelComponentFromPort(t, dut, dp2) + + component1 := gnmi.OC().Component(och1) + for _, frequency := range frequencies { + for _, targetOutputPower := range targetOutputPowers { + cfgplugins.ConfigOpticalChannel(t, dut, och1, frequency, targetOutputPower, operationalMode) + cfgplugins.ConfigOpticalChannel(t, dut, och2, frequency, targetOutputPower, operationalMode) + + // Wait for channels to be up. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + + p1StreamInstant := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Instant().State(), samplingInterval) + p1StreamMin := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Min().State(), samplingInterval) + p1StreamMax := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Max().State(), samplingInterval) + p1StreamAvg := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Avg().State(), samplingInterval) + + defer p1StreamInstant.Close() + defer p1StreamMin.Close() + defer p1StreamMax.Close() + defer p1StreamAvg.Close() + + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_UP) + + // Disable interface. + for _, p := range dut.Ports() { + cfgplugins.ToggleInterface(t, dut, p.Name(), false) + } + // Wait for channels to be down. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + t.Logf("Interfaces are down: %v, %v", dp1.Name(), dp2.Name()) + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_DOWN) + + time.Sleep(flapInterval) + + // Enable interface. + for _, p := range dut.Ports() { + cfgplugins.ToggleInterface(t, dut, p.Name(), true) + } + // Wait for channels to be up. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + t.Logf("Interfaces are up: %v, %v", dp1.Name(), dp2.Name()) + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_UP) + + } + } +} diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md index 9a36062a6b1..756bc623d6b 100644 --- a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-10: Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming. +# TRANSCEIVER-10 (400ZR_PLUS): Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming. ## Summary diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto new file mode 100644 index 00000000000..4d15d622908 --- /dev/null +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto @@ -0,0 +1,28 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "387c1f76-7811-4a04-99e3-f690fba1e98e" +plan_id: "TRANSCEIVER-10 (400ZR_PLUS)" +description: "Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming." +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 + } +} diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go new file mode 100644 index 00000000000..829376d5560 --- /dev/null +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go @@ -0,0 +1,116 @@ +// Copyright 2024 Google LLC +// +// 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 zrp_fec_uncorrectable_frames_test + +import ( + "flag" + "fmt" + "reflect" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/components" + "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 ( + sampleInterval = 10 * time.Second + intUpdateTime = 5 * time.Minute + otnIndexBase = uint32(4000) + ethIndexBase = uint32(40000) + targetOutputPower = -3 + frequency = 193100000 +) + +var ( + operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") + operationalMode uint16 +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func validateFecUncorrectableBlocks(t *testing.T, stream *samplestream.SampleStream[uint64]) { + fecStream := stream.Next() + if fecStream == nil { + t.Fatalf("Fec Uncorrectable Blocks was not streamed in the most recent subscription interval") + } + fec, ok := fecStream.Val() + if !ok { + t.Fatalf("Error capturing streaming Fec value") + } + if reflect.TypeOf(fec).Kind() != reflect.Uint64 { + t.Fatalf("fec value is not type uint64") + } + if fec != 0 { + t.Fatalf("Got FecUncorrectableBlocks got %d, want 0", fec) + } +} + +func TestZrUncorrectableFrames(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") + + var ( + // trs = make(map[string]string) + // ochs = make(map[string]string) + otnIndexes = make(map[string]uint32) + ethIndexes = make(map[string]uint32) + ) + + ports := []string{"port1", "port2"} + + for i, port := range ports { + p := dut.Port(t, port) + och := components.OpticalChannelComponentFromPort(t, dut, p) + otnIndexes[p.Name()] = otnIndexBase + uint32(i) + ethIndexes[p.Name()] = ethIndexBase + uint32(i) + cfgplugins.ConfigOpticalChannel(t, dut, och, frequency, targetOutputPower, operationalMode) + cfgplugins.ConfigOTNChannel(t, dut, och, otnIndexes[p.Name()], ethIndexes[p.Name()]) + cfgplugins.ConfigETHChannel(t, dut, p.Name(), och, otnIndexes[p.Name()], ethIndexes[p.Name()]) + } + + for _, port := range ports { + t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { + p := dut.Port(t, port) + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) + streamFecOtn := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndexes[p.Name()]).Otn().FecUncorrectableBlocks().State(), sampleInterval) + defer streamFecOtn.Close() + validateFecUncorrectableBlocks(t, streamFecOtn) + + // Disable interface + cfgplugins.ToggleInterface(t, dut, p.Name(), false) + // Wait for the cooling-off period + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) + + // Enable interface + cfgplugins.ToggleInterface(t, dut, p.Name(), true) + // Wait for the cooling-off period + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) + + validateFecUncorrectableBlocks(t, streamFecOtn) + }) + } +}