From 0ea3f7907add1e877efcf9e442b19dab659e7cc8 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Sun, 4 Aug 2024 21:43:37 -0300 Subject: [PATCH 001/141] feat(structure): create initial project structure This commit adds the initial project structure along with the initial configuration of the server initialization with graceful shutdown. It includes the following: - Added a commons package with some JSON wrapping utility functions. - Initialized the model package (currently empty). - Created a Dockerfile and Docker Compose setup for the Redis database (for caching) and the PostgreSQL database (for persistent storage). - Added a readiness endpoint for health checks. --- .gitignore | 2 + Dockerfile | 17 ++++++++ Makefile | 41 ++++++++++++++++++ cmd/api/main.go | 22 ++++++++++ docker-compose.yml | 32 ++++++++++++++ go.mod | 8 ++++ go.sum | 4 ++ internal/commons/json.go | 31 ++++++++++++++ internal/handler/readiness_handler.go | 11 +++++ internal/model/currency.go | 1 + internal/model/users.go | 1 + internal/server/routes.go | 19 +++++++++ internal/server/server.go | 61 +++++++++++++++++++++++++++ 13 files changed, 250 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 cmd/api/main.go create mode 100644 docker-compose.yml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/commons/json.go create mode 100644 internal/handler/readiness_handler.go create mode 100644 internal/model/currency.go create mode 100644 internal/model/users.go create mode 100644 internal/server/routes.go create mode 100644 internal/server/server.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..724430518 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +/dist/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..f68a4aafe --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Dockerfile +FROM golang:1.22-alpine + +WORKDIR /app + +COPY go.mod . +COPY go.sum . + +RUN go mod download + +COPY . . + +RUN go build -o main cmd/main.go + +EXPOSE 8080 + +CMD ["./main"] diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..1892349e0 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +# Simple Makefile for a Go project + +# Build the application +all: build + +build: + @echo "Building..." + @go build -o main cmd/api/main.go + +# Run the application +run: + @go run cmd/api/main.go + +# Test the application +test: + @echo "Testing..." + @go test ./tests -v + +# Clean the binary +clean: + @echo "Cleaning..." + @rm -f main + +# Live Reload +watch: + @if [ -x "$(GOPATH)/bin/air" ]; then \ + "$(GOPATH)/bin/air"; \ + @echo "Watching...";\ + else \ + read -p "air is not installed. Do you want to install it now? (y/n) " choice; \ + if [ "$$choice" = "y" ]; then \ + go install github.com/cosmtrek/air@latest; \ + "$(GOPATH)/bin/air"; \ + @echo "Watching...";\ + else \ + echo "You chose not to install air. Exiting..."; \ + exit 1; \ + fi; \ + fi + +.PHONY: all build run test clean diff --git a/cmd/api/main.go b/cmd/api/main.go new file mode 100644 index 000000000..a66de4a2c --- /dev/null +++ b/cmd/api/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "context" + "os" + "os/signal" + + "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/joho/godotenv" +) + +func main() { + godotenv.Load(".env") + srv := server.NewServer() + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + err := srv.Start(ctx) + if err != nil { + panic(err) + } + +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..855f97a3c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +version: "3.8" + +services: + app: + build: . + ports: + - "8081:8080" + depends_on: + - redis + - db + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD} + - DB_HOST=${POSTGRES_HOST} + - DB_USER=${POSTGRES_USER} + - DB_PASSWORD=${POSTGRES_PASSWORD} + - DB_NAME=${POSTGRES_NAME} + - DB_PORT=5432 + + redis: + image: redis:alpine + command: redis-server --requirepass ${REDIS_PASSWORD} + ports: + - "6379:6379" + + db: + image: postgres:alpine + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_NAME} + ports: + - "5432:5432" diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..b9c1733b7 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/Lutefd/challenge-bravo + +go 1.22.3 + +require ( + github.com/go-chi/chi/v5 v5.1.0 + github.com/joho/godotenv v1.5.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..989981bb7 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/internal/commons/json.go b/internal/commons/json.go new file mode 100644 index 000000000..ab1571841 --- /dev/null +++ b/internal/commons/json.go @@ -0,0 +1,31 @@ +package commons + +import ( + "encoding/json" + "log" + "net/http" +) + +func RespondWithError(w http.ResponseWriter, code int, msg string) { + if code > 499 { + log.Printf("Responding with 5XX error: %s", msg) + } + type errorResponse struct { + Error string `json:"error"` + } + RespondWithJSON(w, code, errorResponse{ + Error: msg, + }) +} + +func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) { + w.Header().Set("Content-Type", "application/json") + dat, err := json.Marshal(payload) + if err != nil { + log.Printf("Error marshalling JSON: %s", err) + w.WriteHeader(500) + return + } + w.WriteHeader(code) + w.Write(dat) +} diff --git a/internal/handler/readiness_handler.go b/internal/handler/readiness_handler.go new file mode 100644 index 000000000..2becf8198 --- /dev/null +++ b/internal/handler/readiness_handler.go @@ -0,0 +1,11 @@ +package handler + +import ( + "net/http" + + "github.com/Lutefd/challenge-bravo/internal/commons" +) + +func HandlerReadiness(w http.ResponseWriter, r *http.Request) { + commons.RespondWithJSON(w, http.StatusOK, map[string]string{"status": "ok"}) +} diff --git a/internal/model/currency.go b/internal/model/currency.go new file mode 100644 index 000000000..8b5379070 --- /dev/null +++ b/internal/model/currency.go @@ -0,0 +1 @@ +package model diff --git a/internal/model/users.go b/internal/model/users.go new file mode 100644 index 000000000..8b5379070 --- /dev/null +++ b/internal/model/users.go @@ -0,0 +1 @@ +package model diff --git a/internal/server/routes.go b/internal/server/routes.go new file mode 100644 index 000000000..dd310eb7a --- /dev/null +++ b/internal/server/routes.go @@ -0,0 +1,19 @@ +package server + +import ( + "github.com/Lutefd/challenge-bravo/internal/handler" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +func (s *Server) registerRoutes() { + router := chi.NewRouter() + router.Use(middleware.Logger) + router.Get("/healthz", handler.HandlerReadiness) + router.Route("/currency", s.loadCurrencyRoutes) + + s.router = router +} + +func (s *Server) loadCurrencyRoutes(router chi.Router) { +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 000000000..a364a1481 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,61 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "os" + "strconv" + "time" +) + +type Server struct { + port int + router http.Handler +} + +func NewServer() *Server { + strPort := os.Getenv("SERVER_PORT") + if strPort == "" { + fmt.Println("port environment variable was not setted") + } + port, err := strconv.Atoi(strPort) + if err != nil { + panic(err) + } + server := &Server{ + port: port, + } + server.registerRoutes() + return server +} + +func (s *Server) Start(ctx context.Context) error { + fmt.Println("Starting server on port 8080") + ch := make(chan error, 1) + server := &http.Server{ + Addr: fmt.Sprintf(":%d", s.port), + Handler: s.router, + IdleTimeout: time.Minute, + ReadTimeout: 10 * time.Second, + WriteTimeout: 30 * time.Second, + } + + var err error + go func() { + err := server.ListenAndServe() + if err != nil { + ch <- fmt.Errorf("failed to start server: %w", err) + } + close(ch) + }() + select { + case err = <-ch: + return err + case <-ctx.Done(): + _, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + return server.Shutdown(ctx) + } +} From b784022c9ee4e0bf3c30b1443a73a017d1218f7b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 09:22:42 -0300 Subject: [PATCH 002/141] feat(model): create currency and exchange rates model This commit adds the data models for the currency and exchange rate entities --- internal/model/currency.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/internal/model/currency.go b/internal/model/currency.go index 8b5379070..ea52bf304 100644 --- a/internal/model/currency.go +++ b/internal/model/currency.go @@ -1 +1,19 @@ package model + +import ( + "time" +) + +type Currency struct { + Code string `json:"code"` + Rate float64 `json:"rate"` + UpdatedAt time.Time `json:"updated_at"` +} + +type ExchangeRates struct { + Disclaimer string `json:"disclaimer"` + License string `json:"license"` + Timestamp int64 `json:"timestamp"` + Base string `json:"base"` + Rates map[string]float64 `json:"rates"` +} From 939b176e6abd39c6193f9e380b5eb72e311d5b8d Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 09:26:50 -0300 Subject: [PATCH 003/141] feat(repository): create currency repository interface This commit adds the initial Currency Repository interface with the following methods: - GetByCode: will receive the currency code and return its value or an error. - Create: will receive the currency data and create the currency entry and will return either nil or an error. - Update: will receive the currency data and update a currency and will return either nil or an error. - Delete: will receive the currency code delete a currency entry and will return either nil or an error. This is an initial layout of the currency repository, it could change during the development proccess --- internal/repository/repository.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 internal/repository/repository.go diff --git a/internal/repository/repository.go b/internal/repository/repository.go new file mode 100644 index 000000000..fe25f1752 --- /dev/null +++ b/internal/repository/repository.go @@ -0,0 +1,14 @@ +package repository + +import ( + "context" + + "github.com/Lutefd/challenge-bravo/internal/model" +) + +type CurrencyRepository interface { + GetByCode(ctx context.Context, code string) (*model.Currency, error) + Create(ctx context.Context, currency *model.Currency) error + Update(ctx context.Context, currency *model.Currency) error + Delete(ctx context.Context, code string) error +} From 379e89f5accf60d4e79d0ba6a08e32c4a4954da0 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 09:52:39 -0300 Subject: [PATCH 004/141] feat(service): create currency service and its initial implementation This commit adds the initial implementation of the currency service with the following methods: - Convert: Converts an amount from one currency to another. - getRate: Retrieves the exchange rate for a given currency, using the cache, repository, or external API as needed. - AddCurrency: Placeholder for adding a new currency (not yet implemented). - RemoveCurrency: Placeholder for removing an existing currency (not yet implemented). --- internal/service/currency_service.go | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 internal/service/currency_service.go diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go new file mode 100644 index 000000000..81a704dfa --- /dev/null +++ b/internal/service/currency_service.go @@ -0,0 +1,85 @@ +package service + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/Lutefd/challenge-bravo/internal/worker" +) + +type CurrencyService struct { + repo repository.CurrencyRepository + cache cache.Cache + externalAPI worker.ExternalAPIClient +} + +func NewCurrencyService(repo repository.CurrencyRepository, cache cache.Cache, externalAPI worker.ExternalAPIClient) *CurrencyService { + return &CurrencyService{ + repo: repo, + cache: cache, + externalAPI: externalAPI, + } +} + +func (s *CurrencyService) Convert(ctx context.Context, from, to string, amount float64) (float64, error) { + fromRate, err := s.getRate(ctx, from) + if err != nil { + return 0, err + } + + toRate, err := s.getRate(ctx, to) + if err != nil { + return 0, err + } + usdAmount := amount / fromRate + result := usdAmount * toRate + + return result, nil +} + +func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, error) { + rate, err := s.cache.Get(ctx, code) + if err == nil { + return rate, nil + } + currency, err := s.repo.GetByCode(ctx, code) + if err == nil { + s.cache.Set(ctx, code, currency.Rate, 1*time.Hour) + return currency.Rate, nil + } + rates, err := s.externalAPI.FetchRates(ctx) + if err != nil { + return 0, err + } + + rate, ok := rates.Rates[code] + if !ok { + return 0, fmt.Errorf("currency %s not found", code) + } + currency = &model.Currency{ + Code: code, + Rate: rate, + UpdatedAt: time.Now(), + } + err = s.repo.Create(ctx, currency) + if err != nil { + return 0, err + } + + s.cache.Set(ctx, code, rate, 1*time.Hour) + + return rate, nil +} + +func (s *CurrencyService) AddCurrency(ctx context.Context, code string, rate float64) error { + return errors.New("not implemented") +} + +func (s *CurrencyService) RemoveCurrency(ctx context.Context, code string) error { + return errors.New("not implemented") +} From bb29417c12040b0967ce36eb6de1ef645119ebea Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 09:56:23 -0300 Subject: [PATCH 005/141] feat(handler): create currency handler and its initial implementation This commit adds the initial implementation of the currency handler with the following methods: - ConvertCurrency: Handles HTTP requests to convert an amount from one currency to another. - AddCurrency: Placeholder for handling HTTP requests to add a new currency (not yet implemented). - RemoveCurrency: Placeholder for handling HTTP requests to remove an existing currency (not yet implemented). --- internal/handler/currency_handler.go | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 internal/handler/currency_handler.go diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go new file mode 100644 index 000000000..14e02f131 --- /dev/null +++ b/internal/handler/currency_handler.go @@ -0,0 +1,57 @@ +package handler + +import ( + "net/http" + "strconv" + + "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/service" +) + +type CurrencyHandler struct { + currencyService *service.CurrencyService +} + +func NewCurrencyHandler(currencyService *service.CurrencyService) *CurrencyHandler { + return &CurrencyHandler{ + currencyService: currencyService, + } +} + +func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request) { + from := r.URL.Query().Get("from") + to := r.URL.Query().Get("to") + amountStr := r.URL.Query().Get("amount") + + if from == "" || to == "" || amountStr == "" { + commons.RespondWithError(w, http.StatusBadRequest, "Missing required parameters") + return + } + + amount, err := strconv.ParseFloat(amountStr, 64) + if err != nil { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid amount") + return + } + + result, err := h.currencyService.Convert(r.Context(), from, to, amount) + if err != nil { + commons.RespondWithError(w, http.StatusInternalServerError, "Conversion failed") + return + } + + commons.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ + "from": from, + "to": to, + "amount": amount, + "result": result, + }) +} + +func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { + // TODO: Implement adding a new currency +} + +func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) { + // TODO: Implement removing a currency +} From 87de538f0152fb73821c515d1a118174b6df2341 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 09:58:40 -0300 Subject: [PATCH 006/141] feat(cache): create cache package and define its interface This commit defines the cache interface with the following methods: - Get: Retrieves a value from the cache by key. - Set: Stores a value in the cache with a specified expiration time. - Delete: Removes a value from the cache by key. --- internal/cache/redis_cache.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 internal/cache/redis_cache.go diff --git a/internal/cache/redis_cache.go b/internal/cache/redis_cache.go new file mode 100644 index 000000000..6fd86e4d2 --- /dev/null +++ b/internal/cache/redis_cache.go @@ -0,0 +1,12 @@ +package cache + +import ( + "context" + "time" +) + +type Cache interface { + Get(ctx context.Context, key string) (float64, error) + Set(ctx context.Context, key string, value float64, expiration time.Duration) error + Delete(ctx context.Context, key string) error +} From 4a1140d5d5939647be5a7eda68566fe76d5e0a1d Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:00:30 -0300 Subject: [PATCH 007/141] feat(worker): create worker package and define the external api interface This commit creates the worker package that will interact with the external exchange rate api and fetch it in the background. --- internal/worker/external_api.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 internal/worker/external_api.go diff --git a/internal/worker/external_api.go b/internal/worker/external_api.go new file mode 100644 index 000000000..bf09bf153 --- /dev/null +++ b/internal/worker/external_api.go @@ -0,0 +1,11 @@ +package worker + +import ( + "context" + + "github.com/Lutefd/challenge-bravo/internal/model" +) + +type ExternalAPIClient interface { + FetchRates(ctx context.Context) (*model.ExchangeRates, error) +} From 56e215a8ecf7b0367bcd62e7d5d5012fd4666ff1 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:02:53 -0300 Subject: [PATCH 008/141] feat(server): create config struct and its loader for server setup This commit adds the implementation for loading server configuration from environment variables with the following fields: - PostgresConn: Connection string for PostgreSQL database. - RedisAddr: Address for the Redis server. - RedisPass: Password for the Redis server. - ServerPort: Port on which the server will run. --- internal/server/config.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 internal/server/config.go diff --git a/internal/server/config.go b/internal/server/config.go new file mode 100644 index 000000000..309fc11b1 --- /dev/null +++ b/internal/server/config.go @@ -0,0 +1,31 @@ +package server + +import ( + "os" + "strconv" +) + +type Config struct { + PostgresConn string + RedisAddr string + RedisPass string + ServerPort uint16 +} + +func LoadConfig() Config { + redisPassword := os.Getenv("REDIS_PASSWORD") + redisAddr := os.Getenv("REDIS_ADDR") + serverPort := os.Getenv("SERVER_PORT") + postgresConn := os.Getenv("POSTGRES_CONN") + parsedServerPort, err := strconv.ParseUint(serverPort, 10, 16) + if err != nil { + panic(err) + } + + return Config{ + PostgresConn: postgresConn, + RedisAddr: redisAddr, + RedisPass: redisPassword, + ServerPort: uint16(parsedServerPort), + } +} From c8d33cbf3abeb9e3b921fc13410a302e82dd322a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:08:56 -0300 Subject: [PATCH 009/141] refactor(server): update server initialization to use configuration struct This commit refactors the server initialization to use a configuration struct, removing the direct environment variable fetching. Changes include: - Using the Config struct to pass server configuration. - Removing the direct environment variable fetching for the server port within NewServer. - Incorporating the config parameter in the NewServer function for cleaner initialization. --- internal/server/server.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index a364a1481..398305363 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -5,26 +5,23 @@ import ( "fmt" "net/http" "os" - "strconv" "time" ) type Server struct { port int router http.Handler + config Config } -func NewServer() *Server { +func NewServer(config Config) *Server { strPort := os.Getenv("SERVER_PORT") if strPort == "" { fmt.Println("port environment variable was not setted") } - port, err := strconv.Atoi(strPort) - if err != nil { - panic(err) - } server := &Server{ - port: port, + port: int(config.ServerPort), + config: config, } server.registerRoutes() return server From 818ae973dca8f1f89283be7e641f17f65f3b8f00 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:09:32 -0300 Subject: [PATCH 010/141] refactor(main): update server initialization to load configuration This commit refactors the main function to load server configuration using the LoadConfig function. --- cmd/api/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index a66de4a2c..5aba01b75 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -11,7 +11,7 @@ import ( func main() { godotenv.Load(".env") - srv := server.NewServer() + srv := server.NewServer(server.LoadConfig()) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() err := srv.Start(ctx) From 3b96363ad411f7382f06343f6a51b4be00c08f3e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:12:26 -0300 Subject: [PATCH 011/141] feat(routes): add currency routes and handlers to server This commit adds the currency routes and their corresponding handlers to the server. Changes include: - Importing the service package for initializing CurrencyService. - Initializing CurrencyService and CurrencyHandler in the loadCurrencyRoutes function. - Adding the following routes to the server: - GET /convert: Route to convert currency. - POST /: Route to add a new currency. - DELETE /{code}: Route to remove an existing currency. --- internal/server/routes.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/server/routes.go b/internal/server/routes.go index dd310eb7a..b9fd2ec64 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -2,6 +2,7 @@ package server import ( "github.com/Lutefd/challenge-bravo/internal/handler" + "github.com/Lutefd/challenge-bravo/internal/service" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) @@ -16,4 +17,10 @@ func (s *Server) registerRoutes() { } func (s *Server) loadCurrencyRoutes(router chi.Router) { + currencyService := service.NewCurrencyService() + currencyHandler := handler.NewCurrencyHandler(currencyService) + + router.Get("/convert", currencyHandler.ConvertCurrency) + router.Post("/", currencyHandler.AddCurrency) + router.Delete("/{code}", currencyHandler.RemoveCurrency) } From 06331724c4c667c0fbe3efa6f812da2d87526d0a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:17:14 -0300 Subject: [PATCH 012/141] refactor(cache): rename redis_cache.go to cache.go This commit renames the file redis_cache.go to cache.go since it's only defining the cache interface and I will use the redis_cache file to implement the caching through redis. --- internal/cache/{redis_cache.go => cache.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/cache/{redis_cache.go => cache.go} (100%) diff --git a/internal/cache/redis_cache.go b/internal/cache/cache.go similarity index 100% rename from internal/cache/redis_cache.go rename to internal/cache/cache.go From 72facf8f01465676b244244dcfd3004094f793b4 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:22:16 -0300 Subject: [PATCH 013/141] chore(modules): add PostgreSQL and Redis client libraries This commit updates the go.mod and the go.sum files to include additional dependencies for the PostgreSQL and Redis client libraries, along with tidying up the files. --- go.mod | 10 ++++++++++ go.sum | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/go.mod b/go.mod index b9c1733b7..5697c5f41 100644 --- a/go.mod +++ b/go.mod @@ -6,3 +6,13 @@ require ( github.com/go-chi/chi/v5 v5.1.0 github.com/joho/godotenv v1.5.1 ) + +require ( + github.com/lib/pq v1.10.9 + github.com/redis/go-redis/v9 v9.6.1 +) + +require ( + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect +) diff --git a/go.sum b/go.sum index 989981bb7..60e799879 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,16 @@ +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= From 1b2a85f1c776aa907b9c06ce11efc00e2f8f2c3a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:36:27 -0300 Subject: [PATCH 014/141] refactor(config): improve configuration loading with error handling This commit enhances the configuration loading by adding error handling and validation for required environment variables. Changes include: - Adding the APIKey field to the Config struct. - Modifying LoadConfig to return an error if required environment variables are not set. - Adding validation for REDIS_PASSWORD, REDIS_ADDR, POSTGRES_CONN, API_KEY, and SERVER_PORT environment variables. - Returning detailed error messages if any configuration values are missing or invalid. --- internal/server/config.go | 54 ++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/internal/server/config.go b/internal/server/config.go index 309fc11b1..2884d7459 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -1,6 +1,7 @@ package server import ( + "fmt" "os" "strconv" ) @@ -10,22 +11,51 @@ type Config struct { RedisAddr string RedisPass string ServerPort uint16 + APIKey string } -func LoadConfig() Config { - redisPassword := os.Getenv("REDIS_PASSWORD") - redisAddr := os.Getenv("REDIS_ADDR") +func LoadConfig() (Config, error) { + var config Config + var errors []string + + config.RedisPass = os.Getenv("REDIS_PASSWORD") + if config.RedisPass == "" { + errors = append(errors, "REDIS_PASSWORD is not set") + } + + config.RedisAddr = os.Getenv("REDIS_ADDR") + if config.RedisAddr == "" { + errors = append(errors, "REDIS_ADDR is not set") + } + + config.PostgresConn = os.Getenv("POSTGRES_CONN") + if config.PostgresConn == "" { + errors = append(errors, "POSTGRES_CONN is not set") + } + + config.APIKey = os.Getenv("API_KEY") + if config.APIKey == "" { + errors = append(errors, "API_KEY is not set") + } + serverPort := os.Getenv("SERVER_PORT") - postgresConn := os.Getenv("POSTGRES_CONN") - parsedServerPort, err := strconv.ParseUint(serverPort, 10, 16) - if err != nil { - panic(err) + if serverPort == "" { + errors = append(errors, "SERVER_PORT is not set") + } else { + parsedServerPort, err := strconv.ParseUint(serverPort, 10, 16) + if err != nil { + errors = append(errors, fmt.Sprintf("Invalid SERVER_PORT: %s", err)) + } else { + config.ServerPort = uint16(parsedServerPort) + } } - return Config{ - PostgresConn: postgresConn, - RedisAddr: redisAddr, - RedisPass: redisPassword, - ServerPort: uint16(parsedServerPort), + if len(errors) > 0 { + for _, err := range errors { + fmt.Println("Configuration Error:", err) + } + return Config{}, fmt.Errorf("configuration errors occurred") } + + return config, nil } From 9c74cc644bee13b884f329991c13e5fb356d1df2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:37:27 -0300 Subject: [PATCH 015/141] refactor(main): improve configuration loading and error handling in main This commit enhances the main function by adding error handling for configuration loading. Changes include: - Logging an error message and terminating the program if configuration loading fails. - Updating the server initialization to use the loaded configuration. - Ensuring proper error handling in the server startup process. --- cmd/api/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 5aba01b75..ab54838f9 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "log" "os" "os/signal" @@ -11,10 +12,14 @@ import ( func main() { godotenv.Load(".env") - srv := server.NewServer(server.LoadConfig()) + config, err := server.LoadConfig() + if err != nil { + log.Fatalf("Failed to load configuration: %v", err) + } + srv := server.NewServer(config) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() - err := srv.Start(ctx) + err = srv.Start(ctx) if err != nil { panic(err) } From 1219c127b1f8b27892e4fbf0cf549f7fafb8328d Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:38:58 -0300 Subject: [PATCH 016/141] feat(repository): add PostgreSQL currency repository implementation This commit adds the implementation of the PostgreSQL currency repository with the following methods: - NewPostgresCurrencyRepository: Initializes a new PostgresCurrencyRepository with a given connection URL. - GetByCode: Retrieves a currency by its code from the database. - Create: Inserts a new currency into the database. - Update: Updates an existing currency in the database. - Delete: Deletes a currency from the database by its code. --- internal/repository/pg_currency_repository.go | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 internal/repository/pg_currency_repository.go diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go new file mode 100644 index 000000000..f045b1b14 --- /dev/null +++ b/internal/repository/pg_currency_repository.go @@ -0,0 +1,68 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + + "github.com/Lutefd/challenge-bravo/internal/model" + _ "github.com/lib/pq" +) + +type PostgresCurrencyRepository struct { + db *sql.DB +} + +func NewPostgresCurrencyRepository(connURL string) (*PostgresCurrencyRepository, error) { + db, err := sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } + + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } + + return &PostgresCurrencyRepository{db: db}, nil +} + +func (r *PostgresCurrencyRepository) GetByCode(ctx context.Context, code string) (*model.Currency, error) { + query := `SELECT code, rate, updated_at FROM currencies WHERE code = $1` + var currency model.Currency + err := r.db.QueryRowContext(ctx, query, code).Scan(¤cy.Code, ¤cy.Rate, ¤cy.UpdatedAt) + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("currency not found") + } + return nil, fmt.Errorf("failed to get currency: %w", err) + } + return ¤cy, nil +} + +func (r *PostgresCurrencyRepository) Create(ctx context.Context, currency *model.Currency) error { + query := `INSERT INTO currencies (code, rate, updated_at) VALUES ($1, $2, $3)` + _, err := r.db.ExecContext(ctx, query, currency.Code, currency.Rate, currency.UpdatedAt) + if err != nil { + return fmt.Errorf("failed to create currency: %w", err) + } + return nil +} + +func (r *PostgresCurrencyRepository) Update(ctx context.Context, currency *model.Currency) error { + query := `UPDATE currencies SET rate = $2, updated_at = $3 WHERE code = $1` + _, err := r.db.ExecContext(ctx, query, currency.Code, currency.Rate, currency.UpdatedAt) + if err != nil { + return fmt.Errorf("failed to update currency: %w", err) + } + return nil +} + +func (r *PostgresCurrencyRepository) Delete(ctx context.Context, code string) error { + query := `DELETE FROM currencies WHERE code = $1` + _, err := r.db.ExecContext(ctx, query, code) + if err != nil { + return fmt.Errorf("failed to delete currency: %w", err) + } + return nil +} From 891c1ce19bb4508c74d36046ca8457fdd654e346 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 10:40:02 -0300 Subject: [PATCH 017/141] feat(cache): add Redis cache implementation This commit adds the implementation of the Redis cache with the following methods: - NewRedisCache: Initializes a new RedisCache with a given address and password. - Get: Retrieves a value from the cache by key, returning an error if the key is not found or if retrieval fails. - Set: Stores a value in the cache with a specified expiration time, returning an error if the operation fails. - Delete: Removes a value from the cache by key, returning an error if the operation fails. --- internal/cache/redis_cache.go | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 internal/cache/redis_cache.go diff --git a/internal/cache/redis_cache.go b/internal/cache/redis_cache.go new file mode 100644 index 000000000..1f2de851c --- /dev/null +++ b/internal/cache/redis_cache.go @@ -0,0 +1,62 @@ +package cache + +import ( + "context" + "fmt" + "strconv" + "time" + + "github.com/redis/go-redis/v9" +) + +type RedisCache struct { + client *redis.Client +} + +func NewRedisCache(addr, password string) (*RedisCache, error) { + client := redis.NewClient(&redis.Options{ + Addr: addr, + Password: password, + DB: 0, + }) + + _, err := client.Ping(context.Background()).Result() + if err != nil { + return nil, fmt.Errorf("failed to connect to Redis: %w", err) + } + + return &RedisCache{client: client}, nil +} + +func (c *RedisCache) Get(ctx context.Context, key string) (float64, error) { + val, err := c.client.Get(ctx, key).Result() + if err != nil { + if err == redis.Nil { + return 0, fmt.Errorf("key not found") + } + return 0, fmt.Errorf("failed to get from cache: %w", err) + } + + rate, err := strconv.ParseFloat(val, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse cached value: %w", err) + } + + return rate, nil +} + +func (c *RedisCache) Set(ctx context.Context, key string, value float64, expiration time.Duration) error { + err := c.client.Set(ctx, key, value, expiration).Err() + if err != nil { + return fmt.Errorf("failed to set in cache: %w", err) + } + return nil +} + +func (c *RedisCache) Delete(ctx context.Context, key string) error { + err := c.client.Del(ctx, key).Err() + if err != nil { + return fmt.Errorf("failed to delete from cache: %w", err) + } + return nil +} From 8e82a3695ddc1506e235eb49ba6a454029a8fa8e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:00:26 -0300 Subject: [PATCH 018/141] feat(worker): add OpenExchangeRates API client implementation This commit adds the implementation of the OpenExchangeRates API client with the following methods: - NewOpenExchangeRatesClient: Initializes a new OpenExchangeRatesClient with a given API key. - FetchRates: Fetches the latest exchange rates from the OpenExchangeRates API, handling HTTP requests and responses, and returns the exchange rates. --- internal/worker/external_api_client.go | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 internal/worker/external_api_client.go diff --git a/internal/worker/external_api_client.go b/internal/worker/external_api_client.go new file mode 100644 index 000000000..55f1c2883 --- /dev/null +++ b/internal/worker/external_api_client.go @@ -0,0 +1,49 @@ +package worker + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/Lutefd/challenge-bravo/internal/model" +) + +type OpenExchangeRatesClient struct { + apiKey string + client *http.Client +} + +func NewOpenExchangeRatesClient(apiKey string) *OpenExchangeRatesClient { + return &OpenExchangeRatesClient{ + apiKey: apiKey, + client: &http.Client{}, + } +} + +func (c *OpenExchangeRatesClient) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { + url := fmt.Sprintf("https://openexchangerates.org/api/latest.json?app_id=%s", c.apiKey) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + resp, err := c.client.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to send request: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("API request failed with status code: %d", resp.StatusCode) + } + + var rates model.ExchangeRates + err = json.NewDecoder(resp.Body).Decode(&rates) + if err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + + return &rates, nil +} From 8edef47b4cf20e598a25b9d59447be2d5e02838b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:01:24 -0300 Subject: [PATCH 019/141] feat(worker): add rate updater implementation This commit adds the implementation of the rate updater with the following functionality: - NewRateUpdater: Initializes a new RateUpdater with the given repository, cache, external API client, and update interval. - Start: Begins the periodic updating of exchange rates using a ticker and context for graceful shutdown. - updateRates: Fetches the latest exchange rates from the external API and updates the repository and cache with the new rates. --- internal/worker/rate_updater.go | 71 +++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 internal/worker/rate_updater.go diff --git a/internal/worker/rate_updater.go b/internal/worker/rate_updater.go new file mode 100644 index 000000000..8a4de6d53 --- /dev/null +++ b/internal/worker/rate_updater.go @@ -0,0 +1,71 @@ +package worker + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" +) + +type RateUpdater struct { + repo repository.CurrencyRepository + cache cache.Cache + externalAPI ExternalAPIClient + interval time.Duration +} + +func NewRateUpdater(repo repository.CurrencyRepository, cache cache.Cache, externalAPI ExternalAPIClient, interval time.Duration) *RateUpdater { + return &RateUpdater{ + repo: repo, + cache: cache, + externalAPI: externalAPI, + interval: interval, + } +} + +func (ru *RateUpdater) Start(ctx context.Context) { + ticker := time.NewTicker(ru.interval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + log.Println("Rate updater stopped") + return + case <-ticker.C: + if err := ru.updateRates(ctx); err != nil { + log.Printf("Error updating rates: %v", err) + } + } + } +} + +func (ru *RateUpdater) updateRates(ctx context.Context) error { + rates, err := ru.externalAPI.FetchRates(ctx) + if err != nil { + return fmt.Errorf("failed to fetch rates: %w", err) + } + + for code, rate := range rates.Rates { + currency := &model.Currency{ + Code: code, + Rate: rate, + UpdatedAt: time.Unix(rates.Timestamp, 0), + } + + if err := ru.repo.Update(ctx, currency); err != nil { + log.Printf("Failed to update currency %s in repository: %v", code, err) + } + + if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { + log.Printf("Failed to update currency %s in cache: %v", code, err) + } + } + + log.Println("Rates updated successfully") + return nil +} From 720d66379270835a8cd6f2a7b3582b916412d284 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:08:09 -0300 Subject: [PATCH 020/141] feat(handler): implement AddCurrency and RemoveCurrency endpoints This commit adds the implementation for the AddCurrency and RemoveCurrency endpoints in the CurrencyHandler. --- internal/handler/currency_handler.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index 14e02f131..dcf662e7e 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -1,11 +1,13 @@ package handler import ( + "encoding/json" "net/http" "strconv" "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/service" + "github.com/go-chi/chi/v5" ) type CurrencyHandler struct { @@ -49,9 +51,31 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request } func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { - // TODO: Implement adding a new currency + var currency struct { + Code string `json:"code"` + Rate float64 `json:"rate"` + } + + if err := json.NewDecoder(r.Body).Decode(¤cy); err != nil { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid request payload") + return + } + + if err := h.currencyService.AddCurrency(r.Context(), currency.Code, currency.Rate); err != nil { + commons.RespondWithError(w, http.StatusInternalServerError, "Failed to add currency") + return + } + + commons.RespondWithJSON(w, http.StatusCreated, map[string]string{"message": "Currency added successfully"}) } func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) { - // TODO: Implement removing a currency + code := chi.URLParam(r, "code") + + if err := h.currencyService.RemoveCurrency(r.Context(), code); err != nil { + commons.RespondWithError(w, http.StatusInternalServerError, "Failed to remove currency") + return + } + + commons.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "Currency removed successfully"}) } From 7bb8a6cfb0612832e0b4aa5a65a7ed43c0209a0c Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:40:15 -0300 Subject: [PATCH 021/141] feat(cache): define and implement Close connection method This committ defines and implements a Close method on the Cache interface for closing the connection to redis. --- internal/cache/cache.go | 1 + internal/cache/redis_cache.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 6fd86e4d2..c32d7477c 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -9,4 +9,5 @@ type Cache interface { Get(ctx context.Context, key string) (float64, error) Set(ctx context.Context, key string, value float64, expiration time.Duration) error Delete(ctx context.Context, key string) error + Close() error } diff --git a/internal/cache/redis_cache.go b/internal/cache/redis_cache.go index 1f2de851c..14ee7edc0 100644 --- a/internal/cache/redis_cache.go +++ b/internal/cache/redis_cache.go @@ -60,3 +60,7 @@ func (c *RedisCache) Delete(ctx context.Context, key string) error { } return nil } + +func (c *RedisCache) Close() error { + return c.client.Close() +} From d5b668e73db8481962bb996fa048413a273d9b49 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:41:21 -0300 Subject: [PATCH 022/141] feat(repository): define and implement Close connection method This commit define and implements the Close method on the currency repository interface for closing the Postgres Connection. --- internal/repository/pg_currency_repository.go | 4 ++++ internal/repository/repository.go | 1 + 2 files changed, 5 insertions(+) diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index f045b1b14..54431f835 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -66,3 +66,7 @@ func (r *PostgresCurrencyRepository) Delete(ctx context.Context, code string) er } return nil } + +func (r *PostgresCurrencyRepository) Close() error { + return r.db.Close() +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index fe25f1752..fdf6cc21e 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -11,4 +11,5 @@ type CurrencyRepository interface { Create(ctx context.Context, currency *model.Currency) error Update(ctx context.Context, currency *model.Currency) error Delete(ctx context.Context, code string) error + Close() error } From 3356b68c69918fa9068f4690f885f334202b3ba2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:43:00 -0300 Subject: [PATCH 023/141] feat(logger): add centralized logging utility This commit adds a centralized logging utility with separate loggers for informational and error messages. The following functionalities are included: - Info: Logs informational messages. - Infof: Logs formatted informational messages. - Error: Logs error messages. - Errorf: Logs formatted error messages. Both loggers include date, time, and short file information in their output. --- internal/logger/logger.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 internal/logger/logger.go diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 000000000..a8de60c82 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,32 @@ +package logger + +import ( + "log" + "os" +) + +var ( + InfoLogger *log.Logger + ErrorLogger *log.Logger +) + +func init() { + InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) +} + +func Info(v ...interface{}) { + InfoLogger.Println(v...) +} + +func Infof(format string, v ...interface{}) { + InfoLogger.Printf(format, v...) +} + +func Error(v ...interface{}) { + ErrorLogger.Println(v...) +} + +func Errorf(format string, v ...interface{}) { + ErrorLogger.Printf(format, v...) +} From 0de3370a2982ed480e8ca33cbca24ef7c4960ad6 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:44:50 -0300 Subject: [PATCH 024/141] refactor(server): enhance server setup and graceful shutdown This commit refactors the server setup. Changes include: - Initializing repository, cache, and external API client within the NewServer function. - Adding rate updater initialization and starting it in a separate goroutine. - Enhancing the Start function to log server start and handle HTTP server errors. - Implementing a Shutdown function to gracefully shut down the server, close database and cache connections, and log shutdown progress. - Utilizing the logger package for logging server events and errors. --- internal/server/server.go | 95 ++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 398305363..f95df6ae2 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -4,55 +4,90 @@ import ( "context" "fmt" "net/http" - "os" "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/logger" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/Lutefd/challenge-bravo/internal/service" + "github.com/Lutefd/challenge-bravo/internal/worker" ) type Server struct { - port int - router http.Handler - config Config + config Config + httpServer *http.Server + router http.Handler + rateUpdater *worker.RateUpdater + currencyRepo repository.CurrencyRepository + currencyCache cache.Cache + externalAPI worker.ExternalAPIClient } -func NewServer(config Config) *Server { - strPort := os.Getenv("SERVER_PORT") - if strPort == "" { - fmt.Println("port environment variable was not setted") +func NewServer(config Config) (*Server, error) { + repo, err := repository.NewPostgresCurrencyRepository(config.PostgresConn) + if err != nil { + return nil, fmt.Errorf("failed to initialize repository: %w", err) + } + redisCache, err := cache.NewRedisCache(config.RedisAddr, config.RedisPass) + if err != nil { + return nil, fmt.Errorf("failed to initialize cache: %w", err) } + externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) + currencyService := service.NewCurrencyService(repo, redisCache, externalAPI) + rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, 1*time.Hour) + server := &Server{ - port: int(config.ServerPort), - config: config, + config: config, + currencyRepo: repo, + currencyCache: redisCache, + externalAPI: externalAPI, + rateUpdater: rateUpdater, } - server.registerRoutes() - return server -} -func (s *Server) Start(ctx context.Context) error { - fmt.Println("Starting server on port 8080") - ch := make(chan error, 1) - server := &http.Server{ - Addr: fmt.Sprintf(":%d", s.port), - Handler: s.router, + server.registerRoutes(currencyService) + + server.httpServer = &http.Server{ + Addr: fmt.Sprintf(":%d", config.ServerPort), + Handler: server.router, IdleTimeout: time.Minute, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, } - var err error + return server, nil +} + +func (s *Server) Start(ctx context.Context) error { + go s.rateUpdater.Start(ctx) go func() { - err := server.ListenAndServe() - if err != nil { - ch <- fmt.Errorf("failed to start server: %w", err) + logger.Infof("Server started on port %d", s.config.ServerPort) + if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Errorf("HTTP server error: %v", err) } - close(ch) }() - select { - case err = <-ch: + + <-ctx.Done() + return s.Shutdown() +} + +func (s *Server) Shutdown() error { + logger.Info("Server is shutting down...") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := s.httpServer.Shutdown(ctx); err != nil { + logger.Errorf("HTTP server shutdown error: %v", err) + return err + } + if err := s.currencyRepo.Close(); err != nil { + logger.Errorf("Database connection close error: %v", err) return err - case <-ctx.Done(): - _, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() + } - return server.Shutdown(ctx) + if err := s.currencyCache.Close(); err != nil { + logger.Errorf("Cache connection close error: %v", err) + return err } + + logger.Info("Server shutdown complete") + return nil } From ec11f2b087a7216a1411e22193d0fc607570695e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:45:48 -0300 Subject: [PATCH 025/141] refactor(routes): streamline route registration This commit refactors the route registration process to streamline the initialization of currency routes. Changes include: - Passing the CurrencyService instance to the registerRoutes function. - Consolidating the route definitions within the registerRoutes function. - Removing the separate loadCurrencyRoutes function for better readability and maintenance. --- internal/server/routes.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/internal/server/routes.go b/internal/server/routes.go index b9fd2ec64..d0e0d18e9 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -7,20 +7,15 @@ import ( "github.com/go-chi/chi/v5/middleware" ) -func (s *Server) registerRoutes() { +func (s *Server) registerRoutes(currencyService *service.CurrencyService) { router := chi.NewRouter() router.Use(middleware.Logger) router.Get("/healthz", handler.HandlerReadiness) - router.Route("/currency", s.loadCurrencyRoutes) - - s.router = router -} - -func (s *Server) loadCurrencyRoutes(router chi.Router) { - currencyService := service.NewCurrencyService() currencyHandler := handler.NewCurrencyHandler(currencyService) - - router.Get("/convert", currencyHandler.ConvertCurrency) - router.Post("/", currencyHandler.AddCurrency) - router.Delete("/{code}", currencyHandler.RemoveCurrency) + router.Route("/currency", func(r chi.Router) { + r.Get("/convert", currencyHandler.ConvertCurrency) + r.Post("/", currencyHandler.AddCurrency) + r.Delete("/{code}", currencyHandler.RemoveCurrency) + }) + s.router = router } From fba3d34c156980c7a85b5a408ee11643819eed26 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 11:46:58 -0300 Subject: [PATCH 026/141] refactor(main): improve error handling and server initialization This commit improves error handling and server initialization in the main function. Changes include: - Logging an error message if the .env file fails to load. - Handling errors when creating the server and logging appropriate messages. - Logging an error message if the server fails to start. - Ensuring consistent error logging and handling throughout the initialization process. --- cmd/api/main.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index ab54838f9..8a14c22da 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -11,17 +11,24 @@ import ( ) func main() { - godotenv.Load(".env") + if err := godotenv.Load(".env"); err != nil { + log.Printf("Error loading .env file: %v", err) + } + config, err := server.LoadConfig() if err != nil { log.Fatalf("Failed to load configuration: %v", err) } - srv := server.NewServer(config) - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - defer cancel() - err = srv.Start(ctx) + + srv, err := server.NewServer(config) if err != nil { - panic(err) + log.Fatalf("Failed to create server: %v", err) } + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + + if err := srv.Start(ctx); err != nil { + log.Fatalf("Server error: %v", err) + } } From 054533a787cbe78c20eca84214a4a2bc26023292 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:51:25 -0300 Subject: [PATCH 027/141] feat(service): implement AddCurrency and RemoveCurrency methods This commit adds the implementation for the AddCurrency and RemoveCurrency methods in the CurrencyService. Changes include: - AddCurrency: Adds a new currency to the repository and updates the cache. Returns an error if the currency already exists. - RemoveCurrency: Removes an existing currency from the repository and cache. Returns an error if the currency is not found. - Proper error handling and logging for cache updates and deletions. --- internal/service/currency_service.go | 36 +++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 81a704dfa..e0171a1ef 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -2,7 +2,6 @@ package service import ( "context" - "errors" "fmt" "time" @@ -77,9 +76,40 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er } func (s *CurrencyService) AddCurrency(ctx context.Context, code string, rate float64) error { - return errors.New("not implemented") + _, err := s.repo.GetByCode(ctx, code) + if err == nil { + return fmt.Errorf("currency %s already exists", code) + } + + currency := &model.Currency{ + Code: code, + Rate: rate, + UpdatedAt: time.Now(), + } + + if err := s.repo.Create(ctx, currency); err != nil { + return fmt.Errorf("failed to add currency to repository: %w", err) + } + + if err := s.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { + fmt.Printf("Failed to update cache for new currency %s: %v\n", code, err) + } + + return nil } func (s *CurrencyService) RemoveCurrency(ctx context.Context, code string) error { - return errors.New("not implemented") + _, err := s.repo.GetByCode(ctx, code) + if err != nil { + return fmt.Errorf("currency %s not found", code) + } + + if err := s.repo.Delete(ctx, code); err != nil { + return fmt.Errorf("failed to remove currency from repository: %w", err) + } + + if err := s.cache.Delete(ctx, code); err != nil { + fmt.Printf("Failed to remove currency %s from cache: %v\n", code, err) + } + return nil } From 07374db70c58438d4a4b420c934bb6658f0b048c Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:52:33 -0300 Subject: [PATCH 028/141] feat(model): add User model with roles and API key This commit adds the User model to the project. The User model includes the following fields: - ID: Unique identifier for the user. - Username: The username of the user. - Password: The hashed password of the user (excluded from JSON responses). - Role: The role of the user, which can be either 'user' or 'admin'. - APIKey: The API key associated with the user. - CreatedAt: The timestamp when the user was created. - UpdatedAt: The timestamp when the user was last updated. --- internal/model/users.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/model/users.go b/internal/model/users.go index 8b5379070..e8b3c80cb 100644 --- a/internal/model/users.go +++ b/internal/model/users.go @@ -1 +1,24 @@ package model + +import ( + "time" + + "github.com/google/uuid" +) + +type Role string + +const ( + RoleUser Role = "user" + RoleAdmin Role = "admin" +) + +type User struct { + ID uuid.UUID `json:"id"` + Username string `json:"username"` + Password string `json:"-"` + Role Role `json:"role"` + APIKey string `json:"api_key"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} From 05322fa7497e19f2451930c601124ac9a03bd206 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:54:03 -0300 Subject: [PATCH 029/141] feat(worker): add initial rate population on startup This commit enhances the RateUpdater by adding an initial rate population on startup. Changes include: - Adding a populateRates method to fetch and update rates from the external API on startup. - Calling populateRates at the start of the Start method to ensure rates are up-to-date when the server starts. - Improved error handling and logging within the populateRates method to handle cases where currencies are not found or updates fail. --- internal/worker/rate_updater.go | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/internal/worker/rate_updater.go b/internal/worker/rate_updater.go index 8a4de6d53..3f4a9f699 100644 --- a/internal/worker/rate_updater.go +++ b/internal/worker/rate_updater.go @@ -29,6 +29,9 @@ func NewRateUpdater(repo repository.CurrencyRepository, cache cache.Cache, exter func (ru *RateUpdater) Start(ctx context.Context) { ticker := time.NewTicker(ru.interval) + if err := ru.populateRates(ctx); err != nil { + log.Printf("Error updating rates on startup: %v", err) + } defer ticker.Stop() for { @@ -69,3 +72,43 @@ func (ru *RateUpdater) updateRates(ctx context.Context) error { log.Println("Rates updated successfully") return nil } + +func (ru *RateUpdater) populateRates(ctx context.Context) error { + rates, err := ru.externalAPI.FetchRates(ctx) + if err != nil { + return fmt.Errorf("failed to fetch rates: %w", err) + } + + for code, rate := range rates.Rates { + currency := &model.Currency{ + Code: code, + Rate: rate, + UpdatedAt: time.Unix(rates.Timestamp, 0), + } + _, err := ru.repo.GetByCode(ctx, code) + if err != nil { + if err.Error() == "currency not found" { + err = ru.repo.Create(ctx, currency) + if err != nil { + log.Printf("Failed to create currency %s in repository: %v", code, err) + continue + } + } else { + log.Printf("Failed to get currency %s in repository: %v", code, err) + continue + } + } else { + err = ru.repo.Update(ctx, currency) + if err != nil { + log.Printf("Failed to update currency %s in repository: %v", code, err) + continue + } + } + if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { + log.Printf("Failed to update currency %s in cache: %v", code, err) + } + } + + log.Println("Rates updated successfully") + return nil +} From 6925920e2b8b489c098b78b38416d29ed0bbd46d Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:55:58 -0300 Subject: [PATCH 030/141] feat(repository): add UserRepository interface This commit adds the UserRepository interface to the project. The UserRepository interface includes the following methods: - Create: Adds a new user to the repository. - GetByUsername: Retrieves a user by their username. - GetByAPIKey: Retrieves a user by their API key. - Close: Closes the repository connection. --- internal/repository/repository.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index fdf6cc21e..f96d2c128 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -13,3 +13,10 @@ type CurrencyRepository interface { Delete(ctx context.Context, code string) error Close() error } + +type UserRepository interface { + Create(ctx context.Context, user *model.User) error + GetByUsername(ctx context.Context, username string) (*model.User, error) + GetByAPIKey(ctx context.Context, apiKey string) (*model.User, error) + Close() error +} From b2e64831855eb12a42410232f3a20702b45280d7 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:57:25 -0300 Subject: [PATCH 031/141] feat(repository): add PostgreSQL user repository implementation This commit adds the implementation of the PostgreSQL user repository with the following methods: - NewPostgresUserRepository: Initializes a new PostgresUserRepository with a given connection URL. - Create: Inserts a new user into the database. - GetByUsername: Retrieves a user by their username from the database. - GetByAPIKey: Retrieves a user by their API key from the database. - Close: Closes the database connection. --- internal/repository/pg_user_repository.go | 72 +++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 internal/repository/pg_user_repository.go diff --git a/internal/repository/pg_user_repository.go b/internal/repository/pg_user_repository.go new file mode 100644 index 000000000..022afeb02 --- /dev/null +++ b/internal/repository/pg_user_repository.go @@ -0,0 +1,72 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + + "github.com/Lutefd/challenge-bravo/internal/model" + _ "github.com/lib/pq" +) + +type PostgresUserRepository struct { + db *sql.DB +} + +func NewPostgresUserRepository(connURL string) (*PostgresUserRepository, error) { + db, err := sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } + + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } + + return &PostgresUserRepository{db: db}, nil +} + +func (r *PostgresUserRepository) Create(ctx context.Context, user *model.User) error { + query := `INSERT INTO users (id, username, password, role, api_key, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7)` + _, err := r.db.ExecContext(ctx, query, user.ID, user.Username, user.Password, user.Role, user.APIKey, user.CreatedAt, user.UpdatedAt) + if err != nil { + return fmt.Errorf("failed to create user: %w", err) + } + return nil +} + +func (r *PostgresUserRepository) GetByUsername(ctx context.Context, username string) (*model.User, error) { + query := `SELECT id, username, password, role, api_key, created_at, updated_at FROM users WHERE username = $1` + var user model.User + err := r.db.QueryRowContext(ctx, query, username).Scan( + &user.ID, &user.Username, &user.Password, &user.Role, &user.APIKey, &user.CreatedAt, &user.UpdatedAt, + ) + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("user not found") + } + return nil, fmt.Errorf("failed to get user: %w", err) + } + return &user, nil +} + +func (r *PostgresUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.User, error) { + query := `SELECT id, username, password, role, api_key, created_at, updated_at FROM users WHERE api_key = $1` + var user model.User + err := r.db.QueryRowContext(ctx, query, apiKey).Scan( + &user.ID, &user.Username, &user.Password, &user.Role, &user.APIKey, &user.CreatedAt, &user.UpdatedAt, + ) + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("user not found") + } + return nil, fmt.Errorf("failed to get user: %w", err) + } + return &user, nil +} + +func (r *PostgresUserRepository) Close() error { + return r.db.Close() +} From a917408d9e5b7b889d372fe12f3581f87514f6ea Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:58:39 -0300 Subject: [PATCH 032/141] feat(handler): add user registration and login endpoints This commit adds the implementation for user registration and login endpoints in the UserHandler. Changes include: - Register: Handles user registration, including password hashing, API key generation, and storing the user in the repository. - Login: Handles user login, including credential validation and password comparison. - Proper error handling and logging for both endpoints. - Responding with JSON responses for successful operations and errors. --- internal/handler/user_handler.go | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 internal/handler/user_handler.go diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go new file mode 100644 index 000000000..236c1369a --- /dev/null +++ b/internal/handler/user_handler.go @@ -0,0 +1,87 @@ +package handler + +import ( + "encoding/json" + "net/http" + "time" + + "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/logger" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/google/uuid" + "golang.org/x/crypto/bcrypt" +) + +type UserHandler struct { + userRepo repository.UserRepository +} + +func NewUserHandler(userRepo repository.UserRepository) *UserHandler { + return &UserHandler{userRepo: userRepo} +} + +func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { + var user model.User + if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + logger.Errorf("Failed to decode user registration request: %v", err) + http.Error(w, "Invalid request payload", http.StatusBadRequest) + return + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) + if err != nil { + logger.Errorf("Failed to hash password: %v", err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + + user.ID = uuid.New() + user.Password = string(hashedPassword) + user.Role = model.RoleUser // Default role + user.APIKey = generateAPIKey() + user.CreatedAt = time.Now() + user.UpdatedAt = time.Now() + + if err := h.userRepo.Create(r.Context(), &user); err != nil { + logger.Errorf("Failed to create user: %v", err) + http.Error(w, "Failed to create user", http.StatusInternalServerError) + return + } + + user.Password = "" + commons.RespondWithJSON(w, http.StatusCreated, user) +} + +func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { + var credentials struct { + Username string `json:"username"` + Password string `json:"password"` + } + + if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { + logger.Errorf("Failed to decode login request: %v", err) + http.Error(w, "Invalid request payload", http.StatusBadRequest) + return + } + + user, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) + if err != nil { + logger.Errorf("Failed to get user: %v", err) + http.Error(w, "Invalid credentials", http.StatusUnauthorized) + return + } + + if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(credentials.Password)); err != nil { + logger.Errorf("Invalid password for user %s: %v", credentials.Username, err) + http.Error(w, "Invalid credentials", http.StatusUnauthorized) + return + } + + user.Password = "" + commons.RespondWithJSON(w, http.StatusOK, user) +} + +func generateAPIKey() string { + return uuid.New().String() +} From a7b9d2f8283128fa3a51510d7b311bc5c7b490d2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 12:59:21 -0300 Subject: [PATCH 033/141] feat(server): add user repository initialization This commit updates the server initialization to include the user repository. --- internal/server/server.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/server/server.go b/internal/server/server.go index f95df6ae2..1df067774 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -21,6 +21,7 @@ type Server struct { currencyRepo repository.CurrencyRepository currencyCache cache.Cache externalAPI worker.ExternalAPIClient + userRepo repository.UserRepository } func NewServer(config Config) (*Server, error) { @@ -28,6 +29,10 @@ func NewServer(config Config) (*Server, error) { if err != nil { return nil, fmt.Errorf("failed to initialize repository: %w", err) } + userRepo, err := repository.NewPostgresUserRepository(config.PostgresConn) + if err != nil { + return nil, fmt.Errorf("failed to initialize user repository: %w", err) + } redisCache, err := cache.NewRedisCache(config.RedisAddr, config.RedisPass) if err != nil { return nil, fmt.Errorf("failed to initialize cache: %w", err) @@ -42,6 +47,7 @@ func NewServer(config Config) (*Server, error) { currencyCache: redisCache, externalAPI: externalAPI, rateUpdater: rateUpdater, + userRepo: userRepo, } server.registerRoutes(currencyService) From 2d73018a8fe54cad62d8c26d1b4d098c0137aac9 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 13:02:00 -0300 Subject: [PATCH 034/141] feat(middleware): add authentication, role-based access control, and rate limiting middleware This commit adds middleware for authentication, role-based access control, and rate limiting. Changes include: - AuthMiddleware: Middleware for authenticating requests using an API key. Adds the user to the request context. - RequireRole: Middleware for enforcing role-based access control. Ensures the user has the required role. - RateLimitMiddleware: Middleware for rate limiting requests. Limits the number of requests per second to prevent abuse. --- internal/middleware/middleware.go | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 internal/middleware/middleware.go diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go new file mode 100644 index 000000000..29b5ab2a1 --- /dev/null +++ b/internal/middleware/middleware.go @@ -0,0 +1,77 @@ +package api_middleware + +import ( + "context" + "net/http" + "sync" + "time" + + "github.com/Lutefd/challenge-bravo/internal/logger" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" + "golang.org/x/time/rate" +) + +type AuthMiddleware struct { + userRepo repository.UserRepository +} + +func NewAuthMiddleware(userRepo repository.UserRepository) *AuthMiddleware { + return &AuthMiddleware{userRepo: userRepo} +} + +var ( + limiter = rate.NewLimiter(rate.Every(time.Second), 10) + clients = make(map[string]*rate.Limiter) + mu sync.Mutex +) + +func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + apiKey := r.Header.Get("X-API-Key") + if apiKey == "" { + logger.Error("No API key provided") + http.Error(w, "No API key provided", http.StatusUnauthorized) + return + } + user, err := am.userRepo.GetByAPIKey(r.Context(), apiKey) + if err != nil { + logger.Errorf("Invalid API key: %s", apiKey) + http.Error(w, "Invalid API key", http.StatusUnauthorized) + return + } + ctx := context.WithValue(r.Context(), "user", user) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +func RequireRole(role model.Role) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + user, ok := r.Context().Value("user").(*model.User) + if !ok { + logger.Error("User not found in context") + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + if user.Role != role { + logger.Errorf("User %s does not have required role %s", user.Username, role) + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + next.ServeHTTP(w, r) + }) + } +} +func RateLimitMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !limiter.Allow() { + logger.Errorf("Rate limit exceeded for IP: %s", r.RemoteAddr) + http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests) + return + } + next.ServeHTTP(w, r) + }) +} From ad81b096eca0c839604095b147fa77f22ff1ae55 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 13:05:28 -0300 Subject: [PATCH 035/141] feat(routes): add authentication, role-based access, and rate limiting to routes This commit updates the route registration process to include authentication, role-based access control, and rate limiting. Changes include: - Adding AuthMiddleware for authenticating requests using an API key. - Adding RequireRole middleware to enforce role-based access control for admin routes. - Adding RateLimitMiddleware to limit the number of requests for registration and login endpoints. - Registering routes for user registration and login. - Securing currency routes with authentication and role-based access control. --- internal/server/routes.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/server/routes.go b/internal/server/routes.go index d0e0d18e9..9ba5c194f 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -2,6 +2,8 @@ package server import ( "github.com/Lutefd/challenge-bravo/internal/handler" + api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" + "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/service" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -10,12 +12,19 @@ import ( func (s *Server) registerRoutes(currencyService *service.CurrencyService) { router := chi.NewRouter() router.Use(middleware.Logger) + authMiddleware := api_middleware.NewAuthMiddleware(s.userRepo) + router.Get("/healthz", handler.HandlerReadiness) currencyHandler := handler.NewCurrencyHandler(currencyService) + userHandler := handler.NewUserHandler(s.userRepo) + router.Route("/auth", func(r chi.Router) { + r.With(api_middleware.RateLimitMiddleware).Post("/register", userHandler.Register) + r.With(api_middleware.RateLimitMiddleware).Post("/login", userHandler.Login) + }) router.Route("/currency", func(r chi.Router) { r.Get("/convert", currencyHandler.ConvertCurrency) - r.Post("/", currencyHandler.AddCurrency) - r.Delete("/{code}", currencyHandler.RemoveCurrency) + r.With(authMiddleware.Authenticate, api_middleware.RequireRole(model.RoleAdmin)).Post("/", currencyHandler.AddCurrency) + r.With(authMiddleware.Authenticate, api_middleware.RequireRole(model.RoleAdmin)).Delete("/{code}", currencyHandler.RemoveCurrency) }) s.router = router } From 0b608b541172d189943c98985276f12229a64d26 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 13:24:59 -0300 Subject: [PATCH 036/141] fix(user): modified user model to handle login bug This commit adds a fix for a bug that ocurred on login, as the password field was ommited in the User model, it didn't return anything when comparing the hashes with Bcrypt. The following changes were made: - Created a separate User struct for database operations - Created conversion func for the different User structs - Modified params and returns in the repository and handler --- internal/handler/user_handler.go | 33 ++++++++++++----------- internal/model/users.go | 20 +++++++++++++- internal/repository/pg_user_repository.go | 10 +++---- internal/repository/repository.go | 6 ++--- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go index 236c1369a..029fd8c62 100644 --- a/internal/handler/user_handler.go +++ b/internal/handler/user_handler.go @@ -22,27 +22,31 @@ func NewUserHandler(userRepo repository.UserRepository) *UserHandler { } func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { - var user model.User - if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + var credentials struct { + Username string `json:"username"` + Password string `json:"password"` + } + if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { logger.Errorf("Failed to decode user registration request: %v", err) http.Error(w, "Invalid request payload", http.StatusBadRequest) return } - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost) if err != nil { logger.Errorf("Failed to hash password: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } - - user.ID = uuid.New() - user.Password = string(hashedPassword) - user.Role = model.RoleUser // Default role - user.APIKey = generateAPIKey() - user.CreatedAt = time.Now() - user.UpdatedAt = time.Now() - + var user model.UserDB = model.UserDB{ + ID: uuid.New(), + Username: credentials.Username, + Password: string(hashedPassword), + Role: model.RoleUser, + APIKey: generateAPIKey(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } if err := h.userRepo.Create(r.Context(), &user); err != nil { logger.Errorf("Failed to create user: %v", err) http.Error(w, "Failed to create user", http.StatusInternalServerError) @@ -58,27 +62,26 @@ func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { Username string `json:"username"` Password string `json:"password"` } - if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { logger.Errorf("Failed to decode login request: %v", err) http.Error(w, "Invalid request payload", http.StatusBadRequest) return } - user, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) + userDB, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) if err != nil { logger.Errorf("Failed to get user: %v", err) http.Error(w, "Invalid credentials", http.StatusUnauthorized) return } - if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(credentials.Password)); err != nil { + if err := bcrypt.CompareHashAndPassword([]byte(userDB.Password), []byte(credentials.Password)); err != nil { logger.Errorf("Invalid password for user %s: %v", credentials.Username, err) http.Error(w, "Invalid credentials", http.StatusUnauthorized) return } - user.Password = "" + user := userDB.ToUser() commons.RespondWithJSON(w, http.StatusOK, user) } diff --git a/internal/model/users.go b/internal/model/users.go index e8b3c80cb..43fd41235 100644 --- a/internal/model/users.go +++ b/internal/model/users.go @@ -13,12 +13,30 @@ const ( RoleAdmin Role = "admin" ) +type UserDB struct { + ID uuid.UUID `json:"id"` + Username string `json:"username"` + Password string `json:"password"` + Role Role `json:"role"` + APIKey string `json:"api_key"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + type User struct { ID uuid.UUID `json:"id"` Username string `json:"username"` - Password string `json:"-"` Role Role `json:"role"` APIKey string `json:"api_key"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } + +func (u *UserDB) ToUser() User { + return User{ + ID: u.ID, + Username: u.Username, + Role: u.Role, + APIKey: u.APIKey, + } +} diff --git a/internal/repository/pg_user_repository.go b/internal/repository/pg_user_repository.go index 022afeb02..01aa874b5 100644 --- a/internal/repository/pg_user_repository.go +++ b/internal/repository/pg_user_repository.go @@ -27,7 +27,7 @@ func NewPostgresUserRepository(connURL string) (*PostgresUserRepository, error) return &PostgresUserRepository{db: db}, nil } -func (r *PostgresUserRepository) Create(ctx context.Context, user *model.User) error { +func (r *PostgresUserRepository) Create(ctx context.Context, user *model.UserDB) error { query := `INSERT INTO users (id, username, password, role, api_key, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7)` _, err := r.db.ExecContext(ctx, query, user.ID, user.Username, user.Password, user.Role, user.APIKey, user.CreatedAt, user.UpdatedAt) @@ -37,9 +37,9 @@ func (r *PostgresUserRepository) Create(ctx context.Context, user *model.User) e return nil } -func (r *PostgresUserRepository) GetByUsername(ctx context.Context, username string) (*model.User, error) { +func (r *PostgresUserRepository) GetByUsername(ctx context.Context, username string) (*model.UserDB, error) { query := `SELECT id, username, password, role, api_key, created_at, updated_at FROM users WHERE username = $1` - var user model.User + var user model.UserDB err := r.db.QueryRowContext(ctx, query, username).Scan( &user.ID, &user.Username, &user.Password, &user.Role, &user.APIKey, &user.CreatedAt, &user.UpdatedAt, ) @@ -52,9 +52,9 @@ func (r *PostgresUserRepository) GetByUsername(ctx context.Context, username str return &user, nil } -func (r *PostgresUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.User, error) { +func (r *PostgresUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) { query := `SELECT id, username, password, role, api_key, created_at, updated_at FROM users WHERE api_key = $1` - var user model.User + var user model.UserDB err := r.db.QueryRowContext(ctx, query, apiKey).Scan( &user.ID, &user.Username, &user.Password, &user.Role, &user.APIKey, &user.CreatedAt, &user.UpdatedAt, ) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index f96d2c128..3c59855ae 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -15,8 +15,8 @@ type CurrencyRepository interface { } type UserRepository interface { - Create(ctx context.Context, user *model.User) error - GetByUsername(ctx context.Context, username string) (*model.User, error) - GetByAPIKey(ctx context.Context, apiKey string) (*model.User, error) + Create(ctx context.Context, user *model.UserDB) error + GetByUsername(ctx context.Context, username string) (*model.UserDB, error) + GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) Close() error } From 79f22efa1ba9ed76652ca57998f353f930e4b3e2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 13:26:41 -0300 Subject: [PATCH 037/141] chore(modules): add new dependencies for UUID, bcrypt, and rate limiting This commit updates the go.mod file to include additional dependencies required for user handling and rate limiting. Changes include: - Adding github.com/google/uuid for generating unique user IDs. - Adding golang.org/x/crypto for bcrypt password hashing. - Adding golang.org/x/time for rate limiting. --- go.mod | 3 +++ go.sum | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/go.mod b/go.mod index 5697c5f41..851c0acf5 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,11 @@ require ( ) require ( + github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 github.com/redis/go-redis/v9 v9.6.1 + golang.org/x/crypto v0.25.0 + golang.org/x/time v0.6.0 ) require ( diff --git a/go.sum b/go.sum index 60e799879..19974a535 100644 --- a/go.sum +++ b/go.sum @@ -8,9 +8,15 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= From 4304b3a02287e37d7ab8d903c9869134876f68d6 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 13:30:10 -0300 Subject: [PATCH 038/141] refactor(model): remove unecessary fields from User model This commit removes the following fields from the User struct that is used to shape the JSON response for the login: - CreatedAt - UpdatedAt --- internal/model/users.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/model/users.go b/internal/model/users.go index 43fd41235..27a5c1304 100644 --- a/internal/model/users.go +++ b/internal/model/users.go @@ -24,12 +24,10 @@ type UserDB struct { } type User struct { - ID uuid.UUID `json:"id"` - Username string `json:"username"` - Role Role `json:"role"` - APIKey string `json:"api_key"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID uuid.UUID `json:"id"` + Username string `json:"username"` + Role Role `json:"role"` + APIKey string `json:"api_key"` } func (u *UserDB) ToUser() User { From 1129b3aa5fd91b09ea3c1d44a7606b78966141c1 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 15:58:26 -0300 Subject: [PATCH 039/141] fix(service): ensure that code is always uppercase on creation This commit adds a simple strings.ToUpper to ensure that the code that is passed for currency creation is always uppercase to keep the pattern. --- internal/service/currency_service.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index e0171a1ef..647a4c5d0 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "strings" "time" "github.com/Lutefd/challenge-bravo/internal/cache" @@ -61,7 +62,7 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er return 0, fmt.Errorf("currency %s not found", code) } currency = &model.Currency{ - Code: code, + Code: strings.ToUpper(code), Rate: rate, UpdatedAt: time.Now(), } @@ -82,7 +83,7 @@ func (s *CurrencyService) AddCurrency(ctx context.Context, code string, rate flo } currency := &model.Currency{ - Code: code, + Code: strings.ToUpper(code), Rate: rate, UpdatedAt: time.Now(), } From 80f0aee2baf813cbaffeb7620c26e9bc93b7eb73 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 15:59:02 -0300 Subject: [PATCH 040/141] tests(service): add currency service test This commit adds a comprehensible test suite for the currency service. --- internal/service/currency_service_test.go | 230 ++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 internal/service/currency_service_test.go diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go new file mode 100644 index 000000000..d616b0666 --- /dev/null +++ b/internal/service/currency_service_test.go @@ -0,0 +1,230 @@ +package service_test + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/service" +) + +type mockRepository struct { + currencies map[string]*model.Currency +} + +func (m *mockRepository) GetByCode(ctx context.Context, code string) (*model.Currency, error) { + if currency, ok := m.currencies[code]; ok { + return currency, nil + } + return nil, errors.New("currency not found") +} + +func (m *mockRepository) Create(ctx context.Context, currency *model.Currency) error { + m.currencies[currency.Code] = currency + return nil +} + +func (m *mockRepository) Update(ctx context.Context, currency *model.Currency) error { + m.currencies[currency.Code] = currency + return nil +} + +func (m *mockRepository) Delete(ctx context.Context, code string) error { + delete(m.currencies, code) + return nil +} + +func (m *mockRepository) Close() error { + return nil +} + +type mockCache struct { + data map[string]float64 +} + +func (m *mockCache) Get(ctx context.Context, key string) (float64, error) { + if rate, ok := m.data[key]; ok { + return rate, nil + } + return 0, errors.New("key not found") +} + +func (m *mockCache) Set(ctx context.Context, key string, value float64, expiration time.Duration) error { + m.data[key] = value + return nil +} + +func (m *mockCache) Delete(ctx context.Context, key string) error { + delete(m.data, key) + return nil +} + +func (m *mockCache) Close() error { + return nil +} + +type mockExternalAPI struct { + rates map[string]float64 +} + +func (m *mockExternalAPI) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { + return &model.ExchangeRates{ + Rates: m.rates, + }, nil +} + +func TestCurrencyService_Convert(t *testing.T) { + repo := &mockRepository{ + currencies: map[string]*model.Currency{ + "USD": {Code: "USD", Rate: 1.0}, + "EUR": {Code: "EUR", Rate: 0.85}, + }, + } + cache := &mockCache{ + data: map[string]float64{}, + } + externalAPI := &mockExternalAPI{ + rates: map[string]float64{ + "USD": 1.0, + "EUR": 0.85, + "GBP": 0.75, + }, + } + + currencyService := service.NewCurrencyService(repo, cache, externalAPI) + + tests := []struct { + name string + from string + to string + amount float64 + expected float64 + expectedError bool + }{ + {"USD to EUR", "USD", "EUR", 100, 85, false}, + {"EUR to USD", "EUR", "USD", 85, 100, false}, + {"USD to GBP", "USD", "GBP", 100, 75, false}, + {"Invalid currency", "USD", "XYZ", 100, 0, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := currencyService.Convert(context.Background(), tt.from, tt.to, tt.amount) + + if tt.expectedError { + if err == nil { + t.Errorf("Expected an error, but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if result != tt.expected { + t.Errorf("Expected %f, but got %f", tt.expected, result) + } + } + }) + } +} + +func TestCurrencyService_AddCurrency(t *testing.T) { + repo := &mockRepository{ + currencies: map[string]*model.Currency{}, + } + cache := &mockCache{ + data: map[string]float64{}, + } + externalAPI := &mockExternalAPI{ + rates: map[string]float64{}, + } + + currencyService := service.NewCurrencyService(repo, cache, externalAPI) + + tests := []struct { + name string + code string + rate float64 + expectedError bool + }{ + {"Add new currency", "JPY", 110.0, false}, + {"Add existing currency", "JPY", 1.0, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := currencyService.AddCurrency(context.Background(), tt.code, tt.rate) + + if tt.expectedError { + if err == nil { + t.Errorf("Expected an error, but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + currency, err := repo.GetByCode(context.Background(), tt.code) + if err != nil { + t.Errorf("Failed to get added currency: %v", err) + } + if currency.Rate != tt.rate { + t.Errorf("Expected rate %f, but got %f", tt.rate, currency.Rate) + } + } + }) + } +} + +func TestCurrencyService_RemoveCurrency(t *testing.T) { + repo := &mockRepository{ + currencies: map[string]*model.Currency{ + "USD": {Code: "USD", Rate: 1.0}, + "EUR": {Code: "EUR", Rate: 0.85}, + }, + } + cache := &mockCache{ + data: map[string]float64{ + "USD": 1.0, + "EUR": 0.85, + }, + } + externalAPI := &mockExternalAPI{ + rates: map[string]float64{}, + } + + currencyService := service.NewCurrencyService(repo, cache, externalAPI) + + tests := []struct { + name string + code string + expectedError bool + }{ + {"Remove existing currency", "USD", false}, + {"Remove non-existing currency", "JPY", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := currencyService.RemoveCurrency(context.Background(), tt.code) + + if tt.expectedError { + if err == nil { + t.Errorf("Expected an error, but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + _, err := repo.GetByCode(context.Background(), tt.code) + if err == nil { + t.Errorf("Currency should have been removed, but it still exists") + } + _, err = cache.Get(context.Background(), tt.code) + if err == nil { + t.Errorf("Currency should have been removed from cache, but it still exists") + } + } + }) + } +} From d0f71e3390a9bf273c10668d185fb45e6485aa71 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 16:00:01 -0300 Subject: [PATCH 041/141] fix(handler): add input validation for the user handler This commit adds validation for empty strings for the username and password. --- internal/handler/user_handler.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go index 029fd8c62..7f174d093 100644 --- a/internal/handler/user_handler.go +++ b/internal/handler/user_handler.go @@ -32,13 +32,20 @@ func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { return } + if credentials.Username == "" || credentials.Password == "" { + logger.Errorf("Invalid input: username or password is empty") + http.Error(w, "Username and password are required", http.StatusBadRequest) + return + } + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost) if err != nil { logger.Errorf("Failed to hash password: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } - var user model.UserDB = model.UserDB{ + + user := model.UserDB{ ID: uuid.New(), Username: credentials.Username, Password: string(hashedPassword), @@ -47,6 +54,7 @@ func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { CreatedAt: time.Now(), UpdatedAt: time.Now(), } + if err := h.userRepo.Create(r.Context(), &user); err != nil { logger.Errorf("Failed to create user: %v", err) http.Error(w, "Failed to create user", http.StatusInternalServerError) @@ -62,11 +70,17 @@ func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { Username string `json:"username"` Password string `json:"password"` } + if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { logger.Errorf("Failed to decode login request: %v", err) http.Error(w, "Invalid request payload", http.StatusBadRequest) return } + if credentials.Username == "" || credentials.Password == "" { + logger.Errorf("Invalid input: username or password is empty") + http.Error(w, "Username and password are required", http.StatusBadRequest) + return + } userDB, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) if err != nil { From d4e8407d7007d5bf7649eb43236502b65e176fc6 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 16:00:25 -0300 Subject: [PATCH 042/141] tests(handler): add user handler test This commit adds a comprehensible test suite for the user handler. --- internal/handler/user_handler_test.go | 182 ++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 internal/handler/user_handler_test.go diff --git a/internal/handler/user_handler_test.go b/internal/handler/user_handler_test.go new file mode 100644 index 000000000..c9feb6a9c --- /dev/null +++ b/internal/handler/user_handler_test.go @@ -0,0 +1,182 @@ +package handler + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "golang.org/x/crypto/bcrypt" +) + +type MockUserRepository struct { + mock.Mock +} + +func (m *MockUserRepository) Create(ctx context.Context, user *model.UserDB) error { + args := m.Called(ctx, user) + return args.Error(0) +} + +func (m *MockUserRepository) GetByUsername(ctx context.Context, username string) (*model.UserDB, error) { + args := m.Called(ctx, username) + return args.Get(0).(*model.UserDB), args.Error(1) +} +func (m *MockUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) { + args := m.Called(ctx, apiKey) + return args.Get(0).(*model.UserDB), args.Error(1) +} + +func (m *MockUserRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +func TestRegister(t *testing.T) { + mockRepo := new(MockUserRepository) + handler := NewUserHandler(mockRepo) + + t.Run("Successful registration", func(t *testing.T) { + mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.UserDB")).Return(nil).Once() + + body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + req, _ := http.NewRequest("POST", "/register", body) + rr := httptest.NewRecorder() + + handler.Register(rr, req) + + assert.Equal(t, http.StatusCreated, rr.Code) + + var response model.UserDB + err := json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.NotEmpty(t, response.ID) + assert.Equal(t, "testuser", response.Username) + assert.Empty(t, response.Password) // Password should not be returned + assert.Equal(t, model.RoleUser, response.Role) + assert.NotEmpty(t, response.APIKey) + }) + + t.Run("Invalid request payload", func(t *testing.T) { + body := bytes.NewBufferString(`{"invalid":"json"}`) + req, _ := http.NewRequest("POST", "/register", body) + rr := httptest.NewRecorder() + + handler.Register(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("Empty username or password", func(t *testing.T) { + body := bytes.NewBufferString(`{"username":"","password":""}`) + req, _ := http.NewRequest("POST", "/register", body) + rr := httptest.NewRecorder() + + handler.Register(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("Repository error", func(t *testing.T) { + mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.UserDB")).Return(assert.AnError).Once() + + body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + req, _ := http.NewRequest("POST", "/register", body) + rr := httptest.NewRecorder() + + handler.Register(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + }) +} + +func TestLogin(t *testing.T) { + mockRepo := new(MockUserRepository) + handler := NewUserHandler(mockRepo) + + t.Run("Successful login", func(t *testing.T) { + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("testpass"), bcrypt.DefaultCost) + mockUser := &model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Password: string(hashedPassword), + Role: model.RoleUser, + APIKey: "test-api-key", + } + mockRepo.On("GetByUsername", mock.Anything, "testuser").Return(mockUser, nil).Once() + + body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + req, _ := http.NewRequest("POST", "/login", body) + rr := httptest.NewRecorder() + + handler.Login(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + + var response model.User + err := json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, mockUser.ID, response.ID) + assert.Equal(t, "testuser", response.Username) + assert.Equal(t, model.RoleUser, response.Role) + assert.Equal(t, "test-api-key", response.APIKey) + }) + + t.Run("Invalid request payload", func(t *testing.T) { + body := bytes.NewBufferString(`{"invalid":"json"}`) + req, _ := http.NewRequest("POST", "/login", body) + rr := httptest.NewRecorder() + + handler.Login(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("Empty username or password", func(t *testing.T) { + body := bytes.NewBufferString(`{"username":"","password":""}`) + req, _ := http.NewRequest("POST", "/login", body) + rr := httptest.NewRecorder() + + handler.Login(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("User not found", func(t *testing.T) { + mockRepo.On("GetByUsername", mock.Anything, "nonexistent").Return((*model.UserDB)(nil), assert.AnError).Once() + + body := bytes.NewBufferString(`{"username":"nonexistent","password":"testpass"}`) + req, _ := http.NewRequest("POST", "/login", body) + rr := httptest.NewRecorder() + + handler.Login(rr, req) + + assert.Equal(t, http.StatusUnauthorized, rr.Code) + }) + + t.Run("Incorrect password", func(t *testing.T) { + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("correctpass"), bcrypt.DefaultCost) + mockUser := &model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Password: string(hashedPassword), + Role: model.RoleUser, + APIKey: "test-api-key", + } + mockRepo.On("GetByUsername", mock.Anything, "testuser").Return(mockUser, nil).Once() + + body := bytes.NewBufferString(`{"username":"testuser","password":"wrongpass"}`) + req, _ := http.NewRequest("POST", "/login", body) + rr := httptest.NewRecorder() + + handler.Login(rr, req) + + assert.Equal(t, http.StatusUnauthorized, rr.Code) + }) +} From de8dcdefa38a883f09c9c9f1c156ed4bbd174450 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 16:01:53 -0300 Subject: [PATCH 043/141] fix(handler): ensure that the currency codes from the params are uppercase This commit adds a simple manipulation of the "to" and "from" URL parameters to ensure that they're passed always as uppercase. --- internal/handler/currency_handler.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index dcf662e7e..cc618cb62 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "strconv" + "strings" "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/service" @@ -21,8 +22,8 @@ func NewCurrencyHandler(currencyService *service.CurrencyService) *CurrencyHandl } func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request) { - from := r.URL.Query().Get("from") - to := r.URL.Query().Get("to") + from := strings.ToUpper(r.URL.Query().Get("from")) + to := strings.ToUpper(r.URL.Query().Get("to")) amountStr := r.URL.Query().Get("amount") if from == "" || to == "" || amountStr == "" { From b91c621c4218f45f892dd48a1966222fe1ff0c1a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 16:11:39 -0300 Subject: [PATCH 044/141] fix(handler): ensure that code parameter is validated This commit the following validation for the params related to currencies code: - Verify if they aren't an empty string. - Verify if they follow the ISO 4217, always having 3 digits. --- internal/handler/currency_handler.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index cc618cb62..8f0653885 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -26,11 +26,14 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request to := strings.ToUpper(r.URL.Query().Get("to")) amountStr := r.URL.Query().Get("amount") - if from == "" || to == "" || amountStr == "" { + if from == "" || to == "" || (amountStr == "") { commons.RespondWithError(w, http.StatusBadRequest, "Missing required parameters") return } - + if len(from) != 3 || len(to) != 3 { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + return + } amount, err := strconv.ParseFloat(amountStr, 64) if err != nil { commons.RespondWithError(w, http.StatusBadRequest, "Invalid amount") @@ -61,7 +64,14 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { commons.RespondWithError(w, http.StatusBadRequest, "Invalid request payload") return } - + if currency.Code == "" || currency.Rate == 0 { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code or rate") + return + } + if len(currency.Code) != 3 { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + return + } if err := h.currencyService.AddCurrency(r.Context(), currency.Code, currency.Rate); err != nil { commons.RespondWithError(w, http.StatusInternalServerError, "Failed to add currency") return @@ -71,7 +81,16 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { } func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) { - code := chi.URLParam(r, "code") + code := strings.ToUpper(chi.URLParam(r, "code")) + + if code == "" { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code") + return + } + if len(code) != 3 { + commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + return + } if err := h.currencyService.RemoveCurrency(r.Context(), code); err != nil { commons.RespondWithError(w, http.StatusInternalServerError, "Failed to remove currency") From 4a1d71a1d5a7d3b38e9b3652d584c7af22c10125 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 16:24:51 -0300 Subject: [PATCH 045/141] style: change logs and error messages to all lowercase This commit standardize server errors, logs and json responses to be all lowercase --- internal/handler/currency_handler.go | 18 +++++++++--------- internal/handler/user_handler.go | 16 ++++++++-------- internal/middleware/middleware.go | 20 ++++++++++---------- internal/server/config.go | 2 +- internal/server/server.go | 6 +++--- internal/service/currency_service.go | 4 ++-- internal/service/currency_service_test.go | 20 ++++++++++---------- internal/worker/rate_updater.go | 22 +++++++++++----------- 8 files changed, 54 insertions(+), 54 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index 8f0653885..0493948bc 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -61,41 +61,41 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { } if err := json.NewDecoder(r.Body).Decode(¤cy); err != nil { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid request payload") + commons.RespondWithError(w, http.StatusBadRequest, "invalid request payload") return } if currency.Code == "" || currency.Rate == 0 { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code or rate") + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code or rate") return } if len(currency.Code) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") return } if err := h.currencyService.AddCurrency(r.Context(), currency.Code, currency.Rate); err != nil { - commons.RespondWithError(w, http.StatusInternalServerError, "Failed to add currency") + commons.RespondWithError(w, http.StatusInternalServerError, "failed to add currency") return } - commons.RespondWithJSON(w, http.StatusCreated, map[string]string{"message": "Currency added successfully"}) + commons.RespondWithJSON(w, http.StatusCreated, map[string]string{"message": "currency added successfully"}) } func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) { code := strings.ToUpper(chi.URLParam(r, "code")) if code == "" { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code") + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") return } if len(code) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") return } if err := h.currencyService.RemoveCurrency(r.Context(), code); err != nil { - commons.RespondWithError(w, http.StatusInternalServerError, "Failed to remove currency") + commons.RespondWithError(w, http.StatusInternalServerError, "failed to remove currency") return } - commons.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "Currency removed successfully"}) + commons.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "currency removed successfully"}) } diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go index 7f174d093..7c1e555ba 100644 --- a/internal/handler/user_handler.go +++ b/internal/handler/user_handler.go @@ -72,26 +72,26 @@ func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { } if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { - logger.Errorf("Failed to decode login request: %v", err) - http.Error(w, "Invalid request payload", http.StatusBadRequest) + logger.Errorf("failed to decode login request: %v", err) + http.Error(w, "invalid request payload", http.StatusBadRequest) return } if credentials.Username == "" || credentials.Password == "" { - logger.Errorf("Invalid input: username or password is empty") - http.Error(w, "Username and password are required", http.StatusBadRequest) + logger.Errorf("invalid input: username or password is empty") + http.Error(w, "username and password are required", http.StatusBadRequest) return } userDB, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) if err != nil { - logger.Errorf("Failed to get user: %v", err) - http.Error(w, "Invalid credentials", http.StatusUnauthorized) + logger.Errorf("failed to get user: %v", err) + http.Error(w, "invalid credentials", http.StatusUnauthorized) return } if err := bcrypt.CompareHashAndPassword([]byte(userDB.Password), []byte(credentials.Password)); err != nil { - logger.Errorf("Invalid password for user %s: %v", credentials.Username, err) - http.Error(w, "Invalid credentials", http.StatusUnauthorized) + logger.Errorf("invalid password for user %s: %v", credentials.Username, err) + http.Error(w, "invalid credentials", http.StatusUnauthorized) return } diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 29b5ab2a1..8686575c4 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -30,14 +30,14 @@ func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKey := r.Header.Get("X-API-Key") if apiKey == "" { - logger.Error("No API key provided") - http.Error(w, "No API key provided", http.StatusUnauthorized) + logger.Error("no API key provided") + http.Error(w, "no API key provided", http.StatusUnauthorized) return } user, err := am.userRepo.GetByAPIKey(r.Context(), apiKey) if err != nil { - logger.Errorf("Invalid API key: %s", apiKey) - http.Error(w, "Invalid API key", http.StatusUnauthorized) + logger.Errorf("invalid API key: %s", apiKey) + http.Error(w, "invalid API key", http.StatusUnauthorized) return } ctx := context.WithValue(r.Context(), "user", user) @@ -50,14 +50,14 @@ func RequireRole(role model.Role) func(http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value("user").(*model.User) if !ok { - logger.Error("User not found in context") - http.Error(w, "Unauthorized", http.StatusUnauthorized) + logger.Error("user not found in context") + http.Error(w, "unauthorized", http.StatusUnauthorized) return } if user.Role != role { - logger.Errorf("User %s does not have required role %s", user.Username, role) - http.Error(w, "Forbidden", http.StatusForbidden) + logger.Errorf("user %s does not have required role %s", user.Username, role) + http.Error(w, "forbidden", http.StatusForbidden) return } @@ -68,8 +68,8 @@ func RequireRole(role model.Role) func(http.Handler) http.Handler { func RateLimitMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !limiter.Allow() { - logger.Errorf("Rate limit exceeded for IP: %s", r.RemoteAddr) - http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests) + logger.Errorf("rate limit exceeded for IP: %s", r.RemoteAddr) + http.Error(w, "rate limit exceeded", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) diff --git a/internal/server/config.go b/internal/server/config.go index 2884d7459..7762f0dd7 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -44,7 +44,7 @@ func LoadConfig() (Config, error) { } else { parsedServerPort, err := strconv.ParseUint(serverPort, 10, 16) if err != nil { - errors = append(errors, fmt.Sprintf("Invalid SERVER_PORT: %s", err)) + errors = append(errors, fmt.Sprintf("invalid SERVER_PORT: %s", err)) } else { config.ServerPort = uint16(parsedServerPort) } diff --git a/internal/server/server.go b/internal/server/server.go index 1df067774..740647039 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -85,15 +85,15 @@ func (s *Server) Shutdown() error { return err } if err := s.currencyRepo.Close(); err != nil { - logger.Errorf("Database connection close error: %v", err) + logger.Errorf("database connection close error: %v", err) return err } if err := s.currencyCache.Close(); err != nil { - logger.Errorf("Cache connection close error: %v", err) + logger.Errorf("cache connection close error: %v", err) return err } - logger.Info("Server shutdown complete") + logger.Info("server shutdown complete") return nil } diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 647a4c5d0..9693ab078 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -93,7 +93,7 @@ func (s *CurrencyService) AddCurrency(ctx context.Context, code string, rate flo } if err := s.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { - fmt.Printf("Failed to update cache for new currency %s: %v\n", code, err) + fmt.Printf("failed to update cache for new currency %s: %v\n", code, err) } return nil @@ -110,7 +110,7 @@ func (s *CurrencyService) RemoveCurrency(ctx context.Context, code string) error } if err := s.cache.Delete(ctx, code); err != nil { - fmt.Printf("Failed to remove currency %s from cache: %v\n", code, err) + fmt.Printf("failed to remove currency %s from cache: %v\n", code, err) } return nil } diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go index d616b0666..6c20eca8b 100644 --- a/internal/service/currency_service_test.go +++ b/internal/service/currency_service_test.go @@ -158,18 +158,18 @@ func TestCurrencyService_AddCurrency(t *testing.T) { if tt.expectedError { if err == nil { - t.Errorf("Expected an error, but got none") + t.Errorf("expected an error, but got none") } } else { if err != nil { - t.Errorf("Unexpected error: %v", err) + t.Errorf("unexpected error: %v", err) } currency, err := repo.GetByCode(context.Background(), tt.code) if err != nil { - t.Errorf("Failed to get added currency: %v", err) + t.Errorf("failed to get added currency: %v", err) } if currency.Rate != tt.rate { - t.Errorf("Expected rate %f, but got %f", tt.rate, currency.Rate) + t.Errorf("expected rate %f, but got %f", tt.rate, currency.Rate) } } }) @@ -200,8 +200,8 @@ func TestCurrencyService_RemoveCurrency(t *testing.T) { code string expectedError bool }{ - {"Remove existing currency", "USD", false}, - {"Remove non-existing currency", "JPY", true}, + {"remove existing currency", "USD", false}, + {"remove non-existing currency", "JPY", true}, } for _, tt := range tests { @@ -210,19 +210,19 @@ func TestCurrencyService_RemoveCurrency(t *testing.T) { if tt.expectedError { if err == nil { - t.Errorf("Expected an error, but got none") + t.Errorf("expected an error, but got none") } } else { if err != nil { - t.Errorf("Unexpected error: %v", err) + t.Errorf("unexpected error: %v", err) } _, err := repo.GetByCode(context.Background(), tt.code) if err == nil { - t.Errorf("Currency should have been removed, but it still exists") + t.Errorf("currency should have been removed, but it still exists") } _, err = cache.Get(context.Background(), tt.code) if err == nil { - t.Errorf("Currency should have been removed from cache, but it still exists") + t.Errorf("currency should have been removed from cache, but it still exists") } } }) diff --git a/internal/worker/rate_updater.go b/internal/worker/rate_updater.go index 3f4a9f699..84018a1f6 100644 --- a/internal/worker/rate_updater.go +++ b/internal/worker/rate_updater.go @@ -30,18 +30,18 @@ func NewRateUpdater(repo repository.CurrencyRepository, cache cache.Cache, exter func (ru *RateUpdater) Start(ctx context.Context) { ticker := time.NewTicker(ru.interval) if err := ru.populateRates(ctx); err != nil { - log.Printf("Error updating rates on startup: %v", err) + log.Printf("error updating rates on startup: %v", err) } defer ticker.Stop() for { select { case <-ctx.Done(): - log.Println("Rate updater stopped") + log.Println("rate updater stopped") return case <-ticker.C: if err := ru.updateRates(ctx); err != nil { - log.Printf("Error updating rates: %v", err) + log.Printf("error updating rates: %v", err) } } } @@ -61,15 +61,15 @@ func (ru *RateUpdater) updateRates(ctx context.Context) error { } if err := ru.repo.Update(ctx, currency); err != nil { - log.Printf("Failed to update currency %s in repository: %v", code, err) + log.Printf("failed to update currency %s in repository: %v", code, err) } if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { - log.Printf("Failed to update currency %s in cache: %v", code, err) + log.Printf("failed to update currency %s in cache: %v", code, err) } } - log.Println("Rates updated successfully") + log.Println("rates updated successfully") return nil } @@ -90,25 +90,25 @@ func (ru *RateUpdater) populateRates(ctx context.Context) error { if err.Error() == "currency not found" { err = ru.repo.Create(ctx, currency) if err != nil { - log.Printf("Failed to create currency %s in repository: %v", code, err) + log.Printf("failed to create currency %s in repository: %v", code, err) continue } } else { - log.Printf("Failed to get currency %s in repository: %v", code, err) + log.Printf("failed to get currency %s in repository: %v", code, err) continue } } else { err = ru.repo.Update(ctx, currency) if err != nil { - log.Printf("Failed to update currency %s in repository: %v", code, err) + log.Printf("failed to update currency %s in repository: %v", code, err) continue } } if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { - log.Printf("Failed to update currency %s in cache: %v", code, err) + log.Printf("failed to update currency %s in cache: %v", code, err) } } - log.Println("Rates updated successfully") + log.Println("rates updated successfully") return nil } From 2a8ad12a3c75f14456812bd0926d7c9af5c71023 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 22:18:42 -0300 Subject: [PATCH 046/141] feat(sql): add goose migration schemas and seed script to repo This commit adds the goose migration scripts and the seed script to repo, both were uncommited until the initial data model was completely defined and implemented. --- sql/schema/001_currencies.sql | 8 +++++ sql/schema/002_users.sql | 13 ++++++++ sql/seed.go | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 sql/schema/001_currencies.sql create mode 100644 sql/schema/002_users.sql create mode 100644 sql/seed.go diff --git a/sql/schema/001_currencies.sql b/sql/schema/001_currencies.sql new file mode 100644 index 000000000..1b6988858 --- /dev/null +++ b/sql/schema/001_currencies.sql @@ -0,0 +1,8 @@ +-- +goose Up +CREATE TABLE currencies ( + code CHAR(3) PRIMARY KEY, + rate DECIMAL(10, 4) NOT NULL, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); +-- +goose Down +DROP TABLE currencies; diff --git a/sql/schema/002_users.sql b/sql/schema/002_users.sql new file mode 100644 index 000000000..1e5e29588 --- /dev/null +++ b/sql/schema/002_users.sql @@ -0,0 +1,13 @@ +-- +goose Up +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY, + username VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + role VARCHAR(50) NOT NULL, + api_key VARCHAR(255) UNIQUE NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); +CREATE INDEX idx_users_api_key ON users(api_key); +-- +goose Down +DROP TABLE users; diff --git a/sql/seed.go b/sql/seed.go new file mode 100644 index 000000000..a4ec48e1b --- /dev/null +++ b/sql/seed.go @@ -0,0 +1,60 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/google/uuid" + "github.com/joho/godotenv" + _ "github.com/lib/pq" + "golang.org/x/crypto/bcrypt" +) + +func main() { + godotenv.Load() + config, err := server.LoadConfig() + if err != nil { + log.Fatalf("error loading config: %v", err) + } + db, err := sql.Open("postgres", config.PostgresConn) + if err != nil { + log.Fatalf("error opening database connection: %v", err) + } + defer db.Close() + + err = db.Ping() + if err != nil { + log.Fatalf("error connecting to the database: %v", err) + } + + adminUser := model.UserDB{ + ID: uuid.New(), + Username: "admin", + Password: "password", + Role: model.RoleAdmin, + APIKey: uuid.New().String(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(adminUser.Password), bcrypt.DefaultCost) + if err != nil { + log.Fatalf("error hashing password: %v", err) + } + adminUser.Password = string(hashedPassword) + + _, err = db.Exec(` + INSERT INTO users (id, username, password, role, api_key, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7) + `, adminUser.ID, adminUser.Username, adminUser.Password, adminUser.Role, adminUser.APIKey, adminUser.CreatedAt, adminUser.UpdatedAt) + + if err != nil { + log.Fatalf("Error inserting admin user: %v", err) + } + + fmt.Println("Admin user created successfully!") +} From 6a7b35754d42a8fc7c1707a2155053b0486b1c15 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Mon, 5 Aug 2024 22:19:42 -0300 Subject: [PATCH 047/141] feat(makefile): add docker and db commands to Makefile This commit adds commands for building the app image, running it and doing seeding and migration of the database. --- Makefile | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1892349e0..45344fbc3 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Simple Makefile for a Go project +include .env # Build the application all: build @@ -38,4 +38,21 @@ watch: fi; \ fi -.PHONY: all build run test clean +# Docker commands +docker-build: + docker build -t myapp . + +docker-run: + docker run -p 8080:8080 myapp + +# DB commands +migrate-up: + goose -dir ./sql/schema postgres "$(POSTGRES_CONN)" up + +migrate-down: + goose -dir ./sql/schema postgres "$(POSTGRES_CONN)" down + +seed: + go run ./sql/seed.go + +.PHONY: all build run test clean watch docker-build docker-run migrate-up migrate-down seed From e44d21c9dd82813973776ebdc00af4f7e5abe099 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 08:48:52 -0300 Subject: [PATCH 048/141] refactor(user): separate user logic into service layer This commit adds a new UserService to handle user-related business logic and updates the UserHandler to use this service. - Create new UserService with methods for user operations. - Update UserHandler to use UserService instead of directly accessing the repository. - Update UserHandler initialization and add User Service initialization on server setup. --- internal/handler/user_handler.go | 57 +++------- internal/server/routes.go | 4 +- internal/server/server.go | 3 +- internal/service/user_service.go | 104 +++++++++++++++++ internal/service/user_service_test.go | 157 ++++++++++++++++++++++++++ 5 files changed, 278 insertions(+), 47 deletions(-) create mode 100644 internal/service/user_service.go create mode 100644 internal/service/user_service_test.go diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go index 7c1e555ba..398bea6cc 100644 --- a/internal/handler/user_handler.go +++ b/internal/handler/user_handler.go @@ -3,22 +3,18 @@ package handler import ( "encoding/json" "net/http" - "time" "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/logger" - "github.com/Lutefd/challenge-bravo/internal/model" - "github.com/Lutefd/challenge-bravo/internal/repository" - "github.com/google/uuid" - "golang.org/x/crypto/bcrypt" + "github.com/Lutefd/challenge-bravo/internal/service" ) type UserHandler struct { - userRepo repository.UserRepository + userService service.UserServiceInterface } -func NewUserHandler(userRepo repository.UserRepository) *UserHandler { - return &UserHandler{userRepo: userRepo} +func NewUserHandler(userService service.UserServiceInterface) *UserHandler { + return &UserHandler{userService: userService} } func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { @@ -38,30 +34,13 @@ func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) { return } - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost) + user, err := h.userService.Create(r.Context(), credentials.Username, credentials.Password) if err != nil { - logger.Errorf("Failed to hash password: %v", err) - http.Error(w, "Internal server error", http.StatusInternalServerError) - return - } - - user := model.UserDB{ - ID: uuid.New(), - Username: credentials.Username, - Password: string(hashedPassword), - Role: model.RoleUser, - APIKey: generateAPIKey(), - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - - if err := h.userRepo.Create(r.Context(), &user); err != nil { logger.Errorf("Failed to create user: %v", err) http.Error(w, "Failed to create user", http.StatusInternalServerError) return } - user.Password = "" commons.RespondWithJSON(w, http.StatusCreated, user) } @@ -72,33 +51,23 @@ func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { } if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil { - logger.Errorf("failed to decode login request: %v", err) - http.Error(w, "invalid request payload", http.StatusBadRequest) + logger.Errorf("Failed to decode login request: %v", err) + http.Error(w, "Invalid request payload", http.StatusBadRequest) return } + if credentials.Username == "" || credentials.Password == "" { - logger.Errorf("invalid input: username or password is empty") - http.Error(w, "username and password are required", http.StatusBadRequest) + logger.Errorf("Invalid input: username or password is empty") + http.Error(w, "Username and password are required", http.StatusBadRequest) return } - userDB, err := h.userRepo.GetByUsername(r.Context(), credentials.Username) + user, err := h.userService.Authenticate(r.Context(), credentials.Username, credentials.Password) if err != nil { - logger.Errorf("failed to get user: %v", err) - http.Error(w, "invalid credentials", http.StatusUnauthorized) + logger.Errorf("Authentication failed: %v", err) + http.Error(w, "Invalid credentials", http.StatusUnauthorized) return } - if err := bcrypt.CompareHashAndPassword([]byte(userDB.Password), []byte(credentials.Password)); err != nil { - logger.Errorf("invalid password for user %s: %v", credentials.Username, err) - http.Error(w, "invalid credentials", http.StatusUnauthorized) - return - } - - user := userDB.ToUser() commons.RespondWithJSON(w, http.StatusOK, user) } - -func generateAPIKey() string { - return uuid.New().String() -} diff --git a/internal/server/routes.go b/internal/server/routes.go index 9ba5c194f..752cb0674 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -9,14 +9,14 @@ import ( "github.com/go-chi/chi/v5/middleware" ) -func (s *Server) registerRoutes(currencyService *service.CurrencyService) { +func (s *Server) registerRoutes(currencyService *service.CurrencyService, userService *service.UserService) { router := chi.NewRouter() router.Use(middleware.Logger) authMiddleware := api_middleware.NewAuthMiddleware(s.userRepo) router.Get("/healthz", handler.HandlerReadiness) currencyHandler := handler.NewCurrencyHandler(currencyService) - userHandler := handler.NewUserHandler(s.userRepo) + userHandler := handler.NewUserHandler(userService) router.Route("/auth", func(r chi.Router) { r.With(api_middleware.RateLimitMiddleware).Post("/register", userHandler.Register) r.With(api_middleware.RateLimitMiddleware).Post("/login", userHandler.Login) diff --git a/internal/server/server.go b/internal/server/server.go index 740647039..8cdd9d981 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -39,6 +39,7 @@ func NewServer(config Config) (*Server, error) { } externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) currencyService := service.NewCurrencyService(repo, redisCache, externalAPI) + userService := service.NewUserService(userRepo) rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, 1*time.Hour) server := &Server{ @@ -50,7 +51,7 @@ func NewServer(config Config) (*Server, error) { userRepo: userRepo, } - server.registerRoutes(currencyService) + server.registerRoutes(currencyService, userService) server.httpServer = &http.Server{ Addr: fmt.Sprintf(":%d", config.ServerPort), diff --git a/internal/service/user_service.go b/internal/service/user_service.go new file mode 100644 index 000000000..1a518e522 --- /dev/null +++ b/internal/service/user_service.go @@ -0,0 +1,104 @@ +package service + +import ( + "context" + "fmt" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/google/uuid" + "golang.org/x/crypto/bcrypt" +) + +type UserService struct { + userRepo repository.UserRepository +} + +func NewUserService(userRepo repository.UserRepository) *UserService { + return &UserService{userRepo: userRepo} +} + +func (s *UserService) GetByUsername(ctx context.Context, username string) (model.User, error) { + userDB, err := s.userRepo.GetByUsername(ctx, username) + if err != nil { + return model.User{}, fmt.Errorf("failed to get user: %w", err) + } + return userDB.ToUser(), nil +} + +func (s *UserService) GetByAPIKey(ctx context.Context, apiKey string) (model.User, error) { + userDB, err := s.userRepo.GetByAPIKey(ctx, apiKey) + if err != nil { + return model.User{}, fmt.Errorf("failed to get user: %w", err) + } + return userDB.ToUser(), nil +} + +func (s *UserService) Create(ctx context.Context, username, password string) (model.User, error) { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return model.User{}, fmt.Errorf("failed to hash password: %w", err) + } + + user := &model.UserDB{ + ID: uuid.New(), + Username: username, + Password: string(hashedPassword), + Role: model.RoleUser, + APIKey: generateAPIKey(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + if err := s.userRepo.Create(ctx, user); err != nil { + return model.User{}, fmt.Errorf("failed to create user: %w", err) + } + + return user.ToUser(), nil +} + +func (s *UserService) Update(ctx context.Context, username, password string) error { + userDB, err := s.userRepo.GetByUsername(ctx, username) + if err != nil { + return fmt.Errorf("failed to get user: %w", err) + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return fmt.Errorf("failed to hash password: %w", err) + } + + userDB.Password = string(hashedPassword) + userDB.UpdatedAt = time.Now() + + if err := s.userRepo.Update(ctx, userDB); err != nil { + return fmt.Errorf("failed to update user: %w", err) + } + + return nil +} + +func (s *UserService) Delete(ctx context.Context, username string) error { + if err := s.userRepo.Delete(ctx, username); err != nil { + return fmt.Errorf("failed to delete user: %w", err) + } + return nil +} + +func (s *UserService) Authenticate(ctx context.Context, username, password string) (model.User, error) { + userDB, err := s.userRepo.GetByUsername(ctx, username) + if err != nil { + return model.User{}, fmt.Errorf("invalid credentials") + } + + if err := bcrypt.CompareHashAndPassword([]byte(userDB.Password), []byte(password)); err != nil { + return model.User{}, fmt.Errorf("invalid credentials") + } + + return userDB.ToUser(), nil +} + +func generateAPIKey() string { + return uuid.New().String() +} diff --git a/internal/service/user_service_test.go b/internal/service/user_service_test.go new file mode 100644 index 000000000..401bb153b --- /dev/null +++ b/internal/service/user_service_test.go @@ -0,0 +1,157 @@ +package service + +import ( + "context" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "golang.org/x/crypto/bcrypt" +) + +type MockUserRepository struct { + mock.Mock +} + +func (m *MockUserRepository) Create(ctx context.Context, user *model.UserDB) error { + args := m.Called(ctx, user) + return args.Error(0) +} + +func (m *MockUserRepository) GetByUsername(ctx context.Context, username string) (*model.UserDB, error) { + args := m.Called(ctx, username) + return args.Get(0).(*model.UserDB), args.Error(1) +} + +func (m *MockUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) { + args := m.Called(ctx, apiKey) + return args.Get(0).(*model.UserDB), args.Error(1) +} + +func (m *MockUserRepository) Update(ctx context.Context, user *model.UserDB) error { + args := m.Called(ctx, user) + return args.Error(0) +} + +func (m *MockUserRepository) Delete(ctx context.Context, username string) error { + args := m.Called(ctx, username) + return args.Error(0) +} + +func (m *MockUserRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +func TestUserService_GetByUsername(t *testing.T) { + mockRepo := new(MockUserRepository) + service := NewUserService(mockRepo) + + ctx := context.Background() + username := "testuser" + userDB := &model.UserDB{ + ID: uuid.New(), + Username: username, + Role: model.RoleUser, + APIKey: "test-api-key", + } + + mockRepo.On("GetByUsername", ctx, username).Return(userDB, nil) + + user, err := service.GetByUsername(ctx, username) + + assert.NoError(t, err) + assert.Equal(t, username, user.Username) + assert.Equal(t, userDB.ID, user.ID) + assert.Equal(t, userDB.Role, user.Role) + assert.Equal(t, userDB.APIKey, user.APIKey) + + mockRepo.AssertExpectations(t) +} + +func TestUserService_Create(t *testing.T) { + mockRepo := new(MockUserRepository) + service := NewUserService(mockRepo) + + ctx := context.Background() + username := "newuser" + password := "password123" + + mockRepo.On("Create", ctx, mock.AnythingOfType("*model.UserDB")).Return(nil) + + user, err := service.Create(ctx, username, password) + + assert.NoError(t, err) + assert.Equal(t, username, user.Username) + assert.Equal(t, model.RoleUser, user.Role) + assert.NotEmpty(t, user.APIKey) + + mockRepo.AssertExpectations(t) +} + +func TestUserService_Authenticate(t *testing.T) { + mockRepo := new(MockUserRepository) + service := NewUserService(mockRepo) + + ctx := context.Background() + username := "testuser" + password := "password123" + + hashedPassword, _ := generateHashedPassword(password) + userDB := &model.UserDB{ + ID: uuid.New(), + Username: username, + Password: hashedPassword, + Role: model.RoleUser, + APIKey: "test-api-key", + } + + mockRepo.On("GetByUsername", ctx, username).Return(userDB, nil) + + user, err := service.Authenticate(ctx, username, password) + + assert.NoError(t, err) + assert.Equal(t, username, user.Username) + assert.Equal(t, userDB.ID, user.ID) + assert.Equal(t, userDB.Role, user.Role) + assert.Equal(t, userDB.APIKey, user.APIKey) + + mockRepo.AssertExpectations(t) +} + +func TestUserService_Authenticate_InvalidCredentials(t *testing.T) { + mockRepo := new(MockUserRepository) + service := NewUserService(mockRepo) + + ctx := context.Background() + username := "testuser" + password := "wrongpassword" + + hashedPassword, _ := generateHashedPassword("correctpassword") + userDB := &model.UserDB{ + ID: uuid.New(), + Username: username, + Password: hashedPassword, + Role: model.RoleUser, + APIKey: "test-api-key", + } + + mockRepo.On("GetByUsername", ctx, username).Return(userDB, nil) + + _, err := service.Authenticate(ctx, username, password) + + assert.Error(t, err) + assert.Equal(t, "invalid credentials", err.Error()) + + mockRepo.AssertExpectations(t) +} + +func generateHashedPassword(password string) (string, error) { + hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", err + } + return string(hashedBytes), nil +} From 3dfed75f65d6e094bc1339cecd103cc0f51154bc Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 08:52:24 -0300 Subject: [PATCH 049/141] refactor(user): implement missing methods in user repository This commit adds two new methods in the user repository along with its implementation for postgres. - Implement missing Update and Delete methods in PostgresUserRepository --- internal/repository/pg_user_repository.go | 39 +++++++++++++++++++++++ internal/repository/repository.go | 2 ++ 2 files changed, 41 insertions(+) diff --git a/internal/repository/pg_user_repository.go b/internal/repository/pg_user_repository.go index 01aa874b5..c91d108f6 100644 --- a/internal/repository/pg_user_repository.go +++ b/internal/repository/pg_user_repository.go @@ -67,6 +67,45 @@ func (r *PostgresUserRepository) GetByAPIKey(ctx context.Context, apiKey string) return &user, nil } +func (r *PostgresUserRepository) Update(ctx context.Context, user *model.UserDB) error { + query := `UPDATE users + SET password = $1, role = $2, api_key = $3, updated_at = $4 + WHERE username = $5` + result, err := r.db.ExecContext(ctx, query, user.Password, user.Role, user.APIKey, user.UpdatedAt, user.Username) + if err != nil { + return fmt.Errorf("failed to update user: %w", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to get rows affected: %w", err) + } + + if rowsAffected == 0 { + return fmt.Errorf("user not found") + } + + return nil +} +func (r *PostgresUserRepository) Delete(ctx context.Context, username string) error { + query := `DELETE FROM users WHERE username = $1` + result, err := r.db.ExecContext(ctx, query, username) + if err != nil { + return fmt.Errorf("failed to delete user: %w", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to get rows affected: %w", err) + } + + if rowsAffected == 0 { + return fmt.Errorf("user not found") + } + + return nil +} + func (r *PostgresUserRepository) Close() error { return r.db.Close() } diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 3c59855ae..6f4e2be00 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -18,5 +18,7 @@ type UserRepository interface { Create(ctx context.Context, user *model.UserDB) error GetByUsername(ctx context.Context, username string) (*model.UserDB, error) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) + Update(ctx context.Context, user *model.UserDB) error + Delete(ctx context.Context, username string) error Close() error } From f818749d887f89f84e6eef73d553eec80ff6ff60 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 08:52:57 -0300 Subject: [PATCH 050/141] refactor(user): introduce UserServiceInterface for better testability This commit introduces a UserServiceInterface to improve the testability of the UserHandler and to decouple it from the concrete UserService implementation. - Separate the definition of the services interface into its own file. - Create new UserServiceInterface in service package. - Modify UserHandler tests to use a mock that implements UserServiceInterface. --- internal/handler/user_handler_test.go | 118 +++++++++++++------------- internal/service/service.go | 22 +++++ 2 files changed, 79 insertions(+), 61 deletions(-) create mode 100644 internal/service/service.go diff --git a/internal/handler/user_handler_test.go b/internal/handler/user_handler_test.go index c9feb6a9c..848d67959 100644 --- a/internal/handler/user_handler_test.go +++ b/internal/handler/user_handler_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "net/http" "net/http/httptest" "testing" @@ -12,40 +13,56 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "golang.org/x/crypto/bcrypt" ) -type MockUserRepository struct { +type MockUserService struct { mock.Mock } -func (m *MockUserRepository) Create(ctx context.Context, user *model.UserDB) error { - args := m.Called(ctx, user) - return args.Error(0) -} - -func (m *MockUserRepository) GetByUsername(ctx context.Context, username string) (*model.UserDB, error) { +func (m *MockUserService) GetByUsername(ctx context.Context, username string) (model.User, error) { args := m.Called(ctx, username) - return args.Get(0).(*model.UserDB), args.Error(1) + return args.Get(0).(model.User), args.Error(1) } -func (m *MockUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) { + +func (m *MockUserService) GetByAPIKey(ctx context.Context, apiKey string) (model.User, error) { args := m.Called(ctx, apiKey) - return args.Get(0).(*model.UserDB), args.Error(1) + return args.Get(0).(model.User), args.Error(1) } -func (m *MockUserRepository) Close() error { - args := m.Called() +func (m *MockUserService) Create(ctx context.Context, username, password string) (model.User, error) { + args := m.Called(ctx, username, password) + return args.Get(0).(model.User), args.Error(1) +} + +func (m *MockUserService) Update(ctx context.Context, username, password string) error { + args := m.Called(ctx, username, password) return args.Error(0) } -func TestRegister(t *testing.T) { - mockRepo := new(MockUserRepository) - handler := NewUserHandler(mockRepo) +func (m *MockUserService) Delete(ctx context.Context, username string) error { + args := m.Called(ctx, username) + return args.Error(0) +} + +func (m *MockUserService) Authenticate(ctx context.Context, username, password string) (model.User, error) { + args := m.Called(ctx, username, password) + return args.Get(0).(model.User), args.Error(1) +} + +func TestUserHandler_Register(t *testing.T) { + mockService := new(MockUserService) + handler := NewUserHandler(mockService) t.Run("Successful registration", func(t *testing.T) { - mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.UserDB")).Return(nil).Once() + newUser := model.User{ + ID: uuid.New(), + Username: "newuser", + Role: model.RoleUser, + APIKey: "test-api-key", + } + mockService.On("Create", mock.Anything, "newuser", "password123").Return(newUser, nil).Once() - body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + body := bytes.NewBufferString(`{"username":"newuser","password":"password123"}`) req, _ := http.NewRequest("POST", "/register", body) rr := httptest.NewRecorder() @@ -53,14 +70,12 @@ func TestRegister(t *testing.T) { assert.Equal(t, http.StatusCreated, rr.Code) - var response model.UserDB + var response model.User err := json.Unmarshal(rr.Body.Bytes(), &response) assert.NoError(t, err) - assert.NotEmpty(t, response.ID) - assert.Equal(t, "testuser", response.Username) - assert.Empty(t, response.Password) // Password should not be returned - assert.Equal(t, model.RoleUser, response.Role) - assert.NotEmpty(t, response.APIKey) + assert.Equal(t, newUser, response) + + mockService.AssertExpectations(t) }) t.Run("Invalid request payload", func(t *testing.T) { @@ -83,35 +98,35 @@ func TestRegister(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rr.Code) }) - t.Run("Repository error", func(t *testing.T) { - mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.UserDB")).Return(assert.AnError).Once() + t.Run("Service error", func(t *testing.T) { + mockService.On("Create", mock.Anything, "newuser", "password123").Return(model.User{}, errors.New("service error")).Once() - body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + body := bytes.NewBufferString(`{"username":"newuser","password":"password123"}`) req, _ := http.NewRequest("POST", "/register", body) rr := httptest.NewRecorder() handler.Register(rr, req) assert.Equal(t, http.StatusInternalServerError, rr.Code) + + mockService.AssertExpectations(t) }) } -func TestLogin(t *testing.T) { - mockRepo := new(MockUserRepository) - handler := NewUserHandler(mockRepo) +func TestUserHandler_Login(t *testing.T) { + mockService := new(MockUserService) + handler := NewUserHandler(mockService) t.Run("Successful login", func(t *testing.T) { - hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("testpass"), bcrypt.DefaultCost) - mockUser := &model.UserDB{ + authenticatedUser := model.User{ ID: uuid.New(), Username: "testuser", - Password: string(hashedPassword), Role: model.RoleUser, APIKey: "test-api-key", } - mockRepo.On("GetByUsername", mock.Anything, "testuser").Return(mockUser, nil).Once() + mockService.On("Authenticate", mock.Anything, "testuser", "password123").Return(authenticatedUser, nil).Once() - body := bytes.NewBufferString(`{"username":"testuser","password":"testpass"}`) + body := bytes.NewBufferString(`{"username":"testuser","password":"password123"}`) req, _ := http.NewRequest("POST", "/login", body) rr := httptest.NewRecorder() @@ -122,10 +137,9 @@ func TestLogin(t *testing.T) { var response model.User err := json.Unmarshal(rr.Body.Bytes(), &response) assert.NoError(t, err) - assert.Equal(t, mockUser.ID, response.ID) - assert.Equal(t, "testuser", response.Username) - assert.Equal(t, model.RoleUser, response.Role) - assert.Equal(t, "test-api-key", response.APIKey) + assert.Equal(t, authenticatedUser, response) + + mockService.AssertExpectations(t) }) t.Run("Invalid request payload", func(t *testing.T) { @@ -148,35 +162,17 @@ func TestLogin(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rr.Code) }) - t.Run("User not found", func(t *testing.T) { - mockRepo.On("GetByUsername", mock.Anything, "nonexistent").Return((*model.UserDB)(nil), assert.AnError).Once() + t.Run("Authentication failure", func(t *testing.T) { + mockService.On("Authenticate", mock.Anything, "testuser", "wrongpassword").Return(model.User{}, errors.New("invalid credentials")).Once() - body := bytes.NewBufferString(`{"username":"nonexistent","password":"testpass"}`) + body := bytes.NewBufferString(`{"username":"testuser","password":"wrongpassword"}`) req, _ := http.NewRequest("POST", "/login", body) rr := httptest.NewRecorder() handler.Login(rr, req) assert.Equal(t, http.StatusUnauthorized, rr.Code) - }) - - t.Run("Incorrect password", func(t *testing.T) { - hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("correctpass"), bcrypt.DefaultCost) - mockUser := &model.UserDB{ - ID: uuid.New(), - Username: "testuser", - Password: string(hashedPassword), - Role: model.RoleUser, - APIKey: "test-api-key", - } - mockRepo.On("GetByUsername", mock.Anything, "testuser").Return(mockUser, nil).Once() - - body := bytes.NewBufferString(`{"username":"testuser","password":"wrongpass"}`) - req, _ := http.NewRequest("POST", "/login", body) - rr := httptest.NewRecorder() - - handler.Login(rr, req) - assert.Equal(t, http.StatusUnauthorized, rr.Code) + mockService.AssertExpectations(t) }) } diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 000000000..c8dff9046 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,22 @@ +package service + +import ( + "context" + + "github.com/Lutefd/challenge-bravo/internal/model" +) + +type CurrencyServiceInterface interface { + Convert(ctx context.Context, from, to string, amount float64) (float64, error) + AddCurrency(ctx context.Context, code string, rate float64) error + RemoveCurrency(ctx context.Context, code string) error +} + +type UserServiceInterface interface { + GetByUsername(ctx context.Context, username string) (model.User, error) + GetByAPIKey(ctx context.Context, apiKey string) (model.User, error) + Authenticate(ctx context.Context, username, password string) (model.User, error) + Create(ctx context.Context, username, password string) (model.User, error) + Update(ctx context.Context, username, password string) error + Delete(ctx context.Context, username string) error +} From 5524eac535601416b2c4f3b579be068f8daa71df Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 08:57:13 -0300 Subject: [PATCH 051/141] refactor(currency): update currency handler to depend on the service interface This commit updates the currency handler to depend on the currency service interface instead of the concrete user service to improve testability and creation of mock methods. --- internal/handler/currency_handler.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index 0493948bc..b1a055e29 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -12,10 +12,10 @@ import ( ) type CurrencyHandler struct { - currencyService *service.CurrencyService + currencyService service.CurrencyServiceInterface } -func NewCurrencyHandler(currencyService *service.CurrencyService) *CurrencyHandler { +func NewCurrencyHandler(currencyService service.CurrencyServiceInterface) *CurrencyHandler { return &CurrencyHandler{ currencyService: currencyService, } @@ -91,7 +91,6 @@ func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") return } - if err := h.currencyService.RemoveCurrency(r.Context(), code); err != nil { commons.RespondWithError(w, http.StatusInternalServerError, "failed to remove currency") return From 185364485ccadfa32e64eb52539d8f608fb5d319 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 09:00:40 -0300 Subject: [PATCH 052/141] tests(handler): add currency handler tests This commit adds tests for the currency handler endpoints to ensure correct functionality. Tests include: - TestConvertCurrency: Tests for successful conversion and missing parameters. - TestAddCurrency: Tests for successful currency addition and handling of invalid payloads. - TestRemoveCurrency: Tests for successful currency removal and handling of invalid currency codes. --- internal/handler/currency_handler_test.go | 152 ++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 internal/handler/currency_handler_test.go diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go new file mode 100644 index 000000000..60bcc8e66 --- /dev/null +++ b/internal/handler/currency_handler_test.go @@ -0,0 +1,152 @@ +package handler_test + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/handler" + "github.com/go-chi/chi/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type MockCurrencyService struct { + mock.Mock +} + +func (m *MockCurrencyService) Convert(ctx context.Context, from, to string, amount float64) (float64, error) { + args := m.Called(ctx, from, to, amount) + return args.Get(0).(float64), args.Error(1) +} + +func (m *MockCurrencyService) AddCurrency(ctx context.Context, code string, rate float64) error { + args := m.Called(ctx, code, rate) + return args.Error(0) +} + +func (m *MockCurrencyService) RemoveCurrency(ctx context.Context, code string) error { + args := m.Called(ctx, code) + return args.Error(0) +} + +func TestConvertCurrency(t *testing.T) { + mockService := new(MockCurrencyService) + h := handler.NewCurrencyHandler(mockService) + + t.Run("Success", func(t *testing.T) { + req, err := http.NewRequest("GET", "/convert?from=USD&to=EUR&amount=100", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + mockService.On("Convert", mock.Anything, "USD", "EUR", 100.0).Return(90.0, nil) + + handler := http.HandlerFunc(h.ConvertCurrency) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + assert.JSONEq(t, `{"from":"USD","to":"EUR","amount":100,"result":90}`, rr.Body.String()) + mockService.AssertExpectations(t) + }) + + t.Run("Missing Parameters", func(t *testing.T) { + req, err := http.NewRequest("GET", "/convert", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(h.ConvertCurrency) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.JSONEq(t, `{"error":"Missing required parameters"}`, rr.Body.String()) + }) + +} + +func TestAddCurrency(t *testing.T) { + mockService := new(MockCurrencyService) + h := handler.NewCurrencyHandler(mockService) + + t.Run("Success", func(t *testing.T) { + body := strings.NewReader(`{"code":"USD","rate":1.0}`) + req, err := http.NewRequest("POST", "/currency", body) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + mockService.On("AddCurrency", mock.Anything, "USD", 1.0).Return(nil) + + handler := http.HandlerFunc(h.AddCurrency) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusCreated, rr.Code) + assert.JSONEq(t, `{"message":"currency added successfully"}`, rr.Body.String()) + mockService.AssertExpectations(t) + }) + + t.Run("Invalid Payload", func(t *testing.T) { + body := strings.NewReader(`{"code":"USD"}`) + req, err := http.NewRequest("POST", "/currency", body) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(h.AddCurrency) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.JSONEq(t, `{"error":"invalid currency code or rate"}`, rr.Body.String()) + }) + +} + +func TestRemoveCurrency(t *testing.T) { + mockService := new(MockCurrencyService) + h := handler.NewCurrencyHandler(mockService) + + t.Run("Success", func(t *testing.T) { + req, err := http.NewRequest("DELETE", "/currency/USD", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + mockService.On("RemoveCurrency", mock.Anything, "USD").Return(nil) + + router := chi.NewRouter() + router.Delete("/currency/{code}", h.RemoveCurrency) + router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + assert.JSONEq(t, `{"message":"currency removed successfully"}`, rr.Body.String()) + mockService.AssertExpectations(t) + }) + + t.Run("Invalid Code - Empty", func(t *testing.T) { + req, err := http.NewRequest("DELETE", "/currency/", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + + router := chi.NewRouter() + router.Delete("/currency/{code}", h.RemoveCurrency) + router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusNotFound, rr.Code) + }) + + t.Run("Invalid Code - Length", func(t *testing.T) { + req, err := http.NewRequest("DELETE", "/currency/RR", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + + router := chi.NewRouter() + router.Delete("/currency/{code}", h.RemoveCurrency) + router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.JSONEq(t, `{"error":"invalid currency code, must be 3 characters long following ISO 4217"}`, rr.Body.String()) + + }) +} From 460054d96bd481209ef68161469c0612ee52dba3 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 09:01:42 -0300 Subject: [PATCH 053/141] refactor(model): simplify ExchangeRates struct This commit refactors the ExchangeRates struct by removing unused fields, that would facilitate changing the external api client. Changes include: - Removing the Disclaimer and License fields from the ExchangeRates struct. - Keeping only the Timestamp, Base, and Rates fields for simplicity and relevance. --- internal/model/currency.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/internal/model/currency.go b/internal/model/currency.go index ea52bf304..5dbe87ef4 100644 --- a/internal/model/currency.go +++ b/internal/model/currency.go @@ -11,9 +11,7 @@ type Currency struct { } type ExchangeRates struct { - Disclaimer string `json:"disclaimer"` - License string `json:"license"` - Timestamp int64 `json:"timestamp"` - Base string `json:"base"` - Rates map[string]float64 `json:"rates"` + Timestamp int64 `json:"timestamp"` + Base string `json:"base"` + Rates map[string]float64 `json:"rates"` } From d701c097cdf9d86c271031ab857e5fdddd010c91 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 09:02:46 -0300 Subject: [PATCH 054/141] chore(env): add sample environment configuration file This commit adds a sample environment configuration file (.env.sample) to the project. The file includes the following environment variables: - POSTGRES_HOST: Host address for the PostgreSQL database. - POSTGRES_USER: Username for the PostgreSQL database. - POSTGRES_PASSWORD: Password for the PostgreSQL database. - POSTGRES_NAME: Database name for the PostgreSQL database. - POSTGRES_CONN: Connection string for the PostgreSQL database. - SERVER_PORT: Port on which the server will run. - REDIS_PASSWORD: Password for the Redis server. - REDIS_ADDR: Address for the Redis server. - API_KEY: API key for external services. --- .env.sample | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 000000000..87eb7d4f6 --- /dev/null +++ b/.env.sample @@ -0,0 +1,9 @@ +POSTGRES_HOST=0.0.0.0 +POSTGRES_USER=curr +POSTGRES_PASSWORD=currpass +POSTGRES_NAME=currdb +POSTGRES_CONN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_NAME}?sslmode=disable +SERVER_PORT=8080 +REDIS_PASSWORD=redis_pass +REDIS_ADDR="localhost:6379" +API_KEY=your_api_key From 29761884f7d89754c9ef3e10491923b9ad00fbc7 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 09:04:29 -0300 Subject: [PATCH 055/141] chore(dependencies): add testify and other indirect dependencies This commit updates the go.mod file to include new dependencies for testing and other utilities. Changes include: - Adding github.com/stretchr/testify for test assertions and mocking. - Adding github.com/davecgh/go-spew for deep pretty printing of Go data structures (indirect). - Adding github.com/pmezard/go-difflib for diffs of Go data structures (indirect). - Adding github.com/stretchr/objx for manipulating maps, slices, and JSON (indirect). - Adding gopkg.in/yaml.v3 for YAML parsing and encoding (indirect). --- go.mod | 5 +++++ go.sum | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/go.mod b/go.mod index 851c0acf5..969de9242 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,16 @@ require ( github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 github.com/redis/go-redis/v9 v9.6.1 + github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.25.0 golang.org/x/time v0.6.0 ) require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 19974a535..b40ed4aca 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= @@ -14,9 +16,19 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From ae302113fca237c21b9fb941e288ed575c7e32ba Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:26:22 -0300 Subject: [PATCH 056/141] feat(model): add Log model for logging This commit adds a Log model to the project for handling logging entries. The Log model includes the following fields: - ID: Unique identifier for the log entry. - Level: The log level, which can be either 'INFO' or 'ERROR'. - Message: The log message. - Timestamp: The time the log entry was created. - Source: The source of the log entry, for now everything is being saved as application. Additionally, the following SQL migration is included: - 003_logs.sql: Creates the logs table with partitions by month, and indexes on timestamp and level for efficient querying. --- internal/model/log.go | 22 ++++++++++++++++++++++ sql/schema/003_logs.sql | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 internal/model/log.go create mode 100644 sql/schema/003_logs.sql diff --git a/internal/model/log.go b/internal/model/log.go new file mode 100644 index 000000000..3b64ae882 --- /dev/null +++ b/internal/model/log.go @@ -0,0 +1,22 @@ +package model + +import ( + "time" + + "github.com/google/uuid" +) + +type LogLevel string + +const ( + LogLevelInfo LogLevel = "INFO" + LogLevelError LogLevel = "ERROR" +) + +type Log struct { + ID uuid.UUID `json:"id"` + Level LogLevel `json:"level"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + Source string `json:"source"` +} diff --git a/sql/schema/003_logs.sql b/sql/schema/003_logs.sql new file mode 100644 index 000000000..a964ef45a --- /dev/null +++ b/sql/schema/003_logs.sql @@ -0,0 +1,24 @@ +-- +goose Up +CREATE TABLE logs ( + id UUID NOT NULL, + level VARCHAR(10) NOT NULL, + message TEXT NOT NULL, + timestamp TIMESTAMP NOT NULL, + source VARCHAR(255) NOT NULL, + PRIMARY KEY (id, timestamp) +) PARTITION BY RANGE (timestamp); + +CREATE TABLE logs_y2024m08 PARTITION OF logs + FOR VALUES FROM ('2024-08-01') TO ('2024-09-01'); + +CREATE TABLE logs_y2024m09 PARTITION OF logs + FOR VALUES FROM ('2024-09-01') TO ('2024-10-01'); + + CREATE TABLE logs_y2024m10 PARTITION OF logs + FOR VALUES FROM ('2024-10-01') TO ('2024-11-01'); + +CREATE INDEX idx_logs_timestamp ON logs (timestamp); +CREATE INDEX idx_logs_level ON logs (level); + +-- +goose Down +DROP TABLE logs; From cc166606a0941289d4bc475bbb2adcdf62a81bf8 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:29:18 -0300 Subject: [PATCH 057/141] feat(repository): add LogRepository interface and PostgreSQL implementation This commit adds the LogRepository interface and its PostgreSQL implementation. Changes include: - Adding SaveLog, CreatePartition, and Close methods to the LogRepository interface. - Implementing the LogRepository interface in the PostgresLogRepository struct. - NewPostgresLogRepository: Initializes a new PostgresLogRepository with a given connection URL. - SaveLog: Saves a log entry to the logs table in the database. - CreatePartition: Creates a new partition for the logs table based on the month. - Close: Closes the database connection. --- internal/repository/pg_logger_repository.go | 60 +++++++++++++++++++++ internal/repository/repository.go | 7 +++ 2 files changed, 67 insertions(+) create mode 100644 internal/repository/pg_logger_repository.go diff --git a/internal/repository/pg_logger_repository.go b/internal/repository/pg_logger_repository.go new file mode 100644 index 000000000..b671e3465 --- /dev/null +++ b/internal/repository/pg_logger_repository.go @@ -0,0 +1,60 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" +) + +type PostgresLogRepository struct { + db *sql.DB +} + +func NewPostgresLogRepository(connURL string) (*PostgresLogRepository, error) { + db, err := sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } + + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } + + return &PostgresLogRepository{db: db}, nil +} + +func (r *PostgresLogRepository) SaveLog(ctx context.Context, log model.Log) error { + _, err := r.db.ExecContext(ctx, ` + INSERT INTO logs (id, level, message, timestamp, source) + VALUES ($1, $2, $3, $4, $5) + `, log.ID, log.Level, log.Message, log.Timestamp, log.Source) + if err != nil { + return fmt.Errorf("failed to save log: %w", err) + } + return nil +} + +func (r *PostgresLogRepository) CreatePartition(ctx context.Context, month time.Time) error { + partitionName := fmt.Sprintf("logs_y%04dm%02d", month.Year(), month.Month()) + startDate := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, time.UTC) + endDate := startDate.AddDate(0, 1, 0) + + query := fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s PARTITION OF logs + FOR VALUES FROM ('%s') TO ('%s') + `, partitionName, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + + _, err := r.db.ExecContext(ctx, query) + if err != nil { + return fmt.Errorf("failed to create partition %s: %w", partitionName, err) + } + + return nil +} +func (r *PostgresLogRepository) Close() error { + return r.db.Close() +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 6f4e2be00..61ed870f9 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -2,6 +2,7 @@ package repository import ( "context" + "time" "github.com/Lutefd/challenge-bravo/internal/model" ) @@ -22,3 +23,9 @@ type UserRepository interface { Delete(ctx context.Context, username string) error Close() error } + +type LogRepository interface { + SaveLog(ctx context.Context, log model.Log) error + CreatePartition(ctx context.Context, month time.Time) error + Close() error +} From b1c2ee3bc0974cd34f7f82e5f0be11994a61cb16 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:30:43 -0300 Subject: [PATCH 058/141] feat(logger): add asynchronous logging and persistent log storage This commit enhances the logger package by adding asynchronous logging and persistent log storage. Changes include: - Adding a log channel (logChan) for asynchronous logging. - Introducing the InitLogger function to initialize the logger with a repository and start processing logs. - Implementing the processLogs function to save logs asynchronously to the repository. - Updating log functions (Info, Infof, Error, Errorf) to use asynchronous logging. - Adding the Shutdown function to gracefully shut down the logger and ensure all logs are processed. Aditionally this commit also include the test for the modifications above --- internal/logger/logger.go | 69 ++++++++++++++++++++++++++++-- internal/logger/logger_test.go | 76 ++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 internal/logger/logger_test.go diff --git a/internal/logger/logger.go b/internal/logger/logger.go index a8de60c82..83766ec7b 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -1,32 +1,93 @@ package logger import ( + "context" + "fmt" "log" "os" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/google/uuid" ) var ( InfoLogger *log.Logger ErrorLogger *log.Logger + logChan chan model.Log + logRepo repository.LogRepository ) func init() { InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + logChan = make(chan model.Log, 1000) +} + +func InitLogger(repo repository.LogRepository) { + logRepo = repo + go processLogs() +} + +func processLogs() { + for logEntry := range logChan { + if err := logRepo.SaveLog(context.Background(), logEntry); err != nil { + ErrorLogger.Printf("failed to save log: %v", err) + } + } +} + +func logAsync(level model.LogLevel, message string) { + logEntry := model.Log{ + ID: uuid.New(), + Level: level, + Message: message, + Timestamp: time.Now(), + Source: "application", + } + + select { + case logChan <- logEntry: + default: + ErrorLogger.Printf("log channel full. Dropping log: %v", logEntry) + } + + if level == model.LogLevelInfo { + InfoLogger.Println(message) + } else { + ErrorLogger.Println(message) + } } func Info(v ...interface{}) { - InfoLogger.Println(v...) + logAsync(model.LogLevelInfo, fmt.Sprint(v...)) } func Infof(format string, v ...interface{}) { - InfoLogger.Printf(format, v...) + logAsync(model.LogLevelInfo, fmt.Sprintf(format, v...)) } func Error(v ...interface{}) { - ErrorLogger.Println(v...) + logAsync(model.LogLevelError, fmt.Sprint(v...)) } func Errorf(format string, v ...interface{}) { - ErrorLogger.Printf(format, v...) + logAsync(model.LogLevelError, fmt.Sprintf(format, v...)) +} + +func Shutdown(ctx context.Context) error { + close(logChan) + + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + if len(logChan) == 0 { + return logRepo.Close() + } + time.Sleep(100 * time.Millisecond) + } + } } diff --git a/internal/logger/logger_test.go b/internal/logger/logger_test.go new file mode 100644 index 000000000..2da4b0516 --- /dev/null +++ b/internal/logger/logger_test.go @@ -0,0 +1,76 @@ +package logger_test + +import ( + "context" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/logger" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type MockLogRepository struct { + mock.Mock +} + +func (m *MockLogRepository) SaveLog(ctx context.Context, log model.Log) error { + args := m.Called(ctx, log) + return args.Error(0) +} +func (m *MockLogRepository) CreatePartition(ctx context.Context, time time.Time) error { + args := m.Called(ctx, time) + return args.Error(0) +} +func (m *MockLogRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +func TestLogger_Info(t *testing.T) { + mockRepo := new(MockLogRepository) + logger.InitLogger(mockRepo) + + mockRepo.On("SaveLog", mock.Anything, mock.AnythingOfType("model.Log")).Return(nil) + + logger.Info("Test info message") + + time.Sleep(100 * time.Millisecond) + + mockRepo.AssertCalled(t, "SaveLog", mock.Anything, mock.MatchedBy(func(log model.Log) bool { + return log.Level == model.LogLevelInfo && log.Message == "Test info message" + })) +} + +func TestLogger_Error(t *testing.T) { + mockRepo := new(MockLogRepository) + logger.InitLogger(mockRepo) + + mockRepo.On("SaveLog", mock.Anything, mock.AnythingOfType("model.Log")).Return(nil) + + logger.Error("Test error message") + + time.Sleep(100 * time.Millisecond) + mockRepo.AssertCalled(t, "SaveLog", mock.Anything, mock.MatchedBy(func(log model.Log) bool { + return log.Level == model.LogLevelError && log.Message == "Test error message" + })) +} + +func TestLogger_Shutdown(t *testing.T) { + mockRepo := new(MockLogRepository) + logger.InitLogger(mockRepo) + + mockRepo.On("SaveLog", mock.Anything, mock.AnythingOfType("model.Log")).Return(nil) + mockRepo.On("Close").Return(nil) + + logger.Info("Test shutdown message") + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + err := logger.Shutdown(ctx) + assert.NoError(t, err) + + mockRepo.AssertCalled(t, "Close") +} From f4126f1fc7f21b98db7a76b97b1585054f72e831 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:32:24 -0300 Subject: [PATCH 059/141] feat(logger): add partition manager for log table partitions This commit adds a PartitionManager to handle the creation of log table partitions. Changes include: - NewPartitionManager: Initializes the PartitionManager with a log repository and sets up a cron job. - Start: Starts the partition manager, creating initial partitions and starting the cron job. - createInitialPartitions: Creates log partitions for the next three months. - createNextMonthPartition: Creates a log partition for the month three months from now. - createNextMonthPartitionWrapper: Wrapper function for the cron job to create the next month's partition. Aditionally, this commit also adds the tests for the PartitionManager --- internal/logger/partition_manager.go | 67 ++++++++++ internal/logger/partition_manager_test.go | 146 ++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 internal/logger/partition_manager.go create mode 100644 internal/logger/partition_manager_test.go diff --git a/internal/logger/partition_manager.go b/internal/logger/partition_manager.go new file mode 100644 index 000000000..824477adb --- /dev/null +++ b/internal/logger/partition_manager.go @@ -0,0 +1,67 @@ +package logger + +import ( + "context" + "time" + + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/robfig/cron/v3" +) + +type PartitionManager struct { + repo repository.LogRepository + cron *cron.Cron +} + +func NewPartitionManager(repo repository.LogRepository) *PartitionManager { + c := cron.New() + pm := &PartitionManager{ + repo: repo, + cron: c, + } + + _, err := c.AddFunc("0 0 1 * *", pm.createNextMonthPartitionWrapper) + if err != nil { + Errorf("failed to add cron job: %v\n", err) + } + + return pm +} + +func (pm *PartitionManager) Start(ctx context.Context) error { + if err := pm.createInitialPartitions(ctx); err != nil { + Errorf("failed to create initial partitions: %s", err) + } + + pm.cron.Start() + + go func() { + <-ctx.Done() + pm.cron.Stop() + }() + + return nil +} + +func (pm *PartitionManager) createInitialPartitions(ctx context.Context) error { + now := time.Now() + for i := 0; i < 3; i++ { + month := now.AddDate(0, i, 0) + if err := pm.repo.CreatePartition(ctx, month); err != nil { + return err + } + } + return nil +} + +func (pm *PartitionManager) createNextMonthPartition(ctx context.Context) error { + nextMonth := time.Now().AddDate(0, 3, 0) + return pm.repo.CreatePartition(ctx, nextMonth) +} + +func (pm *PartitionManager) createNextMonthPartitionWrapper() { + ctx := context.Background() + if err := pm.createNextMonthPartition(ctx); err != nil { + Errorf("failed to create next month partition: %v\n", err) + } +} diff --git a/internal/logger/partition_manager_test.go b/internal/logger/partition_manager_test.go new file mode 100644 index 000000000..3dbddf323 --- /dev/null +++ b/internal/logger/partition_manager_test.go @@ -0,0 +1,146 @@ +package logger + +import ( + "context" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type MockLogRepository struct { + mock.Mock +} + +func (m *MockLogRepository) SaveLog(ctx context.Context, log model.Log) error { + args := m.Called(ctx, log) + return args.Error(0) +} + +func (m *MockLogRepository) CreatePartition(ctx context.Context, month time.Time) error { + args := m.Called(ctx, month) + return args.Error(0) +} + +func (m *MockLogRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +func TestNewPartitionManager(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + assert.NotNil(t, pm) + assert.Equal(t, mockRepo, pm.repo) + assert.NotNil(t, pm.cron) +} + +func timeEqual(t1, t2 time.Time) bool { + return t1.Year() == t2.Year() && + t1.Month() == t2.Month() && + t1.Day() == t2.Day() && + t1.Hour() == t2.Hour() && + t1.Minute() == t2.Minute() && + t1.Second() == t2.Second() +} + +func TestPartitionManager_Start(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now()) + })).Return(nil) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now().AddDate(0, 1, 0)) + })).Return(nil) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now().AddDate(0, 2, 0)) + })).Return(nil) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + err := pm.Start(ctx) + assert.NoError(t, err) + + time.Sleep(100 * time.Millisecond) + + mockRepo.AssertExpectations(t) + + cancel() +} + +func TestPartitionManager_createInitialPartitions(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now()) + })).Return(nil) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now().AddDate(0, 1, 0)) + })).Return(nil) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now().AddDate(0, 2, 0)) + })).Return(nil) + + err := pm.createInitialPartitions(context.Background()) + assert.NoError(t, err) + + mockRepo.AssertExpectations(t) +} + +func TestPartitionManager_createNextMonthPartition(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + expectedMonth := time.Now().AddDate(0, 3, 0) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return t.Year() == expectedMonth.Year() && t.Month() == expectedMonth.Month() + })).Return(nil) + + err := pm.createNextMonthPartition(context.Background()) + assert.NoError(t, err) + + mockRepo.AssertExpectations(t) +} +func TestPartitionManager_Start_FailedInitialPartition(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now()) + })).Return(nil) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(t time.Time) bool { + return timeEqual(t, time.Now().AddDate(0, 1, 0)) + })).Return(assert.AnError) + + err := pm.Start(context.Background()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to create initial partitions") + + mockRepo.AssertExpectations(t) +} + +func TestPartitionManager_cronJob(t *testing.T) { + mockRepo := new(MockLogRepository) + pm := NewPartitionManager(mockRepo) + + nextMonth := time.Now().AddDate(0, 3, 0) + mockRepo.On("CreatePartition", mock.Anything, mock.MatchedBy(func(month time.Time) bool { + return month.Year() == nextMonth.Year() && month.Month() == nextMonth.Month() + })).Return(nil) + + pm.cron.Start() + entries := pm.cron.Entries() + assert.Len(t, entries, 1) + entries[0].Job.Run() + + time.Sleep(100 * time.Millisecond) + + mockRepo.AssertExpectations(t) +} From 946fc273a206b6326da57b5c400574f5b92195fb Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:33:21 -0300 Subject: [PATCH 060/141] feat(server): integrate logging and partition management into server This commit enhances the server initialization to include logging and partition management. Changes include: - Initializing the PostgresLogRepository within the NewServer function. - Adding the logRepo field to the Server struct. - Initializing the logger with the log repository and starting the PartitionManager. - Updating the Shutdown method to include graceful shutdown of the logger. - Ensuring proper error handling for log repository initialization and partition manager startup. --- internal/server/server.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 8cdd9d981..46d4d3a08 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -22,6 +22,7 @@ type Server struct { currencyCache cache.Cache externalAPI worker.ExternalAPIClient userRepo repository.UserRepository + logRepo repository.LogRepository } func NewServer(config Config) (*Server, error) { @@ -33,6 +34,10 @@ func NewServer(config Config) (*Server, error) { if err != nil { return nil, fmt.Errorf("failed to initialize user repository: %w", err) } + logRepo, err := repository.NewPostgresLogRepository(config.PostgresConn) + if err != nil { + return nil, fmt.Errorf("failed to initialize log repository: %w", err) + } redisCache, err := cache.NewRedisCache(config.RedisAddr, config.RedisPass) if err != nil { return nil, fmt.Errorf("failed to initialize cache: %w", err) @@ -41,7 +46,11 @@ func NewServer(config Config) (*Server, error) { currencyService := service.NewCurrencyService(repo, redisCache, externalAPI) userService := service.NewUserService(userRepo) rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, 1*time.Hour) - + logger.InitLogger(logRepo) + partManager := logger.NewPartitionManager(logRepo) + if err := partManager.Start(context.Background()); err != nil { + return nil, fmt.Errorf("failed to start partition manager: %w", err) + } server := &Server{ config: config, currencyRepo: repo, @@ -49,6 +58,7 @@ func NewServer(config Config) (*Server, error) { externalAPI: externalAPI, rateUpdater: rateUpdater, userRepo: userRepo, + logRepo: logRepo, } server.registerRoutes(currencyService, userService) @@ -94,7 +104,10 @@ func (s *Server) Shutdown() error { logger.Errorf("cache connection close error: %v", err) return err } + if err := logger.Shutdown(ctx); err != nil { + logger.Errorf("error shutting down logger: %v", err) + } - logger.Info("server shutdown complete") + fmt.Println("server shutdown complete") return nil } From c1430b8d946f0a294d3f2380dff357550b157938 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:35:13 -0300 Subject: [PATCH 061/141] chore(dependencies): add cron dependency for scheduled tasks This commit updates the go.mod file to include the github.com/robfig/cron/v3 dependency for managing scheduled tasks such as partition management. --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 969de9242..8cf880da4 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 github.com/redis/go-redis/v9 v9.6.1 + github.com/robfig/cron/v3 v3.0.1 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.25.0 golang.org/x/time v0.6.0 diff --git a/go.sum b/go.sum index b40ed4aca..7c0dae656 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= From 1fbd3aaa334f62ba4838b42c0d84504c2b3aef3a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 10:55:59 -0300 Subject: [PATCH 062/141] fix(logger): add error return in PartitionManager Start method This commit adds an error return in the PartitionManager Start method if the initial partition creation fails. --- internal/logger/partition_manager.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/logger/partition_manager.go b/internal/logger/partition_manager.go index 824477adb..5c00f7c21 100644 --- a/internal/logger/partition_manager.go +++ b/internal/logger/partition_manager.go @@ -2,6 +2,7 @@ package logger import ( "context" + "fmt" "time" "github.com/Lutefd/challenge-bravo/internal/repository" @@ -31,6 +32,7 @@ func NewPartitionManager(repo repository.LogRepository) *PartitionManager { func (pm *PartitionManager) Start(ctx context.Context) error { if err := pm.createInitialPartitions(ctx); err != nil { Errorf("failed to create initial partitions: %s", err) + return fmt.Errorf("failed to create initial partitions: %w", err) } pm.cron.Start() From 55f2c215d5913ce98dd79fd1989b71009840361e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 11:33:43 -0300 Subject: [PATCH 063/141] refactor(commons): update error logging and add tests for JSON responses This commit refactors the commons package to improve error logging and adds tests for JSON response functions. Changes include: - Updating RespondWithError to use the logger package for errors. - Adding a new file json_test.go with tests for RespondWithError and RespondWithJSON. - Ensuring proper logging and response handling in both functions. --- internal/commons/json.go | 6 +- internal/commons/json_test.go | 137 ++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 internal/commons/json_test.go diff --git a/internal/commons/json.go b/internal/commons/json.go index ab1571841..54b6b3598 100644 --- a/internal/commons/json.go +++ b/internal/commons/json.go @@ -4,11 +4,13 @@ import ( "encoding/json" "log" "net/http" + + "github.com/Lutefd/challenge-bravo/internal/logger" ) func RespondWithError(w http.ResponseWriter, code int, msg string) { if code > 499 { - log.Printf("Responding with 5XX error: %s", msg) + logger.Errorf("responding with %d error: %s", code, msg) } type errorResponse struct { Error string `json:"error"` @@ -22,7 +24,7 @@ func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) { w.Header().Set("Content-Type", "application/json") dat, err := json.Marshal(payload) if err != nil { - log.Printf("Error marshalling JSON: %s", err) + log.Printf("error marshalling JSON: %s", err) w.WriteHeader(500) return } diff --git a/internal/commons/json_test.go b/internal/commons/json_test.go new file mode 100644 index 000000000..67874d474 --- /dev/null +++ b/internal/commons/json_test.go @@ -0,0 +1,137 @@ +package commons_test + +import ( + "bytes" + "encoding/json" + "log" + "net/http/httptest" + "strings" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/logger" +) + +func TestRespondWithError(t *testing.T) { + var buf bytes.Buffer + oldErrorLogger := logger.ErrorLogger + logger.ErrorLogger = log.New(&buf, "", 0) + defer func() { logger.ErrorLogger = oldErrorLogger }() + + tests := []struct { + name string + code int + msg string + expectedLog string + expectedStatus int + expectedBody string + }{ + { + name: "4xx error", + code: 400, + msg: "Bad Request", + expectedLog: "", + expectedStatus: 400, + expectedBody: `{"error":"Bad Request"}`, + }, + { + name: "5xx error", + code: 500, + msg: "Internal Server Error", + expectedLog: "responding with 500 error: Internal Server Error", + expectedStatus: 500, + expectedBody: `{"error":"Internal Server Error"}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf.Reset() + w := httptest.NewRecorder() + commons.RespondWithError(w, tt.code, tt.msg) + + if tt.expectedLog != "" { + logOutput := strings.TrimSpace(buf.String()) + if !strings.Contains(logOutput, tt.expectedLog) { + t.Errorf("Expected log to contain: %s, got: %s", tt.expectedLog, logOutput) + } + } + + if w.Code != tt.expectedStatus { + t.Errorf("Expected status code: %d, got: %d", tt.expectedStatus, w.Code) + } + + if w.Body.String() != tt.expectedBody { + t.Errorf("Expected body: %s, got: %s", tt.expectedBody, w.Body.String()) + } + }) + } +} + +func TestRespondWithJSON(t *testing.T) { + tests := []struct { + name string + code int + payload interface{} + expectedStatus int + expectedBody string + }{ + { + name: "Success response", + code: 200, + payload: map[string]string{"message": "Success"}, + expectedStatus: 200, + expectedBody: `{"message":"Success"}`, + }, + { + name: "Error response", + code: 400, + payload: map[string]string{"error": "Bad Request"}, + expectedStatus: 400, + expectedBody: `{"error":"Bad Request"}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + commons.RespondWithJSON(w, tt.code, tt.payload) + + if w.Code != tt.expectedStatus { + t.Errorf("Expected status code: %d, got: %d", tt.expectedStatus, w.Code) + } + + if w.Header().Get("Content-Type") != "application/json" { + t.Errorf("Expected Content-Type: application/json, got: %s", w.Header().Get("Content-Type")) + } + + var result map[string]string + err := json.Unmarshal(w.Body.Bytes(), &result) + if err != nil { + t.Errorf("Error unmarshalling response body: %v", err) + } + + expectedResult := make(map[string]string) + err = json.Unmarshal([]byte(tt.expectedBody), &expectedResult) + if err != nil { + t.Errorf("Error unmarshalling expected body: %v", err) + } + + if !jsonEqual(result, expectedResult) { + t.Errorf("Expected body: %s, got: %s", tt.expectedBody, w.Body.String()) + } + }) + } +} + +func jsonEqual(a, b map[string]string) bool { + if len(a) != len(b) { + return false + } + for k, v := range a { + if w, ok := b[k]; !ok || v != w { + return false + } + } + return true +} From 94af82eb3993221175d57f5b20f42df875675ad5 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 11:39:01 -0300 Subject: [PATCH 064/141] refactor(tests): correct package name in user handler tests This commit corrects the package name in the user handler tests to follow Go conventions. --- internal/handler/user_handler_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/handler/user_handler_test.go b/internal/handler/user_handler_test.go index 848d67959..5d303d3bf 100644 --- a/internal/handler/user_handler_test.go +++ b/internal/handler/user_handler_test.go @@ -1,4 +1,4 @@ -package handler +package handler_test import ( "bytes" @@ -9,6 +9,7 @@ import ( "net/http/httptest" "testing" + "github.com/Lutefd/challenge-bravo/internal/handler" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -51,7 +52,7 @@ func (m *MockUserService) Authenticate(ctx context.Context, username, password s func TestUserHandler_Register(t *testing.T) { mockService := new(MockUserService) - handler := NewUserHandler(mockService) + handler := handler.NewUserHandler(mockService) t.Run("Successful registration", func(t *testing.T) { newUser := model.User{ @@ -115,7 +116,7 @@ func TestUserHandler_Register(t *testing.T) { func TestUserHandler_Login(t *testing.T) { mockService := new(MockUserService) - handler := NewUserHandler(mockService) + handler := handler.NewUserHandler(mockService) t.Run("Successful login", func(t *testing.T) { authenticatedUser := model.User{ From 72254b42b0a20b968d3d398cb198812bbdd5ca61 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 15:53:01 -0300 Subject: [PATCH 065/141] chore(dependencies): add new dependencies for testing and utilities This commit updates the go.mod and go.sum files to add the following package and its dependencies: - Adding github.com/alicebob/miniredis/v2 for Redis testing. --- go.mod | 3 +++ go.sum | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/go.mod b/go.mod index 8cf880da4..ab19bd8c6 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/alicebob/miniredis/v2 v2.33.0 github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 github.com/redis/go-redis/v9 v9.6.1 @@ -18,10 +19,12 @@ require ( ) require ( + github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/yuin/gopher-lua v1.1.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7c0dae656..c2403213f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= +github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -26,6 +30,8 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= From 232681a9acc5ceb4c85c7ac80198db976a469e40 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 15:53:57 -0300 Subject: [PATCH 066/141] test(cache): add unit tests for Redis cache implementation This commit adds unit tests for the Redis cache implementation. Tests include: - TestNewRedisCache: Ensures the Redis cache is created successfully. - TestGet: Verifies the Get method, including handling non-existent and invalid keys. - TestSet: Verifies the Set method, including setting values with and without expiration. - TestDelete: Verifies the Delete method, ensuring keys are removed correctly. - TestClose: Ensures the Redis cache connection is closed properly. --- internal/cache/redis_cache_test.go | 112 +++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 internal/cache/redis_cache_test.go diff --git a/internal/cache/redis_cache_test.go b/internal/cache/redis_cache_test.go new file mode 100644 index 000000000..1edfe7400 --- /dev/null +++ b/internal/cache/redis_cache_test.go @@ -0,0 +1,112 @@ +package cache_test + +import ( + "context" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/alicebob/miniredis/v2" + "github.com/stretchr/testify/assert" +) + +func setupTestRedis(t *testing.T) (*cache.RedisCache, *miniredis.Miniredis) { + mr, err := miniredis.Run() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + + redisCache, err := cache.NewRedisCache(mr.Addr(), "") + if err != nil { + t.Fatalf("failed to create Redis cache: %v", err) + } + + return redisCache, mr +} + +func TestNewRedisCache(t *testing.T) { + redisCache, mr := setupTestRedis(t) + defer mr.Close() + defer redisCache.Close() + + assert.NotNil(t, redisCache) +} + +func TestGet(t *testing.T) { + redisCache, mr := setupTestRedis(t) + defer mr.Close() + defer redisCache.Close() + + ctx := context.Background() + + _, err := redisCache.Get(ctx, "non_existent_key") + assert.Error(t, err) + assert.Contains(t, err.Error(), "key not found") + + err = redisCache.Set(ctx, "test_key", 123.45, time.Minute) + assert.NoError(t, err) + + value, err := redisCache.Get(ctx, "test_key") + assert.NoError(t, err) + assert.Equal(t, 123.45, value) + + mr.Set("invalid_key", "not_a_float") + _, err = redisCache.Get(ctx, "invalid_key") + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse cached value") +} + +func TestSet(t *testing.T) { + redisCache, mr := setupTestRedis(t) + defer mr.Close() + defer redisCache.Close() + + ctx := context.Background() + + err := redisCache.Set(ctx, "test_key", 123.45, time.Minute) + assert.NoError(t, err) + + value, err := redisCache.Get(ctx, "test_key") + assert.NoError(t, err) + assert.Equal(t, 123.45, value) + + err = redisCache.Set(ctx, "no_expiration_key", 678.90, 0) + assert.NoError(t, err) + + value, err = redisCache.Get(ctx, "no_expiration_key") + assert.NoError(t, err) + assert.Equal(t, 678.90, value) +} + +func TestDelete(t *testing.T) { + redisCache, mr := setupTestRedis(t) + defer mr.Close() + defer redisCache.Close() + + ctx := context.Background() + + err := redisCache.Set(ctx, "test_key", 123.45, time.Minute) + assert.NoError(t, err) + + err = redisCache.Delete(ctx, "test_key") + assert.NoError(t, err) + + _, err = redisCache.Get(ctx, "test_key") + assert.Error(t, err) + assert.Contains(t, err.Error(), "key not found") + + err = redisCache.Delete(ctx, "non_existent_key") + assert.NoError(t, err) +} + +func TestClose(t *testing.T) { + redisCache, mr := setupTestRedis(t) + defer mr.Close() + + err := redisCache.Close() + assert.NoError(t, err) + + ctx := context.Background() + _, err = redisCache.Get(ctx, "test_key") + assert.Error(t, err) +} From 94f39022c1873e905b07591d74004952a53aa875 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 18:43:01 -0300 Subject: [PATCH 067/141] feat(currency): add auditing fields to Currency model and update schema This commit enhances the Currency model by adding auditing fields and updates the database schema accordingly. Changes include: - Adding `CreatedBy`, `UpdatedBy`, and `CreatedAt` fields to the Currency model. - Adding a new SQL migration script `004_currencies_users.sql` to modify the currencies table: - Adding `created_by` column for storing the UUID of the user who created the record. - Adding `updated_by` column for storing the UUID of the user who last updated the record. - Adding `created_at` column for storing the timestamp when the record was created, with a default value of the current timestamp. - Ensuring the `CreatedAt` field in the model aligns with the new database schema. --- internal/model/currency.go | 5 +++++ sql/schema/004_auditing_currencies.sql | 11 +++++++++++ 2 files changed, 16 insertions(+) create mode 100644 sql/schema/004_auditing_currencies.sql diff --git a/internal/model/currency.go b/internal/model/currency.go index 5dbe87ef4..559c7d679 100644 --- a/internal/model/currency.go +++ b/internal/model/currency.go @@ -2,12 +2,17 @@ package model import ( "time" + + "github.com/google/uuid" ) type Currency struct { Code string `json:"code"` Rate float64 `json:"rate"` UpdatedAt time.Time `json:"updated_at"` + CreatedBy uuid.UUID `json:"created_by"` + UpdatedBy uuid.UUID `json:"updated_by"` + CreatedAt time.Time `json:"created_at"` } type ExchangeRates struct { diff --git a/sql/schema/004_auditing_currencies.sql b/sql/schema/004_auditing_currencies.sql new file mode 100644 index 000000000..3880a5203 --- /dev/null +++ b/sql/schema/004_auditing_currencies.sql @@ -0,0 +1,11 @@ +-- +goose Up +ALTER TABLE currencies +ADD COLUMN created_by UUID, +ADD COLUMN updated_by UUID, +ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- +goose Down +ALTER TABLE currencies +DROP COLUMN created_by, +DROP COLUMN updated_by, +DROP COLUMN created_at; From d082b810dd64e231383f5c949ad49414f64611e7 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 18:47:05 -0300 Subject: [PATCH 068/141] feat(repository): add auditing fields to currency repository methods This commit enhances the PostgreSQL currency repository implementation by incorporating auditing fields. Changes include: - Updating the `GetByCode` method to retrieve `created_by`, `updated_by`, and `created_at` fields. - Modifying the `Create` method to insert `created_by`, `updated_by`, and `created_at` fields. - Adjusting the `Update` method to update the `updated_by` field along with other fields. --- internal/repository/pg_currency_repository.go | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index 54431f835..5782a9af4 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -28,9 +28,12 @@ func NewPostgresCurrencyRepository(connURL string) (*PostgresCurrencyRepository, } func (r *PostgresCurrencyRepository) GetByCode(ctx context.Context, code string) (*model.Currency, error) { - query := `SELECT code, rate, updated_at FROM currencies WHERE code = $1` + query := `SELECT code, rate, updated_at, created_by, updated_by, created_at FROM currencies WHERE code = $1` var currency model.Currency - err := r.db.QueryRowContext(ctx, query, code).Scan(¤cy.Code, ¤cy.Rate, ¤cy.UpdatedAt) + err := r.db.QueryRowContext(ctx, query, code).Scan( + ¤cy.Code, ¤cy.Rate, ¤cy.UpdatedAt, + ¤cy.CreatedBy, ¤cy.UpdatedBy, ¤cy.CreatedAt, + ) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("currency not found") @@ -41,8 +44,12 @@ func (r *PostgresCurrencyRepository) GetByCode(ctx context.Context, code string) } func (r *PostgresCurrencyRepository) Create(ctx context.Context, currency *model.Currency) error { - query := `INSERT INTO currencies (code, rate, updated_at) VALUES ($1, $2, $3)` - _, err := r.db.ExecContext(ctx, query, currency.Code, currency.Rate, currency.UpdatedAt) + query := `INSERT INTO currencies (code, rate, updated_at, created_by, updated_by, created_at) + VALUES ($1, $2, $3, $4, $5, $6)` + _, err := r.db.ExecContext(ctx, query, + currency.Code, currency.Rate, currency.UpdatedAt, + currency.CreatedBy, currency.UpdatedBy, currency.CreatedAt, + ) if err != nil { return fmt.Errorf("failed to create currency: %w", err) } @@ -50,8 +57,10 @@ func (r *PostgresCurrencyRepository) Create(ctx context.Context, currency *model } func (r *PostgresCurrencyRepository) Update(ctx context.Context, currency *model.Currency) error { - query := `UPDATE currencies SET rate = $2, updated_at = $3 WHERE code = $1` - _, err := r.db.ExecContext(ctx, query, currency.Code, currency.Rate, currency.UpdatedAt) + query := `UPDATE currencies SET rate = $2, updated_at = $3, updated_by = $4 WHERE code = $1` + _, err := r.db.ExecContext(ctx, query, + currency.Code, currency.Rate, currency.UpdatedAt, currency.UpdatedBy, + ) if err != nil { return fmt.Errorf("failed to update currency: %w", err) } From 6fea961412b88bcd2ec43cdaaa530f1c0fbea7ca Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 18:48:45 -0300 Subject: [PATCH 069/141] feat(service): add UpdateCurrency method and enhance AddCurrency This commit enhances the CurrencyService with an UpdateCurrency method and updates the AddCurrency method to support auditing fields. Changes include: - Adding UpdateCurrency method to update an existing currency's rate and auditing fields. - Modifying AddCurrency method to accept a Currency model, allowing for auditing fields (created_by, updated_by, created_at). - Updating tests for AddCurrency and adding tests for UpdateCurrency to ensure proper functionality. - Adjusting the CurrencyServiceInterface to include the new UpdateCurrency method. --- internal/service/currency_service.go | 36 ++++-- internal/service/currency_service_test.go | 138 ++++++++++++++++------ internal/service/service.go | 4 +- 3 files changed, 131 insertions(+), 47 deletions(-) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 9693ab078..166970e70 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -10,6 +10,7 @@ import ( "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" "github.com/Lutefd/challenge-bravo/internal/worker" + "github.com/google/uuid" ) type CurrencyService struct { @@ -76,24 +77,39 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er return rate, nil } -func (s *CurrencyService) AddCurrency(ctx context.Context, code string, rate float64) error { - _, err := s.repo.GetByCode(ctx, code) +func (s *CurrencyService) AddCurrency(ctx context.Context, currency *model.Currency) error { + _, err := s.repo.GetByCode(ctx, currency.Code) if err == nil { - return fmt.Errorf("currency %s already exists", code) - } - - currency := &model.Currency{ - Code: strings.ToUpper(code), - Rate: rate, - UpdatedAt: time.Now(), + return fmt.Errorf("currency %s already exists", currency.Code) } if err := s.repo.Create(ctx, currency); err != nil { return fmt.Errorf("failed to add currency to repository: %w", err) } + if err := s.cache.Set(ctx, currency.Code, currency.Rate, 1*time.Hour); err != nil { + fmt.Printf("failed to update cache for new currency %s: %v\n", currency.Code, err) + } + + return nil +} + +func (s *CurrencyService) UpdateCurrency(ctx context.Context, code string, rate float64, updatedBy uuid.UUID) error { + currency, err := s.repo.GetByCode(ctx, code) + if err != nil { + return fmt.Errorf("currency %s not found", code) + } + + currency.Rate = rate + currency.UpdatedAt = time.Now() + currency.UpdatedBy = updatedBy + + if err := s.repo.Update(ctx, currency); err != nil { + return fmt.Errorf("failed to update currency in repository: %w", err) + } + if err := s.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { - fmt.Printf("failed to update cache for new currency %s: %v\n", code, err) + fmt.Printf("failed to update cache for currency %s: %v\n", code, err) } return nil diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go index 6c20eca8b..d680b0ba0 100644 --- a/internal/service/currency_service_test.go +++ b/internal/service/currency_service_test.go @@ -8,6 +8,8 @@ import ( "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/service" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" ) type mockRepository struct { @@ -15,10 +17,11 @@ type mockRepository struct { } func (m *mockRepository) GetByCode(ctx context.Context, code string) (*model.Currency, error) { - if currency, ok := m.currencies[code]; ok { - return currency, nil + currency, ok := m.currencies[code] + if !ok { + return nil, errors.New("currency not found") } - return nil, errors.New("currency not found") + return currency, nil } func (m *mockRepository) Create(ctx context.Context, currency *model.Currency) error { @@ -27,6 +30,9 @@ func (m *mockRepository) Create(ctx context.Context, currency *model.Currency) e } func (m *mockRepository) Update(ctx context.Context, currency *model.Currency) error { + if _, ok := m.currencies[currency.Code]; !ok { + return errors.New("currency not found") + } m.currencies[currency.Code] = currency return nil } @@ -131,51 +137,111 @@ func TestCurrencyService_Convert(t *testing.T) { func TestCurrencyService_AddCurrency(t *testing.T) { repo := &mockRepository{ - currencies: map[string]*model.Currency{}, + currencies: make(map[string]*model.Currency), } cache := &mockCache{ - data: map[string]float64{}, + data: make(map[string]float64), } externalAPI := &mockExternalAPI{ - rates: map[string]float64{}, + rates: make(map[string]float64), } currencyService := service.NewCurrencyService(repo, cache, externalAPI) - tests := []struct { - name string - code string - rate float64 - expectedError bool - }{ - {"Add new currency", "JPY", 110.0, false}, - {"Add existing currency", "JPY", 1.0, true}, - } + ctx := context.Background() + userID := uuid.New() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := currencyService.AddCurrency(context.Background(), tt.code, tt.rate) + t.Run("Add new currency", func(t *testing.T) { + newCurrency := &model.Currency{ + Code: "JPY", + Rate: 110.0, + CreatedBy: userID, + UpdatedBy: userID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } - if tt.expectedError { - if err == nil { - t.Errorf("expected an error, but got none") - } - } else { - if err != nil { - t.Errorf("unexpected error: %v", err) - } - currency, err := repo.GetByCode(context.Background(), tt.code) - if err != nil { - t.Errorf("failed to get added currency: %v", err) - } - if currency.Rate != tt.rate { - t.Errorf("expected rate %f, but got %f", tt.rate, currency.Rate) - } - } - }) - } + err := currencyService.AddCurrency(ctx, newCurrency) + + assert.NoError(t, err) + assert.Equal(t, newCurrency, repo.currencies["JPY"]) + assert.Equal(t, 110.0, cache.data["JPY"]) + }) + + t.Run("Add existing currency", func(t *testing.T) { + existingCurrency := &model.Currency{ + Code: "USD", + Rate: 1.0, + CreatedBy: userID, + UpdatedBy: userID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + repo.currencies["USD"] = existingCurrency + + newCurrency := &model.Currency{ + Code: "USD", + Rate: 1.1, + CreatedBy: userID, + UpdatedBy: userID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + err := currencyService.AddCurrency(ctx, newCurrency) + + assert.Error(t, err) + assert.Equal(t, existingCurrency, repo.currencies["USD"]) + }) } +func TestCurrencyService_UpdateCurrency(t *testing.T) { + repo := &mockRepository{ + currencies: make(map[string]*model.Currency), + } + cache := &mockCache{ + data: make(map[string]float64), + } + externalAPI := &mockExternalAPI{ + rates: make(map[string]float64), + } + + currencyService := service.NewCurrencyService(repo, cache, externalAPI) + + ctx := context.Background() + userID := uuid.New() + + t.Run("Update existing currency", func(t *testing.T) { + existingCurrency := &model.Currency{ + Code: "EUR", + Rate: 0.85, + CreatedBy: uuid.New(), + UpdatedBy: uuid.New(), + CreatedAt: time.Now().Add(-24 * time.Hour), + UpdatedAt: time.Now().Add(-24 * time.Hour), + } + repo.currencies["EUR"] = existingCurrency + + originalUpdatedAt := existingCurrency.UpdatedAt + + err := currencyService.UpdateCurrency(ctx, "EUR", 0.82, userID) + + assert.NoError(t, err) + updatedCurrency := repo.currencies["EUR"] + assert.Equal(t, 0.82, updatedCurrency.Rate) + assert.Equal(t, userID, updatedCurrency.UpdatedBy) + assert.True(t, updatedCurrency.UpdatedAt.After(originalUpdatedAt), "UpdatedAt should be later than the original time") + assert.Equal(t, 0.82, cache.data["EUR"]) + }) + + t.Run("Update non-existing currency", func(t *testing.T) { + err := currencyService.UpdateCurrency(ctx, "GBP", 0.75, userID) + + assert.Error(t, err) + assert.NotContains(t, repo.currencies, "GBP") + assert.NotContains(t, cache.data, "GBP") + }) +} func TestCurrencyService_RemoveCurrency(t *testing.T) { repo := &mockRepository{ currencies: map[string]*model.Currency{ diff --git a/internal/service/service.go b/internal/service/service.go index c8dff9046..c91173e53 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -4,11 +4,13 @@ import ( "context" "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" ) type CurrencyServiceInterface interface { Convert(ctx context.Context, from, to string, amount float64) (float64, error) - AddCurrency(ctx context.Context, code string, rate float64) error + AddCurrency(ctx context.Context, currency *model.Currency) error + UpdateCurrency(ctx context.Context, code string, rate float64, updatedBy uuid.UUID) error RemoveCurrency(ctx context.Context, code string) error } From ba3074def2334315a3d53337ab225ff98bf03e84 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 18:50:20 -0300 Subject: [PATCH 070/141] feat(handler): enhance AddCurrency with user context and auditing fields This commit enhances the AddCurrency handler to utilize user context and include auditing fields. Changes include: - Updating the AddCurrency handler to extract user information from the context and set auditing fields (`created_by`, `updated_by`, `created_at`, `updated_at`). - Modifying the currency service to accept a Currency model for adding new currencies. - Enhancing tests to verify the inclusion of auditing fields and handling of missing user context. - Adding a test case for the scenario where user information is not available in the context. --- internal/handler/currency_handler.go | 20 ++++++++++++- internal/handler/currency_handler_test.go | 36 +++++++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index b1a055e29..a87c72223 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -5,8 +5,10 @@ import ( "net/http" "strconv" "strings" + "time" "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/service" "github.com/go-chi/chi/v5" ) @@ -72,7 +74,23 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") return } - if err := h.currencyService.AddCurrency(r.Context(), currency.Code, currency.Rate); err != nil { + + user, ok := r.Context().Value("user").(*model.User) + if !ok { + commons.RespondWithError(w, http.StatusInternalServerError, "user information not available") + return + } + + newCurrency := &model.Currency{ + Code: strings.ToUpper(currency.Code), + Rate: currency.Rate, + CreatedBy: user.ID, + UpdatedBy: user.ID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + if err := h.currencyService.AddCurrency(r.Context(), newCurrency); err != nil { commons.RespondWithError(w, http.StatusInternalServerError, "failed to add currency") return } diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go index 60bcc8e66..cd3c2c641 100644 --- a/internal/handler/currency_handler_test.go +++ b/internal/handler/currency_handler_test.go @@ -8,7 +8,9 @@ import ( "testing" "github.com/Lutefd/challenge-bravo/internal/handler" + "github.com/Lutefd/challenge-bravo/internal/model" "github.com/go-chi/chi/v5" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -22,10 +24,14 @@ func (m *MockCurrencyService) Convert(ctx context.Context, from, to string, amou return args.Get(0).(float64), args.Error(1) } -func (m *MockCurrencyService) AddCurrency(ctx context.Context, code string, rate float64) error { - args := m.Called(ctx, code, rate) +func (m *MockCurrencyService) AddCurrency(ctx context.Context, curr *model.Currency) error { + args := m.Called(ctx, curr) return args.Error(0) } +func (m *MockCurrencyService) UpdateCurrency(ctx context.Context, code string, rate float64, updatedBy uuid.UUID) error { + args := m.Called(ctx, code, rate, updatedBy) + return args.Error(1) +} func (m *MockCurrencyService) RemoveCurrency(ctx context.Context, code string) error { args := m.Called(ctx, code) @@ -75,8 +81,14 @@ func TestAddCurrency(t *testing.T) { assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") + userID := uuid.New() + user := &model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} + ctx := context.WithValue(req.Context(), "user", user) + req = req.WithContext(ctx) + rr := httptest.NewRecorder() - mockService.On("AddCurrency", mock.Anything, "USD", 1.0).Return(nil) + + mockService.On("AddCurrency", mock.Anything, mock.AnythingOfType("*model.Currency")).Return(nil).Once() handler := http.HandlerFunc(h.AddCurrency) handler.ServeHTTP(rr, req) @@ -84,6 +96,10 @@ func TestAddCurrency(t *testing.T) { assert.Equal(t, http.StatusCreated, rr.Code) assert.JSONEq(t, `{"message":"currency added successfully"}`, rr.Body.String()) mockService.AssertExpectations(t) + + mockService.AssertCalled(t, "AddCurrency", mock.Anything, mock.MatchedBy(func(c *model.Currency) bool { + return c.Code == "USD" && c.Rate == 1.0 && c.CreatedBy == userID && c.UpdatedBy == userID + })) }) t.Run("Invalid Payload", func(t *testing.T) { @@ -100,6 +116,20 @@ func TestAddCurrency(t *testing.T) { assert.JSONEq(t, `{"error":"invalid currency code or rate"}`, rr.Body.String()) }) + t.Run("No User in Context", func(t *testing.T) { + body := strings.NewReader(`{"code":"USD","rate":1.0}`) + req, err := http.NewRequest("POST", "/currency", body) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + + handler := http.HandlerFunc(h.AddCurrency) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.JSONEq(t, `{"error":"user information not available"}`, rr.Body.String()) + }) } func TestRemoveCurrency(t *testing.T) { From be913a0e0146f3370ca623e7b577c579e575f7f5 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 19:39:16 -0300 Subject: [PATCH 071/141] feat(handler): enhance currency conversion and addition handlers This commit enhances the currency conversion and addition handlers with additional validations and parsing logic. Changes include: - Updating `ConvertCurrency` handler to handle amounts with commas and validate non-negative amounts. - Adding `parseAmount` and `parseRate` helper functions for better input handling. - Modifying `AddCurrency` handler to accept both string and float types for rates and validate rate positivity. - Enhancing `currency_handler_test.go` with comprehensive test cases for `ConvertCurrency` and `AddCurrency`, covering various input scenarios and edge cases. --- internal/handler/currency_handler.go | 55 +++-- internal/handler/currency_handler_test.go | 250 +++++++++++++++------- 2 files changed, 208 insertions(+), 97 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index a87c72223..b5a96579a 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -2,10 +2,10 @@ package handler import ( "encoding/json" + "fmt" "net/http" "strconv" "strings" - "time" "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" @@ -29,22 +29,27 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request amountStr := r.URL.Query().Get("amount") if from == "" || to == "" || (amountStr == "") { - commons.RespondWithError(w, http.StatusBadRequest, "Missing required parameters") + commons.RespondWithError(w, http.StatusBadRequest, "missing required parameters") return } if len(from) != 3 || len(to) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid currency code, must be 3 characters long following ISO 4217") + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") return } - amount, err := strconv.ParseFloat(amountStr, 64) + amount, err := parseAmount(amountStr) if err != nil { - commons.RespondWithError(w, http.StatusBadRequest, "Invalid amount") + commons.RespondWithError(w, http.StatusBadRequest, "invalid amount") + return + } + + if amount < 0 { + commons.RespondWithError(w, http.StatusBadRequest, "amount must be non-negative") return } result, err := h.currencyService.Convert(r.Context(), from, to, amount) if err != nil { - commons.RespondWithError(w, http.StatusInternalServerError, "Conversion failed") + commons.RespondWithError(w, http.StatusInternalServerError, "conversion failed") return } @@ -58,16 +63,16 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { var currency struct { - Code string `json:"code"` - Rate float64 `json:"rate"` + Code string `json:"code"` + Rate interface{} `json:"rate_to_usd"` } if err := json.NewDecoder(r.Body).Decode(¤cy); err != nil { commons.RespondWithError(w, http.StatusBadRequest, "invalid request payload") return } - if currency.Code == "" || currency.Rate == 0 { - commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code or rate") + if currency.Code == "" { + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") return } if len(currency.Code) != 3 { @@ -75,19 +80,26 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { return } - user, ok := r.Context().Value("user").(*model.User) + user, ok := r.Context().Value("user").(model.User) if !ok { commons.RespondWithError(w, http.StatusInternalServerError, "user information not available") return } + rate, err := parseRate(currency.Rate) + if err != nil { + commons.RespondWithError(w, http.StatusBadRequest, "invalid rate: "+err.Error()) + return + } + if rate <= 0 { + commons.RespondWithError(w, http.StatusBadRequest, "rate must be positive") + return + } newCurrency := &model.Currency{ Code: strings.ToUpper(currency.Code), - Rate: currency.Rate, + Rate: rate, CreatedBy: user.ID, UpdatedBy: user.ID, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), } if err := h.currencyService.AddCurrency(r.Context(), newCurrency); err != nil { @@ -116,3 +128,18 @@ func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) commons.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "currency removed successfully"}) } +func parseAmount(amountStr string) (float64, error) { + amountStr = strings.Replace(amountStr, ",", ".", -1) + return strconv.ParseFloat(amountStr, 64) +} +func parseRate(rate interface{}) (float64, error) { + switch v := rate.(type) { + case float64: + return v, nil + case string: + v = strings.Replace(v, ",", ".", -1) + return strconv.ParseFloat(v, 64) + default: + return 0, fmt.Errorf("unsupported rate type") + } +} diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go index cd3c2c641..56c8f972f 100644 --- a/internal/handler/currency_handler_test.go +++ b/internal/handler/currency_handler_test.go @@ -1,13 +1,15 @@ package handler_test import ( + "bytes" "context" + "encoding/json" "net/http" "net/http/httptest" - "strings" "testing" "github.com/Lutefd/challenge-bravo/internal/handler" + api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/go-chi/chi/v5" "github.com/google/uuid" @@ -42,94 +44,176 @@ func TestConvertCurrency(t *testing.T) { mockService := new(MockCurrencyService) h := handler.NewCurrencyHandler(mockService) - t.Run("Success", func(t *testing.T) { - req, err := http.NewRequest("GET", "/convert?from=USD&to=EUR&amount=100", nil) - assert.NoError(t, err) - - rr := httptest.NewRecorder() - mockService.On("Convert", mock.Anything, "USD", "EUR", 100.0).Return(90.0, nil) - - handler := http.HandlerFunc(h.ConvertCurrency) - handler.ServeHTTP(rr, req) - - assert.Equal(t, http.StatusOK, rr.Code) - assert.JSONEq(t, `{"from":"USD","to":"EUR","amount":100,"result":90}`, rr.Body.String()) - mockService.AssertExpectations(t) - }) - - t.Run("Missing Parameters", func(t *testing.T) { - req, err := http.NewRequest("GET", "/convert", nil) - assert.NoError(t, err) - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(h.ConvertCurrency) - handler.ServeHTTP(rr, req) - - assert.Equal(t, http.StatusBadRequest, rr.Code) - assert.JSONEq(t, `{"error":"Missing required parameters"}`, rr.Body.String()) - }) - + tests := []struct { + name string + from string + to string + amount string + expectedStatus int + expectedBody string + mockBehavior func() + }{ + { + name: "Valid conversion", + from: "USD", + to: "EUR", + amount: "100.00", + expectedStatus: http.StatusOK, + expectedBody: `{"amount":100,"from":"USD","result":85,"to":"EUR"}`, + mockBehavior: func() { + mockService.On("Convert", mock.Anything, "USD", "EUR", 100.0).Return(85.0, nil).Once() + }, + }, + { + name: "Valid conversion with comma", + from: "USD", + to: "EUR", + amount: "100,00", + expectedStatus: http.StatusOK, + expectedBody: `{"amount":100,"from":"USD","result":85,"to":"EUR"}`, + mockBehavior: func() { + mockService.On("Convert", mock.Anything, "USD", "EUR", 100.0).Return(85.0, nil).Once() + }, + }, + { + name: "Negative amount", + from: "USD", + to: "EUR", + amount: "-100.00", + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"amount must be non-negative"}`, + mockBehavior: func() {}, + }, + { + name: "Invalid amount", + from: "USD", + to: "EUR", + amount: "invalid", + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid amount"}`, + mockBehavior: func() {}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.mockBehavior() + + req, _ := http.NewRequest("GET", "/convert?from="+tt.from+"&to="+tt.to+"&amount="+tt.amount, nil) + rr := httptest.NewRecorder() + + h.ConvertCurrency(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + assert.JSONEq(t, tt.expectedBody, rr.Body.String()) + + mockService.AssertExpectations(t) + }) + } } func TestAddCurrency(t *testing.T) { mockService := new(MockCurrencyService) h := handler.NewCurrencyHandler(mockService) - t.Run("Success", func(t *testing.T) { - body := strings.NewReader(`{"code":"USD","rate":1.0}`) - req, err := http.NewRequest("POST", "/currency", body) - assert.NoError(t, err) - req.Header.Set("Content-Type", "application/json") - - userID := uuid.New() - user := &model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} - ctx := context.WithValue(req.Context(), "user", user) - req = req.WithContext(ctx) - - rr := httptest.NewRecorder() - - mockService.On("AddCurrency", mock.Anything, mock.AnythingOfType("*model.Currency")).Return(nil).Once() - - handler := http.HandlerFunc(h.AddCurrency) - handler.ServeHTTP(rr, req) - - assert.Equal(t, http.StatusCreated, rr.Code) - assert.JSONEq(t, `{"message":"currency added successfully"}`, rr.Body.String()) - mockService.AssertExpectations(t) - - mockService.AssertCalled(t, "AddCurrency", mock.Anything, mock.MatchedBy(func(c *model.Currency) bool { - return c.Code == "USD" && c.Rate == 1.0 && c.CreatedBy == userID && c.UpdatedBy == userID - })) - }) - - t.Run("Invalid Payload", func(t *testing.T) { - body := strings.NewReader(`{"code":"USD"}`) - req, err := http.NewRequest("POST", "/currency", body) - assert.NoError(t, err) - req.Header.Set("Content-Type", "application/json") - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(h.AddCurrency) - handler.ServeHTTP(rr, req) - - assert.Equal(t, http.StatusBadRequest, rr.Code) - assert.JSONEq(t, `{"error":"invalid currency code or rate"}`, rr.Body.String()) - }) - - t.Run("No User in Context", func(t *testing.T) { - body := strings.NewReader(`{"code":"USD","rate":1.0}`) - req, err := http.NewRequest("POST", "/currency", body) - assert.NoError(t, err) - req.Header.Set("Content-Type", "application/json") - - rr := httptest.NewRecorder() - - handler := http.HandlerFunc(h.AddCurrency) - handler.ServeHTTP(rr, req) - - assert.Equal(t, http.StatusInternalServerError, rr.Code) - assert.JSONEq(t, `{"error":"user information not available"}`, rr.Body.String()) - }) + tests := []struct { + name string + payload map[string]interface{} + expectedStatus int + expectedBody string + mockBehavior func() + }{ + { + name: "Valid currency with period", + payload: map[string]interface{}{ + "code": "USD", + "rate_to_usd": 1.0, + }, + expectedStatus: http.StatusCreated, + expectedBody: `{"message":"currency added successfully"}`, + mockBehavior: func() { + mockService.On("AddCurrency", mock.Anything, mock.MatchedBy(func(c *model.Currency) bool { + return c.Code == "USD" && c.Rate == 1.0 + })).Return(nil).Once() + }, + }, + { + name: "Valid currency with comma", + payload: map[string]interface{}{ + "code": "EUR", + "rate_to_usd": "0,85", + }, + expectedStatus: http.StatusCreated, + expectedBody: `{"message":"currency added successfully"}`, + mockBehavior: func() { + mockService.On("AddCurrency", mock.Anything, mock.MatchedBy(func(c *model.Currency) bool { + return c.Code == "EUR" && c.Rate == 0.85 + })).Return(nil).Once() + }, + }, + { + name: "Negative rate", + payload: map[string]interface{}{ + "code": "USD", + "rate_to_usd": -1.0, + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"rate must be positive"}`, + mockBehavior: func() {}, + }, + { + name: "Invalid rate type", + payload: map[string]interface{}{ + "code": "USD", + "rate_to_usd": "invalid", + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid rate: strconv.ParseFloat: parsing \"invalid\": invalid syntax"}`, + mockBehavior: func() {}, + }, + { + name: "Missing code", + payload: map[string]interface{}{ + "rate_to_usd": 1.0, + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid currency code"}`, + mockBehavior: func() {}, + }, + { + name: "Invalid code length", + payload: map[string]interface{}{ + "code": "USDD", + "rate_to_usd": 1.0, + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid currency code, must be 3 characters long following ISO 4217"}`, + mockBehavior: func() {}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.mockBehavior() + + body, _ := json.Marshal(tt.payload) + req, _ := http.NewRequest("POST", "/currency", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + + userID := uuid.New() + user := model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} + ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, user) + req = req.WithContext(ctx) + + rr := httptest.NewRecorder() + + h.AddCurrency(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + assert.JSONEq(t, tt.expectedBody, rr.Body.String()) + mockService.AssertExpectations(t) + }) + } } func TestRemoveCurrency(t *testing.T) { From d8db1176f2965eeb72173b1059248678f74377a2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 19:42:32 -0300 Subject: [PATCH 072/141] feat(middleware): enhance authentication and role-based access control This commit adds enhancements to the authentication and role-based access control mechanisms. - Added `UserContextKey` constant for consistent context key usage. - Updated `Authenticate` middleware to store user information in context. - Modified `RequireRole` middleware to handle user roles and context appropriately. - Enhanced middleware tests to cover various scenarios, including authentication and rate limiting. - Added comprehensive test cases for `Authenticate`, `RequireRole`, and `RateLimitMiddleware` middlewares. --- internal/middleware/middleware.go | 18 +- internal/middleware/middleware_tests.go | 214 ++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 6 deletions(-) create mode 100644 internal/middleware/middleware_tests.go diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 8686575c4..e8de02831 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -12,6 +12,8 @@ import ( "golang.org/x/time/rate" ) +const UserContextKey = "user" + type AuthMiddleware struct { userRepo repository.UserRepository } @@ -29,18 +31,21 @@ var ( func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKey := r.Header.Get("X-API-Key") + if apiKey == "" { logger.Error("no API key provided") http.Error(w, "no API key provided", http.StatusUnauthorized) return } - user, err := am.userRepo.GetByAPIKey(r.Context(), apiKey) + userDB, err := am.userRepo.GetByAPIKey(r.Context(), apiKey) if err != nil { logger.Errorf("invalid API key: %s", apiKey) http.Error(w, "invalid API key", http.StatusUnauthorized) return } - ctx := context.WithValue(r.Context(), "user", user) + + user := userDB.ToUser() + ctx := context.WithValue(r.Context(), UserContextKey, user) next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -48,19 +53,20 @@ func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { func RequireRole(role model.Role) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - user, ok := r.Context().Value("user").(*model.User) + + contextUser := r.Context().Value(UserContextKey) + + user, ok := contextUser.(model.User) if !ok { - logger.Error("user not found in context") + logger.Error("user not found in context or has unexpected type") http.Error(w, "unauthorized", http.StatusUnauthorized) return } - if user.Role != role { logger.Errorf("user %s does not have required role %s", user.Username, role) http.Error(w, "forbidden", http.StatusForbidden) return } - next.ServeHTTP(w, r) }) } diff --git a/internal/middleware/middleware_tests.go b/internal/middleware/middleware_tests.go new file mode 100644 index 000000000..abf428b21 --- /dev/null +++ b/internal/middleware/middleware_tests.go @@ -0,0 +1,214 @@ +package api_middleware + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "golang.org/x/time/rate" +) + +type MockUserRepository struct { + mock.Mock +} + +func (m *MockUserRepository) Create(ctx context.Context, user *model.UserDB) error { + args := m.Called(ctx, user) + return args.Error(0) +} + +func (m *MockUserRepository) GetByUsername(ctx context.Context, username string) (*model.UserDB, error) { + args := m.Called(ctx, username) + return args.Get(0).(*model.UserDB), args.Error(1) +} + +func (m *MockUserRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.UserDB, error) { + args := m.Called(ctx, apiKey) + return args.Get(0).(*model.UserDB), args.Error(1) +} + +func (m *MockUserRepository) Update(ctx context.Context, user *model.UserDB) error { + args := m.Called(ctx, user) + return args.Error(0) +} + +func (m *MockUserRepository) Delete(ctx context.Context, username string) error { + args := m.Called(ctx, username) + return args.Error(0) +} + +func (m *MockUserRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +func createTestRequest(apiKey string) *http.Request { + req := httptest.NewRequest("GET", "/", nil) + req.Header.Set("X-API-Key", apiKey) + return req +} + +func TestAuthMiddleware_Authenticate(t *testing.T) { + mockRepo := new(MockUserRepository) + authMiddleware := NewAuthMiddleware(mockRepo) + + tests := []struct { + name string + apiKey string + setupMock func() + expectedStatus int + checkUser func(*testing.T, *http.Request) + }{ + { + name: "Valid API Key", + apiKey: "valid-api-key", + setupMock: func() { + mockRepo.On("GetByAPIKey", mock.Anything, "valid-api-key").Return( + &model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Role: model.RoleUser, + APIKey: "valid-api-key", + }, nil, + ) + }, + expectedStatus: http.StatusOK, + checkUser: func(t *testing.T, r *http.Request) { + user, ok := r.Context().Value(UserContextKey).(model.User) + assert.True(t, ok) + assert.Equal(t, "testuser", user.Username) + }, + }, + { + name: "Missing API Key", + apiKey: "", + setupMock: func() {}, + expectedStatus: http.StatusUnauthorized, + checkUser: func(t *testing.T, r *http.Request) {}, + }, + { + name: "Invalid API Key", + apiKey: "invalid-api-key", + setupMock: func() { + mockRepo.On("GetByAPIKey", mock.Anything, "invalid-api-key").Return((*model.UserDB)(nil), assert.AnError) + }, + expectedStatus: http.StatusUnauthorized, + checkUser: func(t *testing.T, r *http.Request) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMock() + + req := createTestRequest(tt.apiKey) + rr := httptest.NewRecorder() + + nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + tt.checkUser(t, r) + }) + + handler := authMiddleware.Authenticate(nextHandler) + handler.ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + mockRepo.AssertExpectations(t) + }) + } +} + +func TestRequireRole(t *testing.T) { + tests := []struct { + name string + user model.User + requiredRole model.Role + expectedStatus int + }{ + { + name: "User has required role", + user: model.User{Username: "admin", Role: model.RoleAdmin}, + requiredRole: model.RoleAdmin, + expectedStatus: http.StatusOK, + }, + { + name: "User doesn't have required role", + user: model.User{Username: "user", Role: model.RoleUser}, + requiredRole: model.RoleAdmin, + expectedStatus: http.StatusForbidden, + }, + { + name: "No user in context", + user: model.User{}, + requiredRole: model.RoleAdmin, + expectedStatus: http.StatusUnauthorized, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + + if tt.user != (model.User{}) { + ctx := context.WithValue(req.Context(), UserContextKey, tt.user) + req = req.WithContext(ctx) + } + + nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + handler := RequireRole(tt.requiredRole)(nextHandler) + handler.ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + }) + } +} + +func TestRateLimitMiddleware(t *testing.T) { + tests := []struct { + name string + setupLimiter func() + expectedStatus int + }{ + { + name: "Under rate limit", + setupLimiter: func() { + limiter.SetLimit(rate.Inf) + }, + expectedStatus: http.StatusOK, + }, + { + name: "Exceeds rate limit", + setupLimiter: func() { + limiter.SetLimit(rate.Limit(0)) + }, + expectedStatus: http.StatusTooManyRequests, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupLimiter() + + req := httptest.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + + nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + handler := RateLimitMiddleware(nextHandler) + handler.ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + }) + } +} From 7078fca6c6db67795fc221437bc7bf605b976679 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 19:55:00 -0300 Subject: [PATCH 073/141] refactor(currency): standardize currency not found error handling This commit standardizes the handling of the "currency not found" error across the codebase. - Added `ErrCurrencyNotFound` to the `model` package. - Updated `GetByCode` method in `PostgresCurrencyRepository` to use `ErrCurrencyNotFound`. - Modified `UpdateCurrency` method in `CurrencyService` to handle `ErrCurrencyNotFound`. --- internal/model/currency.go | 3 +++ internal/repository/pg_currency_repository.go | 2 +- internal/service/currency_service.go | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/model/currency.go b/internal/model/currency.go index 559c7d679..317e53d8a 100644 --- a/internal/model/currency.go +++ b/internal/model/currency.go @@ -1,6 +1,7 @@ package model import ( + "errors" "time" "github.com/google/uuid" @@ -20,3 +21,5 @@ type ExchangeRates struct { Base string `json:"base"` Rates map[string]float64 `json:"rates"` } + +var ErrCurrencyNotFound = errors.New("currency not found") diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index 5782a9af4..0fddecbe1 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -36,7 +36,7 @@ func (r *PostgresCurrencyRepository) GetByCode(ctx context.Context, code string) ) if err != nil { if err == sql.ErrNoRows { - return nil, fmt.Errorf("currency not found") + return nil, model.ErrCurrencyNotFound } return nil, fmt.Errorf("failed to get currency: %w", err) } diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 166970e70..6e5cfdaec 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -97,7 +97,10 @@ func (s *CurrencyService) AddCurrency(ctx context.Context, currency *model.Curre func (s *CurrencyService) UpdateCurrency(ctx context.Context, code string, rate float64, updatedBy uuid.UUID) error { currency, err := s.repo.GetByCode(ctx, code) if err != nil { - return fmt.Errorf("currency %s not found", code) + if err == model.ErrCurrencyNotFound { + return model.ErrCurrencyNotFound + } + return fmt.Errorf("failed to get currency: %w", err) } currency.Rate = rate From c41bad0de61e182780cdb5b69b74ea5768313e0a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 19:56:33 -0300 Subject: [PATCH 074/141] feat(currency): add update currency functionality This commit introduces the functionality to update an existing currency in the currency handler. - Added `UpdateCurrency` method to the `CurrencyHandler`. - Created test cases for `UpdateCurrency` in `currency_handler_test.go`. --- internal/handler/currency_handler.go | 45 +++++++++ internal/handler/currency_handler_test.go | 108 +++++++++++++++++++++- 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index b5a96579a..3ae2a31a3 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -110,6 +110,51 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { commons.RespondWithJSON(w, http.StatusCreated, map[string]string{"message": "currency added successfully"}) } +func (h *CurrencyHandler) UpdateCurrency(w http.ResponseWriter, r *http.Request) { + code := strings.ToUpper(chi.URLParam(r, "code")) + if code == "" || len(code) != 3 { + commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") + return + } + + var input struct { + Rate interface{} `json:"rate_to_usd"` + } + + if err := json.NewDecoder(r.Body).Decode(&input); err != nil { + commons.RespondWithError(w, http.StatusBadRequest, "invalid request payload") + return + } + + rate, err := parseRate(input.Rate) + if err != nil { + commons.RespondWithError(w, http.StatusBadRequest, "invalid rate: "+err.Error()) + return + } + + if rate <= 0 { + commons.RespondWithError(w, http.StatusBadRequest, "rate must be positive") + return + } + + user, ok := r.Context().Value("user").(model.User) + if !ok { + commons.RespondWithError(w, http.StatusInternalServerError, "user information not available") + return + } + + if err := h.currencyService.UpdateCurrency(r.Context(), code, rate, user.ID); err != nil { + if err == model.ErrCurrencyNotFound { + commons.RespondWithError(w, http.StatusNotFound, "currency not found") + } else { + commons.RespondWithError(w, http.StatusInternalServerError, "failed to update currency") + } + return + } + + commons.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "currency updated successfully"}) +} + func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) { code := strings.ToUpper(chi.URLParam(r, "code")) diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go index 56c8f972f..2bb21fcf9 100644 --- a/internal/handler/currency_handler_test.go +++ b/internal/handler/currency_handler_test.go @@ -32,7 +32,7 @@ func (m *MockCurrencyService) AddCurrency(ctx context.Context, curr *model.Curre } func (m *MockCurrencyService) UpdateCurrency(ctx context.Context, code string, rate float64, updatedBy uuid.UUID) error { args := m.Called(ctx, code, rate, updatedBy) - return args.Error(1) + return args.Error(0) } func (m *MockCurrencyService) RemoveCurrency(ctx context.Context, code string) error { @@ -264,3 +264,109 @@ func TestRemoveCurrency(t *testing.T) { }) } + +func TestUpdateCurrency(t *testing.T) { + mockService := new(MockCurrencyService) + h := handler.NewCurrencyHandler(mockService) + + tests := []struct { + name string + code string + payload map[string]interface{} + expectedStatus int + expectedBody string + mockBehavior func() + }{ + { + name: "Valid update with period", + code: "USD", + payload: map[string]interface{}{ + "rate_to_usd": 1.5, + }, + expectedStatus: http.StatusOK, + expectedBody: `{"message":"currency updated successfully"}`, + mockBehavior: func() { + mockService.On("UpdateCurrency", mock.Anything, "USD", 1.5, mock.AnythingOfType("uuid.UUID")).Return(nil).Once() + }, + }, + { + name: "Valid update with comma", + code: "EUR", + payload: map[string]interface{}{ + "rate_to_usd": "0,95", + }, + expectedStatus: http.StatusOK, + expectedBody: `{"message":"currency updated successfully"}`, + mockBehavior: func() { + mockService.On("UpdateCurrency", mock.Anything, "EUR", 0.95, mock.AnythingOfType("uuid.UUID")).Return(nil).Once() + }, + }, + { + name: "Negative rate", + code: "GBP", + payload: map[string]interface{}{ + "rate_to_usd": -1.0, + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"rate must be positive"}`, + mockBehavior: func() {}, + }, + { + name: "Invalid rate type", + code: "JPY", + payload: map[string]interface{}{ + "rate_to_usd": "invalid", + }, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid rate: strconv.ParseFloat: parsing \"invalid\": invalid syntax"}`, + mockBehavior: func() {}, + }, + { + name: "Missing rate", + code: "CAD", + payload: map[string]interface{}{}, + expectedStatus: http.StatusBadRequest, + expectedBody: `{"error":"invalid rate: unsupported rate type"}`, + mockBehavior: func() {}, + }, + { + name: "Currency not found", + code: "XYZ", + payload: map[string]interface{}{ + "rate_to_usd": 1.0, + }, + expectedStatus: http.StatusNotFound, + expectedBody: `{"error":"currency not found"}`, + mockBehavior: func() { + mockService.On("UpdateCurrency", mock.Anything, "XYZ", 1.0, mock.AnythingOfType("uuid.UUID")).Return(model.ErrCurrencyNotFound).Once() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.mockBehavior() + + body, _ := json.Marshal(tt.payload) + req, _ := http.NewRequest("PUT", "/currency/"+tt.code, bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + + userID := uuid.New() + user := model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} + ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, user) + req = req.WithContext(ctx) + + rctx := chi.NewRouteContext() + rctx.URLParams.Add("code", tt.code) + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + rr := httptest.NewRecorder() + + h.UpdateCurrency(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + assert.JSONEq(t, tt.expectedBody, rr.Body.String()) + mockService.AssertExpectations(t) + }) + } +} From 115a5405f64441ca7e5c5b310fddf99dfd698cec Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 19:57:45 -0300 Subject: [PATCH 075/141] feat(routes): add route for updating currency This commit adds a route for updating an existing currency via the API and refactor the route grouping for a more readable approach. Changes include: - Updated `registerRoutes` in `server.go` to include the `UpdateCurrency` endpoint. - Ensured the `UpdateCurrency` endpoint requires authentication and admin role. --- internal/server/routes.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/server/routes.go b/internal/server/routes.go index 752cb0674..10d7e7c86 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -23,8 +23,13 @@ func (s *Server) registerRoutes(currencyService *service.CurrencyService, userSe }) router.Route("/currency", func(r chi.Router) { r.Get("/convert", currencyHandler.ConvertCurrency) - r.With(authMiddleware.Authenticate, api_middleware.RequireRole(model.RoleAdmin)).Post("/", currencyHandler.AddCurrency) - r.With(authMiddleware.Authenticate, api_middleware.RequireRole(model.RoleAdmin)).Delete("/{code}", currencyHandler.RemoveCurrency) + r.Group(func(r chi.Router) { + r.Use(authMiddleware.Authenticate) + r.Use(api_middleware.RequireRole(model.RoleAdmin)) + r.Post("/", currencyHandler.AddCurrency) + r.Put("/{code}", currencyHandler.UpdateCurrency) + r.Delete("/{code}", currencyHandler.RemoveCurrency) + }) }) s.router = router } From ff5d2bd075af22eac3f5d22e33eba88b05c43ea5 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 20:39:06 -0300 Subject: [PATCH 076/141] fix(handler): set CreatedAt and UpdatedAt timestamps for AddCurrency This commit ensures that the `CreatedAt` and `UpdatedAt` timestamps are set when adding a new currency. --- internal/handler/currency_handler.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index 3ae2a31a3..b9e62dbaf 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -6,6 +6,7 @@ import ( "net/http" "strconv" "strings" + "time" "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" @@ -100,6 +101,8 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { Rate: rate, CreatedBy: user.ID, UpdatedBy: user.ID, + UpdatedAt: time.Now(), + CreatedAt: time.Now(), } if err := h.currencyService.AddCurrency(r.Context(), newCurrency); err != nil { From daa67136f2768cedcc933a141424a713f767629b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 20:41:06 -0300 Subject: [PATCH 077/141] test(model): add unit tests for UserDB to User conversion This commit adds unit tests to verify the correct conversion of UserDB to User in the model package. --- internal/model/users_test.go | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 internal/model/users_test.go diff --git a/internal/model/users_test.go b/internal/model/users_test.go new file mode 100644 index 000000000..c04d6f01d --- /dev/null +++ b/internal/model/users_test.go @@ -0,0 +1,65 @@ +package model_test + +import ( + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +func TestToUser(t *testing.T) { + tests := []struct { + name string + userDB model.UserDB + expected model.User + }{ + { + name: "RoleUser", + userDB: model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Password: "testpass", + Role: model.RoleUser, + APIKey: "testapikey", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + }, + expected: model.User{ + ID: uuid.New(), + Username: "testuser", + Role: model.RoleUser, + APIKey: "testapikey", + }, + }, + { + name: "RoleAdmin", + userDB: model.UserDB{ + ID: uuid.New(), + Username: "adminuser", + Password: "adminpass", + Role: model.RoleAdmin, + APIKey: "adminkey", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + }, + expected: model.User{ + ID: uuid.New(), + Username: "adminuser", + Role: model.RoleAdmin, + APIKey: "adminkey", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := tt.userDB.ToUser() + + tt.expected.ID = tt.userDB.ID + + assert.Equal(t, tt.expected, actual) + }) + } +} From 7478b95c5cfd45c7effe7c88188f17c60ae5f051 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 20:42:14 -0300 Subject: [PATCH 078/141] feat(worker): enhance OpenExchangeRatesClient with retry policy This commit enhances the OpenExchangeRatesClient by introducing a retry mechanism with exponential backoff and jitter for handling transient errors. The following changes were made: - Introduced options for configuring max retries, base delay, and max delay. - Implemented a retry loop in FetchRates with backoff calculation. - Added shouldRetry method to determine retryable errors. - Improved error logging and handling for better observability. --- internal/worker/external_api_client.go | 127 ++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 12 deletions(-) diff --git a/internal/worker/external_api_client.go b/internal/worker/external_api_client.go index 55f1c2883..a0c375a10 100644 --- a/internal/worker/external_api_client.go +++ b/internal/worker/external_api_client.go @@ -4,46 +4,149 @@ import ( "context" "encoding/json" "fmt" + "math/rand" + "net" "net/http" + "time" + "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/model" ) type OpenExchangeRatesClient struct { - apiKey string - client *http.Client + apiKey string + client *http.Client + baseURL string + maxRetries int + baseDelay time.Duration + maxDelay time.Duration } -func NewOpenExchangeRatesClient(apiKey string) *OpenExchangeRatesClient { - return &OpenExchangeRatesClient{ - apiKey: apiKey, - client: &http.Client{}, +type OpenExchangeRatesClientOption func(*OpenExchangeRatesClient) + +func WithMaxRetries(maxRetries int) OpenExchangeRatesClientOption { + return func(c *OpenExchangeRatesClient) { + c.maxRetries = maxRetries } } +func WithBaseDelay(baseDelay time.Duration) OpenExchangeRatesClientOption { + return func(c *OpenExchangeRatesClient) { + c.baseDelay = baseDelay + } +} + +func WithMaxDelay(maxDelay time.Duration) OpenExchangeRatesClientOption { + return func(c *OpenExchangeRatesClient) { + c.maxDelay = maxDelay + } +} + +func NewOpenExchangeRatesClient(apiKey string, options ...OpenExchangeRatesClientOption) *OpenExchangeRatesClient { + client := &OpenExchangeRatesClient{ + apiKey: apiKey, + client: &http.Client{}, + baseURL: "https://openexchangerates.org/api", + maxRetries: 3, + baseDelay: time.Second, + maxDelay: 30 * time.Second, + } + + for _, option := range options { + option(client) + } + + return client +} + func (c *OpenExchangeRatesClient) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { - url := fmt.Sprintf("https://openexchangerates.org/api/latest.json?app_id=%s", c.apiKey) + url := fmt.Sprintf("%s/latest.json?app_id=%s", c.baseURL, c.apiKey) + + var rates *model.ExchangeRates + var err error + var resp *http.Response + + for attempt := 0; attempt < c.maxRetries; attempt++ { + rates, resp, err = c.doRequest(ctx, url) + if err == nil { + return rates, nil + } + + if !c.shouldRetry(err, resp) { + logger.Errorf("Non-retryable error encountered: %v", err) + return nil, err + } + + backoffDuration := c.calculateBackoff(attempt) + logger.Infof("Retry attempt %d/%d after %v due to error: %v", attempt+1, c.maxRetries, backoffDuration, err) + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(backoffDuration): + } + } + + logger.Errorf("Max retries reached. Last error: %v", err) + return nil, fmt.Errorf("max retries reached: %w", err) +} + +func (c *OpenExchangeRatesClient) doRequest(ctx context.Context, url string) (*model.ExchangeRates, *http.Response, error) { req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { - return nil, fmt.Errorf("failed to create request: %w", err) + return nil, nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) if err != nil { - return nil, fmt.Errorf("failed to send request: %w", err) + return nil, resp, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("API request failed with status code: %d", resp.StatusCode) + return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode) } var rates model.ExchangeRates err = json.NewDecoder(resp.Body).Decode(&rates) if err != nil { - return nil, fmt.Errorf("failed to decode response: %w", err) + return nil, resp, fmt.Errorf("failed to decode response: %w", err) + } + + return &rates, resp, nil +} + +func (c *OpenExchangeRatesClient) shouldRetry(err error, resp *http.Response) bool { + if err == nil { + return false } - return &rates, nil + if netErr, ok := err.(net.Error); ok { + logger.Infof("Network error occurred: %v. Will retry.", netErr) + return netErr.Timeout() + } + + if resp != nil { + if resp.StatusCode >= 500 { + logger.Infof("Received 5xx status code: %d. Will retry.", resp.StatusCode) + return true + } + if resp.StatusCode == 429 { + logger.Infof("Received 429 status code: %d. Will retry.", resp.StatusCode) + return true + } + + } + + logger.Infof("Non-retryable error occurred: %v", err) + return false +} + +func (c *OpenExchangeRatesClient) calculateBackoff(attempt int) time.Duration { + delay := c.baseDelay * time.Duration(1< c.maxDelay { + delay = c.maxDelay + } + jitter := time.Duration(rand.Int63n(int64(delay) / 2)) + return delay + jitter } From ee811241a32cf22dd31bc78898b1b12878898518 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 20:43:50 -0300 Subject: [PATCH 079/141] test(worker): add tests for OpenExchangeRatesClient and RateUpdater This commit adds comprehensive tests for the OpenExchangeRatesClient and RateUpdater components. The following changes were made: - Added unit tests for NewOpenExchangeRatesClient, FetchRates, shouldRetry, and calculateBackoff in OpenExchangeRatesClient. - Included mock server and network error simulation for FetchRates tests. - Added unit tests for NewRateUpdater, updateRates, populateRates, and Start in RateUpdater. --- internal/worker/external_api_client_tests.go | 209 +++++++++++++++++++ internal/worker/rate_updater_test.go | 194 +++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 internal/worker/external_api_client_tests.go create mode 100644 internal/worker/rate_updater_test.go diff --git a/internal/worker/external_api_client_tests.go b/internal/worker/external_api_client_tests.go new file mode 100644 index 000000000..0104b6faa --- /dev/null +++ b/internal/worker/external_api_client_tests.go @@ -0,0 +1,209 @@ +package worker + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestNewOpenExchangeRatesClient(t *testing.T) { + apiKey := "test-api-key" + client := NewOpenExchangeRatesClient(apiKey) + + assert.Equal(t, apiKey, client.apiKey) + assert.Equal(t, 3, client.maxRetries) + assert.Equal(t, time.Second, client.baseDelay) + assert.Equal(t, 30*time.Second, client.maxDelay) + + customClient := NewOpenExchangeRatesClient( + apiKey, + WithMaxRetries(5), + WithBaseDelay(2*time.Second), + WithMaxDelay(1*time.Minute), + ) + + assert.Equal(t, 5, customClient.maxRetries) + assert.Equal(t, 2*time.Second, customClient.baseDelay) + assert.Equal(t, 1*time.Minute, customClient.maxDelay) +} + +func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { + tests := []struct { + name string + responses []mockResponse + expectedError bool + expectedRetries int + }{ + { + name: "Successful response", + responses: []mockResponse{ + {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, + }, + expectedError: false, + expectedRetries: 0, + }, + { + name: "Retry on 500 error", + responses: []mockResponse{ + {statusCode: http.StatusInternalServerError, body: ""}, + {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, + }, + expectedError: false, + expectedRetries: 1, + }, + { + name: "Retry on network error", + responses: []mockResponse{ + {err: &networkError{message: "connection refused"}}, + {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, + }, + expectedError: false, + expectedRetries: 1, + }, + { + name: "Max retries reached", + responses: []mockResponse{ + {statusCode: http.StatusInternalServerError, body: ""}, + {statusCode: http.StatusInternalServerError, body: ""}, + {statusCode: http.StatusInternalServerError, body: ""}, + {statusCode: http.StatusInternalServerError, body: ""}, + }, + expectedError: true, + expectedRetries: 3, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := newMockServer(tt.responses) + defer server.Close() + + client := NewOpenExchangeRatesClient("test-api-key") + client.baseURL = server.URL + client.client = server.Client() + + rates, err := client.FetchRates(context.Background()) + + if tt.expectedError { + assert.Error(t, err) + assert.Nil(t, rates) + } else { + assert.NoError(t, err) + assert.NotNil(t, rates) + } + + assert.Equal(t, tt.expectedRetries, server.requestCount-1) + }) + } +} + +func TestOpenExchangeRatesClient_shouldRetry(t *testing.T) { + client := NewOpenExchangeRatesClient("test-api-key") + + tests := []struct { + name string + err error + resp *http.Response + expected bool + }{ + { + name: "No error", + err: nil, + resp: nil, + expected: false, + }, + { + name: "Network timeout", + err: &networkError{message: "timeout", timeout: true}, + resp: nil, + expected: true, + }, + { + name: "500 status code", + err: fmt.Errorf("server error"), + resp: &http.Response{StatusCode: http.StatusInternalServerError}, + expected: true, + }, + { + name: "429 status code", + err: fmt.Errorf("rate limit exceeded"), + resp: &http.Response{StatusCode: http.StatusTooManyRequests}, + expected: true, + }, + { + name: "400 status code", + err: fmt.Errorf("bad request"), + resp: &http.Response{StatusCode: http.StatusBadRequest}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := client.shouldRetry(tt.err, tt.resp) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestOpenExchangeRatesClient_calculateBackoff(t *testing.T) { + client := NewOpenExchangeRatesClient("test-api-key") + + for i := 0; i < 5; i++ { + backoff := client.calculateBackoff(i) + assert.GreaterOrEqual(t, backoff, client.baseDelay*(1<= len(ms.responses) { + http.Error(w, "Too many requests", http.StatusInternalServerError) + return + } + + resp := ms.responses[ms.requestCount] + ms.requestCount++ + + if resp.err != nil { + http.Error(w, resp.err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(resp.statusCode) + w.Write([]byte(resp.body)) + })) + return ms +} + +type networkError struct { + message string + timeout bool +} + +func (e *networkError) Error() string { return e.message } +func (e *networkError) Timeout() bool { return e.timeout } +func (e *networkError) Temporary() bool { return true } diff --git a/internal/worker/rate_updater_test.go b/internal/worker/rate_updater_test.go new file mode 100644 index 000000000..5bb852af7 --- /dev/null +++ b/internal/worker/rate_updater_test.go @@ -0,0 +1,194 @@ +package worker + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +// Mock implementations +type MockCurrencyRepository struct { + mock.Mock +} + +func (m *MockCurrencyRepository) GetByCode(ctx context.Context, code string) (*model.Currency, error) { + args := m.Called(ctx, code) + return args.Get(0).(*model.Currency), args.Error(1) +} + +func (m *MockCurrencyRepository) Create(ctx context.Context, currency *model.Currency) error { + args := m.Called(ctx, currency) + return args.Error(0) +} + +func (m *MockCurrencyRepository) Update(ctx context.Context, currency *model.Currency) error { + args := m.Called(ctx, currency) + return args.Error(0) +} + +func (m *MockCurrencyRepository) Delete(ctx context.Context, code string) error { + args := m.Called(ctx, code) + return args.Error(0) +} + +func (m *MockCurrencyRepository) Close() error { + args := m.Called() + return args.Error(0) +} + +type MockCache struct { + mock.Mock +} + +func (m *MockCache) Get(ctx context.Context, key string) (float64, error) { + args := m.Called(ctx, key) + return args.Get(0).(float64), args.Error(1) +} + +func (m *MockCache) Set(ctx context.Context, key string, value float64, expiration time.Duration) error { + args := m.Called(ctx, key, value, expiration) + return args.Error(0) +} + +func (m *MockCache) Delete(ctx context.Context, key string) error { + args := m.Called(ctx, key) + return args.Error(0) +} + +func (m *MockCache) Close() error { + args := m.Called() + return args.Error(0) +} + +type MockExternalAPIClient struct { + mock.Mock +} + +func (m *MockExternalAPIClient) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { + args := m.Called(ctx) + return args.Get(0).(*model.ExchangeRates), args.Error(1) +} + +func TestNewRateUpdater(t *testing.T) { + repo := &MockCurrencyRepository{} + cache := &MockCache{} + externalAPI := &MockExternalAPIClient{} + interval := time.Hour + + updater := NewRateUpdater(repo, cache, externalAPI, interval) + + assert.Equal(t, repo, updater.repo) + assert.Equal(t, cache, updater.cache) + assert.Equal(t, externalAPI, updater.externalAPI) + assert.Equal(t, interval, updater.interval) +} + +func TestRateUpdater_updateRates(t *testing.T) { + repo := &MockCurrencyRepository{} + cache := &MockCache{} + externalAPI := &MockExternalAPIClient{} + updater := NewRateUpdater(repo, cache, externalAPI, time.Hour) + + ctx := context.Background() + mockRates := &model.ExchangeRates{ + Timestamp: time.Now().Unix(), + Rates: map[string]float64{ + "USD": 1.0, + "EUR": 0.85, + }, + } + + externalAPI.On("FetchRates", ctx).Return(mockRates, nil) + repo.On("Update", ctx, mock.AnythingOfType("*model.Currency")).Return(nil) + cache.On("Set", ctx, mock.AnythingOfType("string"), mock.AnythingOfType("float64"), 1*time.Hour).Return(nil) + + err := updater.updateRates(ctx) + + assert.NoError(t, err) + externalAPI.AssertExpectations(t) + repo.AssertExpectations(t) + cache.AssertExpectations(t) +} + +func TestRateUpdater_updateRates_Error(t *testing.T) { + repo := &MockCurrencyRepository{} + cache := &MockCache{} + externalAPI := &MockExternalAPIClient{} + updater := NewRateUpdater(repo, cache, externalAPI, time.Hour) + + ctx := context.Background() + + externalAPI.On("FetchRates", ctx).Return((*model.ExchangeRates)(nil), errors.New("API error")) + + err := updater.updateRates(ctx) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to fetch rates") + externalAPI.AssertExpectations(t) +} + +func TestRateUpdater_populateRates(t *testing.T) { + repo := &MockCurrencyRepository{} + cache := &MockCache{} + externalAPI := &MockExternalAPIClient{} + updater := NewRateUpdater(repo, cache, externalAPI, time.Hour) + + ctx := context.Background() + mockRates := &model.ExchangeRates{ + Timestamp: time.Now().Unix(), + Rates: map[string]float64{ + "USD": 1.0, + "EUR": 0.85, + }, + } + + externalAPI.On("FetchRates", ctx).Return(mockRates, nil) + repo.On("GetByCode", ctx, mock.AnythingOfType("string")).Return((*model.Currency)(nil), errors.New("currency not found")) + repo.On("Create", ctx, mock.AnythingOfType("*model.Currency")).Return(nil) + cache.On("Set", ctx, mock.AnythingOfType("string"), mock.AnythingOfType("float64"), 1*time.Hour).Return(nil) + + err := updater.populateRates(ctx) + + assert.NoError(t, err) + externalAPI.AssertExpectations(t) + repo.AssertExpectations(t) + cache.AssertExpectations(t) +} + +func TestRateUpdater_Start(t *testing.T) { + repo := &MockCurrencyRepository{} + cache := &MockCache{} + externalAPI := &MockExternalAPIClient{} + updater := NewRateUpdater(repo, cache, externalAPI, 100*time.Millisecond) + + ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond) + defer cancel() + + mockRates := &model.ExchangeRates{ + Timestamp: time.Now().Unix(), + Rates: map[string]float64{ + "USD": 1.0, + "EUR": 0.85, + }, + } + + externalAPI.On("FetchRates", mock.Anything).Return(mockRates, nil) + repo.On("GetByCode", mock.Anything, mock.AnythingOfType("string")).Return((*model.Currency)(nil), errors.New("currency not found")) + repo.On("Create", mock.Anything, mock.AnythingOfType("*model.Currency")).Return(nil) + repo.On("Update", mock.Anything, mock.AnythingOfType("*model.Currency")).Return(nil) + cache.On("Set", mock.Anything, mock.AnythingOfType("string"), mock.AnythingOfType("float64"), 1*time.Hour).Return(nil) + + go updater.Start(ctx) + + <-ctx.Done() + + // The updater should have run at least twice (initial populate + at least one update) + externalAPI.AssertNumberOfCalls(t, "FetchRates", 3) + repo.AssertExpectations(t) + cache.AssertExpectations(t) +} From f38f4681d190dc16ae4a5c46001b9c5bbcd98c41 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 6 Aug 2024 21:06:18 -0300 Subject: [PATCH 080/141] test(worker): enhance RateUpdater tests and improve error handling in mocks This commit improves the tests for the RateUpdater and adjusts error handling in mock implementations. - Introduced a helper function newTestRateUpdater to streamline test setup. - Refined assertions and enhanced the readability of test cases for RateUpdater. - Renamed external_api_client_tests.go to external_api_client_test.go for consistency. --- ...t_tests.go => external_api_client_test.go} | 17 ++--- internal/worker/rate_updater_test.go | 73 +++++++++++-------- 2 files changed, 49 insertions(+), 41 deletions(-) rename internal/worker/{external_api_client_tests.go => external_api_client_test.go} (95%) diff --git a/internal/worker/external_api_client_tests.go b/internal/worker/external_api_client_test.go similarity index 95% rename from internal/worker/external_api_client_tests.go rename to internal/worker/external_api_client_test.go index 0104b6faa..2756d6ae8 100644 --- a/internal/worker/external_api_client_tests.go +++ b/internal/worker/external_api_client_test.go @@ -34,9 +34,9 @@ func TestNewOpenExchangeRatesClient(t *testing.T) { func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { tests := []struct { - name string - responses []mockResponse - expectedError bool + name string + responses []mockResponse + expectedError bool expectedRetries int }{ { @@ -44,7 +44,7 @@ func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { responses: []mockResponse{ {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, }, - expectedError: false, + expectedError: false, expectedRetries: 0, }, { @@ -53,7 +53,7 @@ func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { {statusCode: http.StatusInternalServerError, body: ""}, {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, }, - expectedError: false, + expectedError: false, expectedRetries: 1, }, { @@ -62,7 +62,7 @@ func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { {err: &networkError{message: "connection refused"}}, {statusCode: http.StatusOK, body: `{"rates":{"USD":1,"EUR":0.85}}`}, }, - expectedError: false, + expectedError: false, expectedRetries: 1, }, { @@ -73,8 +73,8 @@ func TestOpenExchangeRatesClient_FetchRates(t *testing.T) { {statusCode: http.StatusInternalServerError, body: ""}, {statusCode: http.StatusInternalServerError, body: ""}, }, - expectedError: true, - expectedRetries: 3, + expectedError: true, + expectedRetries: 2, }, } @@ -160,7 +160,6 @@ func TestOpenExchangeRatesClient_calculateBackoff(t *testing.T) { assert.LessOrEqual(t, backoff, client.baseDelay*(1< Date: Tue, 6 Aug 2024 21:26:23 -0300 Subject: [PATCH 081/141] refactor(middleware): update tests and improve rate limit configuration This commit enhances the middleware package by updating test imports and improving the rate limit configuration. - Renamed middleware_tests.go to middleware_test.go for consistency. - Refactored rate limit middleware to use a global Limiter variable for better configurability in tests. - Fixed broken test case for rate limiting. --- internal/middleware/middleware.go | 4 ++-- ...middleware_tests.go => middleware_test.go} | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) rename internal/middleware/{middleware_tests.go => middleware_test.go} (88%) diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index e8de02831..cada2d7e4 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -23,7 +23,7 @@ func NewAuthMiddleware(userRepo repository.UserRepository) *AuthMiddleware { } var ( - limiter = rate.NewLimiter(rate.Every(time.Second), 10) + Limiter = rate.NewLimiter(rate.Every(time.Second), 10) clients = make(map[string]*rate.Limiter) mu sync.Mutex ) @@ -73,7 +73,7 @@ func RequireRole(role model.Role) func(http.Handler) http.Handler { } func RateLimitMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !limiter.Allow() { + if !Limiter.Allow() { logger.Errorf("rate limit exceeded for IP: %s", r.RemoteAddr) http.Error(w, "rate limit exceeded", http.StatusTooManyRequests) return diff --git a/internal/middleware/middleware_tests.go b/internal/middleware/middleware_test.go similarity index 88% rename from internal/middleware/middleware_tests.go rename to internal/middleware/middleware_test.go index abf428b21..10ea3978c 100644 --- a/internal/middleware/middleware_tests.go +++ b/internal/middleware/middleware_test.go @@ -1,11 +1,13 @@ -package api_middleware +package api_middleware_test import ( "context" "net/http" "net/http/httptest" "testing" + "time" + api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -55,7 +57,7 @@ func createTestRequest(apiKey string) *http.Request { func TestAuthMiddleware_Authenticate(t *testing.T) { mockRepo := new(MockUserRepository) - authMiddleware := NewAuthMiddleware(mockRepo) + authMiddleware := api_middleware.NewAuthMiddleware(mockRepo) tests := []struct { name string @@ -79,7 +81,7 @@ func TestAuthMiddleware_Authenticate(t *testing.T) { }, expectedStatus: http.StatusOK, checkUser: func(t *testing.T, r *http.Request) { - user, ok := r.Context().Value(UserContextKey).(model.User) + user, ok := r.Context().Value(api_middleware.UserContextKey).(model.User) assert.True(t, ok) assert.Equal(t, "testuser", user.Username) }, @@ -156,7 +158,7 @@ func TestRequireRole(t *testing.T) { rr := httptest.NewRecorder() if tt.user != (model.User{}) { - ctx := context.WithValue(req.Context(), UserContextKey, tt.user) + ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, tt.user) req = req.WithContext(ctx) } @@ -164,7 +166,7 @@ func TestRequireRole(t *testing.T) { w.WriteHeader(http.StatusOK) }) - handler := RequireRole(tt.requiredRole)(nextHandler) + handler := api_middleware.RequireRole(tt.requiredRole)(nextHandler) handler.ServeHTTP(rr, req) assert.Equal(t, tt.expectedStatus, rr.Code) @@ -181,14 +183,15 @@ func TestRateLimitMiddleware(t *testing.T) { { name: "Under rate limit", setupLimiter: func() { - limiter.SetLimit(rate.Inf) + api_middleware.Limiter.SetLimit(rate.Inf) }, expectedStatus: http.StatusOK, }, { name: "Exceeds rate limit", setupLimiter: func() { - limiter.SetLimit(rate.Limit(0)) + api_middleware.Limiter = rate.NewLimiter(rate.Every(time.Second), 1) + _ = api_middleware.Limiter.Allow() }, expectedStatus: http.StatusTooManyRequests, }, @@ -205,7 +208,7 @@ func TestRateLimitMiddleware(t *testing.T) { w.WriteHeader(http.StatusOK) }) - handler := RateLimitMiddleware(nextHandler) + handler := api_middleware.RateLimitMiddleware(nextHandler) handler.ServeHTTP(rr, req) assert.Equal(t, tt.expectedStatus, rr.Code) From 25221344e6bda144ae9ee0221a9c040aaf77781a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 09:25:00 -0300 Subject: [PATCH 082/141] refactor(seed): improve seeding process and add unit tests This commit enhances the seeding process for the database by improving the main seeding logic and adding unit tests for better reliability. Changes includes: - Refactored seed.go to use a dependencies struct for better testability and dependency injection. - Improved error handling and context usage in seed.go. - Added seed_test.go with unit tests for the seeding process using sqlmock to mock database interactions. - Ensured that the admin user creation logic is tested thoroughly, including hashing and database insertion. --- sql/seed.go | 67 ++++++++++++++++++++++++++++--------- sql/seed_test.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 sql/seed_test.go diff --git a/sql/seed.go b/sql/seed.go index a4ec48e1b..b57db9292 100644 --- a/sql/seed.go +++ b/sql/seed.go @@ -1,6 +1,7 @@ package main import ( + "context" "database/sql" "fmt" "log" @@ -14,47 +15,81 @@ import ( "golang.org/x/crypto/bcrypt" ) +type dependencies struct { + loadConfig func() (server.Config, error) + openDB func(driverName, dataSourceName string) (*sql.DB, error) + newUUID func() uuid.UUID + timeNow func() time.Time + loadEnv func(...string) error +} + +var defaultDeps = dependencies{ + loadConfig: server.LoadConfig, + openDB: sql.Open, + newUUID: uuid.New, + timeNow: time.Now, + loadEnv: godotenv.Load, +} + func main() { - godotenv.Load() - config, err := server.LoadConfig() + if err := run(context.Background(), defaultDeps); err != nil { + log.Fatal(err) + } +} + +func run(ctx context.Context, deps dependencies) error { + if err := deps.loadEnv(); err != nil { + return fmt.Errorf("error loading .env file: %w", err) + } + + config, err := deps.loadConfig() if err != nil { - log.Fatalf("error loading config: %v", err) + return fmt.Errorf("error loading config: %w", err) } - db, err := sql.Open("postgres", config.PostgresConn) + + db, err := deps.openDB("postgres", config.PostgresConn) if err != nil { - log.Fatalf("error opening database connection: %v", err) + return fmt.Errorf("error opening database connection: %w", err) } defer db.Close() - err = db.Ping() - if err != nil { - log.Fatalf("error connecting to the database: %v", err) + if err := db.PingContext(ctx); err != nil { + return fmt.Errorf("error connecting to the database: %w", err) + } + + if err := createAdminUser(ctx, db, deps); err != nil { + return fmt.Errorf("error creating admin user: %w", err) } + fmt.Println("Admin user created successfully!") + return nil +} + +func createAdminUser(ctx context.Context, db *sql.DB, deps dependencies) error { adminUser := model.UserDB{ - ID: uuid.New(), + ID: deps.newUUID(), Username: "admin", Password: "password", Role: model.RoleAdmin, - APIKey: uuid.New().String(), - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + APIKey: deps.newUUID().String(), + CreatedAt: deps.timeNow(), + UpdatedAt: deps.timeNow(), } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(adminUser.Password), bcrypt.DefaultCost) if err != nil { - log.Fatalf("error hashing password: %v", err) + return fmt.Errorf("error hashing password: %w", err) } adminUser.Password = string(hashedPassword) - _, err = db.Exec(` + _, err = db.ExecContext(ctx, ` INSERT INTO users (id, username, password, role, api_key, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7) `, adminUser.ID, adminUser.Username, adminUser.Password, adminUser.Role, adminUser.APIKey, adminUser.CreatedAt, adminUser.UpdatedAt) if err != nil { - log.Fatalf("Error inserting admin user: %v", err) + return fmt.Errorf("error inserting admin user: %w", err) } - fmt.Println("Admin user created successfully!") + return nil } diff --git a/sql/seed_test.go b/sql/seed_test.go new file mode 100644 index 000000000..eb5bc4d8a --- /dev/null +++ b/sql/seed_test.go @@ -0,0 +1,87 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRun(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + mockDeps := dependencies{ + loadConfig: func() (server.Config, error) { + return server.Config{PostgresConn: "mock"}, nil + }, + openDB: func(driverName, dataSourceName string) (*sql.DB, error) { + return db, nil + }, + newUUID: func() uuid.UUID { + return uuid.MustParse("00000000-0000-0000-0000-000000000000") + }, + timeNow: func() time.Time { + return time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC) + }, + loadEnv: func(...string) error { + return nil + }, + } + + mock.ExpectPing() + + mock.ExpectExec("INSERT INTO users").WithArgs( + uuid.MustParse("00000000-0000-0000-0000-000000000000"), + "admin", + sqlmock.AnyArg(), + model.RoleAdmin, + "00000000-0000-0000-0000-000000000000", + mockDeps.timeNow(), + mockDeps.timeNow(), + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = run(context.Background(), mockDeps) + assert.NoError(t, err) + + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestCreateAdminUser(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + mockDeps := dependencies{ + newUUID: func() uuid.UUID { + return uuid.MustParse("00000000-0000-0000-0000-000000000000") + }, + timeNow: func() time.Time { + return time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC) + }, + } + + mock.ExpectExec("INSERT INTO users").WithArgs( + uuid.MustParse("00000000-0000-0000-0000-000000000000"), + "admin", + sqlmock.AnyArg(), + model.RoleAdmin, + "00000000-0000-0000-0000-000000000000", + mockDeps.timeNow(), + mockDeps.timeNow(), + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = createAdminUser(context.Background(), db, mockDeps) + assert.NoError(t, err) + fmt.Println("success creating an admin user") + assert.NoError(t, mock.ExpectationsWereMet()) +} From 715b765d70fb470bf38203f059d2d975a267a9da Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 09:43:34 -0300 Subject: [PATCH 083/141] fix(repository): handle no rows affected in currency update This commit improves error handling in the `Update` method of the `PostgresCurrencyRepository` by properly checking for the number of rows affected after an update operation. If no rows are affected, it returns an appropriate `ErrCurrencyNotFound` error. --- internal/repository/pg_currency_repository.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index 0fddecbe1..75668abe1 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -58,12 +58,22 @@ func (r *PostgresCurrencyRepository) Create(ctx context.Context, currency *model func (r *PostgresCurrencyRepository) Update(ctx context.Context, currency *model.Currency) error { query := `UPDATE currencies SET rate = $2, updated_at = $3, updated_by = $4 WHERE code = $1` - _, err := r.db.ExecContext(ctx, query, + result, err := r.db.ExecContext(ctx, query, currency.Code, currency.Rate, currency.UpdatedAt, currency.UpdatedBy, ) if err != nil { return fmt.Errorf("failed to update currency: %w", err) } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to get rows affected: %w", err) + } + + if rowsAffected == 0 { + return model.ErrCurrencyNotFound + } + return nil } From 8d4fe17aed3467cdf355295dffd0ec2856b4fc77 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 09:45:53 -0300 Subject: [PATCH 084/141] test(repository): add unit tests for user, logger, and currency repositories This commit adds unit tests for the Postgres repositories handling users, logs, and currencies. The changes were made: - Added `pg_user_repository_test.go` to test user repository CRUD operations. - Added `pg_logger_repository_test.go` to test log repository operations. - Added `pg_currency_repository_test.go` to test currency repository CRUD operations. - Ensured all tests cover both successful cases and failure scenarios. --- .../repository/pg_currency_repository_test.go | 146 ++++++++++++++ .../repository/pg_logger_repository_test.go | 101 ++++++++++ .../repository/pg_user_repository_test.go | 182 ++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 internal/repository/pg_currency_repository_test.go create mode 100644 internal/repository/pg_logger_repository_test.go create mode 100644 internal/repository/pg_user_repository_test.go diff --git a/internal/repository/pg_currency_repository_test.go b/internal/repository/pg_currency_repository_test.go new file mode 100644 index 000000000..3b1606e6b --- /dev/null +++ b/internal/repository/pg_currency_repository_test.go @@ -0,0 +1,146 @@ +package repository + +import ( + "context" + "database/sql" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPostgresCurrencyRepository_GetByCode(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresCurrencyRepository{db: db} + + t.Run("Successful retrieval", func(t *testing.T) { + rows := sqlmock.NewRows([]string{"code", "rate", "updated_at", "created_by", "updated_by", "created_at"}). + AddRow("USD", 1.0, time.Now(), uuid.New(), uuid.New(), time.Now()) + + mock.ExpectQuery("SELECT code, rate, updated_at, created_by, updated_by, created_at FROM currencies WHERE code = \\$1"). + WithArgs("USD"). + WillReturnRows(rows) + + currency, err := repo.GetByCode(context.Background(), "USD") + assert.NoError(t, err) + assert.NotNil(t, currency) + assert.Equal(t, "USD", currency.Code) + }) + + t.Run("Currency not found", func(t *testing.T) { + mock.ExpectQuery("SELECT code, rate, updated_at, created_by, updated_by, created_at FROM currencies WHERE code = \\$1"). + WithArgs("EUR"). + WillReturnError(sql.ErrNoRows) + + currency, err := repo.GetByCode(context.Background(), "EUR") + assert.Error(t, err) + assert.Nil(t, currency) + assert.Equal(t, model.ErrCurrencyNotFound, err) + }) +} + +func TestPostgresCurrencyRepository_Create(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresCurrencyRepository{db: db} + + t.Run("Successful creation", func(t *testing.T) { + currency := &model.Currency{ + Code: "EUR", + Rate: 0.85, + UpdatedAt: time.Now(), + CreatedBy: uuid.New(), + UpdatedBy: uuid.New(), + CreatedAt: time.Now(), + } + + mock.ExpectExec("INSERT INTO currencies"). + WithArgs(currency.Code, currency.Rate, currency.UpdatedAt, currency.CreatedBy, currency.UpdatedBy, currency.CreatedAt). + WillReturnResult(sqlmock.NewResult(1, 1)) + + err := repo.Create(context.Background(), currency) + assert.NoError(t, err) + }) +} + +func TestPostgresCurrencyRepository_Update(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresCurrencyRepository{db: db} + + t.Run("Successful update", func(t *testing.T) { + currency := &model.Currency{ + Code: "USD", + Rate: 1.1, + UpdatedAt: time.Now(), + UpdatedBy: uuid.New(), + } + + mock.ExpectExec("UPDATE currencies SET"). + WithArgs(currency.Code, currency.Rate, currency.UpdatedAt, currency.UpdatedBy). + WillReturnResult(sqlmock.NewResult(0, 1)) + + err := repo.Update(context.Background(), currency) + assert.NoError(t, err) + }) + + t.Run("Currency not found", func(t *testing.T) { + currency := &model.Currency{ + Code: "XYZ", + Rate: 1.0, + UpdatedAt: time.Now(), + UpdatedBy: uuid.New(), + } + + mock.ExpectExec("UPDATE currencies SET"). + WithArgs(currency.Code, currency.Rate, currency.UpdatedAt, currency.UpdatedBy). + WillReturnResult(sqlmock.NewResult(0, 0)) + + err := repo.Update(context.Background(), currency) + assert.Error(t, err) + assert.Equal(t, model.ErrCurrencyNotFound, err) + }) +} + +func TestPostgresCurrencyRepository_Delete(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresCurrencyRepository{db: db} + + t.Run("Successful deletion", func(t *testing.T) { + mock.ExpectExec("DELETE FROM currencies WHERE code = \\$1"). + WithArgs("USD"). + WillReturnResult(sqlmock.NewResult(0, 1)) + + err := repo.Delete(context.Background(), "USD") + assert.NoError(t, err) + }) +} + +func TestPostgresCurrencyRepository_Close(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + + repo := &PostgresCurrencyRepository{db: db} + + mock.ExpectClose() + + err = repo.Close() + assert.NoError(t, err) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) +} diff --git a/internal/repository/pg_logger_repository_test.go b/internal/repository/pg_logger_repository_test.go new file mode 100644 index 000000000..58418c33b --- /dev/null +++ b/internal/repository/pg_logger_repository_test.go @@ -0,0 +1,101 @@ +package repository + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPostgresLogRepository_SaveLog(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresLogRepository{db: db} + + t.Run("Successful log save", func(t *testing.T) { + log := model.Log{ + ID: uuid.New(), + Level: model.LogLevelInfo, + Message: "Test log message", + Timestamp: time.Now(), + Source: "test", + } + + mock.ExpectExec("INSERT INTO logs"). + WithArgs(log.ID, log.Level, log.Message, log.Timestamp, log.Source). + WillReturnResult(sqlmock.NewResult(1, 1)) + + err := repo.SaveLog(context.Background(), log) + assert.NoError(t, err) + }) + + t.Run("Failed log save", func(t *testing.T) { + log := model.Log{ + ID: uuid.New(), + Level: model.LogLevelError, + Message: "Test error message", + Timestamp: time.Now(), + Source: "test", + } + + mock.ExpectExec("INSERT INTO logs"). + WithArgs(log.ID, log.Level, log.Message, log.Timestamp, log.Source). + WillReturnError(fmt.Errorf("database error")) + + err := repo.SaveLog(context.Background(), log) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to save log") + }) +} + +func TestPostgresLogRepository_CreatePartition(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresLogRepository{db: db} + + t.Run("Successful partition creation", func(t *testing.T) { + month := time.Date(2023, time.May, 1, 0, 0, 0, 0, time.UTC) + + mock.ExpectExec("CREATE TABLE IF NOT EXISTS logs_y2023m05 PARTITION OF logs"). + WillReturnResult(sqlmock.NewResult(0, 0)) + + err := repo.CreatePartition(context.Background(), month) + assert.NoError(t, err) + }) + + t.Run("Failed partition creation", func(t *testing.T) { + month := time.Date(2023, time.June, 1, 0, 0, 0, 0, time.UTC) + + mock.ExpectExec("CREATE TABLE IF NOT EXISTS logs_y2023m06 PARTITION OF logs"). + WillReturnError(fmt.Errorf("database error")) + + err := repo.CreatePartition(context.Background(), month) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to create partition logs_y2023m06") + }) +} + +func TestPostgresLogRepository_Close(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + + repo := &PostgresLogRepository{db: db} + + mock.ExpectClose() + + err = repo.Close() + assert.NoError(t, err) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) +} diff --git a/internal/repository/pg_user_repository_test.go b/internal/repository/pg_user_repository_test.go new file mode 100644 index 000000000..d1d78b97e --- /dev/null +++ b/internal/repository/pg_user_repository_test.go @@ -0,0 +1,182 @@ +package repository + +import ( + "context" + "database/sql" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPostgresUserRepository_Create(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresUserRepository{db: db} + + t.Run("Successful creation", func(t *testing.T) { + user := &model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Password: "hashedpassword", + Role: model.RoleUser, + APIKey: uuid.New().String(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + mock.ExpectExec("INSERT INTO users"). + WithArgs(user.ID, user.Username, user.Password, user.Role, user.APIKey, user.CreatedAt, user.UpdatedAt). + WillReturnResult(sqlmock.NewResult(1, 1)) + + err := repo.Create(context.Background(), user) + assert.NoError(t, err) + }) +} + +func TestPostgresUserRepository_GetByUsername(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresUserRepository{db: db} + + t.Run("Successful retrieval", func(t *testing.T) { + rows := sqlmock.NewRows([]string{"id", "username", "password", "role", "api_key", "created_at", "updated_at"}). + AddRow(uuid.New(), "testuser", "hashedpassword", model.RoleUser, uuid.New().String(), time.Now(), time.Now()) + + mock.ExpectQuery("SELECT .+ FROM users WHERE username = \\$1"). + WithArgs("testuser"). + WillReturnRows(rows) + + user, err := repo.GetByUsername(context.Background(), "testuser") + assert.NoError(t, err) + assert.NotNil(t, user) + assert.Equal(t, "testuser", user.Username) + }) + + t.Run("User not found", func(t *testing.T) { + mock.ExpectQuery("SELECT .+ FROM users WHERE username = \\$1"). + WithArgs("nonexistent"). + WillReturnError(sql.ErrNoRows) + + user, err := repo.GetByUsername(context.Background(), "nonexistent") + assert.Error(t, err) + assert.Nil(t, user) + assert.Contains(t, err.Error(), "user not found") + }) +} + +func TestPostgresUserRepository_GetByAPIKey(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresUserRepository{db: db} + + t.Run("Successful retrieval", func(t *testing.T) { + apiKey := uuid.New().String() + rows := sqlmock.NewRows([]string{"id", "username", "password", "role", "api_key", "created_at", "updated_at"}). + AddRow(uuid.New(), "testuser", "hashedpassword", model.RoleUser, apiKey, time.Now(), time.Now()) + + mock.ExpectQuery("SELECT .+ FROM users WHERE api_key = \\$1"). + WithArgs(apiKey). + WillReturnRows(rows) + + user, err := repo.GetByAPIKey(context.Background(), apiKey) + assert.NoError(t, err) + assert.NotNil(t, user) + assert.Equal(t, apiKey, user.APIKey) + }) +} + +func TestPostgresUserRepository_Update(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresUserRepository{db: db} + + t.Run("Successful update", func(t *testing.T) { + user := &model.UserDB{ + Username: "testuser", + Password: "newhashpassword", + Role: model.RoleAdmin, + APIKey: uuid.New().String(), + UpdatedAt: time.Now(), + } + + mock.ExpectExec("UPDATE users SET"). + WithArgs(user.Password, user.Role, user.APIKey, user.UpdatedAt, user.Username). + WillReturnResult(sqlmock.NewResult(0, 1)) + + err := repo.Update(context.Background(), user) + assert.NoError(t, err) + }) + + t.Run("User not found", func(t *testing.T) { + user := &model.UserDB{ + Username: "nonexistent", + Password: "newhashpassword", + Role: model.RoleAdmin, + APIKey: uuid.New().String(), + UpdatedAt: time.Now(), + } + + mock.ExpectExec("UPDATE users SET"). + WithArgs(user.Password, user.Role, user.APIKey, user.UpdatedAt, user.Username). + WillReturnResult(sqlmock.NewResult(0, 0)) + + err := repo.Update(context.Background(), user) + assert.Error(t, err) + assert.Contains(t, err.Error(), "user not found") + }) +} + +func TestPostgresUserRepository_Delete(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + repo := &PostgresUserRepository{db: db} + + t.Run("Successful deletion", func(t *testing.T) { + mock.ExpectExec("DELETE FROM users WHERE username = \\$1"). + WithArgs("testuser"). + WillReturnResult(sqlmock.NewResult(0, 1)) + + err := repo.Delete(context.Background(), "testuser") + assert.NoError(t, err) + }) + + t.Run("User not found", func(t *testing.T) { + mock.ExpectExec("DELETE FROM users WHERE username = \\$1"). + WithArgs("nonexistent"). + WillReturnResult(sqlmock.NewResult(0, 0)) + + err := repo.Delete(context.Background(), "nonexistent") + assert.Error(t, err) + assert.Contains(t, err.Error(), "user not found") + }) +} + +func TestPostgresUserRepository_Close(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + + repo := &PostgresUserRepository{db: db} + + mock.ExpectClose() + + err = repo.Close() + assert.NoError(t, err) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) +} From 9a84aa0066a53f2a32374735cf83884874d058c6 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 09:46:37 -0300 Subject: [PATCH 085/141] chore(dependencies): add go-sqlmock dependency This commit adds the `go-sqlmock` dependency to the project to facilitate mocking SQL database interactions in tests. --- go.mod | 1 + go.sum | 3 +++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index ab19bd8c6..57c4d98c8 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/alicebob/miniredis/v2 v2.33.0 github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 diff --git a/go.sum b/go.sum index c2403213f..bae7da6b3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= @@ -18,6 +20,7 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= From c9a041d0844c8c3865e44f561e05109ae3829a53 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 12:35:33 -0300 Subject: [PATCH 086/141] feat(commons): add global constants This commit introduces a new `constants.go` file under the `commons` package. The file includes various constants that will be used throughout the project. - Added `AllowedCurrencyLength`, `MinimumCurrencyLength`, `UserContextKey`, and `AllowedRPS` constants in `constants.go`. --- internal/commons/constants.go | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 internal/commons/constants.go diff --git a/internal/commons/constants.go b/internal/commons/constants.go new file mode 100644 index 000000000..13233b5ee --- /dev/null +++ b/internal/commons/constants.go @@ -0,0 +1,8 @@ +package commons + +const ( + AllowedCurrencyLength = 5 + MinimumCurrencyLength = 3 + UserContextKey = "user" + AllowedRPS = 10 +) From 030ead57e6df57694e6d1e76edef78b3ac3ead79 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 12:38:44 -0300 Subject: [PATCH 087/141] feat(handler): enforce currency code length constraints This commit introduces stricter validation for currency codes in the currency handler. Currency codes must now adhere to defined length constraints. The changes include: - Added validation to ensure currency codes are at least `MinimumCurrencyLength` and at most `AllowedCurrencyLength` characters long. - Updated error messages to reflect the new length constraints. - Adjusted tests to cover cases for currency codes below minimum and above maximum allowed lengths. --- internal/handler/currency_handler.go | 28 ++++++++++++---- internal/handler/currency_handler_test.go | 41 ++++++++++++++++++----- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index b9e62dbaf..d55ebc1b9 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -33,10 +33,15 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request commons.RespondWithError(w, http.StatusBadRequest, "missing required parameters") return } - if len(from) != 3 || len(to) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") + if len(from) > commons.AllowedCurrencyLength || len(to) > commons.AllowedCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be up to %d characters", commons.AllowedCurrencyLength)) return } + if len(from) < commons.MinimumCurrencyLength || len(to) < commons.MinimumCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be at least %d characters", commons.MinimumCurrencyLength)) + return + } + amount, err := parseAmount(amountStr) if err != nil { commons.RespondWithError(w, http.StatusBadRequest, "invalid amount") @@ -76,8 +81,13 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") return } - if len(currency.Code) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") + if len(currency.Code) > commons.AllowedCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be up to %d characters", commons.AllowedCurrencyLength)) + return + } + + if len(currency.Code) < commons.MinimumCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be at least %d characters", commons.MinimumCurrencyLength)) return } @@ -115,7 +125,7 @@ func (h *CurrencyHandler) AddCurrency(w http.ResponseWriter, r *http.Request) { func (h *CurrencyHandler) UpdateCurrency(w http.ResponseWriter, r *http.Request) { code := strings.ToUpper(chi.URLParam(r, "code")) - if code == "" || len(code) != 3 { + if code == "" || len(code) > commons.AllowedCurrencyLength || len(code) < commons.MinimumCurrencyLength { commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") return } @@ -165,8 +175,12 @@ func (h *CurrencyHandler) RemoveCurrency(w http.ResponseWriter, r *http.Request) commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code") return } - if len(code) != 3 { - commons.RespondWithError(w, http.StatusBadRequest, "invalid currency code, must be 3 characters long following ISO 4217") + if len(code) > commons.AllowedCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be up to %d characters", commons.AllowedCurrencyLength)) + return + } + if len(code) < commons.MinimumCurrencyLength { + commons.RespondWithError(w, http.StatusBadRequest, fmt.Sprintf("invalid currency code, must be at least %d characters", commons.MinimumCurrencyLength)) return } if err := h.currencyService.RemoveCurrency(r.Context(), code); err != nil { diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go index 2bb21fcf9..f724923f8 100644 --- a/internal/handler/currency_handler_test.go +++ b/internal/handler/currency_handler_test.go @@ -4,12 +4,13 @@ import ( "bytes" "context" "encoding/json" + "fmt" "net/http" "net/http/httptest" "testing" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/handler" - api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/go-chi/chi/v5" "github.com/google/uuid" @@ -181,13 +182,23 @@ func TestAddCurrency(t *testing.T) { mockBehavior: func() {}, }, { - name: "Invalid code length", + name: "Invalid code length - Above Maximum Allowed", payload: map[string]interface{}{ - "code": "USDD", + "code": "USDDDD", "rate_to_usd": 1.0, }, expectedStatus: http.StatusBadRequest, - expectedBody: `{"error":"invalid currency code, must be 3 characters long following ISO 4217"}`, + expectedBody: fmt.Sprintf(`{"error":"invalid currency code, must be up to %d characters"}`, commons.AllowedCurrencyLength), + mockBehavior: func() {}, + }, + { + name: "Invalid code length - Below Minimum Allowed", + payload: map[string]interface{}{ + "code": "US", + "rate_to_usd": 1.0, + }, + expectedStatus: http.StatusBadRequest, + expectedBody: fmt.Sprintf(`{"error":"invalid currency code, must be at least %d characters"}`, commons.MinimumCurrencyLength), mockBehavior: func() {}, }, } @@ -202,7 +213,7 @@ func TestAddCurrency(t *testing.T) { userID := uuid.New() user := model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} - ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, user) + ctx := context.WithValue(req.Context(), commons.UserContextKey, user) req = req.WithContext(ctx) rr := httptest.NewRecorder() @@ -249,8 +260,22 @@ func TestRemoveCurrency(t *testing.T) { assert.Equal(t, http.StatusNotFound, rr.Code) }) + t.Run("Invalid Code - Length Under Minimum", func(t *testing.T) { + req, err := http.NewRequest("DELETE", "/currency/R", nil) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + + router := chi.NewRouter() + router.Delete("/currency/{code}", h.RemoveCurrency) + router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.JSONEq(t, fmt.Sprintf(`{"error":"invalid currency code, must be at least %d characters"}`, commons.MinimumCurrencyLength), rr.Body.String()) + + }) t.Run("Invalid Code - Length", func(t *testing.T) { - req, err := http.NewRequest("DELETE", "/currency/RR", nil) + req, err := http.NewRequest("DELETE", "/currency/RRRRRR", nil) assert.NoError(t, err) rr := httptest.NewRecorder() @@ -260,7 +285,7 @@ func TestRemoveCurrency(t *testing.T) { router.ServeHTTP(rr, req) assert.Equal(t, http.StatusBadRequest, rr.Code) - assert.JSONEq(t, `{"error":"invalid currency code, must be 3 characters long following ISO 4217"}`, rr.Body.String()) + assert.JSONEq(t, fmt.Sprintf(`{"error":"invalid currency code, must be up to %d characters"}`, commons.AllowedCurrencyLength), rr.Body.String()) }) } @@ -353,7 +378,7 @@ func TestUpdateCurrency(t *testing.T) { userID := uuid.New() user := model.User{ID: userID, Username: "testuser", Role: model.RoleAdmin} - ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, user) + ctx := context.WithValue(req.Context(), commons.UserContextKey, user) req = req.WithContext(ctx) rctx := chi.NewRouteContext() From f1c6c2fee827e14b24f9230af46f23f9ac984a97 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 12:40:02 -0300 Subject: [PATCH 088/141] refactor(middleware): improve rate limiting and authentication This commit enhances the middleware functionalities by: - Moving user context key and rate limit constants to the `commons` package. - Introducing `getRateLimiter` to manage rate limiters per IP address dynamically. - Updating the rate limit middleware to use the `getRateLimiter` function. - Refactoring `Authenticate` and `RequireRole` middleware to use the `commons.UserContextKey` constant. - Adjusting tests to ensure correct behavior with the new rate limiting logic and user context key. --- internal/middleware/middleware.go | 29 +++++++++++++++++++------- internal/middleware/middleware_test.go | 23 +++++++++++++++----- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index cada2d7e4..a98f81d9f 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -6,14 +6,13 @@ import ( "sync" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" "golang.org/x/time/rate" ) -const UserContextKey = "user" - type AuthMiddleware struct { userRepo repository.UserRepository } @@ -23,11 +22,23 @@ func NewAuthMiddleware(userRepo repository.UserRepository) *AuthMiddleware { } var ( - Limiter = rate.NewLimiter(rate.Every(time.Second), 10) - clients = make(map[string]*rate.Limiter) + Clients = make(map[string]*rate.Limiter) mu sync.Mutex ) +func getRateLimiter(ip string) *rate.Limiter { + mu.Lock() + defer mu.Unlock() + + limiter, exists := Clients[ip] + if !exists { + limiter = rate.NewLimiter(rate.Every(time.Second), commons.AllowedRPS) + Clients[ip] = limiter + } + + return limiter +} + func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKey := r.Header.Get("X-API-Key") @@ -45,7 +56,7 @@ func (am *AuthMiddleware) Authenticate(next http.Handler) http.Handler { } user := userDB.ToUser() - ctx := context.WithValue(r.Context(), UserContextKey, user) + ctx := context.WithValue(r.Context(), commons.UserContextKey, user) next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -54,7 +65,7 @@ func RequireRole(role model.Role) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - contextUser := r.Context().Value(UserContextKey) + contextUser := r.Context().Value(commons.UserContextKey) user, ok := contextUser.(model.User) if !ok { @@ -71,9 +82,13 @@ func RequireRole(role model.Role) func(http.Handler) http.Handler { }) } } + func RateLimitMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !Limiter.Allow() { + ip := r.RemoteAddr + + limiter := getRateLimiter(ip) + if !limiter.Allow() { logger.Errorf("rate limit exceeded for IP: %s", r.RemoteAddr) http.Error(w, "rate limit exceeded", http.StatusTooManyRequests) return diff --git a/internal/middleware/middleware_test.go b/internal/middleware/middleware_test.go index 10ea3978c..4f9589455 100644 --- a/internal/middleware/middleware_test.go +++ b/internal/middleware/middleware_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/google/uuid" @@ -81,7 +82,7 @@ func TestAuthMiddleware_Authenticate(t *testing.T) { }, expectedStatus: http.StatusOK, checkUser: func(t *testing.T, r *http.Request) { - user, ok := r.Context().Value(api_middleware.UserContextKey).(model.User) + user, ok := r.Context().Value(commons.UserContextKey).(model.User) assert.True(t, ok) assert.Equal(t, "testuser", user.Username) }, @@ -158,7 +159,7 @@ func TestRequireRole(t *testing.T) { rr := httptest.NewRecorder() if tt.user != (model.User{}) { - ctx := context.WithValue(req.Context(), api_middleware.UserContextKey, tt.user) + ctx := context.WithValue(req.Context(), commons.UserContextKey, tt.user) req = req.WithContext(ctx) } @@ -175,23 +176,34 @@ func TestRequireRole(t *testing.T) { } func TestRateLimitMiddleware(t *testing.T) { + originalClients := api_middleware.Clients + api_middleware.Clients = make(map[string]*rate.Limiter) + defer func() { + api_middleware.Clients = originalClients + }() + tests := []struct { name string + ip string setupLimiter func() expectedStatus int }{ { name: "Under rate limit", + ip: "192.168.0.1", setupLimiter: func() { - api_middleware.Limiter.SetLimit(rate.Inf) + limiter := rate.NewLimiter(rate.Inf, commons.AllowedRPS) + api_middleware.Clients["192.168.0.1"] = limiter }, expectedStatus: http.StatusOK, }, { name: "Exceeds rate limit", + ip: "192.168.0.1", setupLimiter: func() { - api_middleware.Limiter = rate.NewLimiter(rate.Every(time.Second), 1) - _ = api_middleware.Limiter.Allow() + limiter := rate.NewLimiter(rate.Every(time.Second), 1) + api_middleware.Clients["192.168.0.1"] = limiter + _ = api_middleware.Clients["192.168.0.1"].Allow() }, expectedStatus: http.StatusTooManyRequests, }, @@ -202,6 +214,7 @@ func TestRateLimitMiddleware(t *testing.T) { tt.setupLimiter() req := httptest.NewRequest("GET", "/", nil) + req.RemoteAddr = tt.ip rr := httptest.NewRecorder() nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { From e4acfce271a3ad8ef8652e278dacd3c041dba9f3 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 16:59:20 -0300 Subject: [PATCH 089/141] refactor(logger): externalize constants and improve maintainability This commit improves the logger package by: - Externalizing constants for logger buffer size and sleep duration. - Replacing hardcoded values with constants in `logger.go`. - Updating test files (`logger_test.go` and `partition_manager_test.go`) to use the new constants for consistency. --- internal/logger/logger.go | 14 ++++++++------ internal/logger/logger_test.go | 4 ++-- internal/logger/partition_manager_test.go | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 83766ec7b..e5dd47893 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -13,16 +13,18 @@ import ( ) var ( - InfoLogger *log.Logger - ErrorLogger *log.Logger - logChan chan model.Log - logRepo repository.LogRepository + InfoLogger *log.Logger + ErrorLogger *log.Logger + logChan chan model.Log + logRepo repository.LogRepository + loggerBufferSize = 1000 + LoggerSleepDuration = 100 * time.Millisecond ) func init() { InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - logChan = make(chan model.Log, 1000) + logChan = make(chan model.Log, loggerBufferSize) } func InitLogger(repo repository.LogRepository) { @@ -87,7 +89,7 @@ func Shutdown(ctx context.Context) error { if len(logChan) == 0 { return logRepo.Close() } - time.Sleep(100 * time.Millisecond) + time.Sleep(LoggerSleepDuration) } } } diff --git a/internal/logger/logger_test.go b/internal/logger/logger_test.go index 2da4b0516..0a3d80db9 100644 --- a/internal/logger/logger_test.go +++ b/internal/logger/logger_test.go @@ -36,7 +36,7 @@ func TestLogger_Info(t *testing.T) { logger.Info("Test info message") - time.Sleep(100 * time.Millisecond) + time.Sleep(logger.LoggerSleepDuration) mockRepo.AssertCalled(t, "SaveLog", mock.Anything, mock.MatchedBy(func(log model.Log) bool { return log.Level == model.LogLevelInfo && log.Message == "Test info message" @@ -51,7 +51,7 @@ func TestLogger_Error(t *testing.T) { logger.Error("Test error message") - time.Sleep(100 * time.Millisecond) + time.Sleep(logger.LoggerSleepDuration) mockRepo.AssertCalled(t, "SaveLog", mock.Anything, mock.MatchedBy(func(log model.Log) bool { return log.Level == model.LogLevelError && log.Message == "Test error message" })) diff --git a/internal/logger/partition_manager_test.go b/internal/logger/partition_manager_test.go index 3dbddf323..dbefd568a 100644 --- a/internal/logger/partition_manager_test.go +++ b/internal/logger/partition_manager_test.go @@ -67,7 +67,7 @@ func TestPartitionManager_Start(t *testing.T) { err := pm.Start(ctx) assert.NoError(t, err) - time.Sleep(100 * time.Millisecond) + time.Sleep(LoggerSleepDuration) mockRepo.AssertExpectations(t) @@ -140,7 +140,7 @@ func TestPartitionManager_cronJob(t *testing.T) { assert.Len(t, entries, 1) entries[0].Job.Run() - time.Sleep(100 * time.Millisecond) + time.Sleep(LoggerSleepDuration) mockRepo.AssertExpectations(t) } From d59615e7910077ea9e29c10a39dc945dd1b1f70d Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:01:44 -0300 Subject: [PATCH 090/141] refactor(repository): enhance database connection handling and add tests This commit refactors the repository constructors to accept an optional `*sql.DB` parameter, allowing for dependency injection in tests and other contexts where a pre-existing database connection might be used. This change improves the flexibility and testability of the code. Changes: - Refactored `NewPostgresCurrencyRepository`, `NewPostgresLogRepository`, and `NewPostgresUserRepository` to accept an optional `*sql.DB` parameter. - Updated the constructors to only create and ping a new database connection if one is not provided. - Added unit tests for the constructors in `pg_currency_repository_test.go`, `pg_logger_repository_test.go`, and `pg_user_repository_test.go` to verify behavior with both real and mock database connections. --- internal/repository/pg_currency_repository.go | 20 ++++++++------ .../repository/pg_currency_repository_test.go | 25 ++++++++++++++++++ internal/repository/pg_logger_repository.go | 21 ++++++++------- .../repository/pg_logger_repository_test.go | 26 +++++++++++++++++++ internal/repository/pg_user_repository.go | 19 ++++++++------ .../repository/pg_user_repository_test.go | 26 +++++++++++++++++++ 6 files changed, 112 insertions(+), 25 deletions(-) diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index 75668abe1..acee18a93 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -13,15 +13,19 @@ type PostgresCurrencyRepository struct { db *sql.DB } -func NewPostgresCurrencyRepository(connURL string) (*PostgresCurrencyRepository, error) { - db, err := sql.Open("postgres", connURL) - if err != nil { - return nil, fmt.Errorf("failed to connect to database: %w", err) - } +func NewPostgresCurrencyRepository(connURL string, db *sql.DB) (*PostgresCurrencyRepository, error) { + if db == nil { + fmt.Println("shouldn't be here") + var err error + db, err = sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } - err = db.Ping() - if err != nil { - return nil, fmt.Errorf("failed to ping database: %w", err) + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } } return &PostgresCurrencyRepository{db: db}, nil diff --git a/internal/repository/pg_currency_repository_test.go b/internal/repository/pg_currency_repository_test.go index 3b1606e6b..f0e71f048 100644 --- a/internal/repository/pg_currency_repository_test.go +++ b/internal/repository/pg_currency_repository_test.go @@ -13,6 +13,31 @@ import ( "github.com/stretchr/testify/require" ) +func TestNewPostgresCurrencyRepository(t *testing.T) { + t.Run("With real connection", func(t *testing.T) { + t.Skip("Skipping integration test") + + repo, err := NewPostgresCurrencyRepository("your_real_connection_string", nil) + assert.NoError(t, err) + assert.NotNil(t, repo) + repo.Close() + }) + + t.Run("With mock database", func(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + mock.ExpectPing() + + repo, err := NewPostgresCurrencyRepository("", db) + assert.NoError(t, err) + assert.NotNil(t, repo) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) + }) +} func TestPostgresCurrencyRepository_GetByCode(t *testing.T) { db, mock, err := sqlmock.New() require.NoError(t, err) diff --git a/internal/repository/pg_logger_repository.go b/internal/repository/pg_logger_repository.go index b671e3465..88a82f79d 100644 --- a/internal/repository/pg_logger_repository.go +++ b/internal/repository/pg_logger_repository.go @@ -13,15 +13,18 @@ type PostgresLogRepository struct { db *sql.DB } -func NewPostgresLogRepository(connURL string) (*PostgresLogRepository, error) { - db, err := sql.Open("postgres", connURL) - if err != nil { - return nil, fmt.Errorf("failed to connect to database: %w", err) - } - - err = db.Ping() - if err != nil { - return nil, fmt.Errorf("failed to ping database: %w", err) +func NewPostgresLogRepository(connURL string, db *sql.DB) (*PostgresLogRepository, error) { + if db == nil { + var err error + db, err = sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } + + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } } return &PostgresLogRepository{db: db}, nil diff --git a/internal/repository/pg_logger_repository_test.go b/internal/repository/pg_logger_repository_test.go index 58418c33b..875b73796 100644 --- a/internal/repository/pg_logger_repository_test.go +++ b/internal/repository/pg_logger_repository_test.go @@ -13,6 +13,32 @@ import ( "github.com/stretchr/testify/require" ) +func TestNewPostgresLogRepository(t *testing.T) { + t.Run("With real connection", func(t *testing.T) { + t.Skip("Skipping integration test") + + repo, err := NewPostgresLogRepository("your_real_connection_string", nil) + assert.NoError(t, err) + assert.NotNil(t, repo) + repo.Close() + }) + + t.Run("With mock database", func(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + mock.ExpectPing() + + repo, err := NewPostgresLogRepository("", db) + assert.NoError(t, err) + assert.NotNil(t, repo) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) + }) +} + func TestPostgresLogRepository_SaveLog(t *testing.T) { db, mock, err := sqlmock.New() require.NoError(t, err) diff --git a/internal/repository/pg_user_repository.go b/internal/repository/pg_user_repository.go index c91d108f6..d2dad2c07 100644 --- a/internal/repository/pg_user_repository.go +++ b/internal/repository/pg_user_repository.go @@ -13,15 +13,18 @@ type PostgresUserRepository struct { db *sql.DB } -func NewPostgresUserRepository(connURL string) (*PostgresUserRepository, error) { - db, err := sql.Open("postgres", connURL) - if err != nil { - return nil, fmt.Errorf("failed to connect to database: %w", err) - } +func NewPostgresUserRepository(connURL string, db *sql.DB) (*PostgresUserRepository, error) { + if db == nil { + var err error + db, err = sql.Open("postgres", connURL) + if err != nil { + return nil, fmt.Errorf("failed to connect to database: %w", err) + } - err = db.Ping() - if err != nil { - return nil, fmt.Errorf("failed to ping database: %w", err) + err = db.Ping() + if err != nil { + return nil, fmt.Errorf("failed to ping database: %w", err) + } } return &PostgresUserRepository{db: db}, nil diff --git a/internal/repository/pg_user_repository_test.go b/internal/repository/pg_user_repository_test.go index d1d78b97e..b8574fac7 100644 --- a/internal/repository/pg_user_repository_test.go +++ b/internal/repository/pg_user_repository_test.go @@ -13,6 +13,32 @@ import ( "github.com/stretchr/testify/require" ) +func TestNewPostgresUserRepository(t *testing.T) { + t.Run("With real connection", func(t *testing.T) { + t.Skip("Skipping integration test") + + repo, err := NewPostgresUserRepository("your_real_connection_string", nil) + assert.NoError(t, err) + assert.NotNil(t, repo) + repo.Close() + }) + + t.Run("With mock database", func(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + + mock.ExpectPing() + + repo, err := NewPostgresUserRepository("", db) + assert.NoError(t, err) + assert.NotNil(t, repo) + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) + }) +} + func TestPostgresUserRepository_Create(t *testing.T) { db, mock, err := sqlmock.New() require.NoError(t, err) From f08d94617db89170a89590bf5f85b28fec944986 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:03:14 -0300 Subject: [PATCH 091/141] refactor(server): modify server exports and initialization for better testing This commit refactors the Server initialization to enhance dependency injection for repository components and export Router to facilitate e2e tests. --- internal/server/routes.go | 2 +- internal/server/server.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/server/routes.go b/internal/server/routes.go index 10d7e7c86..02302f17d 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -31,5 +31,5 @@ func (s *Server) registerRoutes(currencyService *service.CurrencyService, userSe r.Delete("/{code}", currencyHandler.RemoveCurrency) }) }) - s.router = router + s.Router = router } diff --git a/internal/server/server.go b/internal/server/server.go index 46d4d3a08..bca0094cc 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -16,7 +16,7 @@ import ( type Server struct { config Config httpServer *http.Server - router http.Handler + Router http.Handler rateUpdater *worker.RateUpdater currencyRepo repository.CurrencyRepository currencyCache cache.Cache @@ -26,15 +26,15 @@ type Server struct { } func NewServer(config Config) (*Server, error) { - repo, err := repository.NewPostgresCurrencyRepository(config.PostgresConn) + repo, err := repository.NewPostgresCurrencyRepository(config.PostgresConn, nil) if err != nil { return nil, fmt.Errorf("failed to initialize repository: %w", err) } - userRepo, err := repository.NewPostgresUserRepository(config.PostgresConn) + userRepo, err := repository.NewPostgresUserRepository(config.PostgresConn, nil) if err != nil { return nil, fmt.Errorf("failed to initialize user repository: %w", err) } - logRepo, err := repository.NewPostgresLogRepository(config.PostgresConn) + logRepo, err := repository.NewPostgresLogRepository(config.PostgresConn, nil) if err != nil { return nil, fmt.Errorf("failed to initialize log repository: %w", err) } @@ -65,7 +65,7 @@ func NewServer(config Config) (*Server, error) { server.httpServer = &http.Server{ Addr: fmt.Sprintf(":%d", config.ServerPort), - Handler: server.router, + Handler: server.Router, IdleTimeout: time.Minute, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, From eb5657fd762dd45ed33cbb3fbcac07a18593f381 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:04:51 -0300 Subject: [PATCH 092/141] feat(sql): expand currency code length to 5 characters This commit introduces a new migration script to expand the length of the currency code in the `currencies` table from 3 to 5 characters. --- sql/schema/005_expand_currency_code.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 sql/schema/005_expand_currency_code.sql diff --git a/sql/schema/005_expand_currency_code.sql b/sql/schema/005_expand_currency_code.sql new file mode 100644 index 000000000..12ce9dda0 --- /dev/null +++ b/sql/schema/005_expand_currency_code.sql @@ -0,0 +1,7 @@ +-- +goose Up +ALTER TABLE currencies +ALTER COLUMN code TYPE CHAR(5); + +-- +goose Down +ALTER TABLE currencies +ALTER COLUMN code TYPE CHAR(3); From 0376e4c9534ee32fcc6f84e4892da533f512f399 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:05:57 -0300 Subject: [PATCH 093/141] refactor(config): add constants for strconv parameters This commit refactors the configuration loading process by introducing constants for the `strconv.ParseUint` parameters, enhancing code readability and maintainability. --- internal/server/config.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/server/config.go b/internal/server/config.go index 7762f0dd7..a139f52f0 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -14,6 +14,11 @@ type Config struct { APIKey string } +const ( + decimalBase = 10 + bitSize = 16 +) + func LoadConfig() (Config, error) { var config Config var errors []string @@ -42,14 +47,13 @@ func LoadConfig() (Config, error) { if serverPort == "" { errors = append(errors, "SERVER_PORT is not set") } else { - parsedServerPort, err := strconv.ParseUint(serverPort, 10, 16) + parsedServerPort, err := strconv.ParseUint(serverPort, decimalBase, bitSize) if err != nil { errors = append(errors, fmt.Sprintf("invalid SERVER_PORT: %s", err)) } else { config.ServerPort = uint16(parsedServerPort) } } - if len(errors) > 0 { for _, err := range errors { fmt.Println("Configuration Error:", err) From ce23e8a0666b9be63e57882ae09f0041fc81163e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:07:31 -0300 Subject: [PATCH 094/141] test(config): add tests for LoadConfig function This commit adds unit tests for the `LoadConfig` function to ensure proper configuration loading and error handling. Changes: - Created `config_test.go` with multiple test cases. - Added tests for valid configuration loading. - Added tests for missing environment variables. - Added tests for invalid `SERVER_PORT` values. - Added tests for partial configuration scenarios --- internal/server/config_test.go | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 internal/server/config_test.go diff --git a/internal/server/config_test.go b/internal/server/config_test.go new file mode 100644 index 000000000..79aa0eff7 --- /dev/null +++ b/internal/server/config_test.go @@ -0,0 +1,76 @@ +package server_test + +import ( + "os" + "strings" + "testing" + + "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/stretchr/testify/assert" +) + +func TestLoadConfig(t *testing.T) { + originalEnv := os.Environ() + defer func() { + os.Clearenv() + for _, pair := range originalEnv { + parts := strings.SplitN(pair, "=", 2) + os.Setenv(parts[0], parts[1]) + } + }() + + setEnv := func(key, value string) { + os.Setenv(key, value) + } + + t.Run("Valid configuration", func(t *testing.T) { + setEnv("REDIS_PASSWORD", "password") + setEnv("REDIS_ADDR", "localhost:6379") + setEnv("POSTGRES_CONN", "postgres://user:pass@localhost:5432/db") + setEnv("API_KEY", "my-api-key") + setEnv("SERVER_PORT", "8080") + + config, err := server.LoadConfig() + + assert.NoError(t, err) + assert.Equal(t, "password", config.RedisPass) + assert.Equal(t, "localhost:6379", config.RedisAddr) + assert.Equal(t, "postgres://user:pass@localhost:5432/db", config.PostgresConn) + assert.Equal(t, "my-api-key", config.APIKey) + assert.Equal(t, uint16(8080), config.ServerPort) + }) + + t.Run("Missing environment variables", func(t *testing.T) { + os.Clearenv() + + _, err := server.LoadConfig() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "configuration errors occurred") + }) + + t.Run("Invalid SERVER_PORT", func(t *testing.T) { + setEnv("REDIS_PASSWORD", "password") + setEnv("REDIS_ADDR", "localhost:6379") + setEnv("POSTGRES_CONN", "postgres://user:pass@localhost:5432/db") + setEnv("API_KEY", "my-api-key") + setEnv("SERVER_PORT", "invalid-port") + + _, err := server.LoadConfig() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "configuration errors occurred") + }) + + t.Run("Partial configuration", func(t *testing.T) { + os.Clearenv() + setEnv("REDIS_PASSWORD", "password") + setEnv("REDIS_ADDR", "localhost:6379") + + _, err := server.LoadConfig() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "configuration errors occurred") + + }) +} From 98f86e11001feb94dcf68a2b5877954548096332 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 17:08:13 -0300 Subject: [PATCH 095/141] test(e2e): add end-to-end tests This commit introduces end-to-end tests for the currency service to ensure the complete workflow is functioning correctly, from user registration and login to currency operations. Changes: - Added `e2e_test.go` to the `tests` directory. - Implemented setup and teardown functions for the test environment. - Created and configured a test database. - Added tests for user registration, login, currency conversion, addition, update, and removal. - Implemented functions to create an admin user and run migrations. --- tests/e2e_test.go | 368 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 tests/e2e_test.go diff --git a/tests/e2e_test.go b/tests/e2e_test.go new file mode 100644 index 000000000..fe318c809 --- /dev/null +++ b/tests/e2e_test.go @@ -0,0 +1,368 @@ +package main + +import ( + "bytes" + "context" + "database/sql" + "encoding/json" + "fmt" + "log" + "net/http" + "net/http/httptest" + "net/url" + "os" + "os/exec" + "path/filepath" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/model" + "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/google/uuid" + "github.com/joho/godotenv" + _ "github.com/lib/pq" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/bcrypt" +) + +var testServer *server.Server +var adminAPIKey string + +func TestMain(m *testing.M) { + // Load the .env file + err := godotenv.Load("../.env") + if err != nil { + log.Fatalf("Error loading .env file: %v", err) + } + + // Setup + err = setup() + if err != nil { + log.Fatalf("Error setting up test environment: %v", err) + } + + // Run tests + code := m.Run() + + // Teardown + err = teardown() + if err != nil { + log.Printf("Error tearing down test environment: %v", err) + } + + os.Exit(code) +} + +func setup() error { + var err error + + // Create test database + err = createTestDatabase() + if err != nil { + return fmt.Errorf("error creating test database: %w", err) + } + + // Run migrations + err = runMigrations() + if err != nil { + return fmt.Errorf("error running migrations: %w", err) + } + + // Seed the database + err = seedDatabase() + if err != nil { + return fmt.Errorf("error seeding database: %w", err) + } + + // Set up the test environment + config, err := server.LoadConfig() + if err != nil { + return fmt.Errorf("failed to load configuration: %w", err) + } + + // Use the test database connection string + config.PostgresConn = os.Getenv("TEST_POSTGRES_CONN") + + // Create a new server instance + testServer, err = server.NewServer(config) + if err != nil { + return fmt.Errorf("failed to create server: %w", err) + } + + return nil +} + +func createTestDatabase() error { + connURL, err := url.Parse(os.Getenv("POSTGRES_CONN")) + if err != nil { + return fmt.Errorf("error parsing database URL: %w", err) + } + + connURL.Path = "/postgres" + db, err := sql.Open("postgres", connURL.String()) + if err != nil { + return fmt.Errorf("error connecting to postgres: %w", err) + } + defer db.Close() + + _, err = db.Exec("CREATE DATABASE test_currency_db") + if err != nil { + return fmt.Errorf("error creating test database: %w", err) + } + + connURL.Path = "/test_currency_db" + testDBConn := connURL.String() + + os.Setenv("TEST_POSTGRES_CONN", testDBConn) + + return nil +} + +func runMigrations() error { + projectRoot, err := filepath.Abs("../") + if err != nil { + return fmt.Errorf("error getting project root path: %w", err) + } + + migrationDir := filepath.Join(projectRoot, "sql", "schema") + + cmd := exec.Command("goose", + "-dir", migrationDir, + "postgres", os.Getenv("TEST_POSTGRES_CONN"), + "up") + + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error running migrations: %w\nOutput: %s", err, string(output)) + } + + log.Printf("Migration output: %s", string(output)) + return nil +} + +func seedDatabase() error { + db, err := sql.Open("postgres", os.Getenv("TEST_POSTGRES_CONN")) + if err != nil { + return err + } + defer db.Close() + + _, err = db.Exec(` + INSERT INTO currencies (code, rate, updated_at) VALUES + ('USD', 1.0, $1), + ('EUR', 0.85, $1), + ('GBP', 0.75, $1) + `, time.Now()) + createAdminUser(context.Background(), db) + return err +} + +func teardown() error { + if testServer != nil { + if err := testServer.Shutdown(); err != nil { + return fmt.Errorf("error shutting down test server: %w", err) + } + } + + connURL, err := url.Parse(os.Getenv("POSTGRES_CONN")) + if err != nil { + return fmt.Errorf("error parsing database URL: %w", err) + } + + connURL.Path = "/postgres" + db, err := sql.Open("postgres", connURL.String()) + if err != nil { + return fmt.Errorf("error connecting to postgres: %w", err) + } + defer db.Close() + + _, err = db.Exec(` + SELECT pg_terminate_backend(pg_stat_activity.pid) + FROM pg_stat_activity + WHERE pg_stat_activity.datname = 'test_currency_db' + AND pid <> pg_backend_pid() + `) + if err != nil { + return fmt.Errorf("error terminating connections to test database: %w", err) + } + + _, err = db.Exec("DROP DATABASE IF EXISTS test_currency_db") + if err != nil { + return fmt.Errorf("error dropping test database: %w", err) + } + + return nil +} + +func setupTestServer(t *testing.T) { + config, err := server.LoadConfig() + require.NoError(t, err, "Failed to load config") + + config.PostgresConn = os.Getenv("TEST_POSTGRES_CONN") + config.RedisAddr = os.Getenv("TEST_REDIS_ADDR") + + testServer, err = server.NewServer(config) + require.NoError(t, err, "Failed to create test server") +} + +func TestEndToEnd(t *testing.T) { + setupTestServer(t) + + var apiKey string + + t.Run("Register User", func(t *testing.T) { + payload := map[string]string{ + "username": "testuser", + "password": "testpassword", + } + body, _ := json.Marshal(payload) + req := httptest.NewRequest("POST", "/auth/register", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusCreated, rr.Code, "Expected status code 201, got %d", rr.Code) + + var response map[string]interface{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "testuser", response["username"]) + assert.NotEmpty(t, response["api_key"]) + apiKey = response["api_key"].(string) + }) + + t.Run("Login User", func(t *testing.T) { + payload := map[string]string{ + "username": "testuser", + "password": "testpassword", + } + body, _ := json.Marshal(payload) + req := httptest.NewRequest("POST", "/auth/login", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code, "Expected status code 200, got %d", rr.Code) + + var response map[string]interface{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "testuser", response["username"]) + assert.NotEmpty(t, response["api_key"]) + }) + + t.Run("Convert Currency", func(t *testing.T) { + req := httptest.NewRequest("GET", "/currency/convert?from=USD&to=EUR&amount=100", nil) + req.Header.Set("X-API-Key", apiKey) + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code, "Expected status code 200, got %d", rr.Code) + + var response map[string]interface{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "USD", response["from"]) + assert.Equal(t, "EUR", response["to"]) + assert.Equal(t, float64(100), response["amount"]) + assert.NotNil(t, response["result"]) + }) + + t.Run("Add Currency", func(t *testing.T) { + payload := map[string]interface{}{ + "code": "GBPT", + "rate_to_usd": 0.75, + } + body, _ := json.Marshal(payload) + req := httptest.NewRequest("POST", "/currency", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-API-Key", adminAPIKey) + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusCreated, rr.Code, "Expected status code 201, got %d", rr.Code) + + var response map[string]string + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "currency added successfully", response["message"]) + }) + + t.Run("Update Currency", func(t *testing.T) { + payload := map[string]interface{}{ + "rate_to_usd": 0.78, + } + body, _ := json.Marshal(payload) + req := httptest.NewRequest("PUT", "/currency/GBPT", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-API-Key", adminAPIKey) + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code, "Expected status code 200, got %d", rr.Code) + + var response map[string]string + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "currency updated successfully", response["message"]) + }) + + t.Run("Remove Currency", func(t *testing.T) { + req := httptest.NewRequest("DELETE", "/currency/GBPT", nil) + req.Header.Set("X-API-Key", adminAPIKey) + + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code, "Expected status code 200, got %d", rr.Code) + + var response map[string]string + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) + + assert.Equal(t, "currency removed successfully", response["message"]) + }) +} +func createAdminUser(ctx context.Context, db *sql.DB) error { + adminAPIKey = generateAPIKey() + adminUser := model.UserDB{ + ID: uuid.New(), + Username: "admin", + Password: "password", + Role: model.RoleAdmin, + APIKey: adminAPIKey, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(adminUser.Password), bcrypt.DefaultCost) + if err != nil { + return fmt.Errorf("error hashing password: %w", err) + } + adminUser.Password = string(hashedPassword) + + _, err = db.ExecContext(ctx, ` + INSERT INTO users (id, username, password, role, api_key, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7) + `, adminUser.ID, adminUser.Username, adminUser.Password, adminUser.Role, adminUser.APIKey, adminUser.CreatedAt, adminUser.UpdatedAt) + + if err != nil { + return fmt.Errorf("error inserting admin user: %w", err) + } + + return nil +} +func generateAPIKey() string { + return uuid.New().String() +} From 250c0403a8fb7a739d60b1eb0a7d3c4ca711aa94 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:18:38 -0300 Subject: [PATCH 096/141] refactor(seed): move seed_test.go from sql to cmd/seed This commit moves seed_test.go from the sql directory to the cmd/seed directory. The sql directory is typically used for SQL migration scripts and related files, while cmd is used for executable commands. As the seed_test.go file is related to seeding the database and should be executable, it makes sense to move it to the cmd/seed directory to follow the conventional Go project structure. --- Dockerfile.migration | 17 +++++++++++++ {sql => cmd/seed}/seed.go | 0 {sql => cmd/seed}/seed_test.go | 0 docker-compose.yml | 44 +++++++++++++++++++++++++++------- run_migrations.sh | 27 +++++++++++++++++++++ 5 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 Dockerfile.migration rename {sql => cmd/seed}/seed.go (100%) rename {sql => cmd/seed}/seed_test.go (100%) create mode 100644 run_migrations.sh diff --git a/Dockerfile.migration b/Dockerfile.migration new file mode 100644 index 000000000..bc82f1cd0 --- /dev/null +++ b/Dockerfile.migration @@ -0,0 +1,17 @@ +FROM golang:1.22 + +WORKDIR /migrations + +RUN go install github.com/pressly/goose/v3/cmd/goose@latest + +RUN apt-get update && apt-get install -y postgresql-client + +COPY ./sql/schema /migrations/ + +COPY run_migrations.sh /migrations/run_migrations.sh + +# Make the script executable +RUN chmod +x /migrations/run_migrations.sh + +# Define the entry point +ENTRYPOINT ["/migrations/run_migrations.sh"] diff --git a/sql/seed.go b/cmd/seed/seed.go similarity index 100% rename from sql/seed.go rename to cmd/seed/seed.go diff --git a/sql/seed_test.go b/cmd/seed/seed_test.go similarity index 100% rename from sql/seed_test.go rename to cmd/seed/seed_test.go diff --git a/docker-compose.yml b/docker-compose.yml index 855f97a3c..e6fb33d09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,26 +1,32 @@ -version: "3.8" - services: app: build: . ports: - - "8081:8080" + - "8080:8080" depends_on: - redis - db + - migrate environment: - - REDIS_PASSWORD=${REDIS_PASSWORD} - - DB_HOST=${POSTGRES_HOST} - - DB_USER=${POSTGRES_USER} - - DB_PASSWORD=${POSTGRES_PASSWORD} - - DB_NAME=${POSTGRES_NAME} - - DB_PORT=5432 + REDIS_PASSWORD: ${REDIS_PASSWORD} + POSTGRES_HOST: db + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_NAME: ${POSTGRES_NAME} + POSTGRES_PORT: ${POSTGRES_PORT} + REDIS_ADDR: redis:${REDIS_PORT} + API_KEY: ${API_KEY} + SERVER_PORT: ${SERVER_PORT} + networks: + - mynetwork redis: image: redis:alpine command: redis-server --requirepass ${REDIS_PASSWORD} ports: - "6379:6379" + networks: + - mynetwork db: image: postgres:alpine @@ -30,3 +36,23 @@ services: POSTGRES_DB: ${POSTGRES_NAME} ports: - "5432:5432" + networks: + - mynetwork + + migrate: + build: + context: . + dockerfile: Dockerfile.migration + environment: + POSTGRES_HOST: db + POSTGRES_PORT: ${POSTGRES_PORT} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_NAME: ${POSTGRES_NAME} + depends_on: + - db + networks: + - mynetwork + +networks: + mynetwork: diff --git a/run_migrations.sh b/run_migrations.sh new file mode 100644 index 000000000..63b85fbf9 --- /dev/null +++ b/run_migrations.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +echo "POSTGRES_HOST: $POSTGRES_HOST" +echo "POSTGRES_PORT: $POSTGRES_PORT" +echo "POSTGRES_USER: $POSTGRES_USER" +echo "POSTGRES_PASSWORD: $POSTGRES_PASSWORD" +echo "POSTGRES_NAME: $POSTGRES_NAME" + +# Wait for the database to be ready +until pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER"; do + echo "Waiting for database to be ready..." + sleep 2 +done + +# Test database connection manually +PGPASSWORD=$POSTGRES_PASSWORD psql -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_NAME" -c '\q' +if [ $? -ne 0 ]; then + echo "Failed to connect to the database" + exit 1 +fi + +# Run Goose migrations +goose -dir /migrations postgres "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_NAME}" up + + +# Clean up and exit +echo "Migrations completed" From 82d9bc288db5ac8f7bbec6dce94b5805c26d78d9 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:21:20 -0300 Subject: [PATCH 097/141] chore(docker): enhance Dockerfile and migration script for streamlined setup This commit improves the Dockerfile and migration script to streamline the build and deployment process. Changes: - Updated `Dockerfile.migration`: - Set `WORKDIR` to `/app`. - Added steps to copy `go.mod` and `go.sum`, download dependencies, and copy the entire project. - Installed PostgreSQL client and Goose. - Compiled the seed command and set appropriate permissions. - Updated `run_migrations.sh`: - Simplified database readiness check. - Changed Goose migrations directory to `/app/migrations`. - Added seeding step after migrations. --- Dockerfile.migration | 25 +++++++++++-------------- run_migrations.sh | 11 +++-------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/Dockerfile.migration b/Dockerfile.migration index bc82f1cd0..5a1957d9d 100644 --- a/Dockerfile.migration +++ b/Dockerfile.migration @@ -1,17 +1,14 @@ FROM golang:1.22 - -WORKDIR /migrations - +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download +COPY . . RUN go install github.com/pressly/goose/v3/cmd/goose@latest - RUN apt-get update && apt-get install -y postgresql-client - -COPY ./sql/schema /migrations/ - -COPY run_migrations.sh /migrations/run_migrations.sh - -# Make the script executable -RUN chmod +x /migrations/run_migrations.sh - -# Define the entry point -ENTRYPOINT ["/migrations/run_migrations.sh"] +COPY ./sql/schema /app/migrations/ +COPY run_migrations.sh /app/ +COPY run_seed.sh /app/ +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o seed cmd/seed/seed.go +RUN chmod +x run_seed.sh +RUN chmod +x run_migrations.sh +ENTRYPOINT ["/app/run_migrations.sh"] diff --git a/run_migrations.sh b/run_migrations.sh index 63b85fbf9..60dd93dde 100644 --- a/run_migrations.sh +++ b/run_migrations.sh @@ -1,27 +1,22 @@ #!/bin/bash - echo "POSTGRES_HOST: $POSTGRES_HOST" echo "POSTGRES_PORT: $POSTGRES_PORT" echo "POSTGRES_USER: $POSTGRES_USER" echo "POSTGRES_PASSWORD: $POSTGRES_PASSWORD" echo "POSTGRES_NAME: $POSTGRES_NAME" -# Wait for the database to be ready until pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER"; do echo "Waiting for database to be ready..." sleep 2 done -# Test database connection manually PGPASSWORD=$POSTGRES_PASSWORD psql -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_NAME" -c '\q' if [ $? -ne 0 ]; then echo "Failed to connect to the database" exit 1 fi -# Run Goose migrations -goose -dir /migrations postgres "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_NAME}" up - +goose -dir /app/migrations postgres "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_NAME}" up +./seed -# Clean up and exit -echo "Migrations completed" +echo "Migrations and seeding completed" From 24c73495627e8b52fabcd5404ff29d33698887e2 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:24:19 -0300 Subject: [PATCH 098/141] chore(docker): optimize app Dockerfile and docker-compose configuration his commit enhances the Dockerfile and docker-compose setup for better efficiency and reliability. Changes: - Updated `Dockerfile`: - Introduced multi-stage build for optimized final image. - Used Alpine for the final stage to reduce image size. - Updated `docker-compose.yml`: - Improved service dependency management with conditions. - Added health checks for PostgreSQL service to ensure readiness before dependent services start. - Set `migrate` service to wait for the database to be healthy before starting. --- Dockerfile | 18 +++++++++++------- docker-compose.yml | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index f68a4aafe..f1ba4ed2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,21 @@ -# Dockerfile -FROM golang:1.22-alpine +FROM golang:1.22 AS builder WORKDIR /app -COPY go.mod . -COPY go.sum . +COPY go.mod go.sum ./ RUN go mod download - COPY . . -RUN go build -o main cmd/main.go +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main cmd/api/main.go + + +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ -EXPOSE 8080 +COPY --from=builder /app/main . CMD ["./main"] diff --git a/docker-compose.yml b/docker-compose.yml index e6fb33d09..af43202a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,9 +4,12 @@ services: ports: - "8080:8080" depends_on: - - redis - - db - - migrate + db: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully environment: REDIS_PASSWORD: ${REDIS_PASSWORD} POSTGRES_HOST: db @@ -36,6 +39,11 @@ services: POSTGRES_DB: ${POSTGRES_NAME} ports: - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_NAME}"] + interval: 10s + timeout: 5s + retries: 5 networks: - mynetwork @@ -50,7 +58,8 @@ services: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_NAME: ${POSTGRES_NAME} depends_on: - - db + db: + condition: service_healthy networks: - mynetwork From 9240db0f21d922985e94eaee29e69675b70eb78e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:25:14 -0300 Subject: [PATCH 099/141] chore(makefile): update test command to run all tests This commit updated the `test` command in the Makefile to run tests across all packages, not just in the `tests` directory. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 45344fbc3..75a1472d0 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ run: # Test the application test: @echo "Testing..." - @go test ./tests -v + @go test ./... -v # Clean the binary clean: From 40f2c870c688294b6cb73208b13743ec34b59896 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:26:11 -0300 Subject: [PATCH 100/141] refactor(tests): change connection string building This commit changes the way connection strings are built in the database creation. This was done because there were some problems with using a pre-made connection string in the docker compose, so the pattern had to be altered all along the application. Unecessary comments were also removed --- tests/e2e_test.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index fe318c809..4c834bd36 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -30,22 +30,18 @@ var testServer *server.Server var adminAPIKey string func TestMain(m *testing.M) { - // Load the .env file err := godotenv.Load("../.env") if err != nil { log.Fatalf("Error loading .env file: %v", err) } - // Setup err = setup() if err != nil { log.Fatalf("Error setting up test environment: %v", err) } - // Run tests code := m.Run() - // Teardown err = teardown() if err != nil { log.Printf("Error tearing down test environment: %v", err) @@ -57,34 +53,28 @@ func TestMain(m *testing.M) { func setup() error { var err error - // Create test database err = createTestDatabase() if err != nil { return fmt.Errorf("error creating test database: %w", err) } - // Run migrations err = runMigrations() if err != nil { return fmt.Errorf("error running migrations: %w", err) } - // Seed the database err = seedDatabase() if err != nil { return fmt.Errorf("error seeding database: %w", err) } - // Set up the test environment config, err := server.LoadConfig() if err != nil { return fmt.Errorf("failed to load configuration: %w", err) } - // Use the test database connection string config.PostgresConn = os.Getenv("TEST_POSTGRES_CONN") - // Create a new server instance testServer, err = server.NewServer(config) if err != nil { return fmt.Errorf("failed to create server: %w", err) @@ -94,7 +84,12 @@ func setup() error { } func createTestDatabase() error { - connURL, err := url.Parse(os.Getenv("POSTGRES_CONN")) + pg_host := os.Getenv("POSTGRES_HOST") + pg_port := os.Getenv("POSTGRES_PORT") + pg_user := os.Getenv("POSTGRES_USER") + pg_pass := os.Getenv("POSTGRES_PASSWORD") + pg_db := os.Getenv("POSTGRES_NAME") + connURL, err := url.Parse(fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pg_user, pg_pass, pg_host, pg_port, pg_db)) if err != nil { return fmt.Errorf("error parsing database URL: %w", err) } From e517518d517f49ebb4a26fd43f1d2dec54b43585 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:28:42 -0300 Subject: [PATCH 101/141] refactor(config): split PostgreSQL connection string into individual environment variables Improved configuration loading by separating PostgreSQL connection string into individual environment variables (user, password, host, port, and database name). --- internal/server/config.go | 27 ++++++++++++++++++++++++--- internal/server/config_test.go | 15 +++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/internal/server/config.go b/internal/server/config.go index a139f52f0..95782b193 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -33,11 +33,32 @@ func LoadConfig() (Config, error) { errors = append(errors, "REDIS_ADDR is not set") } - config.PostgresConn = os.Getenv("POSTGRES_CONN") - if config.PostgresConn == "" { - errors = append(errors, "POSTGRES_CONN is not set") + pg_user := os.Getenv("POSTGRES_USER") + if pg_user == "" { + errors = append(errors, "POSTGRES_USER is not set") } + pg_pass := os.Getenv("POSTGRES_PASSWORD") + if pg_pass == "" { + errors = append(errors, "POSTGRES_PASSWORD is not set") + } + + pg_host := os.Getenv("POSTGRES_HOST") + if pg_host == "" { + errors = append(errors, "POSTGRES_HOST is not set") + } + pg_port := os.Getenv("POSTGRES_PORT") + if pg_port == "" { + errors = append(errors, "POSTGRES_PORT is not set") + } + + pg_db := os.Getenv("POSTGRES_NAME") + if pg_db == "" { + errors = append(errors, "POSTGRES_NAME is not set") + } + + config.PostgresConn = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pg_user, pg_pass, pg_host, pg_port, pg_db) + config.APIKey = os.Getenv("API_KEY") if config.APIKey == "" { errors = append(errors, "API_KEY is not set") diff --git a/internal/server/config_test.go b/internal/server/config_test.go index 79aa0eff7..35f744d2e 100644 --- a/internal/server/config_test.go +++ b/internal/server/config_test.go @@ -26,7 +26,11 @@ func TestLoadConfig(t *testing.T) { t.Run("Valid configuration", func(t *testing.T) { setEnv("REDIS_PASSWORD", "password") setEnv("REDIS_ADDR", "localhost:6379") - setEnv("POSTGRES_CONN", "postgres://user:pass@localhost:5432/db") + setEnv("POSTGRES_USER", "user") + setEnv("POSTGRES_PASSWORD", "pass") + setEnv("POSTGRES_HOST", "localhost") + setEnv("POSTGRES_PORT", "5432") + setEnv("POSTGRES_NAME", "db") setEnv("API_KEY", "my-api-key") setEnv("SERVER_PORT", "8080") @@ -35,7 +39,7 @@ func TestLoadConfig(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "password", config.RedisPass) assert.Equal(t, "localhost:6379", config.RedisAddr) - assert.Equal(t, "postgres://user:pass@localhost:5432/db", config.PostgresConn) + assert.Equal(t, "postgres://user:pass@localhost:5432/db?sslmode=disable", config.PostgresConn) assert.Equal(t, "my-api-key", config.APIKey) assert.Equal(t, uint16(8080), config.ServerPort) }) @@ -52,7 +56,11 @@ func TestLoadConfig(t *testing.T) { t.Run("Invalid SERVER_PORT", func(t *testing.T) { setEnv("REDIS_PASSWORD", "password") setEnv("REDIS_ADDR", "localhost:6379") - setEnv("POSTGRES_CONN", "postgres://user:pass@localhost:5432/db") + setEnv("POSTGRES_USER", "user") + setEnv("POSTGRES_PASSWORD", "pass") + setEnv("POSTGRES_HOST", "localhost") + setEnv("POSTGRES_PORT", "5432") + setEnv("POSTGRES_NAME", "db") setEnv("API_KEY", "my-api-key") setEnv("SERVER_PORT", "invalid-port") @@ -71,6 +79,5 @@ func TestLoadConfig(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "configuration errors occurred") - }) } From fa1b02a41255cabe216acafccbc32cc8ebc97faa Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:29:16 -0300 Subject: [PATCH 102/141] refactor(pg_currency_repository): remove debug print statement Removed an unnecessary debug print statement from the `NewPostgresCurrencyRepository` function. --- internal/repository/pg_currency_repository.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/repository/pg_currency_repository.go b/internal/repository/pg_currency_repository.go index acee18a93..18b76ae34 100644 --- a/internal/repository/pg_currency_repository.go +++ b/internal/repository/pg_currency_repository.go @@ -15,7 +15,6 @@ type PostgresCurrencyRepository struct { func NewPostgresCurrencyRepository(connURL string, db *sql.DB) (*PostgresCurrencyRepository, error) { if db == nil { - fmt.Println("shouldn't be here") var err error db, err = sql.Open("postgres", connURL) if err != nil { From 9902b0f89bece6d38750444edf1b8ef83b97acfc Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:30:14 -0300 Subject: [PATCH 103/141] docs(entity-map): add entity map diagram Added the entity map diagram in two formats: - PNG image (`entity-map.png`) - Mermaid file (`entity-map.mermaid`) --- docs/entity-map/entity-map.mermaid | 44 +++++++++++++++++++++++++++++ docs/entity-map/entity-map.png | Bin 0 -> 75374 bytes 2 files changed, 44 insertions(+) create mode 100644 docs/entity-map/entity-map.mermaid create mode 100644 docs/entity-map/entity-map.png diff --git a/docs/entity-map/entity-map.mermaid b/docs/entity-map/entity-map.mermaid new file mode 100644 index 000000000..3612e62e6 --- /dev/null +++ b/docs/entity-map/entity-map.mermaid @@ -0,0 +1,44 @@ +classDiagram + class Currency { + +string Code + +float64 Rate + +time.Time UpdatedAt + +uuid.UUID CreatedBy + +uuid.UUID UpdatedBy + +time.Time CreatedAt + } + + class ExchangeRates { + +int64 Timestamp + +string Base + +map[string]float64 Rates + } + + class UserDB { + +uuid.UUID ID + +string Username + +string Password + +Role Role + +string APIKey + +time.Time CreatedAt + +time.Time UpdatedAt + } + + class User { + +uuid.UUID ID + +string Username + +Role Role + +string APIKey + } + + class Log { + +uuid.UUID ID + +LogLevel Level + +string Message + +time.Time Timestamp + +string Source + } + + UserDB --|> User : ToUser() + User -- Currency : CreatedBy/UpdatedBy + Currency -- ExchangeRates : Rates diff --git a/docs/entity-map/entity-map.png b/docs/entity-map/entity-map.png new file mode 100644 index 0000000000000000000000000000000000000000..4d189bd2fd9d103606a1df2a1884a907480129aa GIT binary patch literal 75374 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

PC3~hi&cAthzS|~Z4b|c%FaQ-CpILsrt~;H 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 aFfjJy!aJJG9Tz9y%W~OjX0Dmbk$(XLL1KIW literal 0 HcmV?d00001 From 02a8ccfee57b0dbe143e89c2b5c76043e97d0072 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Wed, 7 Aug 2024 21:31:09 -0300 Subject: [PATCH 104/141] docs(c4): add C4 model diagram Added the C4 model diagram in two formats: - PNG image (`c4-model.png`) - Mermaid file (`c4-model.mermaid`) --- docs/c4/c4-model.mermaid | 50 +++++++++++++++++++++++++++++++++++++++ docs/c4/c4-model.png | Bin 0 -> 119371 bytes 2 files changed, 50 insertions(+) create mode 100644 docs/c4/c4-model.mermaid create mode 100644 docs/c4/c4-model.png diff --git a/docs/c4/c4-model.mermaid b/docs/c4/c4-model.mermaid new file mode 100644 index 000000000..b28f509e1 --- /dev/null +++ b/docs/c4/c4-model.mermaid @@ -0,0 +1,50 @@ +graph TB + subgraph "System Context" + U["User"] + A["Admin"] + E["External Exchange Rate API"] + CES["Currency Exchange System"] + end + + U -->|"Uses"| CES + A -->|"Manages"| CES + E -->|"Provides rates"| CES + + subgraph "Container" + API["API Application"] + DB["PostgreSQL Database"] + Cache["Redis Cache"] + Worker["Rate Updater Worker"] + end + + CES -->|"Contains"| API + CES -->|"Contains"| DB + CES -->|"Contains"| Cache + CES -->|"Contains"| Worker + + API -->|"Reads/Writes"| DB + API -->|"Reads/Writes"| Cache + Worker -->|"Updates"| DB + Worker -->|"Updates"| Cache + Worker -->|"Fetches rates"| E + + subgraph "Component" + H["Handlers"] + S["Services"] + R["Repositories"] + M["Middleware"] + L["Logger"] + end + + API -->|"Contains"| H + API -->|"Contains"| S + API -->|"Contains"| R + API -->|"Contains"| M + API -->|"Contains"| L + + H -->|"Uses"| S + S -->|"Uses"| R + H -->|"Uses"| M + S -->|"Uses"| L + R -->|"Interacts with"| DB + R -->|"Interacts with"| Cache diff --git a/docs/c4/c4-model.png b/docs/c4/c4-model.png new file mode 100644 index 0000000000000000000000000000000000000000..2bb778f4fd1ea619f22b8651ab8741afd579bc8c GIT binary patch literal 119371 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 j8`q;>c%ZIrecQH;STD1 Date: Wed, 7 Aug 2024 21:58:09 -0300 Subject: [PATCH 105/141] fix(Dockerfile.migration): remove run_seed.sh and related commands Removed the `run_seed.sh` file and related commands from the Dockerfile.migration to streamline the migration process. --- Dockerfile.migration | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dockerfile.migration b/Dockerfile.migration index 5a1957d9d..230ac41cc 100644 --- a/Dockerfile.migration +++ b/Dockerfile.migration @@ -7,8 +7,6 @@ RUN go install github.com/pressly/goose/v3/cmd/goose@latest RUN apt-get update && apt-get install -y postgresql-client COPY ./sql/schema /app/migrations/ COPY run_migrations.sh /app/ -COPY run_seed.sh /app/ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o seed cmd/seed/seed.go -RUN chmod +x run_seed.sh RUN chmod +x run_migrations.sh ENTRYPOINT ["/app/run_migrations.sh"] From 06e9841d491e79c62782686386b91cf7ebd307b1 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 09:30:19 -0300 Subject: [PATCH 106/141] refactor(service): update error handling for currency not found Updated the `getRate` method in `currency_service.go` to wrap the `ErrCurrencyNotFound` error for more descriptive error messages. Changes: - Updated `getRate` method in `currency_service.go` to wrap the `ErrCurrencyNotFound` error with the specific currency code. - Improved error assertions in `currency_service_test.go` to check for specific error types and messages when currencies are not found. --- internal/service/currency_service.go | 2 +- internal/service/currency_service_test.go | 31 +++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 6e5cfdaec..2c3bbe443 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -60,7 +60,7 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er rate, ok := rates.Rates[code] if !ok { - return 0, fmt.Errorf("currency %s not found", code) + return 0, fmt.Errorf("%w: %s", model.ErrCurrencyNotFound, code) } currency = &model.Currency{ Code: strings.ToUpper(code), diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go index d680b0ba0..d9f004423 100644 --- a/internal/service/currency_service_test.go +++ b/internal/service/currency_service_test.go @@ -107,29 +107,32 @@ func TestCurrencyService_Convert(t *testing.T) { to string amount float64 expected float64 - expectedError bool + expectedError error }{ - {"USD to EUR", "USD", "EUR", 100, 85, false}, - {"EUR to USD", "EUR", "USD", 85, 100, false}, - {"USD to GBP", "USD", "GBP", 100, 75, false}, - {"Invalid currency", "USD", "XYZ", 100, 0, true}, + {"USD to EUR", "USD", "EUR", 100, 85, nil}, + {"EUR to USD", "EUR", "USD", 85, 100, nil}, + {"USD to GBP", "USD", "GBP", 100, 75, nil}, + {"From currency not found", "XYZ", "USD", 100, 0, model.ErrCurrencyNotFound}, + {"To currency not found", "USD", "XYZ", 100, 0, model.ErrCurrencyNotFound}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := currencyService.Convert(context.Background(), tt.from, tt.to, tt.amount) - if tt.expectedError { - if err == nil { - t.Errorf("Expected an error, but got none") + if tt.expectedError != nil { + assert.Error(t, err) + assert.True(t, errors.Is(err, tt.expectedError), "Expected error %v, but got %v", tt.expectedError, err) + if tt.expectedError == model.ErrCurrencyNotFound { + if tt.from == "XYZ" { + assert.Contains(t, err.Error(), tt.from, "Error should contain the 'from' currency code") + } else { + assert.Contains(t, err.Error(), tt.to, "Error should contain the 'to' currency code") + } } } else { - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if result != tt.expected { - t.Errorf("Expected %f, but got %f", tt.expected, result) - } + assert.NoError(t, err) + assert.InDelta(t, tt.expected, result, 0.001, "Expected %f, but got %f", tt.expected, result) } }) } From a220e590eb4a4088fb0b734b8cbbec88e9eb32e0 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 09:32:10 -0300 Subject: [PATCH 107/141] feat(handler): improve error handling and improve tests for currency conversion This commit enhances the error handling in the ConvertCurrency function by returning specific errors when a currency is not found. It also adds unit tests to cover these new error cases. --- internal/handler/currency_handler.go | 7 ++++++- internal/handler/currency_handler_test.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/handler/currency_handler.go b/internal/handler/currency_handler.go index d55ebc1b9..03e3437bc 100644 --- a/internal/handler/currency_handler.go +++ b/internal/handler/currency_handler.go @@ -2,6 +2,7 @@ package handler import ( "encoding/json" + "errors" "fmt" "net/http" "strconv" @@ -55,7 +56,11 @@ func (h *CurrencyHandler) ConvertCurrency(w http.ResponseWriter, r *http.Request result, err := h.currencyService.Convert(r.Context(), from, to, amount) if err != nil { - commons.RespondWithError(w, http.StatusInternalServerError, "conversion failed") + if errors.Is(err, model.ErrCurrencyNotFound) { + commons.RespondWithError(w, http.StatusNotFound, err.Error()) + } else { + commons.RespondWithError(w, http.StatusInternalServerError, "conversion failed") + } return } diff --git a/internal/handler/currency_handler_test.go b/internal/handler/currency_handler_test.go index f724923f8..853996f84 100644 --- a/internal/handler/currency_handler_test.go +++ b/internal/handler/currency_handler_test.go @@ -94,6 +94,28 @@ func TestConvertCurrency(t *testing.T) { expectedBody: `{"error":"invalid amount"}`, mockBehavior: func() {}, }, + { + name: "From currency not found", + from: "XYZ", + to: "EUR", + amount: "100.00", + expectedStatus: http.StatusNotFound, + expectedBody: `{"error":"currency not found: XYZ"}`, + mockBehavior: func() { + mockService.On("Convert", mock.Anything, "XYZ", "EUR", 100.0).Return(0.0, fmt.Errorf("%w: XYZ", model.ErrCurrencyNotFound)).Once() + }, + }, + { + name: "To currency not found", + from: "USD", + to: "XYZ", + amount: "100.00", + expectedStatus: http.StatusNotFound, + expectedBody: `{"error":"currency not found: XYZ"}`, + mockBehavior: func() { + mockService.On("Convert", mock.Anything, "USD", "XYZ", 100.0).Return(0.0, fmt.Errorf("%w: XYZ", model.ErrCurrencyNotFound)).Once() + }, + }, } for _, tt := range tests { From 3170eaa02938ad6398d58bb5003bd300890d9e2c Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 09:34:27 -0300 Subject: [PATCH 108/141] test(e2e): enhance end-to-end tests for currency conversion This commit adds multiple test cases to the Convert Currency endpoint in the end-to-end tests. It includes tests for valid conversions and scenarios where the source or target currency is not found. --- tests/e2e_test.go | 74 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 4c834bd36..c4f4acdb0 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -252,22 +252,72 @@ func TestEndToEnd(t *testing.T) { }) t.Run("Convert Currency", func(t *testing.T) { - req := httptest.NewRequest("GET", "/currency/convert?from=USD&to=EUR&amount=100", nil) - req.Header.Set("X-API-Key", apiKey) + testCases := []struct { + name string + from string + to string + amount string + expectedStatus int + expectedBody map[string]interface{} + }{ + { + name: "Valid conversion", + from: "USD", + to: "EUR", + amount: "100", + expectedStatus: http.StatusOK, + expectedBody: map[string]interface{}{ + "from": "USD", + "to": "EUR", + "amount": float64(100), + }, + }, + { + name: "From currency not found", + from: "XYZ", + to: "EUR", + amount: "100", + expectedStatus: http.StatusNotFound, + expectedBody: map[string]interface{}{ + "error": "currency not found: XYZ", + }, + }, + { + name: "To currency not found", + from: "USD", + to: "XYZ", + amount: "100", + expectedStatus: http.StatusNotFound, + expectedBody: map[string]interface{}{ + "error": "currency not found: XYZ", + }, + }, + } - rr := httptest.NewRecorder() - testServer.Router.ServeHTTP(rr, req) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + url := fmt.Sprintf("/currency/convert?from=%s&to=%s&amount=%s", tc.from, tc.to, tc.amount) + req := httptest.NewRequest("GET", url, nil) + req.Header.Set("X-API-Key", apiKey) - assert.Equal(t, http.StatusOK, rr.Code, "Expected status code 200, got %d", rr.Code) + rr := httptest.NewRecorder() + testServer.Router.ServeHTTP(rr, req) - var response map[string]interface{} - err := json.Unmarshal(rr.Body.Bytes(), &response) - require.NoError(t, err) + assert.Equal(t, tc.expectedStatus, rr.Code, "Expected status code %d, got %d", tc.expectedStatus, rr.Code) + + var response map[string]interface{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + require.NoError(t, err) - assert.Equal(t, "USD", response["from"]) - assert.Equal(t, "EUR", response["to"]) - assert.Equal(t, float64(100), response["amount"]) - assert.NotNil(t, response["result"]) + for key, expectedValue := range tc.expectedBody { + assert.Equal(t, expectedValue, response[key], "For key '%s', expected %v, got %v", key, expectedValue, response[key]) + } + + if tc.expectedStatus == http.StatusOK { + assert.NotNil(t, response["result"], "Result should not be nil for successful conversion") + } + }) + } }) t.Run("Add Currency", func(t *testing.T) { From caed2834de47b67554bb7a6ba80917da5e4e3fd4 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 09:41:40 -0300 Subject: [PATCH 109/141] refactor(routes): update routes to include versioning and adjust e2e tests This commit updates the API routes to include versioning under '/api/v1' for better version control and clarity. It also adjusts the end-to-end tests to reflect these changes and enhances the database connection setup by constructing the PostgreSQL connection string from individual environment variables. --- internal/server/routes.go | 26 ++++++++++++++------------ tests/e2e_test.go | 19 ++++++++++++------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/internal/server/routes.go b/internal/server/routes.go index 02302f17d..85d568cd6 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -17,18 +17,20 @@ func (s *Server) registerRoutes(currencyService *service.CurrencyService, userSe router.Get("/healthz", handler.HandlerReadiness) currencyHandler := handler.NewCurrencyHandler(currencyService) userHandler := handler.NewUserHandler(userService) - router.Route("/auth", func(r chi.Router) { - r.With(api_middleware.RateLimitMiddleware).Post("/register", userHandler.Register) - r.With(api_middleware.RateLimitMiddleware).Post("/login", userHandler.Login) - }) - router.Route("/currency", func(r chi.Router) { - r.Get("/convert", currencyHandler.ConvertCurrency) - r.Group(func(r chi.Router) { - r.Use(authMiddleware.Authenticate) - r.Use(api_middleware.RequireRole(model.RoleAdmin)) - r.Post("/", currencyHandler.AddCurrency) - r.Put("/{code}", currencyHandler.UpdateCurrency) - r.Delete("/{code}", currencyHandler.RemoveCurrency) + router.Route("/api/v1", func(r chi.Router) { + r.Route("/auth", func(r chi.Router) { + r.With(api_middleware.RateLimitMiddleware).Post("/register", userHandler.Register) + r.With(api_middleware.RateLimitMiddleware).Post("/login", userHandler.Login) + }) + r.Route("/currency", func(r chi.Router) { + r.Get("/convert", currencyHandler.ConvertCurrency) + r.Group(func(r chi.Router) { + r.Use(authMiddleware.Authenticate) + r.Use(api_middleware.RequireRole(model.RoleAdmin)) + r.Post("/", currencyHandler.AddCurrency) + r.Put("/{code}", currencyHandler.UpdateCurrency) + r.Delete("/{code}", currencyHandler.RemoveCurrency) + }) }) }) s.Router = router diff --git a/tests/e2e_test.go b/tests/e2e_test.go index c4f4acdb0..0c49bdafa 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -160,7 +160,12 @@ func teardown() error { } } - connURL, err := url.Parse(os.Getenv("POSTGRES_CONN")) + pg_host := os.Getenv("POSTGRES_HOST") + pg_port := os.Getenv("POSTGRES_PORT") + pg_user := os.Getenv("POSTGRES_USER") + pg_pass := os.Getenv("POSTGRES_PASSWORD") + pg_db := os.Getenv("POSTGRES_NAME") + connURL, err := url.Parse(fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pg_user, pg_pass, pg_host, pg_port, pg_db)) if err != nil { return fmt.Errorf("error parsing database URL: %w", err) } @@ -212,7 +217,7 @@ func TestEndToEnd(t *testing.T) { "password": "testpassword", } body, _ := json.Marshal(payload) - req := httptest.NewRequest("POST", "/auth/register", bytes.NewBuffer(body)) + req := httptest.NewRequest("POST", "/api/v1/auth/register", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() @@ -235,7 +240,7 @@ func TestEndToEnd(t *testing.T) { "password": "testpassword", } body, _ := json.Marshal(payload) - req := httptest.NewRequest("POST", "/auth/login", bytes.NewBuffer(body)) + req := httptest.NewRequest("POST", "/api/v1/auth/login", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() @@ -296,7 +301,7 @@ func TestEndToEnd(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - url := fmt.Sprintf("/currency/convert?from=%s&to=%s&amount=%s", tc.from, tc.to, tc.amount) + url := fmt.Sprintf("/api/v1/currency/convert?from=%s&to=%s&amount=%s", tc.from, tc.to, tc.amount) req := httptest.NewRequest("GET", url, nil) req.Header.Set("X-API-Key", apiKey) @@ -326,7 +331,7 @@ func TestEndToEnd(t *testing.T) { "rate_to_usd": 0.75, } body, _ := json.Marshal(payload) - req := httptest.NewRequest("POST", "/currency", bytes.NewBuffer(body)) + req := httptest.NewRequest("POST", "/api/v1/currency", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", adminAPIKey) @@ -347,7 +352,7 @@ func TestEndToEnd(t *testing.T) { "rate_to_usd": 0.78, } body, _ := json.Marshal(payload) - req := httptest.NewRequest("PUT", "/currency/GBPT", bytes.NewBuffer(body)) + req := httptest.NewRequest("PUT", "/api/v1/currency/GBPT", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", adminAPIKey) @@ -364,7 +369,7 @@ func TestEndToEnd(t *testing.T) { }) t.Run("Remove Currency", func(t *testing.T) { - req := httptest.NewRequest("DELETE", "/currency/GBPT", nil) + req := httptest.NewRequest("DELETE", "/api/v1/currency/GBPT", nil) req.Header.Set("X-API-Key", adminAPIKey) rr := httptest.NewRecorder() From daa906d0fac1ea42bde3d23a2049c38f47a6609b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 09:57:06 -0300 Subject: [PATCH 110/141] refactor(constants): centralize and use common constants across modules This commit centralizes various constants into the commons package and updates server, external API client, and rate updater modules to use these constants. --- internal/commons/constants.go | 17 +++++++++++++---- internal/server/server.go | 7 ++++--- internal/worker/external_api_client.go | 7 ++++--- internal/worker/external_api_client_test.go | 7 ++++--- internal/worker/rate_updater.go | 3 ++- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/internal/commons/constants.go b/internal/commons/constants.go index 13233b5ee..67ba1508f 100644 --- a/internal/commons/constants.go +++ b/internal/commons/constants.go @@ -1,8 +1,17 @@ package commons +import "time" + const ( - AllowedCurrencyLength = 5 - MinimumCurrencyLength = 3 - UserContextKey = "user" - AllowedRPS = 10 + AllowedCurrencyLength = 5 + MinimumCurrencyLength = 3 + UserContextKey = "user" + AllowedRPS = 10 + ExternalClientMaxRetries = 3 + ExternalClientBaseDelay = time.Second + ExternalClientMaxDelay = 30 * time.Second + RateUpdaterCacheExipiration = 1 * time.Hour + ServerIdleTimeout = time.Minute + ServerReadTimeout = 10 * time.Second + ServerWriteTimeout = 30 * time.Second ) diff --git a/internal/server/server.go b/internal/server/server.go index bca0094cc..f8d21dd4c 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -7,6 +7,7 @@ import ( "time" "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/repository" "github.com/Lutefd/challenge-bravo/internal/service" @@ -66,9 +67,9 @@ func NewServer(config Config) (*Server, error) { server.httpServer = &http.Server{ Addr: fmt.Sprintf(":%d", config.ServerPort), Handler: server.Router, - IdleTimeout: time.Minute, - ReadTimeout: 10 * time.Second, - WriteTimeout: 30 * time.Second, + IdleTimeout: commons.ServerIdleTimeout, + ReadTimeout: commons.ServerReadTimeout, + WriteTimeout: commons.ServerWriteTimeout, } return server, nil diff --git a/internal/worker/external_api_client.go b/internal/worker/external_api_client.go index a0c375a10..d6a7d3ef0 100644 --- a/internal/worker/external_api_client.go +++ b/internal/worker/external_api_client.go @@ -9,6 +9,7 @@ import ( "net/http" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/model" ) @@ -47,9 +48,9 @@ func NewOpenExchangeRatesClient(apiKey string, options ...OpenExchangeRatesClien apiKey: apiKey, client: &http.Client{}, baseURL: "https://openexchangerates.org/api", - maxRetries: 3, - baseDelay: time.Second, - maxDelay: 30 * time.Second, + maxRetries: commons.ExternalClientMaxRetries, + baseDelay: commons.ExternalClientBaseDelay, + maxDelay: commons.ExternalClientMaxDelay, } for _, option := range options { diff --git a/internal/worker/external_api_client_test.go b/internal/worker/external_api_client_test.go index 2756d6ae8..1173b81d7 100644 --- a/internal/worker/external_api_client_test.go +++ b/internal/worker/external_api_client_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/stretchr/testify/assert" ) @@ -16,9 +17,9 @@ func TestNewOpenExchangeRatesClient(t *testing.T) { client := NewOpenExchangeRatesClient(apiKey) assert.Equal(t, apiKey, client.apiKey) - assert.Equal(t, 3, client.maxRetries) - assert.Equal(t, time.Second, client.baseDelay) - assert.Equal(t, 30*time.Second, client.maxDelay) + assert.Equal(t, commons.ExternalClientMaxRetries, client.maxRetries) + assert.Equal(t, commons.ExternalClientBaseDelay, client.baseDelay) + assert.Equal(t, commons.ExternalClientMaxDelay, client.maxDelay) customClient := NewOpenExchangeRatesClient( apiKey, diff --git a/internal/worker/rate_updater.go b/internal/worker/rate_updater.go index 84018a1f6..40115f693 100644 --- a/internal/worker/rate_updater.go +++ b/internal/worker/rate_updater.go @@ -7,6 +7,7 @@ import ( "time" "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" ) @@ -104,7 +105,7 @@ func (ru *RateUpdater) populateRates(ctx context.Context) error { continue } } - if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { + if err := ru.cache.Set(ctx, code, rate, commons.RateUpdaterCacheExipiration); err != nil { log.Printf("failed to update currency %s in cache: %v", code, err) } } From e4aea172331cb4529f7883259c891e1734ea119b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 12:06:19 -0300 Subject: [PATCH 111/141] docs(swagger): add Swagger documentation for currency conversion API This commit adds a Swagger YAML file to document the currency conversion API. It includes endpoints for currency conversion, user registration, and login. The server routes are updated to serve the Swagger documentation as HTML using the go-scalar-api-reference package. --- docs/swagger/v1/swagger.yaml | 349 +++++++++++++++++++++++++++++++++++ internal/server/routes.go | 19 ++ 2 files changed, 368 insertions(+) create mode 100644 docs/swagger/v1/swagger.yaml diff --git a/docs/swagger/v1/swagger.yaml b/docs/swagger/v1/swagger.yaml new file mode 100644 index 000000000..5cfeea18a --- /dev/null +++ b/docs/swagger/v1/swagger.yaml @@ -0,0 +1,349 @@ +openapi: 3.0.0 +info: + title: Bravo Currency Conversion API + version: 1.0.0 + description: Currency conversion API currency service made by Luis Dourado for the Hurb Bravo Challenge + +servers: + - url: http://localhost:8080/api/v1 + +paths: + /currency/convert: + get: + summary: Convert currency + description: Convert an amount from one currency to another + tags: + - Currency + parameters: + - name: from + in: query + required: true + example: "USD" + schema: + type: string + - name: to + in: query + example: "BRL" + required: true + schema: + type: string + - name: amount + in: query + example: 100 + required: true + schema: + type: number + responses: + "200": + description: Successful conversion + content: + application/json: + schema: + type: object + properties: + from: + type: string + to: + type: string + amount: + type: number + result: + type: number + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "404": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Currency not found + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + + /currency: + post: + summary: Add a new currency + description: Add a new currency to the system + tags: + - Currency + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CurrencyInput" + responses: + "201": + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: Currency added successfully + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + /currency/{code}: + put: + summary: Update a currency + description: Update the rate of an existing currency + tags: + - Currency + security: + - ApiKeyAuth: [] + parameters: + - name: code + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CurrencyInput" + responses: + "200": + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: Currency updated successfully + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "404": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Currency not found + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + + delete: + summary: Remove a currency + description: Remove an existing currency from the system + tags: + - Currency + security: + - ApiKeyAuth: [] + parameters: + - name: code + in: path + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: Currency removed successfully + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + + /auth/register: + post: + summary: Register a new user + description: Register a new user in the system + tags: + - Auth + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UserRegistration" + responses: + "201": + description: User created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/User" + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + + /auth/login: + post: + summary: User login + description: Authenticate a user and return an API key + tags: + - Auth + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UserLogin" + responses: + "200": + description: Successful login + content: + application/json: + schema: + $ref: "#/components/schemas/User" + "400": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Bad request + "401": + description: Invalid credentials + "500": + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Internal server error + +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + + schemas: + CurrencyInput: + type: object + properties: + code: + type: string + example: "USD" + rate_to_usd: + type: number + example: 1.0 + + UserRegistration: + type: object + properties: + username: + type: string + example: "username" + password: + type: string + example: "password" + + UserLogin: + type: object + properties: + username: + type: string + example: "username" + password: + type: string + example: "password" + + User: + type: object + properties: + id: + type: string + format: uuid + username: + type: string + role: + type: string + api_key: + type: string diff --git a/internal/server/routes.go b/internal/server/routes.go index 85d568cd6..94b7803dc 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -1,10 +1,14 @@ package server import ( + "fmt" + "net/http" + "github.com/Lutefd/challenge-bravo/internal/handler" api_middleware "github.com/Lutefd/challenge-bravo/internal/middleware" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/service" + "github.com/MarceloPetrucio/go-scalar-api-reference" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) @@ -15,6 +19,7 @@ func (s *Server) registerRoutes(currencyService *service.CurrencyService, userSe authMiddleware := api_middleware.NewAuthMiddleware(s.userRepo) router.Get("/healthz", handler.HandlerReadiness) + currencyHandler := handler.NewCurrencyHandler(currencyService) userHandler := handler.NewUserHandler(userService) router.Route("/api/v1", func(r chi.Router) { @@ -32,6 +37,20 @@ func (s *Server) registerRoutes(currencyService *service.CurrencyService, userSe r.Delete("/{code}", currencyHandler.RemoveCurrency) }) }) + r.Get("/reference", func(w http.ResponseWriter, r *http.Request) { + htmlContent, err := scalar.ApiReferenceHTML(&scalar.Options{ + SpecURL: "./docs/swagger/v1/swagger.yaml", + CustomOptions: scalar.CustomOptions{ + PageTitle: "Currency Exchange API Reference", + }, + DarkMode: true, + }) + + if err != nil { + fmt.Printf("%v", err) + } + fmt.Fprintln(w, htmlContent) + }) }) s.Router = router } From 9dc81b93b1e5b00f3cebe225df3731b3b1329c12 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 12:08:28 -0300 Subject: [PATCH 112/141] chore(dependencies): add go-scalar-api-reference module This commit updates the go.mod file to include the go-scalar-api-reference module for serving the Swagger API documentation as HTML. --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 57c4d98c8..26ef6b152 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( require ( github.com/DATA-DOG/go-sqlmock v1.5.2 + github.com/MarceloPetrucio/go-scalar-api-reference v0.0.0-20240521013641-ce5d2efe0e06 github.com/alicebob/miniredis/v2 v2.33.0 github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 diff --git a/go.sum b/go.sum index bae7da6b3..0520545d3 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/MarceloPetrucio/go-scalar-api-reference v0.0.0-20240521013641-ce5d2efe0e06 h1:W4Yar1SUsPmmA51qoIRb174uDO/Xt3C48MB1YX9Y3vM= +github.com/MarceloPetrucio/go-scalar-api-reference v0.0.0-20240521013641-ce5d2efe0e06/go.mod h1:/wotfjM8I3m8NuIHPz3S8k+CCYH80EqDT8ZeNLqMQm0= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= From 0618938932749c5ea65877a34a95b13182d5d3bb Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 12:10:27 -0300 Subject: [PATCH 113/141] chore(docker): include swagger documentation in Docker image Updated Dockerfile to include Swagger documentation in the Docker image. --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index f1ba4ed2b..d4cea66a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,5 +17,6 @@ RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/main . +COPY --from=builder /app/docs/swagger /root/docs/swagger CMD ["./main"] From 13fef25b9ee606c1c5b400db5a6d917e46abbebe Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 12:11:43 -0300 Subject: [PATCH 114/141] chore(env): separate PostgreSQL connection string into individual variables Improved the sample environment configuration by separating the PostgreSQL connection string into individual environment variables. --- .env.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index 87eb7d4f6..dd31081e7 100644 --- a/.env.sample +++ b/.env.sample @@ -2,8 +2,8 @@ POSTGRES_HOST=0.0.0.0 POSTGRES_USER=curr POSTGRES_PASSWORD=currpass POSTGRES_NAME=currdb -POSTGRES_CONN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_NAME}?sslmode=disable +POSTGRES_PORT=5432 SERVER_PORT=8080 -REDIS_PASSWORD=redis_pass REDIS_ADDR="localhost:6379" +REDIS_PASSWORD=redis_pass API_KEY=your_api_key From 363157d1b060d24d8e9ce1b86c6a6aa601c74d79 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:09:54 -0300 Subject: [PATCH 115/141] refactor(service): remove unused update method on user service This commit removes the unused update method of the user service. This method was written because I was going to make a more complex user management system, but as the application grew I tried to simplify things and leave only what was necessary to run this project. --- internal/service/service.go | 1 - internal/service/user_service.go | 21 --------------------- 2 files changed, 22 deletions(-) diff --git a/internal/service/service.go b/internal/service/service.go index c91173e53..711e7b949 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -19,6 +19,5 @@ type UserServiceInterface interface { GetByAPIKey(ctx context.Context, apiKey string) (model.User, error) Authenticate(ctx context.Context, username, password string) (model.User, error) Create(ctx context.Context, username, password string) (model.User, error) - Update(ctx context.Context, username, password string) error Delete(ctx context.Context, username string) error } diff --git a/internal/service/user_service.go b/internal/service/user_service.go index 1a518e522..7f7c98dbb 100644 --- a/internal/service/user_service.go +++ b/internal/service/user_service.go @@ -58,27 +58,6 @@ func (s *UserService) Create(ctx context.Context, username, password string) (mo return user.ToUser(), nil } -func (s *UserService) Update(ctx context.Context, username, password string) error { - userDB, err := s.userRepo.GetByUsername(ctx, username) - if err != nil { - return fmt.Errorf("failed to get user: %w", err) - } - - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return fmt.Errorf("failed to hash password: %w", err) - } - - userDB.Password = string(hashedPassword) - userDB.UpdatedAt = time.Now() - - if err := s.userRepo.Update(ctx, userDB); err != nil { - return fmt.Errorf("failed to update user: %w", err) - } - - return nil -} - func (s *UserService) Delete(ctx context.Context, username string) error { if err := s.userRepo.Delete(ctx, username); err != nil { return fmt.Errorf("failed to delete user: %w", err) From cbf524ab1312814a901c9e2b5af8ddb9dcce7eeb Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:10:39 -0300 Subject: [PATCH 116/141] tests(service): add GetByAPIKey tests for user service This commit adds the missing test for the GetByAPIKey method of the user service. --- internal/service/user_service_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/internal/service/user_service_test.go b/internal/service/user_service_test.go index 401bb153b..4df89d734 100644 --- a/internal/service/user_service_test.go +++ b/internal/service/user_service_test.go @@ -71,6 +71,32 @@ func TestUserService_GetByUsername(t *testing.T) { mockRepo.AssertExpectations(t) } +func TestUserService_GetByAPIKey(t *testing.T) { + mockRepo := new(MockUserRepository) + service := NewUserService(mockRepo) + + ctx := context.Background() + api_key := "test-api-key" + userDB := &model.UserDB{ + ID: uuid.New(), + Username: "testuser", + Role: model.RoleUser, + APIKey: "test-api-key", + } + + mockRepo.On("GetByAPIKey", ctx, api_key).Return(userDB, nil) + + user, err := service.GetByAPIKey(ctx, api_key) + + assert.NoError(t, err) + assert.Equal(t, userDB.Username, user.Username) + assert.Equal(t, userDB.ID, user.ID) + assert.Equal(t, userDB.Role, user.Role) + assert.Equal(t, api_key, user.APIKey) + + mockRepo.AssertExpectations(t) +} + func TestUserService_Create(t *testing.T) { mockRepo := new(MockUserRepository) service := NewUserService(mockRepo) From 33795500dea778319c0f34e8d41b45255e064533 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:25:16 -0300 Subject: [PATCH 117/141] docs(diagrams): update generated diagrams for more quality This commit adds better quality images of the c4 model and the entity map --- docs/c4/c4-model.png | Bin 119371 -> 119430 bytes docs/entity-map/entity-map.png | Bin 75374 -> 75668 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/c4/c4-model.png b/docs/c4/c4-model.png index 2bb778f4fd1ea619f22b8651ab8741afd579bc8c..7a0683b83f44d5fcffd0ba41806f8b4f86a5c157 100644 GIT binary patch literal 119430 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 literal 119371 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 WyO)2BZjPOUKl(fO=;Uf23iuyh4N!Xk literal 75374 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

PC3~hi&cAthzS|~Z4b|c%FaQ-CpILsrt~;H zGFCG1f>GgFP=_Jp`rJSUJ`7>sWqrgI5zPdn(3|(bD*!rjqmbe+Ffx_yMdx#Y_&kEx zP)i)ll?B+rGJLhGpj0iE`QTs2^5K_E!YbxOza~=qq4}YrBJd@MD*l4BHVBk!9!aFJ zY#@fYu3F2S9nE2U{yE@yQJ;xN%dd$BGs}4A=+(usF;H&ksmp!dvVorRSY|-wo4y>7 z+7AfquKY83He#ZEJMzYCPi73_j?x8L8?=lq6@Avm`WuxGOD^9X9R^9DF(0b6wo`*x z^Tz&b=RFCCbQBj1h16IWRvTh<;ynILY~hLxI8zbr0?gdu(cezIxDbv$@4fxLOn2T- zE;uh8fuM6A+_+AFUdAp zWkI>HK+n{(M*;0=+Elm`9+PwK~H4gB?DrJWh zvLx?eF9k6v-$8c&R}b>{(P%*I+0F~Y180P+Zn};*#~2oK7kGcG_P3`4RwYoHec52j z`W9-CgU$N>&v@5C5dE^8raSG?>vJF4N@u%bR0pXF*bxh z%L3VLfQs|w*UdlexZ@>%ay{5OZ_M^)&l0|-Dn<-Tq|QY!OSt!gbT@^yJ|kj3hiN@3 zGJF$$@!{;<@(x7v^HW#Y!B@3>30^;etqImlQb(fnIAj9)^Eur|kZcx10d@4?Qvxmn zCwRcT<1#=GiWN^7?di|DyXWRvcX8N^ zlor^Hmj9teCASq6(-;?lzpv;c2!Ejh-%)L9Tl&Q9Urhr1yt4B8xWjQ}S9Q>2-)g}Mbm`7O!#}a~`VEps4 z;SFPq9DE^ zunFwvWdpgX<4B0X&Uk9tIIXKnqFL83Sexkpl zmpChy1eJjnIK|%*CIgOHsor)I@5xUz$6u+(4-rndnzLG)SOo_YUQDJl?gFmE%0^yF z3O6C*(}5YtljCm7JIMYvrPo-;O?lj56GXAnu@1cQkRDKe@j0Al@GS?5Rfan#P35gd zhs(KDS1_rrfxuQOc+IK*U0qTL9aU0D-CI6e`j_FjQU!A;>+qM&A_jSV&f5$;;en#A z^3E2$$JJHGDdS~`ZW6L9#}T?T2jJoMm+%)zrrt=9zF;1B)5<3`+3qlpduPr(XHv*< zzB~+10@VI+Se#SB;~Z*XzHq0{36~U=-V)mUh($$nTi$%Ax%mWilW_wCS zeR1lw1smbE8p1?IUs17dVb_@7gI}rSw@h^#O$WL50Fx-SOfFB)pTj8%p$X3E z7X(2H`m0oF+-u|C1;pv4~}>==5$KDeLt&02Sf1)X`Kpd?x;u?#9?Ow23Oqw+fG1c$-ciE0b@|r z-}iobigac=JI6C>x@Qt80vWxO2KwS|I~@yT3>TG>Qy=Q8QdJ1hnla#;kquB$5Pfth zrKn*_g(TQ| zKhAYf-jZ^<{G^?LwufluHCB!kuXN_zQ-r`iHn~0I6x1M=D3=QvNUPeTMXCt};)d4} z4T~YNnez^@2AonpOl-{$BatTB4fVHms=vINJw}8xT%nHcE%mw(!IDv&rU$nbQ!w6a>TA;ULl}$ z<`Lol)$PPyinie_1FYg2pzdaWTyo*OeT12p#J`p?Zr$vA_Zs8u-c~}b~YdBazw0=k9J31Z-WFfbAXJp zR!rEwL+n1{BL@H;fPe>XfcEPCzOAr{Xz~1j$Q}M{WjO!sIZHu)7=5A-(b<-y0F>{U z)l=@zI%rTB3$BBvfNq!2Y7JzpI4$fP&EP4D{*8&?i+{2r>S+@Xg)AUwK9Cb`Dn5NU z6FBC(@dm41ghj=|u%uc3H~s2AHLH((6ywiN_|Yt{Hoy9fq~zO(H_k9YCI{%=#MGOG zeo*qxdME%n{7<_%Jh&cS+pmG{pXSC^bs!90PZ&Lst|5{b!YG!%4Wc z|2GFr5^6oRqoLn!j^B8R6#v1Xd>^q*e-Rf#S~j5lk|%oAmexVT*m`9}DE6xBBiZufh!UgMI4c zbz^;DMwd_E!WkZe;&Y(r8c{dwkDM zgHR9Vg~^G}+-Wbv8KYMmb$`o_XG;5!-#$}a%hYZ&w4{B zFp41_-K^)r&kJn&24Bhe+O{P~*wZ;9PGq~H5sOns_k8C2-+xw$;kRof@3;)6h~x-1 zsBRU3W#uZLV5(lOiOcr#mmv^$tfh80QZjA8e4G=X=(XA4zA|+SalAM6T6L#~fvD8n z6I*!>cq$@50Qt=KNcIA&mOg+Q!ASJxS48L98OXPe@X$)ow7^5hf(om2a2@ngyy^J^ z%ya-AX&uh~UnHRYPFyIa4gwDTnsa>wanM7bO9{x7t;HArAd5x+w}r_4E`RS=q|N2za;2$c5uU zR0X`ZSgr4Y{xx9sOu}O9;qTDv*#cEm&vr3FNMvzE!I9Y^3IBi7*SL$J-g(b?0m2<%)a zxYsRAq4;E}b`*}dw%PznHF__LSjK<6tRt z8^1i)vBRPND*H+}?WURnbTuV!T^xL`e6C_=ZD>JKQ#jP?cq9qD|_u`%R$ce(P5!&IyfDM&bVlHnhl9Q zT!y;U+XzkMBh|9%H=}l5Wpg1UAvjKKq4+ajo$ODmRMQ)GWYXI5Pip}cTA9#O z54+CDZ#2co=T1NTO6H*Jn``g}BbM$;S@LS&<&vB#r)@ZTl8+*)K?|Ig>+37n34rO~ zOWZ7(r!;6+5EaBY*+1SCfrd1ZU5%2x-K`OCqSq7O*3)4$9bMM(hRN?=dTmaty|7wN zliVoT&?j>Fey^q$aN2-gbM+X$d(dJ~T2%!Mt`NdDjd?vny!~P)eQM;u=KGRGJM11J z3dT=0+Nw<@1nJ~K4@O1GyeK^xkHK7~R8mPQpKzl=Sbdj~H%#P9KaH?++hB>cTbb%W zsg-3xU%#0iF={g@k>{+i?LAosU~q_Y*R@S4WU7)FFiuW!~mmbtGGdb-PfTKLRfh6|G%-NAzJn ztpclFU9{9GsV36Bg=s*)ADXc^427(vyH!|j$%(;V`JnN-zRH=j({*Iknu8va7uS+} zANCX$22Y!4Yq~_sy&?q5`Q<6d$~(y9$*gNDu%AKExAb5B;(XUnE}$@*+fYUSylA5Q zfY$BQWnuf_enqv0*Y|+o+uSbk+;Y*=bF+AY3G}+_x8SKrTPr(&;YrG3pis*^KhRPq( zSd5Vy7%U46;RiPsA#4+v=^vfgwVq;=LbH zdZnDd+<#>yFI$T}A}FOM7j;ev?oin!EpN%m61Pq3a0*yV=2bd%6f0Spqo^$ELPu-C zjRxAFYj&Yj=J(CJE3tWz@7b+W#;8GI9-5Cl%HhM6k>O$5XA`XDVqUL#jp@gN=1HpO z(6UyN7hW*#KPg{&@BVT59x5`a zL`+v>+D-S>yv!J?tzN!LVK8JFxtyf4z5M-48RrlX;NRzD2Y4FkJ8m~Gve#n~Jy?{` zN=!u2+gac(9A$^3Kw9aPUcZ)J1Hwu`0`%;y@>6rKOtP6@p1!F!avl{0a}eLO42Fx+ zdEUm#&Ks*l<{e2AOV8Tr_>$zU>q9}2f6(ut%=p0d;(SJ0!VDp$uxa`w2`RN8K7Y%X z_leVdnjn`B%BDE#Iwb^piEz!zS%!h@Yu7Mv7inMk9|{22dV++km}uVqrgT~$CQQuO z@rw>g2R!A8kR4zg{F$50f3<-o>=Ef+yP-w?jn2nPkL9`7lal4LT6x;Pg@)69lTVg4 zq;OhOw8!GAhe}s_4M(1@U`$Zw-`JpOsr^bALHfAga)Gxm6%bdBASErO@!%T$e$eJI2zxD z&Pe`nCer6y04rVcK@mZ*kDbTAQ?6dB$JVIdf0Y}{K$4CUzpkq!bO=R%ls#v^5rGEq z|IL~(O@#FXQXx*f3N2Seqxz~PVb_}!=I%ipO%K}$uV7nRjWjVdbGl&($ccVzKId3jf#T>&SI7PynPd zkozveOu%pVYdQV`{u=%zAsQi4m=|z$M~yX7YpWab z0D>$CaV!7R2pQ+e&Mp-9vG^SMC&2zxULhzn@>1zQ43ib2ew_l&>ve>J9_~ZBWv+od zn-%<}7cU_MS^B?!S?7NvpAgRFg1-YPFob&5+8p&`y|0fz z6lvSpf$BpcgSvQ!+SMN?W&HL+QVn^rI#K8+uF&I|4Q-+U zm!9;MdqbVwb}-+%5G;BkW9nk_LS-ORA^ku4bwSj5i0Uh0;#2v;?y}D@0bk!oh|u{L zGA&3ifB`BGdZUm}$;?lsJX70R0KRhfyw^t3QD*V}wZ*Z!2+sqCAiUrNy+e1vs8|GD z)~N*r@YR>5M5!uh+u*XFcb#hgq?ib%Eq%ZcBW~wC<}M-q?~1~H&y4dp?v9pUT~NL< zG^b0iNE~+i9_j*LF)2B;1}&IfZ-=3#Hv+QNQ%hawz?neW7+F<+U3kHo@E<~1)8(Jn zZ%ZudWgGlR?GbDfH%m+OD&2vBt^x4{3h{joLG946E7vuDAy;z`Cwr+W_~1jb|LH>g zdjkxC=gLANHV3-Gw-yZVR+t-?I^9Q|aW@#L^4`mDCV}m$ANf2x#j*3me0&m z<_-ptDaJP|X%GVQJpQpjDxY0|lE55=-(&#BXTz#>ZKkKmnq&n~mqT_8YT3U)xj zO*KDmy_*XkRcetjr_5*@C=uD-ojrjXU#IN!M&e5clsx3xp6~)8p`@s1J=&WeC@hGn zprJctS4)~|zs>Wo>>~)wBdmMiaCHc-AFc2Z8%U}xOvov^J2pB4>J+27`yjBWyF&;) zKXl~8z2G)_cBLE8G9gG2A4L=PJYE088^a4;dpqkne2Rzpeqk(gs&?HCtGp^0PJ-H< z4_`6R2P5rpbw2QSd-My*&*o6eUV{}XNn1soEO_mnztKIe^P_Y&$59`1n?;wN*}%zW z$bS?4#}RR*dd-YQlChMWXchk81;nWjk;WLO5ro2>A~%<&o|pi%sse8)jx^?Xtx?7b&7u760A>D?n%Z5dy+7*EGdHVyFLDg=l!;r$C2x@})LcPRbjE;le|OFP(7K7cMH4N?m`(95z+`P-Zw#eO_)Wz%Zpfk zjJc2t74yk>&*a*lAd1aHYo-H=wQ)*A6D%n81TnIB z!k9mJJIRh2+VVays9pI4Tf_B>yuRR|RwNHrj{F-!E?*+#@{6&Sti0Ck|BJad52vzi z+r}dmwP;0zkY!F}OfqCx$e0o`MUt^7k-JbR8A=&4Bt^zDrV<(qNkWpLk(5T7l#)d9 z?dL+z{d~{xe&6@XJz8ndp> z5i_#{wz{>EbKM&(d}Y@yAXrN-FVwSd5i_w={vpOI+C<$~vYqDb+2PQ!N`q4=!8XC0 zcpdJr%)OlbA;~-EN&r|6ZqoFHK|MPXWTa1i;EaR3i*HB@wd1k)uB@t+iq~nuUzrr^ zCBw29#J?>7hMY5_EE$;#QYAPMg6>GE8|!-xuA^qx)O z?N#)`7~WmveU|tVl>1ivuqyj*utopthgS8^{(M^S69jerxNiUqb-kvUl3-&weE5B` z!-kd>a=Q8n5@Pm>-4ddJh876{(pRmw=>Kru)3m)cw+3g-HR``RW0+W3(zP$T8bYk* z>2c58*K6#zh|~QC4qUWOToG>-ud%*7D!t*uU7;8H?j|1g2QO-sHBwH`%rxcnKG^>7 z)X)wQBFVMsVW?hw`QW*89H(6o&Xhv_;eM}e;d+J$YhKj1WdY$aTJZF?1{+sIFZ92? zBI*e4-7!nFe#gZ~xP}|<_ndcO+$ z{YRDU_PkqX;<~M$U6Ocww8UxtLb`jRi9my$fV7ML5xVSw%Yp`dM?4fxR`)-LGeWc} z^Mj=6iC#s6vfVm-LIAMOA6*d+d|&d}>&{^$0?n=`$gN!BI*gov7KPiDpAoYgA5im7 zVskGnp2zon10TB@i&g4OyRvO}ViZ}2Hq6=Ub)itDZhlUZeER`g+vRGnH@Khh=r%A& zRi$z0tk$-24~vQ}mx|8ck{Kgz6axnNHOk^!rn|%>5fCjFdsc7DyiOrjjDElT?Guv7 zoTk=h)%RFxZNVD%6pw2$<*yAx`-SfFEbCG4s>_>r_~H2O)kj;i+B2_q{pL1`=-1#o zosm7$>heBAk+t0({?^6;1MFH8B9N0?6*weFP}49>vWvHm6cU@4<)n6*q8KMj^xUe{ z+&zOYeH3!_ue7dgtJARK%TnSi6W4n(*KX*Y=k<;eI4JoRaL#Y;jf$i!g}WObyjIPn zDUa8!=Q*Tjnv?Z=>2dlzi_`DUeBO5BoD7rfIy#&TJZ3F2xW^b*!RF(i5;3A*CItEZW=W!>Jp^qVepP3{-6&=RjNn`N>iz@n(r zJ;E^5L+Cw)@B4Z`opFn%)~XkMP6=>ut%AabH*G`z=`=n#Zya}naQGVkoaco8Iy z(+jtc>^3etXIR~DM(5;6d<`TZmZDWmerG6#--&p3^5Az&v9K8SXlM()2YT+ivCbf> z^=;de<;^PVRU*nu`@dKi?*hC?xRdda0elGmF22lj9tm#V#(&TdI&K9dnzHZNaojE{b=&x}C>cySN%n>1WQaS+CU~p8w zFd4df0w#}Ler~TDF`{{3NDDMT)^9}BRQo+hfH`Z6_!#=FGU)F`z4}>`Dvi+gQxuC@ z?`q1xSr|llrT+VAXbPEYuAu2nnshIMV|o{1tZMWQ?`QmK27bjXeEVv&Sd}A%kMo1JMaCkG&z~H8 z1q@#F3sXkWFqkB19g*Lgg}|tJc-Y!{Bz1~4Xy+5j)zC;XvjPHF8L+>dDAAOuLK5f_ z;RjTYzF&5&_rSc5U=JO=LzOU3-;M;}ox7JH5=7FopdRKIqBZvM(kGa!WgFJ6x&;T5 zK*}&8OWuDy^^M#Ij!xwL37A_?#8Vu$fR=VQ;M(6oplQuDL`;_1m7P27+rX#b`3h9= z3MdUdKDEm4V;Q`0IjxAJbgg*gz;!_o;(z6jDuCqPyQOhC8E#^p$0Jk57OUkBkuLL1 ztT7Bu|6wwVhG+OB$YgsEVuIMrKP<r_|n%h*=&(Qi#XNyAM_%S?V(2 zZFdZxQpfuzRY4VR?qxiOOh97cRi)8gimr`-0N$LEi=2Xe%Wo$;R(^!BiXfyHK<*{v zx7pV0AMbd7|2gzW-EON`3?8I-_FO!aB;{*bzH0E$eep>xn1vv>w$5OLiV6EvT0iZA zfswG$;xE}B1ygi{(^+t<*@I>R z+t$EqeMGckE{%f~sMR;i^26owWN?*Mm)3NO>YEL7PDF zKlT&sRd;wObFP&@wM%7ZuQvR64$0pA%xp48e}cg2yU+g0uG|j@aRv#Tol@oShH>SY zx{}7bKaTck$Mr6thlTg-Bd*Rg2=!KEnkRLW;k{zR4)2`i3M0$=9JBXeTz{M?>vIXE zkl(=-r6Guz5=mPUWtLRuk#pQGZjxLEtpj`b7%Mg(Aa zZ5-h-7MT-ej4+QwNTFr^%ZByEb}JsW0`qPMY%AZ|lu%YKCOCyznvPNS0&;eib1gN= zL2~MVDVKt6<<87PYg@t5zg({vM*M;;xm?M>mS36#N4caqX|SOB_MHpgUm$eUM3GQQ z8_U>F_jTlNkPJek!9lQjAQe36`EbAzt;DP__s3V@tZQ1K zD@{&XssQs~GbL3sD4;7-6T#L3g#8@HLwXoldiQFObK!g`vCGk+`e z8aVa5!#O09{NuvgmtY<_>sn6QDp>+m+FeCV75{9OYM$HC<7wkbP(&OBpv zXb|s}r=99`eQ$fLIgc1ir zJJukrv{Z=>u>?N#fTAGLqd9ueS=m$`@ysiW!a8m_JJNB}Vn+ZH%d-~^6EBFYKcl24 zw%9+pq2~AZ^Ecg$5Y2S3K2#F_v@L*Fu(BX#f$MR@2xZTX`qN{XzbC%jobPkzD9a%Z z?FUS`U1~Yr>RpN?NB75uId|U&krYxvu+n_)94WtXZb_GPwyb)JV_<&%zGxo7#)6xh zFMl`STl(sD>|cH9Q5y}s5%Kfpws5FBqG<1brl`E-+yKrj1exP6?o!o$K(A44jE}XI zkE1Ejjr5576fqaAhf{0{_`(y;+~+-XGjrPvp0M z_itvT1s+^0zRt2Dyp1GoV=i)z%c-%hxTGRhGBkU!QSp#|?2@HH zCv!#iH!PH#*7$v~RffnD%wRbH4ix9d5k)mJU{6R6Jx__L97jmi&W~Q-*P7unSh3A= zm_t7BZcCHvI^6Gd$qiCO~X7@~zc`F>G7g&!8Udfzeif+^6)tK?KXP^cW(>O7n zoCprVrJVh|6s|wc5sVD<6Y#c#i1dhqy26H%(sRTmVnoRivdTTh>$zS;j$J*U+~i0I z+u-9Hhb6NaH|;VQ-3~8I^5vkAApMjwDIzOORmI1(hZ30x0BD5zf??~E+^&^iPw@CQ zKsOD;No7R^0tP>ijPGj_uh}?a@%|35!rYYy8A{t>+ZSvW-B-R-{N0v6c{@yUoT?Sp zySKGp&*YYKe0roO+gwPb6yljd6F1pawhi17de6Oyv}|(H+A$=0x1$TmKXX`^n&MO* zm6t)TPzOAinzi@MxZ+-H0a}!nQ^_yVbFJ_FUg@)e4Xaw`fUnOmYk@i@E%lzt% zf;4Z%KOLts8}@~7&WrCSv-GN-k+*Jf0KE{e6F9DeSvnAJJk>^RQkjR;L6Dww3&uTc}|zF;M1G#FNm>Z{HB!L zh4-^SyKG@i^F9Z^pPkK*-JOEn$L0&uJ0b_cwIA}``c7?ny7Gw;uy^`&e$VNa%9Ob+2J>A!}v5o%WA8jg5T{+2t_DiLmb` zmlE|0GS#B~+M;95_@FkMrI9k|vALgtvKfzSq+vyK+!$QJ_?ID6$>Z)vuMqvC8ovUA zVjq7^SiuS!ITk`m@_$&!Yjz@ zlm=oZY22*WuWZRYfBVvo=UNX-ZB3kF!&-?qW^!`1uuw;q+6_(4_TS>Rli#>V(mw_5 z9461kbg^~0!F-^tUir`+HglpPMI4dF0e7Nth|t%9v44_$4qgq(=Z(*SVz;P0gPCRv z!-q&A=BYr@&I9F46cy=P4yQIxPkyNOlyDD&3Pb&(76w^klI{XxsRu%aO&7bP6KKHK z454)rgaqsK(ujpw^-TU?R1-0GpD=Bdxw$=#+_R|Wji%+ibXsZRK&I1~a7eyab>~JCo zbN7b;==&J?MY>I|B||f^A7j+B$)!t`Vuoykt8*~Ou%r;nGMmyfTvQSg25D!FI33xE zZbTB3MvthJRRyu|0$__Bz}qJh)|%)6Z2ar4)y7S4>WxUm8d4wDsED!{hAOwzx>}<+ z&(6Fjh?93dt^x7oA;LEHsZf!fG6Yy+r-<5k9 zK4myC4w6azDKkcHH<9ps(nNUzK5h52tPCah-&(^1EYI@3K7Tb5+oF`3ziz9L($?lU zn!d5V5np!8w-dH`TbrqzOI_TIMY3Xy^!Y>*Op{ua`l|Qes~UUiSN`f$)xGqGc4L&4Ylnx#6_1APo;bCX_Ikf&ZyA36&3z zWG4Tt9cI38h?c!3R>ew~Kd@gV34_`M*Y;MRVYfmPM8R9iQ$deDIpa0L>hh6Ug!L|v zT+kQRKg_EsU{$C$n?u0EvAggAjTAk}S8d<;!z(Q?-LNS^+{`K}h&Kxw0^<;l*9*L4 z)-W6^#KmX<{wHlNHR7@V3tkmwR^iaviFtdzsqnF@DmQ|(UFF$}u#pnCF!5)s61KYc zrR~yc2W~;6{mQ?H@;Tp5)vLJSaVxU=Xv24vRMfgjmDi(ld8=av|2jkq41JGXCj#lq z7=cQmGX?HZ!QUUKajbh2W`&C`?0c(u*eR(l?&5>sXJ{Q`(7H9^E zK`Av)hh4WL&ukf_jcAm?(2DAICnKU)k4PAupER^G#uD;?Y*EdDMszzQnhT z?wpd;=6!j6#rLfS_Z9YJ)oU`E#QJzcsC<3;hlX%=DL7bm{>UfKIi#d`8XG6oz}VTy09h~g|pi)-hunbm&R-UGj+YiGXM zxR##|LB@GvYyF>ZI{NnBSZF@wir?7UvW%YVx55g3J2Bbm2@9}{ghbUjC#8xqv$AZg z?VfNwszhNM`0|dO@zSuixf+Q|$8*fn?0lY$PRJ@4aY`!gNQjPORf5W|iPXlDXL0m3 zYr_LdhmJ9Nqir*9&)A0@HZBT#S2ER6h1e#Wp2eDDo?_gQYqWIDvD4LOO@?Lo#6(1N z*QWoRuRhf|^l&lRMLXLGhZGB;mxWWpP*{KN>jWo`U$ly+<+myWWl#KITJ^Qh^Ge_+ zgWlP?cm6R6OkBbgHeOkF#?(Ew>dicr`ljPe;n&Y0i$0&!El6w<4|+)1_2r9Gz-ggZ zfA&tDW2n5?$0bZN7z6xtR!5%EQa+`eYoU&oLn1Zf!G*e4Jex2&}OuxNQ~O~MEJsK@h!O*lz9G(P}pN^*FCzE ztD!Pd`+h}34l%t_?Gdv zso=O_*#Ea5W#C7@@8`%eUbu!W$1vSes3qQLc!}EbD@$5L`dXcmCt96$-4{ru{8@Cz z@S7Kv?^_rLa;;0)uh`d#8$u=|=f7!`(fX|JC9MzPzUd|WQC6FG%jfSdLm1A`Pb?pY z`9I6>bsAkQTl(hx<;A-oW$oQ}HPsCiv? zYnja9O8|xp@IhjB)s4bjI!b+ypf%>5Q(@(MT>aDqCca!jY5^&+oaL zgQur6)QN?a{;SSV6d!1h%=O^yC~LZtAY*&+i~i2qmK2#yv8PgDlS8 zw9p=D`T@QOm~(45B~1Gl@1(9a`^Tw_**8IVZM;_Tl2x}^i%Bwq1{PB?)6Ch8sKf9Y z8om~&zQKn8)a%yM-7;;km?V}2e+d)7%_X#NXgwdQ^(=(d7+ix|DjldzNYaSF2wOuk zvVQ7ge135%Xfry3b#n>5&Cv1WKsQ+>nKV1A48G4LtAb2(*OvF`mJ$9RAFl_uQVe48 ziO4rI`TVR(Uuz{m!cS;?ko2bGed$4KA=O7i>e+GJ-Hpfybj1L5Ajhrg+x1u^cP$jwO?U4&>7KCX zY|_1rOxF(4uAY8_0AUJA(Aw3+A*3M%y|6@x;or0jIi>1bw|&PG=)?D4S@N#)YzpXP zCdj7Ag``EEmzeFvtqH<9%t(VMM>Zn8;h5mIfd}$iQDLtG72>)zIKye>w$if?lUYXZ z_HznT2D!xUlD}U_Z_bt1tN5f>e}RfjyJQ$gn+UtHDOon{iv7JGZ8Jo@^w;3PfASUKpBGM>T(_O^*TXG*xLWlI!_a1q~Nr*VkL_Ewa083{etMk_PU< z`xQh!6IAbMVakWW76${W86d4Cl?HW|A~p^Gpcw09h$P&#OoJVCaqd&{0>&N+x5mv< z_M34nK6b42agK@*fXHA9Nfl$Z5iynM!5ZZ}aaq zMIi3(z3<;T&zh$|v%|Rc)T+DgyVLF>R>?}=KB1>HxeqaobIAQ-5ZZtF0GseP?2kJWV`-^__@>zT8*FNsjyX?FcIr*l-rmZz~(Z4X$4 zB{McxaX&d%>TwXz9A{|xoAbV$qjz%pB)2CAkk=Jn8L}faae{m(j;;_Dp$uBbj4fb| zpV2+4%VJ)E&8>(3CRrlwN37FHOZDT7-TJ(o!Zs)Mr*4Hixb|%VJb8J^v*zRbK}8$3 zXN&zgwHT-QT1=q2+yLX|-if>Z!i1;}@7J1bjT|gvT6bEe9%W9<*`$}NVauJHQBxfr z=*&vjtzxeJf!1f!CX`-_3NKm1_^$8>I(B2_*)`~7?Rxw@?6mg39B{;#8Pmdo)^VU0 z7#@f++c-JRPwjy|&NA+TT1k8-V?<`qxsGZgGxOloP=yJjdn^mmO2~yKIakB#(#6E3 zR;Ez;dt3kR(5+KG&#o_p{C;H1$!p3oZ|{J`Fx8hjYWn01XRxFf*c$Oyja#^*j9{V4{->T~ou^o1@DsTEfzeoOMtYO+d zRl?0vDekH}*=1pB!9Z0q=5a%G6G#@!q3x*0{=7~i2{@x=*m>EtHwAPaHqy!8LmH8(Gu2LDYw zSlfp1T@2X8;uJ7Nwx$RwI2;|m1S&=o0zA@)vL_--*I>+c@Z~Mn_xJNHN*q@0ML;|U zN>m+4CiVDHhT2}iB|v)@A)&(upA2aDO;0;fPVU?1Xio8js3=x)QCK3eHbxFiT!qzO zuYZeC_U^KD-1A~qs)9>I46lN2f|${k0W;{|gIL}WygKCfFQ$;UtaRqJ&^((QgUt%) z_Yqmvo5U#kDADWb+6V-kvo2FNLB-oH<1Bb$`dk`f=IKuroee=OHCwmqRRjB~;E_^r z{TxB#mxF#(5rfS3ogXJ@8(IFaHJ^`GpyLmg{V!9Ii^P=eqc^y#Z z#o)+GK=d+PgVMg@7w-D4NUY3Ls~^9*(be$&7&1O3J=@NNeSC6BvO$_RL{k!`azc*a z^y81<@tdp<`;u#%hdWA^A=ykpKrzOlq8!me3s^Q%SN!^tLBu&B&Ed3+USOFoLhJ+J z`;H+cWH3JgK}ftV4vd+!I5+&4!MXIc8LMUS?-Y0&jo>U|9%jM##w15fkMBKZHa)Sr z`QDrnBTVrU#CF`t!@Aqm5JI@GQLsk&#$iWt=|D!{DR)G_tpKnUU~wrG3*U zin(+JNN>aC^lFoPgk_0??dXrsOKkbFl6dWmUi?PR82vd=2?zKc=XmFQ3=kOV~}1r&{*%cs)ANv*Ir1d!88 zCF2%38w&6CoCXO+aF}elWi`0l^moDHue$|;g_v0CbZb*!G97>r_8s_!q$JJL6LBSX zUGK2I8HdsxYle2-M-{b3ydf6?{RAOgtD|b3f*Y|=(f6g^s=o$KT}R6A+uh~-5gu`8 z=EOk-{87=N>KFPIB{72P)^it1ZQlP3zEi&mP&`^RaaOFbqIK=K?De2!l~`A~&u+r~ z5l2G&g$UZH*Cx%D-H6h^EmrKxIMzLWSe8O86hi5Cn-?#XUcfCIb{!LtZ_+(I0s5GL zWhHZ6$OLQ`>-FU2>`Wv^Dh`i$Y)})J58^rpSl%9$2hm4a=TL+QjL3KhhNZ4-_4wX^ z&hmfqRtzkOu--19=5Kh>{oZnrOcKGiIZ<)1|3xlJZS(9aKJRGvLIK&vevVBjlGL(n z$A|m*qR_E88latTz27ul!f@AtrDOa_G$_nNGQd<64vWoksdUQ38A>&U@1Q>Rz>I^1UABmU%;P}RW<)w6y3 zt4@HGeya3v3)7VSbA18KN`oUoj6E>`8}q^hUFY9lHrgX>>y`@b-!||jhK+umTY9@R1unL6J7q?kGA8nl&tBFksL~(}Q1Ls*hx&%UqyP7!Ve#>+cT7Q)Dkq zSp5TH;=fbB{99w~KVJXT9Qmz~4d^(xKAX4dn*TcyL?PmFQ~vbUB)Vp#m@@#AhFu!8 z9OH4X8b@*n{(6}5fM0}iq3f``(DaCxVZ_fI@?1hjyfPHW6+EBuP*^rXhTE%!tM>n@ zB-bbQrN_nCG#pp}@`7 z>Xm!G^foq=qL#*C%(J#apD;nycT4nDvple0FCt6P7A1o7)d-+xV;*uGe}Y;HTTzx( z!oRJSK6Vn7L9f@vjeh@-=B>fQ zyS4C#_UC5Cw7S=Yv*lUn9h@uJjjT2q;{Q(s^E_N&^a=k8uSR$_Vv<_>a7rqUiy0-< z|1urxjMKlFN@#jd3%OO1ympvvP2ljyrHht3$Y&Z?`1G{6v(iV#j!dne7t7(788Dym zjlhrKg;NGXeq7rJC}bokx*C7GQ)6xFVFSZ#mf!M5FgGQk>3>+D36-C-4$=69JRU?v zPy??-(w17}$XihZN!@uCW+aX%(&|x~Lht6nDlA1=Xc!**i?;*mgBywmAKLFot-W#i zjVmB|-o8g0s~}gKB|&K~)=;~LxX8)5JR5nltP}$cq8;tnvbdMn-P-l3YsH4Dcx6wE zZ%XW&i9kQs2@l=`2{V4b8b>?XZ0`yPVE(!SHe!R(!QYin9q&u`v;@PNJ#J>)}*{&!qheeI|Rc!yZ(&Y01d8 zj_^Q~Wy8>-kgBIQsqB11L4gR{G+P=oz_~$7x~Bc%MRGp-^SBrDC)YzAB{Rm_42pLm z{H4EbZ_d&zvYII<_!%p}EH~QPshSqV%$DT8 z@9{WC=ZN*u%96B|J5G8n^zO!rzwq$+QiEyu9|j1`c3nY}oE*n^zKBzz=Y9j<)fkp- z3r{K(lD?P7i+SzA0b&8gR#H)ORixf|Bt&jRTsD&TCbjrnn>0s{+pDW(b@W2xvKqLw zRJzo>;1;nkuee+3bk%ju%{b(}ow%evbQN>??NRaaz+=YHaJ^gAwF60S z*XPn9~rxjJd+t^z1|}!YPKl9aAoA2^az@rPA1cBxLw{L<1`-TQragea>=Xk6f?I&Q%~!W zt*G6suTVxj>8rf`aohIGs9mw7PRKZ3x4GzcR~psYl)nWcwAw-| z!K1r=la$FiZcR(8iYNUK7Z7m0dqHs#a{Sc%un2jg{rYpw^Q>1* zhzimjb{uc_R#B5UeJwpBYex}{a^c7GRR+_}mueEy@-du8u6vt#^(!fCJSTm2`wIFO z^hJ6+IAra;bG&9o5>11B%I>53pwlnPU$!hF7w@Ieq?^=zxdXU0wjvAs?So5!ZRe_e z^`F<(>GRepk%1vo{bCsoqv~zB`;4dHoVPeLKjU#$`dWNWonhQB! z;$u*~`*$ea8kGI4cU#ThycgHsKPp%Wugz{(-bItEf|bP>=JvXaW#rBZj}ATS{5MxY zmmwd!_+cJdX|T`bpI`IqJ4Q|v78-P%Q?Mf%3i?fWUz*f})11HVR5F`BUy5+PxTGXU zli9wp;EOWFv#Ts0xQ34W@ICkB>%Siavw@&hQ^Q@~-&-*pA4&aaEUuMCXhgu`$%8v`=RAuZ$jygJSB!Sd(loTFBb&vw_p{`pWd_4D14 zX;0K+IOyu1eYo9^B^nktZ$ydG-W&&uE3G*Wo7)83dDGepP}@sY@ji)*T@Q*^%lcYR z9|y?OpGTK4Js}KM&T*7|HRP0BD?>~*3ZLSMv7YlMq%E$$Tj|C7(yWH&R1`$PYYLX# zoQ`z~ufy^WOUT`Xkq|az*)oq&nY}=D=<1%qto#nc6Y`meRoFw?L73mTf0&Pb)zH;| zPbXpjZ6NrVcp82>B7kC6y8c>#_qRT1+!@31j$?IyG*3kTJ@wu17w&xyAGHkb@nrm8 z18>Ag$Bz5*^=bQyM`82-mwDA%MqfSBI}?WJQ5?jN!zBVi^mIV!tL3n!R6W;AoUR;lu3Z4yZdqCWG z|9Jp@@kKb)?B9fNkT|j8p=rpcg9m7C{tn8%!kl6QO(jwZH19wTzT(>qi1=)H@n!Hg z_rDUbiSogju|T6|Dnz2)2wFv^SUE7rm)k(?xfD7m%B za|@xyR046$oltOrB?Xs23Np;smo?KXdSslc9gZ#0S`Pn8)jYMlnU+;kQ)<1*w~ks^ zLV3ktRbc68!{NVN zR{lS{gGq!NJD(AG1e%-xWSovW{>yp%$2b2U;T~}&yAy}5N#JKT+pi-$CLGc+LUZ#- zm?-=#u9-b0>X(S0|CfZeYt(Zo`a`O-VPpS0UeZ~7tSg4gOJvVg56b4I-`ZpN7ov8m(E#tyCMxO20YJoW?bU7L`j zFZpTCh7P*F1g2hg3a;swW!$c-$$cD0f+rNA&;fW}LXD44-N2hYF&QRu^AD1cYmpop zG``~Sw($REXt7%IDk4kD6H&I9O9=BEdEIn;4Pu0SkDmMnq0i#%TEV4I$UrSI1-ovj zh9+bA8Udi({XsAraRmE+>av3KR|IUuB-HV321;nT2fVu!DPu_-f@&wUo?qX)!LGtb z*0Uogo>We{C|I*rIQ{5?h27Jn|90Z5&e{KK#Fw1d*i{21 zK|7vT%OZa)9yB-<1!#J;{Z86qlD+8TRJu6~_PO2w;uwvw+jtT2r7Yc8a_Z+ZAlF<- z-;(4eBQWV)*a^aR8EBW+r}GG2OIi+>Rq<>WM!X*TYBOTsEcDdXWIpE1+XJ6bB_1$; zsZHtToCxa>k6P-21aj0BJ^0+)77NrKmf+iJ>Q1yE6 zR#!tfjKxu`ch~F21<+@SA@M{;VcwsppJVnWV)i0@nutRuwN1C%zs8?J^5uv_o79+U zN?dvz;NoSvbJXu%*rxHQ<8}wf3;GfGV?dS!q2UEPDb4u^#RoKgLIy|gW&-ZTI}i>v zospfibeVNg9PZ+i_86IS5cOgPBk%wM02^&+79pq9UXM^Y!7xZn-|w zcR>V;Zj#EB60@NzU;6eQjO%_-EJ-_vxC~xxEoW*p+I<9_U1d&?}w!VFqTTCtF(F$Zl zemh@s-cB&fJ;sA~7hD^i*fGY$!jN-%X4%%y%lz-UW}QC6h0GO|wOBiN8QuT>)yw)7 z$2>+d!*mGl=Mzvk1X?Ra;YGCLfOC}3abGJlkK6_Tue6$--_+@GV`-8%grUU%+;0c4fMCY4Rj%P!SniejL$` z{M&(*=7XTful)GA_s6ioF@dG1+v0M8mB^X59Jr>zKqg_1^ zh%o0^vU>Z#qxT6U#s?;JW~e4VB1+l0&Xd;=i7-1y=`V_KW<->TN#L6i3l~k}J4EPP zV*QUaBR!Nxq^LZsBCIX?AL04YK1-v`d9#?pXLF1ur;?)c*K_q}@@Sr~-@T6nI5ZM4 zk*QRX_qjTUe6F-#G7rwDM0cfF*Yuxa!1zxdW24PIV8I%}M$Ls46;E%I*SjgKIU)A% zgB;GL*ngo%Sza!VVA*y!P(EL%s~{zPN!E_^_PG>whd`ld>pZ}8`7<}gDQr@5M;UiK zelZIdgG{9q!z*5T{2!>Y*_UV*^^fz~|Z+VZzI)7^pV&rZ6h*`*7BDA94nr#Xa&k zMEt+F$^Qq}xV9k+XOy9yVPIZoB?jW9%EeK^aGJFfts!y>#{LFHYp_D<6PbJGNt%`9 z|D{m`MriuOM6QT0^<>Snj=-$>|00H6N4>2%Gn{tJ-a=y9x9yAZ`VuwW3fCy};N%f` z=P2>yFdfE+Fny@R^qFKmgmTRSAHmj3(^emRn_dQqp~T^eNO$?CL|eaV zpRwUvdmf2R670fBd&f7X{U3*HCLhD#&H3)Rpx=0H&S6AkgnyA3OwHT>{Z$|f_1)@W zyw``BKO#}?$BFDsoQBNNJ4fExBD@iA&Qr8=NKJ9o)LEllD~_SO#CS>X@!Er{F8v(Z zs~)WS=%DTE$Ae0{`i@In4*Xz&Zxai#wx7&W!J!F|L;9ALedH5x` zvR+&tZGrcNVcU~%(#v`)*R_l$?+2T6aGB)MKMkc3x9U$$`5BCF7ZQ_w-yz;5&c26-;~DJ_HxzbC|F~;tgs+vt7Oyo8A!jiEeFL+quEmPDExVL!8tuuG z7k!%(`i^lP))P);#e%=4HUr@gU_?5-6s$=*!s4)f!oyFmoicxr&PA}|bd;Vzl$VJ~ zTZI^1!vEAx;86S`HuacRgp?3IBj=w2*&iD446h5`-ESm*hNq05?y4_F7^@sr^K z#dp>>P2tF6>8~GL9ky9+z@Yk)B~rf>?Uh_G$u17RM#lIzi+srB5L5rj>B~B@35VBt;5>B9;U;Yd}_hwMbsOm+WE`PwF21aJ^>0xzrHmsDp@rR*M)AzQS&gv7V zo+vdtoozL)KdnBzBC74L##=i^YL<-CIRsbp*UXQ6b9SNKjVp{vM$-#`HLW-CH4vJT zjiL6o_z7k+``s9O3Dtd5v#wo>qi2fH5;~5*5&NueL8BLGuAUCASQAI$ z%K~``GAvt|*WZi-lVu4{jYpRN2hI)oKAuP!k(C8Eq6j-~9>V8^q^=T2aDq z7Q~@i>xl~naHPSKdIN^aanx2ee%q4zYWo;i0dYvmX+kOGH_%=oK_p|O%V+N^0o#NG zGJtp-PJPm^qP~`(hRbOM#*x-kKzCu8lIHTp2eR|%x>B| z`s%TdNb5enJT%5E{e3qWRa}fA7yr z1fn%U*v=IKDOoq7t!-k2G`lQi?-$v2vMfSjpE$tbW?0BAeZ)R1;7t$ty>~CPK1|d2 z7ka3pu3l_WS7VBt6OiA1dA&K+2o3#2x|A#0B=NefoRnI4n=|e)q5#0Q;d>T0gWg0+ zb7#xz9VOMZrRDv9A@Zi^*YUGKr8UU*!S!C(4rLOYJ3xb!-%hMj`z5y(lq$;|aKBji7x?E~oXVh23)QG7!vuZ{5oFpKd zLU+=AZ@jBvMfqxgI-ptpiVH5cjo|^w1w=`JHVBu@yWHPbm#>*nGvVDbR&&dgz$|P7 zmMn5;YA}Ybekl@UOzu5WsS()m z-GxuD@9hkyz}>r2tMig3rqaFIfSq1eryFAX{EFY%pNE{}dXlr94@E44*jNHebr=EZ zxbDwm3b#H(b|06&eT<`>S*BKJsR+U2Tchk2WQK)WhkLBc>I(&AV~SY`oG03`Zq0e{ z)*iE{shxe?z?Y_vR4gx>S9YxI%4J&KTIH*iDed1oziseejc7JEdnzdd{jCb}Mh&MF zvVM5nIyzh3OWvo$v@T9{B6;V`sg?4WaF^E>-m)P_E|m?OWVgbGysx^;=tGP8f;RC- zz#%R6^%s?0fl$ogw_dTN-7A_PY4EMyK!q}|?ghwtZ_^>iWJDr^!zbZUCrUbX3wsn_ zT~*d-o4c_1X6z;R6y?6y2pV2D&*v;MUrF)k@@(4ZSw@WaufLjt(^c1^~Y*~EPy6ov4 z5iedv)Y9y;Yn|ut5!zim-n%sD+^q+Y^|#H z3cZlQex9jCzzj>9Q{IlB82zV2u?iBSMehd0BF!%~PWXLpx2f{Swo7^#+)oFCOzOdE}@zF|<&>TuQHNP1(*cHPB2&$3fy3k2SS>hR)KNra7*netOW{zEYvY_H!PG0ok_Da)JPN1zvcfFk-@j`s zI+`b_`TPw$fN!7U3X%dlON`>%>g4J+ogX%V%#XTka!??7C=_nyQ3IZ0{x)sxWh;h+ zHxviADXEkx>fRgLIiFtkRXe2pp;PbWEWPKevunyeeAx5-DTn4ltBO4YE}tsQoRhH@ z1=Pdm1xgV2l9?9&PLBr>zju|`Ym}L5rqORMWEUN3v)HF}c(%l-nq$vlt_{3d+~TBc zji-IZDH1-9=U$+;x|nk>WT;+)DxvJx=`B)X(wFt>5!xZG-*{WI;;&M{dHCQO zC?*P4@>kjQXA*ASEw$FiGG#U3`}b`B)b7Qx;-Qj3nH+np|5(D+ep>kj+sa6qU1qlT zw(pVYg;^;=>k1!;^ZR%8HG0k8+)(o@MXoX+PqvNE;Ss)^zKp{w zG=j$NRP@;}>Oo=hora@McOb?q`k>%Zl<%>39eIi07Ri~^pRQyZ9eOV&WgY4YcgvPrQ|3&a1i^&#b~o0X@!Ie(?H9l1 zH&s9Xo!DKWX-KcDJ-GA_dii@c159&Z29{GNIHuOnjIc9=ou8D}%J|@;)H>nMGk1-| z9tR0pR-Gebx?9+LBozI{@Q>Aw5WL9LpofND0?IpeIlYA>)o2UPzz{HL=Ne7f+uFk6 z_<&Y_b{pe^AmW^GIn66Rb-WAr=EH_MYw?ufTA-HWyUy2!ey8nWUJ(7o$**i0q*vqp zBX4h?CAUC7^RK#BjgpAC#ouYpnd*yh42V+(tQN(Ub2o^$QTGc((eOj?f(pfHa=iFkZa5MpbtM*b(c+Ln;wWW z%s1HSd)|nd6YgbbC_B2dz0!m7C(}DhU%1kl)nt-M5UMrnz`~1M5hH%>9`o=vBtFOe zHrL%e+q@9Rq(8R7nd6-VdxnPguzb}@*sxzK;PA!|UEVKv<)&Y_lO&r6u}?PdCH0Kr z6!DSR96OUSE0-P~e==#UX~SBZaZdRU#F}QN3TiW{9Gy)~$y>mxg?E0j_j8-h#c0J) z`3{dNPA0f&u`Xge%W##hO3M9pOQ&22W!b|zP?vn$@q2+26g06yutMPX1aq9Y}}UeB3)y|EOe%S zRhG>9qR@>$B46EoqUavi8Io~aeZgOKzN13-_Wm#*)2L2a{0GOb!`=wD$fzbC%wxTu zZ)@wg{Y%j-gF5O*nbN_u9j?Pqa|6V|@dJ?k%!3co&i=?XrWjqL2{0hPuT=SQx%@GJQB39T9XPpo#1T0-^w zLpsGbI4ynD7(q5%h+C>wTR}sVgKUE<%fh&@D|fR&N6Mlt2b$ z5+YzkOkpb;-cfA7((fK1BB7!ZBD^ig9GjjKegAxI+sj@_p4mXac|C|F>6H`GKgrSr znX(~ViDdMlKwvY-3$IbzXr=dicauaZ=Z1jazxERT!}XyKlRVifQa-R@5U}J9(N4Ro z7%}8n7Z>-nbJf%?t_NXROvodcP?mQlgl@VS2Zhl_XsU^#1lJKTW273ykuGCUZ!_}2~RF&XWjvmAP1=w7I~(8?|QCPU}|bktsl`z$XK5>tH%p z|HKHsLC&iMG+;>14lua!+j|*uB)W`W8xgLFu*=ya(@;ZrGxNjMa+;ev^PE{eV()Ev zl;rZ1Eawce7CpFc117k_ekLh1hU`7bFAEk9DpLrjnYIsU}y1NA8+*jlHH;kv<`wkV@^h78>9Fu*lXGT#3JmPx$2LqrgT!YrEgt zvWrA?Ql9DXX?RG~i+Nl~%%5y^+)*!9ku6{6fE64C(%PqG0G3Kgyd~ReLzw_kcrI;n zg__J;3J1H)P^ne%>$dYHN^}P+;SynbchtL}z-NuH-b_Q*pBGrQ>qN2A1!!$lHzG{C zO`5Kp^W=g{Bn)OJ663%iuXLF}SpF{0Y2?nNhTd9hzxDn>d9jv>HQ@{gp$hkz6Swo` z^__LbeZ-dFMp}4n?qh&yK$;wYfwzl%HG}B$1s=#sfo>djb`(579^#59&*(4b9#6Lp z?za^R%!@qh93|AOhEyQG8Xx!ekViK+>{dS#p@_DjD@s2ud$j8cq0}E&djEH5b*8~2 zHhJ(#85}8PZdxEmbPq=9S~2gd=~0@>Ae>xb{TG2OOqI8f;3T@6Dg@qjJZS2Mh{}sr zv;xEKINeS+`7XO0+fk)&cRvrm`OP>~7Ckasq;TW;WOxKpXKuXAERGbjzb?P1HZ#yF zbO9SEH=nu`QbQC0Rry`^$9_A|Irm*_LBzX-Rv2*YKb_8{e!MTka|wrRm9kZhmzBu@ z7AUTt$J%rJ@TRieqHka-+fe(T&r#fx6{@3e`FhGPZN9<0!IQY94*AHh9x~;9Ia6rK zRJZ@;kL{h9HDVr^xu2i>k~#3i2Z$`)buI|BHUyc1zLIxIAdYRO*x0GVA7LMSv2N{I zvd(vt3*r(_fFRpHJY29Ws&Oy8xHjBEyxsEnTZ6S4x8#U)W8c)ZDf}3p-rzZ_g@p=V zB=Xg9QK3k4^>5e>MdHp1?x-sYYZ z51OE>IPaYQ#oU|6Q`xrR!X*lkIa7&3C__k+DNBYlP^3gCL`7weRLb0hqGZZ4WGJc3 zB1wZ}SR|PW4TjKUiqdyn3(xz!`}_U&{`TJgeE&R8X}Q;ZU-vbf=W!m#an9_x-q;Sh zGkC|yVYi4c-Tc-K^?mtQLEmakQnIt~Ut9dnSXmNobh8) zX3Lm#mn9Snzm<<)P-KoliP$n;e?ER;Qhom`n5zmOK{<@L0#_{Yz+#v=Dwn{w&u*8WC@UBySI#Y1s%;GWBNLZ z{T)kYMBXAl$dA86GoZ zmGHw8U}V(YNFX~AnTJ{!#i`>deB{q0!^pQ%t7eP)m*EJ0PQm3lk_w6O%dt%Dn-$@} z?u^jDYQNo=e=(HI-=MS93vm2DA^f0k@2LHK1k@dEZtd6f~Xrqo^LtQpX@K!WIK0X$K;NPbSvSFE6_WIGZT>hl>9KyK?>XlF#s}R0I*H zCXcEY^#Mb^O2AFhtH$YVP7->5ZS)*!mnH;1n8z9d#qTs!iWoyuQoBi@yNJ(gW?`RM z%Xo4T#oI7@?czuivT(lhp?s1Gj+BGyQS8Ue6;*AU3`=KZ}E)|+0q->4d1?{CA#z=9jzmBM8 z;enyt6}HRU(RygFxx3Mpu8Kf=JS{b;rZgLZrkC(Du!H^zTs7{#wt~BH8@y^S6nTAp zCm9k0gQ>oq1>=xIJ{wN$GNfyC)^^f3duKE{YU5SkP98!QyZ89YnXP9xg1t(iFXd90 z*#6-xm5ZmrPySPX0@netafl2l%rGtgo)HZ zh;%8DsAvL&h>E6Z3F<4H>^p~rG<@8153!q{7IGv!V|dFgb6zr(-jrp|e@B;y(SFgu zkE)3lx+6j>gRWsEVT}E1fdYF=da~^cw6d-lv$W1rBlQ#F+kqW!=ZiPBGE4twyJ*N! z`w-XOH-t_W7PL&r(f!MttqDH;(m#9Bqr?zzcX#g-q;>_kWYOxPDiQ z)TH3GqV0`LB;?62(7U|5e&v&&PFz9WE>GiU_8A*?Y!HWU&r2qIijE{CzT6)5?@vwM z$vxEc(sU=CEQBCxSMaKIEH2tjow_+RH-ljxprSRg`}g}isYWy;2drPI?J#wp#Yj@y z9{1{t0DsH;^f;`V?zRT+x>YDcaW8oVhm9@PLIb^{A|0Ebc)*m4c{|h01b9ohATFz( zd6Sb=i|8X}m_ZNO?_5_s@grq@rzs@@1|hLBTUn&&BKwkWkfspGwki%^+%s@>Mto9 z3Nd{9b^3e@tmCD$Ld z!*5p8oFyUmM3(4~U)Q_WLFCl9tu%5gmfgeO8m`O1v+jAy-PfgrIbIXn%qUjup)WsH zP=#!wGR}~CFey&cuXWg?w_faLzJT9~O9?F9K5iFXXf$V4p#*WGXhdphAQ7opdHh|} z2Flf=(ng_~ffoI@anZ4>+9#ic+lcj^5Y6sisG+6%UOm}N(DDtK0{3by6u6HvNqzr^ zcuQa%dx;nlEpTopl%HaIQq22Y-$+W7KQ(4}L+5*r{Ms#wAd4YsbL`9%<1|3Tqut*? zZ1imA{SR~@!DZRa@B5?UjQ9O6_}GiIJn5uR->jy)8wWG@vbCCIY*h`)U)qM8yS`L| zuYyxwUj7Q5tEXKafrIaoS0R#}ISpPJA9 z1bzw?$7nHhQ?fY>D&z$F#h`eSe8e0p!kX!q`ZQ?394!5v6Om&L9_mQG4I5pNLoDSU zZF+K7vXomvc9aI0f`;XTNN+mpY;8^s#e`$#M8^5j9tbw~B*bZSsOg`1k? z{EQQgJkhCb29!Y^!S*h12qTT*FU{NGHqn1gfkXjFUAc+yb)cju_|Ueb0UftK*9A zzalRV1@BqnLUUt??q& zJPz@AB6`{eosNslda{WUS)uwwZ}N{xvDMkp=1d&7_{kVMtY#kn?9z;ZJ`{T84q9lSwxeZt7 zptE-Q8?2oCeVX&hzA!Gw8S;{|V~CohkC<)6g53b8XtJ^-GF?CU0Y|KgRtbDnSXL?@ zLrHSDynz^LEV-0<&Bcf|#|{h!f;95f7EXk$VuQ3>?@1JlCSE`WEn!;`kmh`6+X*N_ zw=jjB`bzLBn7bg}HqBM|2!M`<-O0WB!j}foO{*-1k6by1Y^maSQ;ZUW3QwmN>wNFW za~3Hm)GYWHTL0EiloLfSn4c`S_zn(oP_N*UiF|&)y{|y++2Wy(6|Vcu+9Hp;oj zOU2Sqho<^(1v7VRETAl<;QPg>WyO(}9@TwCqnl7}VQlE4eMsv6hAQKzCT%OheS{9FxXjN|x^MZw`$@ zWneMXquD2*clZPb%ets#=ve~@%*P%3!eTsKh!f9 zPB^oMu)tP3F>U9rOd}47<*f{0x4%gcOkOyBM)u9t5`TkR*)4C_N;r2%2-Mja_@F)q zo)@_SY)tg6*?$hJYG1k~)I*w5%EXN1?M9s0i?Zwn*Kh~z_Vp8>SFG^!b}$7ic9L-7 z|DujD$vS>GYY|9{iF5S`3vYZAzD)kYm}8~&-yXH_1H+}x6`b$con{SC&Js1RCZ@2%m9Me-4O~%wCAGj-6&WnW#ljiCnxydi3>}yw&V= zr6gjACUH=EW&kKH!J+_HVT9(cx$@rb1yZa(gL zcnlqa;Ks@!ol6B0mAPH;2A6wVzBgf;s=XGe(v z%DzVY6$nCuC~7gg_ORPft2|)!l0evILa; z1*$=>yh#a&N6sl0uAQ8ByuS~_?a(xAlFW3ny~tpz*|mq|8GZ2^h?d!gEE+@2WgXvq z3qfv=*jE5=QjlQ&z|V{j!loc{k{sAw>XXO9>RxSxU}vjMl0V&CQhrQ`0iD3Dz^)es zE$*Th95K{M27fjP)T|q2r0c+`mgZxh(Skb)Y_+NYJ`hv+*wu)m7$LmkZg1FBlvX^w zqF@I+hIm+>uYIKL&v4&w($lGMm9gpEG->3*EVJ3_|F$9=0;%iP_eUE3P9T=``T3Oq zH*@um*uFqIy+!KgwW-KQZav$G&)u(|Ikrz;nX{|IlwX$ke_4-AU=X*S$w5|-Si#vb z)ulG6b1oDsgl=HRWB_f|RxO|TRqz)hCTs0T1;Q3$Wn-674luYPdGS{Z347tk;&9U97gy7sy2<+L5wkYhi9WSK z0B~+sOpsj+{+VFZurw!8 z;Y~As697Z$&)N-=Z1v?jt5n_FF1R$+uR`$_lVg9TOs>rGv{l*8iumZV>_g1#OF>_o zw=2)NLoxZW|1PIqKja2s1A29@z0oE9)188MVQ=z+Bz+3gUA~6;^d+v%t!L$ke=uL$ zgkxvZOP=^!E_F0nX`jR|4d0zgCd@9Dk(l6gX|C(0f?vdR$U=Z>8?@_2@8dl1mEQDv z3N5uh;)nm;5kJ1?OHUK!Nkp)SPl!V0uG4OU#PgH9)p5dXKQEF<$J9kR`{CGsr~b|w zAt7&{U#r+?#v8MCxmO!nUJGIt+T9y_fVvMY?3CJkhqv&87bc=1|J0+X_Pr{c23d40 zqr}!7eRp;LQ?$_t2dOIN&MKi4M~RRiVT(boodSy9-)tJK5jlPpy6;k2WWG%85>(f* zcZ>+q{QLH$y_A(!^JFO9KCI)jWnoovXiBfDQYWX9H!Dtt-d)@ps(D~Ad&LWO!v+yV z?wS?>q0Pk3$MkUT-fg)II*$%9>EkYwYig}+LsT-YYoH~J@tQEks9q<)7fpx&3C z$TlL{4i3-R#V(#3N#XEql2x^E?neAm5Z~+n07fMu0hvkF#2sy8cJ@zQ_v%-~Q6)bb zCF#Zh0X45XY&6;R7RT=c#B(b%FgD)2b$Ti*~-~`xaJo8>*ad;3Am}O zsWCqt(Y)?v@7y>c<6imhiRz-Mim$M&g8xVuW5>IsyLhh~M{aX>G*Azoa8yk~@>Pw; zPN3aGp66zhK3~kI?}U_4Wu-f5XP?HP`~DfV?d0%Cna{gWc<=Sa<^7-(gUIoWD7!BZ(@qGei%7 zD~PN@A1zHJHMAwr(R7E{v-OFmv$05P&DOBA0qan@{h#TRU123c9aX2b6ea$O@cP2W zRkL4Z4d7+U^CXda91Fmgt%zQeas?6D|KVl)|2lo$*6Ex%_4o4W7sfh4SL?^x%(=L# zOm##0_eLazXRuvV_&M z25J7gVW$!rxQBX~ydFu!g?7ucx4Uc==)Mx_aD8TgBXET!TO}zZ^j5^{jO1FI%>qJG z*NN#<6<0wh8k#4V{D@qI0Adwv{ZHDsg2s-o4kCCUF1`f8X65&fiptomMP(Ui z%%r2M3l!f4AntyH1I^~OO?T4&W<+E?S*9K6=!NKJdZMq)tCOK3oUQRVofC&A)&;FxeDgPD!k+csBznj8 z#qVD~2ZMxNn2id?zP|r@HuyoUTD6j`0mKlNHphm0P1^3;pTD?deFH%#KsC9K&nGr) z4-`d>@IHzuC7mBHDAncw#(7I@oCrnS?Cw4d+FBI$yn5_DqGlM};n8fBf2^y*-8une z5tz2?)aR1ca!6r`wSWq|Vcp-yDu_R^vz*N~O)wooe=ydgAT7%2?4KJXhGN-01UwS` z*_o`S&NpAOEq%_~*}XV=?5iT565Td|KH_0k>It8`FCYY=n@{WO{4I$n;Fv!?jsrUO?0Fzh zYWhqn#oLlD>PU?IB;9w%EaB!?Qin1bw~QnF;A7A^WJyr^2f{$w8l(7>geq{Qbsal| zm`(UfEA8Y-I0$B6zO^BpEp+t#{?=Jkb{MNG#r(ogvH(DBUYzRFU>|)k_=Ri4Zr$wht>**-Qcr5bq8G9Nqr5PPf{%?9b?4{%qoqkD}2*6kR=? z+aa{iW{}_vO4r#`z2DujC{nYLI|je;o@rI4H*KF3a)umeREqqJ8JaY139q(g{`+h? zG(Mw!8%IKA>jj!M*?3+t(6aH3=b|H|cGECbM(ox5=4WO`*Ymr}_7uWlmPfjG;UwNg zhlc5%9avw7A<3b-4Nro)R=CyVN}KlDK1D&R+b_dGZ%Sz3XX46yXlx&%vO=RHNkP|t zhs|HkKmp(uJEjdB_Fj9f^`zF>2G+4xFxS<6FAUt7L7>R@60eLauobP%LcBPQQn*Q!hjK@=aldVO%5TyDZAC zHsEmh{OD>s>8C(8bwvmc#T!HEY>jXE+ETV5nasnB`2*S1a+gq&&N3|U%XrhaH}@6g zIRdnfeS(H#Y=l?W_IEkytFt*0rA3Y5d;!_4A~gQuF@_p_NJZh#$1B_0_u349vTov= zIJ-=hH>G#UpcD0QBX^MF`$cB%jxkl}lO6BK&9~fyG<)PK*v{)C{CgFag28wgWW<9Zh(J9i_e6XWr?5cup)AG#EyC0qM(+Sk?+}G+j z0`}2XQ^AHzvsKN_AF-Qw^uLG0K$nhqpqAnr4yK(JYFAn}3Pj%EOe9Ddj+ise2m~Ig ztQaQ9Q%DYZ_OlFT299-M;0d$<*&Z0pG8UlLY|2~T54-OVDnDPR#T`U@0%_Zj3V$Ho zMX5p))Vs$vPC81l(XRPArwP4HG4(y_*!L1LlrJ)3!$qTQ^}j$sIPPlUN|oWv%Tmyp z4DWqs(NA61?HFpX8H2snG&QNlC~sp%>&{14MEVn-rPpgm3AJv}^>uc<%x;#E-YtO` zaq957on~?ARNb*R0>f(i%q~muHfW0ZoWIDH_q`8pqMc_&23e?|D2Mdt24|{}j_T2G z(rZ@Teb^8v&1#`M1?SSx$|?WA8)^R<37y(=n6?lmfvVL$s`?Sb!@%b2h8XvQZ&AGeoKfqr~MhHRG=5aO zz9+6xQ>;JnU0SlI`yCk-(->kB=(V*0v*sY}KL5q-N#~-AUu>`5&6^@sZn8UBbQ6rB zgij1pVlxgUE*|Xrj+s(4C9N6}Q^9H0+spT;b){}>j*MtST5e`TMCoV!118pa3k+?X zE>GOfUu*riNyg{H#a5c@&GL6Er2ni%%dTHq%h{%BL;eClj6)wACX?Pr+Nw-Cu!(Bn z82YqyE|XYmfEk~v(|Tq~1GREJ{+Ud=P6>p$@-_4QNQgxxq+%v_j&&Jf!m<}>`xN|H zue~ld`k%~E#AgAIHQM7wm1ERT+;4kAM6^yr(zXUSGE}){Rhv1E7;a|8y0_J>W3=2?n#`6qd$FHol zq><)dqC4?9#lR->brNjfo7|OlPhYBA2m6OyS_IviKoHS)RpCF5uW~|k?3Q{@Ys<`!8}JxBDJc7{l^-5XTn)cJk$4I z^UA;BG{?J3_$Q>Detymn;&Ytx)QO})-$)tvxup2~5{dx#xhs0t$nW6CBweXnHYbRD zt?mjoQcxhxd__=7+9_!RU~?21T^q_PJbs>Vy(t0J8jS*r&~5yh#Kb_@s_Y!ZwpH21 z{W6DP|J33A;o=)e|8#puF=VJ1;A9&ZPDelwNA#-bwGEC1?ROv8S398emjpcD9y^OKeemo=mJK7D)Qbkr_kdH8?DQn2>L8-XSw;_AdD3!H@J{ z=Bs)x%kSUI=W$#wJMyJE?|%`5Hfl8A-ox|#Wq7BJ_8$#YgxAhQp(GGi;te8gA6g5J ze$Cv5c6I^EFh0i?u%keI0s$@^#6n7v{}Xn-UYz zv`5A?-3CT?1@dL%6-+Bwue-m;(ft;kiM~w4?hwvoGgNc1LN2oL3kc+Zi(g!PgeF5n z`&dJj*AX~$!^&|?)6eg1W{q6@FJNKX>0Ufc5<69HdW8805oV4_vR(`LY0lt$7oae% z2hAAo<)r|}03(_&5wit!rGb~L?&hMbU-D@kHt<{0rVT%0Q3EedRnM##hpvJ2 z_w=mO7%R-7EM`rB*uC@YWrXQPnQ=s#jhNd7v8CJG7o@?aYXVgIyHT_!xzSKNu=k=* z8q#?Y%50>8!WW{*Jd9duKInbdGmRMzTzdi{SdV(72!v_F91Qea6L8#0><*eSjzOdn z7q?9`mEO0=sXlMY_W%apq`7L-zv9AzUB;w-$sYtUvQ}ETM9u|+p1)vj4;6PRh!>sF@eex7 z)1j5B!W(oOJTzF8b+v-S7!ICy1?gKgc97N5wB-jJewlQntsb(mE(n z5+KF7Rqs5@@n@frk!e&!`}|D9YZrPg%z{>16)QjSGqDfJRLQ-Uwa9GG!_n5mqX@N% z?WHoGF)u;X;t~5&hRq~3B)bh|Wc!*MO{ac+;xDk&-)L}5KoMbBuwFoG%1x1kGAreEwu}R>4s4m8 z#^04#WB7#AEJ!NHu=s+$^C0-8PgNq@lyoQaExkHCT<((YF@>TA?4jbBG+fPlXE6S(BHU%lZmPIXE*lif`6jKctnX|OwN}kQ28(1s*}gn z6N4~uGeSqhJYCA=y4DvvW3$S>RV;KF z04>Giz>c-S&(h}@I!h~%hPEDk4Nptc)}^XM28kgFcOQ#xM3t-K7$0-S@=etaye=J{ zZO#E=Yksbay)?_!-;DK3*Q%bWBL{-`^OS-VN9zb6>UDm$7QepRO)aQP|FO|}D6b$8K_Y46p#nN^fxE8n z_4Iz7qZ?UHZM`d_#k<6jV)Ez2&9DzBc({)lBKJ8!`*MoUqPL7y_Vr!2+Vv}2R*K8| znP?}4aRe%$YE{y<#jI&*{}mMjv+(4a17=%StXQA9)yzlgmC3PWdtINb^Y3btmszl; zh*El171j$MWQfhkOm3}9g`7OQPC75im+{$cx2Bb5Ba6j)nppQ79+=#4|eL}(flSps)mb412-NnHqW>K4* z8PNzgt9xoC!!zu;zpQaWL7Z~qV@@_75iuG8E_)U03Ce5*_uC~ZKP_IyZOEF?Gdhqf zzXdiLEEL7yn3CDoz{|M*k)k-OBV8Iv51~HSIIIp9YvtK=G>aA)3od6`h_1cCXAMgG ztddhvA5oW^Wzi~zGR~Xft2NVN6vQ<@uep(oLnlp>&V|6r*VZHPAN3iUx&xdeIWo;o z&q)dnb!Tr)D@YkRU*sSb3hFB)TFDToIm5@VKX<%zRzdv6L@vFx6c&^qSc+94Ld|4x z9VgzQ`d0)~lQ@HPSrQzk!zFFeCnQu%`=CQYMNJYa9uP@h&sq`g*xyKR=}SUIUEK7F zLzaYLSUHVbI$RAx{3qc(+sVwI4G^N;^-BwJS^seYe_lRu;jynj8MX$Cl{Un5O-{pp z+80;?xPxv3oq}}l0K6r05ze<@5gbKMU(4%{GG7}CD;=dc8oEx^q5;)p5$573YR48R zstrC~u9SPe*Jy zBpBESI!c;J3u8bc`H1!2k}R|Zq23YnMHm7-J55}uK)qJ=!v(gzjBROSl2w6Xa4EjG z_h@Mo;op3H_;Xu@tk=L>TkPQ1WGxF7N^9_1QUUK!X*;h1J5ulj5<8ARUn(cXY#Q_sCGUJ_m`Xa&E<6J0Dm!dH^pkQ5#!SI7 zYWq%n;^U87qT%zJtoKY=(jfzWM!C;Ld|%Z9tZ96S3>5`pjU>esP!itcJMY~Kaz5$g zKJo>Gf&#*{fp4b^th#dmQI$-d{{EC-1$GuYuTxb(wX+3*X;9kvGO%1C$iuteM-8Wl zg`TD23tLf#8i3UDK1%9^%Mf#H{XV7j``fvZzQ*UIoxJ&=>*Qd;UWi6lXWY?AygHHb za*@>)rGwi_@JxfS7xhf@e;H27(o7BYm?A{U_KJvGJgt8q(nKpt>iOGXBFGIG zUq3cf)N>>Hp`}~RTDctKoA+HmZH@(D0lLHvGb_^Z6J|NFT?)imdZ@aT!5;@`Q9iGt zl&P_5BVZexMDfxu(t)~P6j)P1P((x|=u2>;s9w}5@H|5z*pg}{Yd1G6LW~ohd{cj; z?x8VrE#4`|n2QrgRy1Of6Pu+Qi$yqZ9y9561-jh=SgqYP6-6sGUnXIH1zjUw#2@wq zokmHZ26;~>gXq%gXxRtgT%u`R;G+w}vpk;V#NA}gAtAzkc_D2|0xFIDc5Nr&30liuX#&S$Rz^jf^X*nb)eg$Wk9MX_xJ~ow)eK?WlipR4!GJL z&cAp402+%0l3t`rfy>o$bL}B20i9*N`CQkheCCCoxeKa@RHAkJiepmkG*{8U<&U3l zUDxq3a}_ABKCP#m9s(9UsgrYaGR^%j{N76r37CPw*Ax`};KkavDyfrF+L0bMedlGi zyo{DTjI_hc_66>&eTO8|THIaPA8<8mH<>B5_5{G5{Iq=EtOt@^Hg@mN6RuuZLghah zV$1}8JQF@zXun*I_pH=OW4@3}q&J%ELKB-L)=0J3`6jNDj(aX=vM= zYFkLAP|QT6J5FO?lgq7l6&obcfms$N zO}dAIM?coTThh8vg0sC>C~(zw_3r@-J#!!G%?&>*x-_#_wd0SOQ?mU!*09_Q`oSuy zX1zc=4f`}L7AK2}8w>uxYuF856ORmqcOX4d-?x}?QQ*o<8=8nrfLKP2`Yg<-t&Va) z<%ipf#12h#DG38CHdEzWe9R6vXiyp~1gRGdL8SSja}Lbi!b9w(UAlLxo9Z$<(~;;< zxdKtU-)gpr8Wx2WQKX@ndpc;8pVqejEQi@qsoPSPg*h6a6Yqi>mU&gu&peKoP(!!h zzuBpvEBriRXe#qe2B818tGlW%=Pv1krI?rV;fyUg&WFZmlIe%`R{Q7LIlyFWsE3rS zB(x5#@TOQWNur+P(RFDb|Lx{MNZOwZo|xFbl0;HNvgMSrJpz%SdBbtraDg;(~Zb!}BuBc~#QSt{7)F z7eFaw-(Ik8_9{|Eb%Qgdcq_%ddW{~b>@{Nw*|)+n#enPZ>-31W54uJ^2u6$bH;*;H z&AlM8JwZL&s)NEOJdspmIWM1e-HzhR`>tgv7)}N|zUL~HG@rcZ_@1wHYAld{pQ^oT z>rV-A)r zE6PT{0D`9*jQ6j%R4K>D^sVFyvQt~bPX6H?kf`sYzbkdV0)4WL?p-nSg^YxAM>pD< z0irmAx_E*D=0@zLUrv1SH)E!`J9!du;(cF#_X6o}W&q_R0R+D*@(Gm#GGVf^i$ z%7I}*RA43_xxUfQdqV~1vTbTaD?ldaGi>|&PcrlotJhhmZ2PQdC~oo|*%B`a9?;mU z%3B0Q$xPAm`0LgGsT=>la(Of`JGjCWV`9uygw}ra;CMN)aCAD}N;s10xM=r1me9vT zSSFn*H2dj~oFtMEcs_O!^bXH4FA2*iK<35B?DN3qJ>1}YqX_P`lXTU*yw!lsGgv`< z{>qDT(+Gd38-ARqHHVJXqKYlZ3_Yf}>Bj8YLY)BySJxtLl-$#07UjZ>OIGG3L7%X> zAJ9nNaBumsZ=D+_f1j5hY%)|jkXk*=Gjsd@oA(x7<$XkFf6j*0S7wo7%#3kjE7-#^ z=LxwPAh7fQL11Ts7$Vt-SbR$Z!%=-WQmz zO0)0m{|?@a!SnOWER9sf$}A-V9R+j0h0q)K;`9Wal3rTS!gXuu#MG>GjiCe_KL`p!c2{pSwUFy$Lqp7qgxFhwBX z_i;-5r>7ui2!!C_;|bP!bh8f5`Th+Oa=EfvL-#>t4eWAhpLIj|A3{#fZx3PenUJ_# zZMJI8oC2|#xRqrboqgH~(-=;zTD1eyuMv+!VCbF}`)PM}TVzNq3sHUjN(ebNuu@xGwU z%x*Fcw7!zR@s%h&Qr00~wCVEUnXq}z+^dE6M6_-D6k0Kqv@^KN=P%4O-aMuq9`q3;uimGn;2ue_WPLXNxsr-OweS%y1L z6w%3H+UjHuJXx(cs}0xgJWb}&Oh=`Z<;V6^EgYP5F8TfIkX6E>nKz>?x(F|>``8Xa zZt|7d-b~>5++FE4tu4ctQOOQ7D0tJ4{tI8FmgHCc9Wf@lMhT?T$Xv$d%a7Ryx_Y|!{}#(LyZxeQ z^ryV5>T8HTP`<42*-H* zD@NuF2`cZa;2a^f|2L3S!}dKn{`fP&e0YBPBIX^06gL{4k~`1exos{j8q{Du?MuB2SRxpGSnle&g4Uk zMiA!7JccO5^>xH%CMwesjH<-vm!|EG$s)ouRoC3;PG`x9D*GcY^F7sTy!JWTgbbiV zLLO8qdtis#p7<4+`;X5xUrzafwn7L-vesqoW~Uf~#RzL?!^&?DhQI__&wr-3jIcPM z>sEF*1vdc1o<-$}65-MExzqO0o4l zU|s^C|4GPBLv@5X0iI_bfZNBdxh4pST>aAdL6;-ThyZNfOM?_ ziL^Nj^%$i|1gU*1kFJpo`gg=ryHS#`5@y{kGN^^wzOrt~li_o7HXItajTS^WR0-{- z!O1%LWU|Ij%Hy5t3daN9eD56Inrg)F3(r-O%c{WB(p*q+el!@SgIa?h%HjrNjX>ILtoDf-QQn_sgJ12KC9&ci_7}EI3XJ z&7C=R=HA6twPbmLprw19|9~ z^VQ67-J>^X^D|pT&7veoB?vH13qWG9zdat1t{N&1W}HO*SlrK5x>c{*Zjs0oLYbWo z*QZw~*%kR9wf#G_7t9>ObNm@`xQNg-WTt;Y0RSsQU+PtEj#|^AAK}gb!i#L8g|3O=i;W_ zt#Dk3hG$?mk9k>LL*GEVq0|uz`GQ^k-Eh zW6EP(WPg%5N8a${s}*!hfRj=ffhUFsr>$xF@W6(N{0C>KFM#n#S$l$wMtpJR_@|RV z*pIcBj5V&00pEp($Z>U5qW`luAvrwXV~_3?oUshIYr<+yBsVjAZ^wxHy6Ie|-^ENA zpR{4-3g7_a$;B94r%(Cc3$GTZTzBr6T6p)(#lIO20W%-##AtCQZc%IfcZyLs{qiQV}CZnrePIv?&iK4~-OtF-mc>Z{sIJ!l8Cvo!nTeE(}Y-}}7 z*1*?a_U`mAwB;;(`1+A^V|3zRuh#R5W9wX|N0|Q1pdg1k*3B8D50dvjcrDg#=UPg? zF)}|JFzS(Va@(et4YAo@b})X{l2Th8Lsi)b8_I&K|F_&W8;7lLe0kDyw*oYc{+Re0RCct2IGu%%QdhsQk=Gh0n$9 zvE4jQ3>uNlu~I||O9HL-bcOByqW0(FasQ)b9gcUmorDwCvz~~d=@-p;6od6$CHVrO zI2q`Pat0|M_SvAxtZQmhyTOfxvRr1{f!WJ1#^rORj*~_LoMepGX!@^d_d_b1pk7QL z+W&!*OEQiJoU&xhsv2kL0n8~t^ecXnF&!uCalw@VnizMGxBLFy#naF6FFHl}GJMO_ z^@H-4A{8pnKhQ~}&m&I!Ucf=}s=xVTh&d!%k}2YB-+L?TWy#25>;F$;INgnVP2IjF z61E}y2Lm-{dEhg)ft~Z_$_I$y$bax9yF_l!Ai(rCFe2l-Vy?q;ZKRj>1d=gFS&Q5k z-~1~4Y|)#_8Kq>Ff|^K)^L(p!*As7H_?X-Sfi9($NHY(E7@2M5(PWm9@Z~8F*kh`z zhG#mJ({ng-gUgt`rP+!;Mj8RRbqIY;z&e7(Dyj4AA;*!#1h=Q|G^G9;k~;(Ifr{`f(dVnJXVC2JS>Y&hmIF z>V}#neQB|)0ke;yG*Fm`K+X~Bx?Cu;io(Kx{kHv;F(4?(}NTAa&qJ zqdXv6RlPZ+aTC~yGngLgn??JLvJ0a8hF(~($}y1dw$r{5!4;wjngL!Q)8i)d%6LJE=2LRPKY4;Q=~uu@v!$bK6T z@S7ycf-(Dj{s9c^f#Re&kjBqfN+8#4$l8$_wor=KfwV7kkq(Ql;$5}tl@;P^pI8VG zJ3ufUg=DEnLYkEoD80kq-#@qOgePfJ=Ds8GvEjzwP&&Y>d(4s zxqAl~+P+}>Zf`3<)YyW0h&=>pd4%Ij=qb_FU=Tf*y-WNdg|D1Kpj^3VshS<(6WG>} z5c_9OT>-H{+~+r9mIVgx>jYQOul~u}m{Z7-{xH3G%Z+ReT-#aofjReU?s)nP^j=H* z5E*4sXBz84WhswToyvayFlzMXl|hYGeizF8=7uP4MhUU1l00IkL?FW@_!73EHF2Me z4zFZ-x6b2$v+Q|TIHZ+z7TmlM$-e5iMJT`-J69Ieg|=eNT>SJR;z{5_;^VWB@_MCJ za=mU>=%V<$#(Hx%12JVd04K?6tLr8x#PCjzqCa}!v1A0VE-@EI&4~KisvNZekyaz! zuCOI2Gj+;149AR0&>G?#m;I+Kgq7<5k*ry{f7UF`H3IY&tq31zx!SpTmu6-cf?&}R z$>aCSJUuBHBFUlZKj1IAzr4T{U6me2F`~Fzf}^zy^h00tJg|%cXLrRBP-9$vy#$NA zo%4^Dyi(7P{OwsXN9u z%LO=CH>BBI`uES*(`|^GdB9anv-Iu?Bg3Ig zrmb8Z%95~HcB_d*Nc5fbmts)jXP*_%vD{=mkas#{6y65?SsiJ~YK!If4P>s3EVEe0 z8MNiP!eg^zmd7454NV~LEIPzCxRYwH*m~8>Hz*Edf@&A{i=%8NXQ*X=(6EBVH^@=z z^4GG-+ChCP#aSx7{#k03^Ucgpsy<9Pqa*cYE2T%aR{Q3L-X1kDnL}OoU22O-ROqw2 zXY}sAi;9V!pP@0hmMWq6{^ZY#lO8t7&5nP-w+xL|ADqF{!LF?%F$f?_?CG~+Sp$Vy ze^MdUQh~ChAa0ZYS(OD%dQ?^h-VnzFre-0QCq6|D$;yGpZr~kzK_>`Z_zES@UaNBK z3yHp-exEY;yo?kvtTH#Fev*_96gyji@x)Qgr)p4d>GQFCxq?59h&6rOjBCh(QVD^1{1052Tu8WzQhI>$+^sM&62crkm zod@p{I#gl7pws~EOV~($OgVRg-L)F<7 z_2cVyeqV4_scPDEF+l0J+}95_5a_0bCheVm z!hZwErx9+BA4n)w-3)edEvw&bIzA)2Dktfa=5@Qvi(nm*%tI-l2U7pVOPvBg;`?)T z-{V)oQi-5SUDRyUL6x5w zc7nNw8!tOUq-U>VkCDL-FG8@Y_O7v_|8;hJ5&Lm3#z^LqzpGZNoI-C6&IGpUu#WTF zRfK!D($3YAr5&>Z+LTwvKV@eu%-JI8v7(mjQ)JJ6K{Azhaf``h3L$@vi<|%V5th$C zB^qyH;4~9X`YYfg0fJZCQuiQ7s4%$yx}(RV&k-q(aGe&ANsEfA}u#-z?tar;B-lD&K#27D66@5UIVTs3eDzJ<&Ro z@cCaQKh>N*jOaQW4K-a9HMX&JOux+Xe}VnFyF@Lb&Z0aJf6!ubmYH99RXcZzvUI0` z`{G%)iybfCigp-YzPjk_Q_il+{}8q~7{OY{8gf8vQ0n~d;d-+SsK%g$A6X5+X{eom zTVyYp1Z(mRwCY36=r3aEo=DapdMY0QDtD{>5h4+y^cm|}xh?LP)>#Bkyh+}iGg$a3htj)pCPf?y0O ztn6rp$8S0NDZh-=>PCi@ypf}vN9mK(ujO=K>b3UEvS=OrfHIT*r%sq0Ce!CLjiUb%WY=uBJ?@I+(uw6PA z0milAJayLa8O}L;xAYC~Z#Dsi@(~T#07Pq@J|(PZXHcPP7QX}5O8nneBi~_CCxSHF zEf`=TGRz?a5kkoUB_j{U4Q+rNd)asuGpv|YGsBAzY=eN~RJ)}sf*}dL&x^}?HNU$e z->u%FII~rElLANC=PNX_daGDbXD7DSgkVJMLHU(W;;Bbrd-WDv0SEodB6;vHD6#%h z?FZ@N0HWJ`aD-dIWbaTEWMZG#5*+;;CSP?#$-)ryF}jM8Ly|C06m+Z2Nm2$sp9h3~ zxwhHz!_b`^I^;aVAX&Hs#stoAGtWWH-vYBqOKU!t-iLr&Tic7=tjd$@HCcCI{@Ibb z^dGYj(0sWN3{x+HCY@=1cSwgLP=NKyslR``n)7RqA}oVtL3Iq+FSUPuK~U4J!)3Kf zpGn`9{cQ*ODCGk&4M^3yH)VhYKEc*7)77n;KoXigQ6^-631!@|kOBuZJ4ntSWL;1N zrT9~Ae4CXPWb_4<5;+G$%5q6aI|}r$qz*babAIn5?S(XShKZ44D}ryARa0Qua1S)3 zAddD#w@I-X&mrpf;`)tZo6!*|kLztCrR(e{FX{4}HK(XMY}Ej`GOoViq@5Va1;quB zCf1rAkm_`TQ`^X3TXV-P0LLsnK$j;dOe-v?$sa&m2cKEc>nN03XLKKj$sFJzNIx+fWR)=#Ze-1W&oeF^Xdh4UAtNi+WAfSE!ct+&_3iY}LC z$OshkU$|qhWU_)C3@wL@9xgK5=y;k7LCA_iMPk|R3D9=s>a8Z9^pPK0jReT7F*Ttc z=99tnA(rWbnOWJcekKwxH++3~fJlEqHYvV&0B=Mtp#DT4E8pg0J5rxRQ0qh(J$}e7 zM-g(Cgb@q%J;+`=3Q2H0d>y2=h5qhR!}Z+p*uRR<-L{W9N6*L|gyB!Mdmnn=%i4Sb zzL@a`%9ZN{&F)COF2ZKg-ED}R^1PEB=gjsLkL{^_tMojwA8+Fe(GzHZN!{3I0a-Iz zl7K~VkaKVsbHBZ!tM&W|1bZA0UI+mB+Q~4G)}PULQ|TVD z7jAMe&^lo zLA&G@D2+7tz2wNjHE2(*{|uiP4eKp0It!{&@J)AX%)mHTg4VIxjz|keAE|l{Tz8UZbJn~u%vTz*h{C&z za3V)GZ49{t$C=%*-0OI^oK=S;n+5)v?1bk{9Q}8H*(rY) z)n+kKe?{$i#<^L*wcp0u;K|y@7K$lb?aTzZ?;>$}SiAbe^g%3|kJw0ZR*vF4e9fok5Tf$8V8mQn zpIgo+17hpGUB7ZB7Q^p-P%1AAITh#eYyc4*VNsYY(X=(-{q8hdW!i>GSn=flM^NAY zUXZ-`$Y|)bu0VyOoq=bbry@nTi{bpP_TU2Dx0CzDZ3Tjy%+^rvze5P}0P>nWXyjd? zxQuk*B1#?C&#(H1uE7zY*%NB1+c*tuozBGu;4O(iOlT+O-6U|WAak6@U|f0 ze)L=(0G{{&hkcrpI+0_c8)K_%L3?EHZ|tzUA?+T-8Jq){zyhM9M)yarx3LC@0opr$ z3)-RAq;+5{EN7s*k;$w6rOt|*H_^UDcoZa1HXs#tv*p{!U-ny*F9iHBn0jrWs}{p^ zpmxsXXXX;EST%r7LU)00^M1k(HCqNk+k*{5g-`mM?;b7a@QfuE0V=0{d+!Bn&I;hw zP#lp_lTd+m`#bPIiO>W?Q%wXi&9Bg6(+Po~N0%OK3I<438Zk{Xj2jY|wIE~VK(M8s zwe!}cJJyfh5hCWlnXEgd+-8`p?S8}$M_BdP&84cx%9Z6tKw)zkdN5NRZYS;S?yXGl zu9*6n__uQEqy7m-Jbc2O8?&??J4|qIVtN5A76fYogu#d55F$ViJ`sYr5^gRD0sg~j zB~;Wil)2AJ$KHK0omXu~8a6gtx?Nl-?OrCMht3~eLmsqE{6+Odarp+W#ElIgr?wXQ z!YgI{Qw0dXR;Zxl*oNLOr2vhF+UZ&pCD!$?Z=t-`f+Fi3C~w~6*ixFybV#d33)trj zb_Flr~r3C_Z+fRt_p0oyFr@zs(fEa8C9&zolUhVb=xyD=YLT9F#kc9xXIL5|B7 zF)?ID&xR5sr@wVRmRsV8vpuWbm`M+w72MAjqsK!32rY&L8|@&gnyDc* z8CIz*P5i8S3{gubZeyeO1cx<2g^i{uq4wI`Ed0Wf^@_IEk%V5#8eLwtoK>4QJN+(7 zo9*Ik4{lWDAv{Fxb9;jE`rOnFZo|@NO^R)RqVkBfbsn0R)eRpoKsCaPt@2LVt z1EZ6Ygs7_O-oqia@QO_RBgxbr=ej_8{5Tv7ZHZHMv*XqO|Vr25Tcd( zrFPiqia>%Jt zl0#Y5REP>KO6AlD`+g1U>e|<}uKi>0?MIjReDl5E_kQpDJoj_o_tPhDvn-PR*rOvx zD4tN)#bmX;0Q%g3BI!BAe2G_1-FqU{`Q|a)$oKu$K4wsDOj4rHZ}s;iQ?|~#cG6g0 zzkC%HLV>uM32e58Xq~*X9X<89Y1LM=@cCpwYxp7!@GO&NdAckkQ;#X5c)&Kgu`$h! zMwEi6jVBmvoLnfPR(rVwSfh*z|Esw6&61*ObKt;5-`v5~*!AG|G8tOcerRuA$C8XB zNcqa;@FP+?KX8f|Tu%=BS#}pR`%iY3aH`iWGDBEOsgAus-XF3H`w}4Oe*CCv=A5Lc zszk(76RxMH3&WPR1DM-gR=9TsacB0bnN=iMR1`O1O=W<$&<@^@W|i_he(9lX_#7Ip|v{Dpy`@rxASUX%z-cG~i1U6H99UN9Z^tSqRKMlSC%ez)(?v6lQmY?+JmqeyQt z02>x!8DENn_UsMSRe8PDiOk@NbGYKpYKOv}GrB69+~a&k=d~i$86Wa_L2?x7&}U(f zg5S@|j`&es-1&{;I~e?MLfS}}_CF~D{^!_WA6`np#gI?pHHcnNr7CyH!&DA}Ny#HyXJILY08dZT{=Axvcz z!$3@PV*f~!s_*+pSFsg1z)$YgtYTm)eNS!Iyg+Hh6E!TqJKAVBm1aOB(gfZ_Sw!Wf zKXlw!_}rk3G3ft>Ldt8p;|(uQ5RAH1L!$U@dEB1JxbP+nyxo%Q?E zL8*5H5+2`F&_jqr2XSJ=EWd_QmNMwR$iaxZkpudg}w`WONR&22h(zE--2Ft z1^+2$=@F>>M<*cZ)ueFoQJ-b95)u&7Kty&zyVVf1%$I;m_=B5vGe~KnMBO1EBpw7M z>9-j~8XY@mcDW=AO(e9>+{E^C32{Ila0?#N=2bGX(AW?q6Tt8#&;A5W>chugA_f(U zB~`NPMXqW4o|% z@9jsmNA}eav9=;5V}f9)o_1>aNDKR2`*tM>xYkuGB{z2~4><70K_sOxiM1RF$}bF| zevhW&B4P!!G4S>`QdJvtYR!g|q_{iL1QR{3Q-Ii+8HT$$c{PXvbBwlOf6C=ElRI7v zd~u!huQO6*(j-`ry0Q3#2ezF%asRlIN|e7%cH1Hrv=(jYDN@}ssOKFm69;(Rf2!H)N3F+@TxGLipfDOg~0Ab5pQ(>8xZ zWjw@OUXXu8lo7|w+mVw(6*+y@0b+)PSSN5dBJDm3PP30|ToK)*mLB;_@3J9!+gV>H zzmR)rzP&{G-o<{a;bbFH2}jCg>jX(BIpT3Idq!ifXs!flnNmxA)!zBV1~2Od#CruYRYw38k@;#v^8 zRyr$%&6IfrX)XQkx4Q3~Boj9a#1~HCX{u)YucS09Vu11c4y`XfcuU_lC1c0^D7n@n zaT!0mhW8KCQ^vW_F6MA5CQIgk2|}a{WEy=4v75pN{LO*TGaqpKW`MJ;%<=Y zW7d-Hl8FTBA*K2PCQG^$0vRK__>@{E92l5GEWe|_gia$#zG2hBCq#z@c+oIa)5xwU zty%HPN_Cp61ze73+a8~#^skE#F%!C;YCNZcvQQg=HY>WlEyJ}k+OW|BNWu;AlaMyH zvRf-xDq(R*(yrE}YEeTMin*cnTFda<%x{>s(o|Ni(+lH~@4j=a zQ-TWYzh7^_X9qnW!3w6TFL{Z?KAT{$C>B&r6 zQ};fTzd2V+gk_#RLkUR>N4!_(7J$dC(#PAaN4Vb^0e;ynrlnEr&+WB&Q$kfcC=66w zd)iTaFWVz*HZ61sZ;)Yc#APmj6H<0I!!_JYgw{`NUKg)>-22zFy@PwRw=)~mdF9I* z5YcQ@#&uP}LAi&FVGY)6-O~#XPw)HN7<~Y-D02uJ>4cl`5+VDU? zVM7?Q3S0h|B$lcaYynApt+iq;T0rJ+HH%l}$upg~=)&w7&5jX{DH)dLtXTAV5{KV% zDf3sy+|(7ZxHPt(M~C@=vg1G}Zx(wh+bW1@17)e&gHuV=)z4%dY=>mMES``CSP!x} zj0Ob=+q1;|&h2Z7*ji4Fw%UEj=6O29G=xogZ~=6R-0jRTEjP#n-wBDaS~Lbkjis$c z!j#}s>tl6FnkU>?e6s#KFh|ZxG!@)zw!nHtENLUv*;ta!IYkWYe$$Fqn##9YtuKh4 ze&A_iyoo|5@XS(E-8A`<#Xha(`4#C9`BM@jw%1T;$}lyK6c^>r3M*#r$XTT*Ve>9T zYc@=*UY2naAe*rbvzzxAfwX81#X@ zscOJGsytwU-a)xZfE@oi+E|=EoH2iCjq%{cmnWBPsfAzQoP0ZTrD(P>_#wW#q+XP` zU-^*C?nS|V$*7rJG}Z+Rui-?~%dL8GS;iA4h!k2fP3>%g6e?SM?B%2&d?r0XTK%1f zQAS17sPJmisdFe?U$oopWg`;CPV*>dbq%J@;#JsL*>Gb+g(k4pX5Th*&NzuSfmMrp z-Z{Zn!Zj`briMyw)_LBDS!oGM2JeO9qCl0(-@UhLTMt`KMAGqCn)jB6r!->}X#vOD zm(b*F!c#euX%B3u8JQ}m;dnR9n~^^3WEH$M#d~?fY_X+J&zVWFc6yXMbUjF|HMR1Z zuNJDG3eDE0(l{Yan)(XQ!%uTLR?;3C*n1g$iV2oo?vK*Z-3+rjkBz{hM zf8-{Stp6ka4Dv=!II+(E2TBLnpGPhG+Nl)A5~F#0#`Gb{2;2w0|Ku_NrUB`;9Qf#( z>~hQLEq5JK*NnY!0QK|*`_O;G-z$NF$Z{s4&)m_x=|Itl&O+ot#sOFLv_Fj~M95h3 zM<;M1$&RWuT8T&^4iw2ZSN|Vlq6X`RT>oQjgPYkz%ze@dB@h1APu^ZM*`W@mOCw-TjM4`;s zw?_PeZNZJ*_a2!PDRqBVPkugNsZU`P&Qs`_9V0vt*a(jS(#aqVE?kl_{xe9qbM_q6 zyDJYo;f)BdS1W%)9>8d{i!${%E(*Xjr5-zMp9 z2m#qIHys>q$0EeEz#(R}^L-;x4WBaB4Qvy&S=^`I0SC5(w#6Eg^V$%69mWAOa1?R* zB_H)~HFFq$>gTyn{+e`4K`2LjJd^W}R4Z6Z)aW(CPS`I~zV{}v4TOoEnCB)Ko+_jvTX zH+a`5VYB-M0Kq6qAowTv3}$6SLQdM)di2AeQGdbdyfuECBCN*<3hhcreMle6zsCN4 aFfjJy!aJJG9Tz9y%W~OjX0Dmbk$(XLL1KIW From 676ebf18fdeef8b955d97e03492bc1e603d07896 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:26:15 -0300 Subject: [PATCH 118/141] docs(dependency map): add dependency map mermaid and diagram files This commit adds the dependency map mermaid file and the diagram generated from it. --- docs/dependency-map/dependency-map.mermaid | 48 +++++++++++++++++++++ docs/dependency-map/dependency-map.png | Bin 0 -> 98373 bytes 2 files changed, 48 insertions(+) create mode 100644 docs/dependency-map/dependency-map.mermaid create mode 100644 docs/dependency-map/dependency-map.png diff --git a/docs/dependency-map/dependency-map.mermaid b/docs/dependency-map/dependency-map.mermaid new file mode 100644 index 000000000..6378fcc09 --- /dev/null +++ b/docs/dependency-map/dependency-map.mermaid @@ -0,0 +1,48 @@ +graph TD + A[main] --> B[server] + A --> C[logger] + + B --> D[handler] + B --> E[middleware] + B --> F[service] + B --> G[repository] + B --> H[cache] + B --> I[worker] + + D --> F + D --> J[model] + D --> K[commons] + + E --> G + E --> J + E --> K + + F --> G + F --> H + F --> I + F --> J + + G --> J + + H --> J + + I --> J + I --> G + I --> H + + C --> G + C --> J + + subgraph External Dependencies + L[chi] + M[redis] + N[postgres] + O[uuid] + P[bcrypt] + end + + B --> L + H --> M + G --> N + F --> O + F --> P diff --git a/docs/dependency-map/dependency-map.png b/docs/dependency-map/dependency-map.png new file mode 100644 index 0000000000000000000000000000000000000000..a068d16ec3668646201cbcbb0586ba7f9308c39d GIT binary patch literal 98373 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

2>8>0Xp4 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

hw+E4KW!XP0Vpk=mFqgmVhjBx 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�CCP!C$!#6RB1bRC1ubxw9d*Lyn)1-yDytQ>kqLC0mL+64DPmQbGXWt6>_|7vkWmRfspk@{wV8otyWeIN)d zm`&9YX6L}nZ124A>Hm5Gob+qqQGbGNuib{lPJ2;o}c?-pNcZ& zXwin}O5C0gPu@O+z+OU*!?w<@)+DNyyKXN`Zxw0qXkO7Uy@V+%N8`(MiUqEx2FlN# zbqn^XUXQ7=#2?a09MHL4Za3IZ(*&3RL(}Fdm+#2C<*W0<|D5rNxl4ra(A>@T9IMaK zJK&`U{^geE+ALR36P9B{cGM33?%wR|julyVy(M}(0!Gd2BObspdbVepbzOr8&WeIA zn9c`m#OcDAMyN~n+*<|liQ}a3CC9eGUy70)nt;EU#5*FteZFxxpz>sDf2k*Vpj|L* z_j?F;sdkx;_V>i^8EKC|ZQH?t6m5!bUXCF0u^gc|#U?~$BfpTbQG?(koRv6`7YsA~ zUIe%E)wx!%w&p-*x}>T`G5TowFkX3nendqY+F`j79IuEfvdVE$bPCcllc5qFhq)F5 z0F#dc;NevbW3kvnynlH-oqq0SWE>6Yxie_8n26Jz3ODq!#+s|&Ro58=#82ez zwkxS|e(*d4-er$#A6hcB@2}k!WP^@mmr^f*iOgz!dwU#=8vBMa_@18z-FjV%DLf=T z1eU2biZ+r*7#DYG!?>jN^}dOyCbV7kwXC&gXa7#*)41rNPsO z#FzL2%)&X|i~tvK6h zS6NCx(tXrR7t36N7PWw_1$nJuE_s`0aFAV+M4AXv|zYSK#6O!xDlT zF+55$Ex+mKF@<2#6W3+AEB9_X#Xa^KwXD4hB(MmQqJ_Wsc5ar{?5(VljYv2iq{&pb z1&m9Y9@P~YC3FUuK&3H6Y$n_7?3Zw3MyP8UufLdAjjGCu8R=#ueo|=cwnPfQ01_8C z*tyPFPnSU;#@KdQj%c&l$8zn?z=yEULb&wCn!`P4$wC%`<5D_967EUgw|MP>Glmxk z4RawHqfP<@hg%)12R)JzX0IOkNMYcF@8QWch@p~U_ywjl74?dDa?z6QWut|T7 zWQ(KEI{X2{vu#dD|B(#^>bVC+S%y*v6UxrdboejQ<^Fa?y7d z!kRtH6DL+>KrN^I2nSx3@vGG~`PJu!-X&GaewHpLd}w}sq0G*oFH)LQizEq-Iy@v) zFrC^W+$;i&ZHK=9747k^LB3im%&^S^1XUb!E0Yi8$hcQIkjhjD`d+PMvZP$k?=SYp zx?nQH+lSD8p`iFqbu=EAz4`B7Wur7B&H}^;kockkG}ypKty@e0z&O$j)KK(-2Yn=> zimf19LGE79?ygHq=m)z zDc8nDMF@6Mv=PZWf&`HX7iqdtfF;uzmB8fTagkn0YEBT{`q_XKZ9L{qL_TTaV&2hF z9r_%b!2RF-f# znaI+^J9MywQxOPfSlj%k{a==`$jiCgKn6yz4(;-4(N`1B*E(0y`1jA;T>SB&a6n8L zG%(KNOndu)0fvEjo=1HF;pYqQ6?*kI?g}_gKlr+Q#mBG2!wfwL?vmK1&B9Q{0~}p; zG|0Uh6edJWO6|?p>iFQ`yZqkaqP@=}@Vi5VS++l7R4kRsh(CE{-v?XZa- zhCS8jSn=vJ|60-uYm{av!VS6lf3zGF;cvcoFa<4Y+s>{$6#zIMne&G|dJKJH&Eg0A(8SHn zuh_$1;Jp(IT=gtEClhI9uPp!b{!a5PJ2uFWxX}fb_>J$vhzr?C*(&l6nq9W9#)`xX z-ofS2itfCAO;f?X?ha8@`itDyI8lR3!N+UG8**WQ)Js=U(XQre3&wz+UjvRWp#xFiYuk%^wQq{%`}hNWyW? z#;Bpo!oxl>1XRot%zh_ZBjsGoRt5$JV|S7V_&!4j$=ZcFCqua@lLXB$7Nm-?pQBH` zGO{yn^@^x1=7X}piYaoKnaxgi=c>9(;`H$8qe?s|AHe$;obR-h;CYK&oiBTtb?(~M z`90A7Js0tXNf<3^m#Q0mDXu2rOx%qux{p#(4gi35ufaw7%JNk|B^DqS%;VEMePgVs zWXezfW-sek(M3l7KKDZ7f^LFjnq(Za?c#e=8|#&e<1LHz3SE?r2YpO4h9{lhSYk4$ z#iQ-9a?{+f?#~xL|I*%ZH0cXI#&(7BzLK$?yXfb&*JBeCy@=+9-e`)+rAdpMc9LO6 z-Lu=)d--SC_yD#blB1YfiT&sK*RO|wk*Z@{<-(<_=J}`IG8@d7VR@W@9Lr$mrI@Jv zq1N*bBphe!ig{ixQ;Co*T555BAv$h&iOa#|`-i#cF|CD6l@u1Cup+Mh23SBId zTP!|Gq+|@?e5*a0{+YN8x2pxOb2yo8eWuyx{KHZ3-&zf049O3Syz(l~gMV;osOd`c zK=TQFM}7l{i=Ld>jsZ2DqUaY)Dn`=pzSh<33Zq1$4@45ex!=UN<^0Cw(L!w{EsNo2AdeLdeEHo& z_dk{3*rwQAt?S9hBr&p(Ki6WrKC!+``K()GHJRH3oLG0^ji!f7)VE))G38|=@tgKg zgr=3*vEE5)evG$-(8+wj`|bXa{Hm^tbzCMQuAY>ij5SH?es^XYW@^jRG@>qS9Oj6dxmBr!w@=y%^j2B9Owte%S(mfoRoxiJ!IZ3tus^NUCl19K4Z*( zU5&{WF8f;T@fEK|y#LX|DfKIJrSMAaFY%Ch%n{!chl5|wwIE@C<1Qu@JZL5R>_t5^ zh@jL9ESfC99;~n~Z!govqqMji6LGt6+x_5_WXb>;WTp2jWIc0_L;Xi^hxhzv-4aMbS%>)9gxVn>JWdtdQ#q>z8)hb%f?S) zkLsdc3|(hcAZdeI0a~(E$8RTo1q5hfe;X(5$EJ-=Cas`F%z@Ox@g|ygzYDQo5JU4e zjWgjVi}9A3mp5<4=puVj4C6NIYM`x|9}bR{;n9Y4*?Ju9NE2t^`On{zmuJc0z>mCg z)GJXz-`fhtU)bfZ;TES^(5*Dm=a~ojE|0M-PKgWpuSTo*B^G7TFY=Dt79~|43&QCz z_ZF9@s2G|z<{iu)mw)Zc=Jl~x*qmE;BY;3K{TUX6Z@QNAZXIZar(^wSHi z^`nwK^PWSuKI&ws+r=_`2x))Qr@b?O$4xz6q~qv%GM&F}Z9v>6H(6kK-Zr+24&rcpk@P>s9GyX$~dU7qU$%nuj~5y|o=D?g;5s zXGh$3=|SZs7%(^WbUhx$(4n~jqS_-7;j$QbPS`mDHhMWvROS5wsi|Vwbjjt97#ig?L^hsgtY_Bw?EXEU0F5zGBAyPZ!@?0StLs3gABN=R_} zfZ|){p8)$FBvY=@koe`+;L|}O=$VY&5>dlkpr6mr%-PRVS?E5${Ren@{(|s#hIXlR zkGmiL6j#45wW9&#zN?SctDklstEC#b$$!aEbKZ>`VBl4D566I|7+m@{>XjxJJ-_T~ZCpOO0M_2eV zWM7G?HaMbN%g;ad+cKbP>JKgZR_$dmY7%-hp->g;8#1m`pAq-Tt5;#?Q{4~(&f9c3 z=j`FLxI|^V5pFRmLdVt$@5-2UybYi-@${cRp}1w~Y2J7V3kvRhgncu4)#i(j;A zE@g65%<0oLM+HR z?m#W?|5AopQ zw6dymoyI~N(jX)yDAR?&aKZsRoHUR zI++xF!&|Pmow+bC9A>cKdIKJl#=1F2`Ao@6F(Q?hgf5*m#HbwK7@B7%&ZR1}5LP2T zxssE`4R3Utm3{rK8qM~Ifv+T$LS;Cyv`GHOG4qH|pZ|2N{vF;(358`yqPgO?%^qW# z(+;QR9W4&2%s3vz3uxa~sl79^ZqQ-(po#=S_{493N}DD@ShCix|BB=8i`<1#8UOlvoB{R6LUoQ5QkotClf6}o1)D8KH%p$O!=&3r#5HS zuI2b~ULuTJc@XBK_8-eLA}&D zMK$msaRs0r1E*YjC=J{GsE<*Y%WZaT+(E}+htV8njG4>x7a$+W0)*EV4oqgNxi^2OlpaFOHbo3$L+w79W(c_V5rn}Qf5Xl&$Kb#C50iL1T#JmqSban+g}o;r!RaM9URzb>@SuHBjCN0 zPR-jBN0k)Qa~utSH10Rld)^nn*^l)iQ2Xphlz9?3?bx8*Z|{Y`gf$WGo_G&plW(46 zQAUG}riiHm-IY(FHF;_K<01_cCV)F!BAwt@ib+qH|3~|}kwuP&XRDfF$+5blTYQ$}X!SF!kd)#JKTkBJoZ+H8fW^H{nQ_hrQ^W?E$G2$10YuF?BUJ_nC zg8k;o34^?O>Lxd3{)Y0mgkHaFFL(FhkccYjXl>mLA&n$WhYP{mR1_1L^u`pYvM zbo1WPo%1G}NN%{TNk=QI7%U9pZr2`XZa=(OMH0cc35EiOK?e0U$wuFQLg3SI8>9J* z8dnu+4qMi)4=a(12)<$pa;mf23?`9iK;IXmNTto8$l#sa%s0sqT2RorsveAZ&7F^M zo8X1#ROCRmwd=R^hvPg0rvEf^=j$7r%hlzy$DN3UL$)bYM;|kO5ImuGeKtwbUbYcVzGwv2By;Fkl(SPa;0=vS8cJ{d$anPostf4@|UcT*xthc3j&@5t=wYJ)kVt z*y}kLVHN3jFQL&Ya(7CoL0;@Ms!_SS?gkU~n~lUg5`2N*4A|>q_1mGCunZz%ur8>N z)Fd5kt)auGku=i_KB6g+PCOS=x(H)dTzAyCPj?EZN^CS?IHT>9SfBBW{fEkIAf?kFz!I;D;MD^2;4MQ8kpPs9PM=f z-WPDHAK@LhW+6cmQU2U{|MU@fgWKbr=5j^#j?_w|qvh3LomI`{E>Y_oO&NUWF4_`p z_0*$h9%>0bDk+b%9O|)MRk;#<&lei0nBAomOzfwPBuPh2qSKnVm$#jR{DjxC-1|_7 z;}dN^pvmY}Hf@x;^|2HkT{mKCHNYDeA}IPmqNIt+mJWJl#cM?YzVV;-*N4fJ#rkqJ-mqAWoth>O)kdBz6Q@9icXHBvZENA*a#7J?{F7DXE?mQo%L9m_1od7 z$6J{6<=0y6(ih8%6DOlBs}ehKe;4_$O-%O} z=$3PM&3dTLSv-#TtZQgfY12#7XS+j|fcO5Y;dml+QfSvBgE|5mYP7Wm9(wZ{$OEdV zR8{NdvhCJy-TC)kpWiN`!J%$Y0M_PQBZvWuSQ_Jn3sni2&S;a?j$U#~T?5H+&kpl| z((8{p>8N!M6hwC)tP}rmvg^?w*#molX~WV4rs~iL0MqZB*UZY0o*e zp06Gx6^RyHp$dvV-|kU?i!w_3Isf)hT&)su@*8!^r%blp9IvEV#*_r6>}>-`q$7$S zsx?tzsG9?Fp%jU;Pzh#T(*Tci0P#g8bdO(yl<|NX^e0`Th*{}M~>586_IVN z9U$>;1fBs|cJg3mH?U#r%cRK)hqI63c|7%be5;k9qj@jtXdJ)x7QYyYt*kr;FWlu= zKfdwt=po&0>yP0zyhP#6^141SQXwN@)<)I4ov<%nmP&sdvjhI@YNh5|UJ5}(e#;O* zeH@@D3@vN|HEFlwdjMZR>E$bp$Ns@qLsG?&SKyH{yM(xbVGyn@}Qn zR@*}WOKtQgyaU?hQI$BZ=xz43a@ZxCm9NoeraOmG`RLg?4s6t&p(Ajp?Qbbqftl9F zK5C?>o{Odn+>Dbyeqf)tT^~=Tq7qO$lKdIhm1Nx%Af#8@B|5ZSpWK^f()Sd03={oj zi176|2U}}p17Z6Ho~A@K3uiv-5kILZt#JEx_hFJ(%MvAptO+S&UHhda_%EDqPn=g$ zfyCN}x-;^l1p!oeSq9VcVeYN}_>W7V#Ov|j{Cqv!CILh|4j|m!8u4q`fQ|OAZ(xz6 z?dugFEqiAtBkRHyx4ASp1aR-e_0)d&p%Wds@8$ik8Ky}rWeSj=&j`pfx z5G}Qc=Zz)iUM-h85IkkLgFLBkKvaNOzRZ4Q)-oQ2!>z7VXQQV#S*tA$)h6|G>(0DoS_e9Kg#wEmh-K+q);RchBl{ z#;YojWaUsWPqx*J9(!;XF_w9?b$(tYS)_{fDL^RcLl5NQz8RV6kr+n#HDmxVs ze~&gj+a8cf&$jVK;g-R@@y z!M7{W9it4QQL6^dAyGv6UMt0ui2U#IT&bAiwKLvJ(c_7Sxo1(i#g8~yh%Rw3@7$sG zlYcIyHIWJ?vqamt?tOo#8-4raraT8bxcTq3@rP_yvN%>W1$(mTnZEM!TGfcUOKS9&?hoO!k4!TAGF#Wdi z(t|}3@dnY&ba%(PbHkZg6eV9hKmu9c&)KXcHvUrudD2eOT5T7!e7XMNM85TBVMW@T z&r=6xOmpu>hlT=2tp_aV&uM;n-G;=4}l>C>0q=?p?qneSA7s+Wj9??}EZLToB9g>VJfy<0;ZhDAe4(p_$Z$N%v;X8x!pX1k{KG)Tq%ak0wE^+-+ zA{o1)m`PD7l+7y6>2%7sBQA`@)_Y|((xc5y{u8@u^-oPE!;{>@zYPWZIVRGWHKVVG zc@7tnKUn8QQG`RV-au^k3MVCZ1Cr-iqs`2F9|b}9_D%}IAnPN?O_KPy9P!nK7;;_WHv^vEmEArt{%BYY4Xd>v&TFtUYJhVNIk67~?Sx!6$A*Aq)^r~8KTEQ#XN{Wp0MiBJ5>1PT? zXPT*09)D8WNjImmO)H}CBKJBE$>r!^9`!Q^Y4$8G*~cXLdz&2QTI7?q{zub=JlIid zplG5yj&vvqO{b$j^r0^pY@2isSzb#&0_>BYe^p@2VtgBUJnO3|7ukEP9!)vC^zQNb zMg%F#_ZSVkFBu~BL9lMPY^nE()anyVEGQfp)dZyC4LvW#l&;kGvus>nHS7l^5k8l+0dDhN5MF%CirzSY z3U^Aq=WkA1zqY?$Ns`4p=RR#*XF+(6Q{H?&A4*b2ZF50pY~&-V^fBHEuiiERAOLtAlNCSo%FSe;?sO z?qy?c*^Sc7V352q;j$H}W=ImM39bsQ;FV*)9zv972wse-4t*%a$fn>D??)r%P5cP9 zn0uhK7tiBQc9SrRXFkkVzKsy0 z@Tuk+VFdPt4>*cylBRSclnO|s-t(%)V`}N1^?%4ir4dLQcwo`8xN=qbAHVb;e5cYm zrS!}LsUb(7`$%HmXAX)@abY8E*XsDi!e>F1*4c=t5EnMeMsIGj)9fz}C$$u3+n_Ql zF-&*(G8gcYKRtpqd+1!WNqSvd$U$B%(Z4fpkDyf9`Yal*#;hU|dHFFF&6o~A> zp)gZabB#I{Rz&8`RrsGkRA&$ARY{>j*hn^u)S|@nNm|4m0t+~F$ienWVP3Y3r&E5I zvMv3D;@6Xt&&anJEbj(v;|mObo~ba$EfCj%%$z6NUS&p+G@+=ArzDj`1z(-(UiPyL zs(Z%=Uwl}zZin4|V8TXc*s1w!F;?zvgSKK%{vt_o+jX*p2cG1=3$lMRWdw_D(zS$E zlGVg+S8jT*jpm9l`Q57EX$ENT!&1|0#HOXq<)r&xF)4r0_-=0Fj}W zu@MmvX-^P^1e{<5DG?P!L5d&^L2MJ0$~l*rPgDat5D5Ji-(lnjg@9Ytg)il_`C zqN_OA#&Pd^F9|X3IXh?1p0mqekG$`@<#&Jge)ru3vN~XW9A%W1Y`@NB!|tnrcZUb+ zHOkWHZ#bsydF&T&+kKrkB_J!hbs$m%VizS5d0O-Pm}5kY=grB6-A~%e(`c`5M8?N& zqmr8ls@u-y>V~hUtdfc~xN_>1mbB#|`0|4r5gA!atgB0Q^vQpEQM}r0(Y8K~UbNDk zg&Ms6z>kuHXD%KJiu$eP_56?^WJGTg#&JueFVapb<#ByeE7$iuyt~F>^^u5}uGGk7 zA&TDJ1-DAV<+{|_C8K6r2kR28m$!Y6TBCk zdqUPboN2FB)EBFC<{mbE2WO)jxnH6}yu3Tsf0}dP{lE>YiLwWC z%N)Z$IBr^(VDZ~CqmGNzG{k@ODLndn7>=BDpJQ4bC};jCx@Kp`FW0;P>uie$qZ7Ya zR9n9Br`B&VSsSc&3Wh>k(BWJB_>~r9{%V&uG=m3rT}KzE%<6%AH%-FkV@)$+NQAMG zgR{Cx$NG-M$%P)1mM8YG_o}e{uXnc&Ci@y@RxN`6+{e8-=znp0>N$|=ib{Q=$o9|Z z{V;NNQ(H$$WoE=uU%Rj^FYWL%f1?CUs7~f0D`3bp{=9f3NR~mpH52|X6{SrT#$)as zp)huqM3ou_@o)s((Rvo>JkHv9;LKJz@+qDtEJ7WgM(7d?jxrM z|NMCtI^+Ufd8i^+36W_VIqP81(LgP-JLOSTxvbc9FhiAzH^rl_$EjP%GFYr4=0{PoY1{ps+8Upzq#Z!_yjJ+ z8VI#|RMx-41N|zp6Jw*>_j`}szoHLsI6ikfJClN8H)5-?v{Rd zFQ)~**Xc#O@k;f(7M0T#QFvI%$kWO%?{4QOn~$5GEiZYwTszCQHLn~#G=1Wua@yWM zLW?%uJ=PwnFgTodqA@bnt9TgEJJaS3|J3f(y^f|^skUo(#!?>K_gJZgfvwsJ1PtTEt6jM4rX^n~I!i?HvSn|aiJdzw~5+mR; z&&vq2!z}>>Sp?6h4Xj$}Y!-EGKQ=a&=mU$_XCV8z2 zCT$vv1#Ylbc=PRICW5#anU;J!0&78+t@f)5OiVO=CahhuZaf7O!_0)G%`*3f@rtgY zCeLm?Ai3)Uu2K({URV%5gAW$^tG%Ayh&>M00sxCr!+>{o(BDtUk{I9XmNIa#4#Lt= zeU}X@aObUkD)l>L8Qh=VdQHcKZFPr{y-5-Jwh+1^8=^uT-jCp$GhuU+!P3B0*k;mO zFe*<2x1L8Q_}-?^Gv-HA#|}`nK03Tk8p{u~fSykd^W+C$1_WT{rAgdeE)$k+k$k?J z9{?~npo&-#g{>`82C>emRcsvF3}u#0ePZKyc~7oq+{Anw){UwaLmq=hf!TWwwXD1r ziR*}_e*j)RNqXs`z(oh}S{;&CMq{U|xQb#BT>Qc#Ck_rbp_cls8IZh@6Z z0st0jpfZA^E!ZnTD$#-ZeByorh7Rr;CMQ%GnCh2ru8TY2lS>R}RoAOMf<=RMAL`i^ zCEC<_e)yeGEemIiEXTtlpRt)>wS!x+%jc>v(ACe$i6dwV8JwB_c>gsqg-`)z^EuPt z;#1(<{PDG=S)dK>39}56;Cf3(FQ1LVy$qlwTVi6jm|~ynfKZCpq4qNZQ}~FeJ45*9 zXQT_|Fposr2XTK=##o=GuSs?rLqbE89E#m zBy;F>?qg*tLC`&uZu)$UJ<<18t3(Y#nlc%7>bqZl3imeI5Lfua-#>PYCjq1`#*kqj=j~@rL50~uM+tmTAYLFfzybVr zxi!973`K(Pk5oQHAv(|#sqmSYu^$Lnl3p~1pY~HamK=Ux{E8KKDthCEZ*+sJIR zrR9WGES_Cj=Q?Gsx*B2dOXG$4r=?i=iWyai|E2fvS2a^%LHBl+0^PQSHj1NVyAaN1 zK|vSU;{{1@Lp99uYbkU%0O}Hx-q6fNmi{lqyVda4Ur7DEiTSa=+2 zg}!Ry+AA5Ia>8tASO?{REBT~E_zHdjD8e&TMW4RFApT*4aDkX#E5N-e(SpvVvHKg) z7eUL+3HsUGPz)g_GhXf|C!RGi4is1c$P~uyK-s1-bW9>h+rJJw^DlrwEYr zK%%1@gG$qqnkVuqW^@U(#X$-^h2nI04F?)$Q>M8VvDnau`7k8Cwm?_7x03~VJl#JI zB{1uyr)cx|Sok;tHYv`|?RdwI@`WcsBAwUGNjwc}Y}C&w3OU5T_zPW-z)uNb zg;rBWDqIDRN!V>(D`ZjtH_vNv+{`4L2`jec8Kv*OmW+EJb>}N!y_-m z6;U8h7%|}%LV5TF(hGW;jB2l0MApx3nKc)$_+3La>m|d;Kuh%YGK02rJ^&Hep-01t}hCEe) zN?#2UU&P;*=0hlq_$ui8v+k7`PZbeA&76q_b>$crsBo7da(-TxPUyHnxCJh@ZiHvr zlDy9%r3BF?e*BebZ+(MI^nhGiC-c>Yf7cfaUHKL`(Odthb=O{ZdhFBppQgc&y^Yg~ J!sR|O{{#;#blU&` literal 0 HcmV?d00001 From 7efefb1ab1685fa975511d37824281c6a7e8d39a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:28:26 -0300 Subject: [PATCH 119/141] docs(postman): add a postman collection to facilitate manual testing This commit adds a postman collection to help evaluators manually test the api endpoints. --- docs/postman/postman-collection.json | 176 +++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 docs/postman/postman-collection.json diff --git a/docs/postman/postman-collection.json b/docs/postman/postman-collection.json new file mode 100644 index 000000000..4a3affc8f --- /dev/null +++ b/docs/postman/postman-collection.json @@ -0,0 +1,176 @@ +{ + "info": { + "_postman_id": "{{$guid}}", + "name": "Bravo Currency Conversion API", + "description": "Currency conversion API currency service made by Luis Dourado for the Hurb Bravo Challenge", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:8080/api/v1" + }, + { + "key": "apiKey", + "value": "your_api_key_here" + } + ], + "item": [ + { + "name": "Currency", + "item": [ + { + "name": "Convert Currency", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/currency/convert?from=USD&to=BRL&amount=100", + "host": ["{{baseUrl}}"], + "path": ["currency", "convert"], + "query": [ + { + "key": "from", + "value": "USD" + }, + { + "key": "to", + "value": "BRL" + }, + { + "key": "amount", + "value": "100" + } + ] + } + }, + "response": [] + }, + { + "name": "Add New Currency", + "request": { + "method": "POST", + "header": [ + { + "key": "X-API-Key", + "value": "{{apiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"EUR\",\n \"rate_to_usd\": 0.85\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/currency", + "host": ["{{baseUrl}}"], + "path": ["currency"] + } + }, + "response": [] + }, + { + "name": "Update Currency", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-API-Key", + "value": "{{apiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"EUR\",\n \"rate_to_usd\": 0.86\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/currency/EUR", + "host": ["{{baseUrl}}"], + "path": ["currency", "EUR"] + } + }, + "response": [] + }, + { + "name": "Remove Currency", + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-API-Key", + "value": "{{apiKey}}", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/currency/EUR", + "host": ["{{baseUrl}}"], + "path": ["currency", "EUR"] + } + }, + "response": [] + } + ] + }, + { + "name": "Auth", + "item": [ + { + "name": "Register User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"newuser\",\n \"password\": \"password123\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/auth/register", + "host": ["{{baseUrl}}"], + "path": ["auth", "register"] + } + }, + "response": [] + }, + { + "name": "Login User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"admin\",\n \"password\": \"password\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/auth/login", + "host": ["{{baseUrl}}"], + "path": ["auth", "login"] + } + }, + "response": [] + } + ] + } + ] +} From 81c014f732ecde7c66827207d82c6b4313918780 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:29:01 -0300 Subject: [PATCH 120/141] chore(makefile): update testing command This commit changes the testing command removing the -v flag for a less verbose testing output --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 75a1472d0..be32d0f2f 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ run: # Test the application test: @echo "Testing..." - @go test ./... -v + @go test ./... # Clean the binary clean: From c43abc6726b97d25a1fc8c0f72b3aa5e514f9a4e Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:36:24 -0300 Subject: [PATCH 121/141] docs(README): update README.md and remove README.pt.md Updated the README.md to include detailed documentation for the Bravo Challenge API. The README now contains sections on project description, technology stack, services, features, setup and configuration, API documentation, and error responses. Changes: - Removed README.pt.md. - Expanded README.md with detailed instructions and examples for setting up and using the API. - Added information on environment variables and constants configuration. - Included examples for Docker setup, local development, and testing. --- README.md | 729 +++++++++++++++++++++++++++++++++++++++++++++++---- README.pt.md | 82 ------ 2 files changed, 674 insertions(+), 137 deletions(-) delete mode 100644 README.pt.md diff --git a/README.md b/README.md index 22af01577..3c23f1577 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,700 @@ -# Hurb Bravo Challenge +# Challenge Bravo -[[English](README.md) | [Portuguese](README.pt.md)] +![Current Code Coverage](https://img.shields.io/badge/coverage-69.3%25-yellow) -Build an API, which responds to JSON, for currency conversion. It must have a backing currency (USD) and make conversions between different currencies with **real and live values**. +## Table of Contents -The API must convert between the following currencies: +- [Challenge Bravo](#challenge-bravo) + - [Table of Contents](#table-of-contents) + - [Project Description](#project-description) + - [Technology Stack](#technology-stack) + - [Services](#services) + - [Features](#features) + - [Setup and Configuration](#setup-and-configuration) + - [Environment Variables](#environment-variables) + - [Constants Configuration](#constants-configuration) + - [Docker Setup](#docker-setup) + - [Local Development](#local-development) + - [Testing](#testing) + - [Manual Testing](#manual-testing) + - [API Documentation](#api-documentation) + - [Base URL](#base-url) + - [Swagger Documentation](#swagger-documentation) + - [Authentication](#authentication) + - [Endpoints](#endpoints) + - [Currency Conversion](#currency-conversion) + - [GET /currency/convert](#get-currencyconvert) + - [Currency Management (Admin only)](#currency-management-admin-only) + - [POST /currency](#post-currency) + - [PUT /currency/{code}](#put-currencycode) + - [DELETE /currency/{code}](#delete-currencycode) + - [User Management](#user-management) + - [POST /auth/register](#post-authregister) + - [POST /auth/login](#post-authlogin) + - [Error Responses](#error-responses) + - [Rate Limiting](#rate-limiting) + - [Technology Stack](#technology-stack-1) + - [Services](#services-1) + - [Features](#features-1) + - [Setup and Configuration](#setup-and-configuration-1) + - [Environment Variables](#environment-variables-1) + - [Constants Configuration](#constants-configuration-1) + - [Docker Setup](#docker-setup-1) + - [Local Development](#local-development-1) + - [Testing](#testing-1) + - [API Documentation](#api-documentation-1) + - [Base URL](#base-url-1) + - [Authentication](#authentication-1) + - [Endpoints](#endpoints-1) + - [Currency Conversion](#currency-conversion-1) + - [GET /currency/convert](#get-currencyconvert-1) + - [Currency Management (Admin only)](#currency-management-admin-only-1) + - [POST /currency](#post-currency-1) + - [PUT /currency/{code}](#put-currencycode-1) + - [DELETE /currency/{code}](#delete-currencycode-1) + - [User Management](#user-management-1) + - [POST /auth/register](#post-authregister-1) + - [POST /auth/login](#post-authlogin-1) + - [Error Responses](#error-responses-1) + - [Rate Limiting](#rate-limiting-1) -- USD -- BRL -- EUR -- BTC -- ETH +## Project Description -Other coins could be added as usage. +This API was developed for the Bravo challenge. The goal was to create an API that could convert between various currencies, both real and fictional, with live and custom values.# Challenge Bravo -Ex: USD to BRL, USD to BTC, ETH to BRL, etc... +**Additionally, it should be noted that the API's base currency is USD**. -The request must receive as parameters: The source currency, the amount to be converted and the final currency. +## Technology Stack -Ex: `?from=BTC&to=EUR&amount=123.45` +This challenge was built using a modern, scalable technology stack: -Also build an endpoint to add and remove API supported currencies using HTTP verbs. +- **Go (Golang) 1.22**: The core programming language, chosen for its performance, concurrency support, and robust standard library. +- **PostgreSQL**: A powerful, open-source relational database used for persistent storage of currency data, user information, and logs. +- **Redis**: An in-memory data structure store used as a caching layer to improve performance of frequent currency rate lookups. +- **Docker**: Used for containerization, ensuring consistent environments across development and production. +- **Docker Compose**: A tool for defining and running multi-container Docker applications, simplifying the setup and deployment process. +- **Chi Router**: A lightweight, idiomatic HTTP router for Go, providing a flexible and composable way to build APIs. -The API must support conversion between FIAT, crypto and fictitious. Example: BRL->HURB, HURB->ETH +## Services -"Currency is the means by which monetary transactions are effected." (Wikipedia, 2021). +1. **API Application**: The main service handling HTTP requests for currency conversion, user management, and currency administration. +2. **PostgreSQL Database**: Stores user data, currency information, and logs. +3. **Redis Cache**: Caches frequently accessed exchange rates for improved performance. +4. **Migrator**: A standalone service for running database migrations to create and update the database schema, as well as + seeding the database for a default admin user. -Therefore, it is possible to imagine that new coins come into existence or cease to exist, it is also possible to imagine fictitious coins such as Dungeons & Dragons coins being used in these transactions, such as how much is a Gold Piece (Dungeons & Dragons) in Real or how much is the GTA$1 in Real. +## Features -Let's consider the PSN quote where GTA$1,250,000.00 cost R$83.50 we clearly have a relationship between the currencies, so it is possible to create a quote. (Playstation Store, 2021). +- Real-time currency conversion +- User registration and authentication +- Admin-only currency management (add, update, remove currencies) +- Rate limiting to prevent abuse +- Logging and auditing of operations +- Scheduled updates of exchange rates +- Caching of frequently accessed data +- Comprehensive error handling and logging +- Containerized deployment for easy scaling and management -Ref: -Wikipedia [Institutional Website]. Available at: . Accessed on: 28 April 2021. -Playstation Store [Virtual Store]. Available at: . Accessed on: 28 April 2021. +## Setup and Configuration -You can use any programming language for the challenge. Below is the list of languages ​​that we here at Hurb have more affinity: +This section outlines how to setup and configure this api, including environment variables and important constants. -- JavaScript (NodeJS) -- Python -- Go -- Ruby -- C++ -- PHP +One thing that is important to note is that the API uses an [external service](https://openexchangerates.org/) to get the exchange rates, so you will need +an API token to use the service. To facilitate this proccess please use this API Key: `75cc9115d3524769a498914d118e093a` -## Requirements +### Environment Variables -- Fork this challenge and create your project (or workspace) using your version of that repository, as soon as you finish the challenge, submit a _pull request_. - - If you have any reason not to submit a _pull request_, create a private repository on Github, do every challenge on the **main** branch and don't forget to fill in the `pull-request.txt` file. As soon as you finish your development, add the user `automator-hurb` to your repository as a contributor and make it available for at least 30 days. **Do not add the `automator-hurb` until development is complete.** - - If you have any problem creating the private repository, at the end of the challenge fill in the file called `pull-request.txt`, compress the project folder - including the `.git` folder - and send it to us by email. -- The code needs to run on macOS or Ubuntu (preferably as a Docker container) -- To run your code, all you need to do is run the following commands: - - git clone \$your-fork - - cd \$your-fork - - command to install dependencies - - command to run the application -- The API can be written with or without the help of _frameworks_ - - If you choose to use a _framework_ that results in _boilerplate code_, mark in the README which piece of code was written by you. The more code you make, the more content we will have to rate. -- The API needs to support a volume of 1000 requests per second in a stress test. -- The API needs to include real and current quotes through integration with public currency quote APIs +Create a `.env` file in the project root with the following variables: -## Evaluation criteria +- `REDIS_PASSWORD`: Password for the Redis instance. +- `REDIS_ADDR`: Address and port of the Redis instance (e.g., "localhost:6379"). +- `POSTGRES_USER`: Username for the PostgreSQL database. +- `POSTGRES_PASSWORD`: Password for the PostgreSQL database. +- `POSTGRES_HOST`: Hostname of the PostgreSQL database. +- `POSTGRES_PORT`: Port number for the PostgreSQL database. +- `POSTGRES_NAME`: Name of the PostgreSQL database. +- `API_KEY`: API key for the OpenExchangeRates. +- `SERVER_PORT`: Port on which the API server will listen. -- **Organization of code**: Separation of modules, view and model, back-end and front-end -- **Clarity**: Does the README explain briefly what the problem is and how can I run the application? -- **Assertiveness**: Is the application doing what is expected? If something is missing, does the README explain why? -- **Code readability** (including comments) -- **Security**: Are there any clear vulnerabilities? -- **Test coverage** (We don't expect full coverage) -- **History of commits** (structure and quality) -- **UX**: Is the interface user-friendly and self-explanatory? Is the API intuitive? -- **Technical choices**: Is the choice of libraries, database, architecture, etc. the best choice for the application? +Example `.env` file: -## Doubts +``` +REDIS_PASSWORD=myredispassword +REDIS_ADDR=redis:6379 +POSTGRES_USER=myuser +POSTGRES_PASSWORD=mypassword +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_NAME=currency_db +API_KEY=75cc9115d3524769a498914d118e093a +SERVER_PORT=8080 +``` -Any questions you may have, check the [_issues_](https://github.com/HurbCom/challenge-bravo/issues) to see if someone hasn't already and if you can't find your answer, open one yourself. new issue! +### Constants Configuration -Godspeed! ;) +The `internal/commons/constants.go` file contains important constants that can be adjusted to fine-tune the API's behavior: + +- `AllowedCurrencyLength`: Maximum length of currency codes (default: 5). +- `MinimumCurrencyLength`: Minimum length of currency codes (default: 3). +- `AllowedRPS`: Rate limit for API requests per second (default: 10). +- `ExternalClientMaxRetries`: Maximum number of retries for external API calls (default: 3). +- `ExternalClientBaseDelay`: Base delay for exponential backoff in external API calls (default: 1 second). +- `ExternalClientMaxDelay`: Maximum delay for exponential backoff in external API calls (default: 30 seconds). +- `RateUpdaterCacheExipiration`: Expiration time for cached exchange rates (default: 1 hour). +- `ServerIdleTimeout`: Server idle timeout (default: 1 minute). +- `ServerReadTimeout`: Server read timeout (default: 10 seconds). +- `ServerWriteTimeout`: Server write timeout (default: 30 seconds). + +To modify these constants, edit the `internal/commons/constants.go` file and rebuild the application. + +### Docker Setup + +To run the application using Docker, follow these steps: + +1. Ensure you have Docker and Docker Compose installed on your system. + +2. Clone the repository: + + ```bash + git clone git@github.com:Lutefd/challenge-bravo.git + cd challenge-bravo + ``` + +3. Create a `.env` file in the project root and configure the necessary environment variables, a `.env.sample` file is provided (see API Configuration docs for details). + +4. Build and start the Docker containers: + + ``` + docker compose up --build + ``` + +5. The API will be available at `http://localhost:8080` if you're using the default port + and host provided in the `.env.sample`. + +### Local Development + +For local development without Docker: + +1. Ensure you have Go 1.22 or later installed. +2. Install [goose](https://github.com/pressly/goose) for database migrations. +3. Set up the environment variables as described in the API Configuration docs. +4. Run the database migrations: + ``` + make migrate-up + ``` +5. Start the application: + ``` + make run + ``` + +### Testing + +Run the test suite with: + +``` +make test +``` + +For a more verbose output: + +``` +go test ./... -v +``` + +### Manual Testing + +There is a Postman collection in the `postman-collection.json` file inside of the `docs/postman` folder. You can import this collection into Postman and test the API endpoints. + +## API Documentation + +This section details the endpoints and operations available in this API. More information can be found in the Swagger documentation, in the c4 diagram, in the dependencies diagram, and in the entity diagram all located in the `docs` folder along with the Postman collection. + +### Base URL + +All endpoints are relative to: `http://localhost:8080/api/v1` + +### Swagger Documentation + +The API documentation is available at `http://localhost:8080/api/v1/reference` + +### Authentication + +Most endpoints require authentication using an API key. Include the API key in the `X-API-Key` header of your requests. + +### Endpoints + +#### Currency Conversion + +##### GET /currency/convert + +Convert an amount from one currency to another. + +Query Parameters: + +- `from`: Source currency code (e.g., "USD") +- `to`: Target currency code (e.g., "EUR") +- `amount`: Amount to convert (numeric) + +Example Request: + +``` +GET /api/v1/currency/convert?from=USD&to=EUR&amount=100 +``` + +Example Response: + +```json +{ + "from": "USD", + "to": "EUR", + "amount": 100, + "result": 85 +} +``` + +#### Currency Management (Admin only) + +##### POST /currency + +Add a new currency. + +Request Body: + +```json +{ + "code": "JPY", + "rate_to_usd": 110.5 +} +``` + +Example Response: + +```json +{ + "message": "currency added successfully" +} +``` + +##### PUT /currency/{code} + +Update an existing currency. + +Request Body: + +```json +{ + "rate_to_usd": 111.2 +} +``` + +Example Response: + +```json +{ + "message": "currency updated successfully" +} +``` + +##### DELETE /currency/{code} + +Remove a currency. + +Example Response: + +```json +{ + "message": "currency removed successfully" +} +``` + +#### User Management + +##### POST /auth/register + +Register a new user. + +Request Body: + +```json +{ + "username": "newuser", + "password": "securepassword" +} +``` + +Example Response: + +```json +{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "username": "newuser", + "role": "user", + "api_key": "your-api-key-here" +} +``` + +##### POST /auth/login + +Authenticate a user and retrieve their API key. + +Request Body: + +```json +{ + "username": "existinguser", + "password": "userpassword" +} +``` + +Example Response: + +```json +{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "username": "existinguser", + "role": "user", + "api_key": "your-api-key-here" +} +``` + + Update(ctx context.Context, username, password string) error + +### Error Responses + +The API uses standard HTTP status codes to indicate the success or failure of requests. In case of an error, the response body will contain an error message: + +```json +{ + "error": "Description of the error" +} +``` + +Common error status codes: + +- 400: Bad Request (invalid input) +- 401: Unauthorized (missing or invalid API key) +- 403: Forbidden (insufficient permissions) +- 404: Not Found (resource not found) +- 429: Too Many Requests (rate limit exceeded) +- 500: Internal Server Error + +### Rate Limiting + +The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests. + +This version of the API allows for the addition of new real currencies that will be tracked and fictional currencies that will be stored. + +**Additionally, it should be noted that the API's base currency is USD**. + +## Technology Stack + +This challenge was built using a modern, scalable technology stack: + +- **Go (Golang) 1.22**: The core programming language, chosen for its performance, concurrency support, and robust standard library. +- **PostgreSQL**: A powerful, open-source relational database used for persistent storage of currency data, user information, and logs. +- **Redis**: An in-memory data structure store used as a caching layer to improve performance of frequent currency rate lookups. +- **Docker**: Used for containerization, ensuring consistent environments across development and production. +- **Docker Compose**: A tool for defining and running multi-container Docker applications, simplifying the setup and deployment process. +- **Chi Router**: A lightweight, idiomatic HTTP router for Go, providing a flexible and composable way to build APIs. + +## Services + +1. **API Application**: The main service handling HTTP requests for currency conversion, user management, and currency administration. +2. **PostgreSQL Database**: Stores user data, currency information, and logs. +3. **Redis Cache**: Caches frequently accessed exchange rates for improved performance. +4. **Migrator**: A standalone service for running database migrations to create and update the database schema, as well as + seeding the database for a default admin user. + +## Features + +- Real-time currency conversion +- User registration and authentication +- Admin-only currency management (add, update, remove currencies) +- Rate limiting to prevent abuse +- Logging and auditing of operations +- Scheduled updates of exchange rates +- Caching of frequently accessed data +- Comprehensive error handling and logging +- Containerized deployment for easy scaling and management + +## Setup and Configuration + +This section outlines how to setup and configure this api, including environment variables and important constants. + +One thing that is important to note is that the API uses an [external service](https://openexchangerates.org/) to get the exchange rates, so you will need +an API token to use the service. To facilitate this proccess please use this API Key: `75cc9115d3524769a498914d118e093a` + +### Environment Variables + +Create a `.env` file in the project root with the following variables: + +- `REDIS_PASSWORD`: Password for the Redis instance. +- `REDIS_ADDR`: Address and port of the Redis instance (e.g., "localhost:6379"). +- `POSTGRES_USER`: Username for the PostgreSQL database. +- `POSTGRES_PASSWORD`: Password for the PostgreSQL database. +- `POSTGRES_HOST`: Hostname of the PostgreSQL database. +- `POSTGRES_PORT`: Port number for the PostgreSQL database. +- `POSTGRES_NAME`: Name of the PostgreSQL database. +- `API_KEY`: API key for the OpenExchangeRates. +- `SERVER_PORT`: Port on which the API server will listen. + +Example `.env` file: + +``` +REDIS_PASSWORD=myredispassword +REDIS_ADDR=redis:6379 +POSTGRES_USER=myuser +POSTGRES_PASSWORD=mypassword +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_NAME=currency_db +API_KEY=75cc9115d3524769a498914d118e093a +SERVER_PORT=8080 +``` + +### Constants Configuration + +The `internal/commons/constants.go` file contains important constants that can be adjusted to fine-tune the API's behavior: + +- `AllowedCurrencyLength`: Maximum length of currency codes (default: 5). +- `MinimumCurrencyLength`: Minimum length of currency codes (default: 3). +- `AllowedRPS`: Rate limit for API requests per second (default: 10). +- `ExternalClientMaxRetries`: Maximum number of retries for external API calls (default: 3). +- `ExternalClientBaseDelay`: Base delay for exponential backoff in external API calls (default: 1 second). +- `ExternalClientMaxDelay`: Maximum delay for exponential backoff in external API calls (default: 30 seconds). +- `RateUpdaterCacheExipiration`: Expiration time for cached exchange rates (default: 1 hour). +- `ServerIdleTimeout`: Server idle timeout (default: 1 minute). +- `ServerReadTimeout`: Server read timeout (default: 10 seconds). +- `ServerWriteTimeout`: Server write timeout (default: 30 seconds). + +To modify these constants, edit the `internal/commons/constants.go` file and rebuild the application. + +### Docker Setup + +To run the application using Docker, follow these steps: + +1. Ensure you have Docker and Docker Compose installed on your system. + +2. Clone the repository: + + ```bash + git clone git@github.com:Lutefd/challenge-bravo.git + cd challenge-bravo + ``` + +3. Create a `.env` file in the project root and configure the necessary environment variables, a `.env.sample` file is provided (see API Configuration docs for details). + +4. Build and start the Docker containers: + + ``` + docker compose up --build + ``` + +5. The API will be available at `http://localhost:8080` if you're using the default port + and host provided in the `.env.sample`. + +### Local Development + +For local development without Docker: + +1. Ensure you have Go 1.22 or later installed. +2. Install [goose](https://github.com/pressly/goose) for database migrations. +3. Set up the environment variables as described in the API Configuration docs. +4. Run the database migrations: + ``` + make migrate-up + ``` +5. Start the application: + ``` + make run + ``` + +### Testing + +Run the test suite with: + +``` +make test +``` + +For a more verbose output: + +``` +go test ./... -v +``` + +## API Documentation + +This section details the endpoints and operations available in this API. + +### Base URL + +All endpoints are relative to: `http://localhost:8080/api/v1` + +### Authentication + +Most endpoints require authentication using an API key. Include the API key in the `X-API-Key` header of your requests. + +### Endpoints + +#### Currency Conversion + +##### GET /currency/convert + +Convert an amount from one currency to another. + +Query Parameters: + +- `from`: Source currency code (e.g., "USD") +- `to`: Target currency code (e.g., "EUR") +- `amount`: Amount to convert (numeric) + +Example Request: + +``` +GET /api/v1/currency/convert?from=USD&to=EUR&amount=100 +``` + +Example Response: + +```json +{ + "from": "USD", + "to": "EUR", + "amount": 100, + "result": 85 +} +``` + +#### Currency Management (Admin only) + +##### POST /currency + +Add a new currency. + +Request Body: + +```json +{ + "code": "JPY", + "rate_to_usd": 110.5 +} +``` + +Example Response: + +```json +{ + "message": "currency added successfully" +} +``` + +##### PUT /currency/{code} + +Update an existing currency. + +Request Body: + +```json +{ + "rate_to_usd": 111.2 +} +``` + +Example Response: + +```json +{ + "message": "currency updated successfully" +} +``` + +##### DELETE /currency/{code} + +Remove a currency. + +Example Response: + +```json +{ + "message": "currency removed successfully" +} +``` + +#### User Management + +##### POST /auth/register + +Register a new user. + +Request Body: + +```json +{ + "username": "newuser", + "password": "securepassword" +} +``` + +Example Response: + +```json +{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "username": "newuser", + "role": "user", + "api_key": "your-api-key-here" +} +``` + +##### POST /auth/login + +Authenticate a user and retrieve their API key. + +Request Body: + +```json +{ + "username": "existinguser", + "password": "userpassword" +} +``` + +Example Response: + +```json +{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "username": "existinguser", + "role": "user", + "api_key": "your-api-key-here" +} +``` + + Update(ctx context.Context, username, password string) error + +### Error Responses + +The API uses standard HTTP status codes to indicate the success or failure of requests. In case of an error, the response body will contain an error message: + +```json +{ + "error": "Description of the error" +} +``` + +Common error status codes: + +- 400: Bad Request (invalid input) +- 401: Unauthorized (missing or invalid API key) +- 403: Forbidden (insufficient permissions) +- 404: Not Found (resource not found) +- 429: Too Many Requests (rate limit exceeded) +- 500: Internal Server Error + +### Rate Limiting + +The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests.

Challange accepted diff --git a/README.pt.md b/README.pt.md deleted file mode 100644 index 0159db9f0..000000000 --- a/README.pt.md +++ /dev/null @@ -1,82 +0,0 @@ -# Hurb Desafio Bravo - -[[English](README.md) | [Português](README.pt.md)] - -Construa uma API, que responda JSON, para conversão monetária. Ela deve ter uma moeda de lastro (USD) e fazer conversões entre diferentes moedas com **cotações de verdade e atuais**. - -A API precisa converter entre as seguintes moedas: - -- USD -- BRL -- EUR -- BTC -- ETH - -Outras moedas podem ser adicionadas conforme o uso. - -Ex: USD para BRL, USD para BTC, ETH para BRL, etc... - -A requisição deve receber como parâmetros: A moeda de origem, o valor a ser convertido e a moeda final. - -Ex: `?from=BTC&to=EUR&amount=123.45` - -Construa também um endpoint para adicionar e remover moedas suportadas pela API, usando os verbos HTTP. - -A API deve suportar conversão entre moedas fiduciárias, crypto e fictícias. Exemplo: BRL->HURB, HURB->ETH - -"Moeda é o meio pelo qual são efetuadas as transações monetárias." (Wikipedia, 2021). - -Sendo assim, é possível imaginar que novas moedas passem a existir ou deixem de existir, é possível também imaginar moedas fictícias como as de Dungeons & Dragons sendo utilizadas nestas transações, como por exemplo quanto vale uma Peça de Ouro (D&D) em Real ou quanto vale a GTA$ 1 em Real. - -Vamos considerar a cotação da PSN onde GTA$ 1.250.000,00 custam R$ 83,50 claramente temos uma relação entre as moedas, logo é possível criar uma cotação. (Playstation Store, 2021). - -Ref: -Wikipedia [Site Institucional]. Disponível em: . Acesso em: 28 abril 2021. -Playstation Store [Loja Virtual]. Disponível em: . Acesso em: 28 abril 2021. - -Você pode usar qualquer linguagem de programação para o desafio. Abaixo a lista de linguagens que nós aqui do Hurb temos mais afinidade: - -- JavaScript (NodeJS) -- Python -- Go -- Ruby -- C++ -- PHP - -## Requisitos - -- Forkar esse desafio e criar o seu projeto (ou workspace) usando a sua versão desse repositório, tão logo acabe o desafio, submeta um _pull request_. - - Caso você tenha algum motivo para não submeter um _pull request_, crie um repositório privado no Github, faça todo desafio na branch **main** e não se esqueça de preencher o arquivo `pull-request.txt`. Tão logo termine seu desenvolvimento, adicione como colaborador o usuário `automator-hurb` no seu repositório e o deixe disponível por pelo menos 30 dias. **Não adicione o `automator-hurb` antes do término do desenvolvimento.** - - Caso você tenha algum problema para criar o repositório privado, ao término do desafio preencha o arquivo chamado `pull-request.txt`, comprima a pasta do projeto - incluindo a pasta `.git` - e nos envie por email. -- O código precisa rodar em macOS ou Ubuntu (preferencialmente como container Docker) -- Para executar seu código, deve ser preciso apenas rodar os seguintes comandos: - - git clone \$seu-fork - - cd \$seu-fork - - comando para instalar dependências - - comando para executar a aplicação -- A API pode ser escrita com ou sem a ajuda de _frameworks_ - - Se optar por usar um _framework_ que resulte em _boilerplate code_, assinale no README qual pedaço de código foi escrito por você. Quanto mais código feito por você, mais conteúdo teremos para avaliar. -- A API precisa suportar um volume de 1000 requisições por segundo em um teste de estresse. -- A API precisa contemplar cotações de verdade e atuais através de integração com APIs públicas de cotação de moedas - -## Critério de avaliação - -- **Organização do código**: Separação de módulos, view e model, back-end e front-end -- **Clareza**: O README explica de forma resumida qual é o problema e como pode rodar a aplicação? -- **Assertividade**: A aplicação está fazendo o que é esperado? Se tem algo faltando, o README explica o porquê? -- **Legibilidade do código** (incluindo comentários) -- **Segurança**: Existe alguma vulnerabilidade clara? -- **Cobertura de testes** (Não esperamos cobertura completa) -- **Histórico de commits** (estrutura e qualidade) -- **UX**: A interface é de fácil uso e auto-explicativa? A API é intuitiva? -- **Escolhas técnicas**: A escolha das bibliotecas, banco de dados, arquitetura, etc, é a melhor escolha para a aplicação? - -## Dúvidas - -Quaisquer dúvidas que você venha a ter, consulte as [_issues_](https://github.com/HurbCom/challenge-bravo/issues) para ver se alguém já não a fez e caso você não ache sua resposta, abra você mesmo uma nova issue! - -Boa sorte e boa viagem! ;) - -

- Challange accepted -

From 617352d9fd62c846efc46040c89e635a08734cac Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 15:59:19 -0300 Subject: [PATCH 122/141] chore(pull-request): fill out pull-request.txt file This commit fills out the pull request file. --- pull-request.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pull-request.txt b/pull-request.txt index 4eae37418..8b28555a1 100644 --- a/pull-request.txt +++ b/pull-request.txt @@ -1,3 +1,3 @@ -Your name: ___ -Your Github homepage: ___ -Original challenge URL: http://github.com/hurbcom/challenge-___ +Your name: Luis Dourado +Your Github homepage: https://github.com/Lutefd +Original challenge URL: https://github.com/hurbcom/challenge-bravo From bfdee23b0c566edd261516f82abd3b64ba892014 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 16:17:08 -0300 Subject: [PATCH 123/141] chore(docker): leave the redis_port as hard setted to streamline setup This commit changes the docker compose to have the redis port hard setted to streamline setup and avoid another environment variable that is used just there. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index af43202a9..4abf74260 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_NAME: ${POSTGRES_NAME} POSTGRES_PORT: ${POSTGRES_PORT} - REDIS_ADDR: redis:${REDIS_PORT} + REDIS_ADDR: redis:6379 API_KEY: ${API_KEY} SERVER_PORT: ${SERVER_PORT} networks: From 5ac4714a5fa0fa750e9afc79421c203ba8ed0609 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 16:18:56 -0300 Subject: [PATCH 124/141] chore(.env.sample): set temporary api key to streamline setup for evaluators This commit sets the API_KEY env with an api key created specificly to streamline the evaluators setup, so they don't need to generate one in https://openexchangerates.org/. This is a practice that wouldn't happen in production code, but as this is a challenge for a job opportunity I thought it was best to do this. --- .env.sample | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.sample b/.env.sample index dd31081e7..e53ca74d1 100644 --- a/.env.sample +++ b/.env.sample @@ -6,4 +6,5 @@ POSTGRES_PORT=5432 SERVER_PORT=8080 REDIS_ADDR="localhost:6379" REDIS_PASSWORD=redis_pass -API_KEY=your_api_key +API_KEY=75cc9115d3524769a498914d118e093a // this is the API key for the OpenExchangeRates service it was generated only for this challenge to help the +// evaluators to test the API From 7f3864f329c8862d9630d0679d38ba6813ccbb7c Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 16:45:41 -0300 Subject: [PATCH 125/141] docs(README): update README.md to include sections on auto-generated code, improvements, and final thoughts Added new sections to README.md to provide additional context and insights about the project. The updates include: - A section on auto-generated code explaining the use of tools like goose, mermaid, and swagger. - A section on potential improvements that could be made to the project, discussing rate limiting, logging, rate updater, currency management, user management, and testing. - A final thoughts section reflecting on the learning experience and future improvements. --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c23f1577..602f0ad17 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,9 @@ - [POST /auth/login](#post-authlogin-1) - [Error Responses](#error-responses-1) - [Rate Limiting](#rate-limiting-1) + - [Auto-Generated Code](#auto-generated-code) + - [Improvements](#improvements) + - [Final Thoughts](#final-thoughts) ## Project Description @@ -696,6 +699,28 @@ Common error status codes: The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests. -

+## Auto-Generated Code + +- This project used goose to execute migrations, although the migrations were written by hand, the migration code and execute is generated by [goose](https://github.com/pressly/goose). +- It also uses mermaid to generate the diagrams in the docs folder. The mermaid code is written by hand and the diagrams are generated by the [mermaid live editor](https://mermaid.live/). +- The swagger UI and its playground are generated by [Scalar](https://docs.scalar.com/swagger-editor), the swagger documentation is written by hand. +- The Makefile was extracted from a [boilerplate cli tool](https://github.com/Melkeydev/go-blueprint) I've used in a lot of personal projects, but didn't use it in this project, only the makefile was copied from it. + +## Improvements + +There are a lot of improvements that could be made to this project, I decided to keep it as simple as possible, even removing some features that were not necessary for the base requirements of the project, but some improvements that could be made are: + +- Rate limiting using a more robust solution like Redis, this would allow for a more distributed rate limiting system. The current rate limiting is done in memory and is not distributed, using the [Rate package](https://pkg.go.dev/golang.org/x/time/rate), it uses a token bucket algorithm to limit the number of requests per second. +- Logging, the current logging system is very simple, it registers the internal erros and info logs in a postgres database, but it could be improved to use a more robust logging system like the ELK stack. I decided to keep it simple because the requirements didn't ask for a more robust logging system and as I was already using postgres for the database, I decided to use it for the logs as well since it can handle the load, I limited it to about 1000 logs in the channel, so it won't overload the database. +- The rate updater could be improved by making it more robust and into a separate service. Although it has a retry policy and a backoff policy, it could have a circuit breaker to prevent the service from being overloaded if the external service is down for a long time. It could also be separated into a separate service to prevent the main service to work better with a more distributed system. +- The currency management could be improved by adding more features like a list of all currencies, and a more detailed view of each currency, with the possibility of adding more information like the name of the currency, the symbol, and the country of origin. Also due to currencies that have a lot of decimal places, it could be improved to handle more decimal places while rounding up for the ones that don't need it, currently we're using all of the decimal places provided by the external service. +- The user management and security could be greatly improved, right now it's really simple with users not being able to do much, not even edit their own information, it could be improved by adding more features like password recovery, email verification, and more detailed user information. The security could be improved by adding more security features like 2FA, also adding more than just an X-API-Key for authentication, like JWT tokens. But this was a decision that I made to keep it simple and to focus on the core functionality of the project, while having the minimum user management required to use the API. +- Tests could be better and could cover more of the errors that could happen in the system, I've only covered the basic errors that could happen in the system, but there are a lot of edge cases that could be tested. Also, the tests could be more robust and could use a more robust testing framework like [Ginkgo](https://onsi.github.io/ginkgo/). + +## Final Thoughts + +I learned a lot while doing this challenge, there were a lot of things that could be improved and I'm going to keep studying so I can improve my skills and be able to do better in my next projects. It was a bit difficult to find the time to do this project, but I'm happy to have done it and I'm happy with the result. + +

2 Challange accepted

From 16669107c144b8b40e1425a5c407b38e0944376a Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 16:53:13 -0300 Subject: [PATCH 126/141] chore(.env.sample): fix the comment in the .env.sample This commit fixes a mistake I made when commenting about the API_KEY in the .env.sample so if the evaluator only copied without removing the comment it would error out --- .env.sample | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index e53ca74d1..6cf4df214 100644 --- a/.env.sample +++ b/.env.sample @@ -6,5 +6,4 @@ POSTGRES_PORT=5432 SERVER_PORT=8080 REDIS_ADDR="localhost:6379" REDIS_PASSWORD=redis_pass -API_KEY=75cc9115d3524769a498914d118e093a // this is the API key for the OpenExchangeRates service it was generated only for this challenge to help the -// evaluators to test the API +API_KEY=75cc9115d3524769a498914d118e093a # this is the API key for the OpenExchangeRates service it was generated only for this challenge to help the evaluators to test the API From 6d41c8d029f083ad8352d7b721a851468d252a1f Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 17:39:30 -0300 Subject: [PATCH 127/141] feat(service): Implement in-flight request deduplication and negative caching his commit introduces improvements to the CurrencyService to handle in-flight request deduplication and negative caching to enhance performance and try to avoid rate limit on API. Changes: - Added in-flight request deduplication using sync.Map to prevent duplicate requests for the same currency code. - Implemented negative caching to cache failed currency lookups, reducing the load on the external API. - Updated `getRate` method to handle in-flight deduplication and negative caching. - Added related constants to `constants.go`. - Included new test cases in `currency_service_test.go` to verify the functionality of in-flight deduplication and negative caching. Also, constant `CacheExpiration` was added to manage cache duration settings. --- internal/commons/constants.go | 1 + internal/service/currency_service.go | 38 +++++++++++-- internal/service/currency_service_test.go | 65 +++++++++++++++++++++++ 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/internal/commons/constants.go b/internal/commons/constants.go index 67ba1508f..4072f1fd3 100644 --- a/internal/commons/constants.go +++ b/internal/commons/constants.go @@ -14,4 +14,5 @@ const ( ServerIdleTimeout = time.Minute ServerReadTimeout = 10 * time.Second ServerWriteTimeout = 30 * time.Second + CacheExpiration = 1 * time.Hour ) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 2c3bbe443..2e66a1442 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "strings" + "sync" "time" "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" "github.com/Lutefd/challenge-bravo/internal/worker" @@ -14,9 +16,11 @@ import ( ) type CurrencyService struct { - repo repository.CurrencyRepository - cache cache.Cache - externalAPI worker.ExternalAPIClient + repo repository.CurrencyRepository + cache cache.Cache + externalAPI worker.ExternalAPIClient + inFlightReqs sync.Map + negativeCache sync.Map } func NewCurrencyService(repo repository.CurrencyRepository, cache cache.Cache, externalAPI worker.ExternalAPIClient) *CurrencyService { @@ -48,11 +52,30 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er if err == nil { return rate, nil } + + if _, found := s.negativeCache.Load(code); found { + return 0, fmt.Errorf("%w: %s", model.ErrCurrencyNotFound, code) + } + + ch := make(chan struct{}) + actualCh, loaded := s.inFlightReqs.LoadOrStore(code, ch) + if loaded { + <-actualCh.(chan struct{}) + rate, err := s.cache.Get(ctx, code) + if err == nil { + return rate, nil + } + } else { + defer close(ch) + } + defer s.inFlightReqs.Delete(code) + currency, err := s.repo.GetByCode(ctx, code) if err == nil { - s.cache.Set(ctx, code, currency.Rate, 1*time.Hour) + s.cache.Set(ctx, code, currency.Rate, commons.CacheExpiration) return currency.Rate, nil } + rates, err := s.externalAPI.FetchRates(ctx) if err != nil { return 0, err @@ -60,8 +83,14 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er rate, ok := rates.Rates[code] if !ok { + s.negativeCache.Store(code, struct{}{}) + go func() { + time.Sleep(commons.CacheExpiration) + s.negativeCache.Delete(code) + }() return 0, fmt.Errorf("%w: %s", model.ErrCurrencyNotFound, code) } + currency = &model.Currency{ Code: strings.ToUpper(code), Rate: rate, @@ -73,7 +102,6 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er } s.cache.Set(ctx, code, rate, 1*time.Hour) - return rate, nil } diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go index d9f004423..dca7ed503 100644 --- a/internal/service/currency_service_test.go +++ b/internal/service/currency_service_test.go @@ -3,6 +3,7 @@ package service_test import ( "context" "errors" + "sync" "testing" "time" @@ -81,6 +82,25 @@ func (m *mockExternalAPI) FetchRates(ctx context.Context) (*model.ExchangeRates, }, nil } +type mockExternalAPIWithCounter struct { + rates map[string]float64 + callCount int + mu sync.Mutex +} + +func (m *mockExternalAPIWithCounter) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { + m.mu.Lock() + defer m.mu.Unlock() + m.callCount++ + return &model.ExchangeRates{Rates: m.rates}, nil +} + +func (m *mockExternalAPIWithCounter) GetCallCount() int { + m.mu.Lock() + defer m.mu.Unlock() + return m.callCount +} + func TestCurrencyService_Convert(t *testing.T) { repo := &mockRepository{ currencies: map[string]*model.Currency{ @@ -124,6 +144,7 @@ func TestCurrencyService_Convert(t *testing.T) { assert.Error(t, err) assert.True(t, errors.Is(err, tt.expectedError), "Expected error %v, but got %v", tt.expectedError, err) if tt.expectedError == model.ErrCurrencyNotFound { + assert.Contains(t, err.Error(), "currency not found") if tt.from == "XYZ" { assert.Contains(t, err.Error(), tt.from, "Error should contain the 'from' currency code") } else { @@ -136,6 +157,50 @@ func TestCurrencyService_Convert(t *testing.T) { } }) } + + t.Run("Negative cache", func(t *testing.T) { + repo := &mockRepository{currencies: map[string]*model.Currency{}} + cache := &mockCache{data: map[string]float64{}} + externalAPI := &mockExternalAPIWithCounter{rates: map[string]float64{}} + currencyService := service.NewCurrencyService(repo, cache, externalAPI) + + _, err1 := currencyService.Convert(context.Background(), "XYZ", "USD", 100) + assert.Error(t, err1) + assert.True(t, errors.Is(err1, model.ErrCurrencyNotFound)) + assert.Equal(t, 1, externalAPI.GetCallCount(), "Expected external API to be called once") + + _, err2 := currencyService.Convert(context.Background(), "XYZ", "USD", 100) + assert.Error(t, err2) + assert.True(t, errors.Is(err2, model.ErrCurrencyNotFound)) + assert.Equal(t, 1, externalAPI.GetCallCount(), "Expected external API to still have been called only once") + + _, err3 := currencyService.Convert(context.Background(), "ABC", "USD", 100) + assert.Error(t, err3) + assert.True(t, errors.Is(err3, model.ErrCurrencyNotFound)) + assert.Equal(t, 2, externalAPI.GetCallCount(), "Expected external API to be called a second time for a new currency") + }) + t.Run("Concurrent requests", func(t *testing.T) { + var wg sync.WaitGroup + results := make([]float64, 10) + errors := make([]error, 10) + + for i := 0; i < 10; i++ { + wg.Add(1) + go func(index int) { + defer wg.Add(-1) + result, err := currencyService.Convert(context.Background(), "USD", "EUR", 100) + results[index] = result + errors[index] = err + }(i) + } + + wg.Wait() + + for i := 0; i < 10; i++ { + assert.NoError(t, errors[i]) + assert.InDelta(t, 85.0, results[i], 0.001) + } + }) } func TestCurrencyService_AddCurrency(t *testing.T) { From 9f69af5feabb0ee98f0f95eb239a5be202bca354 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 21:48:21 -0300 Subject: [PATCH 128/141] refactor(service): simplify CurrencyService by removing external API dependency This commit simplifies the `CurrencyService` by removing the external API client dependency. The service now relies solely on the repository for currency data, streamlining its responsibilities and reducing complexity. Changes: - Removed the external API client from `CurrencyService` and related methods. - Updated the `CurrencyService` constructor and methods to remove external API interactions. - Modified corresponding tests to reflect the removal of the external API client. - Updated the server setup to match the new `CurrencyService` constructor. This refactor aims to mitigate the external api limits. It would be nice to be able to check there for missing currencies, but the limits are too low and even with negative caching and request deduping it's too risky. --- internal/server/server.go | 2 +- internal/service/currency_service.go | 65 ++---------- internal/service/currency_service_test.go | 123 +++------------------- 3 files changed, 22 insertions(+), 168 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index f8d21dd4c..454be7948 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -44,7 +44,7 @@ func NewServer(config Config) (*Server, error) { return nil, fmt.Errorf("failed to initialize cache: %w", err) } externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) - currencyService := service.NewCurrencyService(repo, redisCache, externalAPI) + currencyService := service.NewCurrencyService(repo, redisCache) userService := service.NewUserService(userRepo) rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, 1*time.Hour) logger.InitLogger(logRepo) diff --git a/internal/service/currency_service.go b/internal/service/currency_service.go index 2e66a1442..3b20f9cba 100644 --- a/internal/service/currency_service.go +++ b/internal/service/currency_service.go @@ -3,31 +3,23 @@ package service import ( "context" "fmt" - "strings" - "sync" "time" "github.com/Lutefd/challenge-bravo/internal/cache" - "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" - "github.com/Lutefd/challenge-bravo/internal/worker" "github.com/google/uuid" ) type CurrencyService struct { - repo repository.CurrencyRepository - cache cache.Cache - externalAPI worker.ExternalAPIClient - inFlightReqs sync.Map - negativeCache sync.Map + repo repository.CurrencyRepository + cache cache.Cache } -func NewCurrencyService(repo repository.CurrencyRepository, cache cache.Cache, externalAPI worker.ExternalAPIClient) *CurrencyService { +func NewCurrencyService(repo repository.CurrencyRepository, cache cache.Cache) *CurrencyService { return &CurrencyService{ - repo: repo, - cache: cache, - externalAPI: externalAPI, + repo: repo, + cache: cache, } } @@ -36,7 +28,6 @@ func (s *CurrencyService) Convert(ctx context.Context, from, to string, amount f if err != nil { return 0, err } - toRate, err := s.getRate(ctx, to) if err != nil { return 0, err @@ -53,56 +44,14 @@ func (s *CurrencyService) getRate(ctx context.Context, code string) (float64, er return rate, nil } - if _, found := s.negativeCache.Load(code); found { - return 0, fmt.Errorf("%w: %s", model.ErrCurrencyNotFound, code) - } - - ch := make(chan struct{}) - actualCh, loaded := s.inFlightReqs.LoadOrStore(code, ch) - if loaded { - <-actualCh.(chan struct{}) - rate, err := s.cache.Get(ctx, code) - if err == nil { - return rate, nil - } - } else { - defer close(ch) - } - defer s.inFlightReqs.Delete(code) - currency, err := s.repo.GetByCode(ctx, code) - if err == nil { - s.cache.Set(ctx, code, currency.Rate, commons.CacheExpiration) - return currency.Rate, nil - } - - rates, err := s.externalAPI.FetchRates(ctx) if err != nil { - return 0, err - } - - rate, ok := rates.Rates[code] - if !ok { - s.negativeCache.Store(code, struct{}{}) - go func() { - time.Sleep(commons.CacheExpiration) - s.negativeCache.Delete(code) - }() return 0, fmt.Errorf("%w: %s", model.ErrCurrencyNotFound, code) } - currency = &model.Currency{ - Code: strings.ToUpper(code), - Rate: rate, - UpdatedAt: time.Now(), - } - err = s.repo.Create(ctx, currency) - if err != nil { - return 0, err - } + s.cache.Set(ctx, code, currency.Rate, 1*time.Hour) - s.cache.Set(ctx, code, rate, 1*time.Hour) - return rate, nil + return currency.Rate, nil } func (s *CurrencyService) AddCurrency(ctx context.Context, currency *model.Currency) error { diff --git a/internal/service/currency_service_test.go b/internal/service/currency_service_test.go index dca7ed503..9c1680764 100644 --- a/internal/service/currency_service_test.go +++ b/internal/service/currency_service_test.go @@ -3,7 +3,6 @@ package service_test import ( "context" "errors" - "sync" "testing" "time" @@ -71,55 +70,23 @@ func (m *mockCache) Delete(ctx context.Context, key string) error { func (m *mockCache) Close() error { return nil } - -type mockExternalAPI struct { - rates map[string]float64 -} - -func (m *mockExternalAPI) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { - return &model.ExchangeRates{ - Rates: m.rates, - }, nil -} - -type mockExternalAPIWithCounter struct { - rates map[string]float64 - callCount int - mu sync.Mutex -} - -func (m *mockExternalAPIWithCounter) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { - m.mu.Lock() - defer m.mu.Unlock() - m.callCount++ - return &model.ExchangeRates{Rates: m.rates}, nil -} - -func (m *mockExternalAPIWithCounter) GetCallCount() int { - m.mu.Lock() - defer m.mu.Unlock() - return m.callCount -} - func TestCurrencyService_Convert(t *testing.T) { repo := &mockRepository{ currencies: map[string]*model.Currency{ "USD": {Code: "USD", Rate: 1.0}, "EUR": {Code: "EUR", Rate: 0.85}, + "GBP": {Code: "GBP", Rate: 0.75}, }, } cache := &mockCache{ - data: map[string]float64{}, - } - externalAPI := &mockExternalAPI{ - rates: map[string]float64{ + data: map[string]float64{ "USD": 1.0, "EUR": 0.85, "GBP": 0.75, }, } - currencyService := service.NewCurrencyService(repo, cache, externalAPI) + currencyService := service.NewCurrencyService(repo, cache) tests := []struct { name string @@ -127,80 +94,27 @@ func TestCurrencyService_Convert(t *testing.T) { to string amount float64 expected float64 - expectedError error + expectedError bool }{ - {"USD to EUR", "USD", "EUR", 100, 85, nil}, - {"EUR to USD", "EUR", "USD", 85, 100, nil}, - {"USD to GBP", "USD", "GBP", 100, 75, nil}, - {"From currency not found", "XYZ", "USD", 100, 0, model.ErrCurrencyNotFound}, - {"To currency not found", "USD", "XYZ", 100, 0, model.ErrCurrencyNotFound}, + {"USD to EUR", "USD", "EUR", 100, 85, false}, + {"EUR to GBP", "EUR", "GBP", 100, 88.24, false}, + {"GBP to USD", "GBP", "USD", 75, 100, false}, + {"Invalid from currency", "INVALID", "USD", 100, 0, true}, + {"Invalid to currency", "USD", "INVALID", 100, 0, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := currencyService.Convert(context.Background(), tt.from, tt.to, tt.amount) - if tt.expectedError != nil { + if tt.expectedError { assert.Error(t, err) - assert.True(t, errors.Is(err, tt.expectedError), "Expected error %v, but got %v", tt.expectedError, err) - if tt.expectedError == model.ErrCurrencyNotFound { - assert.Contains(t, err.Error(), "currency not found") - if tt.from == "XYZ" { - assert.Contains(t, err.Error(), tt.from, "Error should contain the 'from' currency code") - } else { - assert.Contains(t, err.Error(), tt.to, "Error should contain the 'to' currency code") - } - } } else { assert.NoError(t, err) - assert.InDelta(t, tt.expected, result, 0.001, "Expected %f, but got %f", tt.expected, result) + assert.InDelta(t, tt.expected, result, 0.01) } }) } - - t.Run("Negative cache", func(t *testing.T) { - repo := &mockRepository{currencies: map[string]*model.Currency{}} - cache := &mockCache{data: map[string]float64{}} - externalAPI := &mockExternalAPIWithCounter{rates: map[string]float64{}} - currencyService := service.NewCurrencyService(repo, cache, externalAPI) - - _, err1 := currencyService.Convert(context.Background(), "XYZ", "USD", 100) - assert.Error(t, err1) - assert.True(t, errors.Is(err1, model.ErrCurrencyNotFound)) - assert.Equal(t, 1, externalAPI.GetCallCount(), "Expected external API to be called once") - - _, err2 := currencyService.Convert(context.Background(), "XYZ", "USD", 100) - assert.Error(t, err2) - assert.True(t, errors.Is(err2, model.ErrCurrencyNotFound)) - assert.Equal(t, 1, externalAPI.GetCallCount(), "Expected external API to still have been called only once") - - _, err3 := currencyService.Convert(context.Background(), "ABC", "USD", 100) - assert.Error(t, err3) - assert.True(t, errors.Is(err3, model.ErrCurrencyNotFound)) - assert.Equal(t, 2, externalAPI.GetCallCount(), "Expected external API to be called a second time for a new currency") - }) - t.Run("Concurrent requests", func(t *testing.T) { - var wg sync.WaitGroup - results := make([]float64, 10) - errors := make([]error, 10) - - for i := 0; i < 10; i++ { - wg.Add(1) - go func(index int) { - defer wg.Add(-1) - result, err := currencyService.Convert(context.Background(), "USD", "EUR", 100) - results[index] = result - errors[index] = err - }(i) - } - - wg.Wait() - - for i := 0; i < 10; i++ { - assert.NoError(t, errors[i]) - assert.InDelta(t, 85.0, results[i], 0.001) - } - }) } func TestCurrencyService_AddCurrency(t *testing.T) { @@ -210,11 +124,8 @@ func TestCurrencyService_AddCurrency(t *testing.T) { cache := &mockCache{ data: make(map[string]float64), } - externalAPI := &mockExternalAPI{ - rates: make(map[string]float64), - } - currencyService := service.NewCurrencyService(repo, cache, externalAPI) + currencyService := service.NewCurrencyService(repo, cache) ctx := context.Background() userID := uuid.New() @@ -270,11 +181,8 @@ func TestCurrencyService_UpdateCurrency(t *testing.T) { cache := &mockCache{ data: make(map[string]float64), } - externalAPI := &mockExternalAPI{ - rates: make(map[string]float64), - } - currencyService := service.NewCurrencyService(repo, cache, externalAPI) + currencyService := service.NewCurrencyService(repo, cache) ctx := context.Background() userID := uuid.New() @@ -323,11 +231,8 @@ func TestCurrencyService_RemoveCurrency(t *testing.T) { "EUR": 0.85, }, } - externalAPI := &mockExternalAPI{ - rates: map[string]float64{}, - } - currencyService := service.NewCurrencyService(repo, cache, externalAPI) + currencyService := service.NewCurrencyService(repo, cache) tests := []struct { name string From b94f2a1e58c11b371cd1cc685f16d5cc9665cf26 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 21:51:01 -0300 Subject: [PATCH 129/141] docs(readme): Update README with additional instruction for `AllowedCurrencyLength` constant Added clarification to the README regarding the `AllowedCurrencyLength` constant. Users are now informed that changes to this constant also require updating the `005_expand_currency_code.sql` migration, because there we set the column type as CHAR(5). --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 602f0ad17..d209289c7 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ SERVER_PORT=8080 The `internal/commons/constants.go` file contains important constants that can be adjusted to fine-tune the API's behavior: -- `AllowedCurrencyLength`: Maximum length of currency codes (default: 5). +- `AllowedCurrencyLength`: Maximum length of currency codes (default: 5). For this one you'll also need to change the `005_expand_currency_code.sql` migration - `MinimumCurrencyLength`: Minimum length of currency codes (default: 3). - `AllowedRPS`: Rate limit for API requests per second (default: 10). - `ExternalClientMaxRetries`: Maximum number of retries for external API calls (default: 3). From 2c4a89ff92ec43628faafdef87f95e383ecfc8c1 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 8 Aug 2024 22:28:41 -0300 Subject: [PATCH 130/141] docs(readme): fix typo in README file This commit removes a typo in the end of the readme file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d209289c7..4d78b53b6 100644 --- a/README.md +++ b/README.md @@ -721,6 +721,6 @@ There are a lot of improvements that could be made to this project, I decided to I learned a lot while doing this challenge, there were a lot of things that could be improved and I'm going to keep studying so I can improve my skills and be able to do better in my next projects. It was a bit difficult to find the time to do this project, but I'm happy to have done it and I'm happy with the result. -

2 +

Challange accepted

From 513bebcb57ca59bf5436686ed728bf2c7bdd9152 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 01:08:33 -0300 Subject: [PATCH 131/141] refactor(worker): enhance logging by using logger and use commons constants This commit enhances the rate updater by using the logger to handle the error logs of the job. Other changes were cleaning up code smell and updating the docs, as it follows: - Added `RateUpdaterInterval` constant to `constants.go` to allow an easiear and more readable configuration of the rate updater interval. - Updated the Rate Updater initialization to utilize this new constant. - Replaced `log` with `logger` for improved logging consistency throughout the `RateUpdater`. - Updated the README to document the new `RateUpdaterInterval` constant. --- README.md | 1 + internal/commons/constants.go | 1 + internal/server/server.go | 2 +- internal/worker/rate_updater.go | 17 +++++++++-------- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4d78b53b6..37942708c 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ The `internal/commons/constants.go` file contains important constants that can b - `ExternalClientBaseDelay`: Base delay for exponential backoff in external API calls (default: 1 second). - `ExternalClientMaxDelay`: Maximum delay for exponential backoff in external API calls (default: 30 seconds). - `RateUpdaterCacheExipiration`: Expiration time for cached exchange rates (default: 1 hour). +- `RateUpdaterInterval`: Interval for updating exchange rates (default: 1 hour). - `ServerIdleTimeout`: Server idle timeout (default: 1 minute). - `ServerReadTimeout`: Server read timeout (default: 10 seconds). - `ServerWriteTimeout`: Server write timeout (default: 30 seconds). diff --git a/internal/commons/constants.go b/internal/commons/constants.go index 4072f1fd3..6265a3e28 100644 --- a/internal/commons/constants.go +++ b/internal/commons/constants.go @@ -11,6 +11,7 @@ const ( ExternalClientBaseDelay = time.Second ExternalClientMaxDelay = 30 * time.Second RateUpdaterCacheExipiration = 1 * time.Hour + RateUpdaterInterval = 1 * time.Hour ServerIdleTimeout = time.Minute ServerReadTimeout = 10 * time.Second ServerWriteTimeout = 30 * time.Second diff --git a/internal/server/server.go b/internal/server/server.go index 454be7948..ad3e0f63f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -46,7 +46,7 @@ func NewServer(config Config) (*Server, error) { externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) currencyService := service.NewCurrencyService(repo, redisCache) userService := service.NewUserService(userRepo) - rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, 1*time.Hour) + rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, commons.RateUpdaterInterval) logger.InitLogger(logRepo) partManager := logger.NewPartitionManager(logRepo) if err := partManager.Start(context.Background()); err != nil { diff --git a/internal/worker/rate_updater.go b/internal/worker/rate_updater.go index 40115f693..0ab643a95 100644 --- a/internal/worker/rate_updater.go +++ b/internal/worker/rate_updater.go @@ -8,6 +8,7 @@ import ( "github.com/Lutefd/challenge-bravo/internal/cache" "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/repository" ) @@ -31,7 +32,7 @@ func NewRateUpdater(repo repository.CurrencyRepository, cache cache.Cache, exter func (ru *RateUpdater) Start(ctx context.Context) { ticker := time.NewTicker(ru.interval) if err := ru.populateRates(ctx); err != nil { - log.Printf("error updating rates on startup: %v", err) + logger.Errorf("error updating rates on startup: %v", err) } defer ticker.Stop() @@ -42,7 +43,7 @@ func (ru *RateUpdater) Start(ctx context.Context) { return case <-ticker.C: if err := ru.updateRates(ctx); err != nil { - log.Printf("error updating rates: %v", err) + logger.Errorf("error updating rates: %v", err) } } } @@ -62,11 +63,11 @@ func (ru *RateUpdater) updateRates(ctx context.Context) error { } if err := ru.repo.Update(ctx, currency); err != nil { - log.Printf("failed to update currency %s in repository: %v", code, err) + logger.Errorf("failed to update currency %s in repository: %v", code, err) } if err := ru.cache.Set(ctx, code, rate, 1*time.Hour); err != nil { - log.Printf("failed to update currency %s in cache: %v", code, err) + logger.Errorf("failed to update currency %s in cache: %v", code, err) } } @@ -91,22 +92,22 @@ func (ru *RateUpdater) populateRates(ctx context.Context) error { if err.Error() == "currency not found" { err = ru.repo.Create(ctx, currency) if err != nil { - log.Printf("failed to create currency %s in repository: %v", code, err) + logger.Errorf("failed to create currency %s in repository: %v", code, err) continue } } else { - log.Printf("failed to get currency %s in repository: %v", code, err) + logger.Errorf("failed to get currency %s in repository: %v", code, err) continue } } else { err = ru.repo.Update(ctx, currency) if err != nil { - log.Printf("failed to update currency %s in repository: %v", code, err) + logger.Errorf("failed to update currency %s in repository: %v", code, err) continue } } if err := ru.cache.Set(ctx, code, rate, commons.RateUpdaterCacheExipiration); err != nil { - log.Printf("failed to update currency %s in cache: %v", code, err) + logger.Errorf("failed to update currency %s in cache: %v", code, err) } } From 505a470b38bcdf62978494788d2092eda3838ce0 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 09:15:20 -0300 Subject: [PATCH 132/141] refactor(config): move the config functionality for the commons package This commit moves the config functionality from the server package to the commons package, as the seeding and rate updating were moved into separate services it wasn't only the server using the config anymore and it made sense to move it to the commons package. The changes are just changes of which package is being called --- cmd/api/main.go | 3 ++- cmd/seed/seed.go | 6 +++--- cmd/seed/seed_test.go | 6 +++--- internal/{server => commons}/config.go | 2 +- internal/{server => commons}/config_test.go | 12 ++++++------ internal/server/server.go | 12 ++---------- tests/e2e_test.go | 5 +++-- 7 files changed, 20 insertions(+), 26 deletions(-) rename internal/{server => commons}/config.go (99%) rename internal/{server => commons}/config_test.go (90%) diff --git a/cmd/api/main.go b/cmd/api/main.go index 8a14c22da..f0ddc7eb5 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -6,6 +6,7 @@ import ( "os" "os/signal" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/server" "github.com/joho/godotenv" ) @@ -15,7 +16,7 @@ func main() { log.Printf("Error loading .env file: %v", err) } - config, err := server.LoadConfig() + config, err := commons.LoadConfig() if err != nil { log.Fatalf("Failed to load configuration: %v", err) } diff --git a/cmd/seed/seed.go b/cmd/seed/seed.go index b57db9292..f49ca0b2b 100644 --- a/cmd/seed/seed.go +++ b/cmd/seed/seed.go @@ -7,8 +7,8 @@ import ( "log" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" - "github.com/Lutefd/challenge-bravo/internal/server" "github.com/google/uuid" "github.com/joho/godotenv" _ "github.com/lib/pq" @@ -16,7 +16,7 @@ import ( ) type dependencies struct { - loadConfig func() (server.Config, error) + loadConfig func() (commons.Config, error) openDB func(driverName, dataSourceName string) (*sql.DB, error) newUUID func() uuid.UUID timeNow func() time.Time @@ -24,7 +24,7 @@ type dependencies struct { } var defaultDeps = dependencies{ - loadConfig: server.LoadConfig, + loadConfig: commons.LoadConfig, openDB: sql.Open, newUUID: uuid.New, timeNow: time.Now, diff --git a/cmd/seed/seed_test.go b/cmd/seed/seed_test.go index eb5bc4d8a..1dcb33aac 100644 --- a/cmd/seed/seed_test.go +++ b/cmd/seed/seed_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" - "github.com/Lutefd/challenge-bravo/internal/server" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,8 +21,8 @@ func TestRun(t *testing.T) { defer db.Close() mockDeps := dependencies{ - loadConfig: func() (server.Config, error) { - return server.Config{PostgresConn: "mock"}, nil + loadConfig: func() (commons.Config, error) { + return commons.Config{PostgresConn: "mock"}, nil }, openDB: func(driverName, dataSourceName string) (*sql.DB, error) { return db, nil diff --git a/internal/server/config.go b/internal/commons/config.go similarity index 99% rename from internal/server/config.go rename to internal/commons/config.go index 95782b193..045490d2e 100644 --- a/internal/server/config.go +++ b/internal/commons/config.go @@ -1,4 +1,4 @@ -package server +package commons import ( "fmt" diff --git a/internal/server/config_test.go b/internal/commons/config_test.go similarity index 90% rename from internal/server/config_test.go rename to internal/commons/config_test.go index 35f744d2e..1c4312aaa 100644 --- a/internal/server/config_test.go +++ b/internal/commons/config_test.go @@ -1,11 +1,11 @@ -package server_test +package commons_test import ( "os" "strings" "testing" - "github.com/Lutefd/challenge-bravo/internal/server" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/stretchr/testify/assert" ) @@ -34,7 +34,7 @@ func TestLoadConfig(t *testing.T) { setEnv("API_KEY", "my-api-key") setEnv("SERVER_PORT", "8080") - config, err := server.LoadConfig() + config, err := commons.LoadConfig() assert.NoError(t, err) assert.Equal(t, "password", config.RedisPass) @@ -47,7 +47,7 @@ func TestLoadConfig(t *testing.T) { t.Run("Missing environment variables", func(t *testing.T) { os.Clearenv() - _, err := server.LoadConfig() + _, err := commons.LoadConfig() assert.Error(t, err) assert.Contains(t, err.Error(), "configuration errors occurred") @@ -64,7 +64,7 @@ func TestLoadConfig(t *testing.T) { setEnv("API_KEY", "my-api-key") setEnv("SERVER_PORT", "invalid-port") - _, err := server.LoadConfig() + _, err := commons.LoadConfig() assert.Error(t, err) assert.Contains(t, err.Error(), "configuration errors occurred") @@ -75,7 +75,7 @@ func TestLoadConfig(t *testing.T) { setEnv("REDIS_PASSWORD", "password") setEnv("REDIS_ADDR", "localhost:6379") - _, err := server.LoadConfig() + _, err := commons.LoadConfig() assert.Error(t, err) assert.Contains(t, err.Error(), "configuration errors occurred") diff --git a/internal/server/server.go b/internal/server/server.go index ad3e0f63f..d7f0f17dc 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -11,22 +11,19 @@ import ( "github.com/Lutefd/challenge-bravo/internal/logger" "github.com/Lutefd/challenge-bravo/internal/repository" "github.com/Lutefd/challenge-bravo/internal/service" - "github.com/Lutefd/challenge-bravo/internal/worker" ) type Server struct { - config Config + config commons.Config httpServer *http.Server Router http.Handler - rateUpdater *worker.RateUpdater currencyRepo repository.CurrencyRepository currencyCache cache.Cache - externalAPI worker.ExternalAPIClient userRepo repository.UserRepository logRepo repository.LogRepository } -func NewServer(config Config) (*Server, error) { +func NewServer(config commons.Config) (*Server, error) { repo, err := repository.NewPostgresCurrencyRepository(config.PostgresConn, nil) if err != nil { return nil, fmt.Errorf("failed to initialize repository: %w", err) @@ -43,10 +40,8 @@ func NewServer(config Config) (*Server, error) { if err != nil { return nil, fmt.Errorf("failed to initialize cache: %w", err) } - externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) currencyService := service.NewCurrencyService(repo, redisCache) userService := service.NewUserService(userRepo) - rateUpdater := worker.NewRateUpdater(repo, redisCache, externalAPI, commons.RateUpdaterInterval) logger.InitLogger(logRepo) partManager := logger.NewPartitionManager(logRepo) if err := partManager.Start(context.Background()); err != nil { @@ -56,8 +51,6 @@ func NewServer(config Config) (*Server, error) { config: config, currencyRepo: repo, currencyCache: redisCache, - externalAPI: externalAPI, - rateUpdater: rateUpdater, userRepo: userRepo, logRepo: logRepo, } @@ -76,7 +69,6 @@ func NewServer(config Config) (*Server, error) { } func (s *Server) Start(ctx context.Context) error { - go s.rateUpdater.Start(ctx) go func() { logger.Infof("Server started on port %d", s.config.ServerPort) if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 0c49bdafa..02445e82b 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -16,6 +16,7 @@ import ( "testing" "time" + "github.com/Lutefd/challenge-bravo/internal/commons" "github.com/Lutefd/challenge-bravo/internal/model" "github.com/Lutefd/challenge-bravo/internal/server" "github.com/google/uuid" @@ -68,7 +69,7 @@ func setup() error { return fmt.Errorf("error seeding database: %w", err) } - config, err := server.LoadConfig() + config, err := commons.LoadConfig() if err != nil { return fmt.Errorf("failed to load configuration: %w", err) } @@ -196,7 +197,7 @@ func teardown() error { } func setupTestServer(t *testing.T) { - config, err := server.LoadConfig() + config, err := commons.LoadConfig() require.NoError(t, err, "Failed to load config") config.PostgresConn = os.Getenv("TEST_POSTGRES_CONN") From 03e71813d986ef55db1f7a4433f7a54321ed439c Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 09:17:10 -0300 Subject: [PATCH 133/141] feat(worker): create its own executable and service for the worker This commit moves the worker functionality to its own service, it makes more sense than being ran in the background of the server, if this should scale to a distributted system you would have multiple workers running, one for each server, which is nonsense. --- Dockerfile.worker | 21 +++++ cmd/worker/worker.go | 156 +++++++++++++++++++++++++++++++++ cmd/worker/worker_test.go | 175 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 28 ++++++ 4 files changed, 380 insertions(+) create mode 100644 Dockerfile.worker create mode 100644 cmd/worker/worker.go create mode 100644 cmd/worker/worker_test.go diff --git a/Dockerfile.worker b/Dockerfile.worker new file mode 100644 index 000000000..073df983a --- /dev/null +++ b/Dockerfile.worker @@ -0,0 +1,21 @@ +FROM golang:1.22 AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ + +RUN go mod download +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker cmd/worker/worker.go + + +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +COPY --from=builder /app/worker . + +CMD ["./worker"] diff --git a/cmd/worker/worker.go b/cmd/worker/worker.go new file mode 100644 index 000000000..2019172a3 --- /dev/null +++ b/cmd/worker/worker.go @@ -0,0 +1,156 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/commons" + "github.com/Lutefd/challenge-bravo/internal/logger" + "github.com/Lutefd/challenge-bravo/internal/repository" + "github.com/Lutefd/challenge-bravo/internal/worker" + "github.com/joho/godotenv" +) + +type dependencies struct { + currencyRepo repository.CurrencyRepository + cache cache.Cache + logRepo repository.LogRepository + externalAPI worker.ExternalAPIClient + rateUpdater RateUpdater + partitionMgr PartitionManager +} + +type RateUpdater interface { + Start(ctx context.Context) +} + +type PartitionManager interface { + Start(ctx context.Context) error +} + +func main() { + if err := godotenv.Load(".env"); err != nil { + log.Printf("Error loading .env file: %v", err) + } + + config, err := commons.LoadConfig() + if err != nil { + log.Fatalf("Failed to load configuration: %v", err) + } + + deps, err := initDependencies(config) + if err != nil { + log.Fatalf("Failed to initialize dependencies: %v", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + errChan := make(chan error, 1) + go func() { + errChan <- runWorker(ctx, deps) + }() + + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) + + select { + case err := <-errChan: + if err != nil { + log.Fatalf("Worker failed: %v", err) + } + case <-signalChan: + log.Println("Shutdown signal received, initiating graceful shutdown...") + cancel() + + select { + case <-errChan: + log.Println("Worker shut down gracefully") + case <-time.After(30 * time.Second): + log.Println("Shutdown timed out") + } + } +} + +func initDependencies(config commons.Config) (*dependencies, error) { + currencyRepo, err := repository.NewPostgresCurrencyRepository(config.PostgresConn, nil) + if err != nil { + return nil, fmt.Errorf("failed to initialize repository: %w", err) + } + + redisCache, err := cache.NewRedisCache(config.RedisAddr, config.RedisPass) + if err != nil { + return nil, fmt.Errorf("failed to initialize cache: %w", err) + } + + logRepo, err := repository.NewPostgresLogRepository(config.PostgresConn, nil) + if err != nil { + return nil, fmt.Errorf("failed to initialize log repository: %w", err) + } + + externalAPI := worker.NewOpenExchangeRatesClient(config.APIKey) + rateUpdater := worker.NewRateUpdater(currencyRepo, redisCache, externalAPI, commons.RateUpdaterInterval) + partManager := logger.NewPartitionManager(logRepo) + + return &dependencies{ + currencyRepo: currencyRepo, + cache: redisCache, + logRepo: logRepo, + externalAPI: externalAPI, + rateUpdater: rateUpdater, + partitionMgr: partManager, + }, nil +} + +func runWorker(ctx context.Context, deps *dependencies) error { + var wg sync.WaitGroup + errChan := make(chan error, 1) + + wg.Add(1) + go func() { + defer wg.Done() + + logger.InitLogger(deps.logRepo) + + if err := deps.partitionMgr.Start(ctx); err != nil { + errChan <- fmt.Errorf("failed to start partition manager: %w", err) + return + } + + deps.rateUpdater.Start(ctx) + + <-ctx.Done() + log.Println("Worker shutting down...") + }() + + go func() { + wg.Wait() + close(errChan) + }() + + defer func() { + if err := deps.currencyRepo.Close(); err != nil { + log.Printf("Error closing currency repository: %v", err) + } + if err := deps.cache.Close(); err != nil { + log.Printf("Error closing cache: %v", err) + } + if err := deps.logRepo.Close(); err != nil { + log.Printf("Error closing log repository: %v", err) + } + }() + + select { + case err := <-errChan: + return err + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/cmd/worker/worker_test.go b/cmd/worker/worker_test.go new file mode 100644 index 000000000..660f999d9 --- /dev/null +++ b/cmd/worker/worker_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/Lutefd/challenge-bravo/internal/cache" + "github.com/Lutefd/challenge-bravo/internal/repository" +) + +// Mock implementations (same as before, but with some additions) + +type mockCurrencyRepository struct { + repository.CurrencyRepository + closeCalled bool + closeErr error +} + +func (m *mockCurrencyRepository) Close() error { + m.closeCalled = true + return m.closeErr +} + +type mockCache struct { + cache.Cache + closeCalled bool + closeErr error +} + +func (m *mockCache) Close() error { + m.closeCalled = true + return m.closeErr +} + +type mockLogRepository struct { + repository.LogRepository + closeCalled bool + closeErr error +} + +func (m *mockLogRepository) Close() error { + m.closeCalled = true + return m.closeErr +} + +type mockRateUpdater struct { + startCalled bool +} + +func (m *mockRateUpdater) Start(ctx context.Context) { + m.startCalled = true +} + +type mockPartitionManager struct { + startErr error +} + +func (m *mockPartitionManager) Start(ctx context.Context) error { + return m.startErr +} + +func TestRunWorker(t *testing.T) { + tests := []struct { + name string + deps *dependencies + expectedErrMsg string + timeout time.Duration + expectRateUpdaterStart bool + setupContext func() (context.Context, context.CancelFunc) + }{ + { + name: "Success case", + deps: &dependencies{ + currencyRepo: &mockCurrencyRepository{}, + cache: &mockCache{}, + logRepo: &mockLogRepository{}, + rateUpdater: &mockRateUpdater{}, + partitionMgr: &mockPartitionManager{}, + }, + expectedErrMsg: "context deadline exceeded", + timeout: 100 * time.Millisecond, + expectRateUpdaterStart: true, + setupContext: func() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), 100*time.Millisecond) + }, + }, + { + name: "Partition manager start error", + deps: &dependencies{ + currencyRepo: &mockCurrencyRepository{}, + cache: &mockCache{}, + logRepo: &mockLogRepository{}, + rateUpdater: &mockRateUpdater{}, + partitionMgr: &mockPartitionManager{startErr: errors.New("partition manager error")}, + }, + expectedErrMsg: "failed to start partition manager: partition manager error", + timeout: 100 * time.Millisecond, + expectRateUpdaterStart: false, + setupContext: func() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), 100*time.Millisecond) + }, + }, + { + name: "Context cancelled immediately", + deps: &dependencies{ + currencyRepo: &mockCurrencyRepository{}, + cache: &mockCache{}, + logRepo: &mockLogRepository{}, + rateUpdater: &mockRateUpdater{}, + partitionMgr: &mockPartitionManager{}, + }, + expectedErrMsg: "context canceled", + expectRateUpdaterStart: false, + setupContext: func() (context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + return ctx, func() {} + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx, cancel := tt.setupContext() + defer cancel() + + err := runWorker(ctx, tt.deps) + + if tt.expectedErrMsg != "" { + if err == nil { + t.Errorf("Expected error with message '%s', but got no error", tt.expectedErrMsg) + } else if err.Error() != tt.expectedErrMsg { + t.Errorf("Expected error with message '%s', but got '%s'", tt.expectedErrMsg, err.Error()) + } + } else if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + mockRateUpdater, ok := tt.deps.rateUpdater.(*mockRateUpdater) + if !ok { + t.Fatal("rateUpdater is not a mockRateUpdater") + } + if tt.expectRateUpdaterStart && !mockRateUpdater.startCalled { + t.Error("Expected RateUpdater.Start to be called, but it wasn't") + } else if !tt.expectRateUpdaterStart && mockRateUpdater.startCalled { + t.Error("Expected RateUpdater.Start not to be called, but it was") + } + + mockCurrencyRepo, ok := tt.deps.currencyRepo.(*mockCurrencyRepository) + if !ok { + t.Fatal("currencyRepo is not a mockCurrencyRepository") + } + mockCache, ok := tt.deps.cache.(*mockCache) + if !ok { + t.Fatal("cache is not a mockCache") + } + mockLogRepo, ok := tt.deps.logRepo.(*mockLogRepository) + if !ok { + t.Fatal("logRepo is not a mockLogRepository") + } + + if !mockCurrencyRepo.closeCalled { + t.Error("Expected currency repository Close to be called") + } + if !mockCache.closeCalled { + t.Error("Expected cache Close to be called") + } + if !mockLogRepo.closeCalled { + t.Error("Expected log repository Close to be called") + } + }) + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 4abf74260..14aa9bd79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,8 @@ services: condition: service_started migrate: condition: service_completed_successfully + worker: + condition: service_started environment: REDIS_PASSWORD: ${REDIS_PASSWORD} POSTGRES_HOST: db @@ -63,5 +65,31 @@ services: networks: - mynetwork + worker: + build: + context: . + dockerfile: Dockerfile.worker + ports: + - "8081:8081" + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD} + POSTGRES_HOST: db + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_NAME: ${POSTGRES_NAME} + POSTGRES_PORT: ${POSTGRES_PORT} + REDIS_ADDR: redis:6379 + API_KEY: ${API_KEY} + SERVER_PORT: ${SERVER_PORT} + networks: + - mynetwork + networks: mynetwork: From 040a3c8604249a7315e8454abb45a30ba0d2d938 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 09:18:35 -0300 Subject: [PATCH 134/141] docs(README): update README.md to reflect refactors and architecture change This commit updates the README to reflect the changes on the refactoring of the confing and the improvement of the worker to its own service. It also removes some repeated text from when I was composing the readme from different notes. --- README.md | 320 +----------------------------------------------------- 1 file changed, 5 insertions(+), 315 deletions(-) diff --git a/README.md b/README.md index 37942708c..708532daf 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,8 @@ This challenge was built using a modern, scalable technology stack: 3. **Redis Cache**: Caches frequently accessed exchange rates for improved performance. 4. **Migrator**: A standalone service for running database migrations to create and update the database schema, as well as seeding the database for a default admin user. +5. **Rate Updater**: A standalone service that fetches the latest exchange rates from an external API and updates the database and the cache + with the new values. ## Features @@ -133,6 +135,8 @@ API_KEY=75cc9115d3524769a498914d118e093a SERVER_PORT=8080 ``` +To modify and add more environment variables, please create and validate them in the `internal/commons/config.go` file. + ### Constants Configuration The `internal/commons/constants.go` file contains important constants that can be adjusted to fine-tune the API's behavior: @@ -386,320 +390,6 @@ Common error status codes: The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests. -This version of the API allows for the addition of new real currencies that will be tracked and fictional currencies that will be stored. - -**Additionally, it should be noted that the API's base currency is USD**. - -## Technology Stack - -This challenge was built using a modern, scalable technology stack: - -- **Go (Golang) 1.22**: The core programming language, chosen for its performance, concurrency support, and robust standard library. -- **PostgreSQL**: A powerful, open-source relational database used for persistent storage of currency data, user information, and logs. -- **Redis**: An in-memory data structure store used as a caching layer to improve performance of frequent currency rate lookups. -- **Docker**: Used for containerization, ensuring consistent environments across development and production. -- **Docker Compose**: A tool for defining and running multi-container Docker applications, simplifying the setup and deployment process. -- **Chi Router**: A lightweight, idiomatic HTTP router for Go, providing a flexible and composable way to build APIs. - -## Services - -1. **API Application**: The main service handling HTTP requests for currency conversion, user management, and currency administration. -2. **PostgreSQL Database**: Stores user data, currency information, and logs. -3. **Redis Cache**: Caches frequently accessed exchange rates for improved performance. -4. **Migrator**: A standalone service for running database migrations to create and update the database schema, as well as - seeding the database for a default admin user. - -## Features - -- Real-time currency conversion -- User registration and authentication -- Admin-only currency management (add, update, remove currencies) -- Rate limiting to prevent abuse -- Logging and auditing of operations -- Scheduled updates of exchange rates -- Caching of frequently accessed data -- Comprehensive error handling and logging -- Containerized deployment for easy scaling and management - -## Setup and Configuration - -This section outlines how to setup and configure this api, including environment variables and important constants. - -One thing that is important to note is that the API uses an [external service](https://openexchangerates.org/) to get the exchange rates, so you will need -an API token to use the service. To facilitate this proccess please use this API Key: `75cc9115d3524769a498914d118e093a` - -### Environment Variables - -Create a `.env` file in the project root with the following variables: - -- `REDIS_PASSWORD`: Password for the Redis instance. -- `REDIS_ADDR`: Address and port of the Redis instance (e.g., "localhost:6379"). -- `POSTGRES_USER`: Username for the PostgreSQL database. -- `POSTGRES_PASSWORD`: Password for the PostgreSQL database. -- `POSTGRES_HOST`: Hostname of the PostgreSQL database. -- `POSTGRES_PORT`: Port number for the PostgreSQL database. -- `POSTGRES_NAME`: Name of the PostgreSQL database. -- `API_KEY`: API key for the OpenExchangeRates. -- `SERVER_PORT`: Port on which the API server will listen. - -Example `.env` file: - -``` -REDIS_PASSWORD=myredispassword -REDIS_ADDR=redis:6379 -POSTGRES_USER=myuser -POSTGRES_PASSWORD=mypassword -POSTGRES_HOST=db -POSTGRES_PORT=5432 -POSTGRES_NAME=currency_db -API_KEY=75cc9115d3524769a498914d118e093a -SERVER_PORT=8080 -``` - -### Constants Configuration - -The `internal/commons/constants.go` file contains important constants that can be adjusted to fine-tune the API's behavior: - -- `AllowedCurrencyLength`: Maximum length of currency codes (default: 5). -- `MinimumCurrencyLength`: Minimum length of currency codes (default: 3). -- `AllowedRPS`: Rate limit for API requests per second (default: 10). -- `ExternalClientMaxRetries`: Maximum number of retries for external API calls (default: 3). -- `ExternalClientBaseDelay`: Base delay for exponential backoff in external API calls (default: 1 second). -- `ExternalClientMaxDelay`: Maximum delay for exponential backoff in external API calls (default: 30 seconds). -- `RateUpdaterCacheExipiration`: Expiration time for cached exchange rates (default: 1 hour). -- `ServerIdleTimeout`: Server idle timeout (default: 1 minute). -- `ServerReadTimeout`: Server read timeout (default: 10 seconds). -- `ServerWriteTimeout`: Server write timeout (default: 30 seconds). - -To modify these constants, edit the `internal/commons/constants.go` file and rebuild the application. - -### Docker Setup - -To run the application using Docker, follow these steps: - -1. Ensure you have Docker and Docker Compose installed on your system. - -2. Clone the repository: - - ```bash - git clone git@github.com:Lutefd/challenge-bravo.git - cd challenge-bravo - ``` - -3. Create a `.env` file in the project root and configure the necessary environment variables, a `.env.sample` file is provided (see API Configuration docs for details). - -4. Build and start the Docker containers: - - ``` - docker compose up --build - ``` - -5. The API will be available at `http://localhost:8080` if you're using the default port - and host provided in the `.env.sample`. - -### Local Development - -For local development without Docker: - -1. Ensure you have Go 1.22 or later installed. -2. Install [goose](https://github.com/pressly/goose) for database migrations. -3. Set up the environment variables as described in the API Configuration docs. -4. Run the database migrations: - ``` - make migrate-up - ``` -5. Start the application: - ``` - make run - ``` - -### Testing - -Run the test suite with: - -``` -make test -``` - -For a more verbose output: - -``` -go test ./... -v -``` - -## API Documentation - -This section details the endpoints and operations available in this API. - -### Base URL - -All endpoints are relative to: `http://localhost:8080/api/v1` - -### Authentication - -Most endpoints require authentication using an API key. Include the API key in the `X-API-Key` header of your requests. - -### Endpoints - -#### Currency Conversion - -##### GET /currency/convert - -Convert an amount from one currency to another. - -Query Parameters: - -- `from`: Source currency code (e.g., "USD") -- `to`: Target currency code (e.g., "EUR") -- `amount`: Amount to convert (numeric) - -Example Request: - -``` -GET /api/v1/currency/convert?from=USD&to=EUR&amount=100 -``` - -Example Response: - -```json -{ - "from": "USD", - "to": "EUR", - "amount": 100, - "result": 85 -} -``` - -#### Currency Management (Admin only) - -##### POST /currency - -Add a new currency. - -Request Body: - -```json -{ - "code": "JPY", - "rate_to_usd": 110.5 -} -``` - -Example Response: - -```json -{ - "message": "currency added successfully" -} -``` - -##### PUT /currency/{code} - -Update an existing currency. - -Request Body: - -```json -{ - "rate_to_usd": 111.2 -} -``` - -Example Response: - -```json -{ - "message": "currency updated successfully" -} -``` - -##### DELETE /currency/{code} - -Remove a currency. - -Example Response: - -```json -{ - "message": "currency removed successfully" -} -``` - -#### User Management - -##### POST /auth/register - -Register a new user. - -Request Body: - -```json -{ - "username": "newuser", - "password": "securepassword" -} -``` - -Example Response: - -```json -{ - "id": "123e4567-e89b-12d3-a456-426614174000", - "username": "newuser", - "role": "user", - "api_key": "your-api-key-here" -} -``` - -##### POST /auth/login - -Authenticate a user and retrieve their API key. - -Request Body: - -```json -{ - "username": "existinguser", - "password": "userpassword" -} -``` - -Example Response: - -```json -{ - "id": "123e4567-e89b-12d3-a456-426614174000", - "username": "existinguser", - "role": "user", - "api_key": "your-api-key-here" -} -``` - - Update(ctx context.Context, username, password string) error - -### Error Responses - -The API uses standard HTTP status codes to indicate the success or failure of requests. In case of an error, the response body will contain an error message: - -```json -{ - "error": "Description of the error" -} -``` - -Common error status codes: - -- 400: Bad Request (invalid input) -- 401: Unauthorized (missing or invalid API key) -- 403: Forbidden (insufficient permissions) -- 404: Not Found (resource not found) -- 429: Too Many Requests (rate limit exceeded) -- 500: Internal Server Error - -### Rate Limiting - -The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests. - ## Auto-Generated Code - This project used goose to execute migrations, although the migrations were written by hand, the migration code and execute is generated by [goose](https://github.com/pressly/goose). @@ -713,7 +403,7 @@ There are a lot of improvements that could be made to this project, I decided to - Rate limiting using a more robust solution like Redis, this would allow for a more distributed rate limiting system. The current rate limiting is done in memory and is not distributed, using the [Rate package](https://pkg.go.dev/golang.org/x/time/rate), it uses a token bucket algorithm to limit the number of requests per second. - Logging, the current logging system is very simple, it registers the internal erros and info logs in a postgres database, but it could be improved to use a more robust logging system like the ELK stack. I decided to keep it simple because the requirements didn't ask for a more robust logging system and as I was already using postgres for the database, I decided to use it for the logs as well since it can handle the load, I limited it to about 1000 logs in the channel, so it won't overload the database. -- The rate updater could be improved by making it more robust and into a separate service. Although it has a retry policy and a backoff policy, it could have a circuit breaker to prevent the service from being overloaded if the external service is down for a long time. It could also be separated into a separate service to prevent the main service to work better with a more distributed system. +- The rate updater could be improved by making it more robust and based on the last fetched timestamp. Although it has a retry policy and a backoff policy, it could have a circuit breaker to prevent the service from being overloaded if the external service is down for a long time. - The currency management could be improved by adding more features like a list of all currencies, and a more detailed view of each currency, with the possibility of adding more information like the name of the currency, the symbol, and the country of origin. Also due to currencies that have a lot of decimal places, it could be improved to handle more decimal places while rounding up for the ones that don't need it, currently we're using all of the decimal places provided by the external service. - The user management and security could be greatly improved, right now it's really simple with users not being able to do much, not even edit their own information, it could be improved by adding more features like password recovery, email verification, and more detailed user information. The security could be improved by adding more security features like 2FA, also adding more than just an X-API-Key for authentication, like JWT tokens. But this was a decision that I made to keep it simple and to focus on the core functionality of the project, while having the minimum user management required to use the API. - Tests could be better and could cover more of the errors that could happen in the system, I've only covered the basic errors that could happen in the system, but there are a lot of edge cases that could be tested. Also, the tests could be more robust and could use a more robust testing framework like [Ginkgo](https://onsi.github.io/ginkgo/). From eb07d2d7dd3dcb61080985a23ad42e3e9ee2bfd4 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 09:27:52 -0300 Subject: [PATCH 135/141] docs(models/maps): update c4 model and dependency map to reflect previous changes This commit updates the c4 model and the dependency map to reflect previous changes on the project. --- docs/c4/c4-model.mermaid | 76 ++++++++++++--------- docs/c4/c4-model.png | Bin 119430 -> 110468 bytes docs/dependency-map/dependency-map.mermaid | 73 +++++++++++--------- docs/dependency-map/dependency-map.png | Bin 98373 -> 97658 bytes 4 files changed, 86 insertions(+), 63 deletions(-) diff --git a/docs/c4/c4-model.mermaid b/docs/c4/c4-model.mermaid index b28f509e1..d65a61a29 100644 --- a/docs/c4/c4-model.mermaid +++ b/docs/c4/c4-model.mermaid @@ -1,50 +1,64 @@ graph TB subgraph "System Context" - U["User"] - A["Admin"] - E["External Exchange Rate API"] + User["User"] + Admin["Admin"] + ExternalAPI["External Exchange Rate API"] CES["Currency Exchange System"] end - U -->|"Uses"| CES - A -->|"Manages"| CES - E -->|"Provides rates"| CES + User -->|"Uses"| CES + Admin -->|"Manages"| CES + ExternalAPI -->|"Provides rates"| CES subgraph "Container" - API["API Application"] - DB["PostgreSQL Database"] - Cache["Redis Cache"] - Worker["Rate Updater Worker"] + API["API Application\n(Go)"] + Worker["Rate Updater Worker\n(Go)"] + DB["Database\n(PostgreSQL)"] + Cache["Cache\n(Redis)"] end CES -->|"Contains"| API + CES -->|"Contains"| Worker CES -->|"Contains"| DB CES -->|"Contains"| Cache - CES -->|"Contains"| Worker API -->|"Reads/Writes"| DB API -->|"Reads/Writes"| Cache Worker -->|"Updates"| DB Worker -->|"Updates"| Cache - Worker -->|"Fetches rates"| E - - subgraph "Component" - H["Handlers"] - S["Services"] - R["Repositories"] - M["Middleware"] - L["Logger"] + Worker -->|"Fetches rates"| ExternalAPI + + subgraph "Component (API Application)" + Handlers["Handlers"] + Services["Services"] + Repositories["Repositories"] + Middleware["Middleware"] + Logger["Logger"] + end + + API -->|"Contains"| Handlers + API -->|"Contains"| Services + API -->|"Contains"| Repositories + API -->|"Contains"| Middleware + API -->|"Contains"| Logger + + Handlers -->|"Uses"| Services + Services -->|"Uses"| Repositories + Handlers -->|"Uses"| Middleware + Services -->|"Uses"| Logger + Repositories -->|"Interacts with"| DB + Repositories -->|"Interacts with"| Cache + + subgraph "Component (Worker)" + RateUpdater["Rate Updater"] + ExternalClient["External API Client"] + PartitionManager["Partition Manager"] end - API -->|"Contains"| H - API -->|"Contains"| S - API -->|"Contains"| R - API -->|"Contains"| M - API -->|"Contains"| L - - H -->|"Uses"| S - S -->|"Uses"| R - H -->|"Uses"| M - S -->|"Uses"| L - R -->|"Interacts with"| DB - R -->|"Interacts with"| Cache + Worker -->|"Contains"| RateUpdater + Worker -->|"Contains"| ExternalClient + Worker -->|"Contains"| PartitionManager + + RateUpdater -->|"Uses"| ExternalClient + RateUpdater -->|"Updates"| Repositories + PartitionManager -->|"Manages"| DB diff --git a/docs/c4/c4-model.png b/docs/c4/c4-model.png index 7a0683b83f44d5fcffd0ba41806f8b4f86a5c157..94efebb5960425af1186db56d3566034f7367e84 100644 GIT binary patch literal 110468 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 z�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
2>8>0Xp4 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

hw+E4KW!XP0Vpk=mFqgmVhjBx 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�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 J!sR|O{{#;#blU&` From 548b247d4276fa07e06b4a761bafb92301b64a28 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 09:33:27 -0300 Subject: [PATCH 136/141] docs(README): update README.md to add the models and diagrams This commit along with fixing the table of contents, adds the documentations diagrams pngs into the readme itself. --- README.md | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 708532daf..ffa6de587 100644 --- a/README.md +++ b/README.md @@ -33,30 +33,9 @@ - [POST /auth/login](#post-authlogin) - [Error Responses](#error-responses) - [Rate Limiting](#rate-limiting) - - [Technology Stack](#technology-stack-1) - - [Services](#services-1) - - [Features](#features-1) - - [Setup and Configuration](#setup-and-configuration-1) - - [Environment Variables](#environment-variables-1) - - [Constants Configuration](#constants-configuration-1) - - [Docker Setup](#docker-setup-1) - - [Local Development](#local-development-1) - - [Testing](#testing-1) - - [API Documentation](#api-documentation-1) - - [Base URL](#base-url-1) - - [Authentication](#authentication-1) - - [Endpoints](#endpoints-1) - - [Currency Conversion](#currency-conversion-1) - - [GET /currency/convert](#get-currencyconvert-1) - - [Currency Management (Admin only)](#currency-management-admin-only-1) - - [POST /currency](#post-currency-1) - - [PUT /currency/{code}](#put-currencycode-1) - - [DELETE /currency/{code}](#delete-currencycode-1) - - [User Management](#user-management-1) - - [POST /auth/register](#post-authregister-1) - - [POST /auth/login](#post-authlogin-1) - - [Error Responses](#error-responses-1) - - [Rate Limiting](#rate-limiting-1) + - [C4 Diagram](#c4-diagram) + - [Dependencies Map](#dependencies-map) + - [Entity Relationship Diagram](#entity-relationship-diagram) - [Auto-Generated Code](#auto-generated-code) - [Improvements](#improvements) - [Final Thoughts](#final-thoughts) @@ -390,6 +369,18 @@ Common error status codes: The API implements rate limiting to prevent abuse in some endpoints. If you exceed the rate limit, you'll receive a 429 status code. Wait before making additional requests. +### C4 Diagram + +![C4 Diagram](docs/c4/c4-model.png) + +### Dependencies Map + +![Dependencies Map](docs/dependency-map/dependency-map.png) + +### Entity Relationship Diagram + +![ER Diagram](docs/entity-map/entity-map.png) + ## Auto-Generated Code - This project used goose to execute migrations, although the migrations were written by hand, the migration code and execute is generated by [goose](https://github.com/pressly/goose). From ba9650cc1ac8966a6524fe309b635629a2c88511 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 10:34:15 -0300 Subject: [PATCH 137/141] feat(worker): implement worker heartbeat mechanism and its constants This commit adds a heartbeat mechanism to help confirm it's working, this could evolve into a health check mechanism that would be checkable in the docker compose for container health. --- cmd/worker/worker.go | 13 ++++++++++++- internal/commons/constants.go | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cmd/worker/worker.go b/cmd/worker/worker.go index 2019172a3..90faf74e3 100644 --- a/cmd/worker/worker.go +++ b/cmd/worker/worker.go @@ -112,7 +112,18 @@ func initDependencies(config commons.Config) (*dependencies, error) { func runWorker(ctx context.Context, deps *dependencies) error { var wg sync.WaitGroup errChan := make(chan error, 1) - + go func() { + heartbeat := time.NewTicker(commons.WorkerHeartbeatInterval) + defer heartbeat.Stop() + for { + select { + case <-ctx.Done(): + return + case <-heartbeat.C: + log.Println("worker heartbeat") + } + } + }() wg.Add(1) go func() { defer wg.Done() diff --git a/internal/commons/constants.go b/internal/commons/constants.go index 6265a3e28..1d6fe1b6a 100644 --- a/internal/commons/constants.go +++ b/internal/commons/constants.go @@ -12,6 +12,7 @@ const ( ExternalClientMaxDelay = 30 * time.Second RateUpdaterCacheExipiration = 1 * time.Hour RateUpdaterInterval = 1 * time.Hour + WorkerHeartbeatInterval = 5 * time.Minute ServerIdleTimeout = time.Minute ServerReadTimeout = 10 * time.Second ServerWriteTimeout = 30 * time.Second From 39544bb4ac208a901977ce4396c813a52d15f009 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Fri, 9 Aug 2024 10:38:13 -0300 Subject: [PATCH 138/141] docs(README): update README to add new constants and possible improvements This commit adds the WorkerHeartbeatInterval constant to the config docs and adds a few points of improvements that could be done in the rate updater and its service --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ffa6de587..451995a0d 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ The `internal/commons/constants.go` file contains important constants that can b - `ExternalClientMaxDelay`: Maximum delay for exponential backoff in external API calls (default: 30 seconds). - `RateUpdaterCacheExipiration`: Expiration time for cached exchange rates (default: 1 hour). - `RateUpdaterInterval`: Interval for updating exchange rates (default: 1 hour). +- `WorkerHeartbeatInterval`: Interval for worker heartbeat (default: 5 minutes). - `ServerIdleTimeout`: Server idle timeout (default: 1 minute). - `ServerReadTimeout`: Server read timeout (default: 10 seconds). - `ServerWriteTimeout`: Server write timeout (default: 30 seconds). @@ -394,7 +395,7 @@ There are a lot of improvements that could be made to this project, I decided to - Rate limiting using a more robust solution like Redis, this would allow for a more distributed rate limiting system. The current rate limiting is done in memory and is not distributed, using the [Rate package](https://pkg.go.dev/golang.org/x/time/rate), it uses a token bucket algorithm to limit the number of requests per second. - Logging, the current logging system is very simple, it registers the internal erros and info logs in a postgres database, but it could be improved to use a more robust logging system like the ELK stack. I decided to keep it simple because the requirements didn't ask for a more robust logging system and as I was already using postgres for the database, I decided to use it for the logs as well since it can handle the load, I limited it to about 1000 logs in the channel, so it won't overload the database. -- The rate updater could be improved by making it more robust and based on the last fetched timestamp. Although it has a retry policy and a backoff policy, it could have a circuit breaker to prevent the service from being overloaded if the external service is down for a long time. +- The rate updater could be improved by making it more robust and based on the last fetched timestamp. Although it has a retry policy and a backoff policy, it could have a circuit breaker to prevent the service from being overloaded if the external service is down for a long time. It could also have a health check mechanism to help its docker service have a health condition. A catch-up mechanism could be added to fetch the rate updates that were missed while the service was down. - The currency management could be improved by adding more features like a list of all currencies, and a more detailed view of each currency, with the possibility of adding more information like the name of the currency, the symbol, and the country of origin. Also due to currencies that have a lot of decimal places, it could be improved to handle more decimal places while rounding up for the ones that don't need it, currently we're using all of the decimal places provided by the external service. - The user management and security could be greatly improved, right now it's really simple with users not being able to do much, not even edit their own information, it could be improved by adding more features like password recovery, email verification, and more detailed user information. The security could be improved by adding more security features like 2FA, also adding more than just an X-API-Key for authentication, like JWT tokens. But this was a decision that I made to keep it simple and to focus on the core functionality of the project, while having the minimum user management required to use the API. - Tests could be better and could cover more of the errors that could happen in the system, I've only covered the basic errors that could happen in the system, but there are a lot of edge cases that could be tested. Also, the tests could be more robust and could use a more robust testing framework like [Ginkgo](https://onsi.github.io/ginkgo/). From d1c1c1d5349e7a140682988eb0303036768d28f9 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Sat, 10 Aug 2024 10:16:54 -0300 Subject: [PATCH 139/141] docs(README): add seed admin credentials instructions in the readme This commit adds instructions for getting the ADMIN API Key created in the seed proccess along with the migrations. Evaluators should use them to test the protected endpoints. --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 451995a0d..f075fcb83 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,13 @@ To run the application using Docker, follow these steps: 5. The API will be available at `http://localhost:8080` if you're using the default port and host provided in the `.env.sample`. +6. For Endpoints like currency creation, update and delete you will need to use the admin user's API Key created by the migration, the credentials are: + ```json + { + "username": "admin", + "password": "password" + } +``` ### Local Development @@ -174,7 +181,13 @@ For local development without Docker: ``` make run ``` - +6. For Endpoints like currency creation, update and delete you will need to use the admin user created by the migration, the credentials are: + ```json + { + "username": "admin", + "password": "password" + } + ``` ### Testing Run the test suite with: @@ -208,6 +221,13 @@ The API documentation is available at `http://localhost:8080/api/v1/reference` ### Authentication Most endpoints require authentication using an API key. Include the API key in the `X-API-Key` header of your requests. +Get the API Key by logging in the `/api/v1/auth/login in with the admin user created by the migration, the credentials are: +```json +{ + "username": "admin", + "password": "password" +} +``` ### Endpoints @@ -240,7 +260,7 @@ Example Response: } ``` -#### Currency Management (Admin only) +#### Currency Management (Admin only): use the api key from the admin user for these endpoints ##### POST /currency From ddf5d546a6410cd137c3c9daf6a20d020d3b0c1b Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Tue, 13 Aug 2024 10:53:43 -0300 Subject: [PATCH 140/141] style(comments): remove unecessary comments THis commit removes comments related to test on the worker where it detailed that it was the same mock as before but with some added for debugging it. --- cmd/worker/worker_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/worker/worker_test.go b/cmd/worker/worker_test.go index 660f999d9..c79a84f43 100644 --- a/cmd/worker/worker_test.go +++ b/cmd/worker/worker_test.go @@ -10,8 +10,6 @@ import ( "github.com/Lutefd/challenge-bravo/internal/repository" ) -// Mock implementations (same as before, but with some additions) - type mockCurrencyRepository struct { repository.CurrencyRepository closeCalled bool From 3ec1d6fd5c69f9e3029d345b50892b0876bc1336 Mon Sep 17 00:00:00 2001 From: Luis Dourado Date: Thu, 15 Aug 2024 23:15:23 -0300 Subject: [PATCH 141/141] fix(worker): add alternative currencies flag to expand currency catalogue This commit adds the show_alternative flag in the openexchangerate API, I noticed in some manual tests that the ETH currency along with some other ones were missing in the API response without the flag. --- internal/worker/external_api_client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/worker/external_api_client.go b/internal/worker/external_api_client.go index d6a7d3ef0..a919da0e7 100644 --- a/internal/worker/external_api_client.go +++ b/internal/worker/external_api_client.go @@ -61,7 +61,7 @@ func NewOpenExchangeRatesClient(apiKey string, options ...OpenExchangeRatesClien } func (c *OpenExchangeRatesClient) FetchRates(ctx context.Context) (*model.ExchangeRates, error) { - url := fmt.Sprintf("%s/latest.json?app_id=%s", c.baseURL, c.apiKey) + url := fmt.Sprintf("%s/latest.json?app_id=%s&show_alternative=true", c.baseURL, c.apiKey) var rates *model.ExchangeRates var err error

7q@ncMF7Gvn4)$?VqZG;|Lp4uMr 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 QH1J19^N2>iy4A)10nORtZ2$lO literal 119430 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 diff --git a/docs/dependency-map/dependency-map.mermaid b/docs/dependency-map/dependency-map.mermaid index 6378fcc09..3290b1015 100644 --- a/docs/dependency-map/dependency-map.mermaid +++ b/docs/dependency-map/dependency-map.mermaid @@ -1,37 +1,38 @@ graph TD A[main] --> B[server] A --> C[logger] - - B --> D[handler] - B --> E[middleware] - B --> F[service] - B --> G[repository] - B --> H[cache] - B --> I[worker] - - D --> F - D --> J[model] - D --> K[commons] - + A --> D[commons] + + B --> E[handler] + B --> F[middleware] + B --> G[service] + B --> H[repository] + B --> I[cache] + B --> J[worker] + E --> G - E --> J - E --> K - - F --> G + E --> K[model] + E --> D + F --> H - F --> I - F --> J - + F --> K + F --> D + + G --> H + G --> I G --> J - - H --> J - - I --> J - I --> G - I --> H - - C --> G - C --> J + G --> K + + H --> K + + I --> K + + J --> K + J --> H + J --> I + + C --> H + C --> K subgraph External Dependencies L[chi] @@ -39,10 +40,18 @@ graph TD N[postgres] O[uuid] P[bcrypt] + Q[goose] + R[sqlmock] + S[miniredis] + T[cron] end B --> L - H --> M - G --> N - F --> O - F --> P + I --> M + H --> N + G --> O + G --> P + H --> Q + H --> R + I --> S + J --> T diff --git a/docs/dependency-map/dependency-map.png b/docs/dependency-map/dependency-map.png index a068d16ec3668646201cbcbb0586ba7f9308c39d..d31ce3b5aa893131376ddeef93bf5552a1e8f191 100644 GIT binary patch literal 97658 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 F{|n?yjspMy literal 98373 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