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  }