github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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  		serviceName: "led-service",
    34  	}
    35  	s.CheckCalls(c, []testing.StubCall{{
    36  		FuncName: "ApplicationName",
    37  	}}, func() {
    38  		s.context = context.NewLeadershipContext(s.accessor, s.tracker)
    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-service"},
   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-service"},
   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-service", 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  		// The first call fails...
   205  		s.tracker.results = []StubTicket{false}
   206  		err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"})
   207  		c.Check(err, gc.ErrorMatches, "cannot write settings: not the leader")
   208  	})
   209  
   210  	s.CheckCalls(c, nil, func() {
   211  		// The second doesn't even try.
   212  		err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"})
   213  		c.Check(err, gc.ErrorMatches, "cannot write settings: not the leader")
   214  	})
   215  }
   216  
   217  func (s *LeaderSuite) TestWriteLeaderSettingsError(c *gc.C) {
   218  	s.CheckCalls(c, []testing.StubCall{{
   219  		FuncName: "ClaimLeader",
   220  	}, {
   221  		FuncName: "Merge",
   222  		Args: []interface{}{"led-service", map[string]string{
   223  			"some": "very",
   224  			"nice": "data",
   225  		}},
   226  	}}, func() {
   227  		s.tracker.results = []StubTicket{true}
   228  		s.Stub.SetErrors(errors.New("glurk"))
   229  		err := s.context.WriteLeaderSettings(map[string]string{
   230  			"some": "very",
   231  			"nice": "data",
   232  		})
   233  		c.Check(err, gc.ErrorMatches, "cannot write settings: glurk")
   234  	})
   235  }
   236  
   237  func (s *LeaderSuite) TestWriteLeaderSettingsClearsCache(c *gc.C) {
   238  	s.CheckCalls(c, []testing.StubCall{{
   239  		FuncName: "Read",
   240  		Args:     []interface{}{"led-service"},
   241  	}}, func() {
   242  		// Start off by populating the cache...
   243  		s.accessor.results = []map[string]string{{
   244  			"some": "settings",
   245  			"of":   "interest",
   246  		}}
   247  		_, err := s.context.LeaderSettings()
   248  		c.Check(err, gc.IsNil)
   249  	})
   250  
   251  	s.CheckCalls(c, []testing.StubCall{{
   252  		FuncName: "ClaimLeader",
   253  	}, {
   254  		FuncName: "Merge",
   255  		Args: []interface{}{"led-service", map[string]string{
   256  			"some": "very",
   257  			"nice": "data",
   258  		}},
   259  	}}, func() {
   260  		// Write new data to the controller...
   261  		s.tracker.results = []StubTicket{true}
   262  		err := s.context.WriteLeaderSettings(map[string]string{
   263  			"some": "very",
   264  			"nice": "data",
   265  		})
   266  		c.Check(err, jc.ErrorIsNil)
   267  	})
   268  
   269  	s.CheckCalls(c, []testing.StubCall{{
   270  		FuncName: "Read",
   271  		Args:     []interface{}{"led-service"},
   272  	}}, func() {
   273  		s.accessor.results = []map[string]string{{
   274  			"totally": "different",
   275  			"server":  "decides",
   276  		}}
   277  		settings, err := s.context.LeaderSettings()
   278  		c.Check(err, gc.IsNil)
   279  		c.Check(settings, jc.DeepEquals, map[string]string{
   280  			"totally": "different",
   281  			"server":  "decides",
   282  		})
   283  		c.Check(err, jc.ErrorIsNil)
   284  	})
   285  }
   286  
   287  type StubLeadershipSettingsAccessor struct {
   288  	*testing.Stub
   289  	results []map[string]string
   290  }
   291  
   292  func (stub *StubLeadershipSettingsAccessor) Read(serviceName string) (result map[string]string, _ error) {
   293  	stub.MethodCall(stub, "Read", serviceName)
   294  	result, stub.results = stub.results[0], stub.results[1:]
   295  	return result, stub.NextErr()
   296  }
   297  
   298  func (stub *StubLeadershipSettingsAccessor) Merge(serviceName string, settings map[string]string) error {
   299  	stub.MethodCall(stub, "Merge", serviceName, settings)
   300  	return stub.NextErr()
   301  }
   302  
   303  type StubTracker struct {
   304  	leadership.Tracker
   305  	*testing.Stub
   306  	serviceName string
   307  	results     []StubTicket
   308  }
   309  
   310  func (stub *StubTracker) ApplicationName() string {
   311  	stub.MethodCall(stub, "ApplicationName")
   312  	return stub.serviceName
   313  }
   314  
   315  func (stub *StubTracker) ClaimLeader() (result leadership.Ticket) {
   316  	stub.MethodCall(stub, "ClaimLeader")
   317  	result, stub.results = stub.results[0], stub.results[1:]
   318  	return result
   319  }
   320  
   321  type StubTicket bool
   322  
   323  func (ticket StubTicket) Wait() bool {
   324  	return bool(ticket)
   325  }
   326  
   327  func (ticket StubTicket) Ready() <-chan struct{} {
   328  	return alwaysReady
   329  }
   330  
   331  var alwaysReady = make(chan struct{})
   332  
   333  func init() {
   334  	close(alwaysReady)
   335  }