From 4c8c363946be8c5218aa72818a031af4db9e9524 Mon Sep 17 00:00:00 2001 From: froge Date: Fri, 14 Feb 2025 09:51:58 +1000 Subject: [PATCH] Add genre routes and update test cases --- main.go | 6 ++++- routes.go | 44 ++++++++++++++++++++++++++++++++- routes_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index da6de1a..b0048e1 100644 --- a/main.go +++ b/main.go @@ -13,16 +13,20 @@ type Env struct { db *gorm.DB } -// Grab some required spotify credentials from the environment var spotifyClientID = os.Getenv("SPOTIFY_ID") var spotifyClientSecret = os.Getenv("SPOTIFY_TOKEN") func setupRouter(env *Env, spotifyID string, spotifySecret string) *gin.Engine { var r *gin.Engine = gin.Default() + // Do not trust any reverse proxy by default + // See: https://pkg.go.dev/github.com/gin-gonic/gin#Engine.SetTrustedProxies + r.SetTrustedProxies(nil) r.Use(spotifyAuth(spotifyID, spotifySecret)) r.GET("/alive", env.alive) r.GET("/artists/:artistID", env.getArtistByID) r.GET("/artists", env.getArtistByName) + r.GET("/genres", env.getGenres) + r.POST("/genres", env.createGenre) return r } diff --git a/routes.go b/routes.go index 0ab5552..53072fb 100644 --- a/routes.go +++ b/routes.go @@ -72,7 +72,7 @@ func (env *Env) getArtistByName(c *gin.Context) { } // Lookup this name in the DB and return any ArtistProfile objects - // NOTE: This is case insensitive on sqlite + // NOTE: This is case insensitive for ascii on sqlite // NOTE: However unicode is treated case sensitive due to very difficult conversions for some languages/characters // NOTE: In future better DBs with unicode support such as postgres should be used var artistProfiles []ArtistProfile @@ -85,3 +85,45 @@ func (env *Env) getArtistByName(c *gin.Context) { c.JSON(http.StatusOK, artistProfiles) } + +func (env *Env) getGenres(c *gin.Context) { + var genres []Genre + dbResult := env.db.Find(&genres) + if dbResult.Error != nil { + slog.Error("[GOMUSIC] Failed to query local database for genre data") + c.JSON(http.StatusInternalServerError, gin.H{"Error": "Failed to query database for genre data"}) + return + } + recordNum := dbResult.RowsAffected + + // Construct simple slice for response + genreList := make([]string, 0, recordNum) + if recordNum > 0 { + for _, g := range genres { + genreList = append(genreList, g.Name) + } + } + c.JSON(http.StatusOK, genreList) +} + +func (env *Env) createGenre(c * gin.Context) { + var userGenre Genre + if c.ShouldBind(&userGenre) == nil { + // If we didn't get the correct data abort early + if userGenre.Name == "" { + c.JSON(http.StatusBadRequest, gin.H{"Error":"Could not find genre name"}) + return + } + dbResult := env.db.Clauses(clause.OnConflict{ + DoNothing: true, + }).Create(&userGenre) + if dbResult.Error != nil { + slog.Error("[GOMUSIC] Failed to create new genre record in DB") + c.JSON(http.StatusInternalServerError, gin.H{"Error": "Failed to create new genre record"}) + return + } + c.String(http.StatusOK, "Success") + return + } + c.JSON(http.StatusInternalServerError, gin.H{"Error":"Failed to parse input data"}) +} diff --git a/routes_test.go b/routes_test.go index 5a4b226..e584c81 100644 --- a/routes_test.go +++ b/routes_test.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httptest" "testing" + "strings" ) func TestAlive(t *testing.T) { @@ -72,17 +73,16 @@ func TestGetArtistByName(t *testing.T) { env := &Env{db: db} router := setupRouter(env, spotifyClientID, spotifyClientSecret) - // We should request Kanye's data so it is populated in the DB for this test - prew := httptest.NewRecorder() - preReq, _ := http.NewRequest("GET", "/artists/5K4W6rqBFWDnAN6FQUkS6x", nil) - router.ServeHTTP(prew, preReq) - + // We should request Aesop's data so it is populated in the DB for this test w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/artists?name=kanye", nil) + 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) - fmt.Println(w.Body.String()) // Define some custom types to make response parsing easier type SearchResponse struct { @@ -98,8 +98,8 @@ func TestGetArtistByName(t *testing.T) { } // only response should be kanye - assert.Equal(t, "Kanye West", resp[0].Name) - assert.Equal(t, "5K4W6rqBFWDnAN6FQUkS6x", resp[0].SpotifyID) + assert.Equal(t, "Aesop Rock", resp[0].Name) + assert.Equal(t, "2fSaE6BXtQy0x7R7v9IOmZ", resp[0].SpotifyID) } func TestGetArtistByNameEmptyParams(t *testing.T) { @@ -127,3 +127,52 @@ func TestGetArtistByNameMissingParams(t *testing.T) { 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) +}