Skip to content

Commit

Permalink
Add enrichment call on GetTopMembers route (#87)
Browse files Browse the repository at this point in the history
* Implement base for the enrich response process

* Fix some dependencies

* Call enrichment on routes

* add metadata to GetTopMembers test

---------

Co-authored-by: Gustavo <25396922+gussf@users.noreply.github.com>
  • Loading branch information
miguelreiswildlife and gussf committed Jul 27, 2023
1 parent 05c687a commit 1c81e1a
Show file tree
Hide file tree
Showing 7 changed files with 885 additions and 692 deletions.
29 changes: 15 additions & 14 deletions api/leaderboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package api
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"math"
"strings"

Expand Down Expand Up @@ -188,7 +189,7 @@ func (app *App) IncrementScore(ctx context.Context, req *api.IncrementScoreReque
}, nil
}

//TODO: Make this function use RemoveMembers
// TODO: Make this function use RemoveMembers
// RemoveMember removes a member from a leaderboard.
func (app *App) RemoveMember(ctx context.Context, req *api.RemoveMemberRequest) (*api.RemoveMemberResponse, error) {
lg := app.Logger.With(
Expand Down Expand Up @@ -545,24 +546,23 @@ func (app *App) GetTopMembers(ctx context.Context, req *api.GetTopMembersRequest
return nil, status.Errorf(codes.InvalidArgument, msg)
}

var members []*lmodel.Member
err := withSegment("Model", ctx, func() error {
var err error
lg.Debug("Getting top members.")
members, err = app.Leaderboards.GetLeaders(ctx, req.LeaderboardId, pageSize, pageNumber, order)
members, err := app.Leaderboards.GetLeaders(ctx, req.LeaderboardId, pageSize, pageNumber, order)

if err != nil {
lg.Error("Getting top members failed.", zap.Error(err))
app.AddError()
return err
}
lg.Debug("Getting top members succeeded.")
return nil
})
if err != nil {
lg.Error("Getting top members failed.", zap.Error(err))
app.AddError()
return nil, err
}

tenantID := metadata.ValueFromIncomingContext(ctx, "tenant-id")
if tenantID != nil {
members, err = app.Enricher.Enrich(tenantID[0], req.LeaderboardId, members)
if err != nil {
lg.Error("Enriching members failed.", zap.Error(err))
return nil, status.Errorf(codes.Internal, "Unable to enrich members")
}
}

return &api.GetTopMembersResponse{
Success: true,
Members: newMemberRankResponseList(members),
Expand Down Expand Up @@ -690,6 +690,7 @@ func newMemberRankResponseList(members []*lmodel.Member) []*api.Member {
PublicID: m.PublicID,
Score: float64(m.Score),
Rank: int32(m.Rank),
Metadata: m.Metadata,
}
}
return list
Expand Down
89 changes: 89 additions & 0 deletions api/leaderboard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ package api_test
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"time"

"github.com/golang/mock/gomock"
mock_enriching "github.com/topfreegames/podium/leaderboard/v2/mocks"
"github.com/topfreegames/podium/leaderboard/v2/model"

"github.com/topfreegames/podium/api"
"github.com/topfreegames/podium/leaderboard/v2/database/redis"
"github.com/topfreegames/podium/testing"
Expand Down Expand Up @@ -1770,7 +1775,62 @@ var _ = Describe("Leaderboard Handler", func() {
})

Describe("Get Top Members Handler", func() {
tenantID := "test-tenant-id"
It("Should get one page of top members from redis if leaderboard exists (http)", func() {
ctrl := gomock.NewController(GinkgoT())
defer ctrl.Finish()

enricher := mock_enriching.NewMockEnricher(ctrl)
app.Enricher = enricher

expectedMetadataKey := "key"
expectedMetadataValue := "value"
expectedMetadata := map[string]string{expectedMetadataKey: expectedMetadataValue}

enricher.EXPECT().Enrich(tenantID, testLeaderboardID, gomock.Any()).
DoAndReturn(func(_, _ string, members []*model.Member) ([]*model.Member, error) {
Expect(members).To(HaveLen(20))
for _, member := range members {
member.Metadata = expectedMetadata
}
return members, nil
})

for i := 1; i <= 100; i++ {
_, err := app.Leaderboards.SetMemberScore(NewEmptyCtx(), testLeaderboardID, "member_"+strconv.Itoa(i), int64(101-i), false, "")
Expect(err).NotTo(HaveOccurred())
}

status, body := Get(app, "/l/testkey/top/1", "tenant-id", tenantID)
Expect(status).To(Equal(http.StatusOK), body)
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
members := result["members"].([]interface{})
Expect(len(members)).To(Equal(20))
for i, memberObj := range members {
member := memberObj.(map[string]interface{})
metadata := member["metadata"].(map[string]interface{})
Expect(int(member["rank"].(float64))).To(Equal(i + 1))
Expect(member["publicID"]).To(Equal(fmt.Sprintf("member_%d", i+1)))
Expect(int(member["score"].(float64))).To(Equal(100 - i))
Expect(metadata[expectedMetadataKey]).To(Equal(expectedMetadataValue))

dbMember, err := app.Leaderboards.GetMember(NewEmptyCtx(), testLeaderboardID, member["publicID"].(string), "desc", false)
Expect(err).NotTo(HaveOccurred())
Expect(dbMember.Rank).To(Equal(int(member["rank"].(float64))))
Expect(dbMember.Score).To(Equal(int64(member["score"].(float64))))
Expect(dbMember.PublicID).To(Equal(member["publicID"]))
}
})

It("Should succeed with no tenant-id sent for enrichment", func() {
ctrl := gomock.NewController(GinkgoT())
defer ctrl.Finish()

enricher := mock_enriching.NewMockEnricher(ctrl)
app.Enricher = enricher

for i := 1; i <= 100; i++ {
_, err := app.Leaderboards.SetMemberScore(NewEmptyCtx(), testLeaderboardID, "member_"+strconv.Itoa(i), int64(101-i), false, "")
Expect(err).NotTo(HaveOccurred())
Expand All @@ -1785,9 +1845,12 @@ var _ = Describe("Leaderboard Handler", func() {
Expect(len(members)).To(Equal(20))
for i, memberObj := range members {
member := memberObj.(map[string]interface{})
metadata := member["metadata"].(map[string]interface{})

Expect(int(member["rank"].(float64))).To(Equal(i + 1))
Expect(member["publicID"]).To(Equal(fmt.Sprintf("member_%d", i+1)))
Expect(int(member["score"].(float64))).To(Equal(100 - i))
Expect(metadata).To(BeEmpty())

dbMember, err := app.Leaderboards.GetMember(NewEmptyCtx(), testLeaderboardID, member["publicID"].(string), "desc", false)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -1797,6 +1860,32 @@ var _ = Describe("Leaderboard Handler", func() {
}
})

It("Should return error if enrichment is configured but fails", func() {
ctrl := gomock.NewController(GinkgoT())
defer ctrl.Finish()

enricher := mock_enriching.NewMockEnricher(ctrl)
app.Enricher = enricher

enricher.EXPECT().Enrich(tenantID, testLeaderboardID, gomock.Any()).
DoAndReturn(func(_, _ string, members []*model.Member) ([]*model.Member, error) {
Expect(members).To(HaveLen(20))
return nil, errors.New("enrichment error")
})

for i := 1; i <= 100; i++ {
_, err := app.Leaderboards.SetMemberScore(NewEmptyCtx(), testLeaderboardID, "member_"+strconv.Itoa(i), int64(101-i), false, "")
Expect(err).NotTo(HaveOccurred())
}

status, body := Get(app, "/l/testkey/top/1", "tenant-id", tenantID)
Expect(status).To(Equal(http.StatusInternalServerError), body)
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["members"]).To(BeNil())
})

It("Should get one page of top members from redis if leaderboard exists (grpc)", func() {
SetupGRPC(app, func(cli pb.PodiumClient) {
for i := 1; i <= 100; i++ {
Expand Down
Loading

0 comments on commit 1c81e1a

Please sign in to comment.