diff --git a/README.md b/README.md index f04499e..5bc6543 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,39 @@ -# Database: Postgresql, Redis, etc. -This project shows the implementation of clients for postgresql, Redis and other databases in Golang. +# Kit +Set of common packages used by all or most projects in my repositories. ## Table of Contents -- [Implementation](#implementation) +- [Implementation examples](#implementation-examples) - [Postgresql](#postgresql) - [Redis](#redis) +- [Testing](#testing) -## Implementation +## Implementation examples ### Postgresql -See the examples already implemented in the folder `/pgdb`. +See the examples already implemented in the folder `/postgresql`. ### Redis -See the examples already implemented in the folder `/redisdb`. \ No newline at end of file +See the examples already implemented in the folder `/redis`. + +### Testing + +To run the tests simply execute the following command: + +```shell +make test +``` + +This will stop any containers defined by the compose file for tests if already running +and then rebuild the containers using the compose file. + +To down the containers simply execute the following command: + +```shell +make test-down +``` + +lairon14@gmail.com +-- Lairon \ No newline at end of file diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..244b91c --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,39 @@ +version: '3' + +networks: + kit-go-network: + driver: bridge + +services: + kit_tests: + build: + context: . + dockerfile: ./Dockerfile.test + volumes: + - $PWD:/go/src/github.com/laironacosta/kit-go + depends_on: + - db-test + networks: + - kit-go-network + db-test: + image: postgres:13.2 + ports: + - "5432:5432" + expose: + - "5432" + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: testdb + restart: on-failure + networks: + - kit-go-network + redis-test: + image: redis + ports: + - "6379:6379" + expose: + - "6379" + restart: on-failure + networks: + - kit-go-network diff --git a/go.mod b/go.mod index 5dceff7..b5938fd 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ -module github.com/Lairon/db-go +module github.com/laironacosta/kit-go go 1.16 require ( github.com/go-pg/pg/v10 v10.9.0 github.com/go-redis/redis/v8 v8.8.0 + github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 ) diff --git a/go.sum b/go.sum index 1c25310..ab96ec1 100644 --- a/go.sum +++ b/go.sum @@ -63,7 +63,10 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= @@ -122,6 +125,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/makefile b/makefile new file mode 100644 index 0000000..1b13a3b --- /dev/null +++ b/makefile @@ -0,0 +1,16 @@ +run-test: test-up test-down + +mod: + # This make rule requires Go 1.11+ + GO111MODULE=on go mod tidy + +# Test Rules +test: + docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit + docker-compose -f docker-compose.test.yml down --volumes + +test-up: + docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit + +test-down: + docker-compose -f docker-compose.test.yml down --volumes diff --git a/pgdb/pg_db.go b/pgdb/pg_db.go deleted file mode 100644 index f17fe9c..0000000 --- a/pgdb/pg_db.go +++ /dev/null @@ -1,34 +0,0 @@ -package pgdb - -import ( - "github.com/go-pg/pg/v10" - "log" - "sync" -) - -var ( - instance *pg.DB - once sync.Once -) - -func NewPgDB(pgOptions *pg.Options) *pg.DB { - once.Do(func() { - instance = Connect(pgOptions) - }) - - return instance -} - -func Connect(pgOptions *pg.Options) *pg.DB { - db := pg.Connect(pgOptions) - - var n int - _, err := db.QueryOne(pg.Scan(&n), "SELECT 1") - if err != nil { - log.Panicf("Postgres connection error %+v\n", err) - } - - log.Println("Successfully connected to ->", db.Options().Addr) - - return db -} diff --git a/pgdb/pg_db_test.go b/pgdb/pg_db_test.go deleted file mode 100644 index 34efa63..0000000 --- a/pgdb/pg_db_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package pgdb - -import ( - "fmt" - "github.com/go-pg/pg/v10" - "github.com/stretchr/testify/assert" - "testing" -) - -var pgOptions = &pg.Options{ - Addr: "localhost:5432", - User: "postgres", - Password: "postgres", - Database: "pg-db-go", -} - -func TestNewPgDB_WhenOptionsOk_ThenCreateClient(t *testing.T) { - got := NewPgDB(pgOptions) - got.Close() - - assert.NotNil(t, got) - assert.Equal(t, pgOptions.Addr, got.Options().Addr) - assert.Equal(t, pgOptions.User, got.Options().User) - assert.Equal(t, pgOptions.Password, got.Options().Password) - assert.Equal(t, pgOptions.Database, got.Options().Database) -} - -func TestNewPgDB_WhenOptionsNil_ThenPanic(t *testing.T) { - defer func() { - if r := recover(); r != nil { - assert.Equal(t, fmt.Sprint("runtime error: invalid memory address or nil pointer dereference"), fmt.Sprint(r)) - } - }() - NewPgDB(nil) -} - -func TestNewPgDB_WhenOptionsContainBadAddr_ThenPanic(t *testing.T) { - defer func() { - if r := recover(); r != nil { - assert.Equal(t, fmt.Sprintln("Postgres connection error dial tcp: lookup bad: no such host"), fmt.Sprint(r)) - } - }() - NewPgDB(&pg.Options{ - Addr: "bad:6379", - User: "postgres", - Password: "postgres", - Database: "pg-db-go", - }) -} diff --git a/pgdb/example1/example1.go b/postgresql/example1/example1.go similarity index 89% rename from pgdb/example1/example1.go rename to postgresql/example1/example1.go index 0b265c0..0d0b5ee 100644 --- a/pgdb/example1/example1.go +++ b/postgresql/example1/example1.go @@ -1,9 +1,9 @@ package main import ( - "fmt" "github.com/go-pg/pg/v10" "github.com/go-pg/pg/v10/orm" + log "github.com/sirupsen/logrus" ) type User struct { @@ -25,9 +25,9 @@ func main() { func exampleDBModel() { db := pg.Connect(&pg.Options{ - User: "postgres", - Password: "postgres", - Database: "pg-db-go", + User: "root", + Password: "root", + Database: "db-test", }) defer db.Close() @@ -89,9 +89,9 @@ func exampleDBModel() { panic(err) } - fmt.Printf("%+v \n", user) - fmt.Printf("%+v \n", users) - fmt.Printf("%+v \n", book) + log.Infof("%+v \n", user) + log.Infof("%+v \n", users) + log.Infof("%+v \n", book) } diff --git a/pgdb/example2/example2.go b/postgresql/example2/example2.go similarity index 86% rename from pgdb/example2/example2.go rename to postgresql/example2/example2.go index 48f5098..21f8b26 100644 --- a/pgdb/example2/example2.go +++ b/postgresql/example2/example2.go @@ -1,10 +1,10 @@ package main import ( - "fmt" - "github.com/Lairon/db-go/pgdb" "github.com/go-pg/pg/v10" "github.com/go-pg/pg/v10/orm" + pgKit "github.com/laironacosta/kit-go/postgresql" + log "github.com/sirupsen/logrus" ) type User struct { @@ -33,10 +33,10 @@ func main() { func NewPgClient() *PgClient { return &PgClient{ - db: pgdb.NewPgDB(&pg.Options{ - User: "postgres", - Password: "postgres", - Database: "pg-db-go", + db: pgKit.NewPgDB(&pg.Options{ + User: "root", + Password: "root", + Database: "db-test", }), } } @@ -102,9 +102,9 @@ func (c *PgClient) createSchemeInsertSelect() { panic(err) } - fmt.Printf("%+v \n", user) - fmt.Printf("%+v \n", users) - fmt.Printf("%+v \n", book) + log.Infof("%+v \n", user) + log.Infof("%+v \n", users) + log.Infof("%+v \n", book) } diff --git a/postgresql/pg.go b/postgresql/pg.go new file mode 100644 index 0000000..defaca3 --- /dev/null +++ b/postgresql/pg.go @@ -0,0 +1,40 @@ +package postgresql + +import ( + "github.com/go-pg/pg/v10" + log "github.com/sirupsen/logrus" + "sync" + "time" +) + +var ( + instance *pg.DB + once sync.Once +) + +func NewPgDB(pgOptions *pg.Options) *pg.DB { + once.Do(func() { + instance = Connect(pgOptions) + }) + + return instance +} + +func Connect(pgOptions *pg.Options) *pg.DB { + log.Infoln("Connecting to postgres database...") + db := pg.Connect(pgOptions) + + var n int + if _, err := db.QueryOne(pg.Scan(&n), "SELECT 1"); err != nil { + log.Errorln(err) + time.Sleep(2 * time.Second) + + db = pg.Connect(pgOptions) + if _, err := db.QueryOne(pg.Scan(&n), "SELECT 1"); err != nil { + log.Panicf("Postgres connection error %+v\n", err) + } + } + + log.Infoln("Connection to postgres verified and successfully connected...") + return db +} diff --git a/postgresql/pg_test.go b/postgresql/pg_test.go new file mode 100644 index 0000000..1fc18d2 --- /dev/null +++ b/postgresql/pg_test.go @@ -0,0 +1,25 @@ +package postgresql + +import ( + "github.com/go-pg/pg/v10" + "github.com/stretchr/testify/assert" + "testing" +) + +var pgOptions = &pg.Options{ + Addr: "db-test:5432", + User: "root", + Password: "root", + Database: "testdb", +} + +func TestNewPgDB_WhenOptionsOk_ThenCreateClient(t *testing.T) { + got := NewPgDB(pgOptions) + defer got.Close() + + assert.NotNil(t, got) + assert.Equal(t, pgOptions.Addr, got.Options().Addr) + assert.Equal(t, pgOptions.User, got.Options().User) + assert.Equal(t, pgOptions.Password, got.Options().Password) + assert.Equal(t, pgOptions.Database, got.Options().Database) +} diff --git a/redisdb/example1/example1.go b/redis/example1/example1.go similarity index 81% rename from redisdb/example1/example1.go rename to redis/example1/example1.go index 01c6f2c..26acbe8 100644 --- a/redisdb/example1/example1.go +++ b/redis/example1/example1.go @@ -2,10 +2,9 @@ package main import ( "context" - "fmt" - "github.com/Lairon/db-go/redisdb" "github.com/go-redis/redis/v8" - "log" + redisKit "github.com/laironacosta/kit-go/redis" + log "github.com/sirupsen/logrus" "time" ) @@ -25,13 +24,13 @@ func main() { client.SetKey(ctx, key, value, 10*time.Second) val := client.GetKey(ctx, key) - fmt.Printf("Key: %s, Value: %s", key, val) + log.Infof("Key: %s, Value: %s", key, val) } func NewRedisClient() *RedisClient { return &RedisClient{ - db: redisdb.NewRedisDB(&redis.Options{ - Addr: "localhost:6379", + db: redisKit.NewRedisDB(&redis.Options{ + Addr: "redis-test:6379", Password: "", // no password set DB: 0, // use default DB }), diff --git a/redis/redis.go b/redis/redis.go new file mode 100644 index 0000000..e1ef59b --- /dev/null +++ b/redis/redis.go @@ -0,0 +1,41 @@ +package redis + +import ( + "context" + "github.com/go-redis/redis/v8" + log "github.com/sirupsen/logrus" + "sync" + "time" +) + +var ( + instance *redis.Client + once sync.Once +) + +func NewRedisDB(redisOptions *redis.Options) *redis.Client { + once.Do(func() { + instance = Connect(redisOptions) + }) + + return instance +} + +func Connect(redisOptions *redis.Options) *redis.Client { + log.Infoln("Connecting to redis database...") + ctx := context.Background() + db := redis.NewClient(redisOptions) + + if err := db.Ping(ctx).Err(); err != nil { + log.Errorln(err) + time.Sleep(2 * time.Second) + + db := redis.NewClient(redisOptions) + if err := db.Ping(ctx).Err(); err != nil { + log.Panicf("Redis connection error %+v\n", err) + } + } + + log.Infoln("Redis successfully connected...") + return db +} diff --git a/redis/redis_test.go b/redis/redis_test.go new file mode 100644 index 0000000..f4bcbb6 --- /dev/null +++ b/redis/redis_test.go @@ -0,0 +1,23 @@ +package redis + +import ( + "github.com/go-redis/redis/v8" + "github.com/stretchr/testify/assert" + "testing" +) + +var redisOptions = &redis.Options{ + Addr: "redis-test:6379", + Password: "", + DB: 0, +} + +func TestNewRedisDB_WhenOptionsOk_ThenCreateClient(t *testing.T) { + got := NewRedisDB(redisOptions) + got.Close() + + assert.NotNil(t, got) + assert.Equal(t, redisOptions.Addr, got.Options().Addr) + assert.Equal(t, redisOptions.Password, got.Options().Password) + assert.Equal(t, redisOptions.DB, got.Options().DB) +} diff --git a/redisdb/redis_db.go b/redisdb/redis_db.go deleted file mode 100644 index 673fa0a..0000000 --- a/redisdb/redis_db.go +++ /dev/null @@ -1,32 +0,0 @@ -package redisdb - -import ( - "context" - "github.com/go-redis/redis/v8" - "log" - "sync" -) - -var ( - instance *redis.Client - once sync.Once -) - -func NewRedisDB(redisOptions *redis.Options) *redis.Client { - once.Do(func() { - instance = Connect(redisOptions) - }) - - return instance -} - -func Connect(redisOptions *redis.Options) *redis.Client { - db := redis.NewClient(redisOptions) - - if err := db.Ping(context.Background()).Err(); err != nil { - log.Panicf("Redis connection error %+v\n", err) - } - - log.Println("Redis successfully connected to ->", db.Options().Addr) - return db -} diff --git a/redisdb/redis_db_test.go b/redisdb/redis_db_test.go deleted file mode 100644 index d22d01b..0000000 --- a/redisdb/redis_db_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package redisdb - -import ( - "fmt" - "github.com/go-redis/redis/v8" - "github.com/stretchr/testify/assert" - "testing" -) - -var redisOptions = &redis.Options{ - Addr: "localhost:6379", - Password: "", - DB: 0, -} - -func TestNewRedisDB_WhenOptionsOk_ThenCreateClient(t *testing.T) { - got := NewRedisDB(redisOptions) - got.Close() - - assert.NotNil(t, got) - assert.Equal(t, redisOptions.Addr, got.Options().Addr) - assert.Equal(t, redisOptions.Password, got.Options().Password) - assert.Equal(t, redisOptions.DB, got.Options().DB) -} - -func TestNewRedisDB_WhenOptionsNil_ThenPanic(t *testing.T) { - defer func() { - if r := recover(); r != nil { - assert.Equal(t, fmt.Sprint("runtime error: invalid memory address or nil pointer dereference"), fmt.Sprint(r)) - } - }() - NewRedisDB(nil) -} - -func TestNewRedisDB_WhenOptionsContainBadAddr_ThenPanic(t *testing.T) { - defer func() { - if r := recover(); r != nil { - assert.Equal(t, fmt.Sprintln("Redis connection error dial tcp: lookup bad: no such host"), fmt.Sprint(r)) - } - }() - NewRedisDB(&redis.Options{ - Addr: "bad:6379", - Password: "", - DB: 0, - }) -}