Skip to content

Commit

Permalink
Merge pull request #5 from programme-lv/dev
Browse files Browse the repository at this point in the history
database integration testing
  • Loading branch information
KrisjanisP committed Aug 22, 2023
2 parents c5ac524 + d2dff1f commit 34c7310
Show file tree
Hide file tree
Showing 10 changed files with 643 additions and 12 deletions.
55 changes: 51 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,86 @@ go 1.19
require (
github.com/99designs/gqlgen v0.17.36
github.com/alexedwards/scs/v2 v2.5.1
github.com/go-git/go-git/v5 v5.8.1
github.com/jedib0t/go-pretty v4.3.0+incompatible
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.4
github.com/testcontainers/testcontainers-go v0.23.0
github.com/vektah/gqlparser/v2 v2.5.8
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691
)

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/containerd v1.7.3 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.5+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/strfmt v0.21.7 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.12.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/grpc v1.57.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
188 changes: 180 additions & 8 deletions go.sum

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions internal/database/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ func CreateUser(db *sqlx.DB, username string, hashed_password string, email stri
_, err := db.Exec("INSERT INTO users (username, hashed_password, email, first_name, last_name, created_at) VALUES ($1, $2, $3, $4, $5, now())", username, hashed_password, email, firstName, lastName)
return err
}

func DeleteUserById(db *sqlx.DB, id int64) error {
_, err := db.Exec("DELETE FROM users WHERE id = $1", id)
return err
}
53 changes: 53 additions & 0 deletions internal/database/funcs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package database

import (
"log"
"os"
"sync"
"testing"

"github.com/programme-lv/backend/internal/database/testdb"
"github.com/stretchr/testify/assert"
)

var (
once sync.Once
dbProvider testdb.TestDBProvider
)

func TestMain(m *testing.M) {
var err error
dbProvider, err = testdb.NewPostgresTestcontainerProvider()
if err != nil {
log.Fatal(err)
}
exitCode := m.Run()
dbProvider.Close()
os.Exit(exitCode)
}

func TestCreateUser(t *testing.T) {
db := dbProvider.GetTestDB()
assert.NotNil(t, db)

username := "username"
password := "password"
email := "email@gmail.com"
firstName := "firstName"
lastName := "lastName"

assert.Nil(t, CreateUser(db, username, hashPassword(password), email, firstName, lastName))

user, err := SelectUserByUsername(db, username)
assert.Nil(t, err)

assert.Equal(t, user.Username, username)
assert.Equal(t, user.Email, email)
assert.Equal(t, user.FirstName, firstName)
assert.Equal(t, user.LastName, lastName)
assert.Equal(t, user.IsAdmin, false)

assert.True(t, passwordsMatch(user.HashedPassword, password))

assert.Nil(t, DeleteUserById(db, user.ID))
}
71 changes: 71 additions & 0 deletions internal/database/testdb/flyway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package testdb

import (
"context"
"fmt"
"io"
"log"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

type flywayLogConsumer struct{}

func (consumer *flywayLogConsumer) Accept(l testcontainers.Log) {
fmt.Print(string(l.Content))
}

// exectues flyway:21 on host network with migrationsDir mounted to /flyway/flyway-migrations
func execFlywayContainer(networkName string, networkAlias string, migrationDir string, dbHost string, dbPort string, dbName string, dbUser string, dbPassword string) error {
args := []string{
fmt.Sprintf("-url=jdbc:postgresql://%s:%s/%s", dbHost, dbPort, dbName),
fmt.Sprintf("-user=%s", dbUser),
fmt.Sprintf("-password=%s", dbPassword),
"-connectRetries=5",
"-locations=filesystem:/flyway/flyway-migrations",
"migrate",
}

req := testcontainers.ContainerRequest{
Image: "flyway/flyway:9.21",
Mounts: testcontainers.ContainerMounts{
testcontainers.ContainerMount{
Source: testcontainers.GenericBindMountSource{
HostPath: migrationDir,
},
Target: "/flyway/flyway-migrations",
},
},
WaitingFor: wait.ForAll(wait.ForExit()),
Cmd: args,
Networks: []string{networkName},
NetworkAliases: map[string][]string{
networkName: {networkAlias},
},
}

c, err := testcontainers.GenericContainer(context.Background(),
testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: false,
})
if err != nil {
return err
}

err = c.Start(context.Background())
if err != nil {
log.Printf("Error starting flyway container: %v", err)
}
cLogs, err := c.Logs(context.Background())
if err != nil {
log.Printf("Error getting flyway container logs: %v", err)
}
logs, err := io.ReadAll(cLogs)
if err != nil {
log.Printf("Error reading flyway container logs: %v", err)
}
log.Println(string(logs))
return err
}
45 changes: 45 additions & 0 deletions internal/database/testdb/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package testdb

import (
"log"
"os"
"path/filepath"

git "github.com/go-git/go-git/v5"
)

type DBMigrations struct {
rootDir string
}

func cloneGitDBMigrations() (*DBMigrations, error) {
tmpDir, err := os.MkdirTemp("", "proglv-db-migrations")
if err != nil {
return nil, err
}
repoUrl := "https://github.com/programme-lv/database"

_, err = git.PlainClone(tmpDir, false, &git.CloneOptions{
URL: repoUrl,
Progress: os.Stdout,
})
if err != nil {
return nil, err
}

res := &DBMigrations{
rootDir: tmpDir,
}
return res, nil
}

func (dbm *DBMigrations) getFlywayMigrationsDir() string {
return filepath.Join(dbm.rootDir, "flyway-migrations")
}

func (dbm *DBMigrations) erase() {
err := os.RemoveAll(dbm.rootDir)
if err != nil {
log.Printf("Failed to remove tmp dir: %v", err)
}
}
52 changes: 52 additions & 0 deletions internal/database/testdb/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package testdb

import (
"context"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

type postgresContainer struct {
container testcontainers.Container
user string
password string
database string
}

func startPostgresContainer(networkName string, networkAlias string, user string, pass string, dbName string) (*postgresContainer, error) {
req := testcontainers.ContainerRequest{
Image: "postgres:latest",
ExposedPorts: []string{"5432/tcp"},
Env: map[string]string{
"POSTGRES_USER": user,
"POSTGRES_PASSWORD": pass,
"POSTGRES_DB": dbName,
},
WaitingFor: wait.ForAll(
wait.ForLog("database system is ready to accept connections"),
wait.ForExposedPort(),
),
Networks: []string{networkName},
NetworkAliases: map[string][]string{
networkName: {networkAlias},
},
}

container, err := testcontainers.GenericContainer(context.Background(),
testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
return nil, err
}

res := &postgresContainer{
container: container,
user: user,
password: pass,
database: dbName,
}
return res, nil
}
Loading

0 comments on commit 34c7310

Please sign in to comment.