Files
govpp-snmp-agentx/src/vpp/vpp_stats_test.go
2025-11-15 22:42:04 +01:00

241 lines
5.8 KiB
Go

// Copyright 2025, IPng Networks GmbH, Pim van Pelt <pim@ipng.ch>
package vpp
import (
"testing"
"time"
"go.fd.io/govpp/api"
)
func TestNewStatsManager(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
if manager == nil {
t.Fatal("NewStatsManager() returned nil")
return
}
if manager.client != client {
t.Error("StatsManager should store the provided client")
}
if manager.period != time.Duration(*Period)*time.Second {
t.Errorf("Expected period %v, got %v", time.Duration(*Period)*time.Second, manager.period)
}
if manager.running {
t.Error("StatsManager should not be running initially")
}
if manager.statsCallback != nil {
t.Error("StatsManager should have nil callback initially")
}
}
func TestStatsManagerSetStatsCallback(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
var callbackCalled bool
var receivedStats *api.InterfaceStats
callback := func(stats *api.InterfaceStats) {
callbackCalled = true
receivedStats = stats
}
manager.SetStatsCallback(callback)
if manager.statsCallback == nil {
t.Error("SetStatsCallback() should store the callback")
}
// Test callback execution
testStats := &api.InterfaceStats{
Interfaces: []api.InterfaceCounters{
{
InterfaceIndex: 1,
InterfaceName: "test-interface",
Rx: api.InterfaceCounterCombined{Packets: 100, Bytes: 1500},
Tx: api.InterfaceCounterCombined{Packets: 50, Bytes: 750},
},
},
}
manager.statsCallback(testStats)
if !callbackCalled {
t.Error("Callback should have been called")
}
if receivedStats != testStats {
t.Error("Callback should receive the same stats object")
}
if len(receivedStats.Interfaces) != 1 {
t.Errorf("Expected 1 interface, got %d", len(receivedStats.Interfaces))
}
if receivedStats.Interfaces[0].InterfaceName != "test-interface" {
t.Errorf("Expected interface name 'test-interface', got %q", receivedStats.Interfaces[0].InterfaceName)
}
}
func TestStatsManagerSetPeriod(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
newPeriod := 5 * time.Second
manager.SetPeriod(newPeriod)
if manager.period != newPeriod {
t.Errorf("Expected period %v, got %v", newPeriod, manager.period)
}
}
func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
if manager.running {
t.Error("StatsManager should not be running initially")
}
manager.StartStatsRoutine()
if !manager.running {
t.Error("StatsManager should be running after StartStatsRoutine()")
}
// Test starting again (should be safe)
manager.StartStatsRoutine()
if !manager.running {
t.Error("StatsManager should still be running after second StartStatsRoutine()")
}
manager.StopStatsRoutine()
if manager.running {
t.Error("StatsManager should not be running after StopStatsRoutine()")
}
}
func TestStatsManagerGetInterfaceStatsWithoutConnection(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
_, err := manager.GetInterfaceStats()
if err == nil {
t.Error("GetInterfaceStats() should return error when not connected")
}
vppErr, ok := err.(*VPPError)
if !ok {
t.Errorf("Expected VPPError, got %T", err)
}
if vppErr.Message != "VPP client not connected" {
t.Errorf("Expected specific error message, got: %s", vppErr.Message)
}
}
func TestStatsCallback(t *testing.T) {
var callbackInvoked bool
var callbackStats *api.InterfaceStats
callback := StatsCallback(func(stats *api.InterfaceStats) {
callbackInvoked = true
callbackStats = stats
})
testStats := &api.InterfaceStats{
Interfaces: []api.InterfaceCounters{
{
InterfaceIndex: 42,
InterfaceName: "test-callback-interface",
Rx: api.InterfaceCounterCombined{Packets: 200, Bytes: 3000},
Tx: api.InterfaceCounterCombined{Packets: 100, Bytes: 1500},
RxUnicast: api.InterfaceCounterCombined{Packets: 180, Bytes: 2700},
TxUnicast: api.InterfaceCounterCombined{Packets: 90, Bytes: 1350},
},
},
}
callback(testStats)
if !callbackInvoked {
t.Error("Callback should have been invoked")
}
if callbackStats != testStats {
t.Error("Callback should receive the same stats object")
}
if len(callbackStats.Interfaces) != 1 {
t.Errorf("Expected 1 interface, got %d", len(callbackStats.Interfaces))
}
iface := callbackStats.Interfaces[0]
if iface.InterfaceIndex != 42 {
t.Errorf("Expected interface index 42, got %d", iface.InterfaceIndex)
}
if iface.InterfaceName != "test-callback-interface" {
t.Errorf("Expected interface name 'test-callback-interface', got %q", iface.InterfaceName)
}
if iface.Rx.Packets != 200 {
t.Errorf("Expected RX packets 200, got %d", iface.Rx.Packets)
}
if iface.Tx.Bytes != 1500 {
t.Errorf("Expected TX bytes 1500, got %d", iface.Tx.Bytes)
}
if iface.RxUnicast.Packets != 180 {
t.Errorf("Expected RX unicast packets 180, got %d", iface.RxUnicast.Packets)
}
if iface.TxUnicast.Bytes != 1350 {
t.Errorf("Expected TX unicast bytes 1350, got %d", iface.TxUnicast.Bytes)
}
}
func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
// Should return false when not connected
if manager.queryAndReportStats() {
t.Error("queryAndReportStats() should return false when not connected")
}
}
func TestStatsManagerWithShortPeriod(t *testing.T) {
client := &VPPClient{}
manager := NewStatsManager(client)
// Set a very short period for testing
manager.SetPeriod(10 * time.Millisecond)
if manager.period != 10*time.Millisecond {
t.Errorf("Expected period 10ms, got %v", manager.period)
}
manager.StartStatsRoutine()
// Let it run briefly
time.Sleep(50 * time.Millisecond)
manager.StopStatsRoutine()
// Should stop gracefully
if manager.running {
t.Error("StatsManager should have stopped")
}
}