-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from helios-ag/mongo
Simple Ping MongoDB Checker
- Loading branch information
Showing
3 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
language: go | ||
|
||
services: | ||
- mongodb | ||
|
||
before_install: | ||
- go get -t -v ./... | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |