github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/uniter/runner/factory_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package runner_test 5 6 import ( 7 "os" 8 "strings" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v6-unstable/hooks" 16 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/worker/uniter/hook" 19 "github.com/juju/juju/worker/uniter/runner" 20 "github.com/juju/juju/worker/uniter/runner/context" 21 runnertesting "github.com/juju/juju/worker/uniter/runner/testing" 22 ) 23 24 type FactorySuite struct { 25 ContextSuite 26 } 27 28 var _ = gc.Suite(&FactorySuite{}) 29 30 func (s *FactorySuite) AssertPaths(c *gc.C, rnr runner.Runner) { 31 c.Assert(runner.RunnerPaths(rnr), gc.DeepEquals, s.paths) 32 } 33 34 func (s *FactorySuite) TestNewCommandRunnerNoRelation(c *gc.C) { 35 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: -1}) 36 c.Assert(err, jc.ErrorIsNil) 37 s.AssertPaths(c, rnr) 38 } 39 40 func (s *FactorySuite) TestNewCommandRunnerRelationIdDoesNotExist(c *gc.C) { 41 for _, value := range []bool{true, false} { 42 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 43 RelationId: 12, ForceRemoteUnit: value, 44 }) 45 c.Check(err, gc.ErrorMatches, `unknown relation id: 12`) 46 } 47 } 48 49 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitInvalid(c *gc.C) { 50 for _, value := range []bool{true, false} { 51 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 52 RelationId: 0, RemoteUnitName: "blah", ForceRemoteUnit: value, 53 }) 54 c.Check(err, gc.ErrorMatches, `invalid remote unit: blah`) 55 } 56 } 57 58 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitInappropriate(c *gc.C) { 59 for _, value := range []bool{true, false} { 60 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 61 RelationId: -1, RemoteUnitName: "blah/123", ForceRemoteUnit: value, 62 }) 63 c.Check(err, gc.ErrorMatches, `remote unit provided without a relation: blah/123`) 64 } 65 } 66 67 func (s *FactorySuite) TestNewCommandRunnerEmptyRelation(c *gc.C) { 68 _, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 1}) 69 c.Check(err, gc.ErrorMatches, `cannot infer remote unit in empty relation 1`) 70 } 71 72 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitAmbiguous(c *gc.C) { 73 s.membership[1] = []string{"foo/0", "foo/1"} 74 _, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 1}) 75 c.Check(err, gc.ErrorMatches, `ambiguous remote unit; possibilities are \[foo/0 foo/1\]`) 76 } 77 78 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitMissing(c *gc.C) { 79 s.membership[0] = []string{"foo/0", "foo/1"} 80 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 81 RelationId: 0, RemoteUnitName: "blah/123", 82 }) 83 c.Check(err, gc.ErrorMatches, `unknown remote unit blah/123; possibilities are \[foo/0 foo/1\]`) 84 } 85 86 func (s *FactorySuite) TestNewCommandRunnerForceNoRemoteUnit(c *gc.C) { 87 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{ 88 RelationId: 0, ForceRemoteUnit: true, 89 }) 90 c.Assert(err, jc.ErrorIsNil) 91 s.AssertPaths(c, rnr) 92 } 93 94 func (s *FactorySuite) TestNewCommandRunnerForceRemoteUnitMissing(c *gc.C) { 95 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 96 RelationId: 0, RemoteUnitName: "blah/123", ForceRemoteUnit: true, 97 }) 98 c.Assert(err, gc.IsNil) 99 } 100 101 func (s *FactorySuite) TestNewCommandRunnerInferRemoteUnit(c *gc.C) { 102 s.membership[0] = []string{"foo/2"} 103 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 0}) 104 c.Assert(err, jc.ErrorIsNil) 105 s.AssertPaths(c, rnr) 106 } 107 108 func (s *FactorySuite) TestNewHookRunner(c *gc.C) { 109 rnr, err := s.factory.NewHookRunner(hook.Info{Kind: hooks.ConfigChanged}) 110 c.Assert(err, jc.ErrorIsNil) 111 s.AssertPaths(c, rnr) 112 } 113 114 func (s *FactorySuite) TestNewHookRunnerWithBadHook(c *gc.C) { 115 rnr, err := s.factory.NewHookRunner(hook.Info{}) 116 c.Assert(rnr, gc.IsNil) 117 c.Assert(err, gc.ErrorMatches, `unknown hook kind ""`) 118 } 119 120 func (s *FactorySuite) TestNewHookRunnerWithStorage(c *gc.C) { 121 // We need to set up a unit that has storage metadata defined. 122 ch := s.AddTestingCharm(c, "storage-block") 123 sCons := map[string]state.StorageConstraints{ 124 "data": {Pool: "", Size: 1024, Count: 1}, 125 } 126 service := s.AddTestingServiceWithStorage(c, "storage-block", ch, sCons) 127 s.machine = nil // allocate a new machine 128 unit := s.AddUnit(c, service) 129 130 storageAttachments, err := s.State.UnitStorageAttachments(unit.UnitTag()) 131 c.Assert(err, jc.ErrorIsNil) 132 c.Assert(storageAttachments, gc.HasLen, 1) 133 storageTag := storageAttachments[0].StorageInstance() 134 135 volume, err := s.State.StorageInstanceVolume(storageTag) 136 c.Assert(err, jc.ErrorIsNil) 137 volumeTag := volume.VolumeTag() 138 machineTag := s.machine.MachineTag() 139 140 err = s.State.SetVolumeInfo( 141 volumeTag, state.VolumeInfo{ 142 VolumeId: "vol-123", 143 Size: 456, 144 }, 145 ) 146 c.Assert(err, jc.ErrorIsNil) 147 err = s.State.SetVolumeAttachmentInfo( 148 machineTag, volumeTag, state.VolumeAttachmentInfo{ 149 DeviceName: "sdb", 150 }, 151 ) 152 c.Assert(err, jc.ErrorIsNil) 153 154 password, err := utils.RandomPassword() 155 err = unit.SetPassword(password) 156 c.Assert(err, jc.ErrorIsNil) 157 st := s.OpenAPIAs(c, unit.Tag(), password) 158 uniter, err := st.Uniter() 159 c.Assert(err, jc.ErrorIsNil) 160 161 contextFactory, err := context.NewContextFactory( 162 uniter, 163 unit.Tag().(names.UnitTag), 164 runnertesting.FakeTracker{}, 165 s.getRelationInfos, 166 s.storage, 167 s.paths, 168 ) 169 c.Assert(err, jc.ErrorIsNil) 170 factory, err := runner.NewFactory( 171 uniter, 172 s.paths, 173 contextFactory, 174 ) 175 c.Assert(err, jc.ErrorIsNil) 176 177 rnr, err := factory.NewHookRunner(hook.Info{ 178 Kind: hooks.StorageAttached, 179 StorageId: "data/0", 180 }) 181 c.Assert(err, jc.ErrorIsNil) 182 s.AssertPaths(c, rnr) 183 ctx := rnr.Context() 184 c.Assert(ctx.UnitName(), gc.Equals, "storage-block/0") 185 } 186 187 func (s *FactorySuite) TestNewHookRunnerWithRelation(c *gc.C) { 188 rnr, err := s.factory.NewHookRunner(hook.Info{ 189 Kind: hooks.RelationBroken, 190 RelationId: 1, 191 }) 192 c.Assert(err, jc.ErrorIsNil) 193 s.AssertPaths(c, rnr) 194 } 195 196 func (s *FactorySuite) TestNewHookRunnerWithBadRelation(c *gc.C) { 197 rnr, err := s.factory.NewHookRunner(hook.Info{ 198 Kind: hooks.RelationBroken, 199 RelationId: 12345, 200 }) 201 c.Assert(rnr, gc.IsNil) 202 c.Assert(err, gc.ErrorMatches, `unknown relation id: 12345`) 203 } 204 205 func (s *FactorySuite) TestNewActionRunnerGood(c *gc.C) { 206 s.SetCharm(c, "dummy") 207 action, err := s.State.EnqueueAction(s.unit.Tag(), "snapshot", map[string]interface{}{ 208 "outfile": "/some/file.bz2", 209 }) 210 c.Assert(err, jc.ErrorIsNil) 211 rnr, err := s.factory.NewActionRunner(action.Id()) 212 c.Assert(err, jc.ErrorIsNil) 213 s.AssertPaths(c, rnr) 214 ctx := rnr.Context() 215 data, err := ctx.ActionData() 216 c.Assert(err, jc.ErrorIsNil) 217 c.Assert(data, jc.DeepEquals, &context.ActionData{ 218 Name: "snapshot", 219 Tag: action.ActionTag(), 220 Params: map[string]interface{}{ 221 "outfile": "/some/file.bz2", 222 }, 223 ResultsMap: map[string]interface{}{}, 224 }) 225 vars, err := ctx.HookVars(s.paths) 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(len(vars) > 0, jc.IsTrue, gc.Commentf("expected HookVars but found none")) 228 combined := strings.Join(vars, "|") 229 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_NAME=snapshot(\|.*|$)`) 230 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_UUID=`+action.Id()+`(\|.*|$)`) 231 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_TAG=`+action.Tag().String()+`(\|.*|$)`) 232 } 233 234 func (s *FactorySuite) TestNewActionRunnerBadCharm(c *gc.C) { 235 rnr, err := s.factory.NewActionRunner("irrelevant") 236 c.Assert(rnr, gc.IsNil) 237 c.Assert(errors.Cause(err), jc.Satisfies, os.IsNotExist) 238 c.Assert(err, gc.Not(jc.Satisfies), runner.IsBadActionError) 239 } 240 241 func (s *FactorySuite) TestNewActionRunnerBadName(c *gc.C) { 242 s.SetCharm(c, "dummy") 243 action, err := s.State.EnqueueAction(s.unit.Tag(), "no-such-action", nil) 244 c.Assert(err, jc.ErrorIsNil) // this will fail when using AddAction on unit 245 rnr, err := s.factory.NewActionRunner(action.Id()) 246 c.Check(rnr, gc.IsNil) 247 c.Check(err, gc.ErrorMatches, "cannot run \"no-such-action\" action: not defined") 248 c.Check(err, jc.Satisfies, runner.IsBadActionError) 249 } 250 251 func (s *FactorySuite) TestNewActionRunnerBadParams(c *gc.C) { 252 s.SetCharm(c, "dummy") 253 action, err := s.State.EnqueueAction(s.unit.Tag(), "snapshot", map[string]interface{}{ 254 "outfile": 123, 255 }) 256 c.Assert(err, jc.ErrorIsNil) // this will fail when state is done right 257 rnr, err := s.factory.NewActionRunner(action.Id()) 258 c.Check(rnr, gc.IsNil) 259 c.Check(err, gc.ErrorMatches, "cannot run \"snapshot\" action: .*") 260 c.Check(err, jc.Satisfies, runner.IsBadActionError) 261 } 262 263 func (s *FactorySuite) TestNewActionRunnerMissingAction(c *gc.C) { 264 s.SetCharm(c, "dummy") 265 action, err := s.State.EnqueueAction(s.unit.Tag(), "snapshot", nil) 266 c.Assert(err, jc.ErrorIsNil) 267 _, err = s.unit.CancelAction(action) 268 c.Assert(err, jc.ErrorIsNil) 269 rnr, err := s.factory.NewActionRunner(action.Id()) 270 c.Check(rnr, gc.IsNil) 271 c.Check(err, gc.ErrorMatches, "action no longer available") 272 c.Check(err, gc.Equals, runner.ErrActionNotAvailable) 273 } 274 275 func (s *FactorySuite) TestNewActionRunnerUnauthAction(c *gc.C) { 276 s.SetCharm(c, "dummy") 277 otherUnit, err := s.service.AddUnit() 278 c.Assert(err, jc.ErrorIsNil) 279 action, err := s.State.EnqueueAction(otherUnit.Tag(), "snapshot", nil) 280 c.Assert(err, jc.ErrorIsNil) 281 rnr, err := s.factory.NewActionRunner(action.Id()) 282 c.Check(rnr, gc.IsNil) 283 c.Check(err, gc.ErrorMatches, "action no longer available") 284 c.Check(err, gc.Equals, runner.ErrActionNotAvailable) 285 }