mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
Mirrors the .md/.txt sweep across all tracked _test.go, testdata XML,
and .http integration files. Test files are self-contained (producer
+ assertion in the same file), so the matched-pair swap stays green
under `go test ./...`.
Mapping applied:
192.168.178.[0-9]+ → 192.0.2.[same]
192.168.1.[0-9]+ → 192.0.2.[same]
Sound Machinechen → Living Room SoundTouch
A Sound Machine → Kitchen SoundTouch
A81B6A536A98 + case/separator variants → AABBCCDDEEFF (etc.)
A81B6A849D99 → AABBCCDDEE01
A81B6A849D88 → AABBCCDDEE03
A81B6A536A09 → AABBCCDDEE04
884AEAEEBD27 → AABBCCDDEE02
3230304 → 1000001
9569497 → 1000002
Two semantic fixes alongside the bulk swap:
- pkg/service/zeroconf/zeroconf_test.go: the "private 192" and
"strips query" cases pin acceptance of RFC-1918 192.168/16. They
must use a real 192.168 value; doc-range IPs would (correctly) be
rejected by validateZcBaseURL. Switched to 192.168.10.10 — generic
enough not to match any home LAN default, real enough for the
validator. Added a comment explaining why this single test still
carries a 192.168 literal.
- pkg/service/setup/setup_test.go: TestTestDNSRedirection mocks the
device's `od -An -tu1` byte output, which is space-separated
octets ("192 168 1 100"). My sed only matched the dot-separated
form, so the mock was returning the old IP while the test
assertions had moved to the doc range. Updated to " 192 0 2 100".
go build ./... clean. go test ./... clean (only TestDocsConsistency
remains failing, which is a pre-existing/untracked-file issue).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
450 lines
11 KiB
Go
450 lines
11 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDefaultConfig(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
if config.DiscoveryTimeout != 5*time.Second {
|
|
t.Errorf("Expected discovery timeout 5s, got %v", config.DiscoveryTimeout)
|
|
}
|
|
|
|
if !config.UPnPEnabled {
|
|
t.Error("Expected UPnP to be enabled by default")
|
|
}
|
|
|
|
if !config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be enabled by default")
|
|
}
|
|
|
|
if config.HTTPTimeout != 10*time.Second {
|
|
t.Errorf("Expected HTTP timeout 10s, got %v", config.HTTPTimeout)
|
|
}
|
|
|
|
if config.UserAgent != "Bose-SoundTouch-Go-Client/1.0" {
|
|
t.Errorf("Expected default user agent, got %s", config.UserAgent)
|
|
}
|
|
|
|
if !config.CacheEnabled {
|
|
t.Error("Expected cache to be enabled by default")
|
|
}
|
|
|
|
if config.CacheTTL != 30*time.Second {
|
|
t.Errorf("Expected cache TTL 30s, got %v", config.CacheTTL)
|
|
}
|
|
|
|
if len(config.PreferredDevices) != 0 {
|
|
t.Errorf("Expected no preferred devices by default, got %d", len(config.PreferredDevices))
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnv_NoEnvVars(t *testing.T) {
|
|
// Clear relevant environment variables
|
|
clearTestEnvVars()
|
|
|
|
config, err := LoadFromEnv()
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
// Should have default values
|
|
if config.DiscoveryTimeout != 5*time.Second {
|
|
t.Errorf("Expected default discovery timeout, got %v", config.DiscoveryTimeout)
|
|
}
|
|
|
|
if !config.UPnPEnabled {
|
|
t.Error("Expected UPnP enabled by default")
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnv_WithEnvVars(t *testing.T) {
|
|
clearTestEnvVars()
|
|
|
|
// Set test environment variables
|
|
_ = os.Setenv("DISCOVERY_TIMEOUT", "15s")
|
|
_ = os.Setenv("UPNP_ENABLED", "false")
|
|
_ = os.Setenv("MDNS_ENABLED", "false")
|
|
_ = os.Setenv("HTTP_TIMEOUT", "20s")
|
|
_ = os.Setenv("USER_AGENT", "Test-Client/1.0")
|
|
_ = os.Setenv("CACHE_ENABLED", "false")
|
|
_ = os.Setenv("CACHE_TTL", "60s")
|
|
|
|
defer clearTestEnvVars()
|
|
|
|
config, err := LoadFromEnv()
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if config.DiscoveryTimeout != 15*time.Second {
|
|
t.Errorf("Expected discovery timeout 15s, got %v", config.DiscoveryTimeout)
|
|
}
|
|
|
|
if config.UPnPEnabled {
|
|
t.Error("Expected UPnP to be disabled")
|
|
}
|
|
|
|
if config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be disabled")
|
|
}
|
|
|
|
if config.HTTPTimeout != 20*time.Second {
|
|
t.Errorf("Expected HTTP timeout 20s, got %v", config.HTTPTimeout)
|
|
}
|
|
|
|
if config.UserAgent != "Test-Client/1.0" {
|
|
t.Errorf("Expected custom user agent, got %s", config.UserAgent)
|
|
}
|
|
|
|
if config.CacheEnabled {
|
|
t.Error("Expected cache to be disabled")
|
|
}
|
|
|
|
if config.CacheTTL != 60*time.Second {
|
|
t.Errorf("Expected cache TTL 60s, got %v", config.CacheTTL)
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_HostOnly(t *testing.T) {
|
|
device, err := parseDeviceString("192.0.2.100")
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if device.Host != "192.0.2.100" {
|
|
t.Errorf("Expected host '192.0.2.100', got '%s'", device.Host)
|
|
}
|
|
|
|
if device.Port != 8090 {
|
|
t.Errorf("Expected default port 8090, got %d", device.Port)
|
|
}
|
|
|
|
if device.Name != "SoundTouch-192.0.2.100" {
|
|
t.Errorf("Expected default name 'SoundTouch-192.0.2.100', got '%s'", device.Name)
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_HostPort(t *testing.T) {
|
|
device, err := parseDeviceString("192.0.2.100:8091")
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if device.Host != "192.0.2.100" {
|
|
t.Errorf("Expected host '192.0.2.100', got '%s'", device.Host)
|
|
}
|
|
|
|
if device.Port != 8091 {
|
|
t.Errorf("Expected port 8091, got %d", device.Port)
|
|
}
|
|
|
|
if device.Name != "SoundTouch-192.0.2.100" {
|
|
t.Errorf("Expected default name 'SoundTouch-192.0.2.100', got '%s'", device.Name)
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_NameHostPort(t *testing.T) {
|
|
device, err := parseDeviceString("Living Room@192.0.2.100:8090")
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if device.Host != "192.0.2.100" {
|
|
t.Errorf("Expected host '192.0.2.100', got '%s'", device.Host)
|
|
}
|
|
|
|
if device.Port != 8090 {
|
|
t.Errorf("Expected port 8090, got %d", device.Port)
|
|
}
|
|
|
|
if device.Name != "Living Room" {
|
|
t.Errorf("Expected name 'Living Room', got '%s'", device.Name)
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_NameHost(t *testing.T) {
|
|
device, err := parseDeviceString("Kitchen Speaker@192.0.2.101")
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if device.Host != "192.0.2.101" {
|
|
t.Errorf("Expected host '192.0.2.101', got '%s'", device.Host)
|
|
}
|
|
|
|
if device.Port != 8090 {
|
|
t.Errorf("Expected default port 8090, got %d", device.Port)
|
|
}
|
|
|
|
if device.Name != "Kitchen Speaker" {
|
|
t.Errorf("Expected name 'Kitchen Speaker', got '%s'", device.Name)
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_InvalidPort(t *testing.T) {
|
|
_, err := parseDeviceString("192.0.2.100:invalid")
|
|
if err == nil {
|
|
t.Error("Expected error for invalid port, got nil")
|
|
}
|
|
|
|
_, err = parseDeviceString("192.0.2.100:0")
|
|
if err == nil {
|
|
t.Error("Expected error for port 0, got nil")
|
|
}
|
|
|
|
_, err = parseDeviceString("192.0.2.100:70000")
|
|
if err == nil {
|
|
t.Error("Expected error for port > 65535, got nil")
|
|
}
|
|
}
|
|
|
|
func TestParseDeviceString_EmptyHost(t *testing.T) {
|
|
_, err := parseDeviceString("")
|
|
if err == nil {
|
|
t.Error("Expected error for empty string, got nil")
|
|
}
|
|
|
|
_, err = parseDeviceString("@")
|
|
if err == nil {
|
|
t.Error("Expected error for empty host with @, got nil")
|
|
}
|
|
}
|
|
|
|
func TestParsePreferredDevices_SingleDevice(t *testing.T) {
|
|
clearTestEnvVars()
|
|
|
|
_ = os.Setenv("PREFERRED_DEVICES", "192.0.2.100")
|
|
|
|
defer clearTestEnvVars()
|
|
|
|
devices, err := parsePreferredDevices()
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if len(devices) != 1 {
|
|
t.Errorf("Expected 1 device, got %d", len(devices))
|
|
}
|
|
|
|
if devices[0].Host != "192.0.2.100" {
|
|
t.Errorf("Expected host '192.0.2.100', got '%s'", devices[0].Host)
|
|
}
|
|
}
|
|
|
|
func TestParsePreferredDevices_MultipleDevices(t *testing.T) {
|
|
clearTestEnvVars()
|
|
|
|
_ = os.Setenv("PREFERRED_DEVICES", "Living Room@192.0.2.100:8090;Kitchen@192.0.2.101;192.0.2.102:8091")
|
|
|
|
defer clearTestEnvVars()
|
|
|
|
devices, err := parsePreferredDevices()
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if len(devices) != 3 {
|
|
t.Errorf("Expected 3 devices, got %d", len(devices))
|
|
}
|
|
|
|
// Check first device
|
|
if devices[0].Name != "Living Room" {
|
|
t.Errorf("Expected first device name 'Living Room', got '%s'", devices[0].Name)
|
|
}
|
|
|
|
if devices[0].Host != "192.0.2.100" {
|
|
t.Errorf("Expected first device host '192.0.2.100', got '%s'", devices[0].Host)
|
|
}
|
|
|
|
if devices[0].Port != 8090 {
|
|
t.Errorf("Expected first device port 8090, got %d", devices[0].Port)
|
|
}
|
|
|
|
// Check second device
|
|
if devices[1].Name != "Kitchen" {
|
|
t.Errorf("Expected second device name 'Kitchen', got '%s'", devices[1].Name)
|
|
}
|
|
|
|
if devices[1].Host != "192.0.2.101" {
|
|
t.Errorf("Expected second device host '192.0.2.101', got '%s'", devices[1].Host)
|
|
}
|
|
|
|
if devices[1].Port != 8090 {
|
|
t.Errorf("Expected second device port 8090, got %d", devices[1].Port)
|
|
}
|
|
|
|
// Check third device
|
|
if devices[2].Name != "SoundTouch-192.0.2.102" {
|
|
t.Errorf("Expected third device default name, got '%s'", devices[2].Name)
|
|
}
|
|
|
|
if devices[2].Host != "192.0.2.102" {
|
|
t.Errorf("Expected third device host '192.0.2.102', got '%s'", devices[2].Host)
|
|
}
|
|
|
|
if devices[2].Port != 8091 {
|
|
t.Errorf("Expected third device port 8091, got %d", devices[2].Port)
|
|
}
|
|
}
|
|
|
|
func TestParsePreferredDevices_EmptyString(t *testing.T) {
|
|
clearTestEnvVars()
|
|
|
|
_ = os.Setenv("PREFERRED_DEVICES", "")
|
|
|
|
defer clearTestEnvVars()
|
|
|
|
devices, err := parsePreferredDevices()
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if len(devices) != 0 {
|
|
t.Errorf("Expected 0 devices for empty string, got %d", len(devices))
|
|
}
|
|
}
|
|
|
|
func TestParsePreferredDevices_InvalidDevice(t *testing.T) {
|
|
clearTestEnvVars()
|
|
|
|
_ = os.Setenv("PREFERRED_DEVICES", "192.0.2.100:invalid")
|
|
|
|
defer clearTestEnvVars()
|
|
|
|
_, err := parsePreferredDevices()
|
|
if err == nil {
|
|
t.Error("Expected error for invalid device configuration, got nil")
|
|
}
|
|
}
|
|
|
|
func TestGetPreferredDevicesAsDiscovered(t *testing.T) {
|
|
config := &Config{
|
|
PreferredDevices: []DeviceConfig{
|
|
{Name: "Living Room", Host: "192.0.2.100", Port: 8090},
|
|
{Name: "Kitchen", Host: "192.0.2.101", Port: 8091},
|
|
},
|
|
}
|
|
|
|
devices := config.GetPreferredDevicesAsDiscovered()
|
|
|
|
if len(devices) != 2 {
|
|
t.Errorf("Expected 2 discovered devices, got %d", len(devices))
|
|
}
|
|
|
|
// Check first device
|
|
if devices[0].Name != "Living Room" {
|
|
t.Errorf("Expected name 'Living Room', got '%s'", devices[0].Name)
|
|
}
|
|
|
|
if devices[0].Host != "192.0.2.100" {
|
|
t.Errorf("Expected host '192.0.2.100', got '%s'", devices[0].Host)
|
|
}
|
|
|
|
if devices[0].Port != 8090 {
|
|
t.Errorf("Expected port 8090, got %d", devices[0].Port)
|
|
}
|
|
|
|
expectedInfoURL := "http://192.0.2.100:8090/info"
|
|
if devices[0].InfoURL != expectedInfoURL {
|
|
t.Errorf("Expected info URL '%s', got '%s'", expectedInfoURL, devices[0].InfoURL)
|
|
}
|
|
}
|
|
|
|
func TestValidate_ValidConfig(t *testing.T) {
|
|
config := &Config{
|
|
DiscoveryTimeout: 5 * time.Second,
|
|
HTTPTimeout: 10 * time.Second,
|
|
CacheTTL: 30 * time.Second,
|
|
PreferredDevices: []DeviceConfig{
|
|
{Name: "Test", Host: "192.0.2.100", Port: 8090},
|
|
},
|
|
}
|
|
|
|
err := config.Validate()
|
|
if err != nil {
|
|
t.Errorf("Expected valid config, got error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidate_InvalidTimeouts(t *testing.T) {
|
|
config := &Config{
|
|
DiscoveryTimeout: 0,
|
|
HTTPTimeout: 10 * time.Second,
|
|
CacheTTL: 30 * time.Second,
|
|
}
|
|
|
|
err := config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for zero discovery timeout, got nil")
|
|
}
|
|
|
|
config.DiscoveryTimeout = 5 * time.Second
|
|
config.HTTPTimeout = 0
|
|
|
|
err = config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for zero HTTP timeout, got nil")
|
|
}
|
|
|
|
config.HTTPTimeout = 10 * time.Second
|
|
config.CacheTTL = 0
|
|
|
|
err = config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for zero cache TTL, got nil")
|
|
}
|
|
}
|
|
|
|
func TestValidate_InvalidDevices(t *testing.T) {
|
|
config := &Config{
|
|
DiscoveryTimeout: 5 * time.Second,
|
|
HTTPTimeout: 10 * time.Second,
|
|
CacheTTL: 30 * time.Second,
|
|
PreferredDevices: []DeviceConfig{
|
|
{Name: "Test", Host: "", Port: 8090}, // Empty host
|
|
},
|
|
}
|
|
|
|
err := config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for empty host, got nil")
|
|
}
|
|
|
|
config.PreferredDevices[0].Host = "192.0.2.100"
|
|
config.PreferredDevices[0].Port = 0 // Invalid port
|
|
|
|
err = config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for invalid port, got nil")
|
|
}
|
|
|
|
config.PreferredDevices[0].Port = 70000 // Port too high
|
|
|
|
err = config.Validate()
|
|
if err == nil {
|
|
t.Error("Expected error for port > 65535, got nil")
|
|
}
|
|
}
|
|
|
|
// Helper function to clear test environment variables
|
|
func clearTestEnvVars() {
|
|
envVars := []string{
|
|
"DISCOVERY_TIMEOUT",
|
|
"UPNP_ENABLED",
|
|
"MDNS_ENABLED",
|
|
"HTTP_TIMEOUT",
|
|
"USER_AGENT",
|
|
"CACHE_ENABLED",
|
|
"CACHE_TTL",
|
|
"PREFERRED_DEVICES",
|
|
}
|
|
|
|
for _, env := range envVars {
|
|
_ = os.Unsetenv(env)
|
|
}
|
|
}
|