Repository: kmesh-net/kmesh

Issue:
ut coverage for same src/dst but different direction in metrics.go
<!-- Please only use this template for submitting enhancement requests -->

**What would you like to be added**:

**Why is this needed**:


Hints from issue comments:
@yp969803: done after the merge of #1378
@yp969803: /assign@yp969803: i will raise a pr after 3-4 days, currently busy with exams

Solution patch:
diff --git a/bpf/kmesh/workload/include/frontend.h b/bpf/kmesh/workload/include/frontend.h
index 8bb9a21f..a1649298 100644
--- a/bpf/kmesh/workload/include/frontend.h
+++ b/bpf/kmesh/workload/include/frontend.h
@@ -34,7 +34,7 @@ static inline int frontend_manager(struct kmesh_context *kmesh_ctx, frontend_val
         direct_backend = true;
     }
 
-    if (direct_backend) {
+    if (direct_backend) { // in this case, we donot check the healthy status of the backend, just let it go
         // For pod direct access, if a pod has waypoint captured, we will redirect to waypoint, otherwise we do nothing.
         if (backend_v->waypoint_port != 0) {
             BPF_LOG(
diff --git a/bpf/kmesh/workload/xdp.c b/bpf/kmesh/workload/xdp.c
index ad6d61fe..c8e9857d 100644
--- a/bpf/kmesh/workload/xdp.c
+++ b/bpf/kmesh/workload/xdp.c
@@ -70,7 +70,7 @@ static inline wl_policies_v *get_workload_policies(struct xdp_info *info, struct
     }
     frontend_v = kmesh_map_lookup_elem(&map_of_frontend, &frontend_k);
     if (!frontend_v) {
-        BPF_LOG(INFO, XDP, "failed to get frontend in xdp");
+        BPF_LOG(DEBUG, XDP, "failed to get frontend in xdp");
         return AUTH_ALLOW;
     }
     workload_uid = frontend_v->upstream_id;
diff --git a/pkg/controller/telemetry/metric.go b/pkg/controller/telemetry/metric.go
index 1dddb05c..8585c397 100644
--- a/pkg/controller/telemetry/metric.go
+++ b/pkg/controller/telemetry/metric.go
@@ -170,7 +170,6 @@ type requestMetric struct {
 	conSrcDstInfo  connectionSrcDst
 	origDstAddr    [4]uint32
 	origDstPort    uint16
-	direction      uint32
 	receivedBytes  uint32 // total bytes received after previous report
 	sentBytes      uint32 // total bytes sent after previous report
 	state          uint32
@@ -544,7 +543,6 @@ func buildV4Metric(buf *bytes.Buffer, tcpConns map[connectionSrcDst]connMetric)
 	reqMetric.conSrcDstInfo.src[0] = rawStats.SrcAddr
 	reqMetric.conSrcDstInfo.dst[0] = rawStats.DstAddr
 	reqMetric.conSrcDstInfo.direction = rawStats.Direction
-	reqMetric.direction = rawStats.Direction
 	reqMetric.conSrcDstInfo.dstPort = rawStats.DstPort
 	reqMetric.conSrcDstInfo.srcPort = rawStats.SrcPort
 
@@ -601,7 +599,6 @@ func buildV6Metric(buf *bytes.Buffer, tcpConns map[connectionSrcDst]connMetric)
 	reqMetric.conSrcDstInfo.src = rawStats.SrcAddr
 	reqMetric.conSrcDstInfo.dst = rawStats.DstAddr
 	reqMetric.conSrcDstInfo.direction = rawStats.Direction
-	reqMetric.direction = rawStats.Direction
 	reqMetric.conSrcDstInfo.dstPort = rawStats.DstPort
 	reqMetric.conSrcDstInfo.srcPort = rawStats.SrcPort
 
@@ -670,7 +667,7 @@ func (m *MetricController) buildWorkloadMetric(reqMetric *requestMetric) workloa
 	trafficLabels.requestProtocol = "tcp"
 	trafficLabels.connectionSecurityPolicy = "mutual_tls"
 
-	switch reqMetric.direction {
+	switch reqMetric.conSrcDstInfo.direction {
 	case constants.INBOUND:
 		trafficLabels.reporter = "destination"
 	case constants.OUTBOUND:
@@ -768,7 +765,7 @@ func (m *MetricController) buildServiceMetric(reqMetric *requestMetric) (service
 	accesslog.destinationAddress = dstIp + ":" + fmt.Sprintf("%d", reqMetric.conSrcDstInfo.dstPort)
 	accesslog.sourceAddress = srcIp + ":" + fmt.Sprintf("%d", reqMetric.conSrcDstInfo.srcPort)
 
-	switch reqMetric.direction {
+	switch reqMetric.conSrcDstInfo.direction {
 	case constants.INBOUND:
 		trafficLabels.reporter = "destination"
 		accesslog.direction = "INBOUND"
@@ -813,7 +810,7 @@ func (m *MetricController) buildConnectionMetric(reqMetric *requestMetric) conne
 	trafficLabels.requestProtocol = "tcp"
 	trafficLabels.connectionSecurityPolicy = "mutual_tls"
 
-	switch reqMetric.direction {
+	switch reqMetric.conSrcDstInfo.direction {
 	case constants.INBOUND:
 		trafficLabels.reporter = "destination"
 	case constants.OUTBOUND:
diff --git a/pkg/controller/workload/workload_processor.go b/pkg/controller/workload/workload_processor.go
index 7fdb587e..c87bece9 100644
--- a/pkg/controller/workload/workload_processor.go
+++ b/pkg/controller/workload/workload_processor.go
@@ -201,6 +201,24 @@ func (p *Processor) removeWorkload(uid string) error {
 	return p.removeWorkloadFromBpfMap(wl)
 }
 
+// handleUnhealthyWorkload is used to handle unhealthy workload, we only leave it in the frontend and backend map.
+// Because we rely on the backend map to be aware of direct access in `frontend_manager`,
+// and xdp rely on frontend map to get the authz policy and do authz.
+func (p *Processor) handleUnhealthyWorkload(workload *workloadapi.Workload) error {
+	backendUid := p.hashName.Hash(workload.Uid)
+
+	// 1. find all endpoint keys related to this workload and delete them
+	if eks := p.bpf.GetEndpointKeys(backendUid); len(eks) > 0 {
+		if err := p.deleteEndpointRecords(eks.UnsortedList()); err != nil {
+			return fmt.Errorf("handleUnhealthyWorkload: deleteEndpointRecords for %s failed: %v", workload.Uid, err)
+		}
+	}
+
+	// TODO(hzxuzhonghu), maybe need to update backend map to update the workload status
+
+	return nil
+}
+
 func (p *Processor) removeWorkloadFromBpfMap(workload *workloadapi.Workload) error {
 	var (
 		err      error
@@ -486,11 +504,11 @@ func (p *Processor) handleWorkload(workload *workloadapi.Workload) error {
 		p.locality.SetLocality(p.nodeName, workload.GetClusterId(), workload.GetNetwork(), workload.GetLocality())
 	}
 
-	// Exclude unhealthy workload, which is not ready to serve traffic
+	// Exclude unhealthy workload, which is not ready to serve traffic, but keep it in the frontend
+	// backend map for authz
 	if workload.Status == workloadapi.WorkloadStatus_UNHEALTHY {
 		log.Debugf("workload %s is unhealthy", workload.ResourceName())
-		// If the workload is updated to unhealthy, we should remove it from the bpf map
-		return p.removeWorkloadFromBpfMap(workload)
+		return p.handleUnhealthyWorkload(workload)
 	}
 
 	// 1. update workload in backend map



Test patch:
diff --git a/pkg/controller/telemetry/metric_test.go b/pkg/controller/telemetry/metric_test.go
index 92a3917a..e141f459 100644
--- a/pkg/controller/telemetry/metric_test.go
+++ b/pkg/controller/telemetry/metric_test.go
@@ -187,12 +187,13 @@ func TestBuildMetricsToPrometheus(t *testing.T) {
 		want []float64
 	}{
 		{
-			name: "test build workload metrics to metricCache",
+			name: "test build workload metrics to metricCache for destination",
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					},
 					sentBytes:     0x0000003,
 					receivedBytes: 0x0000004,
@@ -227,11 +228,19 @@ func TestBuildMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					}: {
 						totalReports: 1,
 					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
+					}: {
+						totalReports: 3,
+					},
 				},
 			},
 			want: []float64{
@@ -248,8 +257,9 @@ func TestBuildMetricsToPrometheus(t *testing.T) {
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					},
 					sentBytes:     0x0000003,
 					receivedBytes: 0x0000004,
@@ -258,7 +268,7 @@ func TestBuildMetricsToPrometheus(t *testing.T) {
 					state:         TCP_ESTABLISHED,
 				},
 				labels: workloadMetricLabels{
-					reporter:                     "destination",
+					reporter:                     "source",
 					sourceWorkload:               "sleep",
 					sourceCanonicalService:       "sleep",
 					sourceCanonicalRevision:      "latest",
@@ -284,8 +294,16 @@ func TestBuildMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
+					}: {
+						totalReports: 1,
+					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					}: {
 						totalReports: 3,
 					},
@@ -335,14 +353,16 @@ func TestBuildServiceMetricsToPrometheus(t *testing.T) {
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					},
 					sentBytes:     0x0000009,
 					receivedBytes: 0x0000008,
 					state:         TCP_ESTABLISHED,
 				},
 				labels: serviceMetricLabels{
+					reporter:                     "destination",
 					sourceWorkload:               "kmesh-daemon",
 					sourceCanonicalService:       "srcCanonical",
 					sourceCanonicalRevision:      "srcVersion",
@@ -368,11 +388,19 @@ func TestBuildServiceMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					}: {
 						totalReports: 1,
 					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
+					}: {
+						totalReports: 3,
+					},
 				},
 			},
 			want: []float64{
@@ -387,14 +415,16 @@ func TestBuildServiceMetricsToPrometheus(t *testing.T) {
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					},
 					sentBytes:     0x0000009,
 					receivedBytes: 0x0000008,
 					state:         TCP_ESTABLISHED,
 				},
 				labels: serviceMetricLabels{
+					reporter:                     "source",
 					sourceWorkload:               "kmesh-daemon",
 					sourceCanonicalService:       "srcCanonical",
 					sourceCanonicalRevision:      "srcVersion",
@@ -420,8 +450,16 @@ func TestBuildServiceMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
+					}: {
+						totalReports: 1,
+					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					}: {
 						totalReports: 3,
 					},
@@ -469,8 +507,9 @@ func TestBuildConnectionMetricsToPrometheus(t *testing.T) {
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					},
 					sentBytes:     0x0000003,
 					receivedBytes: 0x0000004,
@@ -505,8 +544,9 @@ func TestBuildConnectionMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
 					}: {
 						sentBytes:     0x0000003,
 						receivedBytes: 0x0000004,
@@ -514,6 +554,13 @@ func TestBuildConnectionMetricsToPrometheus(t *testing.T) {
 						totalRetrans:  0x0000002,
 						totalReports:  1,
 					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
+					}: {
+						totalReports: 3,
+					},
 				},
 			},
 			want: []float64{
@@ -529,8 +576,9 @@ func TestBuildConnectionMetricsToPrometheus(t *testing.T) {
 			args: args{
 				data: requestMetric{
 					conSrcDstInfo: connectionSrcDst{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					},
 					sentBytes:     0x0000003,
 					receivedBytes: 0x0000004,
@@ -565,8 +613,20 @@ func TestBuildConnectionMetricsToPrometheus(t *testing.T) {
 				},
 				tcpConns: map[connectionSrcDst]connMetric{
 					{
-						src: [4]uint32{183763210, 0, 0, 0},
-						dst: [4]uint32{183762951, 0, 0, 0},
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.INBOUND,
+					}: {
+						sentBytes:     0x0000003,
+						receivedBytes: 0x0000004,
+						packetLost:    0x0000001,
+						totalRetrans:  0x0000002,
+						totalReports:  1,
+					},
+					{
+						src:       [4]uint32{183763210, 0, 0, 0},
+						dst:       [4]uint32{183762951, 0, 0, 0},
+						direction: constants.OUTBOUND,
 					}: {
 						totalReports: 3,
 					},
@@ -914,14 +974,14 @@ func TestBuildServiceMetric(t *testing.T) {
 						// sleep
 						src: [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						// kmesh-daemon
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
-						dstPort: uint16(8000),
-						srcPort: uint16(8000),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
+						dstPort:   uint16(8000),
+						srcPort:   uint16(8000),
+						direction: uint32(2),
 					},
 					// kmesh-daemon
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
 					origDstPort:   uint16(8000),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -970,14 +1030,14 @@ func TestBuildServiceMetric(t *testing.T) {
 						// sleep
 						src: [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						// kmesh-daemon
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
-						dstPort: uint16(8000),
-						srcPort: uint16(8000),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
+						dstPort:   uint16(8000),
+						srcPort:   uint16(8000),
+						direction: uint32(2),
 					},
 					// kmesh-daemon
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("192.168.1.22"), 0, 0, 0},
 					origDstPort:   uint16(8000),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1026,14 +1086,14 @@ func TestBuildServiceMetric(t *testing.T) {
 						// sleep
 						src: [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						// unknown address
-						dst:     [4]uint32{nets.ConvertIpToUint32("191.168.224.22"), 0, 0, 0},
-						dstPort: uint16(80),
-						srcPort: uint16(8000),
+						dst:       [4]uint32{nets.ConvertIpToUint32("191.168.224.22"), 0, 0, 0},
+						dstPort:   uint16(80),
+						srcPort:   uint16(8000),
+						direction: uint32(2),
 					},
 					// unknown address
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("191.168.224.22"), 0, 0, 0},
 					origDstPort:   uint16(80),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1083,13 +1143,13 @@ func TestBuildServiceMetric(t *testing.T) {
 						src:     [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						srcPort: uint16(49875),
 						// waypoint
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.32"), 0, 0, 0},
-						dstPort: uint16(80),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.32"), 0, 0, 0},
+						dstPort:   uint16(80),
+						direction: uint32(2),
 					},
 					// httpbin service
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("192.168.1.23"), 0, 0, 0},
 					origDstPort:   uint16(80),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1139,13 +1199,13 @@ func TestBuildServiceMetric(t *testing.T) {
 						src:     [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						srcPort: uint16(49875),
 						// waypoint
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.32"), 0, 0, 0},
-						dstPort: uint16(80),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.32"), 0, 0, 0},
+						dstPort:   uint16(80),
+						direction: uint32(2),
 					},
 					// solelyWorkload
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("10.19.25.34"), 0, 0, 0},
 					origDstPort:   uint16(80),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1195,13 +1255,13 @@ func TestBuildServiceMetric(t *testing.T) {
 						src:     [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						srcPort: uint16(49875),
 						// solely workload
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.34"), 0, 0, 0},
-						dstPort: uint16(80),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.34"), 0, 0, 0},
+						dstPort:   uint16(80),
+						direction: uint32(2),
 					},
 					// httpbin service
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("10.19.25.34"), 0, 0, 0},
 					origDstPort:   uint16(80),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1333,14 +1393,14 @@ func TestBuildConnectionMetric(t *testing.T) {
 						// sleep
 						src: [4]uint32{nets.ConvertIpToUint32("10.19.25.33"), 0, 0, 0},
 						// kmesh-daemon
-						dst:     [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
-						dstPort: uint16(8000),
-						srcPort: uint16(8000),
+						dst:       [4]uint32{nets.ConvertIpToUint32("10.19.25.31"), 0, 0, 0},
+						dstPort:   uint16(8000),
+						srcPort:   uint16(8000),
+						direction: uint32(2),
 					},
 					// kmesh-daemon
 					origDstAddr:   [4]uint32{nets.ConvertIpToUint32("192.168.1.22"), 0, 0, 0},
 					origDstPort:   uint16(8000),
-					direction:     uint32(2),
 					sentBytes:     uint32(156),
 					receivedBytes: uint32(1024),
 				},
@@ -1687,7 +1747,6 @@ func TestBuildV4Metric(t *testing.T) {
 		210, 202, 232, 184, 0, 0, 64, 30, 158, 31, 235, 184, 0, 0, 0, 0, 0, 0, 150, 158, 0, 0, 19, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
 	data := requestMetric{
-
 		conSrcDstInfo: connectionSrcDst{
 			src:       [4]uint32{218231818, 0, 0, 0},
 			dst:       [4]uint32{201454602, 0, 0, 0},
@@ -1697,7 +1756,6 @@ func TestBuildV4Metric(t *testing.T) {
 		},
 		origDstAddr:    [4]uint32{3761135626, 0, 0, 0},
 		origDstPort:    8080,
-		direction:      constants.OUTBOUND,
 		receivedBytes:  147,
 		sentBytes:      3,
 		state:          1,
diff --git a/pkg/controller/workload/workload_processor_test.go b/pkg/controller/workload/workload_processor_test.go
index cebcff46..b55026f1 100644
--- a/pkg/controller/workload/workload_processor_test.go
+++ b/pkg/controller/workload/workload_processor_test.go
@@ -160,10 +160,12 @@ func Test_handleWorkload(t *testing.T) {
 	assert.Equal(t, got.Status, workloadapi.WorkloadStatus_UNHEALTHY)
 	checkNotExistInFrontEndMap(t, workload3.Addresses[0], p)
 
-	// 8. update workload from healthy to unhealthy, should remove it from bpf map
+	// 8. update workload from healthy to unhealthy, should remove it from bpf endpoint map
 	workload2.Status = workloadapi.WorkloadStatus_UNHEALTHY
 	_ = p.handleWorkload(workload2)
-	checkNotExistInFrontEndMap(t, workload2.Addresses[0], p)
+	checkNotExistInEndpointMap(t, p, fakeSvc, []uint32{workload2ID})
+	checkFrontEndMap(t, workload2.Addresses[0], p)
+	checkBackendMap(t, p, workload2ID, workload2)
 
 	// 9. delete service
 	p.handleRemovedAddresses([]string{fakeSvc.ResourceName()})
@@ -276,6 +278,18 @@ func checkServiceMap(t *testing.T, p *Processor, svcId uint32, fakeSvc *workload
 	assert.Equal(t, sv.WaypointPort, nets.ConvertPortToBigEndian(fakeSvc.Waypoint.GetHboneMtlsPort()))
 }
 
+func checkNotExistInEndpointMap(t *testing.T, p *Processor, fakeSvc *workloadapi.Service, backendUid []uint32) {
+	endpoints := p.bpf.GetAllEndpointsForService(p.hashName.Hash(fakeSvc.ResourceName()))
+	t.Logf("endpoints number: %v", len(endpoints))
+
+	all := sets.New[uint32](backendUid...)
+	for _, endpoint := range endpoints {
+		if all.Contains(endpoint.BackendUid) {
+			t.Fatalf("endpoint %v still exists", endpoint.BackendUid)
+		}
+	}
+}
+
 func checkEndpointMap(t *testing.T, p *Processor, fakeSvc *workloadapi.Service, backendUid []uint32) {
 	endpoints := p.bpf.GetAllEndpointsForService(p.hashName.Hash(fakeSvc.ResourceName()))
 	assert.Equal(t, len(endpoints), len(backendUid))