github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/relation/relationer_test.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package relation_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/charm/v12"
    10  	"github.com/juju/charm/v12/hooks"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	jc "github.com/juju/testing/checkers"
    14  	"go.uber.org/mock/gomock"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	apiuniter "github.com/juju/juju/api/agent/uniter"
    18  	"github.com/juju/juju/rpc/params"
    19  	"github.com/juju/juju/worker/uniter/hook"
    20  	"github.com/juju/juju/worker/uniter/relation"
    21  	"github.com/juju/juju/worker/uniter/relation/mocks"
    22  )
    23  
    24  type relationerSuite struct {
    25  	stateManager *mocks.MockStateManager
    26  	relationUnit *mocks.MockRelationUnit
    27  	relation     *mocks.MockRelation
    28  	unitGetter   *mocks.MockUnitGetter
    29  }
    30  
    31  var _ = gc.Suite(&relationerSuite{})
    32  
    33  func (s *relationerSuite) TestImplicitRelationerPrepareHook(c *gc.C) {
    34  	defer s.setupMocks(c).Finish()
    35  	// Setup for test
    36  	s.expectEndpoint(implicitRelationEndpoint())
    37  
    38  	r := s.newRelationer()
    39  
    40  	// Hooks are not allowed.
    41  	_, err := r.PrepareHook(hook.Info{})
    42  	c.Assert(err, gc.ErrorMatches, `restart immediately`)
    43  }
    44  
    45  func (s *relationerSuite) TestImplicitRelationerCommitHook(c *gc.C) {
    46  	defer s.setupMocks(c).Finish()
    47  	// Setup for test
    48  	s.expectEndpoint(implicitRelationEndpoint())
    49  
    50  	r := s.newRelationer()
    51  
    52  	// Hooks are not allowed.
    53  	err := r.CommitHook(hook.Info{})
    54  	c.Assert(err, gc.ErrorMatches, `restart immediately`)
    55  }
    56  
    57  func (s *relationerSuite) TestImplicitRelationerSetDying(c *gc.C) {
    58  	defer s.setupMocks(c).Finish()
    59  	// Setup for test
    60  	s.expectEndpoint(implicitRelationEndpoint())
    61  	s.expectLeaveScope()
    62  	s.expectRemoveRelation()
    63  
    64  	r := s.newRelationer()
    65  
    66  	// Set it to Dying
    67  	c.Assert(r.IsDying(), jc.IsFalse)
    68  	err := r.SetDying()
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(r.IsDying(), jc.IsTrue)
    71  }
    72  
    73  func (s *relationerSuite) TestSetDying(c *gc.C) {
    74  	defer s.setupMocks(c).Finish()
    75  	// Setup for test
    76  	s.expectEndpoint(endpoint())
    77  
    78  	r := s.newRelationer()
    79  
    80  	// Set it to Dying
    81  	c.Assert(r.IsDying(), jc.IsFalse)
    82  	err := r.SetDying()
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	c.Assert(r.IsDying(), jc.IsTrue)
    85  }
    86  
    87  func (s *relationerSuite) TestIfDyingFailJoin(c *gc.C) {
    88  	defer s.setupMocks(c).Finish()
    89  	// Setup for test
    90  	s.expectEndpoint(endpoint())
    91  
    92  	r := s.newRelationer()
    93  
    94  	// Set it to Dying
    95  	err := r.SetDying()
    96  	c.Assert(err, jc.ErrorIsNil)
    97  
    98  	// Try to Join
    99  	err = r.Join()
   100  	c.Assert(err, gc.ErrorMatches, `dying relationer must not join!`)
   101  }
   102  
   103  func (s *relationerSuite) TestCommitHookRelationBrokenDies(c *gc.C) {
   104  	defer s.setupMocks(c).Finish()
   105  	// Setup for test
   106  	s.expectEndpoint(endpoint())
   107  	s.expectLeaveScope()
   108  	s.expectRemoveRelation()
   109  
   110  	r := s.newRelationer()
   111  
   112  	err := r.CommitHook(hook.Info{Kind: hooks.RelationBroken})
   113  	c.Assert(err, jc.ErrorIsNil)
   114  }
   115  
   116  func (s *relationerSuite) TestCommitHookRelationRemoved(c *gc.C) {
   117  	defer s.setupMocks(c).Finish()
   118  	// Setup for test
   119  	s.expectEndpoint(endpoint())
   120  	s.relationUnit.EXPECT().LeaveScope().Return(&params.Error{Code: "not found"})
   121  	s.expectRemoveRelation()
   122  
   123  	r := s.newRelationer()
   124  
   125  	err := r.CommitHook(hook.Info{Kind: hooks.RelationBroken})
   126  	c.Assert(err, jc.ErrorIsNil)
   127  }
   128  
   129  func (s *relationerSuite) TestCommitHook(c *gc.C) {
   130  	defer s.setupMocks(c).Finish()
   131  	// Setup for test
   132  	s.expectEndpoint(endpoint())
   133  	s.expectStateManagerRelation(nil)
   134  	s.expectSetRelation()
   135  
   136  	r := s.newRelationer()
   137  
   138  	err := r.CommitHook(hook.Info{Kind: hooks.RelationJoined, RelationId: 1})
   139  	c.Assert(err, jc.ErrorIsNil)
   140  }
   141  
   142  func (s *relationerSuite) TestCommitHookRelationFail(c *gc.C) {
   143  	defer s.setupMocks(c).Finish()
   144  	// Setup for test
   145  	s.expectEndpoint(endpoint())
   146  	s.expectStateManagerRelation(errors.NotImplementedf("testing"))
   147  
   148  	r := s.newRelationer()
   149  
   150  	err := r.CommitHook(hook.Info{Kind: hooks.RelationJoined, RelationId: 1})
   151  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   152  }
   153  
   154  func (s *relationerSuite) TestPrepareHookRelationFail(c *gc.C) {
   155  	defer s.setupMocks(c).Finish()
   156  	// Setup for test
   157  	s.expectEndpoint(endpoint())
   158  	s.expectStateManagerRelation(errors.NotImplementedf("testing"))
   159  
   160  	r := s.newRelationer()
   161  
   162  	_, err := r.PrepareHook(hook.Info{Kind: hooks.RelationJoined, RelationId: 1})
   163  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   164  }
   165  
   166  func (s *relationerSuite) TestPrepareHookValidateFail(c *gc.C) {
   167  	defer s.setupMocks(c).Finish()
   168  	// Setup for test
   169  	s.expectEndpoint(endpoint())
   170  	s.expectStateManagerRelationFailValidate()
   171  
   172  	r := s.newRelationer()
   173  
   174  	// relationID and state id being different will fail validation.
   175  	name, err := r.PrepareHook(hook.Info{Kind: hooks.RelationJoined, RelationId: 1})
   176  	c.Assert(err, gc.NotNil)
   177  	c.Assert(name, gc.Equals, "")
   178  }
   179  
   180  func (s *relationerSuite) TestPrepareHook(c *gc.C) {
   181  	defer s.setupMocks(c).Finish()
   182  	// Setup for test
   183  	ep := endpoint()
   184  	s.expectEndpoint(ep)
   185  	s.expectEndpoint(ep)
   186  	s.expectStateManagerRelation(nil)
   187  
   188  	r := s.newRelationer()
   189  
   190  	name, err := r.PrepareHook(hook.Info{Kind: hooks.RelationJoined, RelationId: 1})
   191  	c.Assert(err, jc.ErrorIsNil)
   192  	c.Assert(name, gc.Equals, fmt.Sprintf("%s-%s", ep.Name, hooks.RelationJoined))
   193  }
   194  
   195  func (s *relationerSuite) TestJoinRelation(c *gc.C) {
   196  	defer s.setupMocks(c).Finish()
   197  	// Setup for test
   198  	s.expectEnterScope()
   199  	s.expectRelationFound(true)
   200  
   201  	r := s.newRelationer()
   202  
   203  	err := r.Join()
   204  	c.Assert(err, jc.ErrorIsNil)
   205  }
   206  
   207  func (s *relationerSuite) TestJoinRelationNotFound(c *gc.C) {
   208  	defer s.setupMocks(c).Finish()
   209  	// Setup for test
   210  	s.expectEnterScope()
   211  	s.expectRelationFound(false)
   212  	s.expectSetRelation()
   213  
   214  	r := s.newRelationer()
   215  	err := r.Join()
   216  	c.Assert(err, jc.ErrorIsNil)
   217  }
   218  
   219  func (s *relationerSuite) newRelationer() relation.Relationer {
   220  	logger := loggo.GetLogger("test")
   221  	return relation.NewRelationer(s.relationUnit, s.stateManager, s.unitGetter, logger)
   222  }
   223  
   224  func (s *relationerSuite) setupMocks(c *gc.C) *gomock.Controller {
   225  	ctrl := gomock.NewController(c)
   226  	s.stateManager = mocks.NewMockStateManager(ctrl)
   227  	s.relationUnit = mocks.NewMockRelationUnit(ctrl)
   228  	s.relation = mocks.NewMockRelation(ctrl)
   229  	s.unitGetter = mocks.NewMockUnitGetter(ctrl)
   230  	// Setup for NewRelationer
   231  	s.expectRelationUnitRelation()
   232  	s.expectRelationId()
   233  	return ctrl
   234  }
   235  
   236  func implicitRelationEndpoint() apiuniter.Endpoint {
   237  	return apiuniter.Endpoint{
   238  		charm.Relation{
   239  			Role:      charm.RoleProvider,
   240  			Name:      "juju-info",
   241  			Interface: "juju-info",
   242  		}}
   243  }
   244  
   245  func endpoint() apiuniter.Endpoint {
   246  	return apiuniter.Endpoint{
   247  		charm.Relation{
   248  			Role:      charm.RoleRequirer,
   249  			Name:      "mysql",
   250  			Interface: "db",
   251  			Scope:     charm.ScopeGlobal,
   252  		}}
   253  }
   254  
   255  // RelationUnit
   256  func (s *relationerSuite) expectEndpoint(ep apiuniter.Endpoint) {
   257  	s.relationUnit.EXPECT().Endpoint().Return(ep)
   258  }
   259  
   260  func (s *relationerSuite) expectLeaveScope() {
   261  	s.relationUnit.EXPECT().LeaveScope().Return(nil)
   262  }
   263  
   264  func (s *relationerSuite) expectEnterScope() {
   265  	s.relationUnit.EXPECT().EnterScope().Return(nil)
   266  }
   267  
   268  func (s *relationerSuite) expectRelationUnitRelation() {
   269  	s.relationUnit.EXPECT().Relation().Return(s.relation)
   270  }
   271  
   272  // Relation
   273  func (s *relationerSuite) expectRelationId() {
   274  	s.relation.EXPECT().Id().Return(1)
   275  }
   276  
   277  // StateManager
   278  func (s *relationerSuite) expectRemoveRelation() {
   279  	s.stateManager.EXPECT().RemoveRelation(1, s.unitGetter, map[string]bool{}).Return(nil)
   280  }
   281  
   282  func (s *relationerSuite) expectRelationFound(found bool) {
   283  	s.stateManager.EXPECT().RelationFound(1).Return(found)
   284  }
   285  
   286  func (s *relationerSuite) expectSetRelation() {
   287  	s.stateManager.EXPECT().SetRelation(gomock.Any()).Return(nil)
   288  }
   289  
   290  func (s *relationerSuite) expectStateManagerRelation(err error) {
   291  	st := relation.NewState(1)
   292  	s.stateManager.EXPECT().Relation(1).Return(st, err)
   293  }
   294  
   295  func (s *relationerSuite) expectStateManagerRelationFailValidate() {
   296  	st := relation.NewState(0)
   297  	s.stateManager.EXPECT().Relation(1).Return(st, nil)
   298  }