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  }