Files
Bose-SoundTouch/pkg/client/recents_integration_test.go
Tobias GesellchenandClaude Opus 4.7 feadc478d5 test: sweep example data in test files to RFC-5737 + placeholders
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>
2026-05-17 22:05:13 +02:00

336 lines
7.8 KiB
Go

package client
import (
"os"
"testing"
"time"
)
func TestClient_GetRecents_Integration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
host := os.Getenv("SOUNDTOUCH_HOST")
if host == "" {
t.Skip("SOUNDTOUCH_HOST not set, skipping integration test")
}
config := &Config{
Host: host,
Timeout: 10 * time.Second,
}
client := NewClient(config)
t.Run("get recents", func(t *testing.T) {
response, err := client.GetRecents()
if err != nil {
t.Fatalf("failed to get recents: %v", err)
}
if response == nil {
t.Fatal("expected response, got nil")
}
t.Logf("Recent items count: %d", response.GetItemCount())
if response.IsEmpty() {
t.Log("No recent items found - this is normal if device hasn't played anything recently")
return
}
// Test basic functionality
t.Logf("Recent items found: %d", response.GetItemCount())
// Get most recent item
mostRecent := response.GetMostRecent()
if mostRecent != nil {
t.Logf("Most recent item: %s (Source: %s, Time: %d)",
mostRecent.GetDisplayName(),
mostRecent.GetSource(),
mostRecent.GetUTCTime())
if mostRecent.HasArtwork() {
t.Logf(" Has artwork: %s", mostRecent.GetArtwork())
}
if mostRecent.IsPresetable() {
t.Log(" Can be saved as preset")
}
// Test content type detection
if mostRecent.IsTrack() {
t.Log(" Content type: Track")
} else if mostRecent.IsStation() {
t.Log(" Content type: Radio Station")
} else if mostRecent.IsPlaylist() {
t.Log(" Content type: Playlist")
} else if mostRecent.IsAlbum() {
t.Log(" Content type: Album")
} else if mostRecent.IsContainer() {
t.Log(" Content type: Container")
}
// Test source type detection
if mostRecent.IsSpotifyContent() {
t.Log(" Source type: Spotify")
} else if mostRecent.IsLocalContent() {
t.Log(" Source type: Local")
} else if mostRecent.IsStreamingContent() {
t.Log(" Source type: Streaming service")
}
}
// Test filtering methods
spotifyItems := response.GetSpotifyItems()
if len(spotifyItems) > 0 {
t.Logf("Spotify items: %d", len(spotifyItems))
for i, item := range spotifyItems {
if i < 3 { // Show first 3
t.Logf(" - %s", item.GetDisplayName())
}
}
}
localItems := response.GetLocalMusicItems()
if len(localItems) > 0 {
t.Logf("Local music items: %d", len(localItems))
}
storedItems := response.GetStoredMusicItems()
if len(storedItems) > 0 {
t.Logf("Stored music items: %d", len(storedItems))
}
tuneInItems := response.GetTuneInItems()
if len(tuneInItems) > 0 {
t.Logf("TuneIn items: %d", len(tuneInItems))
}
pandoraItems := response.GetPandoraItems()
if len(pandoraItems) > 0 {
t.Logf("Pandora items: %d", len(pandoraItems))
}
// Test content type filters
tracks := response.GetTracks()
if len(tracks) > 0 {
t.Logf("Track items: %d", len(tracks))
}
stations := response.GetStations()
if len(stations) > 0 {
t.Logf("Station items: %d", len(stations))
}
playlistsAndAlbums := response.GetPlaylistsAndAlbums()
if len(playlistsAndAlbums) > 0 {
t.Logf("Playlist/Album items: %d", len(playlistsAndAlbums))
}
presetableItems := response.GetPresetableItems()
if len(presetableItems) > 0 {
t.Logf("Presetable items: %d", len(presetableItems))
}
// Show all items with details
t.Log("\nAll recent items:")
for i, item := range response.Items {
if i >= 10 { // Limit to first 10 items to avoid spam
t.Logf(" ... and %d more items", len(response.Items)-i)
break
}
displayName := item.GetDisplayName()
source := item.GetSource()
contentType := item.GetContentType()
utcTime := item.GetUTCTime()
timeStr := ""
if utcTime > 0 {
playTime := time.Unix(utcTime, 0)
timeStr = playTime.Format("2006-01-02 15:04:05")
}
t.Logf(" %d. %s (%s/%s) - %s", i+1, displayName, source, contentType, timeStr)
if item.HasID() {
t.Logf(" ID: %s", item.GetID())
}
}
})
}
func TestClient_GetRecents_Performance(t *testing.T) {
if testing.Short() {
t.Skip("skipping performance test")
}
host := os.Getenv("SOUNDTOUCH_HOST")
if host == "" {
t.Skip("SOUNDTOUCH_HOST not set, skipping integration test")
}
config := &Config{
Host: host,
Timeout: 5 * time.Second,
}
client := NewClient(config)
// Measure response time
start := time.Now()
response, err := client.GetRecents()
duration := time.Since(start)
if err != nil {
t.Fatalf("failed to get recents: %v", err)
}
t.Logf("GetRecents() took %v", duration)
if duration > 2*time.Second {
t.Logf("Warning: GetRecents() took longer than expected: %v", duration)
}
if response != nil {
t.Logf("Retrieved %d recent items", response.GetItemCount())
}
}
func TestClient_GetRecents_ErrorConditions(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Test with invalid host
t.Run("invalid host", func(t *testing.T) {
config := &Config{
Host: "192.168.255.255", // Non-existent IP
Timeout: 2 * time.Second, // Short timeout
}
client := NewClient(config)
response, err := client.GetRecents()
if err == nil {
t.Error("expected error for invalid host, got nil")
}
if response != nil {
t.Error("expected nil response for invalid host, got non-nil")
}
t.Logf("Expected error for invalid host: %v", err)
})
// Test with very short timeout
t.Run("timeout", func(t *testing.T) {
host := os.Getenv("SOUNDTOUCH_HOST")
if host == "" {
t.Skip("SOUNDTOUCH_HOST not set")
}
config := &Config{
Host: host,
Timeout: 1 * time.Nanosecond, // Impossibly short timeout
}
client := NewClient(config)
response, err := client.GetRecents()
if err == nil {
t.Log("Warning: expected timeout error, but request succeeded")
}
if response != nil && err != nil {
t.Error("got both response and error")
}
t.Logf("Timeout test result - error: %v, response nil: %t", err, response == nil)
})
}
// ExampleClient_GetRecents demonstrates how to use the GetRecents method
func ExampleClient_GetRecents() {
config := &Config{
Host: "192.0.2.100",
Port: 8090,
}
client := NewClient(config)
// Get recent items
response, err := client.GetRecents()
if err != nil {
panic(err)
}
if response.IsEmpty() {
println("No recent items found")
return
}
// Show most recent item
mostRecent := response.GetMostRecent()
if mostRecent != nil {
println("Most recent:", mostRecent.GetDisplayName())
println("Source:", mostRecent.GetSource())
if mostRecent.IsPresetable() {
println("Can be saved as preset")
}
}
// Show Spotify items
spotifyItems := response.GetSpotifyItems()
if len(spotifyItems) > 0 {
println("Recent Spotify tracks:")
for _, item := range spotifyItems {
println("-", item.GetDisplayName())
}
}
// Show only tracks (no stations or playlists)
tracks := response.GetTracks()
println("Total tracks in recent items:", len(tracks))
}
// ExampleRecentsResponse_filtering demonstrates filtering recent items
func ExampleRecentsResponse_filtering() {
config := &Config{
Host: "192.0.2.100",
Port: 8090,
}
client := NewClient(config)
response, err := client.GetRecents()
if err != nil {
panic(err)
}
// Filter by source
println("Spotify items:", len(response.GetSpotifyItems()))
println("Local music items:", len(response.GetLocalMusicItems()))
println("TuneIn items:", len(response.GetTuneInItems()))
// Filter by type
println("Tracks:", len(response.GetTracks()))
println("Stations:", len(response.GetStations()))
println("Playlists/Albums:", len(response.GetPlaylistsAndAlbums()))
// Filter by capability
println("Presetable items:", len(response.GetPresetableItems()))
// Get items from streaming services only
streamingItems := 0
for _, item := range response.Items {
if item.IsStreamingContent() {
streamingItems++
}
}
println("Streaming service items:", streamingItems)
}