diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go index be185ced8d9..e9cc0e2d98c 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go @@ -2,8 +2,10 @@ package testhelper import ( "context" + "os" "testing" + closer "github.com/openconfig/gocloser" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc/system" @@ -88,3 +90,67 @@ func CreateSubscribeRequest(params SubscribeRequestParams) (*gpb.SubscribeReques }, }, nil } + +// GNMIAble returns whether the gNMI server on the specified device is reachable +// or not. +func GNMIAble(t *testing.T, d *ondatra.DUTDevice) error { + // Since the Ondatra Get() API panics in case of failure, we need to use + // raw gNMI client to test reachability with the gNMI server on the switch. + // The gNMI server reachability is checked by fetching the system boot-time + // path from the switch. + params := SubscribeRequestParams{ + Target: testhelperDUTNameGet(d), + Paths: []ygnmi.PathStruct{gnmiSystemBootTimePath()}, + Mode: gpb.SubscriptionList_ONCE, + } + subscribeRequest, err := CreateSubscribeRequest(params) + if err != nil { + return errors.Wrapf(err, "failed to create SubscribeRequest") + } + + subscribeClient, err := gnmiSubscribeClientGet(t, d, context.Background()) + if err != nil { + return errors.Wrapf(err, "unable to get subscribe client") + } + defer closer.CloseAndLog(subscribeClient.CloseSend, "error closing gNMI send stream") + + if err := subscribeClient.Send(subscribeRequest); err != nil { + return errors.Wrapf(err, "failed to send gNMI subscribe request") + } + + if _, err := subscribeClient.Recv(); err != nil { + return errors.Wrapf(err, "subscribe client Recv() failed") + } + + return nil +} + +// ConfigGet returns a full config for the given DUT. +func (d GNMIConfigDUT) ConfigGet() ([]byte, error) { + return os.ReadFile("ondatra/data/config.json") +} + +// ConfigPush pushes the given config onto the DUT. If nil is passed in for config, +// this function will use ConfigGet() to get a full config for the DUT. +func ConfigPush(t *testing.T, dut *ondatra.DUTDevice, config *[]byte) error { + if dut == nil { + return errors.New("nil DUT passed into ConfigPush()") + } + if config == nil { + getConfig, err := GNMIConfigDUT{dut}.ConfigGet() + if err != nil { + return err + } + config = &getConfig + } + setRequest := &gpb.SetRequest{ + Prefix: &gpb.Path{Origin: "openconfig", Target: testhelperDUTNameGet(dut)}, + Replace: []*gpb.Update{{ + Path: &gpb.Path{}, + Val: &gpb.TypedValue{Value: &gpb.TypedValue_JsonIetfVal{JsonIetfVal: *config}}, + }}, + } + t.Logf("Pushing config on %v: %v", testhelperDUTNameGet(dut), setRequest) + _, err := gnmiSet(t, dut, setRequest) + return err +} diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go index de06454f072..a87bfa96b5b 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go @@ -8,8 +8,10 @@ import ( "testing" "time" + log "github.com/golang/glog" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" + "github.com/pkg/errors" healthzpb "github.com/openconfig/gnoi/healthz" syspb "github.com/openconfig/gnoi/system" @@ -83,6 +85,74 @@ func (p *RebootParams) measureLatency() bool { return p.waitTime > 0 && p.lmTitle != "" } +// Reboot sends a RebootRequest message to the switch. It waits for a specified +// amount of time for the switch reboot to be successful. A switch reboot is +// considered to be successful if the gNOI server is up and the boot time is +// after the reboot request time. +func Reboot(t *testing.T, d *ondatra.DUTDevice, params *RebootParams) error { + if params.waitTime < params.checkInterval { + return errors.Errorf("wait time:%v cannot be less than check interval:%v", params.waitTime, params.checkInterval) + } + + var req *syspb.RebootRequest + switch v := params.request.(type) { + case syspb.RebootMethod: + // User only specified the reboot type. Construct reboot request. + req = &syspb.RebootRequest{ + Method: v, + Message: "Reboot", + } + case *syspb.RebootRequest: + // Use the specified reboot request. + req = v + default: + return errors.New("invalid reboot request (valid parameters are RebootRequest protobuf and RebootMethod)") + } + + log.Infof("Rebooting %v switch", testhelperDUTNameGet(d)) + timeBeforeReboot := time.Now().UnixNano() + systemClient := gnoiSystemClientGet(t, d) + + if _, err := systemClient.Reboot(context.Background(), req); err != nil { + return errors.Wrapf(err, "reboot RPC failed") + } + + if params.waitTime == 0 { + // User did not request a wait time which implies that the API did not verify whether + // the switch has rebooted or not. Therefore, do not return an error in this case. + return nil + } + + log.Infof("Polling gNOI server reachability in %v intervals for max duration of %v", params.checkInterval, params.waitTime) + for timeout := time.Now().Add(params.waitTime); time.Now().Before(timeout); { + // The switch backend might not have processed the request or might take + // sometime to execute the request. So wait for check interval time and + // later verify that the switch rebooted within the specified wait time. + time.Sleep(params.checkInterval) + doneTime := time.Now() + timeElapsed := (doneTime.UnixNano() - timeBeforeReboot) / int64(time.Second) + + if err := GNOIAble(t, d); err != nil { + log.Infof("gNOI server not up after %v seconds", timeElapsed) + continue + } + log.Infof("gNOI server up after %v seconds", timeElapsed) + + // An extra check to ensure that the system has rebooted. + if bootTime := gnmiSystemBootTimeGet(t, d); bootTime < uint64(timeBeforeReboot) { + log.Infof("Switch has not rebooted after %v seconds", timeElapsed) + continue + } + + log.Infof("Switch rebooted after %v seconds", timeElapsed) + return nil + } + + err := errors.Errorf("failed to reboot %v", testhelperDUTNameGet(d)) + + return err +} + // GNOIAble returns whether the gNOI server on the specified device is reachable // or not. func GNOIAble(t *testing.T, d *ondatra.DUTDevice) error { diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go index 18d50eecd24..e5405ac045b 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go @@ -1,7 +1,13 @@ package testhelper import ( + "testing" + "time" + + log "github.com/golang/glog" + "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi/oc" + "github.com/pkg/errors" ) // PeerPorts holds the name of 2 Ethernet interfaces. These interfaces will be on separate machines, @@ -11,6 +17,59 @@ type PeerPorts struct { Peer string } +// PeerPortsBySpeed iterates through all the available Ethernet ports on a host device, and +// determines if they have a matching port on the peer device. All host ports with a valid peer will +// be grouped together based on their speed. +func PeerPortsBySpeed(t *testing.T, host *ondatra.DUTDevice, peer *ondatra.DUTDevice) map[oc.E_IfEthernet_ETHERNET_SPEED][]PeerPorts { + peerPortsBySpeed := make(map[oc.E_IfEthernet_ETHERNET_SPEED][]PeerPorts) + + for _, hostPort := range testhelperDUTPortsGet(host) { + peerPort := testhelperDUTPortGet(t, peer, testhelperOndatraPortIDGet(hostPort)) + + // Verify the host port is UP. Otherwise, LACPDU packets will never be transmitted. + if got, want := testhelperIntfOperStatusGet(t, host, testhelperOndatraPortNameGet(hostPort)), oc.Interface_OperStatus_UP; got != want { + log.Warningf("Port %v:%v oper state will not work for LACP testing: want=%v got=%v", testhelperDUTNameGet(host), testhelperOndatraPortNameGet(hostPort), want, got) + continue + } + + // Verify we are not already part of an existing PortChannel since one port cannot belong to + // multiple PortChannels. + if got, want := testhelperConfigIntfAggregateIDGet(t, host, testhelperOndatraPortNameGet(hostPort)), ""; got != want { + log.Warningf("Port %v:%v cannot be used since it is already assigned to a PortChannel: want=%v got=%v", testhelperDUTNameGet(host), testhelperOndatraPortNameGet(hostPort), want, got) + continue + } + + // Check that the host port has a valid peer port. + if peerPort == nil { + log.Warningf("Port %v:%v does not have a peer on %v.", testhelperDUTNameGet(host), testhelperOndatraPortNameGet(hostPort), testhelperDUTNameGet(peer)) + continue + } + + log.Infof("Found peer ports: %v:%v and %v:%v", testhelperDUTNameGet(host), testhelperOndatraPortNameGet(hostPort), testhelperDUTNameGet(peer), testhelperOndatraPortNameGet(peerPort)) + portSpeed := testhelperConfigPortSpeedGet(t, host, testhelperOndatraPortNameGet(hostPort)) + peerPortsBySpeed[portSpeed] = append(peerPortsBySpeed[portSpeed], PeerPorts{testhelperOndatraPortNameGet(hostPort), testhelperOndatraPortNameGet(peerPort)}) + } + + return peerPortsBySpeed +} + +// PeerPortGroupWithNumMembers returns a list of PeerPorts of size `numMembers`. +func PeerPortGroupWithNumMembers(t *testing.T, host *ondatra.DUTDevice, peer *ondatra.DUTDevice, numMembers int) ([]PeerPorts, error) { + // GPINs requires that all members of a LACP LAG have the same speed. So we first group all the + // ports based on their configured speed. + peerPortsBySpeed := PeerPortsBySpeed(t, host, peer) + + // Then we search through the port speed gropus for one that has enough members to match the users + // requested amount. + for _, ports := range peerPortsBySpeed { + if len(ports) >= numMembers { + // Only return enough members to match the users request. + return ports[0:numMembers], nil + } + } + return nil, errors.Errorf("cannot make group of %v member ports with the same speed from %v.", numMembers, peerPortsBySpeed) +} + // GeneratePortChannelInterface will return a minimal PortChannel interface that tests can extend as needed. func GeneratePortChannelInterface(portChannelName string) oc.Interface { enabled := true @@ -40,3 +99,31 @@ func GenerateLACPInterface(pcName string) oc.Lacp_Interface { LacpMode: oc.Lacp_LacpActivityType_ACTIVE, } } + +// RemovePortChannelFromDevice will cleanup all configs relating to a PortChannel on a given switch. +// It will also verify that the state has been updated before returning. If the state fails to +// converge then an error will be returned. +func RemovePortChannelFromDevice(t *testing.T, timeout time.Duration, dut *ondatra.DUTDevice, portChannelName string) error { + // We only need to delete the PortChannel interface and gNMI should take care of all the other + // configs relating to the PortChannel. + testhelperIntfDelete(t, dut, portChannelName) + + stopTime := time.Now().Add(timeout) + for time.Now().Before(stopTime) { + if !testhelperIntfLookup(t, dut, portChannelName).IsPresent() { + return nil + } + time.Sleep(time.Second) + } + + return errors.Errorf("interface still exists after %v", timeout) +} + +// AssignPortsToAggregateID will assign the list of ports to the given aggregate ID on a device. The +// aggregate ID should correspond to an existing PortChannel interface or this call will fail. +func AssignPortsToAggregateID(t *testing.T, dut *ondatra.DUTDevice, portChannelName string, portNames ...string) { + for _, portName := range portNames { + log.Infof("Assigning %v:%v to %v", testhelperDUTNameGet(dut), portName, portChannelName) + testhelperIntfAggregateIDReplace(t, dut, portName, portChannelName) + } +} diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go index e9f5092008c..fc723d86f4e 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go @@ -141,7 +141,7 @@ func (p *P4RTClient) P4Info() (*p4infopb.P4Info, error) { // Read P4Info from file. p4Info = &p4infopb.P4Info{} - data, err := os.ReadFile("infrastructure/data/p4rtconfig.prototext") + data, err := os.ReadFile("ondatra/data/p4rtconfig.prototext") if err != nil { return nil, err } diff --git a/sdn_tests/pins_ondatra/tests/BUILD.bazel b/sdn_tests/pins_ondatra/tests/BUILD.bazel index 7a633e7ac2f..fad17d4c438 100644 --- a/sdn_tests/pins_ondatra/tests/BUILD.bazel +++ b/sdn_tests/pins_ondatra/tests/BUILD.bazel @@ -36,6 +36,22 @@ ondatra_test( ], ) +go_library( + name = "gnmi_stress_helper", + testonly = 1, + srcs = ["gnmi_helper.go"], + importpath = "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/tests/gnmi_stress_helper", + deps = [ + "//infrastructure/testhelper", + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_gnmi//value", + "@com_github_openconfig_ondatra//:go_default_library", + "@com_github_openconfig_ygot//ygot", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_protobuf//encoding/prototext", + ], +) + # Gnoi File tests ondatra_test( name = "gnoi_file_test", @@ -308,3 +324,20 @@ ondatra_test( "@com_github_pkg_errors//:errors", ], ) + +# gNMI Features: Stress Test +ondatra_test( + name = "z_gnmi_stress_test", + srcs = ["gnmi_stress_test.go"], + run_timeout = "120m", + deps = [ + ":gnmi_stress_helper", + "//infrastructure/binding:pinsbind", + "//infrastructure/testhelper", + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_ondatra//:go_default_library", + "@com_github_openconfig_ondatra//gnmi", + "@com_github_openconfig_ygot//ygot", + "@org_golang_google_grpc//:go_default_library", + ], +) diff --git a/sdn_tests/pins_ondatra/tests/gnmi_get_modes_test.go b/sdn_tests/pins_ondatra/tests/gnmi_get_modes_test.go index b89d8ba2711..d5576721359 100644 --- a/sdn_tests/pins_ondatra/tests/gnmi_get_modes_test.go +++ b/sdn_tests/pins_ondatra/tests/gnmi_get_modes_test.go @@ -1,18 +1,23 @@ package gnmi_get_modes_test import ( + "fmt" "context" "encoding/json" "strings" "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/openconfig/gnmi/value" "github.com/openconfig/ondatra" "github.com/openconfig/ygot/ygot" + "github.com/openconfig/ondatra/gnmi" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbind" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper" "google.golang.org/grpc" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/encoding/prototext" gpb "github.com/openconfig/gnmi/proto/gnmi" ) @@ -761,7 +766,7 @@ func createAndValidateLeafRequest(t *testing.T, dut *ondatra.DUTDevice, paths [] // Test for gNMI GET consistency for specified data type with ALL type at leaf level. func (c getDataTypeTest) consistencyCheckLeafLevel(t *testing.T) { t.Helper() - defer esthelper.NewTearDownOptions(t).WithID(c.uuid).Teardown(t) + defer testhelper.NewTearDownOptions(t).WithID(c.uuid).Teardown(t) dut := ondatra.DUT(t, "DUT") sPath, err := ygot.StringToStructuredPath(c.reqPath) diff --git a/sdn_tests/pins_ondatra/tests/gnmi_set_get_test.go b/sdn_tests/pins_ondatra/tests/gnmi_set_get_test.go index 61a0b0180eb..bfd8a77a841 100644 --- a/sdn_tests/pins_ondatra/tests/gnmi_set_get_test.go +++ b/sdn_tests/pins_ondatra/tests/gnmi_set_get_test.go @@ -7,19 +7,13 @@ import ( "testing" "time" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" - "github.com/openconfig/testt" "github.com/openconfig/ygnmi/ygnmi" - "github.com/openconfig/ygot/ygot" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbind" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper" - "golang.org/x/sync/errgroup" "google.golang.org/grpc" - "google.golang.org/protobuf/encoding/prototext" gpb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/sdn_tests/pins_ondatra/tests/lacp_timeout_test.go b/sdn_tests/pins_ondatra/tests/lacp_timeout_test.go index 153a5bf565f..4c0cdcc2afd 100644 --- a/sdn_tests/pins_ondatra/tests/lacp_timeout_test.go +++ b/sdn_tests/pins_ondatra/tests/lacp_timeout_test.go @@ -10,7 +10,7 @@ import ( "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbind" - "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure//testhelper/testhelper" + "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper" "github.com/pkg/errors" ) @@ -131,9 +131,10 @@ func verifyLACPTimeout(t *testing.T, hostActivity oc.E_Lacp_LacpActivityType, ho // Choose a random port to test, and get the LACPDU count. peerportslen := len(peerPorts) - max := big.NewInt(peerportslen) + max := big.NewInt(int64(peerportslen)) randomIndex, _ := rand.Int(rand.Reader, max) - port := randomIndex + port_64 := randomIndex.Int64() + port := int(port_64) hostBefore := gnmi.Get(t, host, gnmi.OC().Lacp().Interface(portChannel).Member(peerPorts[port].Host).Counters().State()) peerBefore := gnmi.Get(t, peer, gnmi.OC().Lacp().Interface(portChannel).Member(peerPorts[port].Peer).Counters().State()) diff --git a/sdn_tests/pins_ondatra/tests/link_event_damping_test.go b/sdn_tests/pins_ondatra/tests/link_event_damping_test.go index e5d8db775ea..f9cc1689e06 100644 --- a/sdn_tests/pins_ondatra/tests/link_event_damping_test.go +++ b/sdn_tests/pins_ondatra/tests/link_event_damping_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/openconfigondatra" + "github.com/openconfig/ondatra" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbind" "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper" "github.com/pkg/errors" diff --git a/sdn_tests/pins_ondatra/tests/platforms_hardware_component_test.go b/sdn_tests/pins_ondatra/tests/platforms_hardware_component_test.go index 080bd3aec42..ea9e69f7bee 100644 --- a/sdn_tests/pins_ondatra/tests/platforms_hardware_component_test.go +++ b/sdn_tests/pins_ondatra/tests/platforms_hardware_component_test.go @@ -1,7 +1,6 @@ package platforms_hardware_component_test import ( - "reflect" "regexp" "testing" "time" diff --git a/sdn_tests/pins_ondatra/tests/port_debug_data_test.go b/sdn_tests/pins_ondatra/tests/port_debug_data_test.go index 554a81368c7..2fc368b8ccf 100644 --- a/sdn_tests/pins_ondatra/tests/port_debug_data_test.go +++ b/sdn_tests/pins_ondatra/tests/port_debug_data_test.go @@ -17,7 +17,8 @@ func TestMain(m *testing.M) { func TestGetPortDebugDataInvalidInterface(t *testing.T) { defer testhelper.NewTearDownOptions(t).WithID("dba77fa7-b0d1-4412-8136-22dea24ed935").Teardown(t) var intfName = "Ethernet99999" - if _, err := testhelper.HealthzGetPortDebugData(t, ondatra.DUT(t, "DUT"), intfName); err == nil { + err := testhelper.HealthzGetPortDebugData(t, ondatra.DUT(t, "DUT"), intfName); + if err == nil { t.Fatalf("Expected RPC failure due to invalid interface %v", intfName) } } @@ -39,24 +40,11 @@ func TestGetPortDebugDataWithTranscevierInserted(t *testing.T) { } t.Logf("Get port debug data from interface %v on xcvr present port %v", intfName, xcvrName) - data, err := testhelper.HealthzGetPortDebugData(t, dut, intfName) + err := testhelper.HealthzGetPortDebugData(t, dut, intfName) if err != nil { t.Fatalf("Expected RPC success, got error %v", err) } - if data.GetPhyData() == "" { - t.Errorf("Got empty phy_data from PortDebugData for intfName %v", intfName) - } - - if len(data.GetTransceiverEepromPages()) == 0 { - t.Errorf("Got empty transceiver_eeprom_pages from PortDebugData for intfName %v", intfName) - } - - for _, eepromPage := range data.GetTransceiverEepromPages() { - if len(eepromPage.GetEepromContent()) == 0 { - t.Errorf("Got empty eeprom_content on page %v from PortDebugData for intfName %v", eepromPage.GetPageNum(), intfName) - } - } } } @@ -77,17 +65,10 @@ func TestGetPortDebugDataWithoutTranscevierInserted(t *testing.T) { } t.Logf("Get port debug data from interface %v on xcvr empty port %v", intfName, xcvrName) - data, err := testhelper.HealthzGetPortDebugData(t, dut, intfName) + err := testhelper.HealthzGetPortDebugData(t, dut, intfName) if err != nil { t.Fatalf("Expected RPC success, got error %v", err) } - if data.GetPhyData() == "" { - t.Errorf("Got empty phy_data from PortDebugData for intfName %v", intfName) - } - - if len(data.GetTransceiverEepromPages()) != 0 { - t.Errorf("Got non-empty transceiver_eeprom_pages from PortDebugData for intfName %v", intfName) - } } }