mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 00:26:29 +00:00
Reduces `pkg/discovery` test suite runtime by ~75% (from ~17s to ~4s) by eliminating unnecessary network timeouts and reducing wait intervals. - Refactor `discovery.Service` to use an injectable `http.Client`, allowing UPnP enrichment tests to use `httptest.Server` instead of waiting for 5s network timeouts. - Make `DNSDiscovery` forward timeout configurable and reduce it from 2s to 100ms in unit tests. - Decrease discovery and context timeouts in mDNS and Unified discovery tests to the minimum required for stable verification (typically 100-200ms).
286 lines
7.4 KiB
Go
286 lines
7.4 KiB
Go
package discovery
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/config"
|
|
)
|
|
|
|
func TestNewUnifiedDiscoveryService(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
if service == nil {
|
|
t.Fatal("Expected service to be created, got nil")
|
|
}
|
|
|
|
if service.config != cfg {
|
|
t.Error("Expected config to be set correctly")
|
|
}
|
|
|
|
if service.ssdpService == nil {
|
|
t.Error("Expected SSDP service to be initialized")
|
|
}
|
|
|
|
if service.mdnsService == nil {
|
|
t.Error("Expected mDNS service to be initialized")
|
|
}
|
|
|
|
if service.cache == nil {
|
|
t.Error("Expected cache to be initialized")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryWithDefaultConfig(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
if service == nil {
|
|
t.Error("Expected service to be created, got nil")
|
|
}
|
|
|
|
// Both UPnP and mDNS should be enabled by default
|
|
if !cfg.UPnPEnabled {
|
|
t.Error("Expected UPnP to be enabled by default")
|
|
}
|
|
|
|
if !cfg.MDNSEnabled {
|
|
t.Error("Expected mDNS to be enabled by default")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryWithCustomConfig(t *testing.T) {
|
|
cfg := &config.Config{
|
|
DiscoveryTimeout: 10 * time.Second,
|
|
UPnPEnabled: false,
|
|
MDNSEnabled: true,
|
|
CacheEnabled: false,
|
|
CacheTTL: 60 * time.Second,
|
|
HTTPTimeout: 15 * time.Second,
|
|
}
|
|
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
if service.config.DiscoveryTimeout != 10*time.Second {
|
|
t.Errorf("Expected timeout 10s, got %v", service.config.DiscoveryTimeout)
|
|
}
|
|
|
|
if service.config.UPnPEnabled {
|
|
t.Error("Expected UPnP to be disabled")
|
|
}
|
|
|
|
if !service.config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be enabled")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoverDevices(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 100 * time.Millisecond
|
|
cfg.CacheEnabled = false // Disable cache for testing
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
devices, err := service.DiscoverDevices(ctx)
|
|
|
|
// We don't expect an error, even if no devices are found
|
|
if err != nil {
|
|
t.Errorf("Expected no error, got %v", err)
|
|
}
|
|
|
|
// devices slice should be initialized (but might be empty)
|
|
if devices == nil {
|
|
t.Error("Expected devices slice to be initialized, got nil")
|
|
}
|
|
|
|
// If devices are found, verify they have the required fields
|
|
for _, device := range devices {
|
|
if device.Host == "" {
|
|
t.Error("Device host should not be empty")
|
|
}
|
|
|
|
if device.Port == 0 {
|
|
t.Error("Device port should not be zero")
|
|
}
|
|
|
|
if device.Name == "" {
|
|
t.Error("Device name should not be empty")
|
|
}
|
|
|
|
if device.InfoURL == "" {
|
|
t.Error("Device info URL should not be empty")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryOnlyMDNS(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 100 * time.Millisecond
|
|
cfg.UPnPEnabled = false // Disable UPnP
|
|
cfg.MDNSEnabled = true // Enable only mDNS
|
|
cfg.CacheEnabled = false
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
devices, err := service.DiscoverDevices(ctx)
|
|
if err != nil {
|
|
t.Errorf("Expected no error, got %v", err)
|
|
}
|
|
|
|
// devices should never be nil, even if no devices are found
|
|
if devices == nil {
|
|
t.Error("Expected devices slice to be initialized, got nil")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryOnlySSDP(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 100 * time.Millisecond
|
|
cfg.UPnPEnabled = true // Enable only UPnP
|
|
cfg.MDNSEnabled = false // Disable mDNS
|
|
cfg.CacheEnabled = false
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
devices, err := service.DiscoverDevices(ctx)
|
|
if err != nil {
|
|
t.Errorf("Expected no error, got %v", err)
|
|
}
|
|
|
|
if devices == nil {
|
|
t.Error("Expected devices slice to be initialized, got nil")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryCache(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 100 * time.Millisecond
|
|
cfg.CacheEnabled = true
|
|
cfg.CacheTTL = 1 * time.Second
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
ctx := context.Background()
|
|
|
|
// First discovery
|
|
start := time.Now()
|
|
devices1, err := service.DiscoverDevices(ctx)
|
|
firstDuration := time.Since(start)
|
|
|
|
if err != nil {
|
|
t.Errorf("Expected no error on first discovery, got %v", err)
|
|
}
|
|
|
|
// Second discovery (should use cache)
|
|
start = time.Now()
|
|
devices2, err := service.DiscoverDevices(ctx)
|
|
secondDuration := time.Since(start)
|
|
|
|
if err != nil {
|
|
t.Errorf("Expected no error on second discovery, got %v", err)
|
|
}
|
|
|
|
// Second call should be much faster (cached)
|
|
if secondDuration > firstDuration/2 {
|
|
t.Logf("First discovery: %v, Second discovery: %v", firstDuration, secondDuration)
|
|
// Note: We don't fail here because in a test environment without devices,
|
|
// both calls might be very fast anyway
|
|
}
|
|
|
|
// Results should be the same
|
|
if len(devices1) != len(devices2) {
|
|
t.Errorf("Expected same number of devices from cache, got %d vs %d", len(devices1), len(devices2))
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryClearCache(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.CacheEnabled = true
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
// Clear cache should not panic
|
|
service.ClearCache()
|
|
|
|
// Check that cache is empty
|
|
cached := service.GetCachedDevices()
|
|
if len(cached) != 0 {
|
|
t.Errorf("Expected empty cache after clear, got %d devices", len(cached))
|
|
}
|
|
}
|
|
|
|
func TestUnifiedSetMDNSEnabled(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
// Initially enabled
|
|
if !service.config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be enabled initially")
|
|
}
|
|
|
|
// Disable mDNS
|
|
service.SetMDNSEnabled(false)
|
|
|
|
if service.config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be disabled after SetMDNSEnabled(false)")
|
|
}
|
|
|
|
// Enable mDNS
|
|
service.SetMDNSEnabled(true)
|
|
|
|
if !service.config.MDNSEnabled {
|
|
t.Error("Expected mDNS to be enabled after SetMDNSEnabled(true)")
|
|
}
|
|
}
|
|
|
|
func TestUnifiedDiscoveryWithCancelledContext(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 5 * time.Second
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel() // Cancel immediately
|
|
|
|
devices, err := service.DiscoverDevices(ctx)
|
|
|
|
// Should handle cancelled context gracefully
|
|
// devices should never be nil, even if cancelled
|
|
if devices == nil {
|
|
t.Error("Expected devices slice to be initialized, got nil")
|
|
}
|
|
|
|
// Error might or might not occur depending on timing, network conditions, and cancellation
|
|
// This is acceptable for testing - we just ensure no panic and proper slice initialization
|
|
_ = err
|
|
}
|
|
|
|
func TestUnifiedDiscoveryTimeout(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
cfg.DiscoveryTimeout = 200 * time.Millisecond
|
|
cfg.CacheEnabled = false
|
|
service := NewUnifiedDiscoveryService(cfg)
|
|
|
|
start := time.Now()
|
|
ctx := context.Background()
|
|
|
|
_, err := service.DiscoverDevices(ctx)
|
|
duration := time.Since(start)
|
|
|
|
// The discovery should not take significantly longer than the timeout
|
|
// Allow some buffer for processing time and parallel execution
|
|
maxExpected := 1 * time.Second // More generous for parallel execution
|
|
if duration > maxExpected {
|
|
t.Errorf("Discovery took too long: %v, expected less than %v", duration, maxExpected)
|
|
}
|
|
|
|
// We don't check for error here because discovery might succeed quickly
|
|
// or fail due to network conditions, both are acceptable in tests
|
|
_ = err
|
|
}
|