348 lines
6 KiB
Go
348 lines
6 KiB
Go
//go:build linux
|
|
|
|
/*
|
|
* ============================================================================
|
|
* Projekt.....: rs2322tcp
|
|
* Datei.......: internal/client/virtual_port_linux_test.go
|
|
* Copyright (C) 2026 Dieter Lang
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Beschreibung:
|
|
* Tests für die Linux-spezifische Verwaltung der internen Symlinks
|
|
* virtueller rs2322tcp-Seriellschnittstellen.
|
|
* ============================================================================
|
|
*/
|
|
package client
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"git.lang-dieter.de/rs2322tcp/internal/config"
|
|
)
|
|
|
|
func TestVirtualPortLinkPath(t *testing.T) {
|
|
path, err := virtualPortLinkPath("/dev/ttyUSB100")
|
|
if err != nil {
|
|
t.Fatalf("virtualPortLinkPath() failed: %v", err)
|
|
}
|
|
|
|
wantSuffix := filepath.Join(
|
|
".rs2322tcp",
|
|
"virtual",
|
|
"ttyUSB100",
|
|
)
|
|
|
|
if !filepath.IsAbs(path) {
|
|
t.Fatalf("path is not absolute: %q", path)
|
|
}
|
|
|
|
if !hasPathSuffix(path, wantSuffix) {
|
|
t.Errorf(
|
|
"virtualPortLinkPath() = %q, want suffix %q",
|
|
path,
|
|
wantSuffix,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestSetAndRemoveVirtualPortLink(t *testing.T) {
|
|
tempHome := t.TempDir()
|
|
|
|
t.Setenv("HOME", tempHome)
|
|
|
|
portPath := "/dev/ttyUSB100"
|
|
target := "/dev/pts/2"
|
|
|
|
if err := setVirtualPortLink(portPath, target); err != nil {
|
|
t.Fatalf("setVirtualPortLink() failed: %v", err)
|
|
}
|
|
|
|
linkPath, err := virtualPortLinkPath(portPath)
|
|
if err != nil {
|
|
t.Fatalf("virtualPortLinkPath() failed: %v", err)
|
|
}
|
|
|
|
got, err := os.Readlink(linkPath)
|
|
if err != nil {
|
|
t.Fatalf("Readlink() failed: %v", err)
|
|
}
|
|
|
|
if got != target {
|
|
t.Errorf(
|
|
"link target = %q, want %q",
|
|
got,
|
|
target,
|
|
)
|
|
}
|
|
|
|
if err := removeVirtualPortLink(portPath); err != nil {
|
|
t.Fatalf("removeVirtualPortLink() failed: %v", err)
|
|
}
|
|
|
|
if _, err := os.Lstat(linkPath); !os.IsNotExist(err) {
|
|
t.Fatalf(
|
|
"link still exists after removal: %q",
|
|
linkPath,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestSetVirtualPortLinkReplacesExistingLink(t *testing.T) {
|
|
tempHome := t.TempDir()
|
|
|
|
t.Setenv("HOME", tempHome)
|
|
|
|
portPath := "/dev/ttyUSB100"
|
|
|
|
if err := setVirtualPortLink(
|
|
portPath,
|
|
"/dev/pts/2",
|
|
); err != nil {
|
|
t.Fatalf(
|
|
"first setVirtualPortLink() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
if err := setVirtualPortLink(
|
|
portPath,
|
|
"/dev/pts/7",
|
|
); err != nil {
|
|
t.Fatalf(
|
|
"second setVirtualPortLink() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
linkPath, err := virtualPortLinkPath(portPath)
|
|
if err != nil {
|
|
t.Fatalf("virtualPortLinkPath() failed: %v", err)
|
|
}
|
|
|
|
got, err := os.Readlink(linkPath)
|
|
if err != nil {
|
|
t.Fatalf("Readlink() failed: %v", err)
|
|
}
|
|
|
|
if got != "/dev/pts/7" {
|
|
t.Errorf(
|
|
"link target = %q, want %q",
|
|
got,
|
|
"/dev/pts/7",
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestRemoveVirtualPortLinkMissing(t *testing.T) {
|
|
tempHome := t.TempDir()
|
|
|
|
t.Setenv("HOME", tempHome)
|
|
|
|
if err := removeVirtualPortLink("/dev/ttyUSB100"); err != nil {
|
|
t.Fatalf(
|
|
"removeVirtualPortLink() failed for missing link: %v",
|
|
err,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestVirtualPortLinkPathUsesBaseName(t *testing.T) {
|
|
path, err := virtualPortLinkPath("/dev/ttyUSB123")
|
|
if err != nil {
|
|
t.Fatalf("virtualPortLinkPath() failed: %v", err)
|
|
}
|
|
|
|
if filepath.Base(path) != "ttyUSB123" {
|
|
t.Errorf(
|
|
"filepath.Base() = %q, want %q",
|
|
filepath.Base(path),
|
|
"ttyUSB123",
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestExistingVirtualPortLinksNone(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
cfg := config.VirtualPortRangeConfig{
|
|
First: 100,
|
|
Last: 102,
|
|
}
|
|
|
|
got, err := existingVirtualPortLinksInDirectory(
|
|
cfg,
|
|
tempDir,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
if len(got) != 0 {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() = %v, want empty list",
|
|
got,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestExistingVirtualPortLinksFindsSymlinks(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
cfg := config.VirtualPortRangeConfig{
|
|
First: 100,
|
|
Last: 102,
|
|
}
|
|
|
|
for _, number := range []int{100, 102} {
|
|
path := filepath.Join(
|
|
tempDir,
|
|
"ttyUSB"+itoa(number),
|
|
)
|
|
|
|
if err := os.Symlink(
|
|
"/dev/pts/"+itoa(number),
|
|
path,
|
|
); err != nil {
|
|
t.Fatalf(
|
|
"create test symlink %q: %v",
|
|
path,
|
|
err,
|
|
)
|
|
}
|
|
}
|
|
|
|
got, err := existingVirtualPortLinksInDirectory(
|
|
cfg,
|
|
tempDir,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
want := []string{
|
|
filepath.Join(tempDir, "ttyUSB100"),
|
|
filepath.Join(tempDir, "ttyUSB102"),
|
|
}
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() = %v, want %v",
|
|
got,
|
|
want,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestExistingVirtualPortLinksIgnoresRegularFile(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
cfg := config.VirtualPortRangeConfig{
|
|
First: 100,
|
|
Last: 102,
|
|
}
|
|
|
|
path := filepath.Join(tempDir, "ttyUSB100")
|
|
|
|
if err := os.WriteFile(
|
|
path,
|
|
[]byte("not a symlink"),
|
|
0644,
|
|
); err != nil {
|
|
t.Fatalf(
|
|
"create regular test file %q: %v",
|
|
path,
|
|
err,
|
|
)
|
|
}
|
|
|
|
got, err := existingVirtualPortLinksInDirectory(
|
|
cfg,
|
|
tempDir,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
if len(got) != 0 {
|
|
t.Fatalf(
|
|
"regular file was detected as virtual port: %v",
|
|
got,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestExistingVirtualPortLinksIgnoresOutsideRange(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
cfg := config.VirtualPortRangeConfig{
|
|
First: 100,
|
|
Last: 102,
|
|
}
|
|
|
|
path := filepath.Join(tempDir, "ttyUSB103")
|
|
|
|
if err := os.Symlink(
|
|
"/dev/pts/103",
|
|
path,
|
|
); err != nil {
|
|
t.Fatalf(
|
|
"create outside-range symlink %q: %v",
|
|
path,
|
|
err,
|
|
)
|
|
}
|
|
|
|
got, err := existingVirtualPortLinksInDirectory(
|
|
cfg,
|
|
tempDir,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf(
|
|
"existingVirtualPortLinksInDirectory() failed: %v",
|
|
err,
|
|
)
|
|
}
|
|
|
|
if len(got) != 0 {
|
|
t.Fatalf(
|
|
"outside-range symlink was detected: %v",
|
|
got,
|
|
)
|
|
}
|
|
}
|
|
|
|
func itoa(number int) string {
|
|
const digits = "0123456789"
|
|
|
|
if number == 0 {
|
|
return "0"
|
|
}
|
|
|
|
result := ""
|
|
|
|
for number > 0 {
|
|
result = string(digits[number%10]) + result
|
|
number /= 10
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func hasPathSuffix(path string, suffix string) bool {
|
|
return path == suffix ||
|
|
len(path) > len(suffix) &&
|
|
path[len(path)-len(suffix):] == suffix
|
|
}
|