github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/service/addunit_test.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package service_test
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/cmd/envcmd"
    16  	"github.com/juju/juju/cmd/juju/service"
    17  	"github.com/juju/juju/environs/config"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/testing"
    20  )
    21  
    22  type AddUnitSuite struct {
    23  	testing.FakeJujuHomeSuite
    24  	fake *fakeServiceAddUnitAPI
    25  }
    26  
    27  type fakeServiceAddUnitAPI struct {
    28  	envType     string
    29  	service     string
    30  	numUnits    int
    31  	machineSpec string
    32  	placement   []*instance.Placement
    33  	err         error
    34  	newAPI      bool
    35  }
    36  
    37  func (f *fakeServiceAddUnitAPI) Close() error {
    38  	return nil
    39  }
    40  
    41  func (f *fakeServiceAddUnitAPI) EnvironmentUUID() string {
    42  	return "fake-uuid"
    43  }
    44  
    45  func (f *fakeServiceAddUnitAPI) AddServiceUnits(service string, numUnits int, machineSpec string) ([]string, error) {
    46  	if f.err != nil {
    47  		return nil, f.err
    48  	}
    49  
    50  	if service != f.service {
    51  		return nil, errors.NotFoundf("service %q", service)
    52  	}
    53  
    54  	f.numUnits += numUnits
    55  	f.machineSpec = machineSpec
    56  
    57  	// The add-unit subcommand doesn't check the results, so we can just return nil
    58  	return nil, nil
    59  }
    60  
    61  func (f *fakeServiceAddUnitAPI) AddServiceUnitsWithPlacement(service string, numUnits int, placement []*instance.Placement) ([]string, error) {
    62  	if !f.newAPI {
    63  		return nil, &params.Error{Code: params.CodeNotImplemented}
    64  	}
    65  	if service != f.service {
    66  		return nil, errors.NotFoundf("service %q", service)
    67  	}
    68  
    69  	f.numUnits += numUnits
    70  	f.placement = placement
    71  	return nil, nil
    72  }
    73  
    74  func (f *fakeServiceAddUnitAPI) EnvironmentGet() (map[string]interface{}, error) {
    75  	cfg, err := config.New(config.UseDefaults, map[string]interface{}{
    76  		"type": f.envType,
    77  		"name": "dummy",
    78  	})
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	return cfg.AllAttrs(), nil
    84  }
    85  
    86  func (s *AddUnitSuite) SetUpTest(c *gc.C) {
    87  	s.FakeJujuHomeSuite.SetUpTest(c)
    88  	s.fake = &fakeServiceAddUnitAPI{service: "some-service-name", numUnits: 1, envType: "dummy"}
    89  }
    90  
    91  var _ = gc.Suite(&AddUnitSuite{})
    92  
    93  var initAddUnitErrorTests = []struct {
    94  	args []string
    95  	err  string
    96  }{
    97  	{
    98  		args: []string{"some-service-name", "-n", "0"},
    99  		err:  `--num-units must be a positive integer`,
   100  	}, {
   101  		args: []string{},
   102  		err:  `no service specified`,
   103  	}, {
   104  		args: []string{"some-service-name", "--to", "1,#:foo"},
   105  		err:  `invalid --to parameter "#:foo"`,
   106  	},
   107  }
   108  
   109  func (s *AddUnitSuite) TestInitErrors(c *gc.C) {
   110  	for i, t := range initAddUnitErrorTests {
   111  		c.Logf("test %d", i)
   112  		err := testing.InitCommand(envcmd.Wrap(service.NewAddUnitCommand(s.fake)), t.args)
   113  		c.Check(err, gc.ErrorMatches, t.err)
   114  	}
   115  }
   116  
   117  func (s *AddUnitSuite) runAddUnit(c *gc.C, args ...string) error {
   118  	_, err := testing.RunCommand(c, envcmd.Wrap(service.NewAddUnitCommand(s.fake)), args...)
   119  	return err
   120  }
   121  
   122  func (s *AddUnitSuite) TestInvalidToParamWithOlderServer(c *gc.C) {
   123  	err := s.runAddUnit(c, "some-service-name")
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   126  
   127  	err = s.runAddUnit(c, "--to", "bigglesplop", "some-service-name")
   128  	c.Assert(err, gc.ErrorMatches, `unsupported --to parameter "bigglesplop"`)
   129  }
   130  
   131  func (s *AddUnitSuite) TestUnsupportedNumUnitsWithOlderServer(c *gc.C) {
   132  	err := s.runAddUnit(c, "some-service-name")
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   135  
   136  	err = s.runAddUnit(c, "-n", "2", "--to", "123", "some-service-name")
   137  	c.Assert(err, gc.ErrorMatches, `this version of Juju does not support --num-units > 1 with --to`)
   138  }
   139  
   140  func (s *AddUnitSuite) TestAddUnit(c *gc.C) {
   141  	err := s.runAddUnit(c, "some-service-name")
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   144  
   145  	err = s.runAddUnit(c, "--num-units", "2", "some-service-name")
   146  	c.Assert(err, jc.ErrorIsNil)
   147  	c.Assert(s.fake.numUnits, gc.Equals, 4)
   148  }
   149  
   150  func (s *AddUnitSuite) TestAddUnitWithPlacement(c *gc.C) {
   151  	s.fake.newAPI = true
   152  	err := s.runAddUnit(c, "some-service-name")
   153  	c.Assert(err, jc.ErrorIsNil)
   154  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   155  
   156  	err = s.runAddUnit(c, "--num-units", "2", "--to", "123,lxc:1,1/lxc/2,foo", "some-service-name")
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	c.Assert(s.fake.numUnits, gc.Equals, 4)
   159  	c.Assert(s.fake.placement, jc.DeepEquals, []*instance.Placement{
   160  		{"#", "123"},
   161  		{"lxc", "1"},
   162  		{"#", "1/lxc/2"},
   163  		{"fake-uuid", "foo"},
   164  	})
   165  }
   166  
   167  func (s *AddUnitSuite) TestBlockAddUnit(c *gc.C) {
   168  	// Block operation
   169  	s.fake.err = common.ErrOperationBlocked("TestBlockAddUnit")
   170  	s.runAddUnit(c, "some-service-name")
   171  
   172  	// msg is logged
   173  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   174  	c.Check(stripped, gc.Matches, ".*TestBlockAddUnit.*")
   175  }
   176  
   177  func (s *AddUnitSuite) TestNonLocalCanHostUnits(c *gc.C) {
   178  	err := s.runAddUnit(c, "some-service-name", "--to", "0")
   179  	c.Assert(err, jc.ErrorIsNil)
   180  }
   181  
   182  func (s *AddUnitSuite) TestLocalCannotHostUnits(c *gc.C) {
   183  	s.fake.envType = "local"
   184  	err := s.runAddUnit(c, "some-service-name", "--to", "0")
   185  	c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
   186  	err = s.runAddUnit(c, "some-service-name", "--to", "1,#:0")
   187  	c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
   188  }
   189  
   190  func (s *AddUnitSuite) TestForceMachine(c *gc.C) {
   191  	err := s.runAddUnit(c, "some-service-name", "--to", "3")
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   194  	c.Assert(s.fake.machineSpec, gc.Equals, "3")
   195  
   196  	err = s.runAddUnit(c, "some-service-name", "--to", "23")
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	c.Assert(s.fake.numUnits, gc.Equals, 3)
   199  	c.Assert(s.fake.machineSpec, gc.Equals, "23")
   200  }
   201  
   202  func (s *AddUnitSuite) TestForceMachineNewContainer(c *gc.C) {
   203  	err := s.runAddUnit(c, "some-service-name", "--to", "lxc:1")
   204  	c.Assert(err, jc.ErrorIsNil)
   205  	c.Assert(s.fake.numUnits, gc.Equals, 2)
   206  	c.Assert(s.fake.machineSpec, gc.Equals, "lxc:1")
   207  }
   208  
   209  func (s *AddUnitSuite) TestNameChecks(c *gc.C) {
   210  	assertMachineOrNewContainer := func(s string, expect bool) {
   211  		c.Logf("%s -> %v", s, expect)
   212  		c.Assert(service.IsMachineOrNewContainer(s), gc.Equals, expect)
   213  	}
   214  	assertMachineOrNewContainer("0", true)
   215  	assertMachineOrNewContainer("00", false)
   216  	assertMachineOrNewContainer("1", true)
   217  	assertMachineOrNewContainer("0/lxc/0", true)
   218  	assertMachineOrNewContainer("lxc:0", true)
   219  	assertMachineOrNewContainer("lxc:lxc:0", false)
   220  	assertMachineOrNewContainer("kvm:0/lxc/1", true)
   221  	assertMachineOrNewContainer("lxc:", false)
   222  	assertMachineOrNewContainer(":lxc", false)
   223  	assertMachineOrNewContainer("0/lxc/", false)
   224  	assertMachineOrNewContainer("0/lxc", false)
   225  	assertMachineOrNewContainer("kvm:0/lxc", false)
   226  	assertMachineOrNewContainer("0/lxc/01", false)
   227  	assertMachineOrNewContainer("0/lxc/10", true)
   228  	assertMachineOrNewContainer("0/kvm/4", true)
   229  }