github.com/cilium/cilium@v1.16.2/pkg/hubble/metrics/port-distribution/handler_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package portdistribution
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"github.com/prometheus/client_golang/prometheus"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	wrappers "google.golang.org/protobuf/types/known/wrapperspb"
    14  
    15  	pb "github.com/cilium/cilium/api/v1/flow"
    16  	"github.com/cilium/cilium/pkg/hubble/metrics/api"
    17  	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
    18  )
    19  
    20  func TestPortDistributionHandler(t *testing.T) {
    21  	registry := prometheus.NewRegistry()
    22  	opts := api.Options{"sourceContext": "namespace", "destinationContext": "namespace"}
    23  
    24  	portHandler := &portDistributionHandler{}
    25  
    26  	t.Run("Init", func(t *testing.T) {
    27  		require.NoError(t, portHandler.Init(registry, opts))
    28  	})
    29  
    30  	t.Run("Status", func(t *testing.T) {
    31  		require.Equal(t, "destination=namespace,source=namespace", portHandler.Status())
    32  	})
    33  
    34  	t.Run("ProcessFlow_SkipReply", func(t *testing.T) {
    35  		flow := buildFlow(8080, pb.Verdict_FORWARDED, true)
    36  		portHandler.ProcessFlow(context.TODO(), flow)
    37  
    38  		metricFamilies, err := registry.Gather()
    39  		require.NoError(t, err)
    40  
    41  		require.Empty(t, metricFamilies)
    42  	})
    43  
    44  	t.Run("ProcessFlow_SkipDropped", func(t *testing.T) {
    45  		flow := buildFlow(8080, pb.Verdict_DROPPED, false)
    46  		portHandler.ProcessFlow(context.TODO(), flow)
    47  
    48  		metricFamilies, err := registry.Gather()
    49  		require.NoError(t, err)
    50  
    51  		require.Empty(t, metricFamilies)
    52  	})
    53  
    54  	t.Run("ProcessFlow", func(t *testing.T) {
    55  		flow := buildFlow(8080, pb.Verdict_FORWARDED, false)
    56  		portHandler.ProcessFlow(context.TODO(), flow)
    57  
    58  		metricFamilies, err := registry.Gather()
    59  		require.NoError(t, err)
    60  
    61  		assert.Equal(t, "hubble_port_distribution_total", *metricFamilies[0].Name)
    62  		require.Len(t, metricFamilies[0].Metric, 1)
    63  		metric := metricFamilies[0].Metric[0]
    64  
    65  		assert.Equal(t, "destination", *metric.Label[0].Name)
    66  		assert.Equal(t, "bar", *metric.Label[0].Value)
    67  
    68  		assert.Equal(t, "port", *metric.Label[1].Name)
    69  		assert.Equal(t, "8080", *metric.Label[1].Value)
    70  
    71  		assert.Equal(t, "protocol", *metric.Label[2].Name)
    72  		assert.Equal(t, "TCP", *metric.Label[2].Value)
    73  
    74  		assert.Equal(t, "source", *metric.Label[3].Name)
    75  		assert.Equal(t, "foo", *metric.Label[3].Value)
    76  
    77  		assert.Equal(t, 1., *metric.Counter.Value)
    78  
    79  		//send another flow with same labels
    80  		portHandler.ProcessFlow(context.TODO(), flow)
    81  		metricFamilies, _ = registry.Gather()
    82  		metric = metricFamilies[0].Metric[0]
    83  		assert.Equal(t, 2., *metric.Counter.Value)
    84  	})
    85  
    86  	t.Run("ProcessFlow_MultiplePorts", func(t *testing.T) {
    87  		registry := prometheus.NewRegistry()
    88  		opts := api.Options{"sourceContext": "namespace", "destinationContext": "namespace"}
    89  
    90  		portHandler := &portDistributionHandler{}
    91  		require.NoError(t, portHandler.Init(registry, opts))
    92  
    93  		flow1 := buildFlow(8081, pb.Verdict_FORWARDED, false)
    94  		portHandler.ProcessFlow(context.TODO(), flow1)
    95  
    96  		flow2 := buildFlow(8082, pb.Verdict_FORWARDED, false)
    97  		portHandler.ProcessFlow(context.TODO(), flow2)
    98  		portHandler.ProcessFlow(context.TODO(), flow2)
    99  
   100  		metricFamilies, err := registry.Gather()
   101  		require.NoError(t, err)
   102  
   103  		assert.Equal(t, "hubble_port_distribution_total", *metricFamilies[0].Name)
   104  		require.Len(t, metricFamilies[0].Metric, 2)
   105  
   106  		for _, metric := range metricFamilies[0].Metric {
   107  			switch *metric.Label[1].Value {
   108  			case "8081":
   109  				assert.Equal(t, 1., *metric.Counter.Value)
   110  			case "8082":
   111  				assert.Equal(t, 2., *metric.Counter.Value)
   112  			}
   113  		}
   114  	})
   115  
   116  }
   117  
   118  func buildFlow(port uint32, verdict pb.Verdict, reply bool) *pb.Flow {
   119  	return &pb.Flow{
   120  		EventType: &pb.CiliumEventType{Type: monitorAPI.MessageTypePolicyVerdict},
   121  		L4: &pb.Layer4{
   122  			Protocol: &pb.Layer4_TCP{
   123  				TCP: &pb.TCP{
   124  					DestinationPort: port,
   125  				},
   126  			},
   127  		},
   128  		Source:      &pb.Endpoint{Namespace: "foo"},
   129  		Destination: &pb.Endpoint{Namespace: "bar"},
   130  		Verdict:     verdict,
   131  		IsReply:     &wrappers.BoolValue{Value: reply},
   132  	}
   133  }