Files
pipu-music/services/api/internal/musicbrainz/client_test.go
T
mrleo1nid 39bf7d4b70
ci / module boundaries / boundaries (push) Successful in 10s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m30s
ci / api / api (push) Successful in 58s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m1s
ci / db / db (push) Failing after 25s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m36s
ci / ts / ts (packages + web) (push) Failing after 6m3s
feat(uploads): match release groups with MusicBrainz and AcoustID
2026-10-29 20:44:59 +03:00

123 lines
4.5 KiB
Go

package musicbrainz
import (
"context"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
)
type memoryCache map[string][]byte
func (m memoryCache) GetMetadataCache(_ context.Context, key string) ([]byte, bool, error) {
b, ok := m[key]
return b, ok, nil
}
func (m memoryCache) PutMetadataCache(_ context.Context, key string, b []byte, _ time.Duration) error {
m[key] = b
return nil
}
func TestLookupParsesEditionTracksAndCachesRequests(t *testing.T) {
id := uuid.NewString()
requests := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requests++
require.Equal(t, "PipuTest/1 (test@example.org)", r.UserAgent())
w.Header().Set("Content-Type", "application/json")
if r.URL.Path == "/release" {
require.Contains(t, r.URL.Query().Get("query"), `release:"Album"`)
_, _ = w.Write([]byte(`{"releases":[{"id":"` + id + `"}]}`))
return
}
require.Equal(t, "recordings+artist-credits+release-groups", r.URL.Query().Get("inc"))
_, _ = w.Write([]byte(`{"id":"` + id + `","title":"Album","date":"2024-01-01","country":"XE","artist-credit":[{"name":"Artist"}],"release-group":{"id":"` + uuid.NewString() + `","primary-type":"Single"},"media":[{"position":1,"tracks":[{"position":1,"recording":{"id":"recording","title":"Song","length":180000}}]}]}`))
}))
defer server.Close()
c := New(memoryCache{}, "PipuTest/1 (test@example.org)")
c.base = server.URL
c.interval = 0
for range 2 {
result, err := c.Search(context.Background(), Query{Artist: "Artist", Album: "Album"})
require.NoError(t, err)
require.Len(t, result, 1)
require.Equal(t, "Single", result[0].Type)
require.Equal(t, "Artist", result[0].Tracks[0].Artist)
require.Equal(t, 180000, result[0].Tracks[0].DurationMs)
}
require.Equal(t, 2, requests)
}
func TestRecordingLookupRanksEditionsAndBoundsDiscovery(t *testing.T) {
id, other := uuid.NewString(), uuid.NewString()
lookups, details := 0, 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/release" {
lookups++
require.NotEmpty(t, r.URL.Query().Get("recording"))
require.Equal(t, "100", r.URL.Query().Get("limit"))
if lookups == 1 {
_, _ = w.Write([]byte(`{"releases":[{"id":"` + other + `"},{"id":"` + id + `"}]}`))
} else {
_, _ = w.Write([]byte(`{"releases":[{"id":"` + id + `"}]}`))
}
return
}
details++
releaseID := strings.TrimPrefix(r.URL.Path, "/release/")
_, _ = w.Write([]byte(`{"id":"` + releaseID + `","media":[{"position":1,"tracks":[{"position":1,"title":"Song","length":180000}]}]}`))
}))
defer server.Close()
c := New(memoryCache{}, "test")
c.base = server.URL
c.interval = 0
ids := []string{}
for range 12 {
ids = append(ids, uuid.NewString())
}
ids = append([]string{ids[0]}, ids...)
releases, err := c.Search(context.Background(), Query{RecordingIDs: ids})
require.NoError(t, err)
require.Len(t, releases, 2)
require.Equal(t, id, releases[0].ID)
require.Equal(t, 8, lookups)
require.Equal(t, 2, details)
}
func TestCoverFallbackIsExplicitAndRedirectsAreRestricted(t *testing.T) {
r := Release{ID: uuid.NewString(), GroupID: uuid.NewString()}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if strings.HasPrefix(req.URL.Path, "/release/") {
w.WriteHeader(404)
return
}
_, _ = w.Write([]byte{0xff, 0xd8, 0xff, 1})
}))
defer server.Close()
c := New(memoryCache{}, "test")
c.coverBase = server.URL
cover, err := c.Cover(context.Background(), r)
require.NoError(t, err)
require.False(t, cover.Exact)
require.Contains(t, cover.URL, "/release-group/")
for _, address := range []string{"http://archive.org/a", "https://127.0.0.1/a", "https://archive.org.evil.example/a", "https://archive.org:1234/a"} {
u, _ := url.Parse(address)
require.Error(t, c.http.CheckRedirect(&http.Request{URL: u}, nil))
}
}
func TestLookupRateWaitCanBeCancelledAndResponsesAreBounded(t *testing.T) {
c := New(memoryCache{}, "test")
c.next = time.Now().Add(time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
_, err := c.Search(ctx, Query{Artist: "Artist", Album: "Album"})
require.ErrorIs(t, err, context.DeadlineExceeded)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(strings.Repeat("x", 100))) }))
defer server.Close()
_, err = c.get(context.Background(), server.URL, false, 16)
require.ErrorContains(t, err, "too large")
}