github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/cluster_test.go (about)

     1  // mgo - MongoDB driver for Go
     2  //
     3  // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
     4  //
     5  // All rights reserved.
     6  //
     7  // Redistribution and use in source and binary forms, with or without
     8  // modification, are permitted provided that the following conditions are met:
     9  //
    10  // 1. Redistributions of source code must retain the above copyright notice, this
    11  //    list of conditions and the following disclaimer.
    12  // 2. Redistributions in binary form must reproduce the above copyright notice,
    13  //    this list of conditions and the following disclaimer in the documentation
    14  //    and/or other materials provided with the distribution.
    15  //
    16  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    17  // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    18  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    19  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    20  // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    21  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    22  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    23  // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    24  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    25  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    26  
    27  package mgo_test
    28  
    29  import (
    30  	"camlistore.org/third_party/labix.org/v2/mgo"
    31  	"camlistore.org/third_party/labix.org/v2/mgo/bson"
    32  	. "camlistore.org/third_party/launchpad.net/gocheck"
    33  	"fmt"
    34  	"io"
    35  	"net"
    36  	"strings"
    37  	"sync"
    38  	"time"
    39  )
    40  
    41  func (s *S) TestNewSession(c *C) {
    42  	session, err := mgo.Dial("localhost:40001")
    43  	c.Assert(err, IsNil)
    44  	defer session.Close()
    45  
    46  	// Do a dummy operation to wait for connection.
    47  	coll := session.DB("mydb").C("mycoll")
    48  	err = coll.Insert(M{"_id": 1})
    49  	c.Assert(err, IsNil)
    50  
    51  	// Tweak safety and query settings to ensure other has copied those.
    52  	session.SetSafe(nil)
    53  	session.SetBatch(-1)
    54  	other := session.New()
    55  	defer other.Close()
    56  	session.SetSafe(&mgo.Safe{})
    57  
    58  	// Clone was copied while session was unsafe, so no errors.
    59  	otherColl := other.DB("mydb").C("mycoll")
    60  	err = otherColl.Insert(M{"_id": 1})
    61  	c.Assert(err, IsNil)
    62  
    63  	// Original session was made safe again.
    64  	err = coll.Insert(M{"_id": 1})
    65  	c.Assert(err, NotNil)
    66  
    67  	// With New(), each session has its own socket now.
    68  	stats := mgo.GetStats()
    69  	c.Assert(stats.MasterConns, Equals, 2)
    70  	c.Assert(stats.SocketsInUse, Equals, 2)
    71  
    72  	// Ensure query parameters were cloned.
    73  	err = otherColl.Insert(M{"_id": 2})
    74  	c.Assert(err, IsNil)
    75  
    76  	// Ping the database to ensure the nonce has been received already.
    77  	c.Assert(other.Ping(), IsNil)
    78  
    79  	mgo.ResetStats()
    80  
    81  	iter := otherColl.Find(M{}).Iter()
    82  	c.Assert(err, IsNil)
    83  
    84  	m := M{}
    85  	ok := iter.Next(m)
    86  	c.Assert(ok, Equals, true)
    87  	err = iter.Close()
    88  	c.Assert(err, IsNil)
    89  
    90  	// If Batch(-1) is in effect, a single document must have been received.
    91  	stats = mgo.GetStats()
    92  	c.Assert(stats.ReceivedDocs, Equals, 1)
    93  }
    94  
    95  func (s *S) TestCloneSession(c *C) {
    96  	session, err := mgo.Dial("localhost:40001")
    97  	c.Assert(err, IsNil)
    98  	defer session.Close()
    99  
   100  	// Do a dummy operation to wait for connection.
   101  	coll := session.DB("mydb").C("mycoll")
   102  	err = coll.Insert(M{"_id": 1})
   103  	c.Assert(err, IsNil)
   104  
   105  	// Tweak safety and query settings to ensure clone is copying those.
   106  	session.SetSafe(nil)
   107  	session.SetBatch(-1)
   108  	clone := session.Clone()
   109  	defer clone.Close()
   110  	session.SetSafe(&mgo.Safe{})
   111  
   112  	// Clone was copied while session was unsafe, so no errors.
   113  	cloneColl := clone.DB("mydb").C("mycoll")
   114  	err = cloneColl.Insert(M{"_id": 1})
   115  	c.Assert(err, IsNil)
   116  
   117  	// Original session was made safe again.
   118  	err = coll.Insert(M{"_id": 1})
   119  	c.Assert(err, NotNil)
   120  
   121  	// With Clone(), same socket is shared between sessions now.
   122  	stats := mgo.GetStats()
   123  	c.Assert(stats.SocketsInUse, Equals, 1)
   124  	c.Assert(stats.SocketRefs, Equals, 2)
   125  
   126  	// Refreshing one of them should let the original socket go,
   127  	// while preserving the safety settings.
   128  	clone.Refresh()
   129  	err = cloneColl.Insert(M{"_id": 1})
   130  	c.Assert(err, IsNil)
   131  
   132  	// Must have used another connection now.
   133  	stats = mgo.GetStats()
   134  	c.Assert(stats.SocketsInUse, Equals, 2)
   135  	c.Assert(stats.SocketRefs, Equals, 2)
   136  
   137  	// Ensure query parameters were cloned.
   138  	err = cloneColl.Insert(M{"_id": 2})
   139  	c.Assert(err, IsNil)
   140  
   141  	// Ping the database to ensure the nonce has been received already.
   142  	c.Assert(clone.Ping(), IsNil)
   143  
   144  	mgo.ResetStats()
   145  
   146  	iter := cloneColl.Find(M{}).Iter()
   147  	c.Assert(err, IsNil)
   148  
   149  	m := M{}
   150  	ok := iter.Next(m)
   151  	c.Assert(ok, Equals, true)
   152  	err = iter.Close()
   153  	c.Assert(err, IsNil)
   154  
   155  	// If Batch(-1) is in effect, a single document must have been received.
   156  	stats = mgo.GetStats()
   157  	c.Assert(stats.ReceivedDocs, Equals, 1)
   158  }
   159  
   160  func (s *S) TestSetModeStrong(c *C) {
   161  	session, err := mgo.Dial("localhost:40012")
   162  	c.Assert(err, IsNil)
   163  	defer session.Close()
   164  
   165  	session.SetMode(mgo.Monotonic, false)
   166  	session.SetMode(mgo.Strong, false)
   167  
   168  	c.Assert(session.Mode(), Equals, mgo.Strong)
   169  
   170  	result := M{}
   171  	cmd := session.DB("admin").C("$cmd")
   172  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   173  	c.Assert(err, IsNil)
   174  	c.Assert(result["ismaster"], Equals, true)
   175  
   176  	coll := session.DB("mydb").C("mycoll")
   177  	err = coll.Insert(M{"a": 1})
   178  	c.Assert(err, IsNil)
   179  
   180  	// Wait since the sync also uses sockets.
   181  	for len(session.LiveServers()) != 3 {
   182  		c.Log("Waiting for cluster sync to finish...")
   183  		time.Sleep(5e8)
   184  	}
   185  
   186  	stats := mgo.GetStats()
   187  	c.Assert(stats.MasterConns, Equals, 1)
   188  	c.Assert(stats.SlaveConns, Equals, 2)
   189  	c.Assert(stats.SocketsInUse, Equals, 1)
   190  
   191  	session.SetMode(mgo.Strong, true)
   192  
   193  	stats = mgo.GetStats()
   194  	c.Assert(stats.SocketsInUse, Equals, 0)
   195  }
   196  
   197  func (s *S) TestSetModeMonotonic(c *C) {
   198  	// Must necessarily connect to a slave, otherwise the
   199  	// master connection will be available first.
   200  	session, err := mgo.Dial("localhost:40012")
   201  	c.Assert(err, IsNil)
   202  	defer session.Close()
   203  
   204  	session.SetMode(mgo.Monotonic, false)
   205  
   206  	c.Assert(session.Mode(), Equals, mgo.Monotonic)
   207  
   208  	result := M{}
   209  	cmd := session.DB("admin").C("$cmd")
   210  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   211  	c.Assert(err, IsNil)
   212  	c.Assert(result["ismaster"], Equals, false)
   213  
   214  	coll := session.DB("mydb").C("mycoll")
   215  	err = coll.Insert(M{"a": 1})
   216  	c.Assert(err, IsNil)
   217  
   218  	result = M{}
   219  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   220  	c.Assert(err, IsNil)
   221  	c.Assert(result["ismaster"], Equals, true)
   222  
   223  	// Wait since the sync also uses sockets.
   224  	for len(session.LiveServers()) != 3 {
   225  		c.Log("Waiting for cluster sync to finish...")
   226  		time.Sleep(5e8)
   227  	}
   228  
   229  	stats := mgo.GetStats()
   230  	c.Assert(stats.MasterConns, Equals, 1)
   231  	c.Assert(stats.SlaveConns, Equals, 2)
   232  	c.Assert(stats.SocketsInUse, Equals, 2)
   233  
   234  	session.SetMode(mgo.Monotonic, true)
   235  
   236  	stats = mgo.GetStats()
   237  	c.Assert(stats.SocketsInUse, Equals, 0)
   238  }
   239  
   240  func (s *S) TestSetModeMonotonicAfterStrong(c *C) {
   241  	// Test that a strong session shifting to a monotonic
   242  	// one preserves the socket untouched.
   243  
   244  	session, err := mgo.Dial("localhost:40012")
   245  	c.Assert(err, IsNil)
   246  	defer session.Close()
   247  
   248  	// Insert something to force a connection to the master.
   249  	coll := session.DB("mydb").C("mycoll")
   250  	err = coll.Insert(M{"a": 1})
   251  	c.Assert(err, IsNil)
   252  
   253  	session.SetMode(mgo.Monotonic, false)
   254  
   255  	// Wait since the sync also uses sockets.
   256  	for len(session.LiveServers()) != 3 {
   257  		c.Log("Waiting for cluster sync to finish...")
   258  		time.Sleep(5e8)
   259  	}
   260  
   261  	// Master socket should still be reserved.
   262  	stats := mgo.GetStats()
   263  	c.Assert(stats.SocketsInUse, Equals, 1)
   264  
   265  	// Confirm it's the master even though it's Monotonic by now.
   266  	result := M{}
   267  	cmd := session.DB("admin").C("$cmd")
   268  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   269  	c.Assert(err, IsNil)
   270  	c.Assert(result["ismaster"], Equals, true)
   271  }
   272  
   273  func (s *S) TestSetModeStrongAfterMonotonic(c *C) {
   274  	// Test that shifting from Monotonic to Strong while
   275  	// using a slave socket will keep the socket reserved
   276  	// until the master socket is necessary, so that no
   277  	// switch over occurs unless it's actually necessary.
   278  
   279  	// Must necessarily connect to a slave, otherwise the
   280  	// master connection will be available first.
   281  	session, err := mgo.Dial("localhost:40012")
   282  	c.Assert(err, IsNil)
   283  	defer session.Close()
   284  
   285  	session.SetMode(mgo.Monotonic, false)
   286  
   287  	// Ensure we're talking to a slave, and reserve the socket.
   288  	result := M{}
   289  	err = session.Run("ismaster", &result)
   290  	c.Assert(err, IsNil)
   291  	c.Assert(result["ismaster"], Equals, false)
   292  
   293  	// Switch to a Strong session.
   294  	session.SetMode(mgo.Strong, false)
   295  
   296  	// Wait since the sync also uses sockets.
   297  	for len(session.LiveServers()) != 3 {
   298  		c.Log("Waiting for cluster sync to finish...")
   299  		time.Sleep(5e8)
   300  	}
   301  
   302  	// Slave socket should still be reserved.
   303  	stats := mgo.GetStats()
   304  	c.Assert(stats.SocketsInUse, Equals, 1)
   305  
   306  	// But any operation will switch it to the master.
   307  	result = M{}
   308  	err = session.Run("ismaster", &result)
   309  	c.Assert(err, IsNil)
   310  	c.Assert(result["ismaster"], Equals, true)
   311  }
   312  
   313  func (s *S) TestSetModeMonotonicWriteOnIteration(c *C) {
   314  	// Must necessarily connect to a slave, otherwise the
   315  	// master connection will be available first.
   316  	session, err := mgo.Dial("localhost:40012")
   317  	c.Assert(err, IsNil)
   318  	defer session.Close()
   319  
   320  	session.SetMode(mgo.Monotonic, false)
   321  
   322  	c.Assert(session.Mode(), Equals, mgo.Monotonic)
   323  
   324  	coll1 := session.DB("mydb").C("mycoll1")
   325  	coll2 := session.DB("mydb").C("mycoll2")
   326  
   327  	ns := []int{40, 41, 42, 43, 44, 45, 46}
   328  	for _, n := range ns {
   329  		err := coll1.Insert(M{"n": n})
   330  		c.Assert(err, IsNil)
   331  	}
   332  
   333  	// Release master so we can grab a slave again.
   334  	session.Refresh()
   335  
   336  	// Wait until synchronization is done.
   337  	for {
   338  		n, err := coll1.Count()
   339  		c.Assert(err, IsNil)
   340  		if n == len(ns) {
   341  			break
   342  		}
   343  	}
   344  
   345  	iter := coll1.Find(nil).Batch(2).Iter()
   346  	i := 0
   347  	m := M{}
   348  	for iter.Next(&m) {
   349  		i++
   350  		if i > 3 {
   351  			err := coll2.Insert(M{"n": 47 + i})
   352  			c.Assert(err, IsNil)
   353  		}
   354  	}
   355  	c.Assert(i, Equals, len(ns))
   356  }
   357  
   358  func (s *S) TestSetModeEventual(c *C) {
   359  	// Must necessarily connect to a slave, otherwise the
   360  	// master connection will be available first.
   361  	session, err := mgo.Dial("localhost:40012")
   362  	c.Assert(err, IsNil)
   363  	defer session.Close()
   364  
   365  	session.SetMode(mgo.Eventual, false)
   366  
   367  	c.Assert(session.Mode(), Equals, mgo.Eventual)
   368  
   369  	result := M{}
   370  	err = session.Run("ismaster", &result)
   371  	c.Assert(err, IsNil)
   372  	c.Assert(result["ismaster"], Equals, false)
   373  
   374  	coll := session.DB("mydb").C("mycoll")
   375  	err = coll.Insert(M{"a": 1})
   376  	c.Assert(err, IsNil)
   377  
   378  	result = M{}
   379  	err = session.Run("ismaster", &result)
   380  	c.Assert(err, IsNil)
   381  	c.Assert(result["ismaster"], Equals, false)
   382  
   383  	// Wait since the sync also uses sockets.
   384  	for len(session.LiveServers()) != 3 {
   385  		c.Log("Waiting for cluster sync to finish...")
   386  		time.Sleep(5e8)
   387  	}
   388  
   389  	stats := mgo.GetStats()
   390  	c.Assert(stats.MasterConns, Equals, 1)
   391  	c.Assert(stats.SlaveConns, Equals, 2)
   392  	c.Assert(stats.SocketsInUse, Equals, 0)
   393  }
   394  
   395  func (s *S) TestSetModeEventualAfterStrong(c *C) {
   396  	// Test that a strong session shifting to an eventual
   397  	// one preserves the socket untouched.
   398  
   399  	session, err := mgo.Dial("localhost:40012")
   400  	c.Assert(err, IsNil)
   401  	defer session.Close()
   402  
   403  	// Insert something to force a connection to the master.
   404  	coll := session.DB("mydb").C("mycoll")
   405  	err = coll.Insert(M{"a": 1})
   406  	c.Assert(err, IsNil)
   407  
   408  	session.SetMode(mgo.Eventual, false)
   409  
   410  	// Wait since the sync also uses sockets.
   411  	for len(session.LiveServers()) != 3 {
   412  		c.Log("Waiting for cluster sync to finish...")
   413  		time.Sleep(5e8)
   414  	}
   415  
   416  	// Master socket should still be reserved.
   417  	stats := mgo.GetStats()
   418  	c.Assert(stats.SocketsInUse, Equals, 1)
   419  
   420  	// Confirm it's the master even though it's Eventual by now.
   421  	result := M{}
   422  	cmd := session.DB("admin").C("$cmd")
   423  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   424  	c.Assert(err, IsNil)
   425  	c.Assert(result["ismaster"], Equals, true)
   426  
   427  	session.SetMode(mgo.Eventual, true)
   428  
   429  	stats = mgo.GetStats()
   430  	c.Assert(stats.SocketsInUse, Equals, 0)
   431  }
   432  
   433  func (s *S) TestPrimaryShutdownStrong(c *C) {
   434  	if *fast {
   435  		c.Skip("-fast")
   436  	}
   437  
   438  	session, err := mgo.Dial("localhost:40021")
   439  	c.Assert(err, IsNil)
   440  	defer session.Close()
   441  
   442  	// With strong consistency, this will open a socket to the master.
   443  	result := &struct{ Host string }{}
   444  	err = session.Run("serverStatus", result)
   445  	c.Assert(err, IsNil)
   446  
   447  	// Kill the master.
   448  	host := result.Host
   449  	s.Stop(host)
   450  
   451  	// This must fail, since the connection was broken.
   452  	err = session.Run("serverStatus", result)
   453  	c.Assert(err, Equals, io.EOF)
   454  
   455  	// With strong consistency, it fails again until reset.
   456  	err = session.Run("serverStatus", result)
   457  	c.Assert(err, Equals, io.EOF)
   458  
   459  	session.Refresh()
   460  
   461  	// Now we should be able to talk to the new master.
   462  	// Increase the timeout since this may take quite a while.
   463  	session.SetSyncTimeout(3 * time.Minute)
   464  
   465  	err = session.Run("serverStatus", result)
   466  	c.Assert(err, IsNil)
   467  	c.Assert(result.Host, Not(Equals), host)
   468  
   469  	// Insert some data to confirm it's indeed a master.
   470  	err = session.DB("mydb").C("mycoll").Insert(M{"n": 42})
   471  	c.Assert(err, IsNil)
   472  }
   473  
   474  func (s *S) TestPrimaryHiccup(c *C) {
   475  	if *fast {
   476  		c.Skip("-fast")
   477  	}
   478  
   479  	session, err := mgo.Dial("localhost:40021")
   480  	c.Assert(err, IsNil)
   481  	defer session.Close()
   482  
   483  	// With strong consistency, this will open a socket to the master.
   484  	result := &struct{ Host string }{}
   485  	err = session.Run("serverStatus", result)
   486  	c.Assert(err, IsNil)
   487  
   488  	// Establish a few extra sessions to create spare sockets to
   489  	// the master. This increases a bit the chances of getting an
   490  	// incorrect cached socket.
   491  	var sessions []*mgo.Session
   492  	for i := 0; i < 20; i++ {
   493  		sessions = append(sessions, session.Copy())
   494  		err = sessions[len(sessions)-1].Run("serverStatus", result)
   495  		c.Assert(err, IsNil)
   496  	}
   497  	for i := range sessions {
   498  		sessions[i].Close()
   499  	}
   500  
   501  	// Kill the master, but bring it back immediatelly.
   502  	host := result.Host
   503  	s.Stop(host)
   504  	s.StartAll()
   505  
   506  	// This must fail, since the connection was broken.
   507  	err = session.Run("serverStatus", result)
   508  	c.Assert(err, Equals, io.EOF)
   509  
   510  	// With strong consistency, it fails again until reset.
   511  	err = session.Run("serverStatus", result)
   512  	c.Assert(err, Equals, io.EOF)
   513  
   514  	session.Refresh()
   515  
   516  	// Now we should be able to talk to the new master.
   517  	// Increase the timeout since this may take quite a while.
   518  	session.SetSyncTimeout(3 * time.Minute)
   519  
   520  	// Insert some data to confirm it's indeed a master.
   521  	err = session.DB("mydb").C("mycoll").Insert(M{"n": 42})
   522  	c.Assert(err, IsNil)
   523  }
   524  
   525  func (s *S) TestPrimaryShutdownMonotonic(c *C) {
   526  	if *fast {
   527  		c.Skip("-fast")
   528  	}
   529  
   530  	session, err := mgo.Dial("localhost:40021")
   531  	c.Assert(err, IsNil)
   532  	defer session.Close()
   533  
   534  	session.SetMode(mgo.Monotonic, true)
   535  
   536  	// Insert something to force a switch to the master.
   537  	coll := session.DB("mydb").C("mycoll")
   538  	err = coll.Insert(M{"a": 1})
   539  	c.Assert(err, IsNil)
   540  
   541  	// Wait a bit for this to be synchronized to slaves.
   542  	time.Sleep(3 * time.Second)
   543  
   544  	result := &struct{ Host string }{}
   545  	err = session.Run("serverStatus", result)
   546  	c.Assert(err, IsNil)
   547  
   548  	// Kill the master.
   549  	host := result.Host
   550  	s.Stop(host)
   551  
   552  	// This must fail, since the connection was broken.
   553  	err = session.Run("serverStatus", result)
   554  	c.Assert(err, Equals, io.EOF)
   555  
   556  	// With monotonic consistency, it fails again until reset.
   557  	err = session.Run("serverStatus", result)
   558  	c.Assert(err, Equals, io.EOF)
   559  
   560  	session.Refresh()
   561  
   562  	// Now we should be able to talk to the new master.
   563  	err = session.Run("serverStatus", result)
   564  	c.Assert(err, IsNil)
   565  	c.Assert(result.Host, Not(Equals), host)
   566  }
   567  
   568  func (s *S) TestPrimaryShutdownMonotonicWithSlave(c *C) {
   569  	if *fast {
   570  		c.Skip("-fast")
   571  	}
   572  
   573  	session, err := mgo.Dial("localhost:40021")
   574  	c.Assert(err, IsNil)
   575  	defer session.Close()
   576  
   577  	ssresult := &struct{ Host string }{}
   578  	imresult := &struct{ IsMaster bool }{}
   579  
   580  	// Figure the master while still using the strong session.
   581  	err = session.Run("serverStatus", ssresult)
   582  	c.Assert(err, IsNil)
   583  	err = session.Run("isMaster", imresult)
   584  	c.Assert(err, IsNil)
   585  	master := ssresult.Host
   586  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
   587  
   588  	// Create new monotonic session with an explicit address to ensure
   589  	// a slave is synchronized before the master, otherwise a connection
   590  	// with the master may be used below for lack of other options.
   591  	var addr string
   592  	switch {
   593  	case strings.HasSuffix(ssresult.Host, ":40021"):
   594  		addr = "localhost:40022"
   595  	case strings.HasSuffix(ssresult.Host, ":40022"):
   596  		addr = "localhost:40021"
   597  	case strings.HasSuffix(ssresult.Host, ":40023"):
   598  		addr = "localhost:40021"
   599  	default:
   600  		c.Fatal("Unknown host: ", ssresult.Host)
   601  	}
   602  
   603  	session, err = mgo.Dial(addr)
   604  	c.Assert(err, IsNil)
   605  	defer session.Close()
   606  
   607  	session.SetMode(mgo.Monotonic, true)
   608  
   609  	// Check the address of the socket associated with the monotonic session.
   610  	c.Log("Running serverStatus and isMaster with monotonic session")
   611  	err = session.Run("serverStatus", ssresult)
   612  	c.Assert(err, IsNil)
   613  	err = session.Run("isMaster", imresult)
   614  	c.Assert(err, IsNil)
   615  	slave := ssresult.Host
   616  	c.Assert(imresult.IsMaster, Equals, false, Commentf("%s is not a slave", slave))
   617  
   618  	c.Assert(master, Not(Equals), slave)
   619  
   620  	// Kill the master.
   621  	s.Stop(master)
   622  
   623  	// Session must still be good, since we were talking to a slave.
   624  	err = session.Run("serverStatus", ssresult)
   625  	c.Assert(err, IsNil)
   626  
   627  	c.Assert(ssresult.Host, Equals, slave,
   628  		Commentf("Monotonic session moved from %s to %s", slave, ssresult.Host))
   629  
   630  	// If we try to insert something, it'll have to hold until the new
   631  	// master is available to move the connection, and work correctly.
   632  	coll := session.DB("mydb").C("mycoll")
   633  	err = coll.Insert(M{"a": 1})
   634  	c.Assert(err, IsNil)
   635  
   636  	// Must now be talking to the new master.
   637  	err = session.Run("serverStatus", ssresult)
   638  	c.Assert(err, IsNil)
   639  	err = session.Run("isMaster", imresult)
   640  	c.Assert(err, IsNil)
   641  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
   642  
   643  	// ... which is not the old one, since it's still dead.
   644  	c.Assert(ssresult.Host, Not(Equals), master)
   645  }
   646  
   647  func (s *S) TestPrimaryShutdownEventual(c *C) {
   648  	if *fast {
   649  		c.Skip("-fast")
   650  	}
   651  
   652  	session, err := mgo.Dial("localhost:40021")
   653  	c.Assert(err, IsNil)
   654  	defer session.Close()
   655  
   656  	result := &struct{ Host string }{}
   657  	err = session.Run("serverStatus", result)
   658  	c.Assert(err, IsNil)
   659  	master := result.Host
   660  
   661  	session.SetMode(mgo.Eventual, true)
   662  
   663  	// Should connect to the master when needed.
   664  	coll := session.DB("mydb").C("mycoll")
   665  	err = coll.Insert(M{"a": 1})
   666  	c.Assert(err, IsNil)
   667  
   668  	// Wait a bit for this to be synchronized to slaves.
   669  	time.Sleep(3 * time.Second)
   670  
   671  	// Kill the master.
   672  	s.Stop(master)
   673  
   674  	// Should still work, with the new master now.
   675  	coll = session.DB("mydb").C("mycoll")
   676  	err = coll.Insert(M{"a": 1})
   677  	c.Assert(err, IsNil)
   678  
   679  	err = session.Run("serverStatus", result)
   680  	c.Assert(err, IsNil)
   681  	c.Assert(result.Host, Not(Equals), master)
   682  }
   683  
   684  func (s *S) TestPreserveSocketCountOnSync(c *C) {
   685  	if *fast {
   686  		c.Skip("-fast")
   687  	}
   688  
   689  	session, err := mgo.Dial("localhost:40011")
   690  	c.Assert(err, IsNil)
   691  	defer session.Close()
   692  
   693  	stats := mgo.GetStats()
   694  	for stats.MasterConns+stats.SlaveConns != 3 {
   695  		stats = mgo.GetStats()
   696  		c.Log("Waiting for all connections to be established...")
   697  		time.Sleep(5e8)
   698  	}
   699  
   700  	c.Assert(stats.SocketsAlive, Equals, 3)
   701  
   702  	// Kill the master (with rs1, 'a' is always the master).
   703  	s.Stop("localhost:40011")
   704  
   705  	// Wait for the logic to run for a bit and bring it back.
   706  	go func() {
   707  		time.Sleep(5e9)
   708  		s.StartAll()
   709  	}()
   710  
   711  	// Do an action to kick the resync logic in, and also to
   712  	// wait until the cluster recognizes the server is back.
   713  	result := struct{ Ok bool }{}
   714  	err = session.Run("getLastError", &result)
   715  	c.Assert(err, IsNil)
   716  	c.Assert(result.Ok, Equals, true)
   717  
   718  	for i := 0; i != 20; i++ {
   719  		stats = mgo.GetStats()
   720  		if stats.SocketsAlive == 3 {
   721  			break
   722  		}
   723  		c.Logf("Waiting for 3 sockets alive, have %d", stats.SocketsAlive)
   724  		time.Sleep(5e8)
   725  	}
   726  
   727  	// Ensure the number of sockets is preserved after syncing.
   728  	stats = mgo.GetStats()
   729  	c.Assert(stats.SocketsAlive, Equals, 3)
   730  	c.Assert(stats.SocketsInUse, Equals, 1)
   731  	c.Assert(stats.SocketRefs, Equals, 1)
   732  }
   733  
   734  // Connect to the master of a deployment with a single server,
   735  // run an insert, and then ensure the insert worked and that a
   736  // single connection was established.
   737  func (s *S) TestTopologySyncWithSingleMaster(c *C) {
   738  	// Use hostname here rather than IP, to make things trickier.
   739  	session, err := mgo.Dial("localhost:40001")
   740  	c.Assert(err, IsNil)
   741  	defer session.Close()
   742  
   743  	coll := session.DB("mydb").C("mycoll")
   744  	err = coll.Insert(M{"a": 1, "b": 2})
   745  	c.Assert(err, IsNil)
   746  
   747  	// One connection used for discovery. Master socket recycled for
   748  	// insert. Socket is reserved after insert.
   749  	stats := mgo.GetStats()
   750  	c.Assert(stats.MasterConns, Equals, 1)
   751  	c.Assert(stats.SlaveConns, Equals, 0)
   752  	c.Assert(stats.SocketsInUse, Equals, 1)
   753  
   754  	// Refresh session and socket must be released.
   755  	session.Refresh()
   756  	stats = mgo.GetStats()
   757  	c.Assert(stats.SocketsInUse, Equals, 0)
   758  }
   759  
   760  func (s *S) TestTopologySyncWithSlaveSeed(c *C) {
   761  	// That's supposed to be a slave. Must run discovery
   762  	// and find out master to insert successfully.
   763  	session, err := mgo.Dial("localhost:40012")
   764  	c.Assert(err, IsNil)
   765  	defer session.Close()
   766  
   767  	coll := session.DB("mydb").C("mycoll")
   768  	coll.Insert(M{"a": 1, "b": 2})
   769  
   770  	result := struct{ Ok bool }{}
   771  	err = session.Run("getLastError", &result)
   772  	c.Assert(err, IsNil)
   773  	c.Assert(result.Ok, Equals, true)
   774  
   775  	// One connection to each during discovery. Master
   776  	// socket recycled for insert.
   777  	stats := mgo.GetStats()
   778  	c.Assert(stats.MasterConns, Equals, 1)
   779  	c.Assert(stats.SlaveConns, Equals, 2)
   780  
   781  	// Only one socket reference alive, in the master socket owned
   782  	// by the above session.
   783  	c.Assert(stats.SocketsInUse, Equals, 1)
   784  
   785  	// Refresh it, and it must be gone.
   786  	session.Refresh()
   787  	stats = mgo.GetStats()
   788  	c.Assert(stats.SocketsInUse, Equals, 0)
   789  }
   790  
   791  func (s *S) TestSyncTimeout(c *C) {
   792  	if *fast {
   793  		c.Skip("-fast")
   794  	}
   795  
   796  	session, err := mgo.Dial("localhost:40001")
   797  	c.Assert(err, IsNil)
   798  	defer session.Close()
   799  
   800  	s.Stop("localhost:40001")
   801  
   802  	timeout := 3 * time.Second
   803  	session.SetSyncTimeout(timeout)
   804  	started := time.Now()
   805  
   806  	// Do something.
   807  	result := struct{ Ok bool }{}
   808  	err = session.Run("getLastError", &result)
   809  	c.Assert(err, ErrorMatches, "no reachable servers")
   810  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
   811  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
   812  }
   813  
   814  func (s *S) TestDialWithTimeout(c *C) {
   815  	if *fast {
   816  		c.Skip("-fast")
   817  	}
   818  
   819  	timeout := 2 * time.Second
   820  	started := time.Now()
   821  
   822  	// 40009 isn't used by the test servers.
   823  	session, err := mgo.DialWithTimeout("localhost:40009", timeout)
   824  	if session != nil {
   825  		session.Close()
   826  	}
   827  	c.Assert(err, ErrorMatches, "no reachable servers")
   828  	c.Assert(session, IsNil)
   829  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
   830  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
   831  }
   832  
   833  func (s *S) TestSocketTimeout(c *C) {
   834  	if *fast {
   835  		c.Skip("-fast")
   836  	}
   837  
   838  	session, err := mgo.Dial("localhost:40001")
   839  	c.Assert(err, IsNil)
   840  	defer session.Close()
   841  
   842  	s.Freeze("localhost:40001")
   843  
   844  	timeout := 3 * time.Second
   845  	session.SetSocketTimeout(timeout)
   846  	started := time.Now()
   847  
   848  	// Do something.
   849  	result := struct{ Ok bool }{}
   850  	err = session.Run("getLastError", &result)
   851  	c.Assert(err, ErrorMatches, ".*: i/o timeout")
   852  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
   853  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
   854  }
   855  
   856  func (s *S) TestSocketTimeoutOnDial(c *C) {
   857  	if *fast {
   858  		c.Skip("-fast")
   859  	}
   860  
   861  	timeout := 1 * time.Second
   862  
   863  	defer mgo.HackSyncSocketTimeout(timeout)()
   864  
   865  	s.Freeze("localhost:40001")
   866  
   867  	started := time.Now()
   868  
   869  	session, err := mgo.DialWithTimeout("localhost:40001", timeout)
   870  	c.Assert(err, ErrorMatches, "no reachable servers")
   871  	c.Assert(session, IsNil)
   872  
   873  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
   874  	c.Assert(started.After(time.Now().Add(-20*time.Second)), Equals, true)
   875  }
   876  
   877  func (s *S) TestSocketTimeoutOnInactiveSocket(c *C) {
   878  	if *fast {
   879  		c.Skip("-fast")
   880  	}
   881  
   882  	session, err := mgo.Dial("localhost:40001")
   883  	c.Assert(err, IsNil)
   884  	defer session.Close()
   885  
   886  	timeout := 2 * time.Second
   887  	session.SetSocketTimeout(timeout)
   888  
   889  	// Do something that relies on the timeout and works.
   890  	c.Assert(session.Ping(), IsNil)
   891  
   892  	// Freeze and wait for the timeout to go by.
   893  	s.Freeze("localhost:40001")
   894  	time.Sleep(timeout + 500*time.Millisecond)
   895  	s.Thaw("localhost:40001")
   896  
   897  	// Do something again. The timeout above should not have killed
   898  	// the socket as there was nothing to be done.
   899  	c.Assert(session.Ping(), IsNil)
   900  }
   901  
   902  func (s *S) TestDirect(c *C) {
   903  	session, err := mgo.Dial("localhost:40012?connect=direct")
   904  	c.Assert(err, IsNil)
   905  	defer session.Close()
   906  
   907  	// We know that server is a slave.
   908  	session.SetMode(mgo.Monotonic, true)
   909  
   910  	result := &struct{ Host string }{}
   911  	err = session.Run("serverStatus", result)
   912  	c.Assert(err, IsNil)
   913  	c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true)
   914  
   915  	stats := mgo.GetStats()
   916  	c.Assert(stats.SocketsAlive, Equals, 1)
   917  	c.Assert(stats.SocketsInUse, Equals, 1)
   918  	c.Assert(stats.SocketRefs, Equals, 1)
   919  
   920  	// We've got no master, so it'll timeout.
   921  	session.SetSyncTimeout(5e8 * time.Nanosecond)
   922  
   923  	coll := session.DB("mydb").C("mycoll")
   924  	err = coll.Insert(M{"test": 1})
   925  	c.Assert(err, ErrorMatches, "no reachable servers")
   926  
   927  	// Writing to the local database is okay.
   928  	coll = session.DB("local").C("mycoll")
   929  	defer coll.RemoveAll(nil)
   930  	id := bson.NewObjectId()
   931  	err = coll.Insert(M{"_id": id})
   932  	c.Assert(err, IsNil)
   933  
   934  	// Data was stored in the right server.
   935  	n, err := coll.Find(M{"_id": id}).Count()
   936  	c.Assert(err, IsNil)
   937  	c.Assert(n, Equals, 1)
   938  
   939  	// Server hasn't changed.
   940  	result.Host = ""
   941  	err = session.Run("serverStatus", result)
   942  	c.Assert(err, IsNil)
   943  	c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true)
   944  }
   945  
   946  func (s *S) TestDirectToUnknownStateMember(c *C) {
   947  	session, err := mgo.Dial("localhost:40041?connect=direct")
   948  	c.Assert(err, IsNil)
   949  	defer session.Close()
   950  
   951  	session.SetMode(mgo.Monotonic, true)
   952  
   953  	result := &struct{ Host string }{}
   954  	err = session.Run("serverStatus", result)
   955  	c.Assert(err, IsNil)
   956  	c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true)
   957  
   958  	// We've got no master, so it'll timeout.
   959  	session.SetSyncTimeout(5e8 * time.Nanosecond)
   960  
   961  	coll := session.DB("mydb").C("mycoll")
   962  	err = coll.Insert(M{"test": 1})
   963  	c.Assert(err, ErrorMatches, "no reachable servers")
   964  
   965  	// Slave is still reachable.
   966  	result.Host = ""
   967  	err = session.Run("serverStatus", result)
   968  	c.Assert(err, IsNil)
   969  	c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true)
   970  }
   971  
   972  type OpCounters struct {
   973  	Insert  int
   974  	Query   int
   975  	Update  int
   976  	Delete  int
   977  	GetMore int
   978  	Command int
   979  }
   980  
   981  func getOpCounters(server string) (c *OpCounters, err error) {
   982  	session, err := mgo.Dial(server + "?connect=direct")
   983  	if err != nil {
   984  		return nil, err
   985  	}
   986  	defer session.Close()
   987  	session.SetMode(mgo.Monotonic, true)
   988  	result := struct{ OpCounters }{}
   989  	err = session.Run("serverStatus", &result)
   990  	return &result.OpCounters, err
   991  }
   992  
   993  func (s *S) TestMonotonicSlaveOkFlagWithMongos(c *C) {
   994  	session, err := mgo.Dial("localhost:40021")
   995  	c.Assert(err, IsNil)
   996  	defer session.Close()
   997  
   998  	ssresult := &struct{ Host string }{}
   999  	imresult := &struct{ IsMaster bool }{}
  1000  
  1001  	// Figure the master while still using the strong session.
  1002  	err = session.Run("serverStatus", ssresult)
  1003  	c.Assert(err, IsNil)
  1004  	err = session.Run("isMaster", imresult)
  1005  	c.Assert(err, IsNil)
  1006  	master := ssresult.Host
  1007  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
  1008  
  1009  	// Collect op counters for everyone.
  1010  	opc21a, err := getOpCounters("localhost:40021")
  1011  	c.Assert(err, IsNil)
  1012  	opc22a, err := getOpCounters("localhost:40022")
  1013  	c.Assert(err, IsNil)
  1014  	opc23a, err := getOpCounters("localhost:40023")
  1015  	c.Assert(err, IsNil)
  1016  
  1017  	// Do a SlaveOk query through MongoS
  1018  
  1019  	mongos, err := mgo.Dial("localhost:40202")
  1020  	c.Assert(err, IsNil)
  1021  	defer mongos.Close()
  1022  
  1023  	mongos.SetMode(mgo.Monotonic, true)
  1024  
  1025  	coll := mongos.DB("mydb").C("mycoll")
  1026  	result := &struct{}{}
  1027  	for i := 0; i != 5; i++ {
  1028  		err := coll.Find(nil).One(result)
  1029  		c.Assert(err, Equals, mgo.ErrNotFound)
  1030  	}
  1031  
  1032  	// Collect op counters for everyone again.
  1033  	opc21b, err := getOpCounters("localhost:40021")
  1034  	c.Assert(err, IsNil)
  1035  	opc22b, err := getOpCounters("localhost:40022")
  1036  	c.Assert(err, IsNil)
  1037  	opc23b, err := getOpCounters("localhost:40023")
  1038  	c.Assert(err, IsNil)
  1039  
  1040  	masterPort := master[strings.Index(master, ":")+1:]
  1041  
  1042  	var masterDelta, slaveDelta int
  1043  	switch masterPort {
  1044  	case "40021":
  1045  		masterDelta = opc21b.Query - opc21a.Query
  1046  		slaveDelta = (opc22b.Query - opc22a.Query) + (opc23b.Query - opc23a.Query)
  1047  	case "40022":
  1048  		masterDelta = opc22b.Query - opc22a.Query
  1049  		slaveDelta = (opc21b.Query - opc21a.Query) + (opc23b.Query - opc23a.Query)
  1050  	case "40023":
  1051  		masterDelta = opc23b.Query - opc23a.Query
  1052  		slaveDelta = (opc21b.Query - opc21a.Query) + (opc22b.Query - opc22a.Query)
  1053  	default:
  1054  		c.Fatal("Uh?")
  1055  	}
  1056  
  1057  	c.Check(masterDelta, Equals, 0) // Just the counting itself.
  1058  	c.Check(slaveDelta, Equals, 5)  // The counting for both, plus 5 queries above.
  1059  }
  1060  
  1061  func (s *S) TestRemovalOfClusterMember(c *C) {
  1062  	if *fast {
  1063  		c.Skip("-fast")
  1064  	}
  1065  
  1066  	master, err := mgo.Dial("localhost:40021")
  1067  	c.Assert(err, IsNil)
  1068  	defer master.Close()
  1069  
  1070  	// Wait for cluster to fully sync up.
  1071  	for i := 0; i < 10; i++ {
  1072  		if len(master.LiveServers()) == 3 {
  1073  			break
  1074  		}
  1075  		time.Sleep(5e8)
  1076  	}
  1077  	if len(master.LiveServers()) != 3 {
  1078  		c.Fatalf("Test started with bad cluster state: %v", master.LiveServers())
  1079  	}
  1080  
  1081  	result := &struct {
  1082  		IsMaster bool
  1083  		Me       string
  1084  	}{}
  1085  	slave := master.Copy()
  1086  	slave.SetMode(mgo.Monotonic, true) // Monotonic can hold a non-master socket persistently.
  1087  	err = slave.Run("isMaster", result)
  1088  	c.Assert(err, IsNil)
  1089  	c.Assert(result.IsMaster, Equals, false)
  1090  	slaveAddr := result.Me
  1091  
  1092  	defer func() {
  1093  		master.Refresh()
  1094  		master.Run(bson.D{{"$eval", `rs.add("` + slaveAddr + `")`}}, nil)
  1095  		master.Close()
  1096  		slave.Close()
  1097  	}()
  1098  
  1099  	c.Logf("========== Removing slave: %s ==========", slaveAddr)
  1100  
  1101  	master.Run(bson.D{{"$eval", `rs.remove("` + slaveAddr + `")`}}, nil)
  1102  	err = master.Ping()
  1103  	c.Assert(err, Equals, io.EOF)
  1104  
  1105  	master.Refresh()
  1106  
  1107  	// Give the cluster a moment to catch up by doing a roundtrip to the master.
  1108  	err = master.Ping()
  1109  	c.Assert(err, IsNil)
  1110  
  1111  	time.Sleep(3e9)
  1112  
  1113  	// This must fail since the slave has been taken off the cluster.
  1114  	err = slave.Ping()
  1115  	c.Assert(err, NotNil)
  1116  
  1117  	for i := 0; i < 15; i++ {
  1118  		if len(master.LiveServers()) == 2 {
  1119  			break
  1120  		}
  1121  		time.Sleep(time.Second)
  1122  	}
  1123  	live := master.LiveServers()
  1124  	if len(live) != 2 {
  1125  		c.Errorf("Removed server still considered live: %#s", live)
  1126  	}
  1127  
  1128  	c.Log("========== Test succeeded. ==========")
  1129  }
  1130  
  1131  func (s *S) TestSocketLimit(c *C) {
  1132  	if *fast {
  1133  		c.Skip("-fast")
  1134  	}
  1135  	const socketLimit = 64
  1136  	restore := mgo.HackSocketsPerServer(socketLimit)
  1137  	defer restore()
  1138  
  1139  	session, err := mgo.Dial("localhost:40011")
  1140  	c.Assert(err, IsNil)
  1141  	defer session.Close()
  1142  
  1143  	stats := mgo.GetStats()
  1144  	for stats.MasterConns+stats.SlaveConns != 3 {
  1145  		stats = mgo.GetStats()
  1146  		c.Log("Waiting for all connections to be established...")
  1147  		time.Sleep(5e8)
  1148  	}
  1149  	c.Assert(stats.SocketsAlive, Equals, 3)
  1150  
  1151  	// Consume the whole limit for the master.
  1152  	var master []*mgo.Session
  1153  	for i := 0; i < socketLimit; i++ {
  1154  		s := session.Copy()
  1155  		defer s.Close()
  1156  		err := s.Ping()
  1157  		c.Assert(err, IsNil)
  1158  		master = append(master, s)
  1159  	}
  1160  
  1161  	before := time.Now()
  1162  	go func() {
  1163  		time.Sleep(3e9)
  1164  		master[0].Refresh()
  1165  	}()
  1166  
  1167  	// Now a single ping must block, since it would need another
  1168  	// connection to the master, over the limit. Once the goroutine
  1169  	// above releases its socket, it should move on.
  1170  	session.Ping()
  1171  	delay := time.Now().Sub(before)
  1172  	c.Assert(delay > 3e9, Equals, true)
  1173  	c.Assert(delay < 6e9, Equals, true)
  1174  }
  1175  
  1176  func (s *S) TestSetModeEventualIterBug(c *C) {
  1177  	session1, err := mgo.Dial("localhost:40011")
  1178  	c.Assert(err, IsNil)
  1179  	defer session1.Close()
  1180  
  1181  	session1.SetMode(mgo.Eventual, false)
  1182  
  1183  	coll1 := session1.DB("mydb").C("mycoll")
  1184  
  1185  	const N = 100
  1186  	for i := 0; i < N; i++ {
  1187  		err = coll1.Insert(M{"_id": i})
  1188  		c.Assert(err, IsNil)
  1189  	}
  1190  
  1191  	c.Logf("Waiting until secondary syncs")
  1192  	for {
  1193  		n, err := coll1.Count()
  1194  		c.Assert(err, IsNil)
  1195  		if n == N {
  1196  			c.Logf("Found all")
  1197  			break
  1198  		}
  1199  	}
  1200  
  1201  	session2, err := mgo.Dial("localhost:40011")
  1202  	c.Assert(err, IsNil)
  1203  	defer session2.Close()
  1204  
  1205  	session2.SetMode(mgo.Eventual, false)
  1206  
  1207  	coll2 := session2.DB("mydb").C("mycoll")
  1208  
  1209  	i := 0
  1210  	iter := coll2.Find(nil).Batch(10).Iter()
  1211  	var result struct{}
  1212  	for iter.Next(&result) {
  1213  		i++
  1214  	}
  1215  	c.Assert(iter.Close(), Equals, nil)
  1216  	c.Assert(i, Equals, N)
  1217  }
  1218  
  1219  func (s *S) TestCustomDialOld(c *C) {
  1220  	dials := make(chan bool, 16)
  1221  	dial := func(addr net.Addr) (net.Conn, error) {
  1222  		tcpaddr, ok := addr.(*net.TCPAddr)
  1223  		if !ok {
  1224  			return nil, fmt.Errorf("unexpected address type: %T", addr)
  1225  		}
  1226  		dials <- true
  1227  		return net.DialTCP("tcp", nil, tcpaddr)
  1228  	}
  1229  	info := mgo.DialInfo{
  1230  		Addrs: []string{"localhost:40012"},
  1231  		Dial:  dial,
  1232  	}
  1233  
  1234  	// Use hostname here rather than IP, to make things trickier.
  1235  	session, err := mgo.DialWithInfo(&info)
  1236  	c.Assert(err, IsNil)
  1237  	defer session.Close()
  1238  
  1239  	const N = 3
  1240  	for i := 0; i < N; i++ {
  1241  		select {
  1242  		case <-dials:
  1243  		case <-time.After(5 * time.Second):
  1244  			c.Fatalf("expected %d dials, got %d", N, i)
  1245  		}
  1246  	}
  1247  	select {
  1248  	case <-dials:
  1249  		c.Fatalf("got more dials than expected")
  1250  	case <-time.After(100 * time.Millisecond):
  1251  	}
  1252  }
  1253  
  1254  func (s *S) TestCustomDialNew(c *C) {
  1255  	dials := make(chan bool, 16)
  1256  	dial := func(addr *mgo.ServerAddr) (net.Conn, error) {
  1257  		dials <- true
  1258  		if addr.TCPAddr().Port == 40012 {
  1259  			c.Check(addr.String(), Equals, "localhost:40012")
  1260  		}
  1261  		return net.DialTCP("tcp", nil, addr.TCPAddr())
  1262  	}
  1263  	info := mgo.DialInfo{
  1264  		Addrs:      []string{"localhost:40012"},
  1265  		DialServer: dial,
  1266  	}
  1267  
  1268  	// Use hostname here rather than IP, to make things trickier.
  1269  	session, err := mgo.DialWithInfo(&info)
  1270  	c.Assert(err, IsNil)
  1271  	defer session.Close()
  1272  
  1273  	const N = 3
  1274  	for i := 0; i < N; i++ {
  1275  		select {
  1276  		case <-dials:
  1277  		case <-time.After(5 * time.Second):
  1278  			c.Fatalf("expected %d dials, got %d", N, i)
  1279  		}
  1280  	}
  1281  	select {
  1282  	case <-dials:
  1283  		c.Fatalf("got more dials than expected")
  1284  	case <-time.After(100 * time.Millisecond):
  1285  	}
  1286  }
  1287  
  1288  func (s *S) TestPrimaryShutdownOnAuthShard(c *C) {
  1289  	if *fast {
  1290  		c.Skip("-fast")
  1291  	}
  1292  
  1293  	// Dial the shard.
  1294  	session, err := mgo.Dial("localhost:40203")
  1295  	c.Assert(err, IsNil)
  1296  	defer session.Close()
  1297  
  1298  	// Login and insert something to make it more realistic.
  1299  	session.DB("admin").Login("root", "rapadura")
  1300  	coll := session.DB("mydb").C("mycoll")
  1301  	err = coll.Insert(bson.M{"n": 1})
  1302  	c.Assert(err, IsNil)
  1303  
  1304  	// Dial the replica set to figure the master out.
  1305  	rs, err := mgo.Dial("root:rapadura@localhost:40031")
  1306  	c.Assert(err, IsNil)
  1307  	defer rs.Close()
  1308  
  1309  	// With strong consistency, this will open a socket to the master.
  1310  	result := &struct{ Host string }{}
  1311  	err = rs.Run("serverStatus", result)
  1312  	c.Assert(err, IsNil)
  1313  
  1314  	// Kill the master.
  1315  	host := result.Host
  1316  	s.Stop(host)
  1317  
  1318  	// This must fail, since the connection was broken.
  1319  	err = rs.Run("serverStatus", result)
  1320  	c.Assert(err, Equals, io.EOF)
  1321  
  1322  	// This won't work because the master just died.
  1323  	err = coll.Insert(bson.M{"n": 2})
  1324  	c.Assert(err, NotNil)
  1325  
  1326  	// Refresh session and wait for re-election.
  1327  	session.Refresh()
  1328  	for i := 0; i < 60; i++ {
  1329  		err = coll.Insert(bson.M{"n": 3})
  1330  		if err == nil {
  1331  			break
  1332  		}
  1333  		c.Logf("Waiting for replica set to elect a new master. Last error: %v", err)
  1334  		time.Sleep(500 * time.Millisecond)
  1335  	}
  1336  	c.Assert(err, IsNil)
  1337  
  1338  	count, err := coll.Count()
  1339  	c.Assert(count > 1, Equals, true)
  1340  }
  1341  
  1342  func (s *S) TestNearestSecondary(c *C) {
  1343  	defer mgo.HackPingDelay(3 * time.Second)()
  1344  
  1345  	rs1a := "127.0.0.1:40011"
  1346  	rs1b := "127.0.0.1:40012"
  1347  	rs1c := "127.0.0.1:40013"
  1348  	s.Freeze(rs1b)
  1349  
  1350  	session, err := mgo.Dial(rs1a)
  1351  	c.Assert(err, IsNil)
  1352  	defer session.Close()
  1353  
  1354  	// Wait for the sync up to run through the first couple of servers.
  1355  	for len(session.LiveServers()) != 2 {
  1356  		c.Log("Waiting for two servers to be alive...")
  1357  		time.Sleep(100 * time.Millisecond)
  1358  	}
  1359  
  1360  	// Extra delay to ensure the third server gets penalized.
  1361  	time.Sleep(500 * time.Millisecond)
  1362  
  1363  	// Release third server.
  1364  	s.Thaw(rs1b)
  1365  
  1366  	// Wait for it to come up.
  1367  	for len(session.LiveServers()) != 3 {
  1368  		c.Log("Waiting for all servers to be alive...")
  1369  		time.Sleep(100 * time.Millisecond)
  1370  	}
  1371  
  1372  	session.SetMode(mgo.Monotonic, true)
  1373  	var result struct{ Host string }
  1374  
  1375  	// See which slave picks the line, several times to avoid chance.
  1376  	for i := 0; i < 10; i++ {
  1377  		session.Refresh()
  1378  		err = session.Run("serverStatus", &result)
  1379  		c.Assert(err, IsNil)
  1380  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1c))
  1381  	}
  1382  
  1383  	if *fast {
  1384  		// Don't hold back for several seconds.
  1385  		return
  1386  	}
  1387  
  1388  	// Now hold the other server for long enough to penalize it.
  1389  	s.Freeze(rs1c)
  1390  	time.Sleep(5 * time.Second)
  1391  	s.Thaw(rs1c)
  1392  
  1393  	// Wait for the ping to be processed.
  1394  	time.Sleep(500 * time.Millisecond)
  1395  
  1396  	// Repeating the test should now pick the former server consistently.
  1397  	for i := 0; i < 10; i++ {
  1398  		session.Refresh()
  1399  		err = session.Run("serverStatus", &result)
  1400  		c.Assert(err, IsNil)
  1401  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1b))
  1402  	}
  1403  }
  1404  
  1405  func (s *S) TestConnectCloseConcurrency(c *C) {
  1406  	restore := mgo.HackPingDelay(500 * time.Millisecond)
  1407  	defer restore()
  1408  	var wg sync.WaitGroup
  1409  	const n = 500
  1410  	wg.Add(n)
  1411  	for i := 0; i < n; i++ {
  1412  		go func() {
  1413  			defer wg.Done()
  1414  			session, err := mgo.Dial("localhost:40001")
  1415  			if err != nil {
  1416  				c.Fatal(err)
  1417  			}
  1418  			time.Sleep(1)
  1419  			session.Close()
  1420  		}()
  1421  	}
  1422  	wg.Wait()
  1423  }
  1424  
  1425  func (s *S) TestSelectServers(c *C) {
  1426  	if !s.versionAtLeast(2, 2) {
  1427  		c.Skip("read preferences introduced in 2.2")
  1428  	}
  1429  
  1430  	session, err := mgo.Dial("localhost:40011")
  1431  	c.Assert(err, IsNil)
  1432  	defer session.Close()
  1433  
  1434  	session.SetMode(mgo.Eventual, true)
  1435  
  1436  	var result struct{ Host string }
  1437  
  1438  	session.Refresh()
  1439  	session.SelectServers(bson.D{{"rs1", "b"}})
  1440  	err = session.Run("serverStatus", &result)
  1441  	c.Assert(err, IsNil)
  1442  	c.Assert(hostPort(result.Host), Equals, "40012")
  1443  
  1444  	session.Refresh()
  1445  	session.SelectServers(bson.D{{"rs1", "c"}})
  1446  	err = session.Run("serverStatus", &result)
  1447  	c.Assert(err, IsNil)
  1448  	c.Assert(hostPort(result.Host), Equals, "40013")
  1449  }
  1450  
  1451  func (s *S) TestSelectServersWithMongos(c *C) {
  1452  	if !s.versionAtLeast(2, 2) {
  1453  		c.Skip("read preferences introduced in 2.2")
  1454  	}
  1455  
  1456  	session, err := mgo.Dial("localhost:40021")
  1457  	c.Assert(err, IsNil)
  1458  	defer session.Close()
  1459  
  1460  	ssresult := &struct{ Host string }{}
  1461  	imresult := &struct{ IsMaster bool }{}
  1462  
  1463  	// Figure the master while still using the strong session.
  1464  	err = session.Run("serverStatus", ssresult)
  1465  	c.Assert(err, IsNil)
  1466  	err = session.Run("isMaster", imresult)
  1467  	c.Assert(err, IsNil)
  1468  	master := ssresult.Host
  1469  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
  1470  
  1471  	var slave1, slave2 string
  1472  	switch hostPort(master) {
  1473  	case "40021":
  1474  		slave1, slave2 = "b", "c"
  1475  	case "40022":
  1476  		slave1, slave2 = "a", "c"
  1477  	case "40023":
  1478  		slave1, slave2 = "a", "b"
  1479  	}
  1480  
  1481  	// Collect op counters for everyone.
  1482  	opc21a, err := getOpCounters("localhost:40021")
  1483  	c.Assert(err, IsNil)
  1484  	opc22a, err := getOpCounters("localhost:40022")
  1485  	c.Assert(err, IsNil)
  1486  	opc23a, err := getOpCounters("localhost:40023")
  1487  	c.Assert(err, IsNil)
  1488  
  1489  	// Do a SlaveOk query through MongoS
  1490  	mongos, err := mgo.Dial("localhost:40202")
  1491  	c.Assert(err, IsNil)
  1492  	defer mongos.Close()
  1493  
  1494  	mongos.SetMode(mgo.Monotonic, true)
  1495  
  1496  	mongos.Refresh()
  1497  	mongos.SelectServers(bson.D{{"rs2", slave1}})
  1498  	coll := mongos.DB("mydb").C("mycoll")
  1499  	result := &struct{}{}
  1500  	for i := 0; i != 5; i++ {
  1501  		err := coll.Find(nil).One(result)
  1502  		c.Assert(err, Equals, mgo.ErrNotFound)
  1503  	}
  1504  
  1505  	mongos.Refresh()
  1506  	mongos.SelectServers(bson.D{{"rs2", slave2}})
  1507  	coll = mongos.DB("mydb").C("mycoll")
  1508  	for i := 0; i != 7; i++ {
  1509  		err := coll.Find(nil).One(result)
  1510  		c.Assert(err, Equals, mgo.ErrNotFound)
  1511  	}
  1512  
  1513  	// Collect op counters for everyone again.
  1514  	opc21b, err := getOpCounters("localhost:40021")
  1515  	c.Assert(err, IsNil)
  1516  	opc22b, err := getOpCounters("localhost:40022")
  1517  	c.Assert(err, IsNil)
  1518  	opc23b, err := getOpCounters("localhost:40023")
  1519  	c.Assert(err, IsNil)
  1520  
  1521  	switch hostPort(master) {
  1522  	case "40021":
  1523  		c.Check(opc21b.Query-opc21a.Query, Equals, 0)
  1524  		c.Check(opc22b.Query-opc22a.Query, Equals, 5)
  1525  		c.Check(opc23b.Query-opc23a.Query, Equals, 7)
  1526  	case "40022":
  1527  		c.Check(opc21b.Query-opc21a.Query, Equals, 5)
  1528  		c.Check(opc22b.Query-opc22a.Query, Equals, 0)
  1529  		c.Check(opc23b.Query-opc23a.Query, Equals, 7)
  1530  	case "40023":
  1531  		c.Check(opc21b.Query-opc21a.Query, Equals, 5)
  1532  		c.Check(opc22b.Query-opc22a.Query, Equals, 7)
  1533  		c.Check(opc23b.Query-opc23a.Query, Equals, 0)
  1534  	default:
  1535  		c.Fatal("Uh?")
  1536  	}
  1537  }