From 474c326cf871e40f02fd576ba57bbb71c136d8ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net>
Date: Tue, 18 Nov 2014 13:38:23 -0600
Subject: [PATCH] mongo: Adding support for ConnectURL.

---
 mongo/connection.go      | 122 ++++++++++++++++++++++++++++
 mongo/connection_test.go | 136 +++++++++++++++++++++++++++++++
 mongo/database.go        | 170 +++++++++++++++++++--------------------
 mongo/database_test.go   | 161 +++++++++++++++++++++++++++++-------
 4 files changed, 470 insertions(+), 119 deletions(-)
 create mode 100644 mongo/connection.go
 create mode 100644 mongo/connection_test.go

diff --git a/mongo/connection.go b/mongo/connection.go
new file mode 100644
index 00000000..e0055ec0
--- /dev/null
+++ b/mongo/connection.go
@@ -0,0 +1,122 @@
+// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package mongo
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+	"upper.io/db"
+)
+
+const connectionScheme = `mongodb`
+
+type ConnectionURL struct {
+	User     string
+	Password string
+	Address  db.Address
+	Database string
+	Options  map[string]string
+}
+
+func (c ConnectionURL) String() (s string) {
+
+	if c.Database == "" {
+		return ""
+	}
+
+	vv := url.Values{}
+
+	// Do we have any options?
+	if c.Options == nil {
+		c.Options = map[string]string{}
+	}
+
+	// Converting options into URL values.
+	for k, v := range c.Options {
+		vv.Set(k, v)
+	}
+
+	// Has user?
+	var userInfo *url.Userinfo
+
+	if c.User != "" {
+		if c.Password == "" {
+			userInfo = url.User(c.User)
+		} else {
+			userInfo = url.UserPassword(c.User, c.Password)
+		}
+	}
+
+	// Building URL.
+	u := url.URL{
+		Scheme:   connectionScheme,
+		Path:     c.Database,
+		User:     userInfo,
+		RawQuery: vv.Encode(),
+	}
+
+	if c.Address != nil {
+		u.Host = c.Address.String()
+	}
+
+	return u.String()
+}
+
+func ParseURL(s string) (conn ConnectionURL, err error) {
+	var u *url.URL
+
+	if strings.HasPrefix(s, connectionScheme+"://") == false {
+		return conn, fmt.Errorf(`Expecting mongodb:// connection scheme.`)
+	}
+
+	if u, err = url.Parse(s); err != nil {
+		return conn, err
+	}
+
+	// Parsing host.
+	conn.Address = db.ParseAddress(u.Host)
+
+	// Deleting / from start of the string.
+	conn.Database = strings.Trim(u.Path, "/")
+
+	// Adding user / password.
+	if u.User != nil {
+		conn.User = u.User.Username()
+		conn.Password, _ = u.User.Password()
+	}
+
+	// Adding options.
+	conn.Options = map[string]string{}
+
+	var vv url.Values
+
+	if vv, err = url.ParseQuery(u.RawQuery); err != nil {
+		return conn, err
+	}
+
+	for k := range vv {
+		conn.Options[k] = vv.Get(k)
+	}
+
+	return conn, err
+}
diff --git a/mongo/connection_test.go b/mongo/connection_test.go
new file mode 100644
index 00000000..20cf1f96
--- /dev/null
+++ b/mongo/connection_test.go
@@ -0,0 +1,136 @@
+// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package mongo
+
+import (
+	"testing"
+	"upper.io/db"
+)
+
+func TestConnectionURL(t *testing.T) {
+
+	c := ConnectionURL{}
+
+	// Default connection string is only the protocol.
+	if c.String() != "" {
+		t.Fatal(`Expecting default connectiong string to be empty, got:`, c.String())
+	}
+
+	// Adding a database name.
+	c.Database = "myfilename"
+
+	if c.String() != "mongodb://myfilename" {
+		t.Fatal(`Test failed, got:`, c.String())
+	}
+
+	// Adding an option.
+	c.Options = map[string]string{
+		"cache": "foobar",
+		"mode":  "ro",
+	}
+
+	// Adding username and password
+	c.User = "user"
+	c.Password = "pass"
+
+	// Setting host.
+	c.Address = db.Host("localhost")
+
+	if c.String() != "mongodb://user:pass@localhost/myfilename?cache=foobar&mode=ro" {
+		t.Fatal(`Test failed, got:`, c.String())
+	}
+
+	// Setting host and port.
+	c.Address = db.HostPort("localhost", 27017)
+
+	if c.String() != "mongodb://user:pass@localhost:27017/myfilename?cache=foobar&mode=ro" {
+		t.Fatal(`Test failed, got:`, c.String())
+	}
+
+	// Setting cluster.
+	c.Address = db.Cluster(db.Host("localhost"), db.Host("1.2.3.4"), db.HostPort("example.org", 1234))
+
+	if c.String() != "mongodb://user:pass@localhost,1.2.3.4,example.org:1234/myfilename?cache=foobar&mode=ro" {
+		t.Fatal(`Test failed, got:`, c.String())
+	}
+
+	// Setting another database.
+	c.Database = "another_database"
+
+	if c.String() != "mongodb://user:pass@localhost,1.2.3.4,example.org:1234/another_database?cache=foobar&mode=ro" {
+		t.Fatal(`Test failed, got:`, c.String())
+	}
+
+}
+
+func TestParseConnectionURL(t *testing.T) {
+	var u ConnectionURL
+	var s string
+	var err error
+
+	s = "mongodb:///mydatabase"
+
+	if u, err = ParseURL(s); err != nil {
+		t.Fatal(err)
+	}
+
+	if u.Database != "mydatabase" {
+		t.Fatal("Failed to parse database.")
+	}
+
+	s = "mongodb://user:pass@localhost,1.2.3.4,example.org:1234/another_database?cache=foobar&mode=ro"
+
+	if u, err = ParseURL(s); err != nil {
+		t.Fatal(err)
+	}
+
+	if u.Database != "another_database" {
+		t.Fatal("Failed to get database.")
+	}
+
+	if u.Options["cache"] != "foobar" {
+		t.Fatal("Expecting option.")
+	}
+
+	if u.Options["mode"] != "ro" {
+		t.Fatal("Expecting option.")
+	}
+
+	if u.User != "user" {
+		t.Fatal("Expecting user.")
+	}
+
+	if u.Password != "pass" {
+		t.Fatal("Expecting password.")
+	}
+
+	if u.Address.String() != "localhost,1.2.3.4,example.org:1234" {
+		t.Fatal("Expecting host.")
+	}
+
+	s = "http://example.org"
+
+	if _, err = ParseURL(s); err == nil {
+		t.Fatal("Expecting error.")
+	}
+
+}
diff --git a/mongo/database.go b/mongo/database.go
index 8a54337c..ede0c73b 100644
--- a/mongo/database.go
+++ b/mongo/database.go
@@ -1,32 +1,29 @@
-/*
-  Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
+// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 package mongo
 
 import (
 	"fmt"
 	"log"
-	"net/url"
 	"os"
 	"strings"
 	"time"
@@ -41,7 +38,7 @@ var connTimeout = time.Second * 5
 
 type Source struct {
 	name     string
-	config   db.Settings
+	connURL  db.ConnectionURL
 	session  *mgo.Session
 	database *mgo.Database
 }
@@ -62,119 +59,114 @@ func debugLogQuery(c *chunks) {
 }
 
 // Returns the string name of the database.
-func (self *Source) Name() string {
-	return self.name
+func (s *Source) Name() string {
+	return s.name
 }
 
 // Stores database settings.
-func (self *Source) Setup(config db.Settings) error {
-	self.config = config
-	return self.Open()
+func (s *Source) Setup(connURL db.ConnectionURL) error {
+	s.connURL = connURL
+	return s.Open()
 }
 
-func (self *Source) Clone() (db.Database, error) {
+func (s *Source) Clone() (db.Database, error) {
 	clone := &Source{
-		name:     self.name,
-		config:   self.config,
-		session:  self.session.Copy(),
-		database: self.database,
+		name:     s.name,
+		connURL:  s.connURL,
+		session:  s.session.Copy(),
+		database: s.database,
 	}
 	return clone, nil
 }
 
-func (self *Source) Transaction() (db.Tx, error) {
+func (s *Source) Transaction() (db.Tx, error) {
 	return nil, db.ErrUnsupported
 }
 
-func (self *Source) Ping() error {
-	return self.session.Ping()
+func (s *Source) Ping() error {
+	return s.session.Ping()
 }
 
 // Returns the underlying *mgo.Session instance.
-func (self *Source) Driver() interface{} {
-	return self.session
+func (s *Source) Driver() interface{} {
+	return s.session
 }
 
 // Attempts to connect to a database using the stored settings.
-func (self *Source) Open() error {
+func (s *Source) Open() error {
 	var err error
 
-	connURL := &url.URL{Scheme: `mongodb`}
-
-	if self.config.Port == 0 {
-		self.config.Port = 27017
-	}
-
-	if self.config.Host == "" {
-		self.config.Host = `127.0.0.1`
-	}
-
-	connURL.Host = fmt.Sprintf(`%s:%d`, self.config.Host, self.config.Port)
-
-	if self.config.User != "" {
-		connURL.User = url.UserPassword(self.config.User, self.config.Password)
-	}
+	// Before db.ConnectionURL we used a unified db.Settings struct. This
+	// condition checks for that type and provides backwards compatibility.
+	if settings, ok := s.connURL.(db.Settings); ok {
+		var sAddr string
+
+		if settings.Host != "" {
+			if settings.Port > 0 {
+				sAddr = fmt.Sprintf("%s:%d", settings.Host, settings.Port)
+			} else {
+				sAddr = settings.Host
+			}
+		} else {
+			sAddr = settings.Socket
+		}
 
-	if self.config.Database != "" {
-		connURL.Path = "/" + self.config.Database
-	}
+		conn := ConnectionURL{
+			User:     settings.User,
+			Password: settings.Password,
+			Address:  db.ParseAddress(sAddr),
+			Database: settings.Database,
+		}
 
-	if self.config.Database == "" {
-		return db.ErrMissingDatabaseName
+		// Replace original s.connURL
+		s.connURL = conn
 	}
 
-	if self.session, err = mgo.DialWithTimeout(connURL.String(), connTimeout); err != nil {
+	if s.session, err = mgo.DialWithTimeout(s.connURL.String(), connTimeout); err != nil {
 		return err
 	}
 
-	self.Use(self.config.Database)
+	s.database = s.session.DB("")
 
 	return nil
 }
 
 // Closes the current database session.
-func (self *Source) Close() error {
-	if self.session != nil {
-		self.session.Close()
+func (s *Source) Close() error {
+	if s.session != nil {
+		s.session.Close()
 	}
 	return nil
 }
 
 // Changes the active database.
-func (self *Source) Use(database string) error {
-	self.config.Database = database
-	self.name = database
-	self.database = self.session.DB(self.config.Database)
-	return nil
-}
+func (s *Source) Use(database string) (err error) {
+	var conn ConnectionURL
 
-// Starts a transaction block.
-func (self *Source) Begin() error {
-	// TODO:
-	// MongoDB does not supports something like BEGIN and END statements.
-	return nil
-}
+	if conn, err = ParseURL(s.connURL.String()); err != nil {
+		return err
+	}
 
-// Ends a transaction block.
-func (self *Source) End() error {
-	// TODO:
-	// MongoDB does not supports something like BEGIN and END statements.
-	return nil
+	conn.Database = database
+
+	s.connURL = conn
+
+	return s.Open()
 }
 
 // Drops the currently active database.
-func (self *Source) Drop() error {
-	err := self.database.DropDatabase()
+func (s *Source) Drop() error {
+	err := s.database.DropDatabase()
 	return err
 }
 
 // Returns a slice of non-system collection names within the active
 // database.
-func (self *Source) Collections() (cols []string, err error) {
+func (s *Source) Collections() (cols []string, err error) {
 	var rawcols []string
 	var col string
 
-	if rawcols, err = self.database.CollectionNames(); err != nil {
+	if rawcols, err = s.database.CollectionNames(); err != nil {
 		return nil, err
 	}
 
@@ -190,7 +182,7 @@ func (self *Source) Collections() (cols []string, err error) {
 }
 
 // Returns a collection instance by name.
-func (self *Source) Collection(names ...string) (db.Collection, error) {
+func (s *Source) Collection(names ...string) (db.Collection, error) {
 	var err error
 
 	if len(names) > 1 {
@@ -200,8 +192,8 @@ func (self *Source) Collection(names ...string) (db.Collection, error) {
 	name := names[0]
 
 	col := &Collection{}
-	col.parent = self
-	col.collection = self.database.C(name)
+	col.parent = s
+	col.collection = s.database.C(name)
 
 	if col.Exists() == false {
 		err = db.ErrCollectionDoesNotExist
diff --git a/mongo/database_test.go b/mongo/database_test.go
index 2c22eb0c..5b6e9b5b 100644
--- a/mongo/database_test.go
+++ b/mongo/database_test.go
@@ -1,29 +1,29 @@
-/*
-  Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
+// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
 // Tests for the mongodb adapter.
 package mongo
 
 import (
+	"flag"
 	"math/rand"
 	"os"
 	"reflect"
@@ -39,18 +39,20 @@ import (
 
 // Wrapper settings.
 const (
-	host   = "testserver.local"
-	dbname = "upperio_tests"
+	database = "upperio_tests"
+	username = "upperio"
+	password = "upperio"
 )
 
 // Global settings for tests.
-var settings = db.Settings{
-	Host:     host,
-	Database: dbname,
-	User:     "upperio",
-	Password: "upperio",
+var settings = ConnectionURL{
+	Database: database,
+	User:     username,
+	Password: password,
 }
 
+var host = flag.String("host", "testserver.local", "Testing server address.")
+
 // Structure for testing conversions and datatypes.
 type testValuesStruct struct {
 	Uint   uint   `bson:"_uint"`
@@ -93,6 +95,9 @@ func init() {
 		&t,
 		time.Second * time.Duration(7331),
 	}
+
+	flag.Parse()
+	settings.Address = db.ParseAddress(*host)
 }
 
 // Enabling outputting some information to stdout, useful for development.
@@ -111,6 +116,102 @@ func TestOpenFailed(t *testing.T) {
 }
 */
 
+// Attempts to open an empty datasource.
+func TestOpenWithWrongData(t *testing.T) {
+	var err error
+	var rightSettings, wrongSettings db.Settings
+
+	// Attempt to open with safe settings.
+	rightSettings = db.Settings{
+		Database: database,
+		Host:     *host,
+		User:     username,
+		Password: password,
+	}
+
+	// Attempt to open an empty database.
+	if _, err = db.Open(Adapter, rightSettings); err != nil {
+		// Must fail.
+		t.Fatal(err)
+	}
+
+	// Attempt to open with wrong password.
+	wrongSettings = db.Settings{
+		Database: database,
+		Host:     *host,
+		User:     username,
+		Password: "fail",
+	}
+
+	if _, err = db.Open(Adapter, wrongSettings); err == nil {
+		t.Fatalf("Expecting an error.")
+	}
+
+	// Attempt to open with wrong database.
+	wrongSettings = db.Settings{
+		Database: "fail",
+		Host:     *host,
+		User:     username,
+		Password: password,
+	}
+
+	if _, err = db.Open(Adapter, wrongSettings); err == nil {
+		t.Fatalf("Expecting an error.")
+	}
+
+	// Attempt to open with wrong username.
+	wrongSettings = db.Settings{
+		Database: database,
+		Host:     *host,
+		User:     "fail",
+		Password: password,
+	}
+
+	if _, err = db.Open(Adapter, wrongSettings); err == nil {
+		t.Fatalf("Expecting an error.")
+	}
+}
+
+// Old settings must be compatible.
+func TestOldSettings(t *testing.T) {
+	var err error
+	var sess db.Database
+
+	oldSettings := db.Settings{
+		Database: database,
+		User:     username,
+		Password: password,
+		Host:     settings.Address.String(),
+	}
+
+	// Opening database.
+	if sess, err = db.Open(Adapter, oldSettings); err != nil {
+		t.Fatal(err)
+	}
+
+	// Closing database.
+	sess.Close()
+}
+
+// Test USE
+func TestUse(t *testing.T) {
+	var err error
+	var sess db.Database
+
+	// Opening database, no error expected.
+	if sess, err = db.Open(Adapter, settings); err != nil {
+		t.Fatal(err)
+	}
+
+	// Connecting to another database, error expected.
+	if err = sess.Use("."); err == nil {
+		t.Fatal("This is not a database")
+	}
+
+	// Closing connection.
+	sess.Close()
+}
+
 // Truncates all collections.
 func TestTruncate(t *testing.T) {
 
@@ -768,7 +869,7 @@ func BenchmarkAppendRaw(b *testing.B) {
 
 	driver := sess.Driver().(*mgo.Session)
 
-	mgodb := driver.DB(dbname)
+	mgodb := driver.DB(database)
 	col := mgodb.C("artist")
 
 	b.ResetTimer()
-- 
GitLab