mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-06-22 06:18:51 +00:00
416 lines
11 KiB
Go
416 lines
11 KiB
Go
package servicemap
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
tapApi "github.com/up9inc/mizu/tap/api"
|
|
)
|
|
|
|
const (
|
|
a = "aService"
|
|
b = "bService"
|
|
c = "cService"
|
|
d = "dService"
|
|
Ip = "127.0.0.1"
|
|
Port = "80"
|
|
)
|
|
|
|
var (
|
|
TCPEntryA = &tapApi.TCP{
|
|
Name: a,
|
|
Port: Port,
|
|
IP: fmt.Sprintf("%s.%s", Ip, a),
|
|
}
|
|
TCPEntryB = &tapApi.TCP{
|
|
Name: b,
|
|
Port: Port,
|
|
IP: fmt.Sprintf("%s.%s", Ip, b),
|
|
}
|
|
TCPEntryC = &tapApi.TCP{
|
|
Name: c,
|
|
Port: Port,
|
|
IP: fmt.Sprintf("%s.%s", Ip, c),
|
|
}
|
|
TCPEntryD = &tapApi.TCP{
|
|
Name: d,
|
|
Port: Port,
|
|
IP: fmt.Sprintf("%s.%s", Ip, d),
|
|
}
|
|
TCPEntryUnresolved = &tapApi.TCP{
|
|
Name: "",
|
|
Port: Port,
|
|
IP: Ip,
|
|
}
|
|
TCPEntryUnresolved2 = &tapApi.TCP{
|
|
Name: "",
|
|
Port: Port,
|
|
IP: fmt.Sprintf("%s.%s", Ip, UnresolvedNodeName),
|
|
}
|
|
ProtocolHttp = &tapApi.Protocol{
|
|
Name: "http",
|
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
|
Abbreviation: "HTTP",
|
|
Macro: "http",
|
|
Version: "1.1",
|
|
BackgroundColor: "#205cf5",
|
|
ForegroundColor: "#ffffff",
|
|
FontSize: 12,
|
|
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc2616",
|
|
Ports: []string{"80", "443", "8080"},
|
|
Priority: 0,
|
|
}
|
|
ProtocolRedis = &tapApi.Protocol{
|
|
Name: "redis",
|
|
LongName: "Redis Serialization Protocol",
|
|
Abbreviation: "REDIS",
|
|
Macro: "redis",
|
|
Version: "3.x",
|
|
BackgroundColor: "#a41e11",
|
|
ForegroundColor: "#ffffff",
|
|
FontSize: 11,
|
|
ReferenceLink: "https://redis.io/topics/protocol",
|
|
Ports: []string{"6379"},
|
|
Priority: 3,
|
|
}
|
|
)
|
|
|
|
type ServiceMapDisabledSuite struct {
|
|
suite.Suite
|
|
|
|
instance *defaultServiceMap
|
|
}
|
|
|
|
type ServiceMapEnabledSuite struct {
|
|
suite.Suite
|
|
|
|
instance *defaultServiceMap
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) SetupTest() {
|
|
s.instance = GetDefaultServiceMapInstance()
|
|
}
|
|
|
|
func (s *ServiceMapEnabledSuite) SetupTest() {
|
|
s.instance = GetDefaultServiceMapInstance()
|
|
s.instance.Enable()
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) TestServiceMapInstance() {
|
|
assert := s.Assert()
|
|
|
|
assert.NotNil(s.instance)
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) TestServiceMapSingletonInstance() {
|
|
assert := s.Assert()
|
|
|
|
instance2 := GetDefaultServiceMapInstance()
|
|
|
|
assert.NotNil(s.instance)
|
|
assert.NotNil(instance2)
|
|
assert.Equal(s.instance, instance2)
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) TestServiceMapIsEnabledShouldReturnFalseByDefault() {
|
|
assert := s.Assert()
|
|
|
|
enabled := s.instance.IsEnabled()
|
|
|
|
assert.False(enabled)
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) TestGetStatusShouldReturnDisabledByDefault() {
|
|
assert := s.Assert()
|
|
|
|
status := s.instance.GetStatus()
|
|
|
|
assert.Equal("disabled", status.Status)
|
|
assert.Equal(0, status.EntriesProcessedCount)
|
|
assert.Equal(0, status.NodeCount)
|
|
assert.Equal(0, status.EdgeCount)
|
|
}
|
|
|
|
func (s *ServiceMapDisabledSuite) TestNewTCPEntryShouldDoNothingWhenDisabled() {
|
|
assert := s.Assert()
|
|
|
|
s.instance.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp)
|
|
s.instance.NewTCPEntry(TCPEntryC, TCPEntryD, ProtocolHttp)
|
|
status := s.instance.GetStatus()
|
|
|
|
assert.Equal("disabled", status.Status)
|
|
assert.Equal(0, status.EntriesProcessedCount)
|
|
assert.Equal(0, status.NodeCount)
|
|
assert.Equal(0, status.EdgeCount)
|
|
}
|
|
|
|
// Enabled
|
|
|
|
func (s *ServiceMapEnabledSuite) TestServiceMapIsEnabled() {
|
|
assert := s.Assert()
|
|
|
|
enabled := s.instance.IsEnabled()
|
|
|
|
assert.True(enabled)
|
|
}
|
|
|
|
func (s *ServiceMapEnabledSuite) TestServiceMap() {
|
|
assert := s.Assert()
|
|
|
|
// A -> B - HTTP
|
|
s.instance.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp)
|
|
|
|
nodes := s.instance.GetNodes()
|
|
edges := s.instance.GetEdges()
|
|
|
|
// Counts for the first entry
|
|
assert.Equal(1, s.instance.GetEntriesProcessedCount())
|
|
assert.Equal(2, s.instance.GetNodesCount())
|
|
assert.Equal(2, len(nodes))
|
|
assert.Equal(1, s.instance.GetEdgesCount())
|
|
assert.Equal(1, len(edges))
|
|
//http protocol
|
|
assert.Equal(1, edges[0].Count)
|
|
assert.Equal(ProtocolHttp.Name, edges[0].Protocol.Name)
|
|
|
|
// same A -> B - HTTP, http protocol count should be 2, edges count should be 1
|
|
s.instance.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp)
|
|
|
|
nodes = s.instance.GetNodes()
|
|
edges = s.instance.GetEdges()
|
|
|
|
// Counts for a second entry
|
|
assert.Equal(2, s.instance.GetEntriesProcessedCount())
|
|
assert.Equal(2, s.instance.GetNodesCount())
|
|
assert.Equal(2, len(nodes))
|
|
// edges count should still be 1, but http protocol count should be 2
|
|
assert.Equal(1, s.instance.GetEdgesCount())
|
|
assert.Equal(1, len(edges))
|
|
// http protocol
|
|
assert.Equal(2, edges[0].Count) //http
|
|
assert.Equal(ProtocolHttp.Name, edges[0].Protocol.Name)
|
|
|
|
// same A -> B - REDIS, http protocol count should be 2 and redis protocol count should 1, edges count should be 2
|
|
s.instance.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolRedis)
|
|
|
|
nodes = s.instance.GetNodes()
|
|
edges = s.instance.GetEdges()
|
|
|
|
// Counts after second entry
|
|
assert.Equal(3, s.instance.GetEntriesProcessedCount())
|
|
assert.Equal(2, s.instance.GetNodesCount())
|
|
assert.Equal(2, len(nodes))
|
|
// edges count should be 2, http protocol count should be 2 and redis protocol should be 1
|
|
assert.Equal(2, s.instance.GetEdgesCount())
|
|
assert.Equal(2, len(edges))
|
|
// http and redis protocols
|
|
httpIndex := -1
|
|
redisIndex := -1
|
|
for i, e := range edges {
|
|
if e.Protocol.Name == ProtocolHttp.Name {
|
|
httpIndex = i
|
|
continue
|
|
}
|
|
if e.Protocol.Name == ProtocolRedis.Name {
|
|
redisIndex = i
|
|
}
|
|
}
|
|
assert.NotEqual(-1, httpIndex)
|
|
assert.NotEqual(-1, redisIndex)
|
|
// http protocol
|
|
assert.Equal(2, edges[httpIndex].Count)
|
|
assert.Equal(ProtocolHttp.Name, edges[httpIndex].Protocol.Name)
|
|
// redis protocol
|
|
assert.Equal(1, edges[redisIndex].Count)
|
|
assert.Equal(ProtocolRedis.Name, edges[redisIndex].Protocol.Name)
|
|
|
|
// other entries
|
|
s.instance.NewTCPEntry(TCPEntryUnresolved, TCPEntryA, ProtocolHttp)
|
|
s.instance.NewTCPEntry(TCPEntryB, TCPEntryUnresolved2, ProtocolHttp)
|
|
s.instance.NewTCPEntry(TCPEntryC, TCPEntryD, ProtocolHttp)
|
|
s.instance.NewTCPEntry(TCPEntryA, TCPEntryC, ProtocolHttp)
|
|
|
|
status := s.instance.GetStatus()
|
|
nodes = s.instance.GetNodes()
|
|
edges = s.instance.GetEdges()
|
|
expectedEntriesProcessedCount := 7
|
|
expectedNodeCount := 6
|
|
expectedEdgeCount := 6
|
|
|
|
// Counts after all entries
|
|
assert.Equal(expectedEntriesProcessedCount, s.instance.GetEntriesProcessedCount())
|
|
assert.Equal(expectedNodeCount, s.instance.GetNodesCount())
|
|
assert.Equal(expectedNodeCount, len(nodes))
|
|
assert.Equal(expectedEdgeCount, s.instance.GetEdgesCount())
|
|
assert.Equal(expectedEdgeCount, len(edges))
|
|
|
|
// Status
|
|
assert.Equal("enabled", status.Status)
|
|
assert.Equal(expectedEntriesProcessedCount, status.EntriesProcessedCount)
|
|
assert.Equal(expectedNodeCount, status.NodeCount)
|
|
assert.Equal(expectedEdgeCount, status.EdgeCount)
|
|
|
|
// Nodes
|
|
aNode := -1
|
|
bNode := -1
|
|
cNode := -1
|
|
dNode := -1
|
|
unresolvedNode := -1
|
|
unresolvedNode2 := -1
|
|
var validateNode = func(node ServiceMapNode, entryName string, count int) int {
|
|
// id
|
|
assert.GreaterOrEqual(node.Id, 1)
|
|
assert.LessOrEqual(node.Id, expectedNodeCount)
|
|
|
|
// entry
|
|
// node.Name is the key of the node, key = entry.Name by default
|
|
// entry.Name is the name of the service and could be unresolved
|
|
// when entry.Name is unresolved, key = entry.IP
|
|
if node.Entry.Name == UnresolvedNodeName {
|
|
assert.Equal(node.Name, node.Entry.IP)
|
|
} else {
|
|
assert.Equal(node.Name, node.Entry.Name)
|
|
}
|
|
assert.Equal(Port, node.Entry.Port)
|
|
assert.Equal(entryName, node.Entry.Name)
|
|
|
|
// count
|
|
assert.Equal(count, node.Count)
|
|
|
|
return node.Id
|
|
}
|
|
|
|
for _, v := range nodes {
|
|
if strings.HasSuffix(v.Name, a) {
|
|
aNode = validateNode(v, a, 5)
|
|
continue
|
|
}
|
|
if strings.HasSuffix(v.Name, b) {
|
|
bNode = validateNode(v, b, 4)
|
|
continue
|
|
}
|
|
if strings.HasSuffix(v.Name, c) {
|
|
cNode = validateNode(v, c, 2)
|
|
continue
|
|
}
|
|
if strings.HasSuffix(v.Name, d) {
|
|
dNode = validateNode(v, d, 1)
|
|
continue
|
|
}
|
|
if v.Name == Ip {
|
|
unresolvedNode = validateNode(v, UnresolvedNodeName, 1)
|
|
continue
|
|
}
|
|
if strings.HasSuffix(v.Name, UnresolvedNodeName) {
|
|
unresolvedNode2 = validateNode(v, UnresolvedNodeName, 1)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Make sure we found all the nodes
|
|
nodeIds := [...]int{aNode, bNode, cNode, dNode, unresolvedNode, unresolvedNode2}
|
|
for _, v := range nodeIds {
|
|
assert.NotEqual(-1, v)
|
|
}
|
|
|
|
// Edges
|
|
abEdge := -1
|
|
uaEdge := -1
|
|
buEdge := -1
|
|
cdEdge := -1
|
|
acEdge := -1
|
|
var validateEdge = func(edge ServiceMapEdge, sourceEntryName string, destEntryName string, protocolName string, protocolCount int) {
|
|
// source node
|
|
assert.Contains(nodeIds, edge.Source.Id)
|
|
assert.LessOrEqual(edge.Source.Id, expectedNodeCount)
|
|
if edge.Source.Entry.Name == UnresolvedNodeName {
|
|
assert.Equal(edge.Source.Name, edge.Source.Entry.IP)
|
|
} else {
|
|
assert.Equal(edge.Source.Name, edge.Source.Entry.Name)
|
|
}
|
|
assert.Equal(sourceEntryName, edge.Source.Entry.Name)
|
|
|
|
// destination node
|
|
assert.Contains(nodeIds, edge.Destination.Id)
|
|
assert.LessOrEqual(edge.Destination.Id, expectedNodeCount)
|
|
if edge.Destination.Entry.Name == UnresolvedNodeName {
|
|
assert.Equal(edge.Destination.Name, edge.Destination.Entry.IP)
|
|
} else {
|
|
assert.Equal(edge.Destination.Name, edge.Destination.Entry.Name)
|
|
}
|
|
assert.Equal(destEntryName, edge.Destination.Entry.Name)
|
|
|
|
// protocol
|
|
assert.Equal(protocolName, edge.Protocol.Name)
|
|
assert.Equal(protocolCount, edge.Count)
|
|
}
|
|
|
|
for i, v := range edges {
|
|
if v.Source.Entry.Name == a && v.Destination.Entry.Name == b && v.Protocol.Name == "http" {
|
|
validateEdge(v, a, b, ProtocolHttp.Name, 2)
|
|
abEdge = i
|
|
continue
|
|
}
|
|
if v.Source.Entry.Name == a && v.Destination.Entry.Name == b && v.Protocol.Name == "redis" {
|
|
validateEdge(v, a, b, ProtocolRedis.Name, 1)
|
|
abEdge = i
|
|
continue
|
|
}
|
|
if v.Source.Entry.Name == UnresolvedNodeName && v.Destination.Entry.Name == a {
|
|
validateEdge(v, UnresolvedNodeName, a, ProtocolHttp.Name, 1)
|
|
uaEdge = i
|
|
continue
|
|
}
|
|
if v.Source.Entry.Name == b && v.Destination.Entry.Name == UnresolvedNodeName {
|
|
validateEdge(v, b, UnresolvedNodeName, ProtocolHttp.Name, 1)
|
|
buEdge = i
|
|
continue
|
|
}
|
|
if v.Source.Entry.Name == c && v.Destination.Entry.Name == d {
|
|
validateEdge(v, c, d, ProtocolHttp.Name, 1)
|
|
cdEdge = i
|
|
continue
|
|
}
|
|
if v.Source.Entry.Name == a && v.Destination.Entry.Name == c {
|
|
validateEdge(v, a, c, ProtocolHttp.Name, 1)
|
|
acEdge = i
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Make sure we found all the edges
|
|
for _, v := range [...]int{abEdge, uaEdge, buEdge, cdEdge, acEdge} {
|
|
assert.NotEqual(-1, v)
|
|
}
|
|
|
|
// Reset
|
|
s.instance.Reset()
|
|
status = s.instance.GetStatus()
|
|
nodes = s.instance.GetNodes()
|
|
edges = s.instance.GetEdges()
|
|
|
|
// Counts after reset
|
|
assert.Equal(0, s.instance.GetEntriesProcessedCount())
|
|
assert.Equal(0, s.instance.GetNodesCount())
|
|
assert.Equal(0, s.instance.GetEdgesCount())
|
|
|
|
// Status after reset
|
|
assert.Equal("enabled", status.Status)
|
|
assert.Equal(0, status.EntriesProcessedCount)
|
|
assert.Equal(0, status.NodeCount)
|
|
assert.Equal(0, status.EdgeCount)
|
|
|
|
// Nodes after reset
|
|
assert.Equal([]ServiceMapNode{}, nodes)
|
|
|
|
// Edges after reset
|
|
assert.Equal([]ServiceMapEdge{}, edges)
|
|
}
|
|
|
|
func TestServiceMapSuite(t *testing.T) {
|
|
suite.Run(t, new(ServiceMapDisabledSuite))
|
|
suite.Run(t, new(ServiceMapEnabledSuite))
|
|
}
|