Skip to content

Commit

Permalink
Move topology_test to feature dir & update READMEs (openconfig#1977)
Browse files Browse the repository at this point in the history
* Move topology_test to feature dir & update READMEs

* Fix verb conjugation

* Fix up topology_test

* Name()->ID()
  • Loading branch information
greg-dennis authored Aug 5, 2023
1 parent 32303e1 commit 9c01f36
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 246 deletions.
61 changes: 22 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Feature Profiles

Feature profiles define groups of OpenConfig paths that can be invoked on
Feature profiles defines groups of OpenConfig paths that can be invoked on
network devices. A feature profile may contain configuration, telemetry,
operational or any other paths that a device exposes. Example management plane
device APIs are gNMI, and gNOI. Example control plane APIs are gRIBI, and
protocols such as BGP, IS-IS.

Feature profiles also include a suite of tests for validating the network device
behavior for each defined feature.
Feature profiles also includes a suite of
[Ondatra](https://github.com/openconfig/ondatra) tests for validating the
network device behavior for each defined feature.

# Contributing

Expand All @@ -20,14 +21,15 @@ the
or by opening a GitHub
[issue](https://github.com/openconfig/featureprofiles/issues).

# Examples
# Running Tests on Virtual Devices

Tests below are implemented using the
[ONDATRA](https://github.com/openconfig/ondatra) test framework with the
Tests may be run on virtual devices using the
[Kubernetes Network Emulation](https://github.com/openconfig/kne) binding.

Before creating a topology, follow the
[steps for deploying a cluster](https://github.com/openconfig/kne/blob/main/docs/create_topology.md#deploy-a-cluster).
First, follow the
[steps for deploying a KNE cluster](https://github.com/openconfig/kne/blob/main/docs/create_topology.md#deploy-a-cluster).
Then follow the per-vendor instructions below for creating a KNE topology and
running a test on it.

## Arista cEOS

Expand Down Expand Up @@ -67,7 +69,7 @@ kne create topologies/kne/cisco/8000e/topology.textproto
2. Run a sample test:

```
go test ./feature/system/tests/... -kne-topo $PWD/topologies/kne/cisco/8000e/topology.textproto -vendor_creds CISCO/cisco/cisco123
go test ./feature/example/tests/... -kne-topo $PWD/topologies/kne/cisco/8000e/topology.textproto -vendor_creds CISCO/cisco/cisco123
```

3. Cleanup:
Expand All @@ -89,7 +91,7 @@ kne create topologies/kne/cisco/xrd/topology.textproto
2. Run a sample test:

```
go test ./feature/system/tests/... -kne-topo $PWD/topologies/kne/cisco/xrd/topology.textproto -vendor_creds CISCO/cisco/cisco123
go test ./feature/example/tests/... -kne-topo $PWD/topologies/kne/cisco/xrd/topology.textproto -vendor_creds CISCO/cisco/cisco123
```

3. Cleanup:
Expand All @@ -113,7 +115,7 @@ kne create topologies/kne/juniper/cptx/topology.textproto
2. Run a sample test:

```
go test ./feature/system/tests/... -kne-topo $PWD/topologies/kne/juniper/cptx/topology.textproto -vendor_creds JUNIPER/root/Google123
go test ./feature/example/tests/... -kne-topo $PWD/topologies/kne/juniper/cptx/topology.textproto -vendor_creds JUNIPER/root/Google123
```

3. Cleanup:
Expand All @@ -136,7 +138,7 @@ kne create topologies/kne/nokia/srlinux/topology.textproto
2. Run a sample test:

```
go test ./feature/system/tests/... -kne-topo $PWD/topologies/kne/nokia/srlinux/topology.textproto -vendor_creds NOKIA/admin/NokiaSrl1!
go test ./feature/example/tests/... -kne-topo $PWD/topologies/kne/nokia/srlinux/topology.textproto -vendor_creds NOKIA/admin/NokiaSrl1!
```

3. Cleanup:
Expand All @@ -145,39 +147,20 @@ go test ./feature/system/tests/... -kne-topo $PWD/topologies/kne/nokia/srlinux/t
kne delete topologies/kne/nokia/srlinux/topology.textproto
```

## Static Binding (Experimental)
## Running Tests on Real Hardware

The static binding supports ATE based testing with a real hardware device. It
assumes that there is one ATE hooked up to one DUT in the testbed, and their
ports are connected pairwise. They are defined in `topologies/atedut_*.testbed`
with three variants: 2 ports, 4 ports, and 12 ports.
Tests may be run on real hardware devices using the static binding.

* The 2 port variant is able to run the vast majority of the control plane
tests.
* The 4 port variant is required by some VRF based or data plane tests.
* The 12 port variant is required by the aggregate interface (static LAG and
LACP) tests.

Setup: edit `topologies/atedut_12.binding` to specify the mapping from testbed
topology to the actual hardware as well as the dial options.

Testing:
The static binding supports the testbeds in the `topologies/*.testbed` files.
The mapping between the IDs in the testbed file and the physical devices are
provided by the corresponding `topologies/*.binding` files. To try it out, edit
`otgdut_4.binding` to specify the mapping from testbed IDs to actual hardware
devices, as well as the desired protocol dial options. Then test it by running:

```
cd ./topologies/ate_tests/topology_test
go test . -testbed ../../atedut_12.testbed -binding ../../atedut_12.binding
go test ./feature/example/tests/topology_test -binding $PWD/topologies/otgdut_4.binding
```

> :exclamation: **NOTE**: when `go test` runs a test, the current working
> directory is set to the path of the test package, so the testbed and binding
> files are relative to the test package and not to the source root. It is
> recommended to just `cd` to the test package to be consistent.
> :warning: **WARNING**: the topology\_test is derived from a similar test used
> at Google. The test code compiles but is not tested because we have not hooked
> up Google's testing environment to the open-sourced static binding. This is an
> early preview meant to demonstrate Ondatra API usage.
## Path validation

The `make validate_paths` target will clone the public OpenConfig definitions
Expand Down
33 changes: 33 additions & 0 deletions feature/example/tests/topology_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# example-0.1: Topology Test

## Summary

Tests that ports an be successfully configured in a basic topology.

## Procedure

* Configure the ports on the DUT.
* Check that each port on the DUT has /config telemetry.
* Check that each port on the DUT has /state telemetry.
* Configure the ports on the ATE.
* Start control plane protocols on the ATE.
* Check that the link state on each DUT port is UP.
* Check that the link state on each ATE port is UP.

## Config Parameter coverage

No configuration coverage.

## Telemetry Parameter coverage

* /interfaces/interface/config
* /interfaces/interface/state
* /interfaces/interface/state/oper-status

## Protocol/RPC Parameter coverage

N/A

## Minimum DUT platform requirement

N/A
7 changes: 7 additions & 0 deletions feature/example/tests/topology_test/metadata.textproto
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto
# proto-message: Metadata

uuid: "7e63e9af-44d2-40a9-a77d-ab7b11c080a7"
plan_id: "example-0.1"
description: "Topology Test"
testbed: TESTBED_DUT_ATE_4LINKS
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/open-traffic-generator/snappi/gosnappi"
"github.com/openconfig/featureprofiles/internal/deviations"
"github.com/openconfig/featureprofiles/internal/fptest"
Expand Down Expand Up @@ -100,39 +99,36 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) {
badTelem []string
)

d := gnmi.OC()

// TODO(liulk): configure breakout ports when Ondatra is able to
// specify them in the testbed for reservation.

sortedDutPorts := sortPorts(dut.Ports())
for i, dp := range sortedDutPorts {
di := d.Interface(dp.Name())
dc := gnmi.OC().Interface(dp.Name()).Config()
in := configInterface(dp.Name(), dp.String(), dutPortIP(i), plen, dut)
fptest.LogQuery(t, fmt.Sprintf("%s to Replace()", dp), di.Config(), in)
if ok := fptest.NonFatal(t, func(t testing.TB) { gnmi.Replace(t, dut, di.Config(), in) }); !ok {
fptest.LogQuery(t, fmt.Sprintf("%s to Replace()", dp), dc, in)
if ok := fptest.NonFatal(t, func(t testing.TB) { gnmi.Replace(t, dut, dc, in) }); !ok {
badReplace = append(badReplace, dp.Name())
}
}

for _, dp := range dut.Ports() {
di := d.Interface(dp.Name())
if val, present := gnmi.LookupConfig(t, dut, di.Config()).Val(); present {
fptest.LogQuery(t, fmt.Sprintf("%s from Get()", dp), di.Config(), val)
dc := gnmi.OC().Interface(dp.Name()).Config()
if val, present := gnmi.LookupConfig(t, dut, dc).Val(); present {
fptest.LogQuery(t, fmt.Sprintf("%s from Get()", dp), dc, val)
} else {
badConfig = append(badConfig, dp.Name())
t.Errorf("Config %v Get() failed", di)
t.Errorf("Config %v Get() failed", dc)
}
}

dt := gnmi.OC()
for _, dp := range dut.Ports() {
di := dt.Interface(dp.Name())
if val, present := gnmi.Lookup(t, dut, di.State()).Val(); present {
fptest.LogQuery(t, fmt.Sprintf("%s from Get()", dp), di.State(), val)
ds := gnmi.OC().Interface(dp.Name()).State()
if val, present := gnmi.Lookup(t, dut, ds).Val(); present {
fptest.LogQuery(t, fmt.Sprintf("%s from Get()", dp), ds, val)
} else {
badTelem = append(badTelem, dp.Name())
t.Errorf("Telemetry %v Get() failed", di)
t.Errorf("Telemetry %v Get() failed", ds)
}
}

Expand Down Expand Up @@ -173,13 +169,10 @@ func TestTopology(t *testing.T) {
configureATE(t, ate)

// Query Telemetry
dutPorts := sortPorts(dut.Ports())
t.Run("Telemetry", func(t *testing.T) {
const want = oc.Interface_OperStatus_UP

dt := gnmi.OC()
for _, dp := range dutPorts {
if got := gnmi.Get(t, dut, dt.Interface(dp.Name()).OperStatus().State()); got != want {
for _, dp := range dut.Ports() {
if got := gnmi.Get(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State()); got != want {
t.Errorf("%s oper-status got %v, want %v", dp, got, want)
}
}
Expand All @@ -188,9 +181,11 @@ func TestTopology(t *testing.T) {

// Query ATE telemetry.
t.Run("ATE Telemetry", func(t *testing.T) {
want := []otgoc.E_Port_Link{otgoc.Port_Link_UP, otgoc.Port_Link_UP}
if got := gnmi.GetAll(t, ate.OTG(), gnmi.OTG().PortAny().Link().State()); !cmp.Equal(got, want) {
t.Errorf("did not get expected ATE telemetry, got: %v, want: %v", got, want)
const want = otgoc.Port_Link_UP
for _, ap := range ate.Ports() {
if got := gnmi.Get(t, ate.OTG(), gnmi.OTG().Port(ap.ID()).Link().State()); got != want {
t.Errorf("%s link-state got: %v, want: %v", ap, got, want)
}
}
})
}
Loading

0 comments on commit 9c01f36

Please sign in to comment.