mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Improve source sync by adding deduction of known source IDs (#167)
This commit is contained in:
@@ -37,16 +37,16 @@ func TestFetchTuneInMetadata(t *testing.T) {
|
||||
|
||||
if metadata == nil {
|
||||
t.Fatal("fetchTuneInMetadata() returned nil metadata")
|
||||
}
|
||||
} else {
|
||||
expectedName := "WDR 2 Rheinland"
|
||||
if metadata.Name != expectedName {
|
||||
t.Errorf("metadata.Name = %v, want %v", metadata.Name, expectedName)
|
||||
}
|
||||
|
||||
expectedName := "WDR 2 Rheinland"
|
||||
if metadata.Name != expectedName {
|
||||
t.Errorf("metadata.Name = %v, want %v", metadata.Name, expectedName)
|
||||
}
|
||||
|
||||
expectedArtwork := "https://cdn-radiotime-logos.tunein.com/s213886g.png"
|
||||
if metadata.Artwork != expectedArtwork {
|
||||
t.Errorf("metadata.Artwork = %v, want %v", metadata.Artwork, expectedArtwork)
|
||||
expectedArtwork := "https://cdn-radiotime-logos.tunein.com/s213886g.png"
|
||||
if metadata.Artwork != expectedArtwork {
|
||||
t.Errorf("metadata.Artwork = %v, want %v", metadata.Artwork, expectedArtwork)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,15 +192,15 @@ func TestFetchSpotifyMetadata(t *testing.T) {
|
||||
|
||||
if metadata == nil {
|
||||
t.Fatal("fetchSpotifyMetadata() returned nil metadata")
|
||||
}
|
||||
} else {
|
||||
expectedName := "Terminal Caribe - Album by Santi & Tuğçe"
|
||||
if metadata.Name != expectedName {
|
||||
t.Errorf("metadata.Name = %v, want %v", metadata.Name, expectedName)
|
||||
}
|
||||
|
||||
expectedName := "Terminal Caribe - Album by Santi & Tuğçe"
|
||||
if metadata.Name != expectedName {
|
||||
t.Errorf("metadata.Name = %v, want %v", metadata.Name, expectedName)
|
||||
}
|
||||
|
||||
expectedArtwork := "https://i.scdn.co/image/ab67616d0000b273f0e55478f4a15182405bcb47"
|
||||
if metadata.Artwork != expectedArtwork {
|
||||
t.Errorf("metadata.Artwork = %v, want %v", metadata.Artwork, expectedArtwork)
|
||||
expectedArtwork := "https://i.scdn.co/image/ab67616d0000b273f0e55478f4a15182405bcb47"
|
||||
if metadata.Artwork != expectedArtwork {
|
||||
t.Errorf("metadata.Artwork = %v, want %v", metadata.Artwork, expectedArtwork)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
@@ -1076,6 +1077,124 @@ func (ds *DataStore) RemoveDeviceDir(account, device string) error {
|
||||
return ds.RemoveDevice(account, device)
|
||||
}
|
||||
|
||||
// DeduceSourceIDs updates the source IDs in the given slice by deducing them from recents and presets.
|
||||
func (ds *DataStore) DeduceSourceIDs(account, device string, sources []models.ConfiguredSource) {
|
||||
// Deduce source IDs from recents and presets
|
||||
deducedIDs := ds.collectDeducedIDs(account, device)
|
||||
|
||||
for i := range sources {
|
||||
if id, ok := deducedIDs[sources[i].SourceProviderID]; ok {
|
||||
sources[i].ID = id
|
||||
} else if sources[i].SourceKeyType == "AUX" {
|
||||
if id, ok := deducedIDs["9"]; ok {
|
||||
sources[i].ID = id
|
||||
sources[i].SourceProviderID = "9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DataStore) collectDeducedIDs(account, device string) map[string]string {
|
||||
deducedIDs := make(map[string]string)
|
||||
|
||||
// Check recents and presets to find source IDs for provider IDs 2, 9, 11, 25
|
||||
for _, filename := range []string{constants.RecentsFile, constants.PresetsFile} {
|
||||
fileContent, err := os.ReadFile(filepath.Join(ds.AccountDeviceDir(account, device), filename))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ds.parseIDsFromFile(fileContent, deducedIDs)
|
||||
}
|
||||
|
||||
return deducedIDs
|
||||
}
|
||||
|
||||
func (ds *DataStore) parseIDsFromFile(fileContent []byte, deducedIDs map[string]string) {
|
||||
decoder := xml.NewDecoder(bytes.NewReader(fileContent))
|
||||
for {
|
||||
token, _ := decoder.Token()
|
||||
if token == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if se, ok := token.(xml.StartElement); ok {
|
||||
switch se.Name.Local {
|
||||
case "source":
|
||||
ds.parseSourceElement(decoder, &se, deducedIDs)
|
||||
case "recent", "preset":
|
||||
ds.parseRecentPresetElement(decoder, &se, deducedIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DataStore) parseSourceElement(decoder *xml.Decoder, se *xml.StartElement, deducedIDs map[string]string) {
|
||||
var s struct {
|
||||
ID string `xml:"id,attr"`
|
||||
SourceProviderID string `xml:"sourceproviderid"`
|
||||
// Also check for sourceproviderid as attribute just in case
|
||||
SourceProviderIDAttr string `xml:"sourceproviderid,attr"`
|
||||
}
|
||||
if err := decoder.DecodeElement(&s, se); err == nil {
|
||||
pid := s.SourceProviderID
|
||||
if pid == "" {
|
||||
pid = s.SourceProviderIDAttr
|
||||
}
|
||||
|
||||
ds.extractIDs(pid, s.ID, deducedIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DataStore) parseRecentPresetElement(decoder *xml.Decoder, se *xml.StartElement, deducedIDs map[string]string) {
|
||||
var s struct {
|
||||
SourceID string `xml:"sourceid"`
|
||||
SourceProviderID string `xml:"sourceproviderid"`
|
||||
ContentItem struct {
|
||||
Source string `xml:"source,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
} `xml:"contentItem"`
|
||||
Source struct {
|
||||
SourceProviderID string `xml:"sourceproviderid"`
|
||||
} `xml:"source"`
|
||||
}
|
||||
if err := decoder.DecodeElement(&s, se); err == nil {
|
||||
pid := s.SourceProviderID
|
||||
if pid == "" {
|
||||
pid = s.Source.SourceProviderID
|
||||
}
|
||||
|
||||
if pid == "" {
|
||||
// For AUX, we often don't have provider ID 9 but we know its name/source
|
||||
switch s.ContentItem.Source {
|
||||
case "AUX":
|
||||
pid = "9"
|
||||
case "INTERNET_RADIO":
|
||||
pid = "2"
|
||||
case "LOCAL_INTERNET_RADIO":
|
||||
pid = "11"
|
||||
case "TUNEIN":
|
||||
pid = "25"
|
||||
}
|
||||
}
|
||||
|
||||
ds.extractIDs(pid, s.SourceID, deducedIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DataStore) extractIDs(providerID, sourceID string, deducedIDs map[string]string) {
|
||||
if sourceID == "" || providerID == "" {
|
||||
return
|
||||
}
|
||||
// Stick to the provider ids mentioned: 2, 9, 11, 25
|
||||
switch providerID {
|
||||
case "2", "9", "11", "25":
|
||||
if _, exists := deducedIDs[providerID]; !exists {
|
||||
deducedIDs[providerID] = sourceID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfiguredSources retrieves all configured sources for the specified account and device.
|
||||
func (ds *DataStore) GetConfiguredSources(account, device string) ([]models.ConfiguredSource, error) {
|
||||
ds.fileMutex.RLock()
|
||||
@@ -1086,7 +1205,10 @@ func (ds *DataStore) GetConfiguredSources(account, device string) ([]models.Conf
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return ds.getDefaultSources(), nil
|
||||
sources := ds.getDefaultSources()
|
||||
ds.DeduceSourceIDs(account, device, sources)
|
||||
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
@@ -1139,9 +1261,6 @@ func (ds *DataStore) GetConfiguredSources(account, device string) ([]models.Conf
|
||||
if ps.Credential.Value != "" {
|
||||
s.Secret = ps.Credential.Value
|
||||
s.SecretType = ps.Credential.Type
|
||||
} else {
|
||||
s.Secret = ps.Secret
|
||||
s.SecretType = ps.SecretType
|
||||
}
|
||||
|
||||
// Ensure Secret/SecretType values are prioritized from legacy fields if still missing
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetConfiguredSources_DeduceIDs(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "datastore-test-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
ds := NewDataStore(tempDir)
|
||||
account := "test-account"
|
||||
device := "test-device"
|
||||
|
||||
// Create recents with specific source IDs for provider IDs
|
||||
// Let's create a manual Recents.xml and Presets.xml in the temp directory to simulate the state.
|
||||
deviceDir := ds.AccountDeviceDir(account, device)
|
||||
if err := os.MkdirAll(deviceDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create device dir: %v", err)
|
||||
}
|
||||
|
||||
recentsXML := `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<recents>
|
||||
<recent id="2184615630">
|
||||
<contentItemType></contentItemType>
|
||||
<createdOn>2017-02-07T11:22:00.000+00:00</createdOn>
|
||||
<lastplayedat>2017-05-17T13:18:57.000+00:00</lastplayedat>
|
||||
<location>52349</location>
|
||||
<name>Lounge FM Digital</name>
|
||||
<source id="9330201" type="Audio">
|
||||
<createdOn>2015-03-11T19:12:38.000+00:00</createdOn>
|
||||
<credential type="token"></credential>
|
||||
<name>9330201</name>
|
||||
<sourceproviderid>2</sourceproviderid>
|
||||
<sourcename></sourcename>
|
||||
<sourceSettings/>
|
||||
<updatedOn>2015-03-11T19:12:38.000+00:00</updatedOn>
|
||||
<username></username>
|
||||
</source>
|
||||
<sourceid>9330201</sourceid>
|
||||
<updatedOn>2017-05-17T17:18:58.000+00:00</updatedOn>
|
||||
<username>Lounge FM Digital</username>
|
||||
</recent>
|
||||
</recents>`
|
||||
|
||||
if err := os.WriteFile(filepath.Join(deviceDir, "Recents.xml"), []byte(recentsXML), 0644); err != nil {
|
||||
t.Fatalf("Failed to write Recents.xml: %v", err)
|
||||
}
|
||||
|
||||
// Now call GetConfiguredSources and expect it to have "9330201" for provider ID "2"
|
||||
sources, err := ds.GetConfiguredSources(account, device)
|
||||
if err != nil {
|
||||
t.Fatalf("GetConfiguredSources failed: %v", err)
|
||||
}
|
||||
|
||||
foundDeducted := false
|
||||
for _, s := range sources {
|
||||
if s.SourceProviderID == "2" {
|
||||
if s.ID == "9330201" {
|
||||
foundDeducted = true
|
||||
} else {
|
||||
t.Errorf("Expected source ID 9330201 for provider 2, got %s", s.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !foundDeducted {
|
||||
t.Errorf("Did not find source with provider ID 2 and deducted ID 9330201")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfiguredSources_DeduceIDs_AllProviders(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "datastore-test-all-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
ds := NewDataStore(tempDir)
|
||||
account := "test-account"
|
||||
device := "test-device"
|
||||
|
||||
deviceDir := ds.AccountDeviceDir(account, device)
|
||||
if err := os.MkdirAll(deviceDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create device dir: %v", err)
|
||||
}
|
||||
|
||||
// 2: INTERNET_RADIO
|
||||
// 9: AUX
|
||||
// 11: LOCAL_INTERNET_RADIO
|
||||
// 25: TUNEIN
|
||||
presetsXML := `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<presets>
|
||||
<preset id="1">
|
||||
<contentItem source="INTERNET_RADIO" sourceAccount="" isPresetable="true" type="station" itemName="Station 2">
|
||||
<containerArt>http://example.com/art2.png</containerArt>
|
||||
</contentItem>
|
||||
<source id="ID2" type="Audio" sourceproviderid="2" />
|
||||
<sourceid>ID2</sourceid>
|
||||
</preset>
|
||||
<preset id="2">
|
||||
<contentItem source="AUX" sourceAccount="AUX" isPresetable="true" type="station" itemName="Station 9">
|
||||
<containerArt>http://example.com/art9.png</containerArt>
|
||||
</contentItem>
|
||||
<source id="ID9" type="Audio" sourceproviderid="9" />
|
||||
<sourceid>ID9</sourceid>
|
||||
</preset>
|
||||
<preset id="3">
|
||||
<contentItem source="LOCAL_INTERNET_RADIO" sourceAccount="" isPresetable="true" type="station" itemName="Station 11">
|
||||
<containerArt>http://example.com/art11.png</containerArt>
|
||||
</contentItem>
|
||||
<source id="ID11" type="Audio" sourceproviderid="11" />
|
||||
<sourceid>ID11</sourceid>
|
||||
</preset>
|
||||
<preset id="4">
|
||||
<contentItem source="TUNEIN" sourceAccount="" isPresetable="true" type="station" itemName="Station 25">
|
||||
<containerArt>http://example.com/art25.png</containerArt>
|
||||
</contentItem>
|
||||
<source id="ID25" type="Audio" sourceproviderid="25" />
|
||||
<sourceid>ID25</sourceid>
|
||||
</preset>
|
||||
</presets>`
|
||||
|
||||
if err := os.WriteFile(filepath.Join(deviceDir, "Presets.xml"), []byte(presetsXML), 0644); err != nil {
|
||||
t.Fatalf("Failed to write Presets.xml: %v", err)
|
||||
}
|
||||
|
||||
sources, err := ds.GetConfiguredSources(account, device)
|
||||
if err != nil {
|
||||
t.Fatalf("GetConfiguredSources failed: %v", err)
|
||||
}
|
||||
|
||||
expected := map[string]string{
|
||||
"2": "ID2",
|
||||
"9": "ID9",
|
||||
"11": "ID11",
|
||||
"25": "ID25",
|
||||
}
|
||||
|
||||
found := make(map[string]bool)
|
||||
for _, s := range sources {
|
||||
if expID, ok := expected[s.SourceProviderID]; ok {
|
||||
if s.ID != expID {
|
||||
t.Errorf("Expected source ID %s for provider %s, got %s", expID, s.SourceProviderID, s.ID)
|
||||
}
|
||||
found[s.SourceProviderID] = true
|
||||
} else if s.SourceKeyType == "AUX" && s.SourceProviderID == "" {
|
||||
// Special case for AUX if it doesn't have provider ID 9 by default
|
||||
if expID, ok := expected["9"]; ok {
|
||||
if s.ID != expID {
|
||||
t.Errorf("Expected source ID %s for AUX, got %s", expID, s.ID)
|
||||
}
|
||||
found["9"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for pid := range expected {
|
||||
if !found[pid] {
|
||||
t.Errorf("Did not find source with provider ID %s", pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,17 +394,17 @@ func TestHandleMgmtAccountDetails_Sources(t *testing.T) {
|
||||
|
||||
if gesellixSource == nil {
|
||||
t.Fatal("gesellix source not found")
|
||||
}
|
||||
|
||||
// It should have fallen back to Account name "gesellix" because DisplayName was generic "Audio"
|
||||
if gesellixSource.DisplayName != "gesellix" {
|
||||
t.Errorf("Expected display_name 'gesellix', got '%s'", gesellixSource.DisplayName)
|
||||
}
|
||||
if gesellixSource.Name != "gesellix" {
|
||||
t.Errorf("Expected name 'gesellix', got '%s'", gesellixSource.Name)
|
||||
}
|
||||
if gesellixSource.Type != "Audio" {
|
||||
t.Errorf("Expected type 'Audio', got '%s'", gesellixSource.Type)
|
||||
} else {
|
||||
// It should have fallen back to Account name "gesellix" because DisplayName was generic "Audio"
|
||||
if gesellixSource.DisplayName != "gesellix" {
|
||||
t.Errorf("Expected display_name 'gesellix', got '%s'", gesellixSource.DisplayName)
|
||||
}
|
||||
if gesellixSource.Name != "gesellix" {
|
||||
t.Errorf("Expected name 'gesellix', got '%s'", gesellixSource.Name)
|
||||
}
|
||||
if gesellixSource.Type != "Audio" {
|
||||
t.Errorf("Expected type 'Audio', got '%s'", gesellixSource.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// Find the generic audio source
|
||||
@@ -417,9 +417,10 @@ func TestHandleMgmtAccountDetails_Sources(t *testing.T) {
|
||||
}
|
||||
if audioSource == nil {
|
||||
t.Fatal("audio source not found")
|
||||
}
|
||||
// It should still be "Audio" as there is no account fallback
|
||||
if audioSource.DisplayName != "Audio" {
|
||||
t.Errorf("Expected display_name 'Audio', got '%s'", audioSource.DisplayName)
|
||||
} else {
|
||||
// It should still be "Audio" as there is no account fallback
|
||||
if audioSource.DisplayName != "Audio" {
|
||||
t.Errorf("Expected display_name 'Audio', got '%s'", audioSource.DisplayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,14 @@ func SyncFromAccountFull(ds *datastore.DataStore, resp *models.AccountFullRespon
|
||||
// 1. Update Device Info
|
||||
syncDeviceInfo(ds, accountID, dev)
|
||||
|
||||
// 2. Update Configured Sources for this device
|
||||
syncConfiguredSources(ds, accountID, deviceID, resp.Sources, dev)
|
||||
|
||||
// 3. Update Presets
|
||||
// 2. Update Presets
|
||||
syncPresets(ds, accountID, deviceID, dev.Presets)
|
||||
|
||||
// 4. Update Recents
|
||||
// 3. Update Recents
|
||||
syncRecents(ds, accountID, deviceID, dev.Recents)
|
||||
|
||||
// 4. Update Configured Sources for this device (requires presets and recents to be on disk for deduction)
|
||||
syncConfiguredSources(ds, accountID, deviceID, resp.Sources, dev)
|
||||
}
|
||||
|
||||
log.Printf("[SYNC] Synchronization completed for account %s", accountID)
|
||||
@@ -166,6 +166,9 @@ func syncConfiguredSources(ds *datastore.DataStore, accountID, deviceID string,
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Add deduction based on local presets/recents
|
||||
ds.DeduceSourceIDs(accountID, deviceID, deviceSources)
|
||||
|
||||
if err := ds.SaveConfiguredSources(accountID, deviceID, deviceSources); err != nil {
|
||||
log.Printf("[SYNC_ERR] Failed to save sources for %s: %v", deviceID, err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package marge
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gesellix/bose-soundtouch/pkg/models"
|
||||
"github.com/gesellix/bose-soundtouch/pkg/service/datastore"
|
||||
)
|
||||
|
||||
func TestSyncFromAccountFull_DeduceIDs(t *testing.T) {
|
||||
// Setup a temporary datastore
|
||||
tmpDir, err := os.MkdirTemp("", "sync_deduce_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
ds := datastore.NewDataStore(tmpDir)
|
||||
accountID := "USER_123"
|
||||
deviceID := "DEVICE_ABC"
|
||||
|
||||
// Mock AccountFullResponse with generic source IDs (e.g., from a fresh sync or default mapping)
|
||||
// and specific source IDs in presets/recents that we want to "deduce" and use.
|
||||
xmlData := `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<account id="USER_123">
|
||||
<devices>
|
||||
<device deviceid="DEVICE_ABC">
|
||||
<presets>
|
||||
<preset buttonNumber="1">
|
||||
<contentItem itemName="Lounge FM Digital" location="52349" source="INTERNET_RADIO" type="station" />
|
||||
<source id="9330201" type="Audio">
|
||||
<sourceproviderid>2</sourceproviderid>
|
||||
</source>
|
||||
<sourceid>9330201</sourceid>
|
||||
</preset>
|
||||
</presets>
|
||||
<recents>
|
||||
<recent id="RECENT_1">
|
||||
<contentItem itemName="TuneIn Station" source="TUNEIN" type="station" />
|
||||
<source id="DEDUCED_TUNEIN" type="Audio">
|
||||
<sourceproviderid>25</sourceproviderid>
|
||||
</source>
|
||||
<sourceid>DEDUCED_TUNEIN</sourceid>
|
||||
</recent>
|
||||
</recents>
|
||||
</device>
|
||||
</devices>
|
||||
<sources>
|
||||
<source id="GENERIC_2" type="Audio" sourceproviderid="2" />
|
||||
<source id="GENERIC_25" type="Audio" sourceproviderid="25" />
|
||||
</sources>
|
||||
</account>`
|
||||
|
||||
var resp models.AccountFullResponse
|
||||
if err := xml.Unmarshal([]byte(xmlData), &resp); err != nil {
|
||||
t.Fatalf("Failed to unmarshal mock data: %v", err)
|
||||
}
|
||||
|
||||
// Run Sync
|
||||
if err := SyncFromAccountFull(ds, &resp); err != nil {
|
||||
t.Fatalf("SyncFromAccountFull failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify Sources
|
||||
sources, err := ds.GetConfiguredSources(accountID, deviceID)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get sources: %v", err)
|
||||
}
|
||||
|
||||
found2 := false
|
||||
found25 := false
|
||||
for _, s := range sources {
|
||||
if s.SourceProviderID == "2" {
|
||||
if s.ID == "9330201" {
|
||||
found2 = true
|
||||
} else {
|
||||
t.Errorf("Expected source ID 9330201 for provider 2, got %s", s.ID)
|
||||
}
|
||||
}
|
||||
if s.SourceProviderID == "25" {
|
||||
if s.ID == "DEDUCED_TUNEIN" {
|
||||
found25 = true
|
||||
} else {
|
||||
t.Errorf("Expected source ID DEDUCED_TUNEIN for provider 25, got %s", s.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found2 {
|
||||
t.Errorf("Did not find source with provider ID 2 and deducted ID 9330201")
|
||||
}
|
||||
if !found25 {
|
||||
t.Errorf("Did not find source with provider ID 25 and deducted ID DEDUCED_TUNEIN")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user