diff --git a/Makefile b/Makefile index dc87116..cd6c6e3 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ test-coverage: @rm -rf _build @mkdir -p _build @echo "mode: count" > _build/test-coverage-all.out - @bash -c 'for f in $$(find . -name "*.coverprofile"); do tail -n +2 $$f >> _build/test-coverage-all.out; done' + @bash -c 'find . -name "*.coverprofile" | xargs tail -n +2 | egrep -v "\=\=>" | egrep -v "^$$" >> _build/test-coverage-all.out' test-coverage-html: test-coverage @go tool cover -html=_build/test-coverage-all.out diff --git a/errors/models.go b/errors/models.go index 0cbde97..e1bd9f3 100644 --- a/errors/models.go +++ b/errors/models.go @@ -48,9 +48,10 @@ type LimitOfCardsInDonationRequestReachedError struct { GameID string DonationRequestID string ItemKey string + Amount int } //Error string func (err LimitOfCardsInDonationRequestReachedError) Error() string { - return "This donation request is already finished." + return "This donation request can't accept this donation." } diff --git a/models/donation.go b/models/donation.go index 3fffa23..0aa6987 100644 --- a/models/donation.go +++ b/models/donation.go @@ -194,6 +194,8 @@ func (d *DonationRequest) ValidateDonationRequestLimit(game *Game, amount int, l err := &errors.LimitOfCardsInDonationRequestReachedError{ GameID: game.ID, DonationRequestID: d.ID, + ItemKey: d.Item, + Amount: amount, } log.E(logger, err.Error(), func(cm log.CM) { cm.Write(zap.Error(err)) diff --git a/models/donation_test.go b/models/donation_test.go index 753607d..64a7f0d 100644 --- a/models/donation_test.go +++ b/models/donation_test.go @@ -83,6 +83,23 @@ var _ = Describe("Donation Model", func() { Expect(err.Error()).To(ContainSubstring("GameID is required to create a new DonationRequest")) }) + It("Should fail to create a new donation request with null item", func() { + game, err := GetTestGame(db, logger, true) + Expect(err).NotTo(HaveOccurred()) + + playerID := uuid.NewV4().String() + clanID := uuid.NewV4().String() + donationRequest := models.NewDonationRequest( + game.ID, + "", + playerID, + clanID, + ) + err = donationRequest.Create(db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Item 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()) @@ -127,7 +144,7 @@ var _ = Describe("Donation Model", func() { Expect(err).NotTo(HaveOccurred()) }) - Expect(runtime.Seconds()).Should(BeNumerically("<", 0.01), "Operation shouldn't take this long.") + Expect(runtime.Seconds()).Should(BeNumerically("<", 0.1), "Operation shouldn't take this long.") }, 10) }) }) @@ -179,6 +196,19 @@ var _ = Describe("Donation Model", func() { Expect(dbDonationRequest.FinishedAt).To(BeNumerically(">", start.Unix()-10)) }) + It("Should respect the donation per donation request limit max items", func() { + game, err := GetTestGame(db, logger, true, map[string]interface{}{ + "LimitOfCardsInEachDonationRequest": 2, + }) + Expect(err).NotTo(HaveOccurred()) + + dr, err := GetTestDonationRequest(game, db, logger) + + err = dr.Donate(uuid.NewV4().String(), 3, db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("This donation request can't accept this donation.")) + }) + It("Should respect the donation per donation request limit", func() { game, err := GetTestGame(db, logger, true, map[string]interface{}{ "LimitOfCardsInEachDonationRequest": 2, @@ -192,7 +222,21 @@ var _ = Describe("Donation Model", func() { err = dr.Donate(uuid.NewV4().String(), 1, db, logger) Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("This donation request is already finished.")) + Expect(err.Error()).To(ContainSubstring("This donation request can't accept this donation.")) + }) + + It("Should fail if DonationRequest is not loaded", func() { + game, err := GetTestGame(db, logger, true, map[string]interface{}{ + "LimitOfCardsInEachDonationRequest": 2, + }) + Expect(err).NotTo(HaveOccurred()) + + itemID := GetFirstItem(game).Key + dr := models.NewDonationRequest(game.ID, itemID, uuid.NewV4().String(), uuid.NewV4().String()) + + err = dr.Donate(uuid.NewV4().String(), 2, db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Can't donate without a proper DB-loaded DonationRequest (ID is required).")) }) It("Should fail if no player to donate", func() { @@ -258,7 +302,7 @@ var _ = Describe("Donation Model", func() { Expect(err).NotTo(HaveOccurred()) }) - Expect(runtime.Seconds()).Should(BeNumerically("<", 0.01), "Operation shouldn't take this long.") + Expect(runtime.Seconds()).Should(BeNumerically("<", 0.1), "Operation shouldn't take this long.") }, 5) }) }) @@ -279,6 +323,19 @@ var _ = Describe("Donation Model", func() { Expect(dbDonationRequest.Clan).To(Equal(donationRequest.Clan)) Expect(dbDonationRequest.GameID).To(Equal(game.ID)) }) + + It("Should fail if donation request does not exist", func() { + _, err := GetTestGame(db, logger, true) + Expect(err).NotTo(HaveOccurred()) + + drID := uuid.NewV4().String() + dbDonationRequest, err := models.GetDonationRequestByID(drID, db, logger) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal( + fmt.Sprintf("Document with id %s was not found in collection donationRequest.", drID), + )) + Expect(dbDonationRequest).To(BeNil()) + }) }) Describe("Measure", func() { @@ -298,9 +355,8 @@ var _ = Describe("Donation Model", func() { Expect(err).NotTo(HaveOccurred()) }) - Expect(runtime.Seconds()).Should(BeNumerically("<", 0.01), "Operation shouldn't take this long.") + Expect(runtime.Seconds()).Should(BeNumerically("<", 0.1), "Operation shouldn't take this long.") }, 5) }) }) - }) diff --git a/models/game.go b/models/game.go index 041a3fa..f5e602a 100644 --- a/models/game.go +++ b/models/game.go @@ -97,7 +97,6 @@ func (g *Game) AddItem( return item, nil } -//ToJSON returns the game as JSON func (g *Game) ToJSON() ([]byte, error) { w := jwriter.Writer{} g.MarshalEasyJSON(&w) diff --git a/models/game_test.go b/models/game_test.go index 2784464..883fc0e 100644 --- a/models/game_test.go +++ b/models/game_test.go @@ -34,6 +34,25 @@ var _ = Describe("Game Model", func() { Describe("Saving a game", func() { Describe("Feature", func() { + It("Should create a new game and generate id", func() { + game := &models.Game{ + Name: uuid.NewV4().String(), + DonationCooldownHours: 1, + DonationRequestCooldownHours: 2, + } + err := game.Save(db, logger) + Expect(err).NotTo(HaveOccurred()) + Expect(game.ID).NotTo(BeEmpty()) + + var dbGame *models.Game + err = db.C("games").FindId(game.ID).One(&dbGame) + Expect(err).NotTo(HaveOccurred()) + Expect(dbGame.Name).To(Equal(game.Name)) + Expect(dbGame.ID).To(Equal(game.ID)) + Expect(dbGame.DonationCooldownHours).To(Equal(1)) + Expect(dbGame.DonationRequestCooldownHours).To(Equal(2)) + }) + It("Should create a new game", func() { game := models.NewGame( uuid.NewV4().String(), @@ -110,7 +129,7 @@ var _ = Describe("Game Model", func() { }) Expect(runtime.Seconds()).Should(BeNumerically("<", 0.5), "Operation shouldn't take this long.") - }, 500) + }, 5) Measure("it should update games fast", func(b Benchmarker) { i++ @@ -121,7 +140,7 @@ var _ = Describe("Game Model", func() { }) Expect(runtime.Seconds()).Should(BeNumerically("<", 0.5), "Operation shouldn't take this long.") - }, 500) + }, 5) }) }) @@ -167,7 +186,7 @@ var _ = Describe("Game Model", func() { }) Expect(runtime.Seconds()).Should(BeNumerically("<", 0.5), "Operation shouldn't take this long.") - }, 200) + }, 5) }) }) @@ -274,7 +293,7 @@ var _ = Describe("Game Model", func() { }) Expect(runtime.Seconds()).Should(BeNumerically("<", 0.5), "Operation shouldn't take this long.") - }, 500) + }, 5) }) }) }) diff --git a/models/item.go b/models/item.go index c2ae3f0..df2ef18 100644 --- a/models/item.go +++ b/models/item.go @@ -21,7 +21,7 @@ type Item struct { //This weight counts for the donation cooldown limits of each player WeightPerDonation int `json:"weightPerDonation" bson:"weightPerDonation"` - UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` + UpdatedAt int64 `json:"updatedAt" bson:"updatedAt"` } //NewItem returns a configured new item @@ -37,7 +37,7 @@ func NewItem( WeightPerDonation: weightPerDonation, LimitOfCardsPerPlayerDonation: limitOfCardsPerPlayerDonation, LimitOfCardsInEachDonationRequest: limitOfCardsInEachDonationRequest, - UpdatedAt: time.Now().UTC(), + UpdatedAt: time.Now().UTC().Unix(), } } diff --git a/models/item_easyjson.go b/models/item_easyjson.go index 809fb79..c382d53 100644 --- a/models/item_easyjson.go +++ b/models/item_easyjson.go @@ -59,9 +59,7 @@ func easyjsonA80d3b19DecodeGithubComTopfreegamesDonationsModels(in *jlexer.Lexer case "weightPerDonation": out.WeightPerDonation = int(in.Int()) case "updatedAt": - if data := in.Raw(); in.Ok() { - in.AddError((out.UpdatedAt).UnmarshalJSON(data)) - } + out.UpdatedAt = int64(in.Int64()) default: in.SkipRecursive() } @@ -127,7 +125,7 @@ func easyjsonA80d3b19EncodeGithubComTopfreegamesDonationsModels(out *jwriter.Wri } first = false out.RawString("\"updatedAt\":") - out.Raw((in.UpdatedAt).MarshalJSON()) + out.Int64(int64(in.UpdatedAt)) out.RawByte('}') } diff --git a/models/item_test.go b/models/item_test.go new file mode 100644 index 0000000..1784f2a --- /dev/null +++ b/models/item_test.go @@ -0,0 +1,59 @@ +package models_test + +import ( + mgo "gopkg.in/mgo.v2" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/topfreegames/donations/models" + . "github.com/topfreegames/donations/testing" + "github.com/uber-go/zap" +) + +var _ = Describe("Item Model", func() { + var logger zap.Logger + var session *mgo.Session + var db *mgo.Database + + BeforeEach(func() { + logger = zap.New( + zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests + zap.FatalLevel, + ) + + session, db = GetTestMongoDB() + }) + + AfterEach(func() { + session.Close() + session = nil + db = nil + }) + + Describe("Item Auxiliary Methods", func() { + Describe("Feature", func() { + It("Should parse and serialize to json", func() { + item := &models.Item{ + Key: "some-key", + Metadata: map[string]interface{}{"x": 1}, + LimitOfCardsInEachDonationRequest: 2, + LimitOfCardsPerPlayerDonation: 3, + WeightPerDonation: 4, + UpdatedAt: 400, + } + + r, err := item.ToJSON() + Expect(err).NotTo(HaveOccurred()) + + rr, err := models.GetItemFromJSON(r) + Expect(err).NotTo(HaveOccurred()) + + Expect(rr.Key).To(Equal(item.Key)) + Expect(int(rr.Metadata["x"].(float64))).To(Equal(1)) + Expect(rr.LimitOfCardsInEachDonationRequest).To(BeEquivalentTo(item.LimitOfCardsInEachDonationRequest)) + Expect(rr.LimitOfCardsPerPlayerDonation).To(BeEquivalentTo(item.LimitOfCardsPerPlayerDonation)) + Expect(rr.WeightPerDonation).To(BeEquivalentTo(item.WeightPerDonation)) + }) + }) + }) +})