diff --git a/go.mod b/go.mod index bdd90ea..64f04bd 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,8 @@ require ( github.com/networkservicemesh/sdk v0.5.1-0.20240205110352-f37b863ccb82 github.com/sirupsen/logrus v1.9.0 github.com/spiffe/go-spiffe/v2 v2.0.0 + github.com/stretchr/testify v1.8.4 + go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.59.0 ) @@ -21,6 +23,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.3.0 // indirect @@ -42,6 +45,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect diff --git a/go.sum b/go.sum index 7de03ca..653c677 100644 --- a/go.sum +++ b/go.sum @@ -175,6 +175,7 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= diff --git a/model_utils.go b/model_utils.go index 8f2e3a4..b1b4aa4 100644 --- a/model_utils.go +++ b/model_utils.go @@ -1,6 +1,4 @@ -// Copyright (c) 2023 Cisco and/or its affiliates. -// -// Copyright (c) 2023 Pragmagic Inc. and/or its affiliates. +// Copyright (c) 2023-2024 Pragmagic Inc. and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -87,13 +85,13 @@ func parceConnectionsToGraphicalModel() { nodeMap[interfID] = makeInterface(interfID, node.Data.ID, getInterfaceLabelFromMetrics(segment, serverInterface)) edges = addEdge(edges, previousInterfaceID, interfID, interfaceConnection, healthy) case segmentType == forwarderNT: - interfCID := fmt.Sprintf("int-c--%s--%s", connectionID, node.Data.ID) - nodeMap[interfCID] = makeInterface(interfCID, node.Data.ID, getInterfaceLabelFromMetrics(segment, clientInterface)) - edges = addEdge(edges, previousInterfaceID, interfCID, interfaceConnection, healthy) interfEID := fmt.Sprintf("int-s--%s--%s", connectionID, node.Data.ID) nodeMap[interfEID] = makeInterface(interfEID, node.Data.ID, getInterfaceLabelFromMetrics(segment, serverInterface)) - edges = addEdge(edges, interfCID, interfEID, interfaceCrossConnection, healthy) - previousInterfaceID = interfEID + edges = addEdge(edges, previousInterfaceID, interfEID, interfaceConnection, healthy) + interfCID := fmt.Sprintf("int-c--%s--%s", connectionID, node.Data.ID) + nodeMap[interfCID] = makeInterface(interfCID, node.Data.ID, getInterfaceLabelFromMetrics(segment, clientInterface)) + edges = addEdge(edges, interfEID, interfCID, interfaceCrossConnection, healthy) + previousInterfaceID = interfCID // TODO Aggregate statistics for the Overview page } } diff --git a/model_utils_test.go b/model_utils_test.go new file mode 100644 index 0000000..7233796 --- /dev/null +++ b/model_utils_test.go @@ -0,0 +1,128 @@ +// Copyright (c) 2024 Pragmagic Inc. and/or its affiliates. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 main + +import ( + "fmt" + "testing" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/stretchr/testify/require" + "go.uber.org/goleak" +) + +func Test_Interface_Order(t *testing.T) { + t.Cleanup(func() { + goleak.VerifyNone(t) + }) + + nsmgrAddr := "10.244.1.4:5001" + nscName := "alpine-0a9d9aa7" + fwd1Name := "forwarder-vpp-t2jgb" + fwd2Name := "forwarder-vpp-9dxwt" + nseName := "nse-kernel-zz6m5" + + connection := &networkservice.Connection{ + NetworkService: "kernel2ip2kernel", + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{ + { + Name: nscName, + Id: "alpine-0a9d9aa7-0", + Metrics: map[string]string{ + "client_interface": "KERNEL/nsm-1", + }, + }, + { + Name: "nsmgr-2pctm", + Id: "12345", + }, + { + Name: fwd1Name, + Id: "23456", + Metrics: map[string]string{ + "client_interface": "WIREGUARD TUNNEL/wg0", + "server_interface": "VIRTIO/tun0", + }, + }, + { + Name: "nsmgr-zjr6b", + Id: "34567", + }, + { + Name: fwd2Name, + Id: "45678", + Metrics: map[string]string{ + "client_interface": "VIRTIO/tun0", + "server_interface": "WIREGUARD TUNNEL/wg0", + }, + }, + { + Name: nseName, + Id: "56789", + Metrics: map[string]string{ + "server_interface": "KERNEL/kernel2ip2-ff6c", + }, + }, + }, + }, + } + connectionID := generateConnectionID(connection) + + connections.Store(connectionID, connection) + addManagerConnection(nsmgrAddr, connectionID) + parceConnectionsToGraphicalModel() + + require.Equal(t, 14, len(storageData.Nodes)) + require.Equal(t, 5, len(storageData.Edges)) + + // Connection 1 (client-forwarder1) + source1 := fmt.Sprintf("int-c--%s--%s", connectionID, nscName) + target1 := fmt.Sprintf("int-s--%s--%s", connectionID, fwd1Name) + require.Equal(t, source1, storageData.Edges[0].Data.Source) + require.Equal(t, target1, storageData.Edges[0].Data.Target) + // Connection 2 (forwarder1 internal interface cross connection) + source2 := fmt.Sprintf("int-s--%s--%s", connectionID, fwd1Name) + target2 := fmt.Sprintf("int-c--%s--%s", connectionID, fwd1Name) + require.Equal(t, source2, storageData.Edges[1].Data.Source) + require.Equal(t, target2, storageData.Edges[1].Data.Target) + // Connection 3 (forwarder1-forwarder2) + source3 := fmt.Sprintf("int-c--%s--%s", connectionID, fwd1Name) + target3 := fmt.Sprintf("int-s--%s--%s", connectionID, fwd2Name) + require.Equal(t, source3, storageData.Edges[2].Data.Source) + require.Equal(t, target3, storageData.Edges[2].Data.Target) + // Connection 4 (forwarder2 internal interface cross connection) + source4 := fmt.Sprintf("int-s--%s--%s", connectionID, fwd2Name) + target4 := fmt.Sprintf("int-c--%s--%s", connectionID, fwd2Name) + require.Equal(t, source4, storageData.Edges[3].Data.Source) + require.Equal(t, target4, storageData.Edges[3].Data.Target) + // Connection 5 (forwarder2-endpoint) + source5 := fmt.Sprintf("int-c--%s--%s", connectionID, fwd2Name) + target5 := fmt.Sprintf("int-s--%s--%s", connectionID, nseName) + require.Equal(t, source5, storageData.Edges[4].Data.Source) + require.Equal(t, target5, storageData.Edges[4].Data.Target) + + // Cleanup + connections.Delete(connectionID) + managerConnections.Delete(nsmgrAddr) + nsmgrs.Delete(nsmgrAddr) + parceConnectionsToGraphicalModel() + + require.Equal(t, 0, len(storageData.Nodes)) + require.Equal(t, 0, len(storageData.Edges)) +}