Add unit tests for configuration, cryptography, interfaces, and packet handling.
This commit is contained in:
230
pkg/interfaces/interface_test.go
Normal file
230
pkg/interfaces/interface_test.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
|
||||
)
|
||||
|
||||
func TestBaseInterfaceStateChanges(t *testing.T) {
|
||||
bi := NewBaseInterface("test", common.IF_TYPE_TCP, false) // Start disabled
|
||||
|
||||
if bi.IsEnabled() {
|
||||
t.Error("Newly created disabled interface reports IsEnabled() == true")
|
||||
}
|
||||
if bi.IsOnline() {
|
||||
t.Error("Newly created disabled interface reports IsOnline() == true")
|
||||
}
|
||||
if bi.IsDetached() {
|
||||
t.Error("Newly created interface reports IsDetached() == true")
|
||||
}
|
||||
|
||||
bi.Enable()
|
||||
if !bi.IsEnabled() {
|
||||
t.Error("After Enable(), IsEnabled() == false")
|
||||
}
|
||||
if !bi.IsOnline() {
|
||||
t.Error("After Enable(), IsOnline() == false")
|
||||
}
|
||||
if bi.IsDetached() {
|
||||
t.Error("After Enable(), IsDetached() == true")
|
||||
}
|
||||
|
||||
bi.Detach()
|
||||
if bi.IsEnabled() {
|
||||
t.Error("After Detach(), IsEnabled() == true")
|
||||
}
|
||||
if bi.IsOnline() {
|
||||
t.Error("After Detach(), IsOnline() == true")
|
||||
}
|
||||
if !bi.IsDetached() {
|
||||
t.Error("After Detach(), IsDetached() == false")
|
||||
}
|
||||
|
||||
// Reset for Disable test
|
||||
bi = NewBaseInterface("test2", common.IF_TYPE_UDP, true) // Start enabled
|
||||
if !bi.Enabled { // Check the Enabled field directly first
|
||||
t.Error("Newly created enabled interface reports Enabled == false")
|
||||
}
|
||||
if bi.IsEnabled() { // IsEnabled should still be false because Online is false
|
||||
t.Error("Newly created enabled interface reports IsEnabled() == true before Enable() is called")
|
||||
}
|
||||
|
||||
bi.Enable() // Explicitly enable to set Online = true
|
||||
if !bi.IsEnabled() { // Now IsEnabled should be true
|
||||
t.Error("After Enable() on initially enabled interface, IsEnabled() == false")
|
||||
}
|
||||
|
||||
bi.Disable()
|
||||
if bi.Enabled { // Check Enabled field after Disable()
|
||||
t.Error("After Disable(), Enabled == true")
|
||||
}
|
||||
if bi.IsOnline() {
|
||||
t.Error("After Disable(), IsOnline() == true")
|
||||
}
|
||||
if bi.IsDetached() { // Disable doesn't detach
|
||||
t.Error("After Disable(), IsDetached() == true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseInterfaceGetters(t *testing.T) {
|
||||
bi := NewBaseInterface("getterTest", common.IF_TYPE_AUTO, true)
|
||||
|
||||
if bi.GetName() != "getterTest" {
|
||||
t.Errorf("GetName() = %s; want getterTest", bi.GetName())
|
||||
}
|
||||
if bi.GetType() != common.IF_TYPE_AUTO {
|
||||
t.Errorf("GetType() = %v; want %v", bi.GetType(), common.IF_TYPE_AUTO)
|
||||
}
|
||||
if bi.GetMode() != common.IF_MODE_FULL {
|
||||
t.Errorf("GetMode() = %v; want %v", bi.GetMode(), common.IF_MODE_FULL)
|
||||
}
|
||||
if bi.GetMTU() != common.DEFAULT_MTU { // Assuming default MTU
|
||||
t.Errorf("GetMTU() = %d; want %d", bi.GetMTU(), common.DEFAULT_MTU)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseInterfaceCallbacks(t *testing.T) {
|
||||
bi := NewBaseInterface("callbackTest", common.IF_TYPE_TCP, true)
|
||||
var wg sync.WaitGroup
|
||||
var callbackCalled bool
|
||||
|
||||
callback := func(data []byte, iface common.NetworkInterface) {
|
||||
if len(data) != 5 {
|
||||
t.Errorf("Callback received data length %d; want 5", len(data))
|
||||
}
|
||||
if iface.GetName() != "callbackTest" {
|
||||
t.Errorf("Callback received interface name %s; want callbackTest", iface.GetName())
|
||||
}
|
||||
callbackCalled = true
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
bi.SetPacketCallback(callback)
|
||||
if bi.GetPacketCallback() == nil { // Cannot directly compare functions
|
||||
t.Error("GetPacketCallback() returned nil after SetPacketCallback()")
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go bi.ProcessIncoming([]byte{1, 2, 3, 4, 5}) // Run in goroutine as callback might block
|
||||
|
||||
// Wait for callback or timeout
|
||||
waitTimeout(&wg, 1*time.Second, t)
|
||||
|
||||
if !callbackCalled {
|
||||
t.Error("Packet callback was not called after ProcessIncoming")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseInterfaceStats(t *testing.T) {
|
||||
bi := NewBaseInterface("statsTest", common.IF_TYPE_UDP, true)
|
||||
bi.Enable() // Need to be Online for ProcessOutgoing
|
||||
|
||||
data1 := []byte{1, 2, 3}
|
||||
data2 := []byte{4, 5, 6, 7, 8}
|
||||
|
||||
bi.ProcessIncoming(data1)
|
||||
if bi.RxBytes != uint64(len(data1)) {
|
||||
t.Errorf("RxBytes = %d; want %d after first ProcessIncoming", bi.RxBytes, len(data1))
|
||||
}
|
||||
|
||||
bi.ProcessIncoming(data2)
|
||||
if bi.RxBytes != uint64(len(data1)+len(data2)) {
|
||||
t.Errorf("RxBytes = %d; want %d after second ProcessIncoming", bi.RxBytes, len(data1)+len(data2))
|
||||
}
|
||||
|
||||
// ProcessOutgoing only updates TxBytes in BaseInterface
|
||||
err := bi.ProcessOutgoing(data1)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessOutgoing failed: %v", err)
|
||||
}
|
||||
if bi.TxBytes != uint64(len(data1)) {
|
||||
t.Errorf("TxBytes = %d; want %d after first ProcessOutgoing", bi.TxBytes, len(data1))
|
||||
}
|
||||
|
||||
err = bi.ProcessOutgoing(data2)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessOutgoing failed: %v", err)
|
||||
}
|
||||
if bi.TxBytes != uint64(len(data1)+len(data2)) {
|
||||
t.Errorf("TxBytes = %d; want %d after second ProcessOutgoing", bi.TxBytes, len(data1)+len(data2))
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to wait for a WaitGroup with a timeout
|
||||
func waitTimeout(wg *sync.WaitGroup, timeout time.Duration, t *testing.T) {
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
wg.Wait()
|
||||
}()
|
||||
select {
|
||||
case <-c:
|
||||
// Completed normally
|
||||
case <-time.After(timeout):
|
||||
t.Fatal("Timed out waiting for WaitGroup")
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal mock interface for InterceptedInterface test
|
||||
type mockInterface struct {
|
||||
BaseInterface
|
||||
sendCalled bool
|
||||
sendData []byte
|
||||
}
|
||||
|
||||
func (m *mockInterface) Send(data []byte, addr string) error {
|
||||
m.sendCalled = true
|
||||
m.sendData = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add other methods to satisfy the Interface interface (can be minimal/panic)
|
||||
func (m *mockInterface) GetType() common.InterfaceType { return common.IF_TYPE_NONE }
|
||||
func (m *mockInterface) GetMode() common.InterfaceMode { return common.IF_MODE_FULL }
|
||||
func (m *mockInterface) ProcessIncoming(data []byte) {}
|
||||
func (m *mockInterface) ProcessOutgoing(data []byte) error { return nil }
|
||||
func (m *mockInterface) SendPathRequest([]byte) error { return nil }
|
||||
func (m *mockInterface) SendLinkPacket([]byte, []byte, time.Time) error { return nil }
|
||||
func (m *mockInterface) Start() error { return nil }
|
||||
func (m *mockInterface) Stop() error { return nil }
|
||||
func (m *mockInterface) GetConn() net.Conn { return nil }
|
||||
func (m *mockInterface) GetBandwidthAvailable() bool { return true }
|
||||
|
||||
func TestInterceptedInterface(t *testing.T) {
|
||||
mockBase := &mockInterface{}
|
||||
var interceptorCalled bool
|
||||
var interceptedData []byte
|
||||
|
||||
interceptor := func(data []byte, iface common.NetworkInterface) error {
|
||||
interceptorCalled = true
|
||||
interceptedData = data
|
||||
return nil
|
||||
}
|
||||
|
||||
intercepted := NewInterceptedInterface(mockBase, interceptor)
|
||||
|
||||
testData := []byte("intercept me")
|
||||
err := intercepted.Send(testData, "dummy_addr")
|
||||
if err != nil {
|
||||
t.Fatalf("Intercepted Send failed: %v", err)
|
||||
}
|
||||
|
||||
if !interceptorCalled {
|
||||
t.Error("Interceptor function was not called")
|
||||
}
|
||||
if !bytes.Equal(interceptedData, testData) {
|
||||
t.Errorf("Interceptor received data %x; want %x", interceptedData, testData)
|
||||
}
|
||||
|
||||
if !mockBase.sendCalled {
|
||||
t.Error("Original Send function was not called")
|
||||
}
|
||||
if !bytes.Equal(mockBase.sendData, testData) {
|
||||
t.Errorf("Original Send received data %x; want %x", mockBase.sendData, testData)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user