musiclink/cmd/smoketest/main.go

193 lines
4.3 KiB
Go

package main
import (
"context"
"fmt"
"os"
"time"
"musiclink/internal/detector"
"musiclink/internal/resolver"
"musiclink/internal/services"
)
func main() {
fmt.Println("=== MusicLink Smoke Test ===")
// Test 1: Detector
fmt.Println("1. Testing link detection...")
testDetector()
// Test 2: idonthavespotify API
fmt.Println("\n2. Testing idonthavespotify API...")
testAPI()
// Test 3: Full resolution
fmt.Println("\n3. Testing full resolution flow...")
testResolver()
fmt.Println("\n=== All tests passed! ===")
}
func testDetector() {
det := detector.New()
testCases := []struct {
input string
expected int
}{
{"Check this out: https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh", 1},
{"https://www.youtube.com/watch?v=dQw4w9WgXcQ", 1},
{"https://music.apple.com/us/album/some-album/123456789", 1},
{"https://www.deezer.com/track/123456", 1},
{"https://tidal.com/browse/track/12345678", 1},
{"No links here", 0},
{"Multiple: https://open.spotify.com/track/abc123 and https://youtu.be/dQw4w9WgXcQ", 2},
}
for _, tc := range testCases {
links := det.Detect(tc.input)
if len(links) != tc.expected {
fmt.Printf(" FAIL: Expected %d links, got %d for: %s\n", tc.expected, len(links), tc.input[:min(50, len(tc.input))])
os.Exit(1)
}
fmt.Printf(" OK: Found %d link(s) in: %s...\n", len(links), tc.input[:min(40, len(tc.input))])
}
}
func testAPI() {
client := services.NewClient("")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// Test with a known Spotify track
testURL := "https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh"
fmt.Printf(" Calling API with: %s\n", testURL)
resp, err := resolveWithRetry(ctx, client, testURL)
if err != nil {
fmt.Printf(" FAIL: API error: %v\n", err)
os.Exit(1)
}
fmt.Printf(" OK: Got response - Type: %s, Title: %s\n", resp.Type, resp.Title)
fmt.Printf(" OK: Found %d platform links\n", len(resp.Links))
for _, link := range resp.Links {
verified := ""
if link.IsVerified {
verified = " (verified)"
}
fmt.Printf(" - %s: %s%s\n", link.Type, link.URL[:min(50, len(link.URL))], verified)
}
}
func testResolver() {
res := resolver.New("")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
testURL := "https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh"
fmt.Printf(" Resolving: %s\n", testURL)
resolved, err := resolveResolverWithRetry(ctx, res, testURL)
if err != nil {
fmt.Printf(" FAIL: Resolver error: %v\n", err)
os.Exit(1)
}
fmt.Printf(" OK: Resolved to %d platforms\n", len(resolved.Links))
// Test formatting
title := ""
if resolved.Track != nil {
title = resolved.Track.Title
}
formatted := resolver.Format(resolved, title)
fmt.Printf("\n Formatted output:\n")
fmt.Println(" ---")
for _, line := range splitLines(formatted) {
fmt.Printf(" %s\n", line)
}
fmt.Println(" ---")
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func splitLines(s string) []string {
var lines []string
start := 0
for i, c := range s {
if c == '\n' {
lines = append(lines, s[start:i])
start = i + 1
}
}
if start < len(s) {
lines = append(lines, s[start:])
}
return lines
}
func resolveWithRetry(ctx context.Context, client *services.Client, url string) (*services.APIResponse, error) {
const maxAttempts = 3
backoff := time.Second
var lastErr error
for attempt := 1; attempt <= maxAttempts; attempt++ {
resp, err := client.Resolve(ctx, url)
if err == nil {
return resp, nil
}
lastErr = err
if attempt == maxAttempts {
break
}
if !sleepWithContext(ctx, backoff) {
return nil, ctx.Err()
}
backoff *= 2
}
return nil, lastErr
}
func resolveResolverWithRetry(ctx context.Context, res *resolver.Resolver, url string) (*services.ResolvedLinks, error) {
const maxAttempts = 3
backoff := time.Second
var lastErr error
for attempt := 1; attempt <= maxAttempts; attempt++ {
resp, err := res.Resolve(ctx, url)
if err == nil {
return resp, nil
}
lastErr = err
if attempt == maxAttempts {
break
}
if !sleepWithContext(ctx, backoff) {
return nil, ctx.Err()
}
backoff *= 2
}
return nil, lastErr
}
func sleepWithContext(ctx context.Context, delay time.Duration) bool {
timer := time.NewTimer(delay)
defer timer.Stop()
select {
case <-ctx.Done():
return false
case <-timer.C:
return true
}
}