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