Skip to content

Commit

Permalink
Huge refactor 😱
Browse files Browse the repository at this point in the history
- offers (previously offer templates) can be updated
- offer instances (previously offers) are unique by player id, offer id and offer version and contain the offer contents and productid
- counters and timestamps of claims and impressions are now in redis
- offers can be claimed without the offer id
  • Loading branch information
cscatolini committed Mar 9, 2017
1 parent 87d76c5 commit d5bad3c
Show file tree
Hide file tree
Showing 38 changed files with 3,776 additions and 3,064 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ start-deps:
stop-deps:
@env MY_IP=${MY_IP} docker-compose --project-name offers down

test: deps unit integration acceptance test-coverage-func
test: deps unit integration test-coverage-func

clear-coverage-profiles:
@find . -name '*.coverprofile' -delete
Expand Down
5 changes: 5 additions & 0 deletions api/api_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ var _ = AfterEach(func() {
err := app.DB.(*runner.Tx).Rollback()
Expect(err).NotTo(HaveOccurred())
app.DB = db
status := app.RedisClient.Client.FlushAll()
Expect(status.Err()).NotTo(HaveOccurred())
})

var _ = AfterSuite(func() {
Expand All @@ -69,6 +71,9 @@ var _ = AfterSuite(func() {
db = nil
}

status := app.RedisClient.Client.FlushAll()
Expect(status.Err()).NotTo(HaveOccurred())

if closer != nil {
closer.Close()
closer = nil
Expand Down
103 changes: 72 additions & 31 deletions api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,22 @@ import (
"github.com/topfreegames/offers/errors"
"github.com/topfreegames/offers/metadata"
"github.com/topfreegames/offers/models"
"github.com/topfreegames/offers/util"
runner "gopkg.in/mgutz/dat.v2/sqlx-runner"
)

//App is our API application
type App struct {
Address string
Debug bool
Router *mux.Router
Server *http.Server
Config *viper.Viper
DB runner.Connection
Logger logrus.FieldLogger
NewRelic newrelic.Application
Clock models.Clock
Address string
Clock models.Clock
Config *viper.Viper
DB runner.Connection
Debug bool
Logger logrus.FieldLogger
NewRelic newrelic.Application
RedisClient *util.RedisClient
Router *mux.Router
Server *http.Server
}

//NewApp ctor
Expand Down Expand Up @@ -89,68 +91,77 @@ func (a *App) getRouter() *mux.Router {
NewValidationMiddleware(func() interface{} { return &models.Game{} }),
).ServeHTTP).Methods("PUT").Name("game")

r.Handle("/templates", Chain(
&OfferTemplateHandler{App: a, Method: "list"},
r.Handle("/offers", Chain(
&OfferHandler{App: a, Method: "list"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
)).Methods("GET").Name("offer_templates")
)).Methods("GET").Name("offers")

r.Handle("/templates", Chain(
&OfferTemplateHandler{App: a, Method: "insert"},
r.Handle("/offers", Chain(
&OfferHandler{App: a, Method: "insert"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
NewValidationMiddleware(func() interface{} { return &models.OfferTemplate{} }),
)).Methods("POST").Name("offer_templates")
NewValidationMiddleware(func() interface{} { return &models.Offer{} }),
)).Methods("POST").Name("offers")

r.Handle("/templates/{id}/enable", Chain(
&OfferTemplateHandler{App: a, Method: "enable"},
r.Handle("/offers/claim", Chain(
&OfferRequestHandler{App: a, Method: "claim"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
NewParamKeyMiddleware(a, govalidator.IsUUIDv4),
)).Methods("PUT").Name("offer_templates")
NewValidationMiddleware(func() interface{} { return &models.ClaimOfferPayload{} }),
)).Methods("PUT").Name("offer-requests")

r.Handle("/templates/{id}/disable", Chain(
&OfferTemplateHandler{App: a, Method: "disable"},
r.Handle("/offers/{id}", Chain(
&OfferHandler{App: a, Method: "update"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
NewParamKeyMiddleware(a, govalidator.IsUUIDv4),
)).Methods("PUT").Name("offer_templates")
NewValidationMiddleware(func() interface{} { return &models.Offer{} }),
)).Methods("PUT").Name("offers")

r.Handle("/offers", Chain(
&OfferRequestHandler{App: a, Method: "get-offers"},
r.Handle("/offers/{id}/enable", Chain(
&OfferHandler{App: a, Method: "enable"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
)).Methods("GET").Name("offers")
NewParamKeyMiddleware(a, govalidator.IsUUIDv4),
)).Methods("PUT").Name("offers")

r.Handle("/offers/{id}/claim", Chain(
&OfferRequestHandler{App: a, Method: "claim"},
r.Handle("/offers/{id}/disable", Chain(
&OfferHandler{App: a, Method: "disable"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
NewParamKeyMiddleware(a, govalidator.IsUUIDv4),
NewValidationMiddleware(func() interface{} { return &models.OfferToUpdate{} }),
)).Methods("PUT").Name("offers")

r.Handle("/available-offers", Chain(
&OfferRequestHandler{App: a, Method: "get-offers"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
)).Methods("GET").Name("offer-requests")

r.HandleFunc("/offers/{id}/impressions", Chain(
&OfferRequestHandler{App: a, Method: "impressions"},
&NewRelicMiddleware{App: a},
&AuthMiddleware{App: a},
&LoggingMiddleware{App: a},
&VersionMiddleware{},
NewParamKeyMiddleware(a, govalidator.IsUUIDv4),
NewValidationMiddleware(func() interface{} { return &models.OfferToUpdate{} }),
).ServeHTTP).Methods("POST").Name("offers")
NewValidationMiddleware(func() interface{} { return &models.OfferImpressionPayload{} }),
).ServeHTTP).Methods("PUT").Name("offer-requests")

return r
}
Expand All @@ -163,6 +174,11 @@ func (a *App) configureApp() error {
return err
}

err = a.configureRedisClient()
if err != nil {
return err
}

err = a.configureNewRelic()
if err != nil {
return err
Expand All @@ -172,6 +188,31 @@ func (a *App) configureApp() error {
return nil
}

func (a *App) configureRedisClient() error {
redisHost := a.Config.GetString("redis.host")
redisPort := a.Config.GetInt("redis.port")
redisPass := a.Config.GetString("redis.password")
redisDB := a.Config.GetInt("redis.db")
redisMaxPoolSize := a.Config.GetInt("redis.maxPoolSize")

l := a.Logger.WithFields(logrus.Fields{
"redis.host": redisHost,
"redis.port": redisPort,
"redis.redisDB": redisDB,
"redis.redisMaxPoolSize": redisMaxPoolSize,
})
l.Debug("Connecting to Redis...")
cli, err := util.GetRedisClient(redisHost, redisPort, redisPass, redisDB, redisMaxPoolSize, a.Logger)
if err != nil {
l.WithError(err).Error("Connection to redis failed.")
return err
}
l.Debug("Successful connection to redis.")
a.RedisClient = cli

return nil
}

func (a *App) configureDatabase() error {
db, err := a.getDB()
if err != nil {
Expand Down
12 changes: 8 additions & 4 deletions api/game_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ var _ = Describe("Game Handler", func() {
})

oldDB := app.DB
defer func() {
app.DB = oldDB // avoid errors in after each
}()
db, err := GetTestDB()
Expect(err).NotTo(HaveOccurred())
app.DB = db
Expand All @@ -158,7 +161,6 @@ var _ = Describe("Game Handler", func() {
Expect(obj["code"]).To(Equal("OFF-004"))
Expect(obj["error"]).To(Equal("Upserting game failed"))
Expect(obj["description"]).To(Equal("sql: database is closed"))
app.DB = oldDB // avoid errors in after each
})
})

Expand All @@ -181,9 +183,9 @@ var _ = Describe("Game Handler", func() {
})

It("should return empty list if no games", func() {
_, err := app.DB.DeleteFrom("offers").Exec()
_, err := app.DB.DeleteFrom("offer_instances").Exec()
Expect(err).NotTo(HaveOccurred())
_, err = app.DB.DeleteFrom("offer_templates").Exec()
_, err = app.DB.DeleteFrom("offers").Exec()
Expect(err).NotTo(HaveOccurred())
_, err = app.DB.DeleteFrom("games").Exec()
Expect(err).NotTo(HaveOccurred())
Expand All @@ -197,6 +199,9 @@ var _ = Describe("Game Handler", func() {

It("should return status code of 500 if some error occurred", func() {
oldDB := app.DB
defer func() {
app.DB = oldDB // avoid errors in after each
}()
db, err := GetTestDB()
Expect(err).NotTo(HaveOccurred())
app.DB = db
Expand All @@ -212,7 +217,6 @@ var _ = Describe("Game Handler", func() {
Expect(obj["code"]).To(Equal("OFF-004"))
Expect(obj["error"]).To(Equal("List games failed."))
Expect(obj["description"]).To(Equal("sql: database is closed"))
app.DB = oldDB // avoid errors in after each
})
})
})
4 changes: 3 additions & 1 deletion api/healthcheck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ var _ = Describe("Healthcheck Handler", func() {

It("returns status code of 500 if database is unavailable", func() {
oldDB := app.DB
defer func() {
app.DB = oldDB // avoid errors in after each
}()
db, err := GetTestDB()
Expect(err).NotTo(HaveOccurred())
app.DB = db
Expand All @@ -64,7 +67,6 @@ var _ = Describe("Healthcheck Handler", func() {
Expect(obj["code"]).To(Equal("OFF-000"))
Expect(obj["error"]).To(Equal("DatabaseError"))
Expect(obj["description"]).To(Equal("sql: database is closed"))
app.DB = oldDB // avoid errors in after each
})
})
})
Expand Down
Loading

0 comments on commit d5bad3c

Please sign in to comment.