Skip to content

Commit

Permalink
feat: Add basic unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fbufler committed Dec 3, 2023
1 parent 4b11e81 commit 24c9669
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 60 deletions.
6 changes: 5 additions & 1 deletion cmd/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ func local(cmd *cobra.Command, args []string) error {
LocalCfg.TestTimeout = testTimeout
}
log.Debug().Msg("Initializing database tester")
dbs := []database.Database{}
for _, dbCfg := range LocalCfg.Databases {
dbs = append(dbs, database.NewPostgres(dbCfg))
}
tester := tester.NewPostgres(tester.Config{
Databases: LocalCfg.Databases,
Databases: dbs,
TestTimeout: LocalCfg.TestTimeout,
TestInterval: LocalCfg.TestInterval,
})
Expand Down
6 changes: 5 additions & 1 deletion cmd/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ func serve(cmd *cobra.Command, args []string) error {
serveCfg.TestTimeout = testTimeout
}
log.Debug().Msg("Initializing database tester")
dbs := []database.Database{}
for _, dbCfg := range serveCfg.Databases {
dbs = append(dbs, database.NewPostgres(dbCfg))
}
tester := tester.NewPostgres(tester.Config{
Databases: serveCfg.Databases,
Databases: dbs,
TestTimeout: serveCfg.TestTimeout,
TestInterval: serveCfg.TestInterval,
})
Expand Down
6 changes: 5 additions & 1 deletion cmd/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ func setup(cmd *cobra.Command, args []string) error {
}
log.Debug().Msgf("LocalCfg: %+v", LocalCfg)
log.Debug().Msg("Initializing database tester")
dbs := []database.Database{}
for _, dbCfg := range LocalCfg.Databases {
dbs = append(dbs, database.NewPostgres(dbCfg))
}
tester := tester.NewPostgres(tester.Config{
Databases: LocalCfg.Databases,
Databases: dbs,
})
log.Info().Msg("Setup tester")
err = tester.Setup(ctx)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
go.uber.org/mock v0.3.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down
125 changes: 125 additions & 0 deletions internal/service/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package service

import (
"context"
"net/http/httptest"
"testing"
"time"

"github.com/fbufler/database-monitor/internal/tester"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
)

func TestNew(t *testing.T) {
type args struct {
config Config
results chan tester.Result
router *mux.Router
}
tests := []struct {
name string
args args
want Service
}{
{
name: "New",
args: args{
config: Config{
Port: 8080,
InvalidationTime: 60,
},
results: make(chan tester.Result),
router: mux.NewRouter(),
},
want: &ServiceImpl{
config: Config{Port: 8080, InvalidationTime: 60},
results: make(chan tester.Result),
router: mux.NewRouter(),
resultsMap: make(map[string]tester.Result),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := New(tt.args.config, tt.args.results, tt.args.router)
if got == nil {
t.Errorf("New() = %v, want %v", got, tt.want)
}
})
}
}

func TestServiceImplCollectResults(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
results := make(chan tester.Result)
s := New(Config{Port: 8080, InvalidationTime: 1}, results, mux.NewRouter())
go s.(*ServiceImpl).collectResults(ctx)
results <- tester.Result{
Database: "test",
Connectable: true,
Writable: true,
Readable: true,
ConnectionTime: 0,
Timestamp: time.Now(),
WriteTime: 0,
ReadTime: 0,
}
result, ok := s.(*ServiceImpl).resultsMap["test"]
assert.Equal(t, true, ok)
assert.Equal(t, "test", result.Database)
assert.Equal(t, true, result.Connectable)
assert.Equal(t, true, result.Writable)
assert.Equal(t, true, result.Readable)
assert.Equal(t, time.Duration(0), result.ConnectionTime)
assert.Equal(t, time.Duration(0), result.WriteTime)
assert.Equal(t, time.Duration(0), result.ReadTime)
}

func TestServiceImplCollectResultsInvalidation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
results := make(chan tester.Result)
s := New(Config{Port: 8080, InvalidationTime: 1}, results, mux.NewRouter())
go s.(*ServiceImpl).collectResults(ctx)
results <- tester.Result{
Database: "test",
Connectable: true,
Writable: true,
Readable: true,
ConnectionTime: 0,
Timestamp: time.Now().Add(-2 * time.Second),
WriteTime: 0,
ReadTime: 0,
}
_, ok := s.(*ServiceImpl).resultsMap["test"]
assert.Equal(t, false, ok)
}

func TestRunResults(t *testing.T) {
router := mux.NewRouter()
results := make(chan tester.Result)
s := New(Config{Port: 8080, InvalidationTime: 1}, results, router)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go s.Run(ctx)
now := time.Now()
results <- tester.Result{
Database: "test",
Connectable: true,
Writable: true,
Readable: true,
ConnectionTime: 0,
Timestamp: now,
WriteTime: 0,
ReadTime: 0,
}
time.Sleep(50 * time.Millisecond)
server := httptest.NewServer(router)
request := httptest.NewRequest("GET", server.URL+"/results", nil)
response := httptest.NewRecorder()
router.ServeHTTP(response, request)
assert.Equal(t, 200, response.Code)
assert.Equal(t, "{\"results\":{\"test\":{\"database\":\"test\",\"connectable\":true,\"connection_time\":0,\"writable\":true,\"write_time\":0,\"readable\":true,\"read_time\":0,\"timestamp\":\""+now.Format(time.RFC3339Nano)+"\"}}}\n", response.Body.String())
}
100 changes: 46 additions & 54 deletions internal/tester/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,84 +21,76 @@ func NewPostgres(config Config) Tester {
}
}

func (p *Postgres) Run(ctx context.Context) chan Result {
go p.run(ctx)
return p.results
}

func (p *Postgres) run(ctx context.Context) {
log.Info().Msg("Starting postgres tester")
log.Debug().Msg("Initializing databases")
dbs := make([]database.Database, len(p.config.Databases))
for i, cfg := range p.config.Databases {
dbs[i] = database.NewPostgres(cfg)
}
log.Debug().Msg("Starting database tests")
for {
select {
case <-ctx.Done():
log.Debug().Msg("Received termination signal")
log.Debug().Msg("Closing databases")
for _, db := range dbs {
for _, db := range p.config.Databases {
db.Close()
}
log.Debug().Msg("Closing results channel")
close(p.results)
return
default:
for _, db := range dbs {
go func(db database.Database) {
result := Result{
Database: db.Identifier(),
Connectable: false,
Writable: false,
Readable: false,
Timestamp: time.Now(),
}
connectionTime := time.Now()
err := db.Connect()
if err != nil {
log.Error().Msgf("connecting to %s: %s", result.Database, err)
p.results <- result
return
}
result.ConnectionTime = time.Since(connectionTime)
defer db.Close()
result.Connectable = true
readTime := time.Now()
readCtx, readCancel := context.WithTimeout(ctx, time.Duration(p.config.TestTimeout)*time.Second)
err = db.TestRead(readCtx)
readCancel()
if err != nil {
log.Error().Msgf("reading from %s: %s", result.Database, err)
p.results <- result
return
}
result.ReadTime = time.Since(readTime)
result.Readable = true
writeTime := time.Now()
writeCtx, writeCancel := context.WithTimeout(ctx, time.Duration(p.config.TestTimeout)*time.Second)
err = db.TestWrite(writeCtx)
writeCancel()
if err != nil {
log.Error().Msgf("writing to %s: %s", result.Database, err)
p.results <- result
return
}
result.WriteTime = time.Since(writeTime)
result.Writable = true
p.results <- result
}(db)
for _, db := range p.config.Databases {
go p.runDatabaseTest(db, ctx)
}
time.Sleep(time.Duration(p.config.TestInterval) * time.Second)
}
}
}

func (p *Postgres) Run(ctx context.Context) chan Result {
go p.run(ctx)
return p.results
func (p *Postgres) runDatabaseTest(db database.Database, ctx context.Context) {
result := Result{
Database: db.Identifier(),
Connectable: false,
Writable: false,
Readable: false,
Timestamp: time.Now(),
}
connectionTime := time.Now()
err := db.Connect()
if err != nil {
log.Error().Msgf("connecting to %s: %s", result.Database, err)
p.results <- result
return
}
result.ConnectionTime = time.Since(connectionTime)
defer db.Close()
result.Connectable = true
readTime := time.Now()
err = db.TestRead(ctx)
if err != nil {
log.Error().Msgf("reading from %s: %s", result.Database, err)
p.results <- result
return
}
result.ReadTime = time.Since(readTime)
result.Readable = true
writeTime := time.Now()
err = db.TestWrite(ctx)
if err != nil {
log.Error().Msgf("writing to %s: %s", result.Database, err)
p.results <- result
return
}
result.WriteTime = time.Since(writeTime)
result.Writable = true
p.results <- result
}

func (p *Postgres) Setup(ctx context.Context) error {
var setupErrors []error
for _, cfg := range p.config.Databases {
db := database.NewPostgres(cfg)
for _, db := range p.config.Databases {
err := db.SetupTestTable(ctx)
if err != nil {
setupErrors = append(setupErrors, err)
Expand Down
Loading

0 comments on commit 24c9669

Please sign in to comment.