github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/application/addunit_test.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package application_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/juju/application" 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/instance" 18 "github.com/juju/juju/testing" 19 ) 20 21 type AddUnitSuite struct { 22 testing.FakeJujuXDGDataHomeSuite 23 fake *fakeServiceAddUnitAPI 24 } 25 26 type fakeServiceAddUnitAPI struct { 27 envType string 28 application string 29 numUnits int 30 placement []*instance.Placement 31 err error 32 } 33 34 func (f *fakeServiceAddUnitAPI) Close() error { 35 return nil 36 } 37 38 func (f *fakeServiceAddUnitAPI) ModelUUID() string { 39 return "fake-uuid" 40 } 41 42 func (f *fakeServiceAddUnitAPI) AddUnits(application string, numUnits int, placement []*instance.Placement) ([]string, error) { 43 if f.err != nil { 44 return nil, f.err 45 } 46 if application != f.application { 47 return nil, errors.NotFoundf("application %q", application) 48 } 49 50 f.numUnits += numUnits 51 f.placement = placement 52 return nil, nil 53 } 54 55 func (f *fakeServiceAddUnitAPI) ModelGet() (map[string]interface{}, error) { 56 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 57 "type": f.envType, 58 "name": "dummy", 59 }) 60 if err != nil { 61 return nil, err 62 } 63 64 return cfg.AllAttrs(), nil 65 } 66 67 func (s *AddUnitSuite) SetUpTest(c *gc.C) { 68 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 69 s.fake = &fakeServiceAddUnitAPI{application: "some-application-name", numUnits: 1, envType: "dummy"} 70 } 71 72 var _ = gc.Suite(&AddUnitSuite{}) 73 74 var initAddUnitErrorTests = []struct { 75 args []string 76 err string 77 }{ 78 { 79 args: []string{"some-application-name", "-n", "0"}, 80 err: `--num-units must be a positive integer`, 81 }, { 82 args: []string{}, 83 err: `no application specified`, 84 }, { 85 args: []string{"some-application-name", "--to", "1,#:foo"}, 86 err: `invalid --to parameter "#:foo"`, 87 }, 88 } 89 90 func (s *AddUnitSuite) TestInitErrors(c *gc.C) { 91 for i, t := range initAddUnitErrorTests { 92 c.Logf("test %d", i) 93 err := testing.InitCommand(application.NewAddUnitCommandForTest(s.fake), t.args) 94 c.Check(err, gc.ErrorMatches, t.err) 95 } 96 } 97 98 func (s *AddUnitSuite) runAddUnit(c *gc.C, args ...string) error { 99 _, err := testing.RunCommand(c, application.NewAddUnitCommandForTest(s.fake), args...) 100 return err 101 } 102 103 func (s *AddUnitSuite) TestAddUnit(c *gc.C) { 104 err := s.runAddUnit(c, "some-application-name") 105 c.Assert(err, jc.ErrorIsNil) 106 c.Assert(s.fake.numUnits, gc.Equals, 2) 107 108 err = s.runAddUnit(c, "--num-units", "2", "some-application-name") 109 c.Assert(err, jc.ErrorIsNil) 110 c.Assert(s.fake.numUnits, gc.Equals, 4) 111 } 112 113 func (s *AddUnitSuite) TestAddUnitWithPlacement(c *gc.C) { 114 err := s.runAddUnit(c, "some-application-name") 115 c.Assert(err, jc.ErrorIsNil) 116 c.Assert(s.fake.numUnits, gc.Equals, 2) 117 118 err = s.runAddUnit(c, "--num-units", "2", "--to", "123,lxd:1,1/lxd/2,foo", "some-application-name") 119 c.Assert(err, jc.ErrorIsNil) 120 c.Assert(s.fake.numUnits, gc.Equals, 4) 121 c.Assert(s.fake.placement, jc.DeepEquals, []*instance.Placement{ 122 {"#", "123"}, 123 {"lxd", "1"}, 124 {"#", "1/lxd/2"}, 125 {"fake-uuid", "foo"}, 126 }) 127 } 128 129 func (s *AddUnitSuite) TestBlockAddUnit(c *gc.C) { 130 // Block operation 131 s.fake.err = common.OperationBlockedError("TestBlockAddUnit") 132 s.runAddUnit(c, "some-application-name") 133 134 // msg is logged 135 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 136 c.Check(stripped, gc.Matches, ".*TestBlockAddUnit.*") 137 } 138 139 func (s *AddUnitSuite) TestUnauthorizedMentionsJujuGrant(c *gc.C) { 140 s.fake.err = ¶ms.Error{ 141 Message: "permission denied", 142 Code: params.CodeUnauthorized, 143 } 144 ctx, _ := testing.RunCommand(c, application.NewAddUnitCommandForTest(s.fake), "some-application-name") 145 errString := strings.Replace(testing.Stderr(ctx), "\n", " ", -1) 146 c.Assert(errString, gc.Matches, `.*juju grant.*`) 147 } 148 149 func (s *AddUnitSuite) TestForceMachine(c *gc.C) { 150 err := s.runAddUnit(c, "some-application-name", "--to", "3") 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(s.fake.numUnits, gc.Equals, 2) 153 c.Assert(s.fake.placement[0].Directive, gc.Equals, "3") 154 155 err = s.runAddUnit(c, "some-application-name", "--to", "23") 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(s.fake.numUnits, gc.Equals, 3) 158 c.Assert(s.fake.placement[0].Directive, gc.Equals, "23") 159 } 160 161 func (s *AddUnitSuite) TestForceMachineNewContainer(c *gc.C) { 162 err := s.runAddUnit(c, "some-application-name", "--to", "lxd:1") 163 c.Assert(err, jc.ErrorIsNil) 164 c.Assert(s.fake.numUnits, gc.Equals, 2) 165 c.Assert(s.fake.placement[0].Directive, gc.Equals, "1") 166 c.Assert(s.fake.placement[0].Scope, gc.Equals, "lxd") 167 } 168 169 func (s *AddUnitSuite) TestNameChecks(c *gc.C) { 170 assertMachineOrNewContainer := func(s string, expect bool) { 171 c.Logf("%s -> %v", s, expect) 172 c.Assert(application.IsMachineOrNewContainer(s), gc.Equals, expect) 173 } 174 assertMachineOrNewContainer("0", true) 175 assertMachineOrNewContainer("00", false) 176 assertMachineOrNewContainer("1", true) 177 assertMachineOrNewContainer("0/lxd/0", true) 178 assertMachineOrNewContainer("lxd:0", true) 179 assertMachineOrNewContainer("lxd:lxd:0", false) 180 assertMachineOrNewContainer("kvm:0/lxd/1", true) 181 assertMachineOrNewContainer("lxd:", false) 182 assertMachineOrNewContainer(":lxd", false) 183 assertMachineOrNewContainer("0/lxd/", false) 184 assertMachineOrNewContainer("0/lxd", false) 185 assertMachineOrNewContainer("kvm:0/lxd", false) 186 assertMachineOrNewContainer("0/lxd/01", false) 187 assertMachineOrNewContainer("0/lxd/10", true) 188 assertMachineOrNewContainer("0/kvm/4", true) 189 }