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 }