//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) } }