github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/leadership_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 jc "github.com/juju/testing/checkers" 10 "github.com/juju/utils/v3" 11 "go.uber.org/mock/gomock" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 commonmocks "github.com/juju/juju/apiserver/common/mocks" 16 apiservererrors "github.com/juju/juju/apiserver/errors" 17 apiservertesting "github.com/juju/juju/apiserver/testing" 18 "github.com/juju/juju/core/leadership/mocks" 19 "github.com/juju/juju/rpc/params" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type LeadershipSuite struct { 24 coretesting.BaseSuite 25 26 backend *commonmocks.MockLeadershipPinningBackend 27 machine *commonmocks.MockLeadershipMachine 28 pinner *mocks.MockPinner 29 30 modelTag names.ModelTag 31 authTag names.Tag 32 api *common.LeadershipPinning 33 machineApps []string 34 } 35 36 var _ = gc.Suite(&LeadershipSuite{}) 37 38 func (s *LeadershipSuite) SetUpSuite(c *gc.C) { 39 s.BaseSuite.SetUpSuite(c) 40 41 s.modelTag = names.NewModelTag(utils.MustNewUUID().String()) 42 s.machineApps = []string{"mysql", "redis", "wordpress"} 43 } 44 45 func (s *LeadershipSuite) SetUpTest(c *gc.C) { 46 s.BaseSuite.SetUpTest(c) 47 s.authTag = nil 48 } 49 50 func (s *LeadershipSuite) TestPinnedLeadershipSuccess(c *gc.C) { 51 s.authTag = names.NewUserTag("admin") 52 defer s.setup(c).Finish() 53 54 pinned := map[string][]string{"redis": {"machine-0", "machine-1"}} 55 s.pinner.EXPECT().PinnedLeadership().Return(pinned, nil) 56 57 res, err := s.api.PinnedLeadership() 58 c.Assert(err, jc.ErrorIsNil) 59 c.Check(res.Result, gc.DeepEquals, pinned) 60 } 61 62 func (s *LeadershipSuite) TestPinnedLeadershipPermissionDenied(c *gc.C) { 63 defer s.setup(c).Finish() 64 65 _, err := s.api.PinnedLeadership() 66 c.Check(err, gc.ErrorMatches, "permission denied") 67 } 68 69 func (s *LeadershipSuite) TestPinApplicationLeadersSuccess(c *gc.C) { 70 defer s.setup(c).Finish() 71 72 for _, app := range s.machineApps { 73 s.pinner.EXPECT().PinLeadership(app, s.authTag.String()).Return(nil) 74 } 75 76 res, err := s.api.PinApplicationLeaders() 77 c.Assert(err, jc.ErrorIsNil) 78 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: s.pinApplicationsSuccessResults()}) 79 } 80 81 func (s *LeadershipSuite) TestPinApplicationLeadersPartialError(c *gc.C) { 82 defer s.setup(c).Finish() 83 84 errorRes := errors.New("boom") 85 s.pinner.EXPECT().PinLeadership("mysql", s.authTag.String()).Return(nil) 86 s.pinner.EXPECT().PinLeadership("redis", s.authTag.String()).Return(nil) 87 s.pinner.EXPECT().PinLeadership("wordpress", s.authTag.String()).Return(errorRes) 88 89 res, err := s.api.PinApplicationLeaders() 90 c.Assert(err, jc.ErrorIsNil) 91 92 results := s.pinApplicationsSuccessResults() 93 results[2].Error = apiservererrors.ServerError(errorRes) 94 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: results}) 95 } 96 97 func (s *LeadershipSuite) TestUnpinApplicationLeadersSuccess(c *gc.C) { 98 defer s.setup(c).Finish() 99 100 for _, app := range s.machineApps { 101 s.pinner.EXPECT().UnpinLeadership(app, s.authTag.String()).Return(nil) 102 } 103 104 res, err := s.api.UnpinApplicationLeaders() 105 c.Assert(err, jc.ErrorIsNil) 106 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: s.pinApplicationsSuccessResults()}) 107 } 108 109 func (s *LeadershipSuite) TestUnpinApplicationLeadersPartialError(c *gc.C) { 110 defer s.setup(c).Finish() 111 112 errorRes := errors.New("boom") 113 s.pinner.EXPECT().UnpinLeadership("mysql", s.authTag.String()).Return(nil) 114 s.pinner.EXPECT().UnpinLeadership("redis", s.authTag.String()).Return(errorRes) 115 s.pinner.EXPECT().UnpinLeadership("wordpress", s.authTag.String()).Return(nil) 116 117 res, err := s.api.UnpinApplicationLeaders() 118 c.Assert(err, jc.ErrorIsNil) 119 120 results := s.pinApplicationsSuccessResults() 121 results[1].Error = apiservererrors.ServerError(errorRes) 122 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: results}) 123 } 124 125 func (s *LeadershipSuite) TestPinApplicationLeadersPermissionDenied(c *gc.C) { 126 s.authTag = names.NewUserTag("some-random-cat") 127 defer s.setup(c).Finish() 128 129 _, err := s.api.PinApplicationLeaders() 130 c.Assert(err, gc.ErrorMatches, "permission denied") 131 132 _, err = s.api.UnpinApplicationLeaders() 133 c.Assert(err, gc.ErrorMatches, "permission denied") 134 } 135 136 func (s *LeadershipSuite) TestGetMachineApplicationNamesSuccess(c *gc.C) { 137 defer s.setup(c).Finish() 138 139 appNames, err := s.api.GetMachineApplicationNames(s.authTag.Id()) 140 c.Assert(err, jc.ErrorIsNil) 141 c.Check(appNames, gc.DeepEquals, s.machineApps) 142 } 143 144 func (s *LeadershipSuite) TestPinApplicationLeadersByNameSuccess(c *gc.C) { 145 defer s.setup(c).Finish() 146 147 for _, app := range s.machineApps { 148 s.pinner.EXPECT().PinLeadership(app, s.authTag.String()).Return(nil) 149 } 150 151 res, err := s.api.PinApplicationLeadersByName(s.authTag, s.machineApps) 152 c.Assert(err, jc.ErrorIsNil) 153 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: s.pinApplicationsSuccessResults()}) 154 } 155 156 func (s *LeadershipSuite) TestPinApplicationLeadersByNamePartialError(c *gc.C) { 157 defer s.setup(c).Finish() 158 159 errorRes := errors.New("boom") 160 s.pinner.EXPECT().PinLeadership("mysql", s.authTag.String()).Return(nil) 161 s.pinner.EXPECT().PinLeadership("redis", s.authTag.String()).Return(errorRes) 162 s.pinner.EXPECT().PinLeadership("wordpress", s.authTag.String()).Return(nil) 163 164 res, err := s.api.PinApplicationLeadersByName(s.authTag, s.machineApps) 165 c.Assert(err, jc.ErrorIsNil) 166 167 results := s.pinApplicationsSuccessResults() 168 results[1].Error = apiservererrors.ServerError(errorRes) 169 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: results}) 170 } 171 172 func (s *LeadershipSuite) TestUnpinApplicationLeadersByNameSuccess(c *gc.C) { 173 defer s.setup(c).Finish() 174 175 for _, app := range s.machineApps { 176 s.pinner.EXPECT().UnpinLeadership(app, s.authTag.String()).Return(nil) 177 } 178 179 res, err := s.api.UnpinApplicationLeadersByName(s.authTag, s.machineApps) 180 c.Assert(err, jc.ErrorIsNil) 181 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: s.pinApplicationsSuccessResults()}) 182 } 183 184 func (s *LeadershipSuite) TestUnpinApplicationLeadersByNamePartialError(c *gc.C) { 185 defer s.setup(c).Finish() 186 187 errorRes := errors.New("boom") 188 s.pinner.EXPECT().UnpinLeadership("mysql", s.authTag.String()).Return(nil) 189 s.pinner.EXPECT().UnpinLeadership("redis", s.authTag.String()).Return(errorRes) 190 s.pinner.EXPECT().UnpinLeadership("wordpress", s.authTag.String()).Return(nil) 191 192 res, err := s.api.UnpinApplicationLeadersByName(s.authTag, s.machineApps) 193 c.Assert(err, jc.ErrorIsNil) 194 195 results := s.pinApplicationsSuccessResults() 196 results[1].Error = apiservererrors.ServerError(errorRes) 197 c.Check(res, gc.DeepEquals, params.PinApplicationsResults{Results: results}) 198 } 199 200 func (s *LeadershipSuite) setup(c *gc.C) *gomock.Controller { 201 ctrl := gomock.NewController(c) 202 203 s.backend = commonmocks.NewMockLeadershipPinningBackend(ctrl) 204 s.machine = commonmocks.NewMockLeadershipMachine(ctrl) 205 s.pinner = mocks.NewMockPinner(ctrl) 206 207 s.backend.EXPECT().Machine("0").Return(s.machine, nil).AnyTimes() 208 s.machine.EXPECT().ApplicationNames().Return(s.machineApps, nil).AnyTimes() 209 210 if s.authTag == nil { 211 s.authTag = names.NewMachineTag("0") 212 } 213 214 var err error 215 s.api, err = common.NewLeadershipPinning( 216 s.backend, 217 s.modelTag, 218 s.pinner, 219 &apiservertesting.FakeAuthorizer{Tag: s.authTag}, 220 ) 221 c.Assert(err, jc.ErrorIsNil) 222 223 return ctrl 224 } 225 226 func (s *LeadershipSuite) pinApplicationsSuccessResults() []params.PinApplicationResult { 227 results := make([]params.PinApplicationResult, len(s.machineApps)) 228 for i, app := range s.machineApps { 229 results[i] = params.PinApplicationResult{ApplicationName: app} 230 } 231 return results 232 }