From 38e4660049bcb93a9a6514c4bdf30a5a79d26b33 Mon Sep 17 00:00:00 2001 From: Bernardo Heynemann Date: Thu, 17 Nov 2016 20:30:18 -0200 Subject: [PATCH] Item verification in donation requests --- api/donation_test.go | 2 +- errors/models.go | 22 ++++++++++++ models/donation.go | 21 ++++++++++++ models/donation_test.go | 76 ++++++++++++++++++++++++++--------------- models/game_test.go | 2 +- testing/fixtures.go | 11 +++++- 6 files changed, 103 insertions(+), 31 deletions(-) diff --git a/api/donation_test.go b/api/donation_test.go index 6bc3d07..a6e2c12 100644 --- a/api/donation_test.go +++ b/api/donation_test.go @@ -38,7 +38,7 @@ var _ = Describe("Game Handler", func() { Expect(err).NotTo(HaveOccurred()) playerID := uuid.NewV4().String() - itemID := uuid.NewV4().String() + itemID := GetFirstItem(game).Key clanID := uuid.NewV4().String() payload := &api.CreateDonationRequestPayload{ Player: playerID, diff --git a/errors/models.go b/errors/models.go index 3f6bb36..baf792d 100644 --- a/errors/models.go +++ b/errors/models.go @@ -20,3 +20,25 @@ func NewDocumentNotFoundError(collection string, id string) *DocumentNotFoundErr func (err DocumentNotFoundError) Error() string { return fmt.Sprintf("Document with id %s was not found in collection %s.", err.ID, err.Collection) } + +//ParameterIsRequiredError happens when a parameter for a given instance to be saved is required but is empty +type ParameterIsRequiredError struct { + Parameter string + Model string +} + +//Error string +func (err ParameterIsRequiredError) Error() string { + return fmt.Sprintf("%s is required to create a new %s", err.Parameter, err.Model) +} + +//ItemNotFoundInGameError happens when a donation happens for an item that's not in the game +type ItemNotFoundInGameError struct { + ItemKey string + GameID string +} + +//Error string +func (err ItemNotFoundInGameError) Error() string { + return fmt.Sprintf("Item %s was not found in game %s", err.ItemKey, err.GameID) +} diff --git a/models/donation.go b/models/donation.go index ab70462..aaedb02 100644 --- a/models/donation.go +++ b/models/donation.go @@ -44,6 +44,27 @@ func (d *DonationRequest) Create(db *mgo.Database, logger zap.Logger) error { zap.String("operation", "Save"), ) + if d.Game == nil { + return &errors.ParameterIsRequiredError{ + Parameter: "Game", + Model: "DonationRequest", + } + } + + if d.Item == "" { + return &errors.ParameterIsRequiredError{ + Parameter: "Item", + Model: "DonationRequest", + } + } + + if _, ok := d.Game.Items[d.Item]; !ok { + return &errors.ItemNotFoundInGameError{ + ItemKey: d.Item, + GameID: d.Game.ID, + } + } + d.ID = bson.NewObjectId().Hex() d.CreatedAt = time.Now().UTC() d.UpdatedAt = time.Now().UTC() diff --git a/models/donation_test.go b/models/donation_test.go index 91a681f..7cd821a 100644 --- a/models/donation_test.go +++ b/models/donation_test.go @@ -1,6 +1,7 @@ package models_test import ( + "fmt" "time" mgo "gopkg.in/mgo.v2" @@ -39,12 +40,12 @@ var _ = Describe("Donation Model", func() { game, err := GetTestGame(db, logger, true) Expect(err).NotTo(HaveOccurred()) - itemID := uuid.NewV4().String() + itemKey := GetFirstItem(game).Key playerID := uuid.NewV4().String() clanID := uuid.NewV4().String() donationRequest := models.NewDonationRequest( game, - itemID, + itemKey, playerID, clanID, ) @@ -55,7 +56,7 @@ var _ = Describe("Donation Model", func() { c := models.GetDonationRequestsCollection(db) err = c.FindId(donationRequest.ID).One(&dbDonationRequest) Expect(err).NotTo(HaveOccurred()) - Expect(dbDonationRequest.Item).To(Equal(itemID)) + Expect(dbDonationRequest.Item).To(Equal(itemKey)) Expect(dbDonationRequest.Player).To(Equal(playerID)) Expect(dbDonationRequest.Clan).To(Equal(clanID)) Expect(dbDonationRequest.Game).NotTo(BeNil()) @@ -63,29 +64,59 @@ var _ = Describe("Donation Model", func() { Expect(dbDonationRequest.CreatedAt.Unix()).To(BeNumerically(">", start.Unix()-10)) Expect(dbDonationRequest.UpdatedAt.Unix()).To(BeNumerically(">", start.Unix()-10)) }) + + It("Should fail to create a new donation request without a game", func() { + itemID := uuid.NewV4().String() + playerID := uuid.NewV4().String() + clanID := uuid.NewV4().String() + donationRequest := models.NewDonationRequest( + nil, + itemID, + playerID, + clanID, + ) + err := donationRequest.Create(db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Game is required to create a new DonationRequest")) + }) + + It("Should fail to create a new donation request with invalid item", func() { + game, err := GetTestGame(db, logger, true) + Expect(err).NotTo(HaveOccurred()) + + itemID := uuid.NewV4().String() + playerID := uuid.NewV4().String() + clanID := uuid.NewV4().String() + donationRequest := models.NewDonationRequest( + game, + itemID, + playerID, + clanID, + ) + err = donationRequest.Create(db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring( + fmt.Sprintf("Item %s was not found in game %s", itemID, game.ID), + )) + }) }) Describe("Measure", func() { var game *models.Game + var err error BeforeOnce(func() { - game = models.NewGame( - uuid.NewV4().String(), - uuid.NewV4().String(), - 1, - 2, - ) - err := game.Save(db, logger) + game, err = GetTestGame(db, logger, true) Expect(err).NotTo(HaveOccurred()) }) Measure("it should create donation requests fast", func(b Benchmarker) { runtime := b.Time("runtime", func() { - itemID := uuid.NewV4().String() + itemKey := GetFirstItem(game).Key playerID := uuid.NewV4().String() clanID := uuid.NewV4().String() donationRequest := models.NewDonationRequest( game, - itemID, + itemKey, playerID, clanID, ) @@ -101,16 +132,10 @@ var _ = Describe("Donation Model", func() { Describe("Donating an item", func() { Describe("Feature", func() { It("Should append a new donation", func() { - game := models.NewGame( - uuid.NewV4().String(), - uuid.NewV4().String(), - 1, - 2, - ) - err := game.Save(db, logger) + game, err := GetTestGame(db, logger, true) Expect(err).NotTo(HaveOccurred()) - itemID := uuid.NewV4().String() + itemID := GetFirstItem(game).Key playerID := uuid.NewV4().String() clanID := uuid.NewV4().String() donationRequest := models.NewDonationRequest( @@ -140,18 +165,13 @@ var _ = Describe("Donation Model", func() { Describe("Measure", func() { var game *models.Game var donationRequest *models.DonationRequest + var err error BeforeOnce(func() { - game = models.NewGame( - uuid.NewV4().String(), - uuid.NewV4().String(), - 1, - 2, - ) - err := game.Save(db, logger) + game, err = GetTestGame(db, logger, true) Expect(err).NotTo(HaveOccurred()) - itemID := uuid.NewV4().String() + itemID := GetFirstItem(game).Key playerID := uuid.NewV4().String() clanID := uuid.NewV4().String() donationRequest = models.NewDonationRequest( diff --git a/models/game_test.go b/models/game_test.go index d3b36bf..2784464 100644 --- a/models/game_test.go +++ b/models/game_test.go @@ -273,7 +273,7 @@ var _ = Describe("Game Model", func() { Expect(err).NotTo(HaveOccurred()) }) - Expect(runtime.Seconds()).Should(BeNumerically("<", 0.2), "Operation shouldn't take this long.") + Expect(runtime.Seconds()).Should(BeNumerically("<", 0.5), "Operation shouldn't take this long.") }, 500) }) }) diff --git a/testing/fixtures.go b/testing/fixtures.go index 72fb1f3..53ef93d 100644 --- a/testing/fixtures.go +++ b/testing/fixtures.go @@ -38,7 +38,7 @@ func GetTestGame(db *mgo.Database, logger zap.Logger, withItems bool) (*models.G func GetTestDonationRequest(game *models.Game, db *mgo.Database, logger zap.Logger) (*models.DonationRequest, error) { donationRequest := models.NewDonationRequest( game, - uuid.NewV4().String(), + GetFirstItem(game).Key, uuid.NewV4().String(), uuid.NewV4().String(), ) @@ -46,6 +46,15 @@ func GetTestDonationRequest(game *models.Game, db *mgo.Database, logger zap.Logg return donationRequest, err } +//GetFirstItemInGame +func GetFirstItem(g *models.Game) *models.Item { + for _, v := range g.Items { + return &v + } + + return nil +} + //ToNullInt64 returns valid if int > 0 func ToNullInt64(v int64) sql.NullInt64 { return sql.NullInt64{Int64: v, Valid: v > 0}