Model integration testing
continuous-integration/drone/push Build is passing Details

main
Drew Bednar 2 months ago
parent 4986095aaa
commit b18003ed20

@ -13,6 +13,10 @@ test:
go test $(FLAGS) ./...
PHONEY: test
test-short:
go test -short $(FLAGS) ./...
PHONEY: test-short
# make test-int ARGS=no-cache
test-int:
go test $(FLAGS) ./cmd/...

@ -2,12 +2,18 @@ module git.runcible.io/learning/ratchet
go 1.23.3
require github.com/mattn/go-sqlite3 v1.14.24
require (
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885
github.com/alexedwards/scs/v2 v2.8.0
github.com/go-playground/form/v4 v4.2.1
github.com/golang-migrate/migrate/v4 v4.18.1
github.com/justinas/nosurf v1.1.1
github.com/mattn/go-sqlite3 v1.14.24
golang.org/x/crypto v0.32.0
)
require (
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885 // indirect
github.com/alexedwards/scs/v2 v2.8.0 // indirect
github.com/go-playground/form/v4 v4.2.1 // indirect
github.com/justinas/nosurf v1.1.1 // indirect
golang.org/x/crypto v0.32.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
go.uber.org/atomic v1.7.0 // indirect
)

@ -2,13 +2,36 @@ github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885 h1:+D
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/form/v4 v4.2.1 h1:HjdRDKO0fftVMU5epjPW2SOREcZ6/wLUzEobqUGJuPw=
github.com/go-playground/form/v4 v4.2.1/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/justinas/nosurf v1.1.1 h1:92Aw44hjSK4MxJeMSyDa7jwuI9GR2J/JCQiaKvXXSlk=
github.com/justinas/nosurf v1.1.1/go.mod h1:ALpWdSbuNGy2lZWtyXdjkYv4edL23oSEgfBT1gPJ5BQ=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -28,3 +28,11 @@ func StringContains(t *testing.T, actual, expectedSubstring string) {
t.Errorf("got: %q; expected to contain %q", actual, expectedSubstring)
}
}
func NilError(t *testing.T, actual error) {
t.Helper()
if actual != nil {
t.Errorf("got: %v; expected: nil", actual)
}
}

@ -0,0 +1,9 @@
INSERT INTO users VALUES(
1337,
'tester',
'tester@example.com',
/* thisisinsecure */
'$2a$12$M51w5lWkveAOhwoanoCxO.hJe3s1m8qJuCzbzdETt0SThjpq4BPRq',
'2025-02-25 18:58:44',
'2025-02-25 18:58:44'
);

@ -0,0 +1,52 @@
package integration
import (
"database/sql"
"os"
"testing"
"git.runcible.io/learning/ratchet/migrations"
)
const testerPasswd = "thisisinsecure"
func newTestDB(t *testing.T) *sql.DB {
dbFile, err := os.CreateTemp("", "ratchet-*.db")
if err != nil {
t.Fatal(err)
}
db, err := sql.Open("sqlite3", dbFile.Name())
if err != nil {
db.Close()
t.Fatal(err)
}
err = migrations.Migrate(db)
if err != nil {
db.Close()
t.Fatal(err)
}
script, err := os.ReadFile("./testdata/seed.sql")
if err != nil {
db.Close()
t.Fatal(err)
}
_, err = db.Exec(string(script))
if err != nil {
db.Close()
t.Fatal(err)
}
t.Cleanup(func() {
db.Close()
err := os.Remove(dbFile.Name())
if err != nil {
t.Fatal(err)
}
})
return db
}

@ -0,0 +1,51 @@
package integration
import (
"testing"
"git.runcible.io/learning/ratchet/internal/assert"
"git.runcible.io/learning/ratchet/internal/model"
)
func TestUserModelExists(t *testing.T) {
// Skip the test if the "-short" flag is provided when running the test.
if testing.Short() {
t.Skip("models: skipping model integration test")
}
tests := []struct {
name string
userID int
want bool
}{{
name: "Valid ID",
userID: 1337,
want: true,
},
{
name: "Zero ID",
userID: 0,
want: false,
},
{
name: "Zero ID",
userID: 2,
want: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
db := newTestDB(t)
userService := model.UserService{db}
exists, err := userService.Exists(test.userID)
assert.Equal(t, exists, test.want)
assert.NilError(t, err)
})
}
}

@ -0,0 +1,48 @@
package migrations
import (
"database/sql"
"embed"
"fmt"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/golang-migrate/migrate/v4/source/iofs"
)
//go:embed *.sql
var migrationFiles embed.FS
func Migrate(db *sql.DB) error {
// Create a database driver for the specific database type
driver, err := sqlite3.WithInstance(db, &sqlite3.Config{})
if err != nil {
return fmt.Errorf("failed to create database driver: %w", err)
}
// Create an IFS source from the embedded files
source, err := iofs.New(migrationFiles, ".")
if err != nil {
return fmt.Errorf("failed to create migration source: %w", err)
}
// Create a new migrate instance
m, err := migrate.NewWithInstance("iofs", source, "sqlite3", driver)
if err != nil {
return fmt.Errorf("failed to create migrate instance: %w", err)
}
// Run migrations
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("failed to run migrations: %w", err)
}
// set WAL mode
_, err = db.Exec("PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;")
if err != nil {
return fmt.Errorf("failed to set wall mode: %w", err)
}
return nil
}
Loading…
Cancel
Save