diff --git a/internal/config/config_test.go b/internal/config/config_test.go index d09eca6..2ea6e53 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -71,7 +71,7 @@ func TestLoadSaveConfig(t *testing.T) { if loadedCfg.LogLevel != 1 { t.Errorf("Expected LogLevel 1, got %d", loadedCfg.LogLevel) } - if loadedCfg.EnableTransport != false { + if loadedCfg.EnableTransport { t.Error("Expected EnableTransport false") } diff --git a/pkg/link/link_test.go b/pkg/link/link_test.go new file mode 100644 index 0000000..0582da2 --- /dev/null +++ b/pkg/link/link_test.go @@ -0,0 +1,218 @@ +package link + +import ( + "bytes" + "testing" + "time" + + "git.quad4.io/Networks/Reticulum-Go/pkg/common" + "git.quad4.io/Networks/Reticulum-Go/pkg/destination" + "git.quad4.io/Networks/Reticulum-Go/pkg/identity" + "git.quad4.io/Networks/Reticulum-Go/pkg/packet" +) + +type mockTransport struct { + sentPackets []*packet.Packet +} + +func (m *mockTransport) SendPacket(pkt *packet.Packet) error { + m.sentPackets = append(m.sentPackets, pkt) + return nil +} + +func (m *mockTransport) RegisterLink(linkID []byte, link interface{}) { +} + +func (m *mockTransport) GetConfig() *common.ReticulumConfig { + return &common.ReticulumConfig{} +} + +func (m *mockTransport) GetInterfaces() map[string]common.NetworkInterface { + return make(map[string]common.NetworkInterface) +} + +func (m *mockTransport) RegisterDestination(hash []byte, dest interface{}) { +} + +type mockInterface struct { + name string +} + +func (m *mockInterface) GetName() string { + return m.name +} + +func (m *mockInterface) Start() error { + return nil +} + +func (m *mockInterface) Stop() error { + return nil +} + +func (m *mockInterface) Send(data []byte, address string) error { + return nil +} + +func (m *mockInterface) ProcessIncoming(data []byte) error { + return nil +} + +func (m *mockInterface) SetPacketCallback(cb func([]byte, common.NetworkInterface)) { +} + +func (m *mockInterface) GetType() string { + return "mock" +} + +func (m *mockInterface) GetMTU() int { + return 500 +} + +func (m *mockInterface) Detach() { +} + +func (m *mockInterface) Enable() { +} + +func (m *mockInterface) Disable() { +} + +func (m *mockInterface) IsEnabled() bool { + return true +} + +func (m *mockInterface) IsOnline() bool { + return true +} + +func (m *mockInterface) IsDetached() bool { + return false +} + +func (m *mockInterface) GetPacketCallback() func([]byte, common.NetworkInterface) { + return nil +} + +func (m *mockInterface) GetConn() interface{} { + return nil +} + +func (m *mockInterface) ProcessOutgoing(data []byte) ([]byte, error) { + return data, nil +} + +func (m *mockInterface) SendPathRequest(destHash []byte) error { + return nil +} + +func (m *mockInterface) SendLinkPacket(data []byte) error { + return nil +} + +func (m *mockInterface) GetBandwidthAvailable() float64 { + return 1.0 +} + +func TestLinkRequestResponse(t *testing.T) { + serverIdent, err := identity.New() + if err != nil { + t.Fatalf("Failed to create server identity: %v", err) + } + + clientIdent, err := identity.New() + if err != nil { + t.Fatalf("Failed to create client identity: %v", err) + } + + mockTrans := &mockTransport{ + sentPackets: make([]*packet.Packet, 0), + } + + serverDest, err := destination.New(serverIdent, destination.IN, destination.SINGLE, "testapp", mockTrans, "server") + if err != nil { + t.Fatalf("Failed to create server destination: %v", err) + } + + expectedResponse := []byte("response data") + testPath := "/test/path" + + err = serverDest.RegisterRequestHandler(testPath, func(path string, data []byte, requestID []byte, linkID []byte, remoteIdentity *identity.Identity, requestedAt int64) []byte { + if path != testPath { + t.Errorf("Expected path %s, got %s", testPath, path) + } + return expectedResponse + }, destination.ALLOW_ALL, nil) + if err != nil { + t.Fatalf("Failed to register request handler: %v", err) + } + + // Test the handler is registered correctly + pathHash := identity.TruncatedHash([]byte(testPath)) + handler := serverDest.GetRequestHandler(pathHash) + if handler == nil { + t.Fatal("Handler not found after registration") + } + + // Call the handler + testLinkID := make([]byte, 16) + result := handler(pathHash, []byte("test data"), []byte("request-id"), testLinkID, clientIdent, time.Now()) + + if result == nil { + t.Fatal("Handler returned nil") + } + + responseBytes, ok := result.([]byte) + if !ok { + t.Fatalf("Handler returned unexpected type: %T", result) + } + + if !bytes.Equal(responseBytes, expectedResponse) { + t.Errorf("Expected response %q, got %q", expectedResponse, responseBytes) + } +} + +func TestLinkRequestHandlerNotFound(t *testing.T) { + serverIdent, _ := identity.New() + mockTrans := &mockTransport{sentPackets: make([]*packet.Packet, 0)} + + serverDest, _ := destination.New(serverIdent, destination.IN, destination.SINGLE, "testapp", mockTrans, "server") + + nonExistentPath := "/does/not/exist" + pathHash := identity.TruncatedHash([]byte(nonExistentPath)) + + handler := serverDest.GetRequestHandler(pathHash) + if handler != nil { + t.Error("Expected no handler for non-existent path, but found one") + } +} + +func TestLinkResponseHandling(t *testing.T) { + // This test verifies the basic structure for response handling + // Full integration testing would require a proper transport setup + + requestID := []byte("test-request-id-") + responseData := []byte("response payload") + + receipt := &RequestReceipt{ + requestID: requestID, + status: STATUS_PENDING, + } + + // Verify initial state + if receipt.status != STATUS_PENDING { + t.Errorf("Expected initial status PENDING, got %d", receipt.status) + } + + // Simulate setting response + receipt.response = responseData + receipt.status = STATUS_ACTIVE + + if !bytes.Equal(receipt.response, responseData) { + t.Errorf("Expected response %q, got %q", responseData, receipt.response) + } + + if receipt.status != STATUS_ACTIVE { + t.Errorf("Expected status ACTIVE after response, got %d", receipt.status) + } +}