571 lines
13 KiB
Go
571 lines
13 KiB
Go
/*
|
|
Package config_test contains tests for the rs2322tcp configuration package.
|
|
|
|
Project: rs2322tcp
|
|
Module: git.lang-dieter.de/rs2322tcp
|
|
*/
|
|
package config_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"git.lang-dieter.de/rs2322tcp/internal/config"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Server configuration
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestLoadServer(t *testing.T) {
|
|
dir := t.TempDir()
|
|
filename := filepath.Join(dir, "server.json")
|
|
|
|
data := `{
|
|
"listen": {
|
|
"address": "0.0.0.0",
|
|
"port": 5000
|
|
},
|
|
"devices": [
|
|
{
|
|
"id": "radio",
|
|
"name": "Funkgerät",
|
|
"serial_port": "/dev/ttyUSB0",
|
|
"baud_rate": 9600,
|
|
"data_bits": 8,
|
|
"parity": "none",
|
|
"stop_bits": 1
|
|
}
|
|
]
|
|
}`
|
|
|
|
if err := os.WriteFile(filename, []byte(data), 0644); err != nil {
|
|
t.Fatalf("write test configuration: %v", err)
|
|
}
|
|
|
|
cfg, err := config.LoadServer(filename)
|
|
if err != nil {
|
|
t.Fatalf("LoadServer() failed: %v", err)
|
|
}
|
|
|
|
if cfg.HardwareErrorResponse != config.DefaultHardwareErrorResponse {
|
|
t.Errorf(
|
|
"HardwareErrorResponse = %q, want %q",
|
|
cfg.HardwareErrorResponse,
|
|
config.DefaultHardwareErrorResponse,
|
|
)
|
|
}
|
|
|
|
if cfg.Listen.Address != "0.0.0.0" {
|
|
t.Errorf("Listen.Address = %q, want %q",
|
|
cfg.Listen.Address, "0.0.0.0")
|
|
}
|
|
|
|
if cfg.Listen.Port != 5000 {
|
|
t.Errorf("Listen.Port = %d, want %d",
|
|
cfg.Listen.Port, 5000)
|
|
}
|
|
|
|
if len(cfg.Devices) != 1 {
|
|
t.Fatalf("len(Devices) = %d, want 1", len(cfg.Devices))
|
|
}
|
|
|
|
device := cfg.Devices[0]
|
|
|
|
if device.ID != "radio" {
|
|
t.Errorf("Device.ID = %q, want %q",
|
|
device.ID, "radio")
|
|
}
|
|
|
|
if device.SerialPort != "/dev/ttyUSB0" {
|
|
t.Errorf("Device.SerialPort = %q, want %q",
|
|
device.SerialPort, "/dev/ttyUSB0")
|
|
}
|
|
|
|
if device.BaudRate != 9600 {
|
|
t.Errorf("Device.BaudRate = %d, want %d",
|
|
device.BaudRate, 9600)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Client configuration
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestLoadClient(t *testing.T) {
|
|
dir := t.TempDir()
|
|
filename := filepath.Join(dir, "client.json")
|
|
|
|
data := `{
|
|
"server": {
|
|
"address": "100.64.0.10",
|
|
"port": 5000
|
|
},
|
|
"virtual_ports": [
|
|
{
|
|
"port": "COM7",
|
|
"remote_device": "radio"
|
|
}
|
|
]
|
|
}`
|
|
|
|
if err := os.WriteFile(filename, []byte(data), 0644); err != nil {
|
|
t.Fatalf("write test configuration: %v", err)
|
|
}
|
|
|
|
cfg, err := config.LoadClient(filename)
|
|
if err != nil {
|
|
t.Fatalf("LoadClient() failed: %v", err)
|
|
}
|
|
|
|
if cfg.Server.Address != "100.64.0.10" {
|
|
t.Errorf("Server.Address = %q, want %q",
|
|
cfg.Server.Address, "100.64.0.10")
|
|
}
|
|
|
|
if cfg.Server.Port != 5000 {
|
|
t.Errorf("Server.Port = %d, want %d",
|
|
cfg.Server.Port, 5000)
|
|
}
|
|
|
|
if cfg.VirtualPortRange.First != config.DefaultVirtualPortFirst {
|
|
t.Errorf("VirtualPortRange.First = %d, want %d",
|
|
cfg.VirtualPortRange.First, config.DefaultVirtualPortFirst)
|
|
}
|
|
|
|
if cfg.VirtualPortRange.Last != config.DefaultVirtualPortLast {
|
|
t.Errorf("VirtualPortRange.Last = %d, want %d",
|
|
cfg.VirtualPortRange.Last, config.DefaultVirtualPortLast)
|
|
}
|
|
|
|
if len(cfg.VirtualPorts) != 1 {
|
|
t.Fatalf("len(VirtualPorts) = %d, want 1",
|
|
len(cfg.VirtualPorts))
|
|
}
|
|
|
|
virtualPort := cfg.VirtualPorts[0]
|
|
|
|
if virtualPort.Port != "COM7" {
|
|
t.Errorf("VirtualPort.Port = %q, want %q",
|
|
virtualPort.Port, "COM7")
|
|
}
|
|
|
|
if virtualPort.RemoteDevice != "radio" {
|
|
t.Errorf("VirtualPort.RemoteDevice = %q, want %q",
|
|
virtualPort.RemoteDevice, "radio")
|
|
}
|
|
}
|
|
|
|
func TestLoadClientCustomVirtualPortRange(t *testing.T) {
|
|
dir := t.TempDir()
|
|
filename := filepath.Join(dir, "client.json")
|
|
|
|
data := `{
|
|
"server": {
|
|
"address": "100.64.0.10",
|
|
"port": 5000
|
|
},
|
|
"virtual_port_range": {
|
|
"first": 200,
|
|
"last": 299
|
|
},
|
|
"virtual_ports": []
|
|
}`
|
|
|
|
if err := os.WriteFile(filename, []byte(data), 0644); err != nil {
|
|
t.Fatalf("write test configuration: %v", err)
|
|
}
|
|
|
|
cfg, err := config.LoadClient(filename)
|
|
if err != nil {
|
|
t.Fatalf("LoadClient() failed: %v", err)
|
|
}
|
|
|
|
if cfg.VirtualPortRange.First != 200 {
|
|
t.Errorf("VirtualPortRange.First = %d, want 200",
|
|
cfg.VirtualPortRange.First)
|
|
}
|
|
|
|
if cfg.VirtualPortRange.Last != 299 {
|
|
t.Errorf("VirtualPortRange.Last = %d, want 299",
|
|
cfg.VirtualPortRange.Last)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Save and reload
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestSaveAndLoadClient(t *testing.T) {
|
|
dir := t.TempDir()
|
|
filename := filepath.Join(dir, "client.json")
|
|
|
|
original := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Address: "100.64.0.10",
|
|
Port: 5000,
|
|
},
|
|
VirtualPortRange: config.VirtualPortRangeConfig{
|
|
First: 200,
|
|
Last: 299,
|
|
},
|
|
VirtualPorts: []config.VirtualPortConfig{
|
|
{
|
|
Port: "COM7",
|
|
RemoteDevice: "radio",
|
|
},
|
|
{
|
|
Port: "COM8",
|
|
RemoteDevice: "rotor",
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := config.SaveClient(filename, original); err != nil {
|
|
t.Fatalf("SaveClient() failed: %v", err)
|
|
}
|
|
|
|
loaded, err := config.LoadClient(filename)
|
|
if err != nil {
|
|
t.Fatalf("LoadClient() failed: %v", err)
|
|
}
|
|
|
|
if loaded.Server != original.Server {
|
|
t.Errorf("loaded Server differs from original")
|
|
}
|
|
|
|
if loaded.VirtualPortRange != original.VirtualPortRange {
|
|
t.Errorf("loaded VirtualPortRange differs from original")
|
|
}
|
|
|
|
if len(loaded.VirtualPorts) != len(original.VirtualPorts) {
|
|
t.Fatalf("len(VirtualPorts) = %d, want %d",
|
|
len(loaded.VirtualPorts),
|
|
len(original.VirtualPorts))
|
|
}
|
|
|
|
for i := range original.VirtualPorts {
|
|
if loaded.VirtualPorts[i] != original.VirtualPorts[i] {
|
|
t.Errorf("VirtualPorts[%d] differs from original", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Validation
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestServerValidationDuplicateDeviceID(t *testing.T) {
|
|
cfg := &config.ServerConfig{
|
|
Listen: config.ListenConfig{
|
|
Port: 5000,
|
|
},
|
|
Devices: []config.DeviceConfig{
|
|
{
|
|
ID: "radio",
|
|
SerialPort: "/dev/ttyUSB0",
|
|
BaudRate: 9600,
|
|
DataBits: 8,
|
|
StopBits: 1,
|
|
},
|
|
{
|
|
ID: "radio",
|
|
SerialPort: "/dev/ttyUSB1",
|
|
BaudRate: 4800,
|
|
DataBits: 8,
|
|
StopBits: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want duplicate ID error")
|
|
}
|
|
}
|
|
|
|
func TestClientValidationDuplicateVirtualPort(t *testing.T) {
|
|
cfg := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Port: 5000,
|
|
},
|
|
VirtualPortRange: config.DefaultVirtualPortRange(),
|
|
VirtualPorts: []config.VirtualPortConfig{
|
|
{
|
|
Port: "COM7",
|
|
RemoteDevice: "radio",
|
|
},
|
|
{
|
|
Port: "COM7",
|
|
RemoteDevice: "rotor",
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want duplicate virtual port error")
|
|
}
|
|
}
|
|
|
|
func TestServerValidationInvalidPort(t *testing.T) {
|
|
cfg := &config.ServerConfig{
|
|
Listen: config.ListenConfig{
|
|
Port: 70000,
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want invalid port error")
|
|
}
|
|
}
|
|
|
|
func TestClientValidationInvalidPort(t *testing.T) {
|
|
cfg := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Port: 0,
|
|
},
|
|
VirtualPortRange: config.DefaultVirtualPortRange(),
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want invalid port error")
|
|
}
|
|
}
|
|
|
|
func TestClientValidationVirtualPortRangeBelowReservedArea(t *testing.T) {
|
|
cfg := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Port: 5000,
|
|
},
|
|
VirtualPortRange: config.VirtualPortRangeConfig{
|
|
First: 99,
|
|
Last: 199,
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want range-below-reserved-area error")
|
|
}
|
|
}
|
|
|
|
func TestClientValidationVirtualPortRangeReversed(t *testing.T) {
|
|
cfg := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Port: 5000,
|
|
},
|
|
VirtualPortRange: config.VirtualPortRangeConfig{
|
|
First: 200,
|
|
Last: 100,
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Fatal("Validate() succeeded, want reversed-range error")
|
|
}
|
|
}
|
|
|
|
func TestClientValidationVirtualPortRangeValid(t *testing.T) {
|
|
cfg := &config.ClientConfig{
|
|
Server: config.ServerConnectionConfig{
|
|
Port: 5000,
|
|
},
|
|
VirtualPortRange: config.VirtualPortRangeConfig{
|
|
First: 200,
|
|
Last: 299,
|
|
},
|
|
}
|
|
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Fatalf("Validate() failed: %v", err)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Example configurations
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestExampleServerConfig(t *testing.T) {
|
|
cfg, err := config.LoadServer("../../configs/server.json")
|
|
if err != nil {
|
|
t.Fatalf("LoadServer() failed: %v", err)
|
|
}
|
|
|
|
if len(cfg.Devices) != 2 {
|
|
t.Fatalf("len(Devices) = %d, want 2", len(cfg.Devices))
|
|
}
|
|
}
|
|
|
|
func TestExampleClientConfig(t *testing.T) {
|
|
cfg, err := config.LoadClient("../../configs/client.json")
|
|
if err != nil {
|
|
t.Fatalf("LoadClient() failed: %v", err)
|
|
}
|
|
|
|
if len(cfg.VirtualPorts) != 2 {
|
|
t.Fatalf("len(VirtualPorts) = %d, want 2", len(cfg.VirtualPorts))
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Remote device
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestDeviceRemoteDevice(t *testing.T) {
|
|
device := config.DeviceConfig{
|
|
ID: "radio",
|
|
Name: "Funkgerät",
|
|
SerialPort: "/dev/ttyUSB0",
|
|
BaudRate: 9600,
|
|
DataBits: 8,
|
|
Parity: "none",
|
|
StopBits: 1,
|
|
}
|
|
|
|
remote := device.RemoteDevice()
|
|
|
|
if remote.ID != "radio" {
|
|
t.Errorf("RemoteDevice.ID = %q, want %q",
|
|
remote.ID, "radio")
|
|
}
|
|
|
|
if remote.Name != "Funkgerät" {
|
|
t.Errorf("RemoteDevice.Name = %q, want %q",
|
|
remote.Name, "Funkgerät")
|
|
}
|
|
|
|
if remote.BaudRate != 9600 {
|
|
t.Errorf("RemoteDevice.BaudRate = %d, want %d",
|
|
remote.BaudRate, 9600)
|
|
}
|
|
|
|
if remote.DataBits != 8 {
|
|
t.Errorf("RemoteDevice.DataBits = %d, want %d",
|
|
remote.DataBits, 8)
|
|
}
|
|
|
|
if remote.Parity != "none" {
|
|
t.Errorf("RemoteDevice.Parity = %q, want %q",
|
|
remote.Parity, "none")
|
|
}
|
|
|
|
if remote.StopBits != 1 {
|
|
t.Errorf("RemoteDevice.StopBits = %d, want %d",
|
|
remote.StopBits, 1)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Remote device list
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestServerRemoteDevices(t *testing.T) {
|
|
cfg := &config.ServerConfig{
|
|
Devices: []config.DeviceConfig{
|
|
{
|
|
ID: "radio",
|
|
Name: "Funkgerät",
|
|
SerialPort: "/dev/ttyUSB0",
|
|
BaudRate: 9600,
|
|
DataBits: 8,
|
|
Parity: "none",
|
|
StopBits: 1,
|
|
},
|
|
{
|
|
ID: "rotor",
|
|
Name: "Antennenrotor",
|
|
SerialPort: "/dev/ttyUSB1",
|
|
BaudRate: 4800,
|
|
DataBits: 8,
|
|
Parity: "none",
|
|
StopBits: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
list := cfg.RemoteDevices()
|
|
|
|
if len(list.Devices) != 2 {
|
|
t.Fatalf("len(Devices) = %d, want 2", len(list.Devices))
|
|
}
|
|
|
|
if list.Devices[0].ID != "radio" {
|
|
t.Errorf("Devices[0].ID = %q, want %q",
|
|
list.Devices[0].ID, "radio")
|
|
}
|
|
|
|
if list.Devices[1].ID != "rotor" {
|
|
t.Errorf("Devices[1].ID = %q, want %q",
|
|
list.Devices[1].ID, "rotor")
|
|
}
|
|
|
|
if list.Devices[0].Name != "Funkgerät" {
|
|
t.Errorf("Devices[0].Name = %q, want %q",
|
|
list.Devices[0].Name, "Funkgerät")
|
|
}
|
|
|
|
if list.Devices[0].BaudRate != 9600 {
|
|
t.Errorf("Devices[0].BaudRate = %d, want 9600",
|
|
list.Devices[0].BaudRate)
|
|
}
|
|
|
|
if list.Devices[1].BaudRate != 4800 {
|
|
t.Errorf("Devices[1].BaudRate = %d, want 4800",
|
|
list.Devices[1].BaudRate)
|
|
}
|
|
}
|
|
|
|
func TestServerRemoteDevicesNil(t *testing.T) {
|
|
var cfg *config.ServerConfig
|
|
|
|
list := cfg.RemoteDevices()
|
|
|
|
if len(list.Devices) != 0 {
|
|
t.Fatalf("len(Devices) = %d, want 0", len(list.Devices))
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Remote device JSON
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
func TestRemoteDeviceJSON(t *testing.T) {
|
|
list := config.DeviceList{
|
|
Devices: []config.RemoteDevice{
|
|
{
|
|
ID: "radio",
|
|
Name: "Funkgerät",
|
|
BaudRate: 9600,
|
|
DataBits: 8,
|
|
Parity: "none",
|
|
StopBits: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
data, err := json.Marshal(list)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal() failed: %v", err)
|
|
}
|
|
|
|
jsonText := string(data)
|
|
|
|
if strings.Contains(jsonText, "serial_port") {
|
|
t.Fatalf("JSON contains server-internal serial_port")
|
|
}
|
|
|
|
var decoded config.DeviceList
|
|
|
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
|
t.Fatalf("json.Unmarshal() failed: %v", err)
|
|
}
|
|
|
|
if len(decoded.Devices) != 1 {
|
|
t.Fatalf("len(decoded.Devices) = %d, want 1", len(decoded.Devices))
|
|
}
|
|
|
|
if decoded.Devices[0].ID != "radio" {
|
|
t.Errorf("Devices[0].ID = %q, want %q",
|
|
decoded.Devices[0].ID, "radio")
|
|
}
|
|
}
|