Files
Bose-SoundTouch/pkg/service/handlers/server_merge_test.go
T
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

131 lines
3.3 KiB
Go

package handlers
import (
"os"
"testing"
"github.com/gesellix/bose-soundtouch/pkg/models"
"github.com/gesellix/bose-soundtouch/pkg/service/datastore"
)
func TestMergeOverlappingDevices(t *testing.T) {
tempDir, err := os.MkdirTemp("", "merge-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
ds := datastore.NewDataStore(tempDir)
s := NewServer(ds, nil, "http://localhost", false, false, false)
// Case 1: IP-only entry and Serial-based entry for the same IP
ip := "192.0.2.100"
serial := "SERIAL123"
// 1. Save IP-based entry
infoIP := &models.ServiceDeviceInfo{
DeviceID: ip,
Name: "Speaker IP",
IPAddress: ip,
AccountID: "default",
ProductCode: "ST10",
}
err = ds.SaveDeviceInfo("default", ip, infoIP)
if err != nil {
t.Fatalf("Failed to save IP info: %v", err)
}
// 2. Save Serial-based entry
infoSerial := &models.ServiceDeviceInfo{
DeviceID: serial,
DeviceSerialNumber: serial,
Name: "Speaker Serial",
IPAddress: ip,
AccountID: "default",
ProductCode: "ST10",
}
err = ds.SaveDeviceInfo("default", serial, infoSerial)
if err != nil {
t.Fatalf("Failed to save Serial info: %v", err)
}
// Verify both exist
devices, _ := ds.ListAllDevices()
if len(devices) != 2 {
t.Fatalf("Expected 2 devices before merge, got %d", len(devices))
}
// Run merge
s.mergeOverlappingDevices()
// Verify merge
devices, _ = ds.ListAllDevices()
if len(devices) != 1 {
t.Fatalf("Expected 1 device after merge, got %d", len(devices))
}
if devices[0].DeviceID != serial {
t.Errorf("Expected remaining device to be Serial-based (%s), got %s", serial, devices[0].DeviceID)
}
}
func TestFindExistingDeviceID(t *testing.T) {
tempDir, _ := os.MkdirTemp("", "find-test-*")
defer os.RemoveAll(tempDir)
ds := datastore.NewDataStore(tempDir)
s := NewServer(ds, nil, "http://localhost", false, false, false)
ip := "192.0.2.101"
serial := "SERIAL456"
// Save IP-based
ds.SaveDeviceInfo("default", ip, &models.ServiceDeviceInfo{
DeviceID: ip,
IPAddress: ip,
Name: "IP Speaker",
AccountID: "default",
ProductCode: "ST10",
})
// Test finding by IP
foundID := s.findExistingDeviceID(models.DiscoveredDevice{
Host: ip,
})
if foundID != ip {
t.Errorf("Expected to find by IP, got %s", foundID)
}
// Save Serial-based for SAME IP
ds.SaveDeviceInfo("default", serial, &models.ServiceDeviceInfo{
DeviceID: serial,
DeviceSerialNumber: serial,
IPAddress: ip,
Name: "Serial Speaker",
AccountID: "default",
ProductCode: "ST10",
})
// Test finding by IP should now return Serial (if Serial is known)
// Actually findExistingDeviceID returns the first match it finds in allDevices.
// Since we haven't merged yet, it could be either.
// Test finding by Serial
foundID = s.findExistingDeviceID(models.DiscoveredDevice{
Host: ip,
SerialNo: serial,
})
if foundID != serial && foundID != ip {
t.Errorf("Expected to find by Serial or IP, got %s", foundID)
}
// Merge and check again
s.mergeOverlappingDevices()
foundID = s.findExistingDeviceID(models.DiscoveredDevice{
Host: ip,
})
if foundID != serial {
t.Errorf("After merge, expected to find Serial ID for IP, got %s", foundID)
}
}