github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/core/presence/presence_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package presence_test 5 6 import ( 7 "time" 8 9 "github.com/juju/clock/testclock" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/core/presence" 14 ) 15 16 type suite struct{} 17 18 var _ = gc.Suite(&suite{}) 19 20 func (*suite) assertEmptyConnections(c *gc.C, connections presence.Connections) { 21 c.Assert(connections.Count(), gc.Equals, 0) 22 c.Assert(connections.Models(), gc.HasLen, 0) 23 c.Assert(connections.Servers(), gc.HasLen, 0) 24 c.Assert(connections.Agents(), gc.HasLen, 0) 25 c.Assert(connections.Values(), gc.HasLen, 0) 26 } 27 28 func (*suite) assertConnections(c *gc.C, connections presence.Connections, expected []presence.Value) { 29 c.Assert(connections.Values(), jc.SameContents, expected) 30 } 31 32 func (s *suite) TestEmptyRecorder(c *gc.C) { 33 r := presence.New(testclock.NewClock(time.Time{})) 34 c.Assert(r.IsEnabled(), jc.IsFalse) 35 r.Enable() 36 s.assertEmptyConnections(c, r.Connections()) 37 } 38 39 func (s *suite) TestBootstrapCase(c *gc.C) { 40 r, _ := bootstrap() 41 42 c.Assert(r.IsEnabled(), jc.IsTrue) 43 44 connections := r.Connections() 45 expected := []presence.Value{alive(ha0)} 46 47 s.assertConnections(c, connections, expected) 48 s.assertConnections(c, connections.ForModel(bootstrapUUID), expected) 49 s.assertEmptyConnections(c, connections.ForModel(modelUUID)) 50 } 51 52 func (s *suite) TestHAController(c *gc.C) { 53 r, _ := bootstrap() 54 enableHA(r) 55 56 connections := r.Connections() 57 expected := []presence.Value{alive(ha0), alive(ha1), alive(ha2)} 58 59 c.Assert(connections.Values(), jc.DeepEquals, expected) 60 s.assertConnections(c, connections.ForModel(bootstrapUUID), expected) 61 s.assertEmptyConnections(c, connections.ForModel(modelUUID)) 62 63 s.assertConnections(c, connections.ForServer(ha0.Server), values(alive(ha0))) 64 s.assertConnections(c, connections.ForServer(ha1.Server), values(alive(ha1))) 65 s.assertConnections(c, connections.ForServer(ha2.Server), values(alive(ha2))) 66 } 67 68 func (s *suite) TestModels(c *gc.C) { 69 r, _ := bootstrap() 70 enableHA(r) 71 deployModel(r) 72 73 connections := r.Connections() 74 s.assertConnections(c, connections.ForModel(bootstrapUUID), 75 values(alive(ha0), alive(ha1), alive(ha2))) 76 s.assertConnections(c, connections.ForModel(modelUUID), 77 values(alive(modelMachine0), alive(modelMachine1), 78 alive(modelUnit1), alive(modelUnit2))) 79 80 s.assertConnections(c, connections.ForServer(ha0.Server), 81 values(alive(ha0), alive(modelUnit1), alive(modelUnit2))) 82 s.assertConnections(c, connections.ForServer(ha1.Server), 83 values(alive(ha1), alive(modelMachine0))) 84 s.assertConnections(c, connections.ForServer(ha2.Server), 85 values(alive(ha2), alive(modelMachine1))) 86 } 87 88 func (s *suite) TestTimeRecording(c *gc.C) { 89 now := time.Now() 90 r, clock := bootstrap(now) 91 92 m0 := lastSeen(alive(ha0), now) 93 clock.Advance(time.Minute) 94 now = clock.Now() 95 enableHA(r) 96 97 m1 := lastSeen(alive(ha1), now) 98 m2 := lastSeen(alive(ha2), now) 99 100 connections := r.Connections() 101 s.assertConnections(c, connections.ForModel(bootstrapUUID), 102 values(m0, m1, m2)) 103 } 104 105 func (s *suite) TestActivity(c *gc.C) { 106 r, clock := bootstrap() 107 enableHA(r) 108 deployModel(r) 109 110 clock.Advance(5 * time.Minute) 111 112 // Register activity for model machine 0. 113 r.Activity("machine-1", 1237) 114 115 // These connections are all the same except for modelMachine0 116 // which shows an updated time. 117 mm0 := lastSeen(alive(modelMachine0), clock.Now()) 118 119 connections := r.Connections() 120 s.assertConnections(c, connections.ForModel(bootstrapUUID), 121 values(alive(ha0), alive(ha1), alive(ha2))) 122 s.assertConnections(c, connections.ForModel(modelUUID), 123 values(mm0, alive(modelMachine1), 124 alive(modelUnit1), alive(modelUnit2))) 125 126 s.assertConnections(c, connections.ForServer(ha0.Server), 127 values(alive(ha0), alive(modelUnit1), alive(modelUnit2))) 128 s.assertConnections(c, connections.ForServer(ha1.Server), 129 values(alive(ha1), mm0)) 130 s.assertConnections(c, connections.ForServer(ha2.Server), 131 values(alive(ha2), alive(modelMachine1))) 132 } 133 134 func (s *suite) TestDisconnect(c *gc.C) { 135 r, _ := bootstrap() 136 enableHA(r) 137 deployModel(r) 138 139 r.Disconnect(ha0.Server, ha0.ConnectionID) 140 r.Disconnect(modelUnit1.Server, modelUnit1.ConnectionID) 141 142 connections := r.Connections() 143 144 c.Assert(connections.Count(), gc.Equals, 5) 145 s.assertConnections(c, connections.ForModel(bootstrapUUID), 146 values(alive(ha1), alive(ha2))) 147 s.assertConnections(c, connections.ForModel(modelUUID), 148 values(alive(modelMachine0), alive(modelMachine1), alive(modelUnit2))) 149 } 150 151 func (s *suite) TestDisableClears(c *gc.C) { 152 r, _ := bootstrap() 153 r.Disable() 154 155 s.assertEmptyConnections(c, r.Connections()) 156 } 157 158 func (s *suite) TestServerDown(c *gc.C) { 159 r, _ := bootstrap() 160 enableHA(r) 161 deployModel(r) 162 163 r.ServerDown("machine-0") 164 165 connections := r.Connections() 166 s.assertConnections(c, connections.ForModel(bootstrapUUID), 167 values(missing(ha0), alive(ha1), alive(ha2))) 168 s.assertConnections(c, connections.ForModel(modelUUID), 169 values(alive(modelMachine0), alive(modelMachine1), 170 missing(modelUnit1), missing(modelUnit2))) 171 172 s.assertConnections(c, connections.ForServer(ha0.Server), 173 values(missing(ha0), missing(modelUnit1), missing(modelUnit2))) 174 s.assertConnections(c, connections.ForServer(ha1.Server), 175 values(alive(ha1), alive(modelMachine0))) 176 s.assertConnections(c, connections.ForServer(ha2.Server), 177 values(alive(ha2), alive(modelMachine1))) 178 } 179 180 func (s *suite) TestServerDownFollowedByConnections(c *gc.C) { 181 r, _ := bootstrap() 182 enableHA(r) 183 deployModel(r) 184 185 r.ServerDown("machine-0") 186 connect(r, ha0) 187 connect(r, modelUnit1) 188 connect(r, modelUnit2) 189 190 connections := r.Connections() 191 s.assertConnections(c, connections.ForModel(bootstrapUUID), 192 values(alive(ha0), alive(ha1), alive(ha2))) 193 s.assertConnections(c, connections.ForModel(modelUUID), 194 values(alive(modelMachine0), alive(modelMachine1), 195 alive(modelUnit1), alive(modelUnit2))) 196 197 s.assertConnections(c, connections.ForServer(ha0.Server), 198 values(alive(ha0), alive(modelUnit1), alive(modelUnit2))) 199 s.assertConnections(c, connections.ForServer(ha1.Server), 200 values(alive(ha1), alive(modelMachine0))) 201 s.assertConnections(c, connections.ForServer(ha2.Server), 202 values(alive(ha2), alive(modelMachine1))) 203 } 204 205 func (s *suite) TestUpdateServer(c *gc.C) { 206 r, _ := bootstrap() 207 enableHA(r) 208 deployModel(r) 209 210 // Replace machine-0 values with just the ha node. 211 // The values need to include the status of the connection. 212 err := r.UpdateServer("machine-0", values(ha0)) 213 c.Assert(err, jc.ErrorIsNil) 214 215 connections := r.Connections() 216 s.assertConnections(c, connections.ForModel(bootstrapUUID), 217 values(alive(ha0), alive(ha1), alive(ha2))) 218 s.assertConnections(c, connections.ForModel(modelUUID), 219 values(alive(modelMachine0), alive(modelMachine1))) 220 221 s.assertConnections(c, connections.ForServer(ha0.Server), 222 values(alive(ha0))) 223 s.assertConnections(c, connections.ForServer(ha1.Server), 224 values(alive(ha1), alive(modelMachine0))) 225 s.assertConnections(c, connections.ForServer(ha2.Server), 226 values(alive(ha2), alive(modelMachine1))) 227 } 228 229 func (s *suite) TestUpdateServerError(c *gc.C) { 230 r, _ := bootstrap() 231 enableHA(r) 232 deployModel(r) 233 234 err := r.UpdateServer("machine-0", values(alive(ha1))) 235 c.Assert(err, gc.ErrorMatches, `connection server mismatch, got "machine-1" expected "machine-0"`) 236 } 237 238 func (s *suite) TestConnections(c *gc.C) { 239 r, _ := bootstrap() 240 enableHA(r) 241 deployModel(r) 242 243 r.ServerDown("machine-0") 244 245 connections := r.Connections() 246 247 c.Assert(connections.Count(), gc.Equals, 7) 248 status, err := connections.AgentStatus("machine-0") 249 c.Assert(status, gc.Equals, presence.Unknown) 250 c.Assert(err, gc.ErrorMatches, "connections not limited to a model, agent ambiguous") 251 252 controllerConnections := connections.ForModel(bootstrapUUID) 253 c.Assert(controllerConnections.Count(), gc.Equals, 3) 254 255 status, err = controllerConnections.AgentStatus("machine-0") 256 c.Assert(status, gc.Equals, presence.Missing) 257 c.Assert(err, jc.ErrorIsNil) 258 status, err = controllerConnections.AgentStatus("machine-1") 259 c.Assert(status, gc.Equals, presence.Alive) 260 c.Assert(err, jc.ErrorIsNil) 261 status, err = controllerConnections.AgentStatus("machine-4") 262 c.Assert(status, gc.Equals, presence.Unknown) 263 c.Assert(err, jc.ErrorIsNil) 264 } 265 266 func bootstrap(initialTime ...time.Time) (presence.Recorder, *testclock.Clock) { 267 if len(initialTime) > 1 { 268 panic("initialTime should be zero or one values") 269 } 270 var t time.Time 271 if len(initialTime) > 0 { 272 t = initialTime[0] 273 } 274 // By using a testing clock with a zero time, the times are always empty. 275 clock := testclock.NewClock(t) 276 r := presence.New(clock) 277 r.Enable() 278 connect(r, ha0) 279 return r, clock 280 } 281 282 func enableHA(r presence.Recorder) { 283 connect(r, ha1) 284 connect(r, ha2) 285 } 286 287 func deployModel(r presence.Recorder) { 288 connect(r, modelMachine0) 289 connect(r, modelMachine1) 290 connect(r, modelUnit1) 291 connect(r, modelUnit2) 292 } 293 294 func values(v ...presence.Value) []presence.Value { 295 return v 296 } 297 298 func alive(v presence.Value) presence.Value { 299 v.Status = presence.Alive 300 return v 301 } 302 303 func missing(v presence.Value) presence.Value { 304 v.Status = presence.Missing 305 return v 306 } 307 308 func lastSeen(v presence.Value, when time.Time) presence.Value { 309 v.LastSeen = when 310 return v 311 } 312 313 func connect(r presence.Recorder, info presence.Value) { 314 r.Connect(info.Server, info.Model, info.Agent, info.ConnectionID, info.ControllerAgent, info.UserData) 315 } 316 317 const bootstrapUUID = "bootstrap-uuid" 318 const modelUUID = "model-uuid" 319 320 var ha0 = presence.Value{ 321 Model: bootstrapUUID, 322 Server: "machine-0", 323 Agent: "machine-0", 324 ConnectionID: 1234, 325 } 326 var ha1 = presence.Value{ 327 Model: bootstrapUUID, 328 Server: "machine-1", 329 Agent: "machine-1", 330 ConnectionID: 1235, 331 } 332 var ha2 = presence.Value{ 333 Model: bootstrapUUID, 334 Server: "machine-2", 335 Agent: "machine-2", 336 ConnectionID: 1236, 337 } 338 339 var modelMachine0 = presence.Value{ 340 Model: modelUUID, 341 Server: "machine-1", 342 Agent: "machine-0", 343 ConnectionID: 1237, 344 } 345 var modelMachine1 = presence.Value{ 346 Model: modelUUID, 347 Server: "machine-2", 348 Agent: "machine-1", 349 ConnectionID: 1238, 350 } 351 var modelUnit1 = presence.Value{ 352 Model: modelUUID, 353 Server: "machine-0", 354 Agent: "unit-wordpress-0", 355 ConnectionID: 1239, 356 } 357 var modelUnit2 = presence.Value{ 358 Model: modelUUID, 359 Server: "machine-0", 360 Agent: "unit-mysql-0", 361 ConnectionID: 12409, 362 }