mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 17:16:16 +00:00
- Implement full SoundTouch app flow for Spotify registration in the Web UI. - Update `/mgmt/spotify/init` to pass `accountID` via OAuth `state`. - Add "Connect Spotify" button to Local Account tab in Web UI with polling. - Implement legacy and Marge-sync fallbacks for speaker notifications (Error 1029). - Add support for parsing multi-error XML responses (`<errors>`) from speakers. - Add `NotifySourcesUpdated` to client for triggering manual source synchronization. - Improve test coverage for error parsing and Spotify initialization handlers. Co-authored-by: Junie <junie@jetbrains.com>
136 lines
3.7 KiB
Go
136 lines
3.7 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/models"
|
|
)
|
|
|
|
func TestClient_Post_ErrorsResponse(t *testing.T) {
|
|
// Mock speaker error response
|
|
errorXML := `<?xml version="1.0" encoding="UTF-8" ?>
|
|
<errors deviceID="08DF1F0BA325">
|
|
<error value="1029" name="UNKNOWN_ACTION_ERROR" severity="Unknown">This version of SCM does not support spotify create account functionality.</error>
|
|
</errors>`
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/xml")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
_, _ = w.Write([]byte(errorXML))
|
|
}))
|
|
defer server.Close()
|
|
|
|
c := createTestClient(server.URL)
|
|
|
|
// Test post method
|
|
err := c.post("/test", nil)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
|
|
errs := &models.ErrorsResponse{}
|
|
ok := errors.As(err, &errs)
|
|
if !ok {
|
|
t.Fatalf("expected models.ErrorsResponse, got %T: %v", err, err)
|
|
}
|
|
|
|
if errs.DeviceID != "08DF1F0BA325" {
|
|
t.Errorf("expected DeviceID 08DF1F0BA325, got %s", errs.DeviceID)
|
|
}
|
|
|
|
if len(errs.Errors) != 1 {
|
|
t.Fatalf("expected 1 error, got %d", len(errs.Errors))
|
|
}
|
|
|
|
if errs.Errors[0].Value != 1029 {
|
|
t.Errorf("expected error value 1029, got %d", errs.Errors[0].Value)
|
|
}
|
|
|
|
if errs.Errors[0].Name != "UNKNOWN_ACTION_ERROR" {
|
|
t.Errorf("expected error name UNKNOWN_ACTION_ERROR, got %s", errs.Errors[0].Name)
|
|
}
|
|
|
|
expectedMsg := "This version of SCM does not support spotify create account functionality."
|
|
if errs.Errors[0].Message != expectedMsg {
|
|
t.Errorf("expected message '%s', got '%s'", expectedMsg, errs.Errors[0].Message)
|
|
}
|
|
|
|
if err.Error() != expectedMsg {
|
|
t.Errorf("expected Error() to return '%s', got '%s'", expectedMsg, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestClient_PostWithResponse_ErrorsResponse(t *testing.T) {
|
|
// Mock speaker error response
|
|
errorXML := `<?xml version="1.0" encoding="UTF-8" ?>
|
|
<errors deviceID="08DF1F0BA325">
|
|
<error value="1029" name="UNKNOWN_ACTION_ERROR" severity="Unknown">This version of SCM does not support spotify create account functionality.</error>
|
|
</errors>`
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/xml")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
_, _ = w.Write([]byte(errorXML))
|
|
}))
|
|
defer server.Close()
|
|
|
|
c := createTestClient(server.URL)
|
|
|
|
// Test postWithResponse method
|
|
var result struct {
|
|
XMLName xml.Name `xml:"status"`
|
|
Data string `xml:",chardata"`
|
|
}
|
|
err := c.postWithResponse("/test", nil, &result)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
|
|
errs := &models.ErrorsResponse{}
|
|
ok := errors.As(err, &errs)
|
|
if !ok {
|
|
t.Fatalf("expected models.ErrorsResponse, got %T: %v", err, err)
|
|
}
|
|
|
|
if errs.Errors[0].Value != 1029 {
|
|
t.Errorf("expected error value 1029, got %d", errs.Errors[0].Value)
|
|
}
|
|
}
|
|
|
|
func TestClient_Post_StandardAPIError(t *testing.T) {
|
|
// Mock standard API error response
|
|
errorXML := `<?xml version="1.0" encoding="UTF-8"?><error code="404">Not Found</error>`
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/xml")
|
|
w.WriteHeader(http.StatusNotFound)
|
|
_, _ = w.Write([]byte(errorXML))
|
|
}))
|
|
defer server.Close()
|
|
|
|
c := createTestClient(server.URL)
|
|
|
|
err := c.post("/test", nil)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
|
|
apiErr := &models.APIError{}
|
|
ok := errors.As(err, &apiErr)
|
|
if !ok {
|
|
t.Fatalf("expected models.APIError, got %T: %v", err, err)
|
|
}
|
|
|
|
if apiErr.Code != 404 {
|
|
t.Errorf("expected code 404, got %d", apiErr.Code)
|
|
}
|
|
|
|
if apiErr.Message != "Not Found" {
|
|
t.Errorf("expected message 'Not Found', got '%s'", apiErr.Message)
|
|
}
|
|
}
|