363 lines
8.5 KiB
Go
363 lines
8.5 KiB
Go
package lastfm
|
|
|
|
import (
|
|
"context"
|
|
"crypto/md5"
|
|
"crypto/tls"
|
|
_ "embed"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func httpClientMock(handler http.Handler) (http.Client, func()) {
|
|
server := httptest.NewTLSServer(handler)
|
|
client := http.Client{
|
|
Transport: &http.Transport{
|
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return net.Dial(network, server.Listener.Addr().String())
|
|
},
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true, //nolint:gosec
|
|
},
|
|
},
|
|
}
|
|
|
|
return client, server.Close
|
|
}
|
|
|
|
//go:embed testdata/artist_get_info_response.xml
|
|
var artistGetInfoResponse string
|
|
|
|
func TestArtistGetInfo(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"artist.getInfo"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"Artist 1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(artistGetInfoResponse))
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.ArtistGetInfo("apiKey1", "Artist 1")
|
|
|
|
// assert
|
|
require.NoError(err)
|
|
require.Equal(Artist{
|
|
XMLName: xml.Name{
|
|
Local: "artist",
|
|
},
|
|
Name: "Artist 1",
|
|
MBID: "366c1119-ec4f-4312-b729-a5637d148e3e",
|
|
Streamable: "0",
|
|
Stats: struct {
|
|
Listeners string `xml:"listeners"`
|
|
Playcount string `xml:"playcount"`
|
|
}{
|
|
Listeners: "1",
|
|
Playcount: "2",
|
|
},
|
|
URL: "https://www.last.fm/music/Artist+1",
|
|
Image: []Image{
|
|
{
|
|
Size: "small",
|
|
Text: "https://last.fm/artist-1-small.png",
|
|
},
|
|
},
|
|
Bio: ArtistBio{
|
|
Published: "13 May 2023, 00:24",
|
|
Summary: "Summary",
|
|
Content: "Content",
|
|
},
|
|
Similar: struct {
|
|
Artists []Artist `xml:"artist"`
|
|
}{
|
|
Artists: []Artist{
|
|
{
|
|
XMLName: xml.Name{
|
|
Local: "artist",
|
|
},
|
|
Name: "Similar Artist 1",
|
|
URL: "https://www.last.fm/music/Similar+Artist+1",
|
|
Image: []Image{
|
|
{
|
|
Size: "small",
|
|
Text: "https://last.fm/similar-artist-1-small.png",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Tags: struct {
|
|
Tag []ArtistTag `xml:"tag"`
|
|
}{
|
|
Tag: []ArtistTag{
|
|
{
|
|
Name: "tag1",
|
|
URL: "https://www.last.fm/tag/tag1",
|
|
},
|
|
},
|
|
},
|
|
}, actual)
|
|
}
|
|
|
|
func TestArtistGetInfo_clientRequestFails(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"artist.getInfo"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"Artist 1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.ArtistGetInfo("apiKey1", "Artist 1")
|
|
|
|
// assert
|
|
require.Error(err)
|
|
require.Zero(actual)
|
|
}
|
|
|
|
//go:embed testdata/artist_get_top_tracks_response.xml
|
|
var artistGetTopTracksResponse string
|
|
|
|
func TestArtistGetTopTracks(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"artist.getTopTracks"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"artist1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(artistGetTopTracksResponse))
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.ArtistGetTopTracks("apiKey1", "artist1")
|
|
|
|
// assert
|
|
require.NoError(err)
|
|
require.Equal(TopTracks{
|
|
Artist: "Artist 1",
|
|
XMLName: xml.Name{
|
|
Local: "toptracks",
|
|
},
|
|
Tracks: []Track{
|
|
{
|
|
Image: []Image{
|
|
{
|
|
Text: "https://last.fm/track-1-small.png",
|
|
Size: "small",
|
|
},
|
|
{
|
|
Text: "https://last.fm/track-1-large.png",
|
|
Size: "large",
|
|
},
|
|
},
|
|
Listeners: 2,
|
|
MBID: "fdfc47cb-69d3-4318-ba71-d54fbc20169a",
|
|
Name: "Track 1",
|
|
PlayCount: 1,
|
|
Rank: 1,
|
|
URL: "https://www.last.fm/music/Artist+1/_/Track+1",
|
|
},
|
|
{
|
|
Image: []Image{
|
|
{
|
|
Text: "https://last.fm/track-2-small.png",
|
|
Size: "small",
|
|
},
|
|
{
|
|
Text: "https://last.fm/track-2-large.png",
|
|
Size: "large",
|
|
},
|
|
},
|
|
Listeners: 3,
|
|
MBID: "cf32e694-1ea6-4ba0-9e8b-d5f1950da9c8",
|
|
Name: "Track 2",
|
|
PlayCount: 2,
|
|
Rank: 2,
|
|
URL: "https://www.last.fm/music/Artist+1/_/Track+2",
|
|
},
|
|
},
|
|
}, actual)
|
|
}
|
|
|
|
func TestArtistGetTopTracks_clientRequestFails(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"artist.getTopTracks"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"artist1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.ArtistGetTopTracks("apiKey1", "artist1")
|
|
|
|
// assert
|
|
require.Error(err)
|
|
require.Zero(actual)
|
|
}
|
|
|
|
//go:embed testdata/track_get_similar_response.xml
|
|
var trackGetSimilaResponse string
|
|
|
|
func TestTrackGetSimilarTracks(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"track.getSimilar"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"artist1"},
|
|
"track": []string{"track1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(trackGetSimilaResponse))
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.TrackGetSimilarTracks("apiKey1", "artist1", "track1")
|
|
|
|
// assert
|
|
require.NoError(err)
|
|
require.Equal(SimilarTracks{
|
|
Artist: "Artist 1",
|
|
Track: "Track 1",
|
|
XMLName: xml.Name{
|
|
Local: "similartracks",
|
|
},
|
|
Tracks: []Track{
|
|
{
|
|
Image: []Image{
|
|
{
|
|
Text: "https://last.fm/track-1-small.png",
|
|
Size: "small",
|
|
},
|
|
{
|
|
Text: "https://last.fm/track-1-large.png",
|
|
Size: "large",
|
|
},
|
|
},
|
|
MBID: "7096931c-bf82-4896-b1e7-42b60a0e16ea",
|
|
Name: "Track 1",
|
|
PlayCount: 1,
|
|
URL: "https://www.last.fm/music/Artist+1/_/Track+1",
|
|
},
|
|
{
|
|
Image: []Image{
|
|
{
|
|
Text: "https://last.fm/track-2-small.png",
|
|
Size: "small",
|
|
},
|
|
{
|
|
Text: "https://last.fm/track-2-large.png",
|
|
Size: "large",
|
|
},
|
|
},
|
|
MBID: "2aff1321-149f-4000-8762-3468c917600c",
|
|
Name: "Track 2",
|
|
PlayCount: 2,
|
|
URL: "https://www.last.fm/music/Artist+2/_/Track+2",
|
|
},
|
|
},
|
|
}, actual)
|
|
}
|
|
|
|
func TestTrackGetSimilarTracks_clientRequestFails(t *testing.T) {
|
|
// arrange
|
|
require := require.New(t)
|
|
httpClient, shutdown := httpClientMock(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(http.MethodGet, r.Method)
|
|
require.Equal(url.Values{
|
|
"method": []string{"track.getSimilar"},
|
|
"api_key": []string{"apiKey1"},
|
|
"artist": []string{"artist1"},
|
|
"track": []string{"track1"},
|
|
}, r.URL.Query())
|
|
require.Equal("/2.0/", r.URL.Path)
|
|
require.Equal(baseURL, "https://"+r.Host+r.URL.Path)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer shutdown()
|
|
|
|
client := Client{&httpClient}
|
|
|
|
// act
|
|
actual, err := client.TrackGetSimilarTracks("apiKey1", "artist1", "track1")
|
|
|
|
// assert
|
|
require.Error(err)
|
|
require.Zero(actual)
|
|
}
|
|
|
|
func TestGetParamSignature(t *testing.T) {
|
|
params := url.Values{}
|
|
params.Add("ccc", "CCC")
|
|
params.Add("bbb", "BBB")
|
|
params.Add("aaa", "AAA")
|
|
params.Add("ddd", "DDD")
|
|
actual := getParamSignature(params, "secret")
|
|
expected := fmt.Sprintf("%x", md5.Sum([]byte(
|
|
"aaaAAAbbbBBBcccCCCdddDDDsecret",
|
|
)))
|
|
if actual != expected {
|
|
t.Errorf("expected %x, got %s", expected, actual)
|
|
}
|
|
}
|