github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/unitstate_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "github.com/juju/loggo" 8 "github.com/juju/names/v5" 9 jc "github.com/juju/testing/checkers" 10 "go.uber.org/mock/gomock" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/common/mocks" 15 apiservertesting "github.com/juju/juju/apiserver/testing" 16 "github.com/juju/juju/controller" 17 "github.com/juju/juju/rpc/params" 18 "github.com/juju/juju/state" 19 "github.com/juju/juju/testing" 20 ) 21 22 type unitStateSuite struct { 23 testing.BaseSuite 24 25 unitTag1 names.UnitTag 26 27 api *common.UnitStateAPI 28 mockBackend *mocks.MockUnitStateBackend 29 mockUnit *mocks.MockUnitStateUnit 30 mockOp *mocks.MockModelOperation 31 } 32 33 var _ = gc.Suite(&unitStateSuite{}) 34 35 func (s *unitStateSuite) SetUpTest(c *gc.C) { 36 s.unitTag1 = names.NewUnitTag("wordpress/0") 37 } 38 39 func (s *unitStateSuite) assertBackendApi(c *gc.C) *gomock.Controller { 40 resources := common.NewResources() 41 authorizer := apiservertesting.FakeAuthorizer{ 42 Tag: s.unitTag1, 43 } 44 45 ctrl := gomock.NewController(c) 46 s.mockBackend = mocks.NewMockUnitStateBackend(ctrl) 47 s.mockUnit = mocks.NewMockUnitStateUnit(ctrl) 48 s.mockOp = mocks.NewMockModelOperation(ctrl) 49 50 unitAuthFunc := func() (common.AuthFunc, error) { 51 return func(tag names.Tag) bool { 52 if tag.Id() == s.unitTag1.Id() { 53 return true 54 } 55 return false 56 }, nil 57 } 58 59 s.api = common.NewUnitStateAPI( 60 s.mockBackend, resources, authorizer, unitAuthFunc, loggo.GetLogger("juju.apiserver.common")) 61 return ctrl 62 } 63 64 func (s *unitStateSuite) expectState() (map[string]string, string, map[int]string, string, string) { 65 expCharmState := map[string]string{ 66 "foo.bar": "baz", 67 "payload$": "enc0d3d", 68 } 69 expUniterState := "testing" 70 expRelationState := map[int]string{ 71 1: "one", 72 2: "two", 73 } 74 expStorageState := "storage testing" 75 expSecretState := "secret testing" 76 77 unitState := state.NewUnitState() 78 unitState.SetCharmState(expCharmState) 79 unitState.SetUniterState(expUniterState) 80 unitState.SetRelationState(expRelationState) 81 unitState.SetStorageState(expStorageState) 82 unitState.SetSecretState(expSecretState) 83 84 exp := s.mockUnit.EXPECT() 85 exp.State().Return(unitState, nil) 86 87 return expCharmState, expUniterState, expRelationState, expStorageState, expSecretState 88 } 89 90 func (s *unitStateSuite) expectUnit() { 91 exp := s.mockBackend.EXPECT() 92 exp.Unit(s.unitTag1.Id()).Return(s.mockUnit, nil) 93 } 94 95 func (s *unitStateSuite) expectSetStateOperation() string { 96 unitState := state.NewUnitState() 97 expUniterState := "testing" 98 unitState.SetUniterState(expUniterState) 99 100 // Mock controller config which provides the limits passed to SetStateOperation. 101 s.mockBackend.EXPECT().ControllerConfig().Return( 102 controller.Config{ 103 "max-charm-state-size": 123, 104 "max-agent-state-size": 456, 105 }, nil) 106 107 exp := s.mockUnit.EXPECT() 108 exp.SetStateOperation( 109 unitState, 110 state.UnitStateSizeLimits{ 111 MaxCharmStateSize: 123, 112 MaxAgentStateSize: 456, 113 }, 114 ).Return(s.mockOp) 115 return expUniterState 116 } 117 118 func (s *unitStateSuite) expectApplyOperation() { 119 exp := s.mockBackend.EXPECT() 120 exp.ApplyOperation(s.mockOp).Return(nil) 121 } 122 123 func (s *unitStateSuite) TestState(c *gc.C) { 124 defer s.assertBackendApi(c).Finish() 125 s.expectUnit() 126 expCharmState, expUniterState, expRelationState, expStorageState, expSecretState := s.expectState() 127 128 args := params.Entities{ 129 Entities: []params.Entity{ 130 {Tag: "not-a-unit-tag"}, 131 {Tag: "unit-wordpress-0"}, 132 {Tag: "unit-mysql-0"}, // not accessible by current user 133 {Tag: "unit-notfound-0"}, 134 }, 135 } 136 result, err := s.api.State(args) 137 c.Assert(err, jc.ErrorIsNil) 138 c.Assert(result, gc.DeepEquals, params.UnitStateResults{ 139 Results: []params.UnitStateResult{ 140 {Error: ¶ms.Error{Message: `"not-a-unit-tag" is not a valid tag`}}, 141 { 142 Error: nil, 143 CharmState: expCharmState, 144 UniterState: expUniterState, 145 RelationState: expRelationState, 146 StorageState: expStorageState, 147 SecretState: expSecretState, 148 }, 149 {Error: apiservertesting.ErrUnauthorized}, 150 {Error: apiservertesting.ErrUnauthorized}, 151 }, 152 }) 153 } 154 155 func (s *unitStateSuite) TestSetStateUniterState(c *gc.C) { 156 defer s.assertBackendApi(c).Finish() 157 s.expectUnit() 158 expUniterState := s.expectSetStateOperation() 159 s.expectApplyOperation() 160 161 args := params.SetUnitStateArgs{ 162 Args: []params.SetUnitStateArg{ 163 {Tag: "not-a-unit-tag", UniterState: &expUniterState}, 164 {Tag: "unit-wordpress-0", UniterState: &expUniterState}, 165 {Tag: "unit-mysql-0", UniterState: &expUniterState}, // not accessible by current user 166 {Tag: "unit-notfound-0", UniterState: &expUniterState}, 167 }, 168 } 169 170 result, err := s.api.SetState(args) 171 c.Assert(err, jc.ErrorIsNil) 172 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 173 Results: []params.ErrorResult{ 174 {Error: ¶ms.Error{Message: `"not-a-unit-tag" is not a valid tag`}}, 175 {Error: nil}, 176 {Error: apiservertesting.ErrUnauthorized}, 177 {Error: apiservertesting.ErrUnauthorized}, 178 }, 179 }) 180 }