github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/uniter/runner/context_test.go (about) 1 // Copyright 2012-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package runner_test 5 6 import ( 7 "os" 8 "syscall" 9 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v4" 14 15 "github.com/juju/juju/network" 16 "github.com/juju/juju/worker/uniter/runner" 17 "github.com/juju/juju/worker/uniter/runner/jujuc" 18 "github.com/juju/utils/exec" 19 ) 20 21 type InterfaceSuite struct { 22 HookContextSuite 23 } 24 25 var _ = gc.Suite(&InterfaceSuite{}) 26 27 func (s *InterfaceSuite) GetContext( 28 c *gc.C, relId int, remoteName string, 29 ) jujuc.Context { 30 uuid, err := utils.NewUUID() 31 c.Assert(err, jc.ErrorIsNil) 32 return s.HookContextSuite.getHookContext( 33 c, uuid.String(), relId, remoteName, noProxies, 34 ) 35 } 36 37 func (s *InterfaceSuite) TestUtils(c *gc.C) { 38 ctx := s.GetContext(c, -1, "") 39 c.Assert(ctx.UnitName(), gc.Equals, "u/0") 40 r, found := ctx.HookRelation() 41 c.Assert(found, jc.IsFalse) 42 c.Assert(r, gc.IsNil) 43 name, found := ctx.RemoteUnitName() 44 c.Assert(found, jc.IsFalse) 45 c.Assert(name, gc.Equals, "") 46 c.Assert(ctx.RelationIds(), gc.HasLen, 2) 47 r, found = ctx.Relation(0) 48 c.Assert(found, jc.IsTrue) 49 c.Assert(r.Name(), gc.Equals, "db") 50 c.Assert(r.FakeId(), gc.Equals, "db:0") 51 r, found = ctx.Relation(123) 52 c.Assert(found, jc.IsFalse) 53 c.Assert(r, gc.IsNil) 54 55 ctx = s.GetContext(c, 1, "") 56 r, found = ctx.HookRelation() 57 c.Assert(found, jc.IsTrue) 58 c.Assert(r.Name(), gc.Equals, "db") 59 c.Assert(r.FakeId(), gc.Equals, "db:1") 60 61 ctx = s.GetContext(c, 1, "u/123") 62 name, found = ctx.RemoteUnitName() 63 c.Assert(found, jc.IsTrue) 64 c.Assert(name, gc.Equals, "u/123") 65 } 66 67 func (s *InterfaceSuite) TestAvailabilityZone(c *gc.C) { 68 ctx := s.GetContext(c, -1, "") 69 zone, ok := ctx.AvailabilityZone() 70 c.Check(ok, jc.IsTrue) 71 c.Check(zone, gc.Equals, "a-zone") 72 } 73 74 func (s *InterfaceSuite) TestUnitCaching(c *gc.C) { 75 ctx := s.GetContext(c, -1, "") 76 pr, ok := ctx.PrivateAddress() 77 c.Assert(ok, jc.IsTrue) 78 c.Assert(pr, gc.Equals, "u-0.testing.invalid") 79 pa, ok := ctx.PublicAddress() 80 c.Assert(ok, jc.IsTrue) 81 // Initially the public address is the same as the private address since 82 // the "most public" address is chosen. 83 c.Assert(pr, gc.Equals, pa) 84 85 // Change remote state. 86 err := s.machine.SetAddresses( 87 network.NewAddress("blah.testing.invalid", network.ScopePublic)) 88 c.Assert(err, jc.ErrorIsNil) 89 90 // Local view is unchanged. 91 pr, ok = ctx.PrivateAddress() 92 c.Assert(ok, jc.IsTrue) 93 c.Assert(pr, gc.Equals, "u-0.testing.invalid") 94 pa, ok = ctx.PublicAddress() 95 c.Assert(ok, jc.IsTrue) 96 c.Assert(pr, gc.Equals, pa) 97 } 98 99 func (s *InterfaceSuite) TestConfigCaching(c *gc.C) { 100 ctx := s.GetContext(c, -1, "") 101 settings, err := ctx.ConfigSettings() 102 c.Assert(err, jc.ErrorIsNil) 103 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"}) 104 105 // Change remote config. 106 err = s.service.UpdateConfigSettings(charm.Settings{ 107 "blog-title": "Something Else", 108 }) 109 c.Assert(err, jc.ErrorIsNil) 110 111 // Local view is not changed. 112 settings, err = ctx.ConfigSettings() 113 c.Assert(err, jc.ErrorIsNil) 114 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"}) 115 } 116 117 // TestNonActionCallsToActionMethodsFail does exactly what its name says: 118 // it simply makes sure that Action-related calls to HookContexts with a nil 119 // actionData member error out correctly. 120 func (s *InterfaceSuite) TestNonActionCallsToActionMethodsFail(c *gc.C) { 121 ctx := runner.HookContext{} 122 _, err := ctx.ActionParams() 123 c.Check(err, gc.ErrorMatches, "not running an action") 124 err = ctx.SetActionFailed() 125 c.Check(err, gc.ErrorMatches, "not running an action") 126 err = ctx.SetActionMessage("foo") 127 c.Check(err, gc.ErrorMatches, "not running an action") 128 err = ctx.UpdateActionResults([]string{"1", "2", "3"}, "value") 129 c.Check(err, gc.ErrorMatches, "not running an action") 130 } 131 132 // TestUpdateActionResults demonstrates that UpdateActionResults functions 133 // as expected. 134 func (s *InterfaceSuite) TestUpdateActionResults(c *gc.C) { 135 tests := []struct { 136 initial map[string]interface{} 137 keys []string 138 value string 139 expected map[string]interface{} 140 }{{ 141 initial: map[string]interface{}{}, 142 keys: []string{"foo"}, 143 value: "bar", 144 expected: map[string]interface{}{ 145 "foo": "bar", 146 }, 147 }, { 148 initial: map[string]interface{}{ 149 "foo": "bar", 150 }, 151 keys: []string{"foo", "bar"}, 152 value: "baz", 153 expected: map[string]interface{}{ 154 "foo": map[string]interface{}{ 155 "bar": "baz", 156 }, 157 }, 158 }, { 159 initial: map[string]interface{}{ 160 "foo": map[string]interface{}{ 161 "bar": "baz", 162 }, 163 }, 164 keys: []string{"foo"}, 165 value: "bar", 166 expected: map[string]interface{}{ 167 "foo": "bar", 168 }, 169 }} 170 171 for i, t := range tests { 172 c.Logf("UpdateActionResults test %d: %#v: %#v", i, t.keys, t.value) 173 hctx := runner.GetStubActionContext(t.initial) 174 err := hctx.UpdateActionResults(t.keys, t.value) 175 c.Assert(err, jc.ErrorIsNil) 176 actionData, err := hctx.ActionData() 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(actionData.ResultsMap, jc.DeepEquals, t.expected) 179 } 180 } 181 182 // TestSetActionFailed ensures SetActionFailed works properly. 183 func (s *InterfaceSuite) TestSetActionFailed(c *gc.C) { 184 hctx := runner.GetStubActionContext(nil) 185 err := hctx.SetActionFailed() 186 c.Assert(err, jc.ErrorIsNil) 187 actionData, err := hctx.ActionData() 188 c.Assert(err, jc.ErrorIsNil) 189 c.Check(actionData.ActionFailed, jc.IsTrue) 190 } 191 192 // TestSetActionMessage ensures SetActionMessage works properly. 193 func (s *InterfaceSuite) TestSetActionMessage(c *gc.C) { 194 hctx := runner.GetStubActionContext(nil) 195 err := hctx.SetActionMessage("because reasons") 196 c.Assert(err, jc.ErrorIsNil) 197 actionData, err := hctx.ActionData() 198 c.Check(err, jc.ErrorIsNil) 199 c.Check(actionData.ResultsMessage, gc.Equals, "because reasons") 200 } 201 202 func (s *InterfaceSuite) startProcess(c *gc.C) *os.Process { 203 command := exec.RunParams{ 204 Commands: "trap 'exit 0' SIGTERM; while true;do sleep 1;done", 205 } 206 err := command.Run() 207 c.Assert(err, jc.ErrorIsNil) 208 p := command.Process() 209 s.AddCleanup(func(c *gc.C) { p.Kill() }) 210 return p 211 } 212 213 func (s *InterfaceSuite) TestRequestRebootAfterHook(c *gc.C) { 214 ctx := runner.HookContext{} 215 p := s.startProcess(c) 216 ctx.SetProcess(p) 217 err := ctx.RequestReboot(jujuc.RebootAfterHook) 218 c.Assert(err, jc.ErrorIsNil) 219 err = syscall.Kill(p.Pid, syscall.SIGTERM) 220 c.Assert(err, jc.ErrorIsNil) 221 _, err = p.Wait() 222 c.Assert(err, jc.ErrorIsNil) 223 priority := ctx.GetRebootPriority() 224 c.Assert(priority, gc.Equals, jujuc.RebootAfterHook) 225 } 226 227 func (s *InterfaceSuite) TestRequestRebootNow(c *gc.C) { 228 ctx := runner.HookContext{} 229 p := s.startProcess(c) 230 ctx.SetProcess(p) 231 go func() { 232 _, err := p.Wait() 233 c.Assert(err, jc.ErrorIsNil) 234 }() 235 err := ctx.RequestReboot(jujuc.RebootNow) 236 c.Assert(err, jc.ErrorIsNil) 237 priority := ctx.GetRebootPriority() 238 c.Assert(priority, gc.Equals, jujuc.RebootNow) 239 } 240 241 func (s *InterfaceSuite) TestRequestRebootNowNoProcess(c *gc.C) { 242 // A normal hook run or a juju-run command will record the *os.Process 243 // object of the running command, in HookContext. When requesting a 244 // reboot with the --now flag, the process is killed and only 245 // then will we set the reboot priority. This test basically simulates 246 // the case when the process calling juju-reboot is not recorded. 247 ctx := runner.HookContext{} 248 err := ctx.RequestReboot(jujuc.RebootNow) 249 c.Assert(err, gc.ErrorMatches, "no process to kill") 250 priority := ctx.GetRebootPriority() 251 c.Assert(priority, gc.Equals, jujuc.RebootNow) 252 }