From bf21604d425b4feb1b95e4e94643e7a658eeea90 Mon Sep 17 00:00:00 2001
From: Wim <wim@42.be>
Date: Sat, 23 Feb 2019 22:51:27 +0100
Subject: Make all loggers derive from non-default instance (#728)

---
 bridge/bridge.go                                   |   31 +-
 bridge/config/config.go                            |   82 +-
 bridge/helper/helper.go                            |   64 +-
 bridge/slack/helpers_test.go                       |    2 +-
 bridge/sshchat/sshchat.go                          |    3 +-
 gateway/gateway.go                                 |  124 +-
 gateway/gateway_test.go                            |   46 +-
 gateway/handlers.go                                |   40 +-
 gateway/router.go                                  |   39 +-
 gateway/samechannel/samechannel.go                 |    2 +-
 gateway/samechannel/samechannel_test.go            |    8 +-
 matterbridge.go                                    |   73 +-
 matterclient/channels.go                           |   13 +-
 matterclient/helpers.go                            |   30 +-
 matterclient/matterclient.go                       |   88 +-
 matterclient/messages.go                           |   12 +-
 matterclient/users.go                              |    2 +-
 vendor/github.com/stretchr/testify/require/doc.go  |   28 +
 .../testify/require/forward_requirements.go        |   16 +
 .../github.com/stretchr/testify/require/require.go | 1227 ++++++++++++++++++++
 .../stretchr/testify/require/require.go.tmpl       |    6 +
 .../stretchr/testify/require/require_forward.go    |  957 +++++++++++++++
 .../testify/require/require_forward.go.tmpl        |    5 +
 .../stretchr/testify/require/requirements.go       |   29 +
 vendor/github.com/stretchr/testify/suite/doc.go    |   65 ++
 .../stretchr/testify/suite/interfaces.go           |   46 +
 vendor/github.com/stretchr/testify/suite/suite.go  |  160 +++
 vendor/modules.txt                                 |    2 +
 28 files changed, 2932 insertions(+), 268 deletions(-)
 create mode 100644 vendor/github.com/stretchr/testify/require/doc.go
 create mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements.go
 create mode 100644 vendor/github.com/stretchr/testify/require/require.go
 create mode 100644 vendor/github.com/stretchr/testify/require/require.go.tmpl
 create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go
 create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
 create mode 100644 vendor/github.com/stretchr/testify/require/requirements.go
 create mode 100644 vendor/github.com/stretchr/testify/suite/doc.go
 create mode 100644 vendor/github.com/stretchr/testify/suite/interfaces.go
 create mode 100644 vendor/github.com/stretchr/testify/suite/suite.go

diff --git a/bridge/bridge.go b/bridge/bridge.go
index 6b955a9e..fdc1ec8b 100644
--- a/bridge/bridge.go
+++ b/bridge/bridge.go
@@ -2,10 +2,10 @@ package bridge
 
 import (
 	"strings"
+	"sync"
 
 	"github.com/42wim/matterbridge/bridge/config"
 	"github.com/sirupsen/logrus"
-	"sync"
 )
 
 type Bridger interface {
@@ -17,6 +17,8 @@ type Bridger interface {
 
 type Bridge struct {
 	Bridger
+	*sync.RWMutex
+
 	Name           string
 	Account        string
 	Protocol       string
@@ -26,37 +28,34 @@ type Bridge struct {
 	Log            *logrus.Entry
 	Config         config.Config
 	General        *config.Protocol
-	*sync.RWMutex
 }
 
 type Config struct {
-	//	General *config.Protocol
-	Remote chan config.Message
-	Log    *logrus.Entry
 	*Bridge
+
+	Remote chan config.Message
 }
 
 // Factory is the factory function to create a bridge
 type Factory func(*Config) Bridger
 
 func New(bridge *config.Bridge) *Bridge {
-	b := &Bridge{
-		Channels: make(map[string]config.ChannelInfo),
-		RWMutex:  new(sync.RWMutex),
-		Joined:   make(map[string]bool),
-	}
 	accInfo := strings.Split(bridge.Account, ".")
 	protocol := accInfo[0]
 	name := accInfo[1]
-	b.Name = name
-	b.Protocol = protocol
-	b.Account = bridge.Account
-	return b
+
+	return &Bridge{
+		RWMutex:  new(sync.RWMutex),
+		Channels: make(map[string]config.ChannelInfo),
+		Name:     name,
+		Protocol: protocol,
+		Account:  bridge.Account,
+		Joined:   make(map[string]bool),
+	}
 }
 
 func (b *Bridge) JoinChannels() error {
-	err := b.joinChannels(b.Channels, b.Joined)
-	return err
+	return b.joinChannels(b.Channels, b.Joined)
 }
 
 // SetChannelMembers sets the newMembers to the bridge ChannelMembers
diff --git a/bridge/config/config.go b/bridge/config/config.go
index 47914951..61ffe913 100644
--- a/bridge/config/config.go
+++ b/bridge/config/config.go
@@ -8,7 +8,6 @@ import (
 	"time"
 
 	"github.com/fsnotify/fsnotify"
-	prefixed "github.com/matterbridge/logrus-prefixed-formatter"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 )
@@ -204,63 +203,58 @@ type Config interface {
 }
 
 type config struct {
-	v *viper.Viper
 	sync.RWMutex
 
-	cv *BridgeValues
+	logger *logrus.Entry
+	v      *viper.Viper
+	cv     *BridgeValues
 }
 
-func NewConfig(cfgfile string) Config {
-	logrus.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false})
-	flog := logrus.WithFields(logrus.Fields{"prefix": "config"})
+// NewConfig instantiates a new configuration based on the specified configuration file path.
+func NewConfig(rootLogger *logrus.Logger, cfgfile string) Config {
+	logger := rootLogger.WithFields(logrus.Fields{"prefix": "config"})
+
 	viper.SetConfigFile(cfgfile)
-	input, err := getFileContents(cfgfile)
+	input, err := ioutil.ReadFile(cfgfile)
 	if err != nil {
-		logrus.Fatal(err)
+		logger.Fatalf("Failed to read configuration file: %#v", err)
 	}
-	mycfg := newConfigFromString(input)
+
+	mycfg := newConfigFromString(logger, input)
 	if mycfg.cv.General.MediaDownloadSize == 0 {
 		mycfg.cv.General.MediaDownloadSize = 1000000
 	}
 	viper.WatchConfig()
 	viper.OnConfigChange(func(e fsnotify.Event) {
-		flog.Println("Config file changed:", e.Name)
+		logger.Println("Config file changed:", e.Name)
 	})
 	return mycfg
 }
 
-func getFileContents(filename string) ([]byte, error) {
-	input, err := ioutil.ReadFile(filename)
-	if err != nil {
-		logrus.Fatal(err)
-		return []byte(nil), err
-	}
-	return input, nil
-}
-
-func NewConfigFromString(input []byte) Config {
-	return newConfigFromString(input)
+// NewConfigFromString instantiates a new configuration based on the specified string.
+func NewConfigFromString(rootLogger *logrus.Logger, input []byte) Config {
+	logger := rootLogger.WithFields(logrus.Fields{"prefix": "config"})
+	return newConfigFromString(logger, input)
 }
 
-func newConfigFromString(input []byte) *config {
+func newConfigFromString(logger *logrus.Entry, input []byte) *config {
 	viper.SetConfigType("toml")
 	viper.SetEnvPrefix("matterbridge")
-	viper.AddConfigPath(".")
 	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
 	viper.AutomaticEnv()
-	err := viper.ReadConfig(bytes.NewBuffer(input))
-	if err != nil {
-		logrus.Fatal(err)
+
+	if err := viper.ReadConfig(bytes.NewBuffer(input)); err != nil {
+		logger.Fatalf("Failed to parse the configuration: %#v", err)
 	}
 
 	cfg := &BridgeValues{}
-	err = viper.Unmarshal(cfg)
-	if err != nil {
-		logrus.Fatal(err)
+	if err := viper.Unmarshal(cfg); err != nil {
+		logger.Fatalf("Failed to load the configuration: %#v", err)
 	}
 	return &config{
-		v:  viper.GetViper(),
-		cv: cfg,
+		logger: logger,
+		v:      viper.GetViper(),
+		cv:     cfg,
 	}
 }
 
@@ -271,46 +265,44 @@ func (c *config) BridgeValues() *BridgeValues {
 func (c *config) GetBool(key string) (bool, bool) {
 	c.RLock()
 	defer c.RUnlock()
-	//	log.Debugf("getting bool %s = %#v", key, c.v.GetBool(key))
 	return c.v.GetBool(key), c.v.IsSet(key)
 }
 
 func (c *config) GetInt(key string) (int, bool) {
 	c.RLock()
 	defer c.RUnlock()
-	//	log.Debugf("getting int %s = %d", key, c.v.GetInt(key))
 	return c.v.GetInt(key), c.v.IsSet(key)
 }
 
 func (c *config) GetString(key string) (string, bool) {
 	c.RLock()
 	defer c.RUnlock()
-	//	log.Debugf("getting String %s = %s", key, c.v.GetString(key))
 	return c.v.GetString(key), c.v.IsSet(key)
 }
 
 func (c *config) GetStringSlice(key string) ([]string, bool) {
 	c.RLock()
 	defer c.RUnlock()
-	// log.Debugf("getting StringSlice %s = %#v", key, c.v.GetStringSlice(key))
 	return c.v.GetStringSlice(key), c.v.IsSet(key)
 }
 
 func (c *config) GetStringSlice2D(key string) ([][]string, bool) {
 	c.RLock()
 	defer c.RUnlock()
-	result := [][]string{}
-	if res, ok := c.v.Get(key).([]interface{}); ok {
-		for _, entry := range res {
-			result2 := []string{}
-			for _, entry2 := range entry.([]interface{}) {
-				result2 = append(result2, entry2.(string))
-			}
-			result = append(result, result2)
+
+	res, ok := c.v.Get(key).([]interface{})
+	if !ok {
+		return nil, false
+	}
+	var result [][]string
+	for _, entry := range res {
+		result2 := []string{}
+		for _, entry2 := range entry.([]interface{}) {
+			result2 = append(result2, entry2.(string))
 		}
-		return result, true
+		result = append(result, result2)
 	}
-	return result, false
+	return result, true
 }
 
 func GetIconURL(msg *Message, iconURL string) string {
diff --git a/bridge/helper/helper.go b/bridge/helper/helper.go
index 12a587f0..3836556f 100644
--- a/bridge/helper/helper.go
+++ b/bridge/helper/helper.go
@@ -15,10 +15,12 @@ import (
 	"gitlab.com/golang-commonmark/markdown"
 )
 
+// DownloadFile downloads the given non-authenticated URL.
 func DownloadFile(url string) (*[]byte, error) {
 	return DownloadFileAuth(url, "")
 }
 
+// DownloadFileAuth downloads the given URL using the specified authentication token.
 func DownloadFileAuth(url string, auth string) (*[]byte, error) {
 	var buf bytes.Buffer
 	client := &http.Client{
@@ -42,8 +44,8 @@ func DownloadFileAuth(url string, auth string) (*[]byte, error) {
 }
 
 // GetSubLines splits messages in newline-delimited lines. If maxLineLength is
-// specified as non-zero GetSubLines will and also clip long lines to the
-// maximum length and insert a warning marker that the line was clipped.
+// specified as non-zero GetSubLines will also clip long lines to the maximum
+// length and insert a warning marker that the line was clipped.
 //
 // TODO: The current implementation has the inconvenient that it disregards
 // word boundaries when splitting but this is hard to solve without potentially
@@ -79,18 +81,24 @@ func GetSubLines(message string, maxLineLength int) []string {
 	return lines
 }
 
-// handle all the stuff we put into extra
+// HandleExtra manages the supplementary details stored inside a message's 'Extra' field map.
 func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message {
 	extra := msg.Extra
 	rmsg := []config.Message{}
 	for _, f := range extra[config.EventFileFailureSize] {
 		fi := f.(config.FileInfo)
 		text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize)
-		rmsg = append(rmsg, config.Message{Text: text, Username: "<system> ", Channel: msg.Channel, Account: msg.Account})
+		rmsg = append(rmsg, config.Message{
+			Text:     text,
+			Username: "<system> ",
+			Channel:  msg.Channel,
+			Account:  msg.Account,
+		})
 	}
 	return rmsg
 }
 
+// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
 func GetAvatar(av map[string]string, userid string, general *config.Protocol) string {
 	if sha, ok := av[userid]; ok {
 		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png"
@@ -98,13 +106,15 @@ func GetAvatar(av map[string]string, userid string, general *config.Protocol) st
 	return ""
 }
 
-func HandleDownloadSize(flog *logrus.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
+// HandleDownloadSize checks a specified filename against the configured download blacklist
+// and checks a specified file-size against the configure limit.
+func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
 	// check blacklist here
 	for _, entry := range general.MediaDownloadBlackList {
 		if entry != "" {
 			re, err := regexp.Compile(entry)
 			if err != nil {
-				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account)
+				logger.Errorf("incorrect regexp %s for %s", entry, msg.Account)
 				continue
 			}
 			if re.MatchString(name) {
@@ -112,43 +122,53 @@ func HandleDownloadSize(flog *logrus.Entry, msg *config.Message, name string, si
 			}
 		}
 	}
-	flog.Debugf("Trying to download %#v with size %#v", name, size)
+	logger.Debugf("Trying to download %#v with size %#v", name, size)
 	if int(size) > general.MediaDownloadSize {
 		msg.Event = config.EventFileFailureSize
-		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{Name: name, Comment: msg.Text, Size: size})
+		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{
+			Name:    name,
+			Comment: msg.Text,
+			Size:    size,
+		})
 		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize)
 	}
 	return nil
 }
 
-func HandleDownloadData(flog *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
+// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
+func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
 	var avatar bool
-	flog.Debugf("Download OK %#v %#v", name, len(*data))
+	logger.Debugf("Download OK %#v %#v", name, len(*data))
 	if msg.Event == config.EventAvatarDownload {
 		avatar = true
 	}
-	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: name, Data: data, URL: url, Comment: comment, Avatar: avatar})
+	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{
+		Name:    name,
+		Data:    data,
+		URL:     url,
+		Comment: comment,
+		Avatar:  avatar,
+	})
 }
 
+var emptyLineMatcher = regexp.MustCompile("\n+")
+
+// RemoveEmptyNewLines collapses consecutive newline characters into a single one and
+// trims any preceding or trailing newline characters as well.
 func RemoveEmptyNewLines(msg string) string {
-	lines := ""
-	for _, line := range strings.Split(msg, "\n") {
-		if line != "" {
-			lines += line + "\n"
-		}
-	}
-	lines = strings.TrimRight(lines, "\n")
-	return lines
+	return emptyLineMatcher.ReplaceAllString(strings.Trim(msg, "\n"), "\n")
 }
 
+// ClipMessage trims a message to the specified length if it exceeds it and adds a warning
+// to the message in case it does so.
 func ClipMessage(text string, length int) string {
-	// clip too long messages
+	const clippingMessage = " <clipped message>"
 	if len(text) > length {
-		text = text[:length-len(" *message clipped*")]
+		text = text[:length-len(clippingMessage)]
 		if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError {
 			text = text[:len(text)-size]
 		}
-		text += " *message clipped*"
+		text += clippingMessage
 	}
 	return text
 }
diff --git a/bridge/slack/helpers_test.go b/bridge/slack/helpers_test.go
index c9ff647d..fe3ba416 100644
--- a/bridge/slack/helpers_test.go
+++ b/bridge/slack/helpers_test.go
@@ -25,7 +25,7 @@ func TestExtractTopicOrPurpose(t *testing.T) {
 
 	logger := logrus.New()
 	logger.SetOutput(ioutil.Discard)
-	cfg := &bridge.Config{Log: logger.WithFields(nil)}
+	cfg := &bridge.Config{Bridge: &bridge.Bridge{Log: logrus.NewEntry(logger)}}
 	b := newBridge(cfg)
 	for name, tc := range testcases {
 		gotChangeType, gotOutput := b.extractTopicOrPurpose(tc.input)
diff --git a/bridge/sshchat/sshchat.go b/bridge/sshchat/sshchat.go
index 5a8029cf..3a4512cb 100644
--- a/bridge/sshchat/sshchat.go
+++ b/bridge/sshchat/sshchat.go
@@ -9,7 +9,6 @@ import (
 	"github.com/42wim/matterbridge/bridge/config"
 	"github.com/42wim/matterbridge/bridge/helper"
 	"github.com/shazow/ssh-chat/sshd"
-	"github.com/sirupsen/logrus"
 )
 
 type Bsshchat struct {
@@ -134,7 +133,7 @@ func (b *Bsshchat) handleSSHChat() error {
 			res := strings.Split(stripPrompt(b.r.Text()), ":")
 			if res[0] == "-> Set theme" {
 				wait = false
-				logrus.Debugf("mono found, allowing")
+				b.Log.Debugf("mono found, allowing")
 				continue
 			}
 			if !wait {
diff --git a/gateway/gateway.go b/gateway/gateway.go
index 72d7c72d..cb7d94c1 100644
--- a/gateway/gateway.go
+++ b/gateway/gateway.go
@@ -10,7 +10,7 @@ import (
 	"github.com/42wim/matterbridge/bridge"
 	"github.com/42wim/matterbridge/bridge/config"
 	"github.com/d5/tengo/script"
-	"github.com/hashicorp/golang-lru"
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/peterhellberg/emojilib"
 	"github.com/sirupsen/logrus"
 )
@@ -26,6 +26,8 @@ type Gateway struct {
 	Message        chan config.Message
 	Name           string
 	Messages       *lru.Cache
+
+	logger *logrus.Entry
 }
 
 type BrMsgID struct {
@@ -34,25 +36,30 @@ type BrMsgID struct {
 	ChannelID string
 }
 
-var flog *logrus.Entry
+const apiProtocol = "api"
 
-const (
-	apiProtocol = "api"
-)
+// New creates a new Gateway object associated with the specified router and
+// following the given configuration.
+func New(rootLogger *logrus.Logger, cfg *config.Gateway, r *Router) *Gateway {
+	logger := rootLogger.WithFields(logrus.Fields{"prefix": "gateway"})
 
-func New(cfg config.Gateway, r *Router) *Gateway {
-	flog = logrus.WithFields(logrus.Fields{"prefix": "gateway"})
-	gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message,
-		Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config}
 	cache, _ := lru.New(5000)
-	gw.Messages = cache
-	if err := gw.AddConfig(&cfg); err != nil {
-		flog.Errorf("AddConfig failed: %s", err)
+	gw := &Gateway{
+		Channels: make(map[string]*config.ChannelInfo),
+		Message:  r.Message,
+		Router:   r,
+		Bridges:  make(map[string]*bridge.Bridge),
+		Config:   r.Config,
+		Messages: cache,
+		logger:   logger,
+	}
+	if err := gw.AddConfig(cfg); err != nil {
+		logger.Errorf("Failed to add configuration to gateway: %#v", err)
 	}
 	return gw
 }
 
-// Find the canonical ID that the message is keyed under in cache
+// FindCanonicalMsgID returns the ID under which a message was stored in the cache.
 func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
 	ID := protocol + " " + mID
 	if gw.Messages.Contains(ID) {
@@ -72,15 +79,18 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
 	return ""
 }
 
+// AddBridge sets up a new bridge in the gateway object with the specified configuration.
 func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
 	br := gw.Router.getBridge(cfg.Account)
 	if br == nil {
 		br = bridge.New(cfg)
 		br.Config = gw.Router.Config
 		br.General = &gw.BridgeValues().General
-		// set logging
-		br.Log = logrus.WithFields(logrus.Fields{"prefix": "bridge"})
-		brconfig := &bridge.Config{Remote: gw.Message, Log: logrus.WithFields(logrus.Fields{"prefix": br.Protocol}), Bridge: br}
+		br.Log = gw.logger.WithFields(logrus.Fields{"prefix": br.Protocol})
+		brconfig := &bridge.Config{
+			Remote: gw.Message,
+			Bridge: br,
+		}
 		// add the actual bridger for this protocol to this bridge using the bridgeMap
 		br.Bridger = gw.Router.BridgeMap[br.Protocol](brconfig)
 	}
@@ -89,11 +99,12 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
 	return nil
 }
 
+// AddConfig associates a new configuration with the gateway object.
 func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
 	gw.Name = cfg.Name
 	gw.MyConfig = cfg
 	if err := gw.mapChannels(); err != nil {
-		flog.Errorf("mapChannels() failed: %s", err)
+		gw.logger.Errorf("mapChannels() failed: %s", err)
 	}
 	for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
 		br := br //scopelint
@@ -115,20 +126,20 @@ func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
 
 func (gw *Gateway) reconnectBridge(br *bridge.Bridge) {
 	if err := br.Disconnect(); err != nil {
-		flog.Errorf("Disconnect() %s failed: %s", br.Account, err)
+		gw.logger.Errorf("Disconnect() %s failed: %s", br.Account, err)
 	}
 	time.Sleep(time.Second * 5)
 RECONNECT:
-	flog.Infof("Reconnecting %s", br.Account)
+	gw.logger.Infof("Reconnecting %s", br.Account)
 	err := br.Connect()
 	if err != nil {
-		flog.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
+		gw.logger.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
 		time.Sleep(time.Second * 60)
 		goto RECONNECT
 	}
 	br.Joined = make(map[string]bool)
 	if err := br.JoinChannels(); err != nil {
-		flog.Errorf("JoinChannels() %s failed: %s", br.Account, err)
+		gw.logger.Errorf("JoinChannels() %s failed: %s", br.Account, err)
 	}
 }
 
@@ -142,13 +153,19 @@ func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
 			br.Channel = strings.ToLower(br.Channel)
 		}
 		if strings.HasPrefix(br.Account, "mattermost.") && strings.HasPrefix(br.Channel, "#") {
-			flog.Errorf("Mattermost channels do not start with a #: remove the # in %s", br.Channel)
+			gw.logger.Errorf("Mattermost channels do not start with a #: remove the # in %s", br.Channel)
 			os.Exit(1)
 		}
 		ID := br.Channel + br.Account
 		if _, ok := gw.Channels[ID]; !ok {
-			channel := &config.ChannelInfo{Name: br.Channel, Direction: direction, ID: ID, Options: br.Options, Account: br.Account,
-				SameChannel: make(map[string]bool)}
+			channel := &config.ChannelInfo{
+				Name:        br.Channel,
+				Direction:   direction,
+				ID:          ID,
+				Options:     br.Options,
+				Account:     br.Account,
+				SameChannel: make(map[string]bool),
+			}
 			channel.SameChannel[gw.Name] = br.SameChannel
 			gw.Channels[channel.ID] = channel
 		} else {
@@ -207,7 +224,7 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
 	// if source channel is in only, do nothing
 	for _, channel := range gw.Channels {
 		// lookup the channel from the message
-		if channel.ID == getChannelID(*msg) {
+		if channel.ID == getChannelID(msg) {
 			// we only have destinations if the original message is from an "in" (sending) channel
 			if !strings.Contains(channel.Direction, "in") {
 				return channels
@@ -216,11 +233,11 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
 		}
 	}
 	for _, channel := range gw.Channels {
-		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
+		if _, ok := gw.Channels[getChannelID(msg)]; !ok {
 			continue
 		}
 
-		// do samechannelgateway flogic
+		// do samechannelgateway logic
 		if channel.SameChannel[msg.Gateway] {
 			if msg.Channel == channel.Name && msg.Account != dest.Account {
 				channels = append(channels, *channel)
@@ -234,7 +251,7 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
 	return channels
 }
 
-func (gw *Gateway) getDestMsgID(msgID string, dest *bridge.Bridge, channel config.ChannelInfo) string {
+func (gw *Gateway) getDestMsgID(msgID string, dest *bridge.Bridge, channel *config.ChannelInfo) string {
 	if res, ok := gw.Messages.Get(msgID); ok {
 		IDs := res.([]*BrMsgID)
 		for _, id := range IDs {
@@ -263,7 +280,7 @@ func (gw *Gateway) ignoreTextEmpty(msg *config.Message) bool {
 			len(msg.Extra[config.EventFileFailureSize]) > 0) {
 		return false
 	}
-	flog.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
+	gw.logger.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
 	return true
 }
 
@@ -282,7 +299,7 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
 	return false
 }
 
-func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
+func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string {
 	br := gw.Bridges[msg.Account]
 	msg.Protocol = br.Protocol
 	if dest.GetBool("StripNick") {
@@ -298,7 +315,7 @@ func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) strin
 		// TODO move compile to bridge init somewhere
 		re, err := regexp.Compile(search)
 		if err != nil {
-			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
+			gw.logger.Errorf("regexp in %s failed: %s", msg.Account, err)
 			break
 		}
 		msg.Username = re.ReplaceAllString(msg.Username, replace)
@@ -326,7 +343,7 @@ func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) strin
 	return nick
 }
 
-func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
+func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) string {
 	iconurl := dest.GetString("IconURL")
 	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
 	if msg.Avatar == "" {
@@ -337,7 +354,7 @@ func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string
 
 func (gw *Gateway) modifyMessage(msg *config.Message) {
 	if err := modifyMessageTengo(gw.BridgeValues().General.TengoModifyMessage, msg); err != nil {
-		flog.Errorf("TengoModifyMessage failed: %s", err)
+		gw.logger.Errorf("TengoModifyMessage failed: %s", err)
 	}
 
 	// replace :emoji: to unicode
@@ -351,7 +368,7 @@ func (gw *Gateway) modifyMessage(msg *config.Message) {
 		// TODO move compile to bridge init somewhere
 		re, err := regexp.Compile(search)
 		if err != nil {
-			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
+			gw.logger.Errorf("regexp in %s failed: %s", msg.Account, err)
 			break
 		}
 		msg.Text = re.ReplaceAllString(msg.Text, replace)
@@ -365,46 +382,51 @@ func (gw *Gateway) modifyMessage(msg *config.Message) {
 	}
 }
 
-// SendMessage sends a message (with specified parentID) to the channel on the selected destination bridge.
-// returns a message id and error.
-func (gw *Gateway) SendMessage(origmsg config.Message, dest *bridge.Bridge, channel config.ChannelInfo, canonicalParentMsgID string) (string, error) {
-	msg := origmsg
+// SendMessage sends a message (with specified parentID) to the channel on the selected
+// destination bridge and returns a message ID or an error.
+func (gw *Gateway) SendMessage(
+	rmsg *config.Message,
+	dest *bridge.Bridge,
+	channel *config.ChannelInfo,
+	canonicalParentMsgID string,
+) (string, error) {
+	msg := *rmsg
 	// Only send the avatar download event to ourselves.
 	if msg.Event == config.EventAvatarDownload {
-		if channel.ID != getChannelID(origmsg) {
+		if channel.ID != getChannelID(rmsg) {
 			return "", nil
 		}
 	} else {
 		// do not send to ourself for any other event
-		if channel.ID == getChannelID(origmsg) {
+		if channel.ID == getChannelID(rmsg) {
 			return "", nil
 		}
 	}
 
 	// Too noisy to log like other events
 	if msg.Event != config.EventUserTyping {
-		flog.Debugf("=> Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, origmsg.Channel, dest.Account, channel.Name)
+		gw.logger.Debugf("=> Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, rmsg.Channel, dest.Account, channel.Name)
 	}
 
 	msg.Channel = channel.Name
-	msg.Avatar = gw.modifyAvatar(origmsg, dest)
-	msg.Username = gw.modifyUsername(origmsg, dest)
+	msg.Avatar = gw.modifyAvatar(rmsg, dest)
+	msg.Username = gw.modifyUsername(rmsg, dest)
 
-	msg.ID = gw.getDestMsgID(origmsg.Protocol+" "+origmsg.ID, dest, channel)
+	msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel)
 
 	// for api we need originchannel as channel
 	if dest.Protocol == apiProtocol {
-		msg.Channel = origmsg.Channel
+		msg.Channel = rmsg.Channel
 	}
 
-	msg.ParentID = gw.getDestMsgID(origmsg.Protocol+" "+canonicalParentMsgID, dest, channel)
+	msg.ParentID = gw.getDestMsgID(rmsg.Protocol+" "+canonicalParentMsgID, dest, channel)
 	if msg.ParentID == "" {
 		msg.ParentID = canonicalParentMsgID
 	}
 
 	// if the parentID is still empty and we have a parentID set in the original message
 	// this means that we didn't find it in the cache so set it "msg-parent-not-found"
-	if msg.ParentID == "" && origmsg.ParentID != "" {
+	if msg.ParentID == "" && rmsg.ParentID != "" {
 		msg.ParentID = "msg-parent-not-found"
 	}
 
@@ -421,7 +443,7 @@ func (gw *Gateway) SendMessage(origmsg config.Message, dest *bridge.Bridge, chan
 
 	// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice
 	if mID != "" {
-		flog.Debugf("mID %s: %s", dest.Account, mID)
+		gw.logger.Debugf("mID %s: %s", dest.Account, mID)
 		return mID, nil
 		//brMsgIDs = append(brMsgIDs, &BrMsgID{dest, dest.Protocol + " " + mID, channel.ID})
 	}
@@ -432,7 +454,7 @@ func (gw *Gateway) validGatewayDest(msg *config.Message) bool {
 	return msg.Gateway == gw.Name
 }
 
-func getChannelID(msg config.Message) string {
+func getChannelID(msg *config.Message) string {
 	return msg.Channel + msg.Account
 }
 
@@ -449,11 +471,11 @@ func (gw *Gateway) ignoreText(text string, input []string) bool {
 		// TODO do not compile regexps everytime
 		re, err := regexp.Compile(entry)
 		if err != nil {
-			flog.Errorf("incorrect regexp %s", entry)
+			gw.logger.Errorf("incorrect regexp %s", entry)
 			continue
 		}
 		if re.MatchString(text) {
-			flog.Debugf("matching %s. ignoring %s", entry, text)
+			gw.logger.Debugf("matching %s. ignoring %s", entry, text)
 			return true
 		}
 	}
diff --git a/gateway/gateway_test.go b/gateway/gateway_test.go
index 677afde4..b9bb5b93 100644
--- a/gateway/gateway_test.go
+++ b/gateway/gateway_test.go
@@ -2,12 +2,15 @@ package gateway
 
 import (
 	"fmt"
+	"io/ioutil"
 	"strconv"
 	"testing"
 
 	"github.com/42wim/matterbridge/bridge/config"
 	"github.com/42wim/matterbridge/gateway/bridgemap"
+	"github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/suite"
 )
 
 var testconfig = []byte(`
@@ -159,8 +162,10 @@ const (
 )
 
 func maketestRouter(input []byte) *Router {
-	cfg := config.NewConfigFromString(input)
-	r, err := NewRouter(cfg, bridgemap.FullMap)
+	logger := logrus.New()
+	logger.SetOutput(ioutil.Discard)
+	cfg := config.NewConfigFromString(logger, input)
+	r, err := NewRouter(logger, cfg, bridgemap.FullMap)
 	if err != nil {
 		fmt.Println(err)
 	}
@@ -387,7 +392,23 @@ func TestGetDestChannelAdvanced(t *testing.T) {
 	assert.Equal(t, map[string]int{"bridge3": 4, "bridge": 9, "announcements": 3, "bridge2": 4}, hits)
 }
 
-func TestIgnoreTextEmpty(t *testing.T) {
+type ignoreTestSuite struct {
+	suite.Suite
+
+	gw *Gateway
+}
+
+func TestIgnoreSuite(t *testing.T) {
+	s := &ignoreTestSuite{}
+	suite.Run(t, s)
+}
+
+func (s *ignoreTestSuite) SetupSuite() {
+	logger := logrus.New()
+	logger.SetOutput(ioutil.Discard)
+	s.gw = &Gateway{logger: logrus.NewEntry(logger)}
+}
+func (s *ignoreTestSuite) TestIgnoreTextEmpty() {
 	extraFile := make(map[string][]interface{})
 	extraAttach := make(map[string][]interface{})
 	extraFailure := make(map[string][]interface{})
@@ -424,15 +445,14 @@ func TestIgnoreTextEmpty(t *testing.T) {
 			output: true,
 		},
 	}
-	gw := &Gateway{}
 	for testname, testcase := range msgTests {
-		output := gw.ignoreTextEmpty(testcase.input)
-		assert.Equalf(t, testcase.output, output, "case '%s' failed", testname)
+		output := s.gw.ignoreTextEmpty(testcase.input)
+		s.Assert().Equalf(testcase.output, output, "case '%s' failed", testname)
 	}
 
 }
 
-func TestIgnoreTexts(t *testing.T) {
+func (s *ignoreTestSuite) TestIgnoreTexts() {
 	msgTests := map[string]struct {
 		input  string
 		re     []string
@@ -459,14 +479,13 @@ func TestIgnoreTexts(t *testing.T) {
 			output: true,
 		},
 	}
-	gw := &Gateway{}
 	for testname, testcase := range msgTests {
-		output := gw.ignoreText(testcase.input, testcase.re)
-		assert.Equalf(t, testcase.output, output, "case '%s' failed", testname)
+		output := s.gw.ignoreText(testcase.input, testcase.re)
+		s.Assert().Equalf(testcase.output, output, "case '%s' failed", testname)
 	}
 }
 
-func TestIgnoreNicks(t *testing.T) {
+func (s *ignoreTestSuite) TestIgnoreNicks() {
 	msgTests := map[string]struct {
 		input  string
 		re     []string
@@ -493,10 +512,9 @@ func TestIgnoreNicks(t *testing.T) {
 			output: false,
 		},
 	}
-	gw := &Gateway{}
 	for testname, testcase := range msgTests {
-		output := gw.ignoreText(testcase.input, testcase.re)
-		assert.Equalf(t, testcase.output, output, "case '%s' failed", testname)
+		output := s.gw.ignoreText(testcase.input, testcase.re)
+		s.Assert().Equalf(testcase.output, output, "case '%s' failed", testname)
 	}
 }
 
diff --git a/gateway/handlers.go b/gateway/handlers.go
index dfec2ab6..74bf4334 100644
--- a/gateway/handlers.go
+++ b/gateway/handlers.go
@@ -40,7 +40,7 @@ func (r *Router) handleEventGetChannelMembers(msg *config.Message) {
 		for _, br := range gw.Bridges {
 			if msg.Account == br.Account {
 				cMembers := msg.Extra[config.EventGetChannelMembers][0].(config.ChannelMembers)
-				flog.Debugf("Syncing channelmembers from %s", msg.Account)
+				r.logger.Debugf("Syncing channelmembers from %s", msg.Account)
 				br.SetChannelMembers(&cMembers)
 				return
 			}
@@ -58,7 +58,7 @@ func (r *Router) handleEventRejoinChannels(msg *config.Message) {
 			if msg.Account == br.Account {
 				br.Joined = make(map[string]bool)
 				if err := br.JoinChannels(); err != nil {
-					flog.Errorf("channel join failed for %s: %s", msg.Account, err)
+					r.logger.Errorf("channel join failed for %s: %s", msg.Account, err)
 				}
 			}
 		}
@@ -94,13 +94,13 @@ func (gw *Gateway) handleFiles(msg *config.Message) {
 		if gw.BridgeValues().General.MediaServerUpload != "" {
 			// Use MediaServerUpload. Upload using a PUT HTTP request and basicauth.
 			if err := gw.handleFilesUpload(&fi); err != nil {
-				flog.Error(err)
+				gw.logger.Error(err)
 				continue
 			}
 		} else {
 			// Use MediaServerPath. Place the file on the current filesystem.
 			if err := gw.handleFilesLocal(&fi); err != nil {
-				flog.Error(err)
+				gw.logger.Error(err)
 				continue
 			}
 		}
@@ -108,7 +108,7 @@ func (gw *Gateway) handleFiles(msg *config.Message) {
 		// Download URL.
 		durl := gw.BridgeValues().General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name
 
-		flog.Debugf("mediaserver download URL = %s", durl)
+		gw.logger.Debugf("mediaserver download URL = %s", durl)
 
 		// We uploaded/placed the file successfully. Add the SHA and URL.
 		extra := msg.Extra["file"][i].(config.FileInfo)
@@ -133,7 +133,7 @@ func (gw *Gateway) handleFilesUpload(fi *config.FileInfo) error {
 		return fmt.Errorf("mediaserver upload failed, could not create request: %#v", err)
 	}
 
-	flog.Debugf("mediaserver upload url: %s", url)
+	gw.logger.Debugf("mediaserver upload url: %s", url)
 
 	req.Header.Set("Content-Type", "binary/octet-stream")
 	_, err = client.Do(req)
@@ -154,7 +154,7 @@ func (gw *Gateway) handleFilesLocal(fi *config.FileInfo) error {
 	}
 
 	path := dir + "/" + fi.Name
-	flog.Debugf("mediaserver path placing file: %s", path)
+	gw.logger.Debugf("mediaserver path placing file: %s", path)
 
 	err = ioutil.WriteFile(path, *fi.Data, os.ModePerm)
 	if err != nil {
@@ -187,36 +187,36 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
 
 // handleMessage makes sure the message get sent to the correct bridge/channels.
 // Returns an array of msg ID's
-func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID {
+func (gw *Gateway) handleMessage(rmsg *config.Message, dest *bridge.Bridge) []*BrMsgID {
 	var brMsgIDs []*BrMsgID
 
 	// if we have an attached file, or other info
-	if msg.Extra != nil && len(msg.Extra[config.EventFileFailureSize]) != 0 && msg.Text == "" {
+	if rmsg.Extra != nil && len(rmsg.Extra[config.EventFileFailureSize]) != 0 && rmsg.Text == "" {
 		return brMsgIDs
 	}
 
-	if gw.ignoreEvent(msg.Event, dest) {
+	if gw.ignoreEvent(rmsg.Event, dest) {
 		return brMsgIDs
 	}
 
 	// broadcast to every out channel (irc QUIT)
-	if msg.Channel == "" && msg.Event != config.EventJoinLeave {
-		flog.Debug("empty channel")
+	if rmsg.Channel == "" && rmsg.Event != config.EventJoinLeave {
+		gw.logger.Debug("empty channel")
 		return brMsgIDs
 	}
 
 	// Get the ID of the parent message in thread
 	var canonicalParentMsgID string
-	if msg.ParentID != "" && dest.GetBool("PreserveThreading") {
-		canonicalParentMsgID = gw.FindCanonicalMsgID(msg.Protocol, msg.ParentID)
+	if rmsg.ParentID != "" && dest.GetBool("PreserveThreading") {
+		canonicalParentMsgID = gw.FindCanonicalMsgID(rmsg.Protocol, rmsg.ParentID)
 	}
 
-	origmsg := msg
-	channels := gw.getDestChannel(&msg, *dest)
-	for _, channel := range channels {
-		msgID, err := gw.SendMessage(origmsg, dest, channel, canonicalParentMsgID)
+	channels := gw.getDestChannel(rmsg, *dest)
+	for idx := range channels {
+		channel := &channels[idx]
+		msgID, err := gw.SendMessage(rmsg, dest, channel, canonicalParentMsgID)
 		if err != nil {
-			flog.Errorf("SendMessage failed: %s", err)
+			gw.logger.Errorf("SendMessage failed: %s", err)
 			continue
 		}
 		if msgID == "" {
@@ -235,7 +235,7 @@ func (gw *Gateway) handleExtractNicks(msg *config.Message) {
 		replace := outer[1]
 		msg.Username, msg.Text, err = extractNick(search, replace, msg.Username, msg.Text)
 		if err != nil {
-			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
+			gw.logger.Errorf("regexp in %s failed: %s", msg.Account, err)
 			break
 		}
 	}
diff --git a/gateway/router.go b/gateway/router.go
index 425960ce..7d16b07d 100644
--- a/gateway/router.go
+++ b/gateway/router.go
@@ -7,31 +7,40 @@ import (
 
 	"github.com/42wim/matterbridge/bridge"
 	"github.com/42wim/matterbridge/bridge/config"
-	samechannelgateway "github.com/42wim/matterbridge/gateway/samechannel"
+	"github.com/42wim/matterbridge/gateway/samechannel"
+	"github.com/sirupsen/logrus"
 )
 
 type Router struct {
 	config.Config
+	sync.RWMutex
 
 	BridgeMap        map[string]bridge.Factory
 	Gateways         map[string]*Gateway
 	Message          chan config.Message
 	MattermostPlugin chan config.Message
-	sync.RWMutex
+
+	logger *logrus.Entry
 }
 
-func NewRouter(cfg config.Config, bridgeMap map[string]bridge.Factory) (*Router, error) {
+// NewRouter initializes a new Matterbridge router for the specified configuration and
+// sets up all required gateways.
+func NewRouter(rootLogger *logrus.Logger, cfg config.Config, bridgeMap map[string]bridge.Factory) (*Router, error) {
+	logger := rootLogger.WithFields(logrus.Fields{"prefix": "router"})
+
 	r := &Router{
 		Config:           cfg,
 		BridgeMap:        bridgeMap,
 		Message:          make(chan config.Message),
 		MattermostPlugin: make(chan config.Message),
 		Gateways:         make(map[string]*Gateway),
+		logger:           logger,
 	}
-	sgw := samechannelgateway.New(cfg)
-	gwconfigs := sgw.GetConfig()
+	sgw := samechannel.New(cfg)
+	gwconfigs := append(sgw.GetConfig(), cfg.BridgeValues().Gateway...)
 
-	for _, entry := range append(gwconfigs, cfg.BridgeValues().Gateway...) {
+	for idx := range gwconfigs {
+		entry := &gwconfigs[idx]
 		if !entry.Enable {
 			continue
 		}
@@ -41,21 +50,23 @@ func NewRouter(cfg config.Config, bridgeMap map[string]bridge.Factory) (*Router,
 		if _, ok := r.Gateways[entry.Name]; ok {
 			return nil, fmt.Errorf("Gateway with name %s already exists", entry.Name)
 		}
-		r.Gateways[entry.Name] = New(entry, r)
+		r.Gateways[entry.Name] = New(rootLogger, entry, r)
 	}
 	return r, nil
 }
 
+// Start will connect all gateways belonging to this router and subsequently route messages
+// between them.
 func (r *Router) Start() error {
 	m := make(map[string]*bridge.Bridge)
 	for _, gw := range r.Gateways {
-		flog.Infof("Parsing gateway %s", gw.Name)
+		r.logger.Infof("Parsing gateway %s", gw.Name)
 		for _, br := range gw.Bridges {
 			m[br.Account] = br
 		}
 	}
 	for _, br := range m {
-		flog.Infof("Starting bridge: %s ", br.Account)
+		r.logger.Infof("Starting bridge: %s ", br.Account)
 		err := br.Connect()
 		if err != nil {
 			e := fmt.Errorf("Bridge %s failed to start: %v", br.Account, err)
@@ -77,7 +88,7 @@ func (r *Router) Start() error {
 	for _, gw := range r.Gateways {
 		for i, br := range gw.Bridges {
 			if br.Bridger == nil {
-				flog.Errorf("removing failed bridge %s", i)
+				r.logger.Errorf("removing failed bridge %s", i)
 				delete(gw.Bridges, i)
 			}
 		}
@@ -91,7 +102,7 @@ func (r *Router) Start() error {
 // otherwise returns false
 func (r *Router) disableBridge(br *bridge.Bridge, err error) bool {
 	if r.BridgeValues().General.IgnoreFailureOnStart {
-		flog.Error(err)
+		r.logger.Error(err)
 		// setting this bridge empty
 		*br = bridge.Bridge{}
 		return true
@@ -124,7 +135,7 @@ func (r *Router) handleReceive() {
 			gw.modifyMessage(&msg)
 			gw.handleFiles(&msg)
 			for _, br := range gw.Bridges {
-				msgIDs = append(msgIDs, gw.handleMessage(msg, br)...)
+				msgIDs = append(msgIDs, gw.handleMessage(&msg, br)...)
 			}
 			// only add the message ID if it doesn't already exists
 			if _, ok := gw.Messages.Get(msg.Protocol + " " + msg.ID); !ok && msg.ID != "" {
@@ -146,9 +157,9 @@ func (r *Router) updateChannelMembers() {
 				if br.Protocol != "slack" {
 					continue
 				}
-				flog.Debugf("sending %s to %s", config.EventGetChannelMembers, br.Account)
+				r.logger.Debugf("sending %s to %s", config.EventGetChannelMembers, br.Account)
 				if _, err := br.Send(config.Message{Event: config.EventGetChannelMembers}); err != nil {
-					flog.Errorf("updateChannelMembers: %s", err)
+					r.logger.Errorf("updateChannelMembers: %s", err)
 				}
 			}
 		}
diff --git a/gateway/samechannel/samechannel.go b/gateway/samechannel/samechannel.go
index 1d85ea7d..4b6016c6 100644
--- a/gateway/samechannel/samechannel.go
+++ b/gateway/samechannel/samechannel.go
@@ -1,4 +1,4 @@
-package samechannelgateway
+package samechannel
 
 import (
 	"github.com/42wim/matterbridge/bridge/config"
diff --git a/gateway/samechannel/samechannel_test.go b/gateway/samechannel/samechannel_test.go
index bbfb0577..17d816a9 100644
--- a/gateway/samechannel/samechannel_test.go
+++ b/gateway/samechannel/samechannel_test.go
@@ -1,9 +1,11 @@
-package samechannelgateway
+package samechannel
 
 import (
+	"io/ioutil"
 	"testing"
 
 	"github.com/42wim/matterbridge/bridge/config"
+	"github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -66,7 +68,9 @@ var (
 )
 
 func TestGetConfig(t *testing.T) {
-	cfg := config.NewConfigFromString([]byte(testConfig))
+	logger := logrus.New()
+	logger.SetOutput(ioutil.Discard)
+	cfg := config.NewConfigFromString(logger, []byte(testConfig))
 	sgw := New(cfg)
 	configs := sgw.GetConfig()
 	assert.Equal(t, []config.Gateway{expectedConfig}, configs)
diff --git a/matterbridge.go b/matterbridge.go
index 0dac8af5..6c6b11fe 100644
--- a/matterbridge.go
+++ b/matterbridge.go
@@ -17,46 +17,69 @@ import (
 var (
 	version = "1.14.0-dev"
 	githash string
+
+	flagConfig  = flag.String("conf", "matterbridge.toml", "config file")
+	flagDebug   = flag.Bool("debug", false, "enable debug")
+	flagVersion = flag.Bool("version", false, "show version")
+	flagGops    = flag.Bool("gops", false, "enable gops agent")
 )
 
 func main() {
-	logrus.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: true})
-	flog := logrus.WithFields(logrus.Fields{"prefix": "main"})
-	flagConfig := flag.String("conf", "matterbridge.toml", "config file")
-	flagDebug := flag.Bool("debug", false, "enable debug")
-	flagVersion := flag.Bool("version", false, "show version")
-	flagGops := flag.Bool("gops", false, "enable gops agent")
 	flag.Parse()
+	if *flagVersion {
+		fmt.Printf("version: %s %s\n", version, githash)
+		return
+	}
+
+	rootLogger := setupLogger()
+	logger := rootLogger.WithFields(logrus.Fields{"prefix": "main"})
+
 	if *flagGops {
 		if err := agent.Listen(agent.Options{}); err != nil {
-			flog.Errorf("failed to start gops agent: %#v", err)
+			logger.Errorf("Failed to start gops agent: %#v", err)
 		} else {
 			defer agent.Close()
 		}
 	}
-	if *flagVersion {
-		fmt.Printf("version: %s %s\n", version, githash)
-		return
-	}
-	if *flagDebug || os.Getenv("DEBUG") == "1" {
-		logrus.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false, ForceFormatting: true})
-		flog.Info("Enabling debug")
-		logrus.SetLevel(logrus.DebugLevel)
-	}
-	flog.Printf("Running version %s %s", version, githash)
+
+	logger.Printf("Running version %s %s", version, githash)
 	if strings.Contains(version, "-dev") {
-		flog.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.")
+		logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.")
 	}
-	cfg := config.NewConfig(*flagConfig)
+
+	cfg := config.NewConfig(rootLogger, *flagConfig)
 	cfg.BridgeValues().General.Debug = *flagDebug
-	r, err := gateway.NewRouter(cfg, bridgemap.FullMap)
+
+	r, err := gateway.NewRouter(rootLogger, cfg, bridgemap.FullMap)
 	if err != nil {
-		flog.Fatalf("Starting gateway failed: %s", err)
+		logger.Fatalf("Starting gateway failed: %s", err)
 	}
-	err = r.Start()
-	if err != nil {
-		flog.Fatalf("Starting gateway failed: %s", err)
+	if err = r.Start(); err != nil {
+		logger.Fatalf("Starting gateway failed: %s", err)
 	}
-	flog.Printf("Gateway(s) started succesfully. Now relaying messages")
+	logger.Printf("Gateway(s) started succesfully. Now relaying messages")
 	select {}
 }
+
+func setupLogger() *logrus.Logger {
+	logger := &logrus.Logger{
+		Out: os.Stdout,
+		Formatter: &prefixed.TextFormatter{
+			PrefixPadding: 13,
+			DisableColors: true,
+			FullTimestamp: true,
+		},
+		Level: logrus.InfoLevel,
+	}
+	if *flagDebug || os.Getenv("DEBUG") == "1" {
+		logger.Formatter = &prefixed.TextFormatter{
+			PrefixPadding:   13,
+			DisableColors:   true,
+			FullTimestamp:   false,
+			ForceFormatting: true,
+		}
+		logger.Level = logrus.DebugLevel
+		logger.WithFields(logrus.Fields{"prefix": "main"}).Info("Enabling debug logging.")
+	}
+	return logger
+}
diff --git a/matterclient/channels.go b/matterclient/channels.go
index ddd4d006..655efe96 100644
--- a/matterclient/channels.go
+++ b/matterclient/channels.go
@@ -5,7 +5,6 @@ import (
 	"strings"
 
 	"github.com/mattermost/mattermost-server/model"
-	"github.com/sirupsen/logrus"
 )
 
 // GetChannels returns all channels we're members off
@@ -155,11 +154,11 @@ func (m *MMClient) JoinChannel(channelId string) error { //nolint:golint
 	defer m.RUnlock()
 	for _, c := range m.Team.Channels {
 		if c.Id == channelId {
-			m.log.Debug("Not joining ", channelId, " already joined.")
+			m.logger.Debug("Not joining ", channelId, " already joined.")
 			return nil
 		}
 	}
-	m.log.Debug("Joining ", channelId)
+	m.logger.Debug("Joining ", channelId)
 	_, resp := m.Client.AddChannelMember(channelId, m.User.Id)
 	if resp.Error != nil {
 		return resp.Error
@@ -189,19 +188,19 @@ func (m *MMClient) UpdateChannels() error {
 
 func (m *MMClient) UpdateChannelHeader(channelId string, header string) { //nolint:golint
 	channel := &model.Channel{Id: channelId, Header: header}
-	m.log.Debugf("updating channelheader %#v, %#v", channelId, header)
+	m.logger.Debugf("updating channelheader %#v, %#v", channelId, header)
 	_, resp := m.Client.UpdateChannel(channel)
 	if resp.Error != nil {
-		logrus.Error(resp.Error)
+		m.logger.Error(resp.Error)
 	}
 }
 
 func (m *MMClient) UpdateLastViewed(channelId string) error { //nolint:golint
-	m.log.Debugf("posting lastview %#v", channelId)
+	m.logger.Debugf("posting lastview %#v", channelId)
 	view := &model.ChannelView{ChannelId: channelId}
 	_, resp := m.Client.ViewChannel(m.User.Id, view)
 	if resp.Error != nil {
-		m.log.Errorf("ChannelView update for %s failed: %s", channelId, resp.Error)
+		m.logger.Errorf("ChannelView update for %s failed: %s", channelId, resp.Error)
 		return resp.Error
 	}
 	return nil
diff --git a/matterclient/helpers.go b/matterclient/helpers.go
index 625fffaa..b3d43460 100644
--- a/matterclient/helpers.go
+++ b/matterclient/helpers.go
@@ -22,7 +22,7 @@ func (m *MMClient) doLogin(firstConnection bool, b *backoff.Backoff) error {
 	var logmsg = "trying login"
 	var err error
 	for {
-		m.log.Debugf("%s %s %s %s", logmsg, m.Credentials.Team, m.Credentials.Login, m.Credentials.Server)
+		m.logger.Debugf("%s %s %s %s", logmsg, m.Credentials.Team, m.Credentials.Login, m.Credentials.Server)
 		if m.Credentials.Token != "" {
 			resp, err = m.doLoginToken()
 			if err != nil {
@@ -34,14 +34,14 @@ func (m *MMClient) doLogin(firstConnection bool, b *backoff.Backoff) error {
 		appErr = resp.Error
 		if appErr != nil {
 			d := b.Duration()
-			m.log.Debug(appErr.DetailedError)
+			m.logger.Debug(appErr.DetailedError)
 			if firstConnection {
 				if appErr.Message == "" {
 					return errors.New(appErr.DetailedError)
 				}
 				return errors.New(appErr.Message)
 			}
-			m.log.Debugf("LOGIN: %s, reconnecting in %s", appErr, d)
+			m.logger.Debugf("LOGIN: %s, reconnecting in %s", appErr, d)
 			time.Sleep(d)
 			logmsg = "retrying login"
 			continue
@@ -59,17 +59,17 @@ func (m *MMClient) doLoginToken() (*model.Response, error) {
 	m.Client.AuthType = model.HEADER_BEARER
 	m.Client.AuthToken = m.Credentials.Token
 	if m.Credentials.CookieToken {
-		m.log.Debugf(logmsg + " with cookie (MMAUTH) token")
+		m.logger.Debugf(logmsg + " with cookie (MMAUTH) token")
 		m.Client.HttpClient.Jar = m.createCookieJar(m.Credentials.Token)
 	} else {
-		m.log.Debugf(logmsg + " with personal token")
+		m.logger.Debugf(logmsg + " with personal token")
 	}
 	m.User, resp = m.Client.GetMe("")
 	if resp.Error != nil {
 		return resp, resp.Error
 	}
 	if m.User == nil {
-		m.log.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass)
+		m.logger.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass)
 		return resp, errors.New("invalid token")
 	}
 	return resp, nil
@@ -126,7 +126,7 @@ func (m *MMClient) initUser() error {
 	defer m.Unlock()
 	// we only load all team data on initial login.
 	// all other updates are for channels from our (primary) team only.
-	//m.log.Debug("initUser(): loading all team data")
+	//m.logger.Debug("initUser(): loading all team data")
 	teams, resp := m.Client.GetTeamsForUser(m.User.Id, "")
 	if resp.Error != nil {
 		return resp.Error
@@ -156,7 +156,7 @@ func (m *MMClient) initUser() error {
 		m.OtherTeams = append(m.OtherTeams, t)
 		if team.Name == m.Credentials.Team {
 			m.Team = t
-			m.log.Debugf("initUser(): found our team %s (id: %s)", team.Name, team.Id)
+			m.logger.Debugf("initUser(): found our team %s (id: %s)", team.Name, team.Id)
 		}
 		// add all users
 		for k, v := range t.Users {
@@ -180,10 +180,10 @@ func (m *MMClient) serverAlive(firstConnection bool, b *backoff.Backoff) error {
 		}
 		m.ServerVersion = resp.ServerVersion
 		if m.ServerVersion == "" {
-			m.log.Debugf("Server not up yet, reconnecting in %s", d)
+			m.logger.Debugf("Server not up yet, reconnecting in %s", d)
 			time.Sleep(d)
 		} else {
-			m.log.Infof("Found version %s", m.ServerVersion)
+			m.logger.Infof("Found version %s", m.ServerVersion)
 			return nil
 		}
 	}
@@ -207,7 +207,7 @@ func (m *MMClient) wsConnect() {
 	header := http.Header{}
 	header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken)
 
-	m.log.Debugf("WsClient: making connection: %s", wsurl)
+	m.logger.Debugf("WsClient: making connection: %s", wsurl)
 	for {
 		wsDialer := &websocket.Dialer{
 			TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, //nolint:gosec
@@ -217,14 +217,14 @@ func (m *MMClient) wsConnect() {
 		m.WsClient, _, err = wsDialer.Dial(wsurl, header)
 		if err != nil {
 			d := b.Duration()
-			m.log.Debugf("WSS: %s, reconnecting in %s", err, d)
+			m.logger.Debugf("WSS: %s, reconnecting in %s", err, d)
 			time.Sleep(d)
 			continue
 		}
 		break
 	}
 
-	m.log.Debug("WsClient: connected")
+	m.logger.Debug("WsClient: connected")
 	m.WsSequence = 1
 	m.WsPingChan = make(chan *model.WebSocketResponse)
 	// only start to parse WS messages when login is completely done
@@ -252,7 +252,7 @@ func (m *MMClient) checkAlive() error {
 	if resp.Error != nil {
 		return resp.Error
 	}
-	m.log.Debug("WS PING")
+	m.logger.Debug("WS PING")
 	return m.sendWSRequest("ping", nil)
 }
 
@@ -262,7 +262,7 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err
 	req.Action = action
 	req.Data = data
 	m.WsSequence++
-	m.log.Debugf("sendWsRequest %#v", req)
+	m.logger.Debugf("sendWsRequest %#v", req)
 	return m.WsClient.WriteJSON(req)
 }
 
diff --git a/matterclient/matterclient.go b/matterclient/matterclient.go
index 07994c61..18006c7a 100644
--- a/matterclient/matterclient.go
+++ b/matterclient/matterclient.go
@@ -8,7 +8,7 @@ import (
 	"time"
 
 	"github.com/gorilla/websocket"
-	"github.com/hashicorp/golang-lru"
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/jpillora/backoff"
 	prefixed "github.com/matterbridge/logrus-prefixed-formatter"
 	"github.com/mattermost/mattermost-server/model"
@@ -49,13 +49,13 @@ type Team struct {
 type MMClient struct {
 	sync.RWMutex
 	*Credentials
+
 	Team          *Team
 	OtherTeams    []*Team
 	Client        *model.Client4
 	User          *model.User
 	Users         map[string]*model.User
 	MessageChan   chan *Message
-	log           *logrus.Entry
 	WsClient      *websocket.Conn
 	WsQuit        bool
 	WsAway        bool
@@ -64,31 +64,61 @@ type MMClient struct {
 	WsPingChan    chan *model.WebSocketResponse
 	ServerVersion string
 	OnWsConnect   func()
-	lruCache      *lru.Cache
+
+	logger     *logrus.Entry
+	rootLogger *logrus.Logger
+	lruCache   *lru.Cache
 }
 
-func New(login, pass, team, server string) *MMClient {
-	cred := &Credentials{Login: login, Pass: pass, Team: team, Server: server}
-	mmclient := &MMClient{Credentials: cred, MessageChan: make(chan *Message, 100), Users: make(map[string]*model.User)}
-	logrus.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true})
-	mmclient.log = logrus.WithFields(logrus.Fields{"prefix": "matterclient"})
-	mmclient.lruCache, _ = lru.New(500)
-	return mmclient
+// New will instantiate a new Matterclient with the specified login details without connecting.
+func New(login string, pass string, team string, server string) *MMClient {
+	rootLogger := logrus.New()
+	rootLogger.SetFormatter(&prefixed.TextFormatter{
+		PrefixPadding: 13,
+		DisableColors: true,
+	})
+
+	cred := &Credentials{
+		Login:  login,
+		Pass:   pass,
+		Team:   team,
+		Server: server,
+	}
+
+	cache, _ := lru.New(500)
+	return &MMClient{
+		Credentials: cred,
+		MessageChan: make(chan *Message, 100),
+		Users:       make(map[string]*model.User),
+		rootLogger:  rootLogger,
+		lruCache:    cache,
+		logger:      rootLogger.WithFields(logrus.Fields{"prefix": "matterclient"}),
+	}
 }
 
+// SetDebugLog activates debugging logging on all Matterclient log output.
 func (m *MMClient) SetDebugLog() {
-	logrus.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false, ForceFormatting: true})
+	m.rootLogger.SetFormatter(&prefixed.TextFormatter{
+		PrefixPadding:   13,
+		DisableColors:   true,
+		FullTimestamp:   false,
+		ForceFormatting: true,
+	})
 }
 
+// SetLogLevel tries to parse the specified level and if successful sets
+// the log level accordingly. Accepted levels are: 'debug', 'info', 'warn',
+// 'error', 'fatal' and 'panic'.
 func (m *MMClient) SetLogLevel(level string) {
 	l, err := logrus.ParseLevel(level)
 	if err != nil {
-		logrus.SetLevel(logrus.InfoLevel)
-		return
+		m.logger.Warnf("Failed to parse specified log-level '%s': %#v", level, err)
+	} else {
+		m.rootLogger.SetLevel(l)
 	}
-	logrus.SetLevel(l)
 }
 
+// Login tries to connect the client with the loging details with which it was initialized.
 func (m *MMClient) Login() error {
 	// check if this is a first connect or a reconnection
 	firstConnection := true
@@ -131,13 +161,14 @@ func (m *MMClient) Login() error {
 	return nil
 }
 
+// Logout disconnects the client from the chat server.
 func (m *MMClient) Logout() error {
-	m.log.Debugf("logout as %s (team: %s) on %s", m.Credentials.Login, m.Credentials.Team, m.Credentials.Server)
+	m.logger.Debugf("logout as %s (team: %s) on %s", m.Credentials.Login, m.Credentials.Team, m.Credentials.Server)
 	m.WsQuit = true
 	m.WsClient.Close()
 	m.WsClient.UnderlyingConn().Close()
 	if strings.Contains(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN) {
-		m.log.Debug("Not invalidating session in logout, credential is a token")
+		m.logger.Debug("Not invalidating session in logout, credential is a token")
 		return nil
 	}
 	_, resp := m.Client.Logout()
@@ -147,13 +178,16 @@ func (m *MMClient) Logout() error {
 	return nil
 }
 
+// WsReceiver implements the core loop that manages the connection to the chat server. In
+// case of a disconnect it will try to reconnect. A call to this method is blocking until
+// the 'WsQuite' field of the MMClient object is set to 'true'.
 func (m *MMClient) WsReceiver() {
 	for {
 		var rawMsg json.RawMessage
 		var err error
 
 		if m.WsQuit {
-			m.log.Debug("exiting WsReceiver")
+			m.logger.Debug("exiting WsReceiver")
 			return
 		}
 
@@ -163,14 +197,14 @@ func (m *MMClient) WsReceiver() {
 		}
 
 		if _, rawMsg, err = m.WsClient.ReadMessage(); err != nil {
-			m.log.Error("error:", err)
+			m.logger.Error("error:", err)
 			// reconnect
 			m.wsConnect()
 		}
 
 		var event model.WebSocketEvent
 		if err := json.Unmarshal(rawMsg, &event); err == nil && event.IsValid() {
-			m.log.Debugf("WsReceiver event: %#v", event)
+			m.logger.Debugf("WsReceiver event: %#v", event)
 			msg := &Message{Raw: &event, Team: m.Credentials.Team}
 			m.parseMessage(msg)
 			// check if we didn't empty the message
@@ -189,40 +223,42 @@ func (m *MMClient) WsReceiver() {
 
 		var response model.WebSocketResponse
 		if err := json.Unmarshal(rawMsg, &response); err == nil && response.IsValid() {
-			m.log.Debugf("WsReceiver response: %#v", response)
+			m.logger.Debugf("WsReceiver response: %#v", response)
 			m.parseResponse(response)
-			continue
 		}
 	}
 }
 
+// StatusLoop implements a ping-cycle that ensures that the connection to the chat servers
+// remains alive. In case of a disconnect it will try to reconnect. A call to this method
+// is blocking until the 'WsQuite' field of the MMClient object is set to 'true'.
 func (m *MMClient) StatusLoop() {
 	retries := 0
 	backoff := time.Second * 60
 	if m.OnWsConnect != nil {
 		m.OnWsConnect()
 	}
-	m.log.Debug("StatusLoop:", m.OnWsConnect != nil)
+	m.logger.Debug("StatusLoop:", m.OnWsConnect != nil)
 	for {
 		if m.WsQuit {
 			return
 		}
 		if m.WsConnected {
 			if err := m.checkAlive(); err != nil {
-				logrus.Errorf("Connection is not alive: %#v", err)
+				m.logger.Errorf("Connection is not alive: %#v", err)
 			}
 			select {
 			case <-m.WsPingChan:
-				m.log.Debug("WS PONG received")
+				m.logger.Debug("WS PONG received")
 				backoff = time.Second * 60
 			case <-time.After(time.Second * 5):
 				if retries > 3 {
-					m.log.Debug("StatusLoop() timeout")
+					m.logger.Debug("StatusLoop() timeout")
 					m.Logout()
 					m.WsQuit = false
 					err := m.Login()
 					if err != nil {
-						logrus.Errorf("Login failed: %#v", err)
+						m.logger.Errorf("Login failed: %#v", err)
 						break
 					}
 					if m.OnWsConnect != nil {
diff --git a/matterclient/messages.go b/matterclient/messages.go
index c2325c09..b46feff1 100644
--- a/matterclient/messages.go
+++ b/matterclient/messages.go
@@ -10,14 +10,14 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
 	// add post to cache, if it already exists don't relay this again.
 	// this should fix reposts
 	if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok {
-		m.log.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string))
+		m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string))
 		rmsg.Text = ""
 		return
 	}
 	data := model.PostFromJson(strings.NewReader(rmsg.Raw.Data["post"].(string)))
 	// we don't have the user, refresh the userlist
 	if m.GetUser(data.UserId) == nil {
-		m.log.Infof("User '%v' is not known, ignoring message '%#v'",
+		m.logger.Infof("User '%v' is not known, ignoring message '%#v'",
 			data.UserId, data)
 		return
 	}
@@ -54,7 +54,7 @@ func (m *MMClient) parseMessage(rmsg *Message) {
 		}
 	case "group_added":
 		if err := m.UpdateChannels(); err != nil {
-			m.log.Errorf("failed to update channels: %#v", err)
+			m.logger.Errorf("failed to update channels: %#v", err)
 		}
 		/*
 			case model.ACTION_USER_REMOVED:
@@ -178,18 +178,18 @@ func (m *MMClient) SendDirectMessage(toUserId string, msg string, rootId string)
 }
 
 func (m *MMClient) SendDirectMessageProps(toUserId string, msg string, rootId string, props map[string]interface{}) { //nolint:golint
-	m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
+	m.logger.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
 	// create DM channel (only happens on first message)
 	_, resp := m.Client.CreateDirectChannel(m.User.Id, toUserId)
 	if resp.Error != nil {
-		m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, resp.Error)
+		m.logger.Debugf("SendDirectMessage to %#v failed: %s", toUserId, resp.Error)
 		return
 	}
 	channelName := model.GetDMNameFromIds(toUserId, m.User.Id)
 
 	// update our channels
 	if err := m.UpdateChannels(); err != nil {
-		m.log.Errorf("failed to update channels: %#v", err)
+		m.logger.Errorf("failed to update channels: %#v", err)
 	}
 
 	// build & send the message
diff --git a/matterclient/users.go b/matterclient/users.go
index 3dea7ce5..11f22aa0 100644
--- a/matterclient/users.go
+++ b/matterclient/users.go
@@ -124,7 +124,7 @@ func (m *MMClient) UpdateUserNick(nick string) error {
 func (m *MMClient) UsernamesInChannel(channelId string) []string { //nolint:golint
 	res, resp := m.Client.GetChannelMembers(channelId, 0, 50000, "")
 	if resp.Error != nil {
-		m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelId, resp.Error)
+		m.logger.Errorf("UsernamesInChannel(%s) failed: %s", channelId, resp.Error)
 		return []string{}
 	}
 	allusers := m.GetUsers()
diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go
new file mode 100644
index 00000000..169de392
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/doc.go
@@ -0,0 +1,28 @@
+// Package require implements the same assertions as the `assert` package but
+// stops test execution when a test fails.
+//
+// Example Usage
+//
+// The following is a complete example using require in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/require"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      require.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// Assertions
+//
+// The `require` package have same global functions as in the `assert` package,
+// but instead of returning a boolean result they call `t.FailNow()`.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package require
diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go
new file mode 100644
index 00000000..ac71d405
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go
@@ -0,0 +1,16 @@
+package require
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
new file mode 100644
index 00000000..535f2934
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -0,0 +1,1227 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
+	if assert.Condition(t, comp, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
+	if assert.Conditionf(t, comp, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    assert.Contains(t, "Hello World", "World")
+//    assert.Contains(t, ["Hello", "World"], "World")
+//    assert.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if assert.Contains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+//    assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+//    assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if assert.Containsf(t, s, contains, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if assert.DirExists(t, path, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if assert.DirExistsf(t, path, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if assert.ElementsMatchf(t, listA, listB, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  assert.Empty(t, obj)
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if assert.Empty(t, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Emptyf asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  assert.Emptyf(t, obj, "error message %s", "formatted")
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if assert.Emptyf(t, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if assert.Equal(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   assert.EqualError(t, err,  expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
+	if assert.EqualError(t, theError, errString, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   assert.EqualErrorf(t, err,  expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
+	if assert.EqualErrorf(t, theError, errString, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if assert.EqualValues(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if assert.EqualValuesf(t, expected, actual, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Equalf asserts that two objects are equal.
+//
+//    assert.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if assert.Equalf(t, expected, actual, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err) {
+// 	   assert.Equal(t, expectedError, err)
+//   }
+func Error(t TestingT, err error, msgAndArgs ...interface{}) {
+	if assert.Error(t, err, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Errorf(t, err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedErrorf, err)
+//   }
+func Errorf(t TestingT, err error, msg string, args ...interface{}) {
+	if assert.Errorf(t, err, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//    assert.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if assert.Exactly(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//    assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if assert.Exactlyf(t, expected, actual, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if assert.Fail(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if assert.FailNow(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if assert.FailNowf(t, failureMessage, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if assert.Failf(t, failureMessage, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// False asserts that the specified value is false.
+//
+//    assert.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if assert.False(t, value, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Falsef asserts that the specified value is false.
+//
+//    assert.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
+	if assert.Falsef(t, value, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if assert.FileExists(t, path, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if assert.FileExistsf(t, path, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//    assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if assert.Implementsf(t, interfaceObject, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if assert.IsType(t, expectedType, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if assert.IsTypef(t, expectedType, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//  assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+	if assert.JSONEq(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//  assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+	if assert.JSONEqf(t, expected, actual, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
+	if assert.Len(t, object, length, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//    assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
+	if assert.Lenf(t, object, length, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if assert.Nil(t, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//    assert.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if assert.Nilf(t, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
+	if assert.NoError(t, err, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoErrorf(t, err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
+	if assert.NoErrorf(t, err, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContains(t, "Hello World", "Earth")
+//    assert.NotContains(t, ["Hello", "World"], "Earth")
+//    assert.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if assert.NotContains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+//    assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+//    assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if assert.NotContainsf(t, s, contains, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if assert.NotEmpty(t, obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if assert.NotEmpty(t, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if assert.NotEmptyf(t, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if assert.NotEqual(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//    assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if assert.NotEqualf(t, expected, actual, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if assert.NotNil(t, object, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//    assert.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if assert.NotNilf(t, object, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if assert.NotPanics(t, f, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if assert.NotPanicsf(t, f, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if assert.NotRegexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+//  assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if assert.NotRegexpf(t, rx, str, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if assert.NotSubset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if assert.NotSubsetf(t, list, subset, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if assert.NotZero(t, i, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if assert.NotZerof(t, i, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if assert.Panics(t, f, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if assert.PanicsWithValuef(t, expected, f, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if assert.Panicsf(t, f, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if assert.Regexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//  assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+//  assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if assert.Regexpf(t, rx, str, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if assert.Subset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if assert.Subsetf(t, list, subset, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if assert.True(t, value, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Truef asserts that the specified value is true.
+//
+//    assert.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) {
+	if assert.Truef(t, value, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if assert.Zero(t, i, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if assert.Zerof(t, i, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl
new file mode 100644
index 00000000..6ffc751b
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl
@@ -0,0 +1,6 @@
+{{.Comment}}
+func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
+	if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
+	if h, ok := t.(tHelper); ok { h.Helper() }
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
new file mode 100644
index 00000000..9fe41dbd
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -0,0 +1,957 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    a.Contains("Hello World", "World")
+//    a.Contains(["Hello", "World"], "World")
+//    a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    a.Containsf("Hello World", "World", "error message %s", "formatted")
+//    a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+//    a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  a.Empty(obj)
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  a.Emptyf(obj, "error message %s", "formatted")
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//    a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   a.EqualError(err,  expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   a.EqualErrorf(err,  expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+//    a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.Error(err) {
+// 	   assert.Equal(t, expectedError, err)
+//   }
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Error(a.t, err, msgAndArgs...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.Errorf(err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedErrorf, err)
+//   }
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Errorf(a.t, err, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//    a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//    a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+//    a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+//    a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExistsf(a.t, path, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//  a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//  a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//  a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//  a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//    a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 a.InDelta(math.Pi, (22 / 7.0), 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// 	 a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//  a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//  a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//    a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Lenf(a.t, object, length, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//    a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nilf(a.t, object, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.NoError(err) {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.NoErrorf(err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoErrorf(a.t, err, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    a.NotContains("Hello World", "Earth")
+//    a.NotContains(["Hello", "World"], "Earth")
+//    a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+//    a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+//    a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if a.NotEmpty(obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if a.NotEmptyf(obj, "error message %s", "formatted") {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//    a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//    a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//  a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//  a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+//  a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//   a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panicsf(a.t, f, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  a.Regexp(regexp.MustCompile("start"), "it's starting")
+//  a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//  a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+//  a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+//    a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+//    a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//   a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
new file mode 100644
index 00000000..54124df1
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
+	if h, ok := a.t.(tHelper); ok { h.Helper() }
+	{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go
new file mode 100644
index 00000000..6b85c5ec
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/requirements.go
@@ -0,0 +1,29 @@
+package require
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+	FailNow()
+}
+
+type tHelper interface {
+	Helper()
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values.  Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
+
+// ValueAssertionFunc is a common function prototype when validating a single value.  Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
+
+// BoolAssertionFunc is a common function prototype when validating a bool value.  Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{})
+
+// ErrorAssertionFunc is a common function prototype when validating an error value.  Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{})
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs
diff --git a/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/stretchr/testify/suite/doc.go
new file mode 100644
index 00000000..f91a245d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/suite/doc.go
@@ -0,0 +1,65 @@
+// Package suite contains logic for creating testing suite structs
+// and running the methods on those structs as tests.  The most useful
+// piece of this package is that you can create setup/teardown methods
+// on your testing suites, which will run before/after the whole suite
+// or individual tests (depending on which interface(s) you
+// implement).
+//
+// A testing suite is usually built by first extending the built-in
+// suite functionality from suite.Suite in testify.  Alternatively,
+// you could reproduce that logic on your own if you wanted (you
+// just need to implement the TestingSuite interface from
+// suite/interfaces.go).
+//
+// After that, you can implement any of the interfaces in
+// suite/interfaces.go to add setup/teardown functionality to your
+// suite, and add any methods that start with "Test" to add tests.
+// Methods that do not match any suite interfaces and do not begin
+// with "Test" will not be run by testify, and can safely be used as
+// helper methods.
+//
+// Once you've built your testing suite, you need to run the suite
+// (using suite.Run from testify) inside any function that matches the
+// identity that "go test" is already looking for (i.e.
+// func(*testing.T)).
+//
+// Regular expression to select test suites specified command-line
+// argument "-run". Regular expression to select the methods
+// of test suites specified command-line argument "-m".
+// Suite object has assertion methods.
+//
+// A crude example:
+//     // Basic imports
+//     import (
+//         "testing"
+//         "github.com/stretchr/testify/assert"
+//         "github.com/stretchr/testify/suite"
+//     )
+//
+//     // Define the suite, and absorb the built-in basic suite
+//     // functionality from testify - including a T() method which
+//     // returns the current testing context
+//     type ExampleTestSuite struct {
+//         suite.Suite
+//         VariableThatShouldStartAtFive int
+//     }
+//
+//     // Make sure that VariableThatShouldStartAtFive is set to five
+//     // before each test
+//     func (suite *ExampleTestSuite) SetupTest() {
+//         suite.VariableThatShouldStartAtFive = 5
+//     }
+//
+//     // All methods that begin with "Test" are run as tests within a
+//     // suite.
+//     func (suite *ExampleTestSuite) TestExample() {
+//         assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
+//         suite.Equal(5, suite.VariableThatShouldStartAtFive)
+//     }
+//
+//     // In order for 'go test' to run this suite, we need to create
+//     // a normal test function and pass our suite to suite.Run
+//     func TestExampleTestSuite(t *testing.T) {
+//         suite.Run(t, new(ExampleTestSuite))
+//     }
+package suite
diff --git a/vendor/github.com/stretchr/testify/suite/interfaces.go b/vendor/github.com/stretchr/testify/suite/interfaces.go
new file mode 100644
index 00000000..b37cb040
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/suite/interfaces.go
@@ -0,0 +1,46 @@
+package suite
+
+import "testing"
+
+// TestingSuite can store and return the current *testing.T context
+// generated by 'go test'.
+type TestingSuite interface {
+	T() *testing.T
+	SetT(*testing.T)
+}
+
+// SetupAllSuite has a SetupSuite method, which will run before the
+// tests in the suite are run.
+type SetupAllSuite interface {
+	SetupSuite()
+}
+
+// SetupTestSuite has a SetupTest method, which will run before each
+// test in the suite.
+type SetupTestSuite interface {
+	SetupTest()
+}
+
+// TearDownAllSuite has a TearDownSuite method, which will run after
+// all the tests in the suite have been run.
+type TearDownAllSuite interface {
+	TearDownSuite()
+}
+
+// TearDownTestSuite has a TearDownTest method, which will run after
+// each test in the suite.
+type TearDownTestSuite interface {
+	TearDownTest()
+}
+
+// BeforeTest has a function to be executed right before the test
+// starts and receives the suite and test names as input
+type BeforeTest interface {
+	BeforeTest(suiteName, testName string)
+}
+
+// AfterTest has a function to be executed right after the test
+// finishes and receives the suite and test names as input
+type AfterTest interface {
+	AfterTest(suiteName, testName string)
+}
diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go
new file mode 100644
index 00000000..5cea8f8c
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/suite/suite.go
@@ -0,0 +1,160 @@
+package suite
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"reflect"
+	"regexp"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+var allTestsFilter = func(_, _ string) (bool, error) { return true, nil }
+var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run")
+
+// Suite is a basic testing suite with methods for storing and
+// retrieving the current *testing.T context.
+type Suite struct {
+	*assert.Assertions
+	require *require.Assertions
+	t       *testing.T
+}
+
+// T retrieves the current *testing.T context.
+func (suite *Suite) T() *testing.T {
+	return suite.t
+}
+
+// SetT sets the current *testing.T context.
+func (suite *Suite) SetT(t *testing.T) {
+	suite.t = t
+	suite.Assertions = assert.New(t)
+	suite.require = require.New(t)
+}
+
+// Require returns a require context for suite.
+func (suite *Suite) Require() *require.Assertions {
+	if suite.require == nil {
+		suite.require = require.New(suite.T())
+	}
+	return suite.require
+}
+
+// Assert returns an assert context for suite.  Normally, you can call
+// `suite.NoError(expected, actual)`, but for situations where the embedded
+// methods are overridden (for example, you might want to override
+// assert.Assertions with require.Assertions), this method is provided so you
+// can call `suite.Assert().NoError()`.
+func (suite *Suite) Assert() *assert.Assertions {
+	if suite.Assertions == nil {
+		suite.Assertions = assert.New(suite.T())
+	}
+	return suite.Assertions
+}
+
+func failOnPanic(t *testing.T) {
+	r := recover()
+	if r != nil {
+		t.Errorf("test panicked: %v", r)
+		t.FailNow()
+	}
+}
+
+// Run provides suite functionality around golang subtests.  It should be
+// called in place of t.Run(name, func(t *testing.T)) in test suite code.
+// The passed-in func will be executed as a subtest with a fresh instance of t.
+// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName.
+func (suite *Suite) Run(name string, subtest func()) bool {
+	oldT := suite.T()
+	defer suite.SetT(oldT)
+	return oldT.Run(name, func(t *testing.T) {
+		suite.SetT(t)
+		subtest()
+	})
+}
+
+// Run takes a testing suite and runs all of the tests attached
+// to it.
+func Run(t *testing.T, suite TestingSuite) {
+	suite.SetT(t)
+	defer failOnPanic(t)
+
+	if setupAllSuite, ok := suite.(SetupAllSuite); ok {
+		setupAllSuite.SetupSuite()
+	}
+	defer func() {
+		if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
+			tearDownAllSuite.TearDownSuite()
+		}
+	}()
+
+	methodFinder := reflect.TypeOf(suite)
+	tests := []testing.InternalTest{}
+	for index := 0; index < methodFinder.NumMethod(); index++ {
+		method := methodFinder.Method(index)
+		ok, err := methodFilter(method.Name)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
+			os.Exit(1)
+		}
+		if ok {
+			test := testing.InternalTest{
+				Name: method.Name,
+				F: func(t *testing.T) {
+					parentT := suite.T()
+					suite.SetT(t)
+					defer failOnPanic(t)
+
+					if setupTestSuite, ok := suite.(SetupTestSuite); ok {
+						setupTestSuite.SetupTest()
+					}
+					if beforeTestSuite, ok := suite.(BeforeTest); ok {
+						beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
+					}
+					defer func() {
+						if afterTestSuite, ok := suite.(AfterTest); ok {
+							afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name)
+						}
+						if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
+							tearDownTestSuite.TearDownTest()
+						}
+						suite.SetT(parentT)
+					}()
+					method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
+				},
+			}
+			tests = append(tests, test)
+		}
+	}
+	runTests(t, tests)
+}
+
+func runTests(t testing.TB, tests []testing.InternalTest) {
+	r, ok := t.(runner)
+	if !ok { // backwards compatibility with Go 1.6 and below
+		if !testing.RunTests(allTestsFilter, tests) {
+			t.Fail()
+		}
+		return
+	}
+
+	for _, test := range tests {
+		r.Run(test.Name, test.F)
+	}
+}
+
+// Filtering method according to set regular expression
+// specified command-line argument -m
+func methodFilter(name string) (bool, error) {
+	if ok, _ := regexp.MatchString("^Test", name); !ok {
+		return false, nil
+	}
+	return regexp.MatchString(*matchMethod, name)
+}
+
+type runner interface {
+	Run(name string, f func(t *testing.T)) bool
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 740bc5dc..1d75c351 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -175,6 +175,8 @@ github.com/spf13/pflag
 github.com/spf13/viper
 # github.com/stretchr/testify v1.3.0
 github.com/stretchr/testify/assert
+github.com/stretchr/testify/suite
+github.com/stretchr/testify/require
 # github.com/technoweenie/multipartstreamer v1.0.1
 github.com/technoweenie/multipartstreamer
 # github.com/valyala/bytebufferpool v1.0.0
-- 
cgit v1.2.3