github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/uniter/leadership_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_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/api/agent/uniter"
    13  	"github.com/juju/juju/core/watcher"
    14  	"github.com/juju/juju/rpc/params"
    15  )
    16  
    17  type leadershipSuite struct {
    18  	testing.IsolationSuite
    19  	stub       *testing.Stub
    20  	responders []responder
    21  	lsa        *uniter.LeadershipSettingsAccessor
    22  }
    23  
    24  var _ = gc.Suite(&leadershipSuite{})
    25  
    26  type responder func(interface{})
    27  
    28  var mockWatcher = struct{ watcher.NotifyWatcher }{}
    29  
    30  func (s *leadershipSuite) SetUpTest(c *gc.C) {
    31  	s.IsolationSuite.SetUpTest(c)
    32  	s.lsa = uniter.NewLeadershipSettingsAccessor(
    33  		func(request string, params, response interface{}) error {
    34  			s.stub.AddCall("FacadeCall", request, params)
    35  			s.nextResponse(response)
    36  			return s.stub.NextErr()
    37  		},
    38  		func(result params.NotifyWatchResult) watcher.NotifyWatcher {
    39  			s.stub.AddCall("NewNotifyWatcher", result)
    40  			return mockWatcher
    41  		},
    42  	)
    43  }
    44  
    45  func (s *leadershipSuite) nextResponse(response interface{}) {
    46  	var responder responder
    47  	responder, s.responders = s.responders[0], s.responders[1:]
    48  	if responder != nil {
    49  		responder(response)
    50  	}
    51  }
    52  
    53  func (s *leadershipSuite) addResponder(responder responder) {
    54  	s.responders = append(s.responders, responder)
    55  }
    56  
    57  func (s *leadershipSuite) CheckCalls(c *gc.C, calls []testing.StubCall, f func()) {
    58  	s.stub = &testing.Stub{}
    59  	s.responders = nil
    60  	f()
    61  	s.stub.CheckCalls(c, calls)
    62  }
    63  
    64  func (s *leadershipSuite) expectReadCalls() []testing.StubCall {
    65  	return []testing.StubCall{{
    66  		FuncName: "FacadeCall",
    67  		Args: []interface{}{
    68  			"Read",
    69  			params.Entities{Entities: []params.Entity{{
    70  				Tag: "application-foobar",
    71  			}}},
    72  		},
    73  	}}
    74  }
    75  
    76  func (s *leadershipSuite) TestReadSuccess(c *gc.C) {
    77  	s.CheckCalls(c, s.expectReadCalls(), func() {
    78  		s.addResponder(func(response interface{}) {
    79  			typed, ok := response.(*params.GetLeadershipSettingsBulkResults)
    80  			c.Assert(ok, jc.IsTrue)
    81  			typed.Results = []params.GetLeadershipSettingsResult{{
    82  				Settings: params.Settings{
    83  					"foo": "bar",
    84  					"baz": "qux",
    85  				},
    86  			}}
    87  		})
    88  		settings, err := s.lsa.Read("foobar")
    89  		c.Check(err, jc.ErrorIsNil)
    90  		c.Check(settings, jc.DeepEquals, map[string]string{
    91  			"foo": "bar",
    92  			"baz": "qux",
    93  		})
    94  	})
    95  }
    96  
    97  func (s *leadershipSuite) TestReadFailure(c *gc.C) {
    98  	s.CheckCalls(c, s.expectReadCalls(), func() {
    99  		s.addResponder(func(response interface{}) {
   100  			typed, ok := response.(*params.GetLeadershipSettingsBulkResults)
   101  			c.Assert(ok, jc.IsTrue)
   102  			typed.Results = []params.GetLeadershipSettingsResult{{
   103  				Error: &params.Error{Message: "pow"},
   104  			}}
   105  		})
   106  		settings, err := s.lsa.Read("foobar")
   107  		c.Check(err, gc.ErrorMatches, "failed to read leadership settings: pow")
   108  		c.Check(settings, gc.IsNil)
   109  	})
   110  }
   111  
   112  func (s *leadershipSuite) TestReadError(c *gc.C) {
   113  	s.CheckCalls(c, s.expectReadCalls(), func() {
   114  		s.addResponder(nil)
   115  		s.stub.SetErrors(errors.New("blart"))
   116  		settings, err := s.lsa.Read("foobar")
   117  		c.Check(err, gc.ErrorMatches, "failed to call leadership api: blart")
   118  		c.Check(settings, gc.IsNil)
   119  	})
   120  }
   121  
   122  func (s *leadershipSuite) TestReadNoResults(c *gc.C) {
   123  	s.CheckCalls(c, s.expectReadCalls(), func() {
   124  		s.addResponder(nil)
   125  		settings, err := s.lsa.Read("foobar")
   126  		c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0")
   127  		c.Check(settings, gc.IsNil)
   128  	})
   129  }
   130  
   131  func (s *leadershipSuite) expectMergeCalls() []testing.StubCall {
   132  	return []testing.StubCall{{
   133  		FuncName: "FacadeCall",
   134  		Args: []interface{}{
   135  			"Merge",
   136  			params.MergeLeadershipSettingsBulkParams{
   137  				Params: []params.MergeLeadershipSettingsParam{{
   138  					ApplicationTag: "application-foobar",
   139  					UnitTag:        "unit-foobar-0",
   140  					Settings: map[string]string{
   141  						"foo": "bar",
   142  						"baz": "qux",
   143  					},
   144  				}},
   145  			},
   146  		},
   147  	}}
   148  }
   149  
   150  func (s *leadershipSuite) TestMergeSuccess(c *gc.C) {
   151  	s.CheckCalls(c, s.expectMergeCalls(), func() {
   152  		s.addResponder(func(response interface{}) {
   153  			typed, ok := response.(*params.ErrorResults)
   154  			c.Assert(ok, jc.IsTrue)
   155  			typed.Results = []params.ErrorResult{{
   156  				Error: nil,
   157  			}}
   158  		})
   159  		err := s.lsa.Merge("foobar", "foobar/0", map[string]string{
   160  			"foo": "bar",
   161  			"baz": "qux",
   162  		})
   163  		c.Check(err, jc.ErrorIsNil)
   164  	})
   165  }
   166  
   167  func (s *leadershipSuite) TestMergeFailure(c *gc.C) {
   168  	s.CheckCalls(c, s.expectMergeCalls(), func() {
   169  		s.addResponder(func(response interface{}) {
   170  			typed, ok := response.(*params.ErrorResults)
   171  			c.Assert(ok, jc.IsTrue)
   172  			typed.Results = []params.ErrorResult{{
   173  				Error: &params.Error{Message: "zap"},
   174  			}}
   175  		})
   176  		err := s.lsa.Merge("foobar", "foobar/0", map[string]string{
   177  			"foo": "bar",
   178  			"baz": "qux",
   179  		})
   180  		c.Check(err, gc.ErrorMatches, "failed to merge leadership settings: zap")
   181  	})
   182  }
   183  
   184  func (s *leadershipSuite) TestMergeError(c *gc.C) {
   185  	s.CheckCalls(c, s.expectMergeCalls(), func() {
   186  		s.addResponder(nil)
   187  		s.stub.SetErrors(errors.New("dink"))
   188  		err := s.lsa.Merge("foobar", "foobar/0", map[string]string{
   189  			"foo": "bar",
   190  			"baz": "qux",
   191  		})
   192  		c.Check(err, gc.ErrorMatches, "failed to call leadership api: dink")
   193  	})
   194  }
   195  
   196  func (s *leadershipSuite) TestMergeNoResults(c *gc.C) {
   197  	s.CheckCalls(c, s.expectMergeCalls(), func() {
   198  		s.addResponder(nil)
   199  		err := s.lsa.Merge("foobar", "foobar/0", map[string]string{
   200  			"foo": "bar",
   201  			"baz": "qux",
   202  		})
   203  		c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0")
   204  	})
   205  }
   206  
   207  func (s *leadershipSuite) expectWatchCalls() []testing.StubCall {
   208  	return []testing.StubCall{{
   209  		FuncName: "FacadeCall",
   210  		Args: []interface{}{
   211  			"WatchLeadershipSettings",
   212  			params.Entities{Entities: []params.Entity{{
   213  				Tag: "application-foobar",
   214  			}}},
   215  		},
   216  	}}
   217  }
   218  
   219  func (s *leadershipSuite) TestWatchSuccess(c *gc.C) {
   220  	expectCalls := append(s.expectWatchCalls(), testing.StubCall{
   221  		FuncName: "NewNotifyWatcher",
   222  		Args: []interface{}{
   223  			params.NotifyWatchResult{
   224  				NotifyWatcherId: "123",
   225  			},
   226  		},
   227  	})
   228  	s.CheckCalls(c, expectCalls, func() {
   229  		s.addResponder(func(response interface{}) {
   230  			typed, ok := response.(*params.NotifyWatchResults)
   231  			c.Assert(ok, jc.IsTrue)
   232  			typed.Results = []params.NotifyWatchResult{{
   233  				NotifyWatcherId: "123",
   234  			}}
   235  		})
   236  		watcher, err := s.lsa.WatchLeadershipSettings("foobar")
   237  		c.Check(err, jc.ErrorIsNil)
   238  		c.Check(watcher, gc.Equals, mockWatcher)
   239  	})
   240  }
   241  
   242  func (s *leadershipSuite) TestWatchFailure(c *gc.C) {
   243  	s.CheckCalls(c, s.expectWatchCalls(), func() {
   244  		s.addResponder(func(response interface{}) {
   245  			typed, ok := response.(*params.NotifyWatchResults)
   246  			c.Assert(ok, jc.IsTrue)
   247  			typed.Results = []params.NotifyWatchResult{{
   248  				Error: &params.Error{Message: "blah"},
   249  			}}
   250  		})
   251  		watcher, err := s.lsa.WatchLeadershipSettings("foobar")
   252  		c.Check(err, gc.ErrorMatches, "failed to watch leadership settings: blah")
   253  		c.Check(watcher, gc.IsNil)
   254  	})
   255  }
   256  
   257  func (s *leadershipSuite) TestWatchError(c *gc.C) {
   258  	s.CheckCalls(c, s.expectWatchCalls(), func() {
   259  		s.addResponder(nil)
   260  		s.stub.SetErrors(errors.New("snerk"))
   261  		watcher, err := s.lsa.WatchLeadershipSettings("foobar")
   262  		c.Check(err, gc.ErrorMatches, "failed to call leadership api: snerk")
   263  		c.Check(watcher, gc.IsNil)
   264  	})
   265  }
   266  
   267  func (s *leadershipSuite) TestWatchNoResults(c *gc.C) {
   268  	s.CheckCalls(c, s.expectWatchCalls(), func() {
   269  		s.addResponder(nil)
   270  		watcher, err := s.lsa.WatchLeadershipSettings("foobar")
   271  		c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0")
   272  		c.Check(watcher, gc.IsNil)
   273  	})
   274  }