Skip to content

Commit

Permalink
Many changes
Browse files Browse the repository at this point in the history
- Renamed module to `github.com/szabolcs-horvath/nutrition-tracker`
- Updated all dependencies
- Added POC of authentication
- Improved request logging
- Added skeleton of package- and integration testing
- Expanded the coverage check to include integration tests as well
  • Loading branch information
szabolcs-horvath committed Dec 21, 2024
1 parent 9d5de85 commit e69e2b5
Show file tree
Hide file tree
Showing 20 changed files with 226 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .github/.testcoverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# unit tests and integration tests separately, you can combine all those
# profiles into one. In this case, the profile should have a comma-separated list
# of profile files, e.g., 'cover_unit.out,cover_integration.out'.
profile: cover.out
profile: coverage/coverage.out,coverage/it-coverage.out

# (optional; but recommended to set)
# When specified reported file paths will not contain local prefix in the output.
Expand Down
22 changes: 8 additions & 14 deletions .github/workflows/go-build.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Go

name: Build and Test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:

build-and-test:
runs-on: ubuntu-latest
steps:
Expand All @@ -23,17 +17,17 @@ jobs:
- name: Install sqlite3
run: sudo apt-get install sqlite3

- name: Install sqlc
run: go install github.com/sqlc-dev/sqlc/cmd/sqlc@v1.27.0

- name: Install golang-migrate with the sqlite3 driver
run: go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
- name: Install go dependencies
run: make go-deps

- name: Build
run: make build

- name: Generate test coverage
run: go test ./... -v -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
- name: Generate test coverage from package tests
run: make test

- name: Generate test coverage from integration tests
run: make integration-test

- name: Check test coverage
uses: vladopajic/go-test-coverage@v2
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ out/

# vendored files
/vendor

# coverage files
/coverage
19 changes: 18 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
SQLITE_DB_FILE ?= sqlite/nutrition-tracker.db
SQLITE_MIGRATIONS_DIR ?= sqlite/migrations
SQLC_VERSION ?= v1.27.0
GOLANG_MIGRATE_VERSION ?= v4.18.1
HTMX_VERSION ?= 2.0.3
BOOTSTRAP_VERSION ?= 5.3.3
GOCOVERDIR ?= coverage

build: migrate-up sqlc
go-deps:
go install github.com/sqlc-dev/sqlc/cmd/sqlc@$(SQLC_VERSION)
go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@$(GOLANG_MIGRATE_VERSION)

build: sqlc
go build -o out/nutrition-tracker -mod=readonly

sqlc:
Expand All @@ -12,6 +19,16 @@ sqlc:
clean:
rm -rf generated out

test: sqlc
mkdir -p $(GOCOVERDIR)
go test ./... -v -coverprofile=$(GOCOVERDIR)/coverage.out -covermode=atomic -coverpkg=./...

integration-test: sqlc
mkdir -p $(GOCOVERDIR)/it-coverage
go build -o out/nutrition-tracker-integration-test -mod=readonly -cover
integration-test/integration-test.sh out/nutrition-tracker-integration-test $(GOCOVERDIR)/it-coverage
go tool covdata textfmt -i $(GOCOVERDIR)/it-coverage -o $(GOCOVERDIR)/it-coverage.out

create-migration:
ifneq ($(MIGRATION_NAME),)
migrate create -dir sqlite/migrations -ext .sql $(MIGRATION_NAME)
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ This project's purpose is to help Kinga track and plan her diet.
## Building
### Prerequisites
- :white_check_mark: [`go@1.23.1`](https://go.dev/dl/)
- :white_check_mark: [`sqlc@v1.27.0`](https://docs.sqlc.dev/en/latest/overview/install.html)
- :white_check_mark: [`sqlite3`](https://command-not-found.com/sqlite3)
- :white_check_mark: [`golang-migrate`](https://github.com/golang-migrate/migrate/tree/master)
- with the `sqlite3` driver:
- :white_check_mark: go dependencies
- :white_check_mark: [`sqlc`](https://docs.sqlc.dev/en/latest/overview/install.html)
- :white_check_mark: [`golang-migrate`](https://github.com/golang-migrate/migrate/tree/master)
- Install them with:
```shell
go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
make go-deps
```

### Set up
Expand Down
12 changes: 10 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module shorvath/nutrition-tracker
module github.com/szabolcs-horvath/nutrition-tracker

go 1.23.1

Expand All @@ -8,4 +8,12 @@ require (
github.com/mattn/go-sqlite3 v1.14.24
)

require github.com/donseba/go-htmx v1.11.3
require github.com/donseba/go-htmx v1.12.0

require github.com/auth0/go-jwt-middleware/v2 v2.2.2

require (
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/sync v0.10.0 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
)
24 changes: 24 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
github.com/auth0/go-jwt-middleware/v2 v2.2.2 h1:vrvkFZf72r3Qbt45KLjBG3/6Xq2r3NTixWKu2e8de9I=
github.com/auth0/go-jwt-middleware/v2 v2.2.2/go.mod h1:4vwxpVtu/Kl4c4HskT+gFLjq0dra8F1joxzamrje6J0=
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/donseba/go-htmx v1.11.3 h1:YW1JiKImneilQ73r+8xnoTlftlxt2Rh9L3IoZSa5iXk=
github.com/donseba/go-htmx v1.11.3/go.mod h1:8PTAYvNKf8+QYis+DpAsggKz+sa2qljtMgvdAeNBh5s=
github.com/donseba/go-htmx v1.12.0 h1:7tESER0uxaqsuGMv3yP3pK1drfBUXM6apG4H7/3+IgE=
github.com/donseba/go-htmx v1.12.0/go.mod h1:8PTAYvNKf8+QYis+DpAsggKz+sa2qljtMgvdAeNBh5s=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
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/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.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs=
gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
66 changes: 56 additions & 10 deletions http_server/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package middleware

import (
"context"
"github.com/auth0/go-jwt-middleware/v2"
"github.com/auth0/go-jwt-middleware/v2/jwks"
"github.com/auth0/go-jwt-middleware/v2/validator"
"github.com/google/uuid"
"log/slog"
"net/http"
"net/url"
"slices"
"time"
)
Expand All @@ -22,14 +26,28 @@ func CreateStack(middlewares ...Middleware) Middleware {

type wrappedWriter struct {
http.ResponseWriter
statusCode int
statusCode int
responseBody []byte
}

func (w *wrappedWriter) WriteHeader(statusCode int) {
w.ResponseWriter.WriteHeader(statusCode)
w.statusCode = statusCode
}

func (w *wrappedWriter) Write(data []byte) (int, error) {
w.responseBody = data
return w.ResponseWriter.Write(data)
}

func findRequestId(r *http.Request) string {
requestId, ok := r.Context().Value(requestIdKey).(string)
if !ok {
requestId = "_missing_"
}
return requestId
}

const requestIdKey = "x-request_id"

func AddRequestId(next http.Handler) http.Handler {
Expand All @@ -40,26 +58,54 @@ func AddRequestId(next http.Handler) http.Handler {
})
}

func Log(next http.Handler) http.Handler {
func LogIncomingRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
requestId := findRequestId(r)
slog.InfoContext(r.Context(), "[LogIncomingRequest]",
"REQUEST_ID", requestId,
"METHOD", r.Method,
"PATH", r.URL.Path,
)
next.ServeHTTP(w, r)
})
}

func Authenticate(audience string, domain string) Middleware {
return func(next http.Handler) http.Handler {
issuerURL, _ := url.Parse("https://" + domain + "/")
provider := jwks.NewCachingProvider(issuerURL, 5*time.Minute)

jwtValidator, _ := validator.New(
provider.KeyFunc,
validator.RS256,
issuerURL.String(),
[]string{audience},
)

middleware := jwtmiddleware.New(jwtValidator.ValidateToken)
return middleware.CheckJWT(next)
}
}

func LogCompletedRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
wrappedW := &wrappedWriter{
ResponseWriter: w,
statusCode: http.StatusOK,
}

start := time.Now()
next.ServeHTTP(wrappedW, r)
duration := time.Since(start)

requestId, ok := r.Context().Value(requestIdKey).(string)
if !ok {
requestId = "_missing_"
}

slog.Info("Execution time for the request was: "+time.Since(start).String(),
requestId := findRequestId(r)
slog.InfoContext(r.Context(), "[LogCompletedRequest]",
"REQUEST_ID", requestId,
"METHOD", r.Method,
"PATH", r.URL.Path,
"STATUS", wrappedW.statusCode)
"STATUS", wrappedW.statusCode,
"DURATION", duration.String(),
"BODY", string(wrappedW.responseBody),
)
})
}
4 changes: 2 additions & 2 deletions http_server/routes/api/routes.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package api

import (
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes"
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes/api/v1"
"net/http"
"shorvath/nutrition-tracker/http_server/routes"
"shorvath/nutrition-tracker/http_server/routes/api/v1"
)

const Prefix = "/api"
Expand Down
4 changes: 2 additions & 2 deletions http_server/routes/api/v1/items/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package items

import (
"encoding/json"
"github.com/szabolcs-horvath/nutrition-tracker/repository"
"github.com/szabolcs-horvath/nutrition-tracker/util"
"net/http"
"shorvath/nutrition-tracker/repository"
"shorvath/nutrition-tracker/util"
"strconv"
)

Expand Down
4 changes: 2 additions & 2 deletions http_server/routes/api/v1/portions/routes.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package portions

import (
"github.com/szabolcs-horvath/nutrition-tracker/repository"
"github.com/szabolcs-horvath/nutrition-tracker/util"
"net/http"
"shorvath/nutrition-tracker/repository"
"shorvath/nutrition-tracker/util"
"strconv"
)

Expand Down
10 changes: 5 additions & 5 deletions http_server/routes/api/v1/routes.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package v1

import (
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes"
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes/api/v1/items"
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes/api/v1/notifications"
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes/api/v1/portions"
"github.com/szabolcs-horvath/nutrition-tracker/http_server/routes/api/v1/users"
"net/http"
"shorvath/nutrition-tracker/http_server/routes"
"shorvath/nutrition-tracker/http_server/routes/api/v1/items"
"shorvath/nutrition-tracker/http_server/routes/api/v1/notifications"
"shorvath/nutrition-tracker/http_server/routes/api/v1/portions"
"shorvath/nutrition-tracker/http_server/routes/api/v1/users"
)

const Prefix = "/v1"
Expand Down
19 changes: 19 additions & 0 deletions integration-test/integration-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

set -ex

export BINARY=$1
export GOCOVERDIR=$2

main() {
# Run the application in the background
$BINARY& .github/.env
PID=$!

sleep 5 #TODO run the tests here

# Shutdown the application
kill $PID
}

main "$@"
Loading

0 comments on commit e69e2b5

Please sign in to comment.