package main import ( "encoding/json" "fmt" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" "strings" ) // Define some custom types to make response parsing easier type SearchResponse struct { SpotifyID string Name string Popularity int Genres []string } type SearchResponseList []SearchResponse func TestAlive(t *testing.T) { db := setupTestDatabase("testalive") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/alive", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, "yes!", w.Body.String()) } func TestGetArtistByID(t *testing.T) { db := setupTestDatabase("testgetartistbyid") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists/0TnOYISbd1XYRBk9myaseg", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) // Dynamic data is hard to test so here we validate JSON response // And we check known fields which are not likely to change // We then check that the DB was updated correctly just to be sure var resp ArtistProfile err := json.NewDecoder(w.Body).Decode(&resp) if err != nil { assert.Fail(t, fmt.Sprintf("Could not validate and parse JSON response into ArtistProfile struct: %s", err.Error())) } assert.Equal(t, "0TnOYISbd1XYRBk9myaseg", resp.SpotifyID) assert.Equal(t, "Pitbull", resp.Name) var artist ArtistProfile dbResult := env.db.Take(&artist) if dbResult.Error != nil { assert.Fail(t, "Failed to retrieve new info from test database") } assert.Equal(t, "Pitbull", artist.Name) assert.Equal(t, "0TnOYISbd1XYRBk9myaseg", artist.SpotifyID) } func TestGetArtistByIDBadParams(t *testing.T) { db := setupTestDatabase("testgetartistbyidbadparams") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists/ExampleIDthatiscertainlyinvalid", nil) router.ServeHTTP(w, req) assert.Equal(t, 400, w.Code) assert.Equal(t, `{"Error":"Bad request"}`, w.Body.String()) } func TestGetArtistByName(t *testing.T) { db := setupTestDatabase("testgetartistbyname") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) // We should request Aesop's data so it is populated in the DB for this test w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists/2fSaE6BXtQy0x7R7v9IOmZ", nil) router.ServeHTTP(w, req) w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/artists?name=aesop", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) var resp SearchResponseList err := json.NewDecoder(w.Body).Decode(&resp) if err != nil { assert.Fail(t, fmt.Sprintf("Could not validate and parse JSON response: %s", err.Error())) } // only response should be aesop assert.Equal(t, "Aesop Rock", resp[0].Name) assert.Equal(t, "2fSaE6BXtQy0x7R7v9IOmZ", resp[0].SpotifyID) } func TestGetArtistByNameEmptyParams(t *testing.T) { db := setupTestDatabase("testgetartistbynameemptyparams") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists?name=", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, `[]`, w.Body.String()) } func TestGetArtistByNameMissingParams(t *testing.T) { db := setupTestDatabase("testgetartistbynamemissingparams") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists", nil) router.ServeHTTP(w, req) assert.Equal(t, 400, w.Code) assert.Equal(t, `{"Error":"name parameter was not supplied"}`, w.Body.String()) } func TestGetGenres(t *testing.T) { db := setupTestDatabase("testgetgenres") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/genres", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, `[]`, w.Body.String()) // Populate the DB with some genres and test again // This is aesop rock's ID which should return 3 genres w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/artists/2fSaE6BXtQy0x7R7v9IOmZ", nil) router.ServeHTTP(w, req) w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/genres", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, `["underground hip hop","experimental hip hop","alternative hip hop"]`, w.Body.String()) } func TestCreateGenres(t *testing.T) { db := setupTestDatabase("testcreategenres") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/genres", strings.NewReader(`{"Name": "testgenre"}`)) req.Header.Set("content-type", "application/json") router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, `Success`, w.Body.String()) // Confirm new genre was saved in DB var genre Genre dbResult := env.db.Find(&genre) if dbResult.Error != nil { assert.Fail(t, "Could not retrieve genre data from test DB") } assert.Equal(t, "testgenre", genre.Name) } func TestGetPaginatedGenres(t *testing.T) { db := setupTestDatabase("testgetpaginatedgenres") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) // Create a large list of fake genres to test paging var testData []Genre for i := 0; i < 100; i++ { testData = append(testData, Genre{Name: fmt.Sprintf("test%d", i)}) } dbResult := env.db.Create(&testData) if dbResult.Error != nil { assert.Fail(t, "Failed to save test into info into database") } w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/genres?page=3&page_size=12", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, `["test24","test25","test26","test27","test28","test29","test30","test31","test32","test33","test34","test35"]`, w.Body.String()) } func TestGetPaginatedArtistByName(t *testing.T) { db := setupTestDatabase("testgetpaginatedartistbyname") env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) // Create a large list of fake artist profiles to test paging var testData []ArtistProfile for i := 0; i < 100; i++ { testName := fmt.Sprintf("test%d", i) testArtist := ArtistProfile{ Name: testName, SpotifyID: testName, Popularity: i, Genres: []Genre{ Genre{Name: testName} }, } testData = append(testData, testArtist) } dbResult := env.db.Create(&testData) if dbResult.Error != nil { assert.Fail(t, "Failed to save test info into database") } w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/artists?name=test&page=15&page_size=2", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) var resp SearchResponseList err := json.NewDecoder(w.Body).Decode(&resp) if err != nil { assert.Fail(t, fmt.Sprintf("Could not validate and parse JSON response: %s", err.Error())) } assert.Equal(t, "test28", resp[0].SpotifyID) assert.Equal(t, "test28", resp[0].Name) assert.Equal(t, "test28", resp[0].Genres[0]) assert.Equal(t, 28, resp[0].Popularity) // Test end of the returned data is correct too assert.Equal(t, "test29", resp[1].SpotifyID) assert.Equal(t, "test29", resp[1].Name) assert.Equal(t, "test29", resp[1].Genres[0]) assert.Equal(t, 29, resp[1].Popularity) }