github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/pinger_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // TODO(wallyworld) bug http://pad.lv/1408459 5 // Re-enable tests for i386 when these tests are fixed to work on that architecture. 6 7 // +build !386 8 9 package apiserver_test 10 11 import ( 12 "time" 13 14 "github.com/juju/errors" 15 "github.com/juju/loggo" 16 gitjujutesting "github.com/juju/testing" 17 jc "github.com/juju/testing/checkers" 18 "github.com/juju/utils" 19 gc "gopkg.in/check.v1" 20 21 "github.com/juju/juju/api" 22 "github.com/juju/juju/apiserver" 23 "github.com/juju/juju/juju/testing" 24 "github.com/juju/juju/rpc" 25 coretesting "github.com/juju/juju/testing" 26 ) 27 28 type pingerSuite struct { 29 testing.JujuConnSuite 30 } 31 32 var _ = gc.Suite(&pingerSuite{}) 33 34 var testPingPeriod = 100 * time.Millisecond 35 36 func (s *pingerSuite) TestConnectionBrokenDetection(c *gc.C) { 37 s.PatchValue(&api.PingPeriod, testPingPeriod) 38 39 st, _ := s.OpenAPIAsNewMachine(c) 40 41 // Connection still alive 42 select { 43 case <-time.After(testPingPeriod): 44 case <-st.Broken(): 45 c.Fatalf("connection should be alive still") 46 } 47 48 // Close the connection and see if we detect this 49 go st.Close() 50 51 // Check it's detected 52 select { 53 case <-time.After(testPingPeriod + time.Second): 54 c.Fatalf("connection not closed as expected") 55 case <-st.Broken(): 56 return 57 } 58 } 59 60 func (s *pingerSuite) TestPing(c *gc.C) { 61 tw := &loggo.TestWriter{} 62 c.Assert(loggo.RegisterWriter("ping-tester", tw, loggo.DEBUG), gc.IsNil) 63 defer loggo.RemoveWriter("ping-tester") 64 65 st, _ := s.OpenAPIAsNewMachine(c) 66 err := st.Ping() 67 c.Assert(err, jc.ErrorIsNil) 68 err = st.Close() 69 c.Assert(err, jc.ErrorIsNil) 70 err = st.Ping() 71 c.Assert(errors.Cause(err), gc.Equals, rpc.ErrShutdown) 72 73 // Make sure that ping messages have not been logged. 74 for _, m := range tw.Log() { 75 c.Logf("checking %q", m.Message) 76 c.Check(m.Message, gc.Not(gc.Matches), `.*"Request":"Ping".*`) 77 } 78 } 79 80 func (s *pingerSuite) TestClientNoNeedToPing(c *gc.C) { 81 s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0)) 82 st, err := api.Open(s.APIInfo(c), api.DefaultDialOpts()) 83 c.Assert(err, jc.ErrorIsNil) 84 defer st.Close() 85 time.Sleep(coretesting.ShortWait) 86 err = st.Ping() 87 c.Assert(err, jc.ErrorIsNil) 88 } 89 90 func (s *pingerSuite) TestAgentConnectionShutsDownWithNoPing(c *gc.C) { 91 s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0)) 92 st, _ := s.OpenAPIAsNewMachine(c) 93 time.Sleep(coretesting.ShortWait) 94 err := st.Ping() 95 c.Assert(err, gc.ErrorMatches, "connection is shut down") 96 } 97 98 func (s *pingerSuite) calculatePingTimeout(c *gc.C) time.Duration { 99 // Try opening an API connection a few times and take the max 100 // delay among the attempts. 101 attempt := utils.AttemptStrategy{ 102 Delay: coretesting.ShortWait, 103 Min: 3, 104 } 105 var maxTimeout time.Duration 106 for a := attempt.Start(); a.Next(); { 107 openStart := time.Now() 108 st, _ := s.OpenAPIAsNewMachine(c) 109 err := st.Ping() 110 if c.Check(err, jc.ErrorIsNil) { 111 openDelay := time.Since(openStart) 112 c.Logf("API open and initial ping took %v", openDelay) 113 if maxTimeout < openDelay { 114 maxTimeout = openDelay 115 } 116 } 117 if st != nil { 118 c.Check(st.Close(), jc.ErrorIsNil) 119 } 120 } 121 if !c.Failed() && maxTimeout > 0 { 122 return maxTimeout 123 } 124 c.Fatalf("cannot calculate ping timeout") 125 return 0 126 } 127 128 func (s *pingerSuite) TestAgentConnectionDelaysShutdownWithPing(c *gc.C) { 129 // To negate the effects of an underpowered or heavily loaded 130 // machine running this test, tune the shortTimeout based on the 131 // maximum duration it takes to open an API connection. 132 shortTimeout := s.calculatePingTimeout(c) 133 attemptDelay := shortTimeout / 4 134 135 s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(shortTimeout)) 136 137 st, _ := s.OpenAPIAsNewMachine(c) 138 err := st.Ping() 139 c.Assert(err, jc.ErrorIsNil) 140 defer st.Close() 141 142 // As long as we don't wait too long, the connection stays open 143 attempt := utils.AttemptStrategy{ 144 Min: 10, 145 Delay: attemptDelay, 146 } 147 testStart := time.Now() 148 c.Logf( 149 "pinging %d times with %v delay, ping timeout %v, starting at %v", 150 attempt.Min, attempt.Delay, shortTimeout, testStart, 151 ) 152 var lastLoop time.Time 153 for a := attempt.Start(); a.Next(); { 154 testNow := time.Now() 155 loopDelta := testNow.Sub(lastLoop) 156 if lastLoop.IsZero() { 157 loopDelta = 0 158 } 159 c.Logf("duration since last ping: %v", loopDelta) 160 err = st.Ping() 161 if !c.Check( 162 err, jc.ErrorIsNil, 163 gc.Commentf( 164 "ping timeout exceeded at %v (%v since the test start)", 165 testNow, testNow.Sub(testStart), 166 ), 167 ) { 168 c.Check(err, gc.ErrorMatches, "connection is shut down") 169 return 170 } 171 lastLoop = time.Now() 172 } 173 174 // However, once we stop pinging for too long, the connection dies 175 time.Sleep(2 * shortTimeout) // Exceed the timeout. 176 err = st.Ping() 177 c.Assert(err, gc.ErrorMatches, "connection is shut down") 178 } 179 180 type mongoPingerSuite struct { 181 testing.JujuConnSuite 182 } 183 184 var _ = gc.Suite(&mongoPingerSuite{}) 185 186 func (s *mongoPingerSuite) SetUpSuite(c *gc.C) { 187 s.JujuConnSuite.SetUpSuite(c) 188 // We need to set the ping interval before the server is started in test setup. 189 restore := gitjujutesting.PatchValue(apiserver.MongoPingInterval, coretesting.ShortWait) 190 s.AddCleanup(func(*gc.C) { restore() }) 191 } 192 193 func (s *mongoPingerSuite) TestAgentConnectionsShutDownWhenStateDies(c *gc.C) { 194 st, _ := s.OpenAPIAsNewMachine(c) 195 err := st.Ping() 196 c.Assert(err, jc.ErrorIsNil) 197 gitjujutesting.MgoServer.Destroy() 198 199 attempt := utils.AttemptStrategy{ 200 Total: coretesting.LongWait, 201 Delay: coretesting.ShortWait, 202 } 203 for a := attempt.Start(); a.Next(); { 204 if err := st.Ping(); err != nil { 205 c.Assert(err, gc.ErrorMatches, "connection is shut down") 206 return 207 } 208 } 209 c.Fatalf("timed out waiting for API server to die") 210 }