Skip to content

Commit

Permalink
Merge pull request #51 from helios-ag/mongo
Browse files Browse the repository at this point in the history
Simple Ping MongoDB Checker
  • Loading branch information
dselans authored Oct 9, 2018
2 parents 73a22a3 + 5925ccf commit a5df264
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
language: go

services:
- mongodb

before_install:
- go get -t -v ./...

Expand Down
111 changes: 111 additions & 0 deletions checkers/mongo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package checkers

import (
"fmt"
"github.com/globalsign/mgo"
)

// MongoConfig is used for configuring the go-mongo check.
//
// "Auth" is _required_; redis connection/auth config.
//
// "Collection" is optional; method checks if collection exist
//
// "Ping" is optional; Ping runs a trivial ping command just to get in touch with the server.
//
// Note: At least _one_ check method must be set/enabled; you can also enable
// _all_ of the check methods (ie. perform a ping, or check particular collection for existense).
type MongoConfig struct {
Auth *MongoAuthConfig
Collection string
DB string
Ping bool
}

// MongoAuthConfig, used to setup connection params for go-mongo check
// Url format is localhost:27017 or mongo://localhost:27017
// Credential has format described at https://godoc.org/github.com/globalsign/mgo#Credential
type MongoAuthConfig struct {
Url string
Credentials mgo.Credential
}

type Mongo struct {
Config *MongoConfig
Session *mgo.Session
}

func NewMongo(cfg *MongoConfig) (*Mongo, error) {
// validate settings
if err := validateMongoConfig(cfg); err != nil {
return nil, fmt.Errorf("unable to validate mongodb config: %v", err)
}

session, err := mgo.Dial(cfg.Auth.Url)
if err != nil {
return nil, err
}

if err := session.Ping(); err != nil {
return nil, fmt.Errorf("unable to establish initial connection to mongodb: %v", err)
}

return &Mongo{
Config: cfg,
Session: session,
}, nil
}

func (m *Mongo) Status() (interface{}, error) {
if m.Config.Ping {
if err := m.Session.Ping(); err != nil {
return nil, fmt.Errorf("ping failed: %v", err)
}
}

if m.Config.Collection != "" {
collections, err := m.Session.DB(m.Config.DB).CollectionNames()
if err != nil {
return nil, fmt.Errorf("unable to complete set: %v", err)
}
if !contains(collections, m.Config.Collection) {
return nil, fmt.Errorf("mongo db %v collection not found", m.Config.Collection)
}
}

return nil, nil
}

func contains(data []string, needle string) bool {
for _, item := range data {
if item == needle {
return true
}
}
return false
}

func validateMongoConfig(cfg *MongoConfig) error {
if cfg == nil {
return fmt.Errorf("Main config cannot be nil")
}

if cfg.Auth == nil {
return fmt.Errorf("Auth config cannot be nil")
}

if cfg.Auth.Url == "" {
return fmt.Errorf("Url string must be set in auth config")
}

if !cfg.Ping && cfg.Collection == "" {
return fmt.Errorf("At minimum, either cfg.Ping or cfg.Collection")
}

if _, err := mgo.ParseURL(cfg.Auth.Url); err != nil {
return fmt.Errorf("Unable to parse URL: %v", err)
}

return nil
}

152 changes: 152 additions & 0 deletions checkers/mongo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package checkers

import (
"fmt"
. "github.com/onsi/gomega"
"github.com/zaffka/mongodb-boltdb-mock/db"
"testing"
)

func TestNewMongo(t *testing.T) {
RegisterTestingT(t)

t.Run("Happy path", func(t *testing.T) {
mongo := db.New(&db.Mock{})
url := "localhost:27017"
err := mongo.Connect(url)
defer mongo.Close()
Expect(err).ToNot(HaveOccurred())
})

t.Run("Bad config should error", func(t *testing.T) {
var cfg *MongoConfig
r, err := NewMongo(cfg)

Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("unable to validate mongodb config"))
Expect(r).To(BeNil())
})

t.Run("Should error when mongo server is not available", func(t *testing.T) {
cfg := &MongoConfig{
Ping: true,
Auth: &MongoAuthConfig{
Url: "foobar:42848",
},
}

r, err := NewMongo(cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("no reachable servers"))
Expect(r).To(BeNil())
})
}

func TestValidateMongoConfig(t *testing.T) {
RegisterTestingT(t)

t.Run("Should error with nil main config", func(t *testing.T) {
var cfg *MongoConfig
err := validateMongoConfig(cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Main config cannot be nil"))
})

t.Run("Should error with nil auth config", func(t *testing.T) {
err := validateMongoConfig(&MongoConfig{})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Auth config cannot be nil"))
})

t.Run("Auth config must have an addr set", func(t *testing.T) {
cfg := &MongoConfig{
Auth: &MongoAuthConfig{},
}

err := validateMongoConfig(cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Url string must be set in auth config"))
})

t.Run("Should error if none of the check methods are enabled", func(t *testing.T) {
cfg := &MongoConfig{
Auth: &MongoAuthConfig{
Url: "localhost:6379",
},
}

err := validateMongoConfig(cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("At minimum, either cfg.Ping or cfg.Collection"))
})

t.Run("Should error if url has wrong format", func(t *testing.T) {
cfg := &MongoConfig{
Auth: &MongoAuthConfig{
Url: "wrong\\localhost:6379",
},
}

err := validateMongoConfig(cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Unable to parse URL"))
})

}

func TestMongoStatus(t *testing.T) {
RegisterTestingT(t)

t.Run("Shouldn't error when ping is enabled", func(t *testing.T) {
cfg := &MongoConfig{
Ping: true,
}
checker, _, err := setupMongo(cfg)
if err != nil {
t.Fatal(err)
}

Expect(err).ToNot(HaveOccurred())

_, err = checker.Status()

Expect(err).To(BeNil())
})

t.Run("Should error if collection not found(available)", func(t *testing.T) {
cfg := &MongoConfig{
Collection: "go-check",
}
checker, _, err := setupMongo(cfg)
if err != nil {
t.Fatal(err)
}

_, err = checker.Status()

Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("collection not found"))
})

}

func setupMongo(cfg *MongoConfig) (*Mongo, db.Handler, error) {
server := db.New(&db.Mongo{})
url := "mongodb://localhost:27017"
err := server.Connect(url)

if err != nil {
return nil, nil, fmt.Errorf("Unable to setup mongo: %v", err)
}

cfg.Auth = &MongoAuthConfig{
Url: url,
}

checker, err := NewMongo(cfg)
if err != nil {
return nil, nil, fmt.Errorf("Unable to setup checker: %v", err)
}

return checker, server, nil
}

0 comments on commit a5df264

Please sign in to comment.