github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/runner/context/leader_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package context_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/core/leadership"
    13  	"github.com/juju/juju/worker/uniter/runner/context"
    14  )
    15  
    16  type LeaderSuite struct {
    17  	testing.IsolationSuite
    18  	testing.Stub
    19  	accessor *StubLeadershipSettingsAccessor
    20  	tracker  *StubTracker
    21  	context  context.LeadershipContext
    22  }
    23  
    24  var _ = gc.Suite(&LeaderSuite{})
    25  
    26  func (s *LeaderSuite) SetUpTest(c *gc.C) {
    27  	s.IsolationSuite.SetUpTest(c)
    28  	s.accessor = &StubLeadershipSettingsAccessor{
    29  		Stub: &s.Stub,
    30  	}
    31  	s.tracker = &StubTracker{
    32  		Stub:            &s.Stub,
    33  		applicationName: "led-application",
    34  	}
    35  	s.CheckCalls(c, []testing.StubCall{{
    36  		FuncName: "ApplicationName",
    37  	}}, func() {
    38  		s.context = context.NewLeadershipContext(s.accessor, s.tracker, "u/0")
    39  	})
    40  }
    41  
    42  func (s *LeaderSuite) CheckCalls(c *gc.C, stubCalls []testing.StubCall, f func()) {
    43  	s.Stub = testing.Stub{}
    44  	f()
    45  	s.Stub.CheckCalls(c, stubCalls)
    46  }
    47  
    48  func (s *LeaderSuite) TestIsLeaderSuccess(c *gc.C) {
    49  	s.CheckCalls(c, []testing.StubCall{{
    50  		FuncName: "ClaimLeader",
    51  	}}, func() {
    52  		// The first call succeeds...
    53  		s.tracker.results = []StubTicket{true}
    54  		leader, err := s.context.IsLeader()
    55  		c.Check(leader, jc.IsTrue)
    56  		c.Check(err, jc.ErrorIsNil)
    57  	})
    58  
    59  	s.CheckCalls(c, []testing.StubCall{{
    60  		FuncName: "ClaimLeader",
    61  	}}, func() {
    62  		// ...and so does the second.
    63  		s.tracker.results = []StubTicket{true}
    64  		leader, err := s.context.IsLeader()
    65  		c.Check(leader, jc.IsTrue)
    66  		c.Check(err, jc.ErrorIsNil)
    67  	})
    68  }
    69  
    70  func (s *LeaderSuite) TestIsLeaderFailure(c *gc.C) {
    71  	s.CheckCalls(c, []testing.StubCall{{
    72  		FuncName: "ClaimLeader",
    73  	}}, func() {
    74  		// The first call fails...
    75  		s.tracker.results = []StubTicket{false}
    76  		leader, err := s.context.IsLeader()
    77  		c.Check(leader, jc.IsFalse)
    78  		c.Check(err, jc.ErrorIsNil)
    79  	})
    80  
    81  	s.CheckCalls(c, nil, func() {
    82  		// ...and the second doesn't even try.
    83  		leader, err := s.context.IsLeader()
    84  		c.Check(leader, jc.IsFalse)
    85  		c.Check(err, jc.ErrorIsNil)
    86  	})
    87  }
    88  
    89  func (s *LeaderSuite) TestIsLeaderFailureAfterSuccess(c *gc.C) {
    90  	s.CheckCalls(c, []testing.StubCall{{
    91  		FuncName: "ClaimLeader",
    92  	}}, func() {
    93  		// The first call succeeds...
    94  		s.tracker.results = []StubTicket{true}
    95  		leader, err := s.context.IsLeader()
    96  		c.Check(leader, jc.IsTrue)
    97  		c.Check(err, jc.ErrorIsNil)
    98  	})
    99  
   100  	s.CheckCalls(c, []testing.StubCall{{
   101  		FuncName: "ClaimLeader",
   102  	}}, func() {
   103  		// The second fails...
   104  		s.tracker.results = []StubTicket{false}
   105  		leader, err := s.context.IsLeader()
   106  		c.Check(leader, jc.IsFalse)
   107  		c.Check(err, jc.ErrorIsNil)
   108  	})
   109  
   110  	s.CheckCalls(c, nil, func() {
   111  		// The third doesn't even try.
   112  		leader, err := s.context.IsLeader()
   113  		c.Check(leader, jc.IsFalse)
   114  		c.Check(err, jc.ErrorIsNil)
   115  	})
   116  }
   117  
   118  func (s *LeaderSuite) TestLeaderSettingsSuccess(c *gc.C) {
   119  	s.CheckCalls(c, []testing.StubCall{{
   120  		FuncName: "Read",
   121  		Args:     []interface{}{"led-application"},
   122  	}}, func() {
   123  		// The first call grabs the settings...
   124  		s.accessor.results = []map[string]string{{
   125  			"some": "settings",
   126  			"of":   "interest",
   127  		}}
   128  		settings, err := s.context.LeaderSettings()
   129  		c.Check(settings, jc.DeepEquals, map[string]string{
   130  			"some": "settings",
   131  			"of":   "interest",
   132  		})
   133  		c.Check(err, jc.ErrorIsNil)
   134  	})
   135  
   136  	s.CheckCalls(c, nil, func() {
   137  		// The second uses the cache.
   138  		settings, err := s.context.LeaderSettings()
   139  		c.Check(settings, jc.DeepEquals, map[string]string{
   140  			"some": "settings",
   141  			"of":   "interest",
   142  		})
   143  		c.Check(err, jc.ErrorIsNil)
   144  	})
   145  }
   146  
   147  func (s *LeaderSuite) TestLeaderSettingsCopyMap(c *gc.C) {
   148  	// Grab the settings to populate the cache...
   149  	s.accessor.results = []map[string]string{{
   150  		"some": "settings",
   151  		"of":   "interest",
   152  	}}
   153  	settings, err := s.context.LeaderSettings()
   154  	c.Check(err, gc.IsNil)
   155  
   156  	// Put some nonsense into the returned settings...
   157  	settings["bad"] = "news"
   158  
   159  	// Get the settings again and check they're as expected.
   160  	settings, err = s.context.LeaderSettings()
   161  	c.Check(settings, jc.DeepEquals, map[string]string{
   162  		"some": "settings",
   163  		"of":   "interest",
   164  	})
   165  	c.Check(err, jc.ErrorIsNil)
   166  }
   167  
   168  func (s *LeaderSuite) TestLeaderSettingsError(c *gc.C) {
   169  	s.CheckCalls(c, []testing.StubCall{{
   170  		FuncName: "Read",
   171  		Args:     []interface{}{"led-application"},
   172  	}}, func() {
   173  		s.accessor.results = []map[string]string{nil}
   174  		s.Stub.SetErrors(errors.New("blort"))
   175  		settings, err := s.context.LeaderSettings()
   176  		c.Check(settings, gc.IsNil)
   177  		c.Check(err, gc.ErrorMatches, "cannot read settings: blort")
   178  	})
   179  }
   180  
   181  func (s *LeaderSuite) TestWriteLeaderSettingsSuccess(c *gc.C) {
   182  	s.CheckCalls(c, []testing.StubCall{{
   183  		FuncName: "ClaimLeader",
   184  	}, {
   185  		FuncName: "Merge",
   186  		Args: []interface{}{"led-application", "u/0", map[string]string{
   187  			"some": "very",
   188  			"nice": "data",
   189  		}},
   190  	}}, func() {
   191  		s.tracker.results = []StubTicket{true}
   192  		err := s.context.WriteLeaderSettings(map[string]string{
   193  			"some": "very",
   194  			"nice": "data",
   195  		})
   196  		c.Check(err, jc.ErrorIsNil)
   197  	})
   198  }
   199  
   200  func (s *LeaderSuite) TestWriteLeaderSettingsMinion(c *gc.C) {
   201  	s.CheckCalls(c, []testing.StubCall{{
   202  		FuncName: "ClaimLeader",
   203  	}}, func() {
   204  		// We are not the leader.
   205  		s.tracker.results = []StubTicket{false}
   206  		err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"})
   207  		// No error, no call to Merge.
   208  		c.Check(err, jc.ErrorIsNil)
   209  	})
   210  
   211  	s.CheckCalls(c, nil, func() {
   212  		// ctx.isMinion is now true. No call to claim leader.
   213  		err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"})
   214  		c.Check(err, jc.ErrorIsNil)
   215  	})
   216  }
   217  
   218  func (s *LeaderSuite) TestWriteLeaderSettingsError(c *gc.C) {
   219  	s.CheckCalls(c, []testing.StubCall{{
   220  		FuncName: "ClaimLeader",
   221  	}, {
   222  		FuncName: "Merge",
   223  		Args: []interface{}{"led-application", "u/0", map[string]string{
   224  			"some": "very",
   225  			"nice": "data",
   226  		}},
   227  	}}, func() {
   228  		s.tracker.results = []StubTicket{true}
   229  		s.Stub.SetErrors(errors.New("glurk"))
   230  		err := s.context.WriteLeaderSettings(map[string]string{
   231  			"some": "very",
   232  			"nice": "data",
   233  		})
   234  		c.Check(err, gc.ErrorMatches, "cannot write settings: glurk")
   235  	})
   236  }
   237  
   238  func (s *LeaderSuite) TestWriteLeaderSettingsClearsCache(c *gc.C) {
   239  	s.CheckCalls(c, []testing.StubCall{{
   240  		FuncName: "Read",
   241  		Args:     []interface{}{"led-application"},
   242  	}}, func() {
   243  		// Start off by populating the cache...
   244  		s.accessor.results = []map[string]string{{
   245  			"some": "settings",
   246  			"of":   "interest",
   247  		}}
   248  		_, err := s.context.LeaderSettings()
   249  		c.Check(err, gc.IsNil)
   250  	})
   251  
   252  	s.CheckCalls(c, []testing.StubCall{{
   253  		FuncName: "ClaimLeader",
   254  	}, {
   255  		FuncName: "Merge",
   256  		Args: []interface{}{"led-application", "u/0", map[string]string{
   257  			"some": "very",
   258  			"nice": "data",
   259  		}},
   260  	}}, func() {
   261  		// Write new data to the controller...
   262  		s.tracker.results = []StubTicket{true}
   263  		err := s.context.WriteLeaderSettings(map[string]string{
   264  			"some": "very",
   265  			"nice": "data",
   266  		})
   267  		c.Check(err, jc.ErrorIsNil)
   268  	})
   269  
   270  	s.CheckCalls(c, []testing.StubCall{{
   271  		FuncName: "Read",
   272  		Args:     []interface{}{"led-application"},
   273  	}}, func() {
   274  		s.accessor.results = []map[string]string{{
   275  			"totally": "different",
   276  			"server":  "decides",
   277  		}}
   278  		settings, err := s.context.LeaderSettings()
   279  		c.Check(err, gc.IsNil)
   280  		c.Check(settings, jc.DeepEquals, map[string]string{
   281  			"totally": "different",
   282  			"server":  "decides",
   283  		})
   284  		c.Check(err, jc.ErrorIsNil)
   285  	})
   286  }
   287  
   288  type StubLeadershipSettingsAccessor struct {
   289  	*testing.Stub
   290  	results []map[string]string
   291  }
   292  
   293  func (stub *StubLeadershipSettingsAccessor) Read(applicationName string) (result map[string]string, _ error) {
   294  	stub.MethodCall(stub, "Read", applicationName)
   295  	result, stub.results = stub.results[0], stub.results[1:]
   296  	return result, stub.NextErr()
   297  }
   298  
   299  func (stub *StubLeadershipSettingsAccessor) Merge(applicationName, unitName string, settings map[string]string) error {
   300  	stub.MethodCall(stub, "Merge", applicationName, unitName, settings)
   301  	return stub.NextErr()
   302  }
   303  
   304  type StubTracker struct {
   305  	leadership.Tracker
   306  	*testing.Stub
   307  	applicationName string
   308  	results         []StubTicket
   309  }
   310  
   311  func (stub *StubTracker) ApplicationName() string {
   312  	stub.MethodCall(stub, "ApplicationName")
   313  	return stub.applicationName
   314  }
   315  
   316  func (stub *StubTracker) ClaimLeader() (result leadership.Ticket) {
   317  	stub.MethodCall(stub, "ClaimLeader")
   318  	result, stub.results = stub.results[0], stub.results[1:]
   319  	return result
   320  }
   321  
   322  type StubTicket bool
   323  
   324  func (ticket StubTicket) Wait() bool {
   325  	return bool(ticket)
   326  }
   327  
   328  func (ticket StubTicket) Ready() <-chan struct{} {
   329  	return alwaysReady
   330  }
   331  
   332  var alwaysReady = make(chan struct{})
   333  
   334  func init() {
   335  	close(alwaysReady)
   336  }