rs2322tcp/internal/client/virtual_port_manager_linux_test.go

296 lines
5.6 KiB
Go

//go:build linux
/*
* ============================================================================
* Projekt.....: rs2322tcp
* Datei.......: internal/client/virtual_port_manager_linux_test.go
* Copyright (C) 2026 Dieter Lang
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Beschreibung:
* Linux-spezifische Tests für die Erzeugung und Verwaltung virtueller
* rs2322tcp-Ports.
* ============================================================================
*/
package client
import (
"os"
"testing"
"git.lang-dieter.de/rs2322tcp/internal/config"
)
///////////////////////////////////////////////////////////////////////////////
// Tests
///////////////////////////////////////////////////////////////////////////////
func TestVirtualPortManagerOpen(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 199,
},
)
port, err := manager.Open()
if err != nil {
t.Fatalf("Open() failed: %v", err)
}
if port == nil {
t.Fatal("Open() returned nil")
}
if port.Path() != "/dev/ttyUSB100" {
t.Errorf(
"Path() = %q, want %q",
port.Path(),
"/dev/ttyUSB100",
)
}
linkPath, err := virtualPortLinkPath(port.Path())
if err != nil {
t.Fatalf("virtualPortLinkPath() failed: %v", err)
}
target, err := os.Readlink(linkPath)
if err != nil {
t.Fatalf("Readlink() failed: %v", err)
}
if target == "" {
t.Fatal("internal virtual port link has empty target")
}
if err := port.Close(); err != nil {
t.Fatalf("Close() failed: %v", err)
}
targetAfterClose, err := os.Readlink(linkPath)
if err != nil {
t.Fatalf(
"internal link does not exist after Close(): %q: %v",
linkPath,
err,
)
}
if targetAfterClose != target {
t.Errorf(
"internal link target after Close() = %q, want %q",
targetAfterClose,
target,
)
}
}
func TestVirtualPortManagerOpenSpecific(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 199,
},
)
port, err := manager.OpenSpecific(150)
if err != nil {
t.Fatalf("OpenSpecific(150) failed: %v", err)
}
if port == nil {
t.Fatal("OpenSpecific(150) returned nil")
}
if port.Path() != "/dev/ttyUSB150" {
t.Errorf(
"Path() = %q, want %q",
port.Path(),
"/dev/ttyUSB150",
)
}
linkPath, err := virtualPortLinkPath(port.Path())
if err != nil {
t.Fatalf("virtualPortLinkPath() failed: %v", err)
}
target, err := os.Readlink(linkPath)
if err != nil {
t.Fatalf("Readlink() failed: %v", err)
}
if target == "" {
t.Fatal("internal virtual port link has empty target")
}
if err := port.Close(); err != nil {
t.Fatalf("Close() failed: %v", err)
}
targetAfterClose, err := os.Readlink(linkPath)
if err != nil {
t.Fatalf(
"internal link does not exist after Close(): %q: %v",
linkPath,
err,
)
}
if targetAfterClose != target {
t.Errorf(
"internal link target after Close() = %q, want %q",
targetAfterClose,
target,
)
}
}
func TestVirtualPortManagerOpenUsesNextPort(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 101,
},
)
first, err := manager.Open()
if err != nil {
t.Fatalf("first Open() failed: %v", err)
}
second, err := manager.Open()
if err != nil {
_ = first.Close()
t.Fatalf("second Open() failed: %v", err)
}
if first.Path() != "/dev/ttyUSB100" {
t.Errorf(
"first.Path() = %q, want %q",
first.Path(),
"/dev/ttyUSB100",
)
}
if second.Path() != "/dev/ttyUSB101" {
t.Errorf(
"second.Path() = %q, want %q",
second.Path(),
"/dev/ttyUSB101",
)
}
if err := first.Close(); err != nil {
t.Fatalf("first Close() failed: %v", err)
}
if err := second.Close(); err != nil {
t.Fatalf("second Close() failed: %v", err)
}
}
func TestVirtualPortManagerOpenReusesReleasedPort(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 100,
},
)
first, err := manager.Open()
if err != nil {
t.Fatalf("first Open() failed: %v", err)
}
if first.Path() != "/dev/ttyUSB100" {
t.Fatalf(
"first.Path() = %q, want %q",
first.Path(),
"/dev/ttyUSB100",
)
}
if err := first.Close(); err != nil {
t.Fatalf("first Close() failed: %v", err)
}
second, err := manager.Open()
if err != nil {
t.Fatalf("second Open() failed: %v", err)
}
if second.Path() != "/dev/ttyUSB100" {
t.Errorf(
"second.Path() = %q, want %q",
second.Path(),
"/dev/ttyUSB100",
)
}
if err := second.Close(); err != nil {
t.Fatalf("second Close() failed: %v", err)
}
}
func TestVirtualPortManagerOpenNoFreePort(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 100,
},
)
port, err := manager.Open()
if err != nil {
t.Fatalf("first Open() failed: %v", err)
}
defer port.Close()
if _, err := manager.Open(); err == nil {
t.Fatal("second Open() succeeded, want no-free-port error")
}
}
func TestManagedVirtualPortDataPath(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)
manager := NewVirtualPortManager(
config.VirtualPortRangeConfig{
First: 100,
Last: 100,
},
)
port, err := manager.Open()
if err != nil {
t.Fatalf("Open() failed: %v", err)
}
defer port.Close()
data := []byte{0x46, 0x41, 0x00, 0x10, 0x0D}
if _, err := port.Write(data); err != nil {
t.Fatalf("Write() failed: %v", err)
}
}