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  }