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