Skip to content
Snippets Groups Projects
Commit 11dafeae authored by Katharina Renk's avatar Katharina Renk
Browse files

created ping test for Lab01

parent c743e730
No related branches found
No related tags found
2 merge requests!784Draft: Resolve "Integration test for Lab01",!757Draft: Resolve "Integration test for Lab01"
Pipeline #186085 failed
......@@ -114,7 +114,6 @@ func TestLab00(t *testing.T) {
}
// Change the hostname of both managed network elements.
for _, mne := range managedNetworkElements {
hostnamePathListRequest, err := lab_utils.SetHostnamePathListRequestSingleMne(mne.id, mne.newHostname, mnepb.ApiOperation_API_OPERATION_UPDATE)
if err != nil {
......
......
......@@ -19,20 +19,39 @@ const (
targetAUUID = "e3cc56ad-2a6c-4b76-8315-5f17a6dc25bf"
targetBName = "gnmi-targetB"
targetBUUID = "87c8bcc1-d95c-401e-b447-f02c56abd8b1"
targetInterfaceEth1 = "eth1"
targetInterfaceEth2 = "eth2"
targetRoute = "route"
targetAInterfacePathEth1 = "switch0/s0-eth1.json"
targetAInterfacePathEth2 = "switch0/s0-eth2.json"
targetARoutePath = "switch0/s0-route.json"
targetBInterfacePathEth1 = "switch1/s1-eth1.json"
targetBInterfacePathEth2 = "switch1/s1-eth2.json"
targetBRoutePath = "switch1/s1-route.json"
relativePathToJSONSources = "../utils/json_sources/Lab01/"
pathToRouteConfig = "network-instances/network-instance"
pathToInterfaceConfig = "interfaces/interface"
targetLeafInterfaceEth1 = "eth1"
targetLeafInterfaceEth2 = "eth2"
targetLeafRoute = "route"
targetAInterfaceFilePathEth1 = "switch0/s0-eth1.json"
targetAInterfaceFilePathEth2 = "switch0/s0-eth2.json"
targetARouteFilePath = "switch0/s0-route.json"
targetBInterfaceFilePathEth1 = "switch1/s1-eth1.json"
targetBInterfaceFilePathEth2 = "switch1/s1-eth2.json"
targetBRouteFilePath = "switch1/s1-route.json"
relativeFilePathToJSONSources = "../utils/json_sources/Lab01/"
)
var centosOCmds = [][]string{
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ip", "link", "set", "dev", "eth1", "mtu", "1500"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ip", "address", "add", "10.0.0.100/24", "dev", "eth1"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ip", "route", "del", "default"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ip", "route", "add", "default", "via", "10.0.0.1", "dev", "eth1"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ip", "route", "add", "10.50.0.2/32", "via", "10.0.0.1", "dev", "eth1"},
}
var centos1Cmds = [][]string{
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ip", "link", "set", "dev", "eth1", "mtu", "1500"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ip", "address", "add", "192.168.0.100/24", "dev", "eth1"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ip", "route", "del", "default"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ip", "route", "add", "default", "via", "192.168.0.1", "dev", "eth1"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ip", "route", "add", "10.50.0.1/32", "via", "192.168.0.1", "dev", "eth1"},
}
var centosPingCmds = [][]string{
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos0", "ping", "192.168.0.100", "-c", "3"},
{"docker", "exec", "clab-gosdn_csbi_arista_base-centos1", "ping", "10.0.0.100", "-c", "3"},
}
// Represents the yang models stored in JSON files.
// Contains the target leaf in the managed network element, the path to the JSON file and the JSON value, parsed as string.
type configEntry struct {
......@@ -56,16 +75,16 @@ var managedNetworkElements = []managedNetworkElement{
addr: integration_test_utils.DefaultTargetAAdress,
configEntries: []configEntry{
{
leaf: targetInterfaceEth1,
path: targetAInterfacePathEth1,
leaf: targetLeafInterfaceEth1,
path: targetAInterfaceFilePathEth1,
},
{
leaf: targetInterfaceEth2,
path: targetAInterfacePathEth2,
leaf: targetLeafInterfaceEth2,
path: targetAInterfaceFilePathEth2,
},
{
leaf: targetRoute,
path: targetARoutePath,
leaf: targetLeafRoute,
path: targetARouteFilePath,
},
},
},
......@@ -75,16 +94,16 @@ var managedNetworkElements = []managedNetworkElement{
addr: integration_test_utils.DefaultTargetBAdress,
configEntries: []configEntry{
{
leaf: targetInterfaceEth1,
path: targetBInterfacePathEth1,
leaf: targetLeafInterfaceEth1,
path: targetBInterfaceFilePathEth1,
},
{
leaf: targetInterfaceEth2,
path: targetBInterfacePathEth2,
leaf: targetLeafInterfaceEth2,
path: targetBInterfaceFilePathEth2,
},
{
leaf: targetRoute,
path: targetBRoutePath,
leaf: targetLeafRoute,
path: targetBRouteFilePath,
},
},
},
......@@ -121,7 +140,7 @@ func TestMain(m *testing.M) {
// The following test describes a chain of commands (see
// https://code.fbi.h-da.de/danet/gosdn/-/wikis/Labs/Lab01).
func TestLab01(t *testing.T) {
func TestLab01ChangeAndCheckNetworkConfigPaths(t *testing.T) {
defer integration_test_utils.ApplySDNConfig(conn, ctx, defaultSDNConfig)
mneService := mnepb.NewNetworkElementServiceClient(conn)
......@@ -150,7 +169,7 @@ func TestLab01(t *testing.T) {
// Cast JSON config files into strings
for _, mne := range managedNetworkElements {
for i := 0; i < len(mne.configEntries); i++ {
jsonValue, err := lab_utils.ParseFileContent(relativePathToJSONSources + mne.configEntries[i].path)
jsonValue, err := lab_utils.ParseFileContent(relativeFilePathToJSONSources + mne.configEntries[i].path)
if err != nil {
t.Error(err)
}
......@@ -158,26 +177,14 @@ func TestLab01(t *testing.T) {
}
}
// Modify the interface of both managed network elements.
// Modify the configuration of the network elements.
for _, mne := range managedNetworkElements {
for i := 0; i < len(mne.configEntries); i++ {
var pathListRequest *mnepb.SetPathListRequest
var err error
// Interface change request
if strings.Contains(mne.configEntries[i].leaf, "eth") {
pathListRequest, err = lab_utils.SetPathListRequestFromJsonImport(pathToInterfaceConfig, mne.configEntries[i].leaf, mne.id, mnepb.ApiOperation_API_OPERATION_UPDATE, mne.configEntries[i].value, pndID)
if err != nil {
t.Error(err)
}
// Route change request
} else if strings.Contains(mne.configEntries[i].leaf, "route") {
pathListRequest, err = lab_utils.SetPathListRequestFromJsonImport(pathToRouteConfig, mne.configEntries[i].leaf, mne.id, mnepb.ApiOperation_API_OPERATION_UPDATE, mne.configEntries[i].value, pndID)
// Create change request
pathListRequest, err := lab_utils.SetPathListRequestFromJsonImport(mne.configEntries[i].leaf, mne.id, pndID, mnepb.ApiOperation_API_OPERATION_UPDATE, mne.configEntries[i].value)
if err != nil {
t.Error(err)
}
}
// Set the requested path on managed network element
setResp, err := mneService.SetPathList(ctx, pathListRequest)
......@@ -193,9 +200,43 @@ func TestLab01(t *testing.T) {
}
}
// Check if the network interface has been changed
// TODO Find a nicer and more accurate way
// Check if the paths have been changed
// for _, mne := range managedNetworkElements {
// for i := 0; i < len(mne.configEntries); i++ {
// // Create get request
// pathRequest := lab_utils.GetPathRequest(mne.configEntries[i].leaf, mne.id, pndID)
// resp, err := mneService.GetPath(ctx, pathRequest)
// if err != nil {
// t.Error(err)
// }
// Check if the routing configuration has been changed
// // Check if leaf has expected value
// configEntryFormatted := lab_utils.RemoveStringFormatting(string(mne.configEntries[i].value))
// isJsonSubsetOfMneValue, err := lab_utils.IsASubstring(string(resp.MneNotification[0].GetUpdate()[0].GetVal().GetJsonIetfVal()), configEntryFormatted)
// if err != nil {
// t.Error(err)
// }
// assert.Equal(t, 1, len(resp.GetMneNotification()), "Exactly one response is expected.")
// assert.True(t, isJsonSubsetOfMneValue, "Exptected the new changed routing or interface config.")
// }
// }
}
// Ping to check connection between both managed network elements.
func TestLab01CheckConnectionOfNetworkElements(t *testing.T) {
// Configure Interfaces and create routes on clients centos0 and centos1
for i := 0; i < len(centosOCmds); i++ {
lab_utils.ExecBashCmd(centosOCmds[i])
}
for i := 0; i < len(centos1Cmds); i++ {
lab_utils.ExecBashCmd(centos1Cmds[i])
}
// Ping to check connection between centos0 > gnmi-targetA > gnmi-targetB > centos1
// and centos1 > gnmi-targetB > gnmi-targetA > centos0
for i := 0; i < len(centosPingCmds); i++ {
output := lab_utils.ExecBashCmd(centosPingCmds[i])
assert.True(t, strings.Contains(output, "3 packets transmitted, 3 received, 0% packet loss"))
}
}
......@@ -2,7 +2,13 @@ package lab_utils
import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"reflect"
"sort"
"strings"
mnepb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
......@@ -11,6 +17,11 @@ import (
"github.com/openconfig/ygot/ygot"
)
const (
routePath = "network-instances/network-instance[name=default]/protocols"
interfacePath = "interfaces/interface"
)
func GetHostnameSingleMne(mneId string, pndID string) *mnepb.GetPathRequest {
gpr := &mnepb.GetPathRequest{
Timestamp: integration_test_utils.GetTimestamp(),
......@@ -104,15 +115,22 @@ func CreateAddListRequestSingleMne(addr, name, id, username, password string, pn
return alr
}
func SetPathListRequestFromJsonImport(pathToLeaf string, leaf string, mneId string, operation mnepb.ApiOperation, newInterfaceConfig []byte, pndID string) (*mnepb.SetPathListRequest, error) {
// Extract network interface
completePathToLeaf := pathToLeaf + "[name=" + leaf + "]"
interfacePath, err := ygot.StringToStructuredPath(completePathToLeaf)
func SetPathListRequestFromJsonImport(leaf, mneId, pndID string, operation mnepb.ApiOperation, newInterfaceConfig []byte) (*mnepb.SetPathListRequest, error) {
// Build path to config
var completePathToLeaf string
if strings.Contains(leaf, "eth") {
completePathToLeaf = interfacePath + "[name=" + leaf + "]"
} else if strings.Contains(leaf, "route") {
completePathToLeaf = routePath
}
// Create the yang path
structuredPath, err := ygot.StringToStructuredPath(completePathToLeaf)
if err != nil {
return nil, err
}
// Create the yang path
// Create typed value
typedValue := &gnmi.TypedValue{
Value: &gnmi.TypedValue_JsonIetfVal{
JsonIetfVal: newInterfaceConfig,
......@@ -125,7 +143,7 @@ func SetPathListRequestFromJsonImport(pathToLeaf string, leaf string, mneId stri
ChangeRequest: []*mnepb.ChangeRequest{
{
Mneid: mneId,
Path: interfacePath,
Path: structuredPath,
Value: typedValue,
ApiOp: operation,
},
......@@ -141,3 +159,81 @@ func ParseFileContent(path string) ([]byte, error) {
}
return fileContent, nil
}
func GetPathRequest(leaf, mneId, pndID string) *mnepb.GetPathRequest {
var completePathToLeaf string
if strings.Contains(leaf, "eth") {
completePathToLeaf = interfacePath + "[name=" + leaf + "]"
} else if strings.Contains(leaf, "route") {
completePathToLeaf = routePath
}
gpr := &mnepb.GetPathRequest{
Timestamp: integration_test_utils.GetTimestamp(),
Mneid: mneId,
Path: completePathToLeaf,
Pid: pndID,
}
return gpr
}
func RemoveStringFormatting(formattedString string) string {
removedFormatting := strings.Replace(formattedString, " ", "", -1)
removedFormatting = strings.Replace(removedFormatting, "\n", "", -1)
return removedFormatting
}
func IsASubstring(x, y string) (bool, error) {
// Unmarshal JSON strings into map[string]interface{}
var mapX, mapY map[string]interface{}
if err := json.Unmarshal([]byte(x), &mapX); err != nil {
return false, err
}
if err := json.Unmarshal([]byte(y), &mapY); err != nil {
return false, err
}
// Sort keys for comparison
sortMap(&mapX)
sortMap(&mapY)
fmt.Println(mapX)
fmt.Println(mapY)
// Check if all key-value pairs in mapX are present in mapY
for key, valX := range mapX {
valY, ok := mapY[key]
if !ok || !reflect.DeepEqual(valX, valY) {
return false, nil
}
}
return true, nil
}
// Sorts keys of a map[string]interface{}.
func sortMap(m *map[string]interface{}) {
keys := make([]string, 0, len(*m))
for k := range *m {
keys = append(keys, k)
}
sort.Strings(keys)
sorted := make(map[string]interface{})
for _, k := range keys {
sorted[k] = (*m)[k]
}
*m = sorted
}
func ExecBashCmd(args []string) string {
cmd := exec.Command(args[0], args[1:]...)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(err)
}
// Convert bytes.Buffer to string
outputString := string(output)
return outputString
}
......@@ -40,3 +40,10 @@ containerlab-integration-tests-start: create-clab-dir containerize-all generate-
containerlab-integration-tests-stop: create-clab-dir
cd $(CLAB_DIR) &&\
sudo containerlab destroy --topo $(MAKEFILE_DIR)dev_env_data/clab/integration-tests.yaml
containerlab-integration-tests-rush: create-clab-dir containerize-all generate-all-certs
cd $(CLAB_DIR) &&\
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/integration-tests.yaml --log-level debug
go clean -testcache
go test -p 1 ./integration-tests/... -v
sudo containerlab destroy --topo $(MAKEFILE_DIR)dev_env_data/clab/integration-tests.yaml
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment