Core system #1
22 changed files with 385 additions and 33 deletions
|
@ -2,15 +2,12 @@ when:
|
|||
event: [tag, push]
|
||||
|
||||
steps:
|
||||
build:
|
||||
image: golang:1.23-alpine
|
||||
- name: build
|
||||
image: golang:1.24-alpine
|
||||
commands:
|
||||
- apk update
|
||||
- apk add git
|
||||
- go install github.com/goreleaser/goreleaser/v2@latest
|
||||
- echo "$${SENTRY_DSN}" > cmd/api/sentry
|
||||
- goreleaser build --snapshot
|
||||
secrets: [sentry_dsn]
|
||||
- apk add bash
|
||||
- bash scripts/build.sh
|
||||
|
||||
depends_on:
|
||||
- lint
|
||||
|
|
|
@ -2,10 +2,10 @@ when:
|
|||
event: [tag, push]
|
||||
|
||||
steps:
|
||||
lint:
|
||||
image: golang:1.23-alpine
|
||||
- name: lint
|
||||
image: golang:1.24-alpine
|
||||
commands:
|
||||
- apk update
|
||||
- apk add bash curl jq
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.60.1
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.5
|
||||
- $(go env GOPATH)/bin/golangci-lint run --fast
|
||||
|
|
|
@ -4,6 +4,11 @@ when:
|
|||
steps:
|
||||
- name: publish-docker
|
||||
image: docker:27-cli
|
||||
environment:
|
||||
DOCKER_USERNAME:
|
||||
from_secret: docker_username
|
||||
DOCKER_PASSWORD:
|
||||
from_secret: docker_password
|
||||
commands:
|
||||
- tag="tintounn/trepa:$${CI_COMMIT_TAG}"
|
||||
- docker login -u="$${DOCKER_USERNAME}" -p="$${DOCKER_PASSWORD}"
|
||||
|
@ -12,13 +17,6 @@ steps:
|
|||
- docker rmi $tag
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
secrets: [docker_username, docker_password]
|
||||
|
||||
- name: publish-binaries
|
||||
image: goreleaser/goreleaser
|
||||
commands:
|
||||
- goreleaser release
|
||||
secrets: [ gitea_token ]
|
||||
|
||||
depends_on:
|
||||
- build
|
||||
|
|
|
@ -2,21 +2,22 @@ when:
|
|||
event: [tag, push]
|
||||
|
||||
steps:
|
||||
tests:
|
||||
image: golang:1.23-alpine
|
||||
- name: tests
|
||||
image: golang:1.24-alpine
|
||||
environment:
|
||||
TEST_DATABASE_URL: postgres://dev:dev@db/trepa?sslmode=disable
|
||||
TEST_DB_HOST: db
|
||||
TEST_DB_PORT: 5432
|
||||
TEST_DB_USER: dev
|
||||
TEST_DB_PASSWORD: dev
|
||||
TEST_DB_NAME: trepa_test
|
||||
commands:
|
||||
- sleep 30
|
||||
- wget https://github.com/golang-migrate/migrate/releases/download/v4.17.1/migrate.linux-amd64.tar.gz
|
||||
- tar -xf migrate.linux-amd64.tar.gz
|
||||
- ./migrate -source file://migrations/ -database "$${TEST_DATABASE_URL}" up
|
||||
- go test -cover ./internal/... -v
|
||||
|
||||
services:
|
||||
- name: db
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=dev
|
||||
- POSTGRES_PASSWORD=dev
|
||||
- POSTGRES_DB=trepa
|
||||
POSTGRES_USER: dev
|
||||
POSTGRES_PASSWORD: dev
|
||||
POSTGRES_DB: trepa_test
|
||||
|
|
|
@ -12,12 +12,12 @@ RUN chmod +x scripts/build.sh && \
|
|||
./scripts/build.sh
|
||||
|
||||
|
||||
FROM debian:bookworm-slim AS runner
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt update &&\
|
||||
apt install bash curl -y &&\
|
||||
apt install bash curl wget -y &&\
|
||||
wget https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.deb &&\
|
||||
dpkg -i migrate.linux-amd64.deb &&\
|
||||
rm migrate.linux-amd64.deb &&\
|
||||
|
|
|
@ -22,7 +22,7 @@ var ascii string
|
|||
func main() {
|
||||
fmt.Println(ascii)
|
||||
|
||||
core.LoadEnvVars()
|
||||
core.LoadEnvVars(".env")
|
||||
|
||||
db := setupDB()
|
||||
router := setupRouter(db)
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,17 +3,23 @@ module gitea.qpismont.fr/qpismont/trepa
|
|||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/jackc/pgx v3.6.2+incompatible
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/magiconair/properties v1.8.9
|
||||
github.com/stretchr/testify v1.10.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cockroachdb/apd v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
14
go.sum
14
go.sum
|
@ -2,10 +2,14 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
|||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
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/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||
github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
|
||||
|
@ -16,13 +20,23 @@ 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/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
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=
|
||||
|
|
6
internal/accounts/const.go
Normal file
6
internal/accounts/const.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package accounts
|
||||
|
||||
const (
|
||||
SqlInsert = "INSERT INTO accounts (username, password, role_id) VALUES ($1, $2, $3) RETURNING id"
|
||||
SqlFetchOneByUsername = "SELECT * FROM accounts WHERE username = $1"
|
||||
)
|
10
internal/accounts/model.go
Normal file
10
internal/accounts/model.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package accounts
|
||||
|
||||
type Account struct {
|
||||
Id int `db:"id" json:"id"`
|
||||
Username string `db:"username" json:"username"`
|
||||
Password string `db:"password" json:"-"`
|
||||
RoleId int `db:"role_id" json:"role_id"`
|
||||
CreatedAt string `db:"created_at" json:"created_at"`
|
||||
UpdatedAt string `db:"updated_at" json:"updated_at"`
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package accounts
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
|
@ -11,3 +13,36 @@ type Repository struct {
|
|||
func NewRepository(db *sqlx.DB) Repository {
|
||||
return Repository{db: db}
|
||||
}
|
||||
|
||||
func (r *Repository) Insert(account *Account) (int, error) {
|
||||
var id int
|
||||
|
||||
stmt, err := r.db.Prepare(SqlInsert)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
|
||||
defer stmt.Close()
|
||||
|
||||
err = stmt.QueryRow(account.Username, account.Password, account.RoleId).Scan(&id)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (r *Repository) FetchOneByUsername(username string) (*Account, error) {
|
||||
var account Account
|
||||
|
||||
err := r.db.Get(&account, SqlFetchOneByUsername, username)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &account, nil
|
||||
}
|
||||
|
|
48
internal/accounts/repository_test.go
Normal file
48
internal/accounts/repository_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package accounts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.qpismont.fr/qpismont/trepa/test"
|
||||
"github.com/magiconair/properties/assert"
|
||||
)
|
||||
|
||||
func TestRepository_Insert(t *testing.T) {
|
||||
db := test.SetupTestDB(t, "../..")
|
||||
defer db.Close()
|
||||
|
||||
repo := NewRepository(db)
|
||||
|
||||
account := &Account{
|
||||
Username: "test",
|
||||
Password: "test",
|
||||
RoleId: 1,
|
||||
}
|
||||
|
||||
id, err := repo.Insert(account)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert account: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, id, 3)
|
||||
}
|
||||
|
||||
func TestRepository_FetchOneByUsername(t *testing.T) {
|
||||
db := test.SetupTestDB(t, "../..")
|
||||
defer db.Close()
|
||||
|
||||
repo := NewRepository(db)
|
||||
|
||||
account, err := repo.FetchOneByUsername("admin")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to fetch account: %v", err)
|
||||
}
|
||||
|
||||
if account == nil {
|
||||
t.Fatalf("Account not found")
|
||||
}
|
||||
|
||||
assert.Equal(t, account.Username, "admin")
|
||||
assert.Equal(t, account.Password, "LOLPASSWORD")
|
||||
assert.Equal(t, account.RoleId, 1)
|
||||
}
|
39
internal/core/database_test.go
Normal file
39
internal/core/database_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestComputeDBURL(t *testing.T) {
|
||||
LoadEnvVars("../../.env")
|
||||
|
||||
dbHost := MustGetEnvVar("TEST_DB_HOST")
|
||||
dbPort := MustGetEnvVar("TEST_DB_PORT")
|
||||
dbUser := MustGetEnvVar("TEST_DB_USER")
|
||||
dbPassword := MustGetEnvVar("TEST_DB_PASSWORD")
|
||||
dbName := MustGetEnvVar("TEST_DB_NAME")
|
||||
|
||||
dbURL := ComputeDBURL(dbHost, dbPort, dbUser, dbPassword, dbName)
|
||||
|
||||
assert.Equal(t, dbURL, fmt.Sprintf("postgres://%s:%s@%s:%s/%s", dbUser, dbPassword, dbHost, dbPort, dbName))
|
||||
}
|
||||
|
||||
func TestSetupDB(t *testing.T) {
|
||||
LoadEnvVars("../../.env")
|
||||
|
||||
dbHost := MustGetEnvVar("TEST_DB_HOST")
|
||||
dbPort := MustGetEnvVar("TEST_DB_PORT")
|
||||
dbUser := MustGetEnvVar("TEST_DB_USER")
|
||||
dbPassword := MustGetEnvVar("TEST_DB_PASSWORD")
|
||||
dbName := MustGetEnvVar("TEST_DB_NAME")
|
||||
|
||||
dbURL := ComputeDBURL(dbHost, dbPort, dbUser, dbPassword, dbName)
|
||||
db, err := SetupDB(dbURL)
|
||||
defer db.Close()
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, db)
|
||||
}
|
|
@ -4,6 +4,10 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidToken = NewHTTPError(http.StatusUnauthorized, "Invalid token", nil)
|
||||
)
|
||||
|
||||
type HTTPError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
|
|
23
internal/core/errors_test.go
Normal file
23
internal/core/errors_test.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewError(t *testing.T) {
|
||||
err := NewHTTPError(http.StatusBadRequest, "MyError", errors.New("test"))
|
||||
assert.Equal(t, http.StatusBadRequest, err.Code)
|
||||
assert.Equal(t, "MyError", err.Error())
|
||||
assert.Equal(t, errors.New("test"), err.Unwrap())
|
||||
}
|
||||
|
||||
func TestNewInternalServerError(t *testing.T) {
|
||||
err := NewInternalServerError(errors.New("test"))
|
||||
assert.Equal(t, http.StatusInternalServerError, err.Code)
|
||||
assert.Equal(t, "Internal server error", err.Error())
|
||||
assert.Equal(t, errors.New("test"), err.Unwrap())
|
||||
}
|
|
@ -7,10 +7,10 @@ import (
|
|||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func LoadEnvVars() {
|
||||
err := godotenv.Load()
|
||||
func LoadEnvVars(path string) {
|
||||
err := godotenv.Load(path)
|
||||
if err != nil {
|
||||
slog.Warn("Error loading .env file")
|
||||
slog.Warn("Error loading .env file", "path", path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
internal/core/helpers_test.go
Normal file
15
internal/core/helpers_test.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMustGetEnvVar(t *testing.T) {
|
||||
LoadEnvVars("../../.env")
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
MustGetEnvVar("TEST_DB_HOST")
|
||||
})
|
||||
}
|
|
@ -39,6 +39,7 @@ func (r *Response) Write(b []byte) (int, error) {
|
|||
return n, err
|
||||
}
|
||||
|
||||
// Implement http.Handler
|
||||
type ServerMux struct {
|
||||
mux *http.ServeMux
|
||||
}
|
||||
|
|
40
internal/core/jwt.go
Normal file
40
internal/core/jwt.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type JWTClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
AccountId int `json:"account_id"`
|
||||
RoleId int `json:"role_id"`
|
||||
}
|
||||
|
||||
var jwtSecret string
|
||||
|
||||
func InitJWT(secret string) {
|
||||
jwtSecret = secret
|
||||
}
|
||||
|
||||
func SignJWT(claims JWTClaims) (string, error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString([]byte(jwtSecret))
|
||||
}
|
||||
|
||||
func VerifyJWT(token string) (JWTClaims, error) {
|
||||
parsedClaims := JWTClaims{}
|
||||
claims, err := jwt.ParseWithClaims(token, &parsedClaims, func(token *jwt.Token) (any, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return JWTClaims{}, NewInternalServerError(err)
|
||||
}
|
||||
|
||||
if !claims.Valid {
|
||||
return JWTClaims{}, ErrInvalidToken
|
||||
}
|
||||
|
||||
return parsedClaims, nil
|
||||
}
|
29
internal/core/jwt_test.go
Normal file
29
internal/core/jwt_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJWT_GenerateToken(t *testing.T) {
|
||||
InitJWT("secret")
|
||||
|
||||
token, err := SignJWT(JWTClaims{
|
||||
AccountId: 1,
|
||||
RoleId: 1,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate token: %v", err)
|
||||
}
|
||||
|
||||
assert.NotEmpty(t, token)
|
||||
|
||||
claims, err := VerifyJWT(token)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to verify token: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, claims.AccountId, 1)
|
||||
assert.Equal(t, claims.RoleId, 1)
|
||||
}
|
2
test/fixtures/00-accounts.sql
vendored
Normal file
2
test/fixtures/00-accounts.sql
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO accounts (username, password, role_id) VALUES ('admin', 'LOLPASSWORD', 1);
|
||||
INSERT INTO accounts (username, password, role_id) VALUES ('user', 'LOLPASSWORD', 2);
|
84
test/helpers.go
Normal file
84
test/helpers.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
func SetupTestDB(test *testing.T, rootPath string) *sqlx.DB {
|
||||
core.LoadEnvVars(rootPath + "/.env")
|
||||
|
||||
dbHost := core.MustGetEnvVar("TEST_DB_HOST")
|
||||
dbPort := core.MustGetEnvVar("TEST_DB_PORT")
|
||||
dbUser := core.MustGetEnvVar("TEST_DB_USER")
|
||||
dbPassword := core.MustGetEnvVar("TEST_DB_PASSWORD")
|
||||
dbName := core.MustGetEnvVar("TEST_DB_NAME")
|
||||
|
||||
dbExecute := initTestDB(test, dbHost, dbPort, dbUser, dbPassword, "postgres")
|
||||
resetTestDB(dbExecute, test, dbName)
|
||||
dbExecute.Close()
|
||||
|
||||
dbTest := initTestDB(test, dbHost, dbPort, dbUser, dbPassword, dbName)
|
||||
executeMigrations(dbTest, test, rootPath)
|
||||
executeFixtures(dbTest, test, rootPath)
|
||||
|
||||
return dbTest
|
||||
}
|
||||
|
||||
func initTestDB(t *testing.T, dbHost, dbPort, dbUser, dbPassword, dbName string) *sqlx.DB {
|
||||
dbURL := core.ComputeDBURL(dbHost, dbPort, dbUser, dbPassword, dbName)
|
||||
db, err := core.SetupDB(dbURL)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect to test database: %v", err)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func resetTestDB(db *sqlx.DB, t *testing.T, dbName string) {
|
||||
_, err := db.Exec("DROP DATABASE IF EXISTS " + dbName + " WITH (FORCE);")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to drop test database: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE DATABASE " + dbName + ";")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test database: %v", err)
|
||||
}
|
||||
}
|
||||
func executeMigrations(db *sqlx.DB, t *testing.T, rootPath string) {
|
||||
rootPath = filepath.Join(rootPath, "migrations")
|
||||
|
||||
executeSqlFolder(db, t, rootPath)
|
||||
}
|
||||
|
||||
func executeFixtures(db *sqlx.DB, t *testing.T, rootPath string) {
|
||||
rootPath = filepath.Join(rootPath, "test", "fixtures")
|
||||
|
||||
executeSqlFolder(db, t, rootPath)
|
||||
}
|
||||
|
||||
func executeSqlFolder(db *sqlx.DB, t *testing.T, folder string) {
|
||||
files, err := filepath.Glob(folder + "/*.sql")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read sql folder: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
t.Log("Executing " + file)
|
||||
|
||||
sql, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read sql file: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(string(sql))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to execute sql file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue