Skip to content

Commit

Permalink
fix tests. use calculated field in /bettor
Browse files Browse the repository at this point in the history
  • Loading branch information
elh committed Jun 29, 2023
1 parent 963280f commit 791540a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 46 deletions.
17 changes: 1 addition & 16 deletions internal/app/bettor/discord/bettor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package discord
import (
"context"

"github.com/bufbuild/connect-go"
"github.com/bwmarrin/discordgo"
api "github.com/elh/bettor/api/bettor/v1alpha"
)

var getBettorCommand = &discordgo.ApplicationCommand{
Expand All @@ -26,20 +24,7 @@ func GetBettor(ctx context.Context, client bettorClient) Handler {
return nil, CErr("Failed to get or create new user", err)
}

resp, err := client.ListBets(ctx, &connect.Request[api.ListBetsRequest]{Msg: &api.ListBetsRequest{
Book: guildBookName(guildID),
User: bettorUser.GetName(),
ExcludeSettled: true,
}})
if err != nil {
return nil, CErr("Failed to list bets", err)
}
var unsettledCentipoints uint64
for _, b := range resp.Msg.GetBets() {
unsettledCentipoints += b.GetCentipoints()
}

msgformat, margs := formatUser(bettorUser, unsettledCentipoints)
msgformat, margs := formatUser(bettorUser, bettorUser.UnsettledCentipoints)
msgformat = "馃幉 馃懁\n\n" + msgformat
return &discordgo.InteractionResponseData{Content: localized.Sprintf(msgformat, margs...)}, nil
}
Expand Down
20 changes: 11 additions & 9 deletions internal/app/bettor/repo/mem/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ type Repo struct {
betMtx sync.RWMutex
}

// hydrate virtual fields like unsettled_centipoints
func (r *Repo) hydrateUser(user *api.User) (*api.User, error) {
// hydrate virtual fields like unsettled_centipoints.
func (r *Repo) hydrateUser(ctx context.Context, user *api.User) (*api.User, error) {
bookID, _ := entity.UserIDs(user.GetName())
bets, _, err := r.ListBets(context.Background(), &repo.ListBetsArgs{
bets, _, err := r.ListBets(ctx, &repo.ListBetsArgs{
Book: entity.BookN(bookID),
User: user.GetName(),
ExcludeSettled: true,
Expand All @@ -51,6 +51,8 @@ func (r *Repo) CreateUser(_ context.Context, user *api.User) error {
r.userMtx.Lock()
defer r.userMtx.Unlock()

user.UnsettledCentipoints = 0 // defensive

bookID, _ := entity.UserIDs(user.GetName())
for _, u := range r.Users {
if u.GetName() == user.GetName() {
Expand Down Expand Up @@ -86,12 +88,12 @@ func (r *Repo) UpdateUser(_ context.Context, user *api.User) error {
}

// GetUser gets a user by ID.
func (r *Repo) GetUser(_ context.Context, name string) (*api.User, error) {
func (r *Repo) GetUser(ctx context.Context, name string) (*api.User, error) {
r.userMtx.RLock()
defer r.userMtx.RUnlock()
for _, u := range r.Users {
if u.GetName() == name {
u, err := r.hydrateUser(u)
u, err := r.hydrateUser(ctx, u)
if err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
Expand All @@ -102,14 +104,14 @@ func (r *Repo) GetUser(_ context.Context, name string) (*api.User, error) {
}

// GetUserByUsername gets a user by username.
func (r *Repo) GetUserByUsername(_ context.Context, book, username string) (*api.User, error) {
func (r *Repo) GetUserByUsername(ctx context.Context, book, username string) (*api.User, error) {
r.userMtx.RLock()
defer r.userMtx.RUnlock()
bookID := entity.BooksIDs(book)
for _, u := range r.Users {
uBookID, _ := entity.UserIDs(u.GetName())
if uBookID == bookID && u.Username == username {
u, err := r.hydrateUser(u)
u, err := r.hydrateUser(ctx, u)
if err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
Expand All @@ -120,7 +122,7 @@ func (r *Repo) GetUserByUsername(_ context.Context, book, username string) (*api
}

// ListUsers lists users by filters.
func (r *Repo) ListUsers(_ context.Context, args *repo.ListUsersArgs) (users []*api.User, hasMore bool, err error) {
func (r *Repo) ListUsers(ctx context.Context, args *repo.ListUsersArgs) (users []*api.User, hasMore bool, err error) {
r.userMtx.RLock()
defer r.userMtx.RUnlock()
bookID := entity.BooksIDs(args.Book)
Expand All @@ -137,7 +139,7 @@ func (r *Repo) ListUsers(_ context.Context, args *repo.ListUsersArgs) (users []*
continue
}
// hydrate
u, err := r.hydrateUser(u)
u, err := r.hydrateUser(ctx, u)
if err != nil {
return nil, false, connect.NewError(connect.CodeInternal, errors.New("failed to compute unsettled points"))
}
Expand Down
7 changes: 3 additions & 4 deletions internal/app/bettor/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
api "github.com/elh/bettor/api/bettor/v1alpha"
)

// NOTE: same models E2E from API to repo out of laziness

// Repo is a persistence repository.
type Repo interface {
CreateUser(ctx context.Context, user *api.User) error
Expand All @@ -26,12 +28,9 @@ type Repo interface {
// ListUsersArgs are the arguments for listing users.
type ListUsersArgs struct {
Book string
GreaterThanName string // only supported if OrderBy=name
GreaterThanName string
Users []string
Limit int
// TODO: implement
// "name" (asc) or "total_centipoints" (desc). defaults to "name"
OrderBy string
}

// ListMarketsArgs are the arguments for listing markets.
Expand Down
70 changes: 53 additions & 17 deletions internal/app/bettor/server/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,24 @@ func TestGetUser(t *testing.T) {
Username: "rusty",
Centipoints: 100,
}
userWithUnsettled := &api.User{
userHydrated := &api.User{
Name: entity.UserN("guild:1", uuid.NewString()),
Username: "linus",
Centipoints: 100,
}
unsettledBet := &api.Bet{
Name: entity.BetN("guild:1", "b"),
User: userWithUnsettled.Name,
Name: entity.BetN("guild:1", "a"),
User: userHydrated.Name,
Centipoints: 200,
}
hydratedUserWithUnsettled := proto.Clone(userWithUnsettled).(*api.User)
hydratedUserWithUnsettled.UnsettledCentipoints = unsettledBet.Centipoints
unsettledBet2 := &api.Bet{
Name: entity.BetN("guild:1", "b"),
User: userHydrated.Name,
Centipoints: 50,
}
hydratedUserHydrated := proto.Clone(userHydrated).(*api.User)
hydratedUserHydrated.UnsettledCentipoints += unsettledBet.Centipoints
hydratedUserHydrated.UnsettledCentipoints += unsettledBet2.Centipoints
testCases := []struct {
desc string
user string
Expand All @@ -141,8 +147,8 @@ func TestGetUser(t *testing.T) {
},
{
desc: "hydrate unsettled points",
user: userWithUnsettled.GetName(),
expected: hydratedUserWithUnsettled,
user: userHydrated.GetName(),
expected: hydratedUserHydrated,
},
{
desc: "fails if user does not exist",
Expand All @@ -158,7 +164,7 @@ func TestGetUser(t *testing.T) {
for _, tC := range testCases {
tC := tC
t.Run(tC.desc, func(t *testing.T) {
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user, userWithUnsettled}, Bets: []*api.Bet{unsettledBet}}))
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user, userHydrated}, Bets: []*api.Bet{unsettledBet, unsettledBet2}}))
require.Nil(t, err)
out, err := s.GetUser(context.Background(), connect.NewRequest(&api.GetUserRequest{Name: tC.user}))
if tC.expectErr {
Expand All @@ -171,13 +177,30 @@ func TestGetUser(t *testing.T) {
}
}

// TODO: add test for unsettled
func TestGetUserByUsername(t *testing.T) {
user := &api.User{
Name: entity.UserN("guild:1", uuid.NewString()),
Username: "rusty",
Centipoints: 100,
}
userHydrated := &api.User{
Name: entity.UserN("guild:1", uuid.NewString()),
Username: "linus",
Centipoints: 100,
}
unsettledBet := &api.Bet{
Name: entity.BetN("guild:1", "a"),
User: userHydrated.Name,
Centipoints: 200,
}
unsettledBet2 := &api.Bet{
Name: entity.BetN("guild:1", "b"),
User: userHydrated.Name,
Centipoints: 50,
}
hydratedUserHydrated := proto.Clone(userHydrated).(*api.User)
hydratedUserHydrated.UnsettledCentipoints += unsettledBet.Centipoints
hydratedUserHydrated.UnsettledCentipoints += unsettledBet2.Centipoints
testCases := []struct {
desc string
book string
Expand All @@ -191,6 +214,12 @@ func TestGetUserByUsername(t *testing.T) {
username: "rusty",
expected: user,
},
{
desc: "hydrate unsettled points",
book: entity.BookN("guild:1"),
username: "linus",
expected: hydratedUserHydrated,
},
{
desc: "fails if user does not exist",
book: entity.BookN("guild:1"),
Expand All @@ -207,7 +236,7 @@ func TestGetUserByUsername(t *testing.T) {
for _, tC := range testCases {
tC := tC
t.Run(tC.desc, func(t *testing.T) {
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user}}))
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user, userHydrated}, Bets: []*api.Bet{unsettledBet, unsettledBet2}}))
require.Nil(t, err)
out, err := s.GetUserByUsername(context.Background(), connect.NewRequest(&api.GetUserByUsernameRequest{Book: tC.book, Username: tC.username}))
if tC.expectErr {
Expand All @@ -220,7 +249,6 @@ func TestGetUserByUsername(t *testing.T) {
}
}

// TODO: add test for unsettled
func TestListUsers(t *testing.T) {
// tests pagination until all users are returned
// alphabetically ordered ids
Expand All @@ -235,11 +263,19 @@ func TestListUsers(t *testing.T) {
Username: "danny",
Centipoints: 200,
}
// has an unsettled bet
user3 := &api.User{
Name: entity.UserN(bookID, "c"),
Username: "linus",
Centipoints: 300,
}
unsettledBet := &api.Bet{
Name: entity.BetN(bookID, "a"),
User: user3.Name,
Centipoints: 200,
}
user3Hydrated := proto.Clone(user3).(*api.User)
user3Hydrated.UnsettledCentipoints += unsettledBet.Centipoints
testCases := []struct {
desc string
req *api.ListUsersRequest
Expand All @@ -250,7 +286,7 @@ func TestListUsers(t *testing.T) {
{
desc: "basic case",
req: &api.ListUsersRequest{Book: entity.BookN(bookID)},
expected: []*api.User{user1, user2, user3},
expected: []*api.User{user1, user2, user3Hydrated},
expectedCalls: 1,
},
{
Expand All @@ -262,25 +298,25 @@ func TestListUsers(t *testing.T) {
{
desc: "page size 1",
req: &api.ListUsersRequest{Book: entity.BookN(bookID), PageSize: 1},
expected: []*api.User{user1, user2, user3},
expected: []*api.User{user1, user2, user3Hydrated},
expectedCalls: 3,
},
{
desc: "page size 2",
req: &api.ListUsersRequest{Book: entity.BookN(bookID), PageSize: 2},
expected: []*api.User{user1, user2, user3},
expected: []*api.User{user1, user2, user3Hydrated},
expectedCalls: 2,
},
{
desc: "page size 3",
req: &api.ListUsersRequest{Book: entity.BookN(bookID), PageSize: 3},
expected: []*api.User{user1, user2, user3},
expected: []*api.User{user1, user2, user3Hydrated},
expectedCalls: 1,
},
{
desc: "page size 4",
req: &api.ListUsersRequest{Book: entity.BookN(bookID), PageSize: 4},
expected: []*api.User{user1, user2, user3},
expected: []*api.User{user1, user2, user3Hydrated},
expectedCalls: 1,
},
{
Expand All @@ -293,7 +329,7 @@ func TestListUsers(t *testing.T) {
for _, tC := range testCases {
tC := tC
t.Run(tC.desc, func(t *testing.T) {
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user1, user2, user3}}))
s, err := server.New(server.WithRepo(&mem.Repo{Users: []*api.User{user1, user2, user3}, Bets: []*api.Bet{unsettledBet}}))
require.Nil(t, err)
var all []*api.User
var calls int
Expand Down

0 comments on commit 791540a

Please sign in to comment.