github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/suite_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  	"errors"
    34  	"flag"
    35  	"fmt"
    36  	"net"
    37  	"os/exec"
    38  	"strconv"
    39  	"syscall"
    40  
    41  	"testing"
    42  	"time"
    43  )
    44  
    45  var fast = flag.Bool("fast", false, "Skip slow tests")
    46  
    47  type M bson.M
    48  
    49  type cLogger C
    50  
    51  func (c *cLogger) Output(calldepth int, s string) error {
    52  	ns := time.Now().UnixNano()
    53  	t := float64(ns%100e9) / 1e9
    54  	((*C)(c)).Logf("[LOG] %.05f %s", t, s)
    55  	return nil
    56  }
    57  
    58  func TestAll(t *testing.T) {
    59  	TestingT(t)
    60  }
    61  
    62  type S struct {
    63  	session *mgo.Session
    64  	stopped bool
    65  	build   mgo.BuildInfo
    66  	frozen  []string
    67  }
    68  
    69  func (s *S) versionAtLeast(v ...int) bool {
    70  	for i := range v {
    71  		if i == len(s.build.VersionArray) {
    72  			return false
    73  		}
    74  		if s.build.VersionArray[i] < v[i] {
    75  			return false
    76  		}
    77  	}
    78  	return true
    79  }
    80  
    81  var _ = Suite(&S{})
    82  
    83  func (s *S) SetUpSuite(c *C) {
    84  	mgo.SetDebug(true)
    85  	mgo.SetStats(true)
    86  	s.StartAll()
    87  
    88  	session, err := mgo.Dial("localhost:40001")
    89  	c.Assert(err, IsNil)
    90  	s.build, err = session.BuildInfo()
    91  	c.Check(err, IsNil)
    92  	session.Close()
    93  }
    94  
    95  func (s *S) SetUpTest(c *C) {
    96  	err := run("mongo --nodb testdb/dropall.js")
    97  	if err != nil {
    98  		panic(err.Error())
    99  	}
   100  	mgo.SetLogger((*cLogger)(c))
   101  	mgo.ResetStats()
   102  }
   103  
   104  func (s *S) TearDownTest(c *C) {
   105  	if s.stopped {
   106  		s.StartAll()
   107  	}
   108  	for _, host := range s.frozen {
   109  		if host != "" {
   110  			s.Thaw(host)
   111  		}
   112  	}
   113  	var stats mgo.Stats
   114  	for i := 0; ; i++ {
   115  		stats = mgo.GetStats()
   116  		if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
   117  			break
   118  		}
   119  		if i == 20 {
   120  			c.Fatal("Test left sockets in a dirty state")
   121  		}
   122  		c.Logf("Waiting for sockets to die: %d in use, %d alive", stats.SocketsInUse, stats.SocketsAlive)
   123  		time.Sleep(500 * time.Millisecond)
   124  	}
   125  	for i := 0; ; i++ {
   126  		stats = mgo.GetStats()
   127  		if stats.Clusters == 0 {
   128  			break
   129  		}
   130  		if i == 60 {
   131  			c.Fatal("Test left clusters alive")
   132  		}
   133  		c.Logf("Waiting for clusters to die: %d alive", stats.Clusters)
   134  		time.Sleep(1 * time.Second)
   135  	}
   136  }
   137  
   138  func (s *S) Stop(host string) {
   139  	// Give a moment for slaves to sync and avoid getting rollback issues.
   140  	time.Sleep(2 * time.Second)
   141  	err := run("cd _testdb && supervisorctl stop " + supvName(host))
   142  	if err != nil {
   143  		panic(err)
   144  	}
   145  	s.stopped = true
   146  }
   147  
   148  func (s *S) pid(host string) int {
   149  	output, err := exec.Command("lsof", "-iTCP:"+hostPort(host), "-sTCP:LISTEN", "-Fp").CombinedOutput()
   150  	if err != nil {
   151  		panic(err)
   152  	}
   153  	pidstr := string(output[1 : len(output)-1])
   154  	pid, err := strconv.Atoi(pidstr)
   155  	if err != nil {
   156  		panic("cannot convert pid to int: " + pidstr)
   157  	}
   158  	return pid
   159  }
   160  
   161  func (s *S) Freeze(host string) {
   162  	err := syscall.Kill(s.pid(host), syscall.SIGSTOP)
   163  	if err != nil {
   164  		panic(err)
   165  	}
   166  	s.frozen = append(s.frozen, host)
   167  }
   168  
   169  func (s *S) Thaw(host string) {
   170  	err := syscall.Kill(s.pid(host), syscall.SIGCONT)
   171  	if err != nil {
   172  		panic(err)
   173  	}
   174  	for i, frozen := range s.frozen {
   175  		if frozen == host {
   176  			s.frozen[i] = ""
   177  		}
   178  	}
   179  }
   180  
   181  func (s *S) StartAll() {
   182  	// Restart any stopped nodes.
   183  	run("cd _testdb && supervisorctl start all")
   184  	err := run("cd testdb && mongo --nodb wait.js")
   185  	if err != nil {
   186  		panic(err)
   187  	}
   188  	s.stopped = false
   189  }
   190  
   191  func run(command string) error {
   192  	output, err := exec.Command("/bin/sh", "-c", command).CombinedOutput()
   193  	if err != nil {
   194  		msg := fmt.Sprintf("Failed to execute: %s: %s\n%s", command, err.Error(), string(output))
   195  		return errors.New(msg)
   196  	}
   197  	return nil
   198  }
   199  
   200  var supvNames = map[string]string{
   201  	"40001": "db1",
   202  	"40002": "db2",
   203  	"40011": "rs1a",
   204  	"40012": "rs1b",
   205  	"40013": "rs1c",
   206  	"40021": "rs2a",
   207  	"40022": "rs2b",
   208  	"40023": "rs2c",
   209  	"40031": "rs3a",
   210  	"40032": "rs3b",
   211  	"40033": "rs3c",
   212  	"40041": "rs4a",
   213  	"40101": "cfg1",
   214  	"40102": "cfg2",
   215  	"40103": "cfg3",
   216  	"40201": "s1",
   217  	"40202": "s2",
   218  	"40203": "s3",
   219  }
   220  
   221  // supvName returns the supervisord name for the given host address.
   222  func supvName(host string) string {
   223  	host, port, err := net.SplitHostPort(host)
   224  	if err != nil {
   225  		panic(err)
   226  	}
   227  	name, ok := supvNames[port]
   228  	if !ok {
   229  		panic("Unknown host: " + host)
   230  	}
   231  	return name
   232  }
   233  
   234  func hostPort(host string) string {
   235  	_, port, err := net.SplitHostPort(host)
   236  	if err != nil {
   237  		panic(err)
   238  	}
   239  	return port
   240  }