mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 00:56:16 +00:00
The integration suite flaked in CI: with three `go run` mocks now compiling concurrently, the spotify/amazon mocks weren't listening within the fixed `sleep 10`, so the registration requests at the start of the suite hit a connection-refused and the "Account exists" assertions (and the cascading amazon oauth token test) failed. Locally it passed because the mock builds were warm. Replace the fixed sleep with real readiness gating: - Add a /healthz endpoint to the spotify, amazon and tunein mocks. - Give all four CI services (the three mocks + soundtouch-service) a compose healthcheck (busybox wget; all images are alpine-based), and make the service depend_on the mocks being service_healthy. - `docker compose up -d --build --wait` blocks until everything is healthy, so the JetBrains client only runs against a fully-ready stack. Also clear the two semgrep advisories on the new TuneIn mock: - cmd/mock-*: annotate the intentional plaintext ListenAndServe with nosemgrep (throwaway loopback/CI test servers, never production). - pkg/testutils/tunein: sanitize the query-supplied guide id to a safe charset before interpolating it into the JSON/XML response (raw-html-format). make test-http-client: 73 requests, 0 failed (clean testdata, healthcheck-gated). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
// Package spotify provides shared handlers for mocking the Spotify API.
|
|
package spotify
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
// NewSpotifyHandler returns a new http.Handler configured with Spotify mock endpoints.
|
|
func NewSpotifyHandler() http.Handler {
|
|
mux := http.NewServeMux()
|
|
|
|
// OAuth Token Endpoint
|
|
mux.HandleFunc("/api/token", HandleToken)
|
|
|
|
// User Profile Endpoint
|
|
mux.HandleFunc("/v1/me", HandleMe)
|
|
mux.HandleFunc("/me", HandleMe)
|
|
|
|
// Readiness probe (used by the CI compose healthcheck)
|
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })
|
|
|
|
return mux
|
|
}
|
|
|
|
// HandleToken simulates the Spotify OAuth token endpoint.
|
|
func HandleToken(w http.ResponseWriter, r *http.Request) {
|
|
log.Printf("[Spotify Mock] Token request: %s", sanitizeLog(r.Method))
|
|
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Bad request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
grantType := r.FormValue("grant_type")
|
|
log.Printf("[Spotify Mock] Grant type: %s", sanitizeLog(grantType))
|
|
|
|
resp := map[string]interface{}{
|
|
"access_token": "spotify-access-token",
|
|
"token_type": "Bearer",
|
|
"expires_in": 3600,
|
|
"refresh_token": "spotify-refresh-token",
|
|
"scope": "user-read-private user-read-email",
|
|
}
|
|
|
|
switch grantType {
|
|
case "authorization_code":
|
|
code := r.FormValue("code")
|
|
if code == "" {
|
|
http.Error(w, `{"error":"invalid_grant"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
case "refresh_token":
|
|
refreshToken := r.FormValue("refresh_token")
|
|
if refreshToken == "" {
|
|
http.Error(w, `{"error":"invalid_grant"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
default:
|
|
http.Error(w, `{"error":"unsupported_grant_type"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
log.Printf("Error encoding token response: %v", err)
|
|
}
|
|
}
|
|
|
|
// HandleMe simulates the Spotify user profile endpoint.
|
|
func HandleMe(w http.ResponseWriter, r *http.Request) {
|
|
log.Printf("[Spotify Mock] Profile request: %s", sanitizeLog(r.Method))
|
|
|
|
auth := r.Header.Get("Authorization")
|
|
if auth != "Bearer spotify-access-token" {
|
|
http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
resp := map[string]interface{}{
|
|
"id": "spotify-user-id",
|
|
"display_name": "Spotify Test User",
|
|
"email": "spotify-test@example.com",
|
|
"uri": "spotify:user:spotify-user-id",
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
log.Printf("Error encoding profile response: %v", err)
|
|
}
|
|
}
|