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  }