github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/cmd/juju/cmd_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "io" 8 "io/ioutil" 9 "os" 10 "reflect" 11 12 jc "github.com/juju/testing/checkers" 13 gc "launchpad.net/gocheck" 14 15 "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/envcmd" 17 "github.com/juju/juju/juju/osenv" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/provider/dummy" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type CmdSuite struct { 24 testing.JujuConnSuite 25 } 26 27 var _ = gc.Suite(&CmdSuite{}) 28 29 const envConfig = ` 30 default: 31 peckham 32 environments: 33 peckham: 34 type: dummy 35 state-server: false 36 admin-secret: arble 37 authorized-keys: i-am-a-key 38 default-series: raring 39 walthamstow: 40 type: dummy 41 state-server: false 42 authorized-keys: i-am-a-key 43 brokenenv: 44 type: dummy 45 broken: Bootstrap Destroy 46 state-server: false 47 authorized-keys: i-am-a-key 48 ` 49 50 func (s *CmdSuite) SetUpTest(c *gc.C) { 51 s.JujuConnSuite.SetUpTest(c) 52 coretesting.WriteEnvironments(c, envConfig, "peckham", "walthamstow", "brokenenv") 53 } 54 55 func (s *CmdSuite) TearDownTest(c *gc.C) { 56 s.JujuConnSuite.TearDownTest(c) 57 } 58 59 // testInit checks that a command initialises correctly 60 // with the given set of arguments. 61 func testInit(c *gc.C, com cmd.Command, args []string, errPat string) { 62 err := coretesting.InitCommand(com, args) 63 if errPat != "" { 64 c.Assert(err, gc.ErrorMatches, errPat) 65 } else { 66 c.Assert(err, gc.IsNil) 67 } 68 } 69 70 // assertEnvName asserts that the Command is using 71 // the given environment name. 72 // Since every command has a different type, 73 // we use reflection to look at the value of the 74 // Conn field in the value. 75 func assertEnvName(c *gc.C, com cmd.Command, name string) { 76 v := reflect.ValueOf(com).Elem().FieldByName("EnvName") 77 c.Assert(v, jc.Satisfies, reflect.Value.IsValid) 78 c.Assert(v.Interface(), gc.Equals, name) 79 } 80 81 // All members of EnvironmentInitTests are tested for the -environment and -e 82 // flags, and that extra arguments will cause parsing to fail. 83 var EnvironmentInitTests = []func() (envcmd.EnvironCommand, []string){ 84 func() (envcmd.EnvironCommand, []string) { return new(BootstrapCommand), nil }, 85 func() (envcmd.EnvironCommand, []string) { 86 return new(DeployCommand), []string{"charm-name", "service-name"} 87 }, 88 func() (envcmd.EnvironCommand, []string) { return new(StatusCommand), nil }, 89 } 90 91 // TestEnvironmentInit tests that all commands which accept 92 // the --environment variable initialise their 93 // environment name correctly. 94 func (*CmdSuite) TestEnvironmentInit(c *gc.C) { 95 for i, cmdFunc := range EnvironmentInitTests { 96 c.Logf("test %d", i) 97 com, args := cmdFunc() 98 testInit(c, envcmd.Wrap(com), args, "") 99 assertEnvName(c, com, "peckham") 100 101 com, args = cmdFunc() 102 testInit(c, envcmd.Wrap(com), append(args, "-e", "walthamstow"), "") 103 assertEnvName(c, com, "walthamstow") 104 105 com, args = cmdFunc() 106 testInit(c, envcmd.Wrap(com), append(args, "--environment", "walthamstow"), "") 107 assertEnvName(c, com, "walthamstow") 108 109 // JUJU_ENV is the final place the environment can be overriden 110 com, args = cmdFunc() 111 oldenv := os.Getenv(osenv.JujuEnvEnvKey) 112 os.Setenv(osenv.JujuEnvEnvKey, "walthamstow") 113 testInit(c, envcmd.Wrap(com), args, "") 114 os.Setenv(osenv.JujuEnvEnvKey, oldenv) 115 assertEnvName(c, com, "walthamstow") 116 } 117 } 118 119 func nullContext(c *gc.C) *cmd.Context { 120 ctx, err := cmd.DefaultContext() 121 c.Assert(err, gc.IsNil) 122 ctx.Stdin = io.LimitReader(nil, 0) 123 ctx.Stdout = ioutil.Discard 124 ctx.Stderr = ioutil.Discard 125 return ctx 126 } 127 128 func runCommand(ctx *cmd.Context, com cmd.Command, args ...string) (opc chan dummy.Operation, errc chan error) { 129 if ctx == nil { 130 panic("ctx == nil") 131 } 132 errc = make(chan error, 1) 133 opc = make(chan dummy.Operation, 200) 134 dummy.Listen(opc) 135 go func() { 136 // signal that we're done with this ops channel. 137 defer dummy.Listen(nil) 138 139 err := coretesting.InitCommand(com, args) 140 if err != nil { 141 errc <- err 142 return 143 } 144 145 err = com.Run(ctx) 146 errc <- err 147 }() 148 return 149 } 150 151 var deployTests = []struct { 152 args []string 153 com *DeployCommand 154 }{ 155 { 156 []string{"charm-name"}, 157 &DeployCommand{}, 158 }, { 159 []string{"charm-name", "service-name"}, 160 &DeployCommand{ServiceName: "service-name"}, 161 }, { 162 []string{"--repository", "/path/to/another-repo", "charm-name"}, 163 &DeployCommand{RepoPath: "/path/to/another-repo"}, 164 }, { 165 []string{"--upgrade", "charm-name"}, 166 &DeployCommand{BumpRevision: true}, 167 }, { 168 []string{"-u", "charm-name"}, 169 &DeployCommand{BumpRevision: true}, 170 }, { 171 []string{"--num-units", "33", "charm-name"}, 172 &DeployCommand{UnitCommandBase: UnitCommandBase{NumUnits: 33}}, 173 }, { 174 []string{"-n", "104", "charm-name"}, 175 &DeployCommand{UnitCommandBase: UnitCommandBase{NumUnits: 104}}, 176 }, 177 } 178 179 func initExpectations(com *DeployCommand) { 180 if com.CharmName == "" { 181 com.CharmName = "charm-name" 182 } 183 if com.NumUnits == 0 { 184 com.NumUnits = 1 185 } 186 if com.RepoPath == "" { 187 com.RepoPath = "/path/to/repo" 188 } 189 com.EnvCommandBase.EnvName = "peckham" 190 } 191 192 func initDeployCommand(args ...string) (*DeployCommand, error) { 193 com := &DeployCommand{} 194 return com, coretesting.InitCommand(envcmd.Wrap(com), args) 195 } 196 197 func (*CmdSuite) TestDeployCommandInit(c *gc.C) { 198 defer os.Setenv(osenv.JujuRepositoryEnvKey, os.Getenv(osenv.JujuRepositoryEnvKey)) 199 os.Setenv(osenv.JujuRepositoryEnvKey, "/path/to/repo") 200 201 for _, t := range deployTests { 202 initExpectations(t.com) 203 com, err := initDeployCommand(t.args...) 204 c.Assert(err, gc.IsNil) 205 c.Assert(com, gc.DeepEquals, t.com) 206 } 207 208 // test relative --config path 209 ctx := coretesting.Context(c) 210 expected := []byte("test: data") 211 path := ctx.AbsPath("testconfig.yaml") 212 file, err := os.Create(path) 213 c.Assert(err, gc.IsNil) 214 _, err = file.Write(expected) 215 c.Assert(err, gc.IsNil) 216 file.Close() 217 218 com, err := initDeployCommand("--config", "testconfig.yaml", "charm-name") 219 c.Assert(err, gc.IsNil) 220 actual, err := com.Config.Read(ctx) 221 c.Assert(err, gc.IsNil) 222 c.Assert(expected, gc.DeepEquals, actual) 223 224 // missing args 225 _, err = initDeployCommand() 226 c.Assert(err, gc.ErrorMatches, "no charm specified") 227 228 // environment tested elsewhere 229 } 230 231 func initAddUnitCommand(args ...string) (*AddUnitCommand, error) { 232 com := &AddUnitCommand{} 233 return com, coretesting.InitCommand(com, args) 234 } 235 236 func (*CmdSuite) TestAddUnitCommandInit(c *gc.C) { 237 // missing args 238 _, err := initAddUnitCommand() 239 c.Assert(err, gc.ErrorMatches, "no service specified") 240 241 // bad unit count 242 _, err = initDeployCommand("charm-name", "--num-units", "0") 243 c.Assert(err, gc.ErrorMatches, "--num-units must be a positive integer") 244 _, err = initDeployCommand("charm-name", "-n", "0") 245 c.Assert(err, gc.ErrorMatches, "--num-units must be a positive integer") 246 247 // environment tested elsewhere 248 } 249 250 func initExposeCommand(args ...string) (*ExposeCommand, error) { 251 com := &ExposeCommand{} 252 return com, coretesting.InitCommand(com, args) 253 } 254 255 func (*CmdSuite) TestExposeCommandInit(c *gc.C) { 256 // missing args 257 _, err := initExposeCommand() 258 c.Assert(err, gc.ErrorMatches, "no service name specified") 259 260 // environment tested elsewhere 261 } 262 263 func initUnexposeCommand(args ...string) (*UnexposeCommand, error) { 264 com := &UnexposeCommand{} 265 return com, coretesting.InitCommand(com, args) 266 } 267 268 func (*CmdSuite) TestUnexposeCommandInit(c *gc.C) { 269 // missing args 270 _, err := initUnexposeCommand() 271 c.Assert(err, gc.ErrorMatches, "no service name specified") 272 273 // environment tested elsewhere 274 } 275 276 func initSSHCommand(args ...string) (*SSHCommand, error) { 277 com := &SSHCommand{} 278 return com, coretesting.InitCommand(com, args) 279 } 280 281 func (*CmdSuite) TestSSHCommandInit(c *gc.C) { 282 // missing args 283 _, err := initSSHCommand() 284 c.Assert(err, gc.ErrorMatches, "no target name specified") 285 } 286 287 func initSCPCommand(args ...string) (*SCPCommand, error) { 288 com := &SCPCommand{} 289 return com, coretesting.InitCommand(com, args) 290 } 291 292 func (*CmdSuite) TestSCPCommandInit(c *gc.C) { 293 // missing args 294 _, err := initSCPCommand() 295 c.Assert(err, gc.ErrorMatches, "at least two arguments required") 296 297 // not enough args 298 _, err = initSCPCommand("mysql/0:foo") 299 c.Assert(err, gc.ErrorMatches, "at least two arguments required") 300 } 301 302 func initGetCommand(args ...string) (*GetCommand, error) { 303 com := &GetCommand{} 304 return com, coretesting.InitCommand(com, args) 305 } 306 307 func (*CmdSuite) TestGetCommandInit(c *gc.C) { 308 // missing args 309 _, err := initGetCommand() 310 c.Assert(err, gc.ErrorMatches, "no service name specified") 311 } 312 313 func initSetCommand(args ...string) (*SetCommand, error) { 314 com := &SetCommand{} 315 return com, coretesting.InitCommand(com, args) 316 } 317 318 func (*CmdSuite) TestSetCommandInit(c *gc.C) { 319 // missing args 320 _, err := initSetCommand() 321 c.Assert(err, gc.ErrorMatches, "no service name specified") 322 // missing service name 323 _, err = initSetCommand("name=cow") 324 c.Assert(err, gc.ErrorMatches, "no service name specified") 325 326 // test --config path 327 expected := []byte("this: is some test data") 328 ctx := coretesting.Context(c) 329 path := ctx.AbsPath("testconfig.yaml") 330 file, err := os.Create(path) 331 c.Assert(err, gc.IsNil) 332 _, err = file.Write(expected) 333 c.Assert(err, gc.IsNil) 334 file.Close() 335 com, err := initSetCommand("--config", "testconfig.yaml", "service") 336 c.Assert(err, gc.IsNil) 337 c.Assert(com.SettingsYAML.Path, gc.Equals, "testconfig.yaml") 338 actual, err := com.SettingsYAML.Read(ctx) 339 c.Assert(err, gc.IsNil) 340 c.Assert(actual, gc.DeepEquals, expected) 341 342 // --config path, but no service 343 com, err = initSetCommand("--config", "testconfig") 344 c.Assert(err, gc.ErrorMatches, "no service name specified") 345 346 // --config and options specified 347 com, err = initSetCommand("service", "--config", "testconfig", "bees=") 348 c.Assert(err, gc.ErrorMatches, "cannot specify --config when using key=value arguments") 349 } 350 351 func initUnsetCommand(args ...string) (*UnsetCommand, error) { 352 com := &UnsetCommand{} 353 return com, coretesting.InitCommand(com, args) 354 } 355 356 func (*CmdSuite) TestUnsetCommandInit(c *gc.C) { 357 // missing args 358 _, err := initUnsetCommand() 359 c.Assert(err, gc.ErrorMatches, "no service name specified") 360 } 361 362 func initRemoveUnitCommand(args ...string) (*RemoveUnitCommand, error) { 363 com := &RemoveUnitCommand{} 364 return com, coretesting.InitCommand(com, args) 365 } 366 367 func (*CmdSuite) TestRemoveUnitCommandInit(c *gc.C) { 368 // missing args 369 _, err := initRemoveUnitCommand() 370 c.Assert(err, gc.ErrorMatches, "no units specified") 371 // not a unit 372 _, err = initRemoveUnitCommand("seven/nine") 373 c.Assert(err, gc.ErrorMatches, `invalid unit name "seven/nine"`) 374 }