16
// DBServer controls a MongoDB server process to be used within test suites.
18
// The test server is started when Session is called the first time and should
19
// remain running for the duration of all tests, with the Wipe method being
20
// called between tests (before each of them) to clear stored data. After all tests
21
// are done, the Stop method should be called to stop the test server.
23
// Before the DBServer is used the SetPath method must be called to define
24
// the location for the database files to be stored.
25
type DBServer struct {
34
// SetPath defines the path to the directory where the database files will be
35
// stored if it is started. The directory path itself is not created or removed
36
// by the test helper.
37
func (dbs *DBServer) SetPath(dbpath string) {
41
func (dbs *DBServer) start() {
42
if dbs.server != nil {
43
panic("DBServer already started")
46
panic("DBServer.SetPath must be called before using the server")
49
l, err := net.Listen("tcp", "127.0.0.1:0")
51
panic("unable to listen on a local address: " + err.Error())
53
addr := l.Addr().(*net.TCPAddr)
55
dbs.host = addr.String()
58
"--dbpath", dbs.dbpath,
59
"--bind_ip", "127.0.0.1",
60
"--port", strconv.Itoa(addr.Port),
66
dbs.tomb = tomb.Tomb{}
67
dbs.server = exec.Command("mongod", args...)
68
dbs.server.Stdout = &dbs.output
69
dbs.server.Stderr = &dbs.output
70
err = dbs.server.Start()
74
dbs.tomb.Go(dbs.monitor)
78
func (dbs *DBServer) monitor() error {
79
dbs.server.Process.Wait()
81
// Present some debugging information.
82
fmt.Fprintf(os.Stderr, "---- mongod process died unexpectedly:\n")
83
fmt.Fprintf(os.Stderr, "%s", dbs.output.Bytes())
84
fmt.Fprintf(os.Stderr, "---- mongod processes running right now:\n")
85
cmd := exec.Command("/bin/sh", "-c", "ps auxw | grep mongod")
86
cmd.Stdout = os.Stderr
87
cmd.Stderr = os.Stderr
89
fmt.Fprintf(os.Stderr, "----------------------------------------\n")
91
panic("mongod process died unexpectedly")
96
// Stop stops the test server process, if it is running.
98
// It's okay to call Stop multiple times. After the test server is
99
// stopped it cannot be restarted.
101
// All database sessions must be closed before or while the Stop method
102
// is running. Otherwise Stop will panic after a timeout informing that
103
// there is a session leak.
104
func (dbs *DBServer) Stop() {
105
if dbs.session != nil {
107
if dbs.session != nil {
112
if dbs.server != nil {
114
dbs.server.Process.Signal(os.Interrupt)
116
case <-dbs.tomb.Dead():
117
case <-time.After(5 * time.Second):
118
panic("timeout waiting for mongod process to die")
124
// Session returns a new session to the server. The returned session
125
// must be closed after the test is done with it.
127
// The first Session obtained from a DBServer will start it.
128
func (dbs *DBServer) Session() *mgo.Session {
129
if dbs.server == nil {
132
if dbs.session == nil {
135
dbs.session, err = mgo.Dial(dbs.host + "/test")
140
return dbs.session.Copy()
143
// checkSessions ensures all mgo sessions opened were properly closed.
144
// For slightly faster tests, it may be disabled setting the
145
// environmnet variable CHECK_SESSIONS to 0.
146
func (dbs *DBServer) checkSessions() {
147
if check := os.Getenv("CHECK_SESSIONS"); check == "0" || dbs.server == nil || dbs.session == nil {
152
for i := 0; i < 100; i++ {
153
stats := mgo.GetStats()
154
if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
157
time.Sleep(100 * time.Millisecond)
159
panic("There are mgo sessions still alive.")
162
// Wipe drops all created databases and their data.
164
// The MongoDB server remains running if it was prevoiusly running,
165
// or stopped if it was previously stopped.
167
// All database sessions must be closed before or while the Wipe method
168
// is running. Otherwise Wipe will panic after a timeout informing that
169
// there is a session leak.
170
func (dbs *DBServer) Wipe() {
171
if dbs.server == nil || dbs.session == nil {
175
sessionUnset := dbs.session == nil
176
session := dbs.Session()
177
defer session.Close()
182
names, err := session.DatabaseNames()
186
for _, name := range names {
188
case "admin", "local", "config":
190
err = session.DB(name).DropDatabase()