Startbytes für virtuelle Geräteverbindungen ergänzen
This commit is contained in:
parent
f2428a2007
commit
0eccd003f0
4 changed files with 259 additions and 59 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"server": {
|
"server": {
|
||||||
"address": "100.64.0.1",
|
"address": "192.168.178.229",
|
||||||
"port": 5000
|
"port": 5000
|
||||||
},
|
},
|
||||||
"virtual_port_range": {
|
"virtual_port_range": {
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
"virtual_ports": [
|
"virtual_ports": [
|
||||||
{
|
{
|
||||||
"port": "COM100",
|
"port": "COM100",
|
||||||
"remote_device": "rotor"
|
"remote_device": "rotor",
|
||||||
|
"startup_bytes": "57 00 00 00 00 00 00 00 00 00 00 1F 20"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,18 @@
|
||||||
*
|
*
|
||||||
* Die konfigurierte lokale virtuelle Schnittstelle wird dabei exakt
|
* Die konfigurierte lokale virtuelle Schnittstelle wird dabei exakt
|
||||||
* übernommen.
|
* übernommen.
|
||||||
|
*
|
||||||
|
* Optional können nach dem Aufbau der Datenverbindung konfigurierte
|
||||||
|
* Startbytes an das entfernte Gerät gesendet werden.
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
*/
|
*/
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.lang-dieter.de/rs2322tcp/internal/config"
|
"git.lang-dieter.de/rs2322tcp/internal/config"
|
||||||
"git.lang-dieter.de/rs2322tcp/internal/transport"
|
"git.lang-dieter.de/rs2322tcp/internal/transport"
|
||||||
|
|
@ -36,6 +41,11 @@ import (
|
||||||
// The local virtual port is opened using exactly the port number specified
|
// The local virtual port is opened using exactly the port number specified
|
||||||
// in virtualPortConfig.Port. This preserves the user's configured mapping
|
// in virtualPortConfig.Port. This preserves the user's configured mapping
|
||||||
// between local virtual interfaces and remote devices.
|
// between local virtual interfaces and remote devices.
|
||||||
|
//
|
||||||
|
// If StartupBytes are configured, they are sent once immediately after the
|
||||||
|
// TCP data connection has been established. Invalid startup bytes do not
|
||||||
|
// abort the connection setup. A warning is printed and the connection
|
||||||
|
// continues normally.
|
||||||
func connectVirtualPort(
|
func connectVirtualPort(
|
||||||
c *Client,
|
c *Client,
|
||||||
manager *VirtualPortManager,
|
manager *VirtualPortManager,
|
||||||
|
|
@ -81,9 +91,63 @@ func connectVirtualPort(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := sendStartupBytes(conn, virtualPortConfig); err != nil {
|
||||||
|
fmt.Printf(
|
||||||
|
"warning: startup bytes for %q were not sent: %v\n",
|
||||||
|
virtualPortConfig.RemoteDevice,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return virtualPort, conn, nil
|
return virtualPort, conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendStartupBytes sends the optional configured startup byte sequence over
|
||||||
|
// the already established TCP data connection.
|
||||||
|
//
|
||||||
|
// An empty StartupBytes configuration does not send anything and is not an
|
||||||
|
// error.
|
||||||
|
//
|
||||||
|
// The configured value may contain spaces between hexadecimal bytes, for
|
||||||
|
// example:
|
||||||
|
//
|
||||||
|
// 57 00 00 00 00 00 00 00 00 00 00 1F 20
|
||||||
|
func sendStartupBytes(
|
||||||
|
conn net.Conn,
|
||||||
|
virtualPortConfig config.VirtualPortConfig,
|
||||||
|
) error {
|
||||||
|
startupBytes := strings.TrimSpace(virtualPortConfig.StartupBytes)
|
||||||
|
if startupBytes == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hexText := strings.Join(strings.Fields(startupBytes), "")
|
||||||
|
|
||||||
|
data, err := hex.DecodeString(hexText)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid hexadecimal byte sequence: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
written, err := conn.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("send startup bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if written != len(data) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"send startup bytes: wrote %d of %d bytes",
|
||||||
|
written,
|
||||||
|
len(data),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Bridge connection
|
// Bridge connection
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ type VirtualPortRangeConfig struct {
|
||||||
type VirtualPortConfig struct {
|
type VirtualPortConfig struct {
|
||||||
Port string `json:"port"`
|
Port string `json:"port"`
|
||||||
RemoteDevice string `json:"remote_device"`
|
RemoteDevice string `json:"remote_device"`
|
||||||
|
StartupBytes string `json:"startup_bytes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,15 @@ func TestLoadServer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Listen.Address != "0.0.0.0" {
|
if cfg.Listen.Address != "0.0.0.0" {
|
||||||
t.Errorf("Listen.Address = %q, want %q",
|
t.Errorf(
|
||||||
cfg.Listen.Address, "0.0.0.0")
|
"Listen.Address = %q, want %q",
|
||||||
|
cfg.Listen.Address,
|
||||||
|
"0.0.0.0",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Listen.Port != 5000 {
|
if cfg.Listen.Port != 5000 {
|
||||||
t.Errorf("Listen.Port = %d, want %d",
|
t.Errorf("Listen.Port = %d, want %d", cfg.Listen.Port, 5000)
|
||||||
cfg.Listen.Port, 5000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Devices) != 1 {
|
if len(cfg.Devices) != 1 {
|
||||||
|
|
@ -75,18 +77,19 @@ func TestLoadServer(t *testing.T) {
|
||||||
device := cfg.Devices[0]
|
device := cfg.Devices[0]
|
||||||
|
|
||||||
if device.ID != "radio" {
|
if device.ID != "radio" {
|
||||||
t.Errorf("Device.ID = %q, want %q",
|
t.Errorf("Device.ID = %q, want %q", device.ID, "radio")
|
||||||
device.ID, "radio")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if device.SerialPort != "/dev/ttyUSB0" {
|
if device.SerialPort != "/dev/ttyUSB0" {
|
||||||
t.Errorf("Device.SerialPort = %q, want %q",
|
t.Errorf(
|
||||||
device.SerialPort, "/dev/ttyUSB0")
|
"Device.SerialPort = %q, want %q",
|
||||||
|
device.SerialPort,
|
||||||
|
"/dev/ttyUSB0",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if device.BaudRate != 9600 {
|
if device.BaudRate != 9600 {
|
||||||
t.Errorf("Device.BaudRate = %d, want %d",
|
t.Errorf("Device.BaudRate = %d, want %d", device.BaudRate, 9600)
|
||||||
device.BaudRate, 9600)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,40 +124,106 @@ func TestLoadClient(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Server.Address != "100.64.0.10" {
|
if cfg.Server.Address != "100.64.0.10" {
|
||||||
t.Errorf("Server.Address = %q, want %q",
|
t.Errorf(
|
||||||
cfg.Server.Address, "100.64.0.10")
|
"Server.Address = %q, want %q",
|
||||||
|
cfg.Server.Address,
|
||||||
|
"100.64.0.10",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Server.Port != 5000 {
|
if cfg.Server.Port != 5000 {
|
||||||
t.Errorf("Server.Port = %d, want %d",
|
t.Errorf("Server.Port = %d, want %d", cfg.Server.Port, 5000)
|
||||||
cfg.Server.Port, 5000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.VirtualPortRange.First != config.DefaultVirtualPortFirst {
|
if cfg.VirtualPortRange.First != config.DefaultVirtualPortFirst {
|
||||||
t.Errorf("VirtualPortRange.First = %d, want %d",
|
t.Errorf(
|
||||||
cfg.VirtualPortRange.First, config.DefaultVirtualPortFirst)
|
"VirtualPortRange.First = %d, want %d",
|
||||||
|
cfg.VirtualPortRange.First,
|
||||||
|
config.DefaultVirtualPortFirst,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.VirtualPortRange.Last != config.DefaultVirtualPortLast {
|
if cfg.VirtualPortRange.Last != config.DefaultVirtualPortLast {
|
||||||
t.Errorf("VirtualPortRange.Last = %d, want %d",
|
t.Errorf(
|
||||||
cfg.VirtualPortRange.Last, config.DefaultVirtualPortLast)
|
"VirtualPortRange.Last = %d, want %d",
|
||||||
|
cfg.VirtualPortRange.Last,
|
||||||
|
config.DefaultVirtualPortLast,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.VirtualPorts) != 1 {
|
if len(cfg.VirtualPorts) != 1 {
|
||||||
t.Fatalf("len(VirtualPorts) = %d, want 1",
|
t.Fatalf(
|
||||||
len(cfg.VirtualPorts))
|
"len(VirtualPorts) = %d, want 1",
|
||||||
|
len(cfg.VirtualPorts),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualPort := cfg.VirtualPorts[0]
|
virtualPort := cfg.VirtualPorts[0]
|
||||||
|
|
||||||
if virtualPort.Port != "COM7" {
|
if virtualPort.Port != "COM7" {
|
||||||
t.Errorf("VirtualPort.Port = %q, want %q",
|
t.Errorf(
|
||||||
virtualPort.Port, "COM7")
|
"VirtualPort.Port = %q, want %q",
|
||||||
|
virtualPort.Port,
|
||||||
|
"COM7",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if virtualPort.RemoteDevice != "radio" {
|
if virtualPort.RemoteDevice != "radio" {
|
||||||
t.Errorf("VirtualPort.RemoteDevice = %q, want %q",
|
t.Errorf(
|
||||||
virtualPort.RemoteDevice, "radio")
|
"VirtualPort.RemoteDevice = %q, want %q",
|
||||||
|
virtualPort.RemoteDevice,
|
||||||
|
"radio",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if virtualPort.StartupBytes != "" {
|
||||||
|
t.Errorf(
|
||||||
|
"VirtualPort.StartupBytes = %q, want empty",
|
||||||
|
virtualPort.StartupBytes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadClientWithStartupBytes(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",
|
||||||
|
"startup_bytes": "57 00 00 1F 20"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
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 len(cfg.VirtualPorts) != 1 {
|
||||||
|
t.Fatalf(
|
||||||
|
"len(VirtualPorts) = %d, want 1",
|
||||||
|
len(cfg.VirtualPorts),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.VirtualPorts[0].StartupBytes != "57 00 00 1F 20" {
|
||||||
|
t.Errorf(
|
||||||
|
"VirtualPort.StartupBytes = %q, want %q",
|
||||||
|
cfg.VirtualPorts[0].StartupBytes,
|
||||||
|
"57 00 00 1F 20",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,13 +253,17 @@ func TestLoadClientCustomVirtualPortRange(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.VirtualPortRange.First != 200 {
|
if cfg.VirtualPortRange.First != 200 {
|
||||||
t.Errorf("VirtualPortRange.First = %d, want 200",
|
t.Errorf(
|
||||||
cfg.VirtualPortRange.First)
|
"VirtualPortRange.First = %d, want 200",
|
||||||
|
cfg.VirtualPortRange.First,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.VirtualPortRange.Last != 299 {
|
if cfg.VirtualPortRange.Last != 299 {
|
||||||
t.Errorf("VirtualPortRange.Last = %d, want 299",
|
t.Errorf(
|
||||||
cfg.VirtualPortRange.Last)
|
"VirtualPortRange.Last = %d, want 299",
|
||||||
|
cfg.VirtualPortRange.Last,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +288,7 @@ func TestSaveAndLoadClient(t *testing.T) {
|
||||||
{
|
{
|
||||||
Port: "COM7",
|
Port: "COM7",
|
||||||
RemoteDevice: "radio",
|
RemoteDevice: "radio",
|
||||||
|
StartupBytes: "57 00 00 1F 20",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Port: "COM8",
|
Port: "COM8",
|
||||||
|
|
@ -241,9 +315,11 @@ func TestSaveAndLoadClient(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(loaded.VirtualPorts) != len(original.VirtualPorts) {
|
if len(loaded.VirtualPorts) != len(original.VirtualPorts) {
|
||||||
t.Fatalf("len(VirtualPorts) = %d, want %d",
|
t.Fatalf(
|
||||||
|
"len(VirtualPorts) = %d, want %d",
|
||||||
len(loaded.VirtualPorts),
|
len(loaded.VirtualPorts),
|
||||||
len(original.VirtualPorts))
|
len(original.VirtualPorts),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range original.VirtualPorts {
|
for i := range original.VirtualPorts {
|
||||||
|
|
@ -402,8 +478,29 @@ func TestExampleClientConfig(t *testing.T) {
|
||||||
t.Fatalf("LoadClient() failed: %v", err)
|
t.Fatalf("LoadClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.VirtualPorts) != 2 {
|
if len(cfg.VirtualPorts) != 1 {
|
||||||
t.Fatalf("len(VirtualPorts) = %d, want 2", len(cfg.VirtualPorts))
|
t.Fatalf(
|
||||||
|
"len(VirtualPorts) = %d, want 1",
|
||||||
|
len(cfg.VirtualPorts),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
port := cfg.VirtualPorts[0]
|
||||||
|
|
||||||
|
if port.Port != "COM100" {
|
||||||
|
t.Errorf(
|
||||||
|
"VirtualPorts[0].Port = %q, want %q",
|
||||||
|
port.Port,
|
||||||
|
"COM100",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if port.RemoteDevice != "rotor" {
|
||||||
|
t.Errorf(
|
||||||
|
"VirtualPorts[0].RemoteDevice = %q, want %q",
|
||||||
|
port.RemoteDevice,
|
||||||
|
"rotor",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,33 +522,51 @@ func TestDeviceRemoteDevice(t *testing.T) {
|
||||||
remote := device.RemoteDevice()
|
remote := device.RemoteDevice()
|
||||||
|
|
||||||
if remote.ID != "radio" {
|
if remote.ID != "radio" {
|
||||||
t.Errorf("RemoteDevice.ID = %q, want %q",
|
t.Errorf(
|
||||||
remote.ID, "radio")
|
"RemoteDevice.ID = %q, want %q",
|
||||||
|
remote.ID,
|
||||||
|
"radio",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote.Name != "Funkgerät" {
|
if remote.Name != "Funkgerät" {
|
||||||
t.Errorf("RemoteDevice.Name = %q, want %q",
|
t.Errorf(
|
||||||
remote.Name, "Funkgerät")
|
"RemoteDevice.Name = %q, want %q",
|
||||||
|
remote.Name,
|
||||||
|
"Funkgerät",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote.BaudRate != 9600 {
|
if remote.BaudRate != 9600 {
|
||||||
t.Errorf("RemoteDevice.BaudRate = %d, want %d",
|
t.Errorf(
|
||||||
remote.BaudRate, 9600)
|
"RemoteDevice.BaudRate = %d, want %d",
|
||||||
|
remote.BaudRate,
|
||||||
|
9600,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote.DataBits != 8 {
|
if remote.DataBits != 8 {
|
||||||
t.Errorf("RemoteDevice.DataBits = %d, want %d",
|
t.Errorf(
|
||||||
remote.DataBits, 8)
|
"RemoteDevice.DataBits = %d, want %d",
|
||||||
|
remote.DataBits,
|
||||||
|
8,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote.Parity != "none" {
|
if remote.Parity != "none" {
|
||||||
t.Errorf("RemoteDevice.Parity = %q, want %q",
|
t.Errorf(
|
||||||
remote.Parity, "none")
|
"RemoteDevice.Parity = %q, want %q",
|
||||||
|
remote.Parity,
|
||||||
|
"none",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote.StopBits != 1 {
|
if remote.StopBits != 1 {
|
||||||
t.Errorf("RemoteDevice.StopBits = %d, want %d",
|
t.Errorf(
|
||||||
remote.StopBits, 1)
|
"RemoteDevice.StopBits = %d, want %d",
|
||||||
|
remote.StopBits,
|
||||||
|
1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,28 +605,41 @@ func TestServerRemoteDevices(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Devices[0].ID != "radio" {
|
if list.Devices[0].ID != "radio" {
|
||||||
t.Errorf("Devices[0].ID = %q, want %q",
|
t.Errorf(
|
||||||
list.Devices[0].ID, "radio")
|
"Devices[0].ID = %q, want %q",
|
||||||
|
list.Devices[0].ID,
|
||||||
|
"radio",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Devices[1].ID != "rotor" {
|
if list.Devices[1].ID != "rotor" {
|
||||||
t.Errorf("Devices[1].ID = %q, want %q",
|
t.Errorf(
|
||||||
list.Devices[1].ID, "rotor")
|
"Devices[1].ID = %q, want %q",
|
||||||
|
list.Devices[1].ID,
|
||||||
|
"rotor",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Devices[0].Name != "Funkgerät" {
|
if list.Devices[0].Name != "Funkgerät" {
|
||||||
t.Errorf("Devices[0].Name = %q, want %q",
|
t.Errorf(
|
||||||
list.Devices[0].Name, "Funkgerät")
|
"Devices[0].Name = %q, want %q",
|
||||||
|
list.Devices[0].Name,
|
||||||
|
"Funkgerät",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Devices[0].BaudRate != 9600 {
|
if list.Devices[0].BaudRate != 9600 {
|
||||||
t.Errorf("Devices[0].BaudRate = %d, want 9600",
|
t.Errorf(
|
||||||
list.Devices[0].BaudRate)
|
"Devices[0].BaudRate = %d, want 9600",
|
||||||
|
list.Devices[0].BaudRate,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Devices[1].BaudRate != 4800 {
|
if list.Devices[1].BaudRate != 4800 {
|
||||||
t.Errorf("Devices[1].BaudRate = %d, want 4800",
|
t.Errorf(
|
||||||
list.Devices[1].BaudRate)
|
"Devices[1].BaudRate = %d, want 4800",
|
||||||
|
list.Devices[1].BaudRate,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,11 +689,17 @@ func TestRemoteDeviceJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(decoded.Devices) != 1 {
|
if len(decoded.Devices) != 1 {
|
||||||
t.Fatalf("len(decoded.Devices) = %d, want 1", len(decoded.Devices))
|
t.Fatalf(
|
||||||
|
"len(decoded.Devices) = %d, want 1",
|
||||||
|
len(decoded.Devices),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if decoded.Devices[0].ID != "radio" {
|
if decoded.Devices[0].ID != "radio" {
|
||||||
t.Errorf("Devices[0].ID = %q, want %q",
|
t.Errorf(
|
||||||
decoded.Devices[0].ID, "radio")
|
"Devices[0].ID = %q, want %q",
|
||||||
|
decoded.Devices[0].ID,
|
||||||
|
"radio",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue