mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
Major Features: • Implement complete /requestToken API endpoint for bearer token generation • Fix clock time parsing and display with comprehensive time information • Add comprehensive API documentation for 103 discovered endpoints /requestToken Implementation: • Add BearerToken model with full XML marshaling support • Add RequestToken() client method with proper error handling • Add 'soundtouch-cli token request' CLI command with security features • Token validation, formatting, and secure display (truncated for security) • Comprehensive unit tests and integration tests • Support for Authorization header formatting and raw token extraction Clock Time Fixes: • Fix ClockTime model to match actual device XML response structure • Add LocalTime component for nested time details • Support for utcTime, timeFormat, brightness, clockError attributes • Enhanced CLI display with comprehensive time information • Fixed month conversion (device uses 0-11, Go uses 1-12) Documentation Enhancements: • Add comprehensive /supportedURLs endpoint analysis (103 endpoints discovered) • Create detailed unimplemented endpoints documentation with examples • Update API coverage from 34% implemented to full endpoint catalog • Add SoundTouch End of Life notice with May 6, 2026 details • Enhanced endpoint descriptions with real device response examples Security: • All tests use generic token examples (no real tokens exposed) • Integration tests validate token properties without exposing values • Secure token display with truncation in CLI and string representations • Environment variable based testing for real devices Testing: • 15+ new test functions with comprehensive coverage • Real device validation on 192.168.178.28 and 192.168.178.35 • Mock server tests and XML marshaling validation • Integration tests with SOUNDTOUCH_TEST_HOST environment variable CLI Enhancements: • Enhanced clock time display with local time details and device settings • New token management commands with usage instructions • Improved error handling and user-friendly output formatting
96 lines
2.8 KiB
Go
96 lines
2.8 KiB
Go
package client
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestRequestToken_Integration tests the RequestToken method against a real device
|
|
// This test only runs when SOUNDTOUCH_TEST_HOST environment variable is set
|
|
func TestRequestToken_Integration(t *testing.T) {
|
|
host := os.Getenv("SOUNDTOUCH_TEST_HOST")
|
|
if host == "" {
|
|
t.Skip("Skipping integration test: SOUNDTOUCH_TEST_HOST not set")
|
|
}
|
|
|
|
// Create client for real device
|
|
config := &Config{
|
|
Host: host,
|
|
Port: 8090,
|
|
}
|
|
client := NewClient(config)
|
|
|
|
// Test RequestToken with real device
|
|
token, err := client.RequestToken()
|
|
if err != nil {
|
|
t.Fatalf("RequestToken() failed with real device: %v", err)
|
|
}
|
|
|
|
if token == nil {
|
|
t.Fatal("RequestToken() returned nil token from real device")
|
|
}
|
|
|
|
// Validate token properties without exposing actual values
|
|
tokenValue := token.GetToken()
|
|
|
|
// Token should have Bearer prefix
|
|
if !strings.HasPrefix(tokenValue, "Bearer ") {
|
|
t.Error("Real device token should have 'Bearer ' prefix")
|
|
}
|
|
|
|
// Token should be valid according to our validation
|
|
if !token.IsValid() {
|
|
t.Error("Real device token should be valid")
|
|
}
|
|
|
|
// Raw token should not include Bearer prefix
|
|
rawToken := token.GetTokenWithoutPrefix()
|
|
if strings.HasPrefix(rawToken, "Bearer ") {
|
|
t.Error("Raw token should not include Bearer prefix")
|
|
}
|
|
|
|
// Token should be reasonably long (real bearer tokens are substantial)
|
|
if len(rawToken) < 80 {
|
|
t.Errorf("Real device token seems too short: %d characters", len(rawToken))
|
|
}
|
|
|
|
// Token should only contain base64-like characters plus common token chars
|
|
validChars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
|
for _, char := range rawToken {
|
|
if !strings.ContainsRune(validChars, char) {
|
|
t.Errorf("Token contains unexpected character: %c", char)
|
|
}
|
|
}
|
|
|
|
// Auth header should match full token value
|
|
if token.GetAuthHeader() != tokenValue {
|
|
t.Error("Auth header should match full token value")
|
|
}
|
|
|
|
// String representation should be truncated for security
|
|
stringRepr := token.String()
|
|
if len(stringRepr) >= len(tokenValue) {
|
|
t.Error("String representation should be shorter than full token for security")
|
|
}
|
|
|
|
// String representation should contain "..." for long tokens
|
|
if !strings.Contains(stringRepr, "...") {
|
|
t.Error("String representation should contain '...' for long tokens")
|
|
}
|
|
|
|
// Multiple calls should generate different tokens (if the device supports it)
|
|
token2, err := client.RequestToken()
|
|
if err != nil {
|
|
t.Fatalf("Second RequestToken() call failed: %v", err)
|
|
}
|
|
|
|
// Note: Some devices may return the same token, so we don't enforce uniqueness
|
|
// but we do verify the second token is also valid
|
|
if !token2.IsValid() {
|
|
t.Error("Second token should also be valid")
|
|
}
|
|
|
|
t.Logf("Successfully validated real device token properties (length: %d chars)", len(rawToken))
|
|
}
|