github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/operation/factory_test.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package operation_test 5 6 import ( 7 "github.com/juju/charm/v12/hooks" 8 "github.com/juju/loggo" 9 "github.com/juju/names/v5" 10 "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 utilexec "github.com/juju/utils/v3/exec" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/api/agent/uniter" 16 basetesting "github.com/juju/juju/api/base/testing" 17 "github.com/juju/juju/rpc/params" 18 "github.com/juju/juju/worker/common/charmrunner" 19 "github.com/juju/juju/worker/uniter/hook" 20 "github.com/juju/juju/worker/uniter/operation" 21 ) 22 23 type FactorySuite struct { 24 testing.IsolationSuite 25 factory operation.Factory 26 actionErr *params.Error 27 } 28 29 var _ = gc.Suite(&FactorySuite{}) 30 31 func (s *FactorySuite) SetUpTest(c *gc.C) { 32 s.IsolationSuite.SetUpTest(c) 33 // Yes, this factory will produce useless ops; this suite is just for 34 // verifying that inadequate args to the factory methods will produce 35 // the expected errors; and that the results of same get a string 36 // representation that does not depend on the factory attributes. 37 deployer := &MockDeployer{ 38 MockNotifyRevert: &MockNoArgs{}, 39 MockNotifyResolved: &MockNoArgs{}, 40 } 41 s.actionErr = nil 42 apiCaller := basetesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { 43 actionResult := params.ActionResult{ 44 Action: ¶ms.Action{Name: "backup"}, 45 } 46 if s.actionErr != nil { 47 actionResult = params.ActionResult{Error: s.actionErr} 48 } 49 *(result.(*params.ActionResults)) = params.ActionResults{ 50 Results: []params.ActionResult{actionResult}, 51 } 52 return nil 53 }) 54 st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) 55 s.factory = operation.NewFactory(operation.FactoryParams{ 56 State: st, 57 Deployer: deployer, 58 Logger: loggo.GetLogger("test"), 59 }) 60 } 61 62 func (s *FactorySuite) testNewDeployError(c *gc.C, newDeploy newDeploy) { 63 op, err := newDeploy(s.factory, "") 64 c.Check(op, gc.IsNil) 65 c.Check(err, gc.ErrorMatches, "charm url required") 66 } 67 68 func (s *FactorySuite) TestNewInstallError(c *gc.C) { 69 s.testNewDeployError(c, (operation.Factory).NewInstall) 70 } 71 72 func (s *FactorySuite) TestNewUpgradeError(c *gc.C) { 73 s.testNewDeployError(c, (operation.Factory).NewUpgrade) 74 } 75 76 func (s *FactorySuite) TestNewRevertUpgradeError(c *gc.C) { 77 s.testNewDeployError(c, (operation.Factory).NewRevertUpgrade) 78 } 79 80 func (s *FactorySuite) TestNewResolvedUpgradeError(c *gc.C) { 81 s.testNewDeployError(c, (operation.Factory).NewResolvedUpgrade) 82 } 83 84 func (s *FactorySuite) testNewDeployString(c *gc.C, newDeploy newDeploy, expectPrefix string) { 85 op, err := newDeploy(s.factory, "ch:quantal/wordpress-1") 86 c.Check(err, jc.ErrorIsNil) 87 c.Check(op.String(), gc.Equals, expectPrefix+" ch:quantal/wordpress-1") 88 } 89 90 func (s *FactorySuite) TestNewInstallString(c *gc.C) { 91 s.testNewDeployString(c, (operation.Factory).NewInstall, "install") 92 } 93 94 func (s *FactorySuite) TestNewUpgradeString(c *gc.C) { 95 s.testNewDeployString(c, (operation.Factory).NewUpgrade, "upgrade to") 96 } 97 98 func (s *FactorySuite) TestNewRevertUpgradeString(c *gc.C) { 99 s.testNewDeployString(c, 100 (operation.Factory).NewRevertUpgrade, 101 "switch upgrade to", 102 ) 103 } 104 105 func (s *FactorySuite) TestNewResolvedUpgradeString(c *gc.C) { 106 s.testNewDeployString(c, 107 (operation.Factory).NewResolvedUpgrade, 108 "continue upgrade to", 109 ) 110 } 111 112 func (s *FactorySuite) TestNewActionError(c *gc.C) { 113 op, err := s.factory.NewAction("lol-something") 114 c.Check(op, gc.IsNil) 115 c.Check(err, gc.ErrorMatches, `invalid action id "lol-something"`) 116 } 117 118 func (s *FactorySuite) TestNewActionString(c *gc.C) { 119 op, err := s.factory.NewAction(someActionId) 120 c.Check(err, jc.ErrorIsNil) 121 c.Check(op.String(), gc.Equals, "run action "+someActionId) 122 } 123 124 func panicSendResponse(*utilexec.ExecResponse, error) bool { 125 panic("don't call this") 126 } 127 128 func commandArgs(commands string, relationId int, remoteUnit string) operation.CommandArgs { 129 return operation.CommandArgs{ 130 Commands: commands, 131 RelationId: relationId, 132 RemoteUnitName: remoteUnit, 133 // TODO(jam): 2019-10-24 Include RemoteAppName 134 } 135 } 136 137 func (s *FactorySuite) TestNewCommandsSendResponseError(c *gc.C) { 138 op, err := s.factory.NewCommands(commandArgs("anything", -1, ""), nil) 139 c.Check(op, gc.IsNil) 140 c.Check(err, gc.ErrorMatches, "response sender required") 141 } 142 143 func (s *FactorySuite) testNewCommandsArgsError( 144 c *gc.C, args operation.CommandArgs, expect string, 145 ) { 146 op, err := s.factory.NewCommands(args, panicSendResponse) 147 c.Check(op, gc.IsNil) 148 c.Check(err, gc.ErrorMatches, expect) 149 } 150 151 func (s *FactorySuite) TestNewCommandsArgsError_NoCommand(c *gc.C) { 152 s.testNewCommandsArgsError(c, 153 commandArgs("", -1, ""), 154 "commands required", 155 ) 156 } 157 158 func (s *FactorySuite) TestNewCommandsArgsError_BadRemoteUnit(c *gc.C) { 159 s.testNewCommandsArgsError(c, 160 commandArgs("any old thing", -1, "unit/1"), 161 "remote unit not valid without relation", 162 ) 163 } 164 165 func (s *FactorySuite) TestNewCommandsArgsError_BadRemoteUnitName(c *gc.C) { 166 s.testNewCommandsArgsError(c, 167 commandArgs("any old thing", 0, "lol"), 168 `invalid remote unit name "lol"`, 169 ) 170 } 171 172 func (s *FactorySuite) testNewCommandsString( 173 c *gc.C, args operation.CommandArgs, expect string, 174 ) { 175 op, err := s.factory.NewCommands(args, panicSendResponse) 176 c.Check(err, jc.ErrorIsNil) 177 c.Check(op.String(), gc.Equals, expect) 178 } 179 180 func (s *FactorySuite) TestNewCommandsString_CommandsOnly(c *gc.C) { 181 s.testNewCommandsString(c, 182 commandArgs("anything", -1, ""), 183 "run commands", 184 ) 185 } 186 187 func (s *FactorySuite) TestNewCommandsString_WithRelation(c *gc.C) { 188 s.testNewCommandsString(c, 189 commandArgs("anything", 0, ""), 190 "run commands (0)", 191 ) 192 } 193 194 func (s *FactorySuite) TestNewCommandsString_WithRelationAndUnit(c *gc.C) { 195 s.testNewCommandsString(c, 196 commandArgs("anything", 3, "unit/123"), 197 "run commands (3; unit/123)", 198 ) 199 } 200 201 func (s *FactorySuite) testNewHookError(c *gc.C, newHook newHook) { 202 op, err := newHook(s.factory, hook.Info{Kind: hooks.Kind("gibberish")}) 203 c.Check(op, gc.IsNil) 204 c.Check(err, gc.ErrorMatches, `unknown hook kind "gibberish"`) 205 } 206 207 func (s *FactorySuite) TestNewHookError_Run(c *gc.C) { 208 s.testNewHookError(c, (operation.Factory).NewRunHook) 209 } 210 211 func (s *FactorySuite) TestNewHookError_Skip(c *gc.C) { 212 s.testNewHookError(c, (operation.Factory).NewSkipHook) 213 } 214 215 func (s *FactorySuite) TestNewHookString_Run(c *gc.C) { 216 op, err := s.factory.NewRunHook(hook.Info{Kind: hooks.Install}) 217 c.Check(err, jc.ErrorIsNil) 218 c.Check(op.String(), gc.Equals, "run install hook") 219 } 220 221 func (s *FactorySuite) TestNewHookString_Skip(c *gc.C) { 222 op, err := s.factory.NewSkipHook(hook.Info{ 223 Kind: hooks.RelationJoined, 224 RemoteUnit: "foo/22", 225 RemoteApplication: "foo/22", 226 RelationId: 123, 227 }) 228 c.Assert(err, jc.ErrorIsNil) 229 c.Check(op.String(), gc.Equals, "skip run relation-joined (123; unit: foo/22) hook") 230 } 231 232 func (s *FactorySuite) TestNewAcceptLeadershipString(c *gc.C) { 233 op, err := s.factory.NewAcceptLeadership() 234 c.Assert(err, jc.ErrorIsNil) 235 c.Assert(op.String(), gc.Equals, "accept leadership") 236 } 237 238 func (s *FactorySuite) TestNewResignLeadershipString(c *gc.C) { 239 op, err := s.factory.NewResignLeadership() 240 c.Assert(err, jc.ErrorIsNil) 241 c.Assert(op.String(), gc.Equals, "resign leadership") 242 } 243 244 func (s *FactorySuite) TestNewActionNotAvailable(c *gc.C) { 245 s.actionErr = ¶ms.Error{Code: "action no longer available"} 246 rnr, err := s.factory.NewAction("666") 247 c.Assert(rnr, gc.IsNil) 248 c.Assert(err, gc.Equals, charmrunner.ErrActionNotAvailable) 249 } 250 251 func (s *FactorySuite) TestNewActionUnauthorised(c *gc.C) { 252 s.actionErr = ¶ms.Error{Code: "unauthorized access"} 253 rnr, err := s.factory.NewAction("666") 254 c.Assert(rnr, gc.IsNil) 255 c.Assert(err, gc.Equals, charmrunner.ErrActionNotAvailable) 256 } 257 258 func (s *FactorySuite) TestNewNoOpSecretsRemoved(c *gc.C) { 259 op, err := s.factory.NewNoOpSecretsRemoved([]string{"secreturi"}) 260 c.Assert(err, jc.ErrorIsNil) 261 c.Assert(op.String(), gc.Equals, "process removed secrets: [secreturi]") 262 }