github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/storage/add_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage_test
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cmd/juju/storage"
    18  	_ "github.com/juju/juju/provider/dummy"
    19  	"github.com/juju/juju/testing"
    20  )
    21  
    22  type addSuite struct {
    23  	SubStorageSuite
    24  	mockAPI *mockAddAPI
    25  	args    []string
    26  }
    27  
    28  var _ = gc.Suite(&addSuite{})
    29  
    30  func (s *addSuite) SetUpTest(c *gc.C) {
    31  	s.SubStorageSuite.SetUpTest(c)
    32  
    33  	s.mockAPI = &mockAddAPI{
    34  		addToUnitFunc: func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
    35  			result := make([]params.ErrorResult, len(storages))
    36  			for i, one := range storages {
    37  				if strings.HasPrefix(one.StorageName, "err") {
    38  					result[i].Error = common.ServerError(errors.Errorf("test failure"))
    39  				}
    40  			}
    41  			return result, nil
    42  		},
    43  	}
    44  	s.args = nil
    45  }
    46  
    47  type tstData struct {
    48  	args        []string
    49  	expectedErr string
    50  	visibleErr  string
    51  }
    52  
    53  var errorTsts = []tstData{
    54  	{
    55  		args:        nil,
    56  		expectedErr: "add-storage requires a unit and a storage directive",
    57  		visibleErr:  "add-storage requires a unit and a storage directive",
    58  	},
    59  	{
    60  		args:        []string{"tst/123"},
    61  		expectedErr: "add-storage requires a unit and a storage directive",
    62  		visibleErr:  "add-storage requires a unit and a storage directive",
    63  	},
    64  	{
    65  		args:        []string{"tst/123", "data="},
    66  		expectedErr: `storage constraints require at least one field to be specified`,
    67  		visibleErr:  `cannot parse constraints for storage "data": storage constraints require at least one field to be specified`,
    68  	},
    69  	{
    70  		args:        []string{"tst/123", "data=-676"},
    71  		expectedErr: `count must be greater than zero, got "-676"`,
    72  		visibleErr:  `cannot parse constraints for storage "data": cannot parse count: count must be greater than zero, got "-676"`,
    73  	},
    74  	{
    75  		args:        []string{"tst/123", "data=676", "data=676"},
    76  		expectedErr: `storage "data" specified more than once`,
    77  		visibleErr:  `storage "data" specified more than once`,
    78  	},
    79  }
    80  
    81  func (s *addSuite) TestAddArgs(c *gc.C) {
    82  	for i, t := range errorTsts {
    83  		c.Logf("test %d for %q", i, t.args)
    84  		s.args = t.args
    85  		s.assertAddErrorOutput(c, t.expectedErr, "", visibleErrorMessage(t.visibleErr))
    86  	}
    87  }
    88  
    89  func (s *addSuite) TestAddInvalidUnit(c *gc.C) {
    90  	s.args = []string{"tst-123", "data=676"}
    91  
    92  	expectedErr := `unit name "tst-123" not valid`
    93  	s.assertAddErrorOutput(c, expectedErr, "", visibleErrorMessage(expectedErr))
    94  }
    95  
    96  var validArgs = [][]string{
    97  	[]string{"tst/123", "data=676"},
    98  	[]string{"tst/123", "data"},
    99  }
   100  
   101  func (s *addSuite) TestAddSuccess(c *gc.C) {
   102  	for i, args := range validArgs {
   103  		c.Logf("test %d for %q", i, args)
   104  		s.args = args
   105  		s.assertAddOutput(c, "added \"data\"\n", "")
   106  	}
   107  }
   108  
   109  func (s *addSuite) TestAddOperationAborted(c *gc.C) {
   110  	s.args = []string{"tst/123", "data=676"}
   111  	s.mockAPI.addToUnitFunc = func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   112  		return nil, errors.New("aborted")
   113  	}
   114  	s.assertAddErrorOutput(c, ".*aborted.*", "", "")
   115  }
   116  
   117  func (s *addSuite) TestAddFailure(c *gc.C) {
   118  	s.args = []string{"tst/123", "err=676"}
   119  	s.assertAddErrorOutput(c, "cmd: error out silently", "", "failed to add \"err\": test failure\n")
   120  }
   121  
   122  func (s *addSuite) TestAddMixOrderPreserved(c *gc.C) {
   123  	expectedOut := `
   124  added "a"
   125  `[1:]
   126  	expectedErr := `
   127  failed to add "err": test failure
   128  `[1:]
   129  
   130  	s.args = []string{"tst/123", "a=676", "err=676"}
   131  	s.assertAddErrorOutput(c, "cmd: error out silently", expectedOut, expectedErr)
   132  
   133  	s.args = []string{"tst/123", "err=676", "a=676"}
   134  	s.assertAddErrorOutput(c, "cmd: error out silently", expectedOut, expectedErr)
   135  }
   136  
   137  func (s *addSuite) TestAddAllDistinctErrors(c *gc.C) {
   138  	expectedOut := `
   139  added "storage0"
   140  added "storage1"
   141  `[1:]
   142  	expectedErr := `
   143  failed to add "storage2": storage pool "barf" not found
   144  failed to add "storage42": storage "storage42" not found
   145  `[1:]
   146  
   147  	s.args = []string{"tst/123", "storage0=ebs", "storage2=barf", "storage1=123", "storage42=loop"}
   148  	s.mockAPI.addToUnitFunc = func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   149  		result := make([]params.ErrorResult, len(storages))
   150  		for i, one := range storages {
   151  			if one.StorageName == "storage2" {
   152  				result[i].Error = common.ServerError(errors.Errorf(`storage pool "barf" not found`))
   153  			}
   154  			if one.StorageName == "storage42" {
   155  				result[i].Error = common.ServerError(errors.Errorf(`storage "storage42" not found`))
   156  			}
   157  		}
   158  		return result, nil
   159  	}
   160  
   161  	s.assertAddErrorOutput(c, "cmd: error out silently", expectedOut, expectedErr)
   162  }
   163  
   164  func (s *addSuite) TestAddStorageOnlyDistinctErrors(c *gc.C) {
   165  	expectedOut := `
   166  added "storage0"
   167  `[1:]
   168  	expectedErr := `
   169  failed to add "storage2": storage "storage2" not found
   170  failed to add "storage42": storage "storage42" not found
   171  `[1:]
   172  
   173  	s.args = []string{"tst/123", "storage0=ebs", "storage2=barf", "storage42=loop"}
   174  	s.mockAPI.addToUnitFunc = func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   175  		result := make([]params.ErrorResult, len(storages))
   176  		for i, one := range storages {
   177  			if one.StorageName == "storage42" || one.StorageName == "storage2" {
   178  				result[i].Error = common.ServerError(errors.Errorf(`storage "%v" not found`, one.StorageName))
   179  			}
   180  		}
   181  		return result, nil
   182  	}
   183  
   184  	s.assertAddErrorOutput(c, "cmd: error out silently", expectedOut, expectedErr)
   185  }
   186  
   187  func (s *addSuite) TestAddStorageMixDistinctAndNonDistinctErrors(c *gc.C) {
   188  	expectedOut := ``
   189  	expectedErr := `
   190  some unit error
   191  storage "storage0" not found
   192  `[1:]
   193  
   194  	unitErr := `some unit error`
   195  	s.args = []string{"tst/123", "storage0=ebs", "storage2=barf", "storage42=loop"}
   196  	s.mockAPI.addToUnitFunc = func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   197  		result := make([]params.ErrorResult, len(storages))
   198  		for i, one := range storages {
   199  			if one.StorageName == "storage42" || one.StorageName == "storage2" {
   200  				result[i].Error = common.ServerError(errors.New(unitErr))
   201  			} else {
   202  				result[i].Error = common.ServerError(errors.Errorf(`storage "%v" not found`, one.StorageName))
   203  			}
   204  		}
   205  		return result, nil
   206  	}
   207  
   208  	s.assertAddErrorOutput(c, "cmd: error out silently", expectedOut, expectedErr)
   209  }
   210  
   211  func (s *addSuite) TestCollapseUnitErrors(c *gc.C) {
   212  	expectedErr := `some unit error`
   213  
   214  	s.args = []string{"tst/123", "storage0=ebs", "storage2=barf", "storage1=123", "storage42=loop"}
   215  	s.mockAPI.addToUnitFunc = func(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   216  		result := make([]params.ErrorResult, len(storages))
   217  		for i, _ := range storages {
   218  			result[i].Error = common.ServerError(errors.New(expectedErr))
   219  		}
   220  		return result, nil
   221  	}
   222  
   223  	s.assertAddErrorOutput(c, "cmd: error out silently", "", fmt.Sprintf("%v\n", expectedErr))
   224  }
   225  
   226  func (s *addSuite) assertAddOutput(c *gc.C, expectedOut, expectedErr string) {
   227  	context, err := s.runAdd(c, s.args...)
   228  	c.Assert(err, jc.ErrorIsNil)
   229  
   230  	s.assertExpectedOutput(c, context, expectedOut, expectedErr)
   231  }
   232  
   233  func (s *addSuite) assertAddErrorOutput(c *gc.C, expected string, expectedOut, expectedErr string) {
   234  	context, err := s.runAdd(c, s.args...)
   235  	c.Assert(errors.Cause(err), gc.ErrorMatches, expected)
   236  	s.assertExpectedOutput(c, context, expectedOut, expectedErr)
   237  }
   238  
   239  func (s *addSuite) assertExpectedOutput(c *gc.C, context *cmd.Context, expectedOut, expectedErr string) {
   240  	obtainedErr := testing.Stderr(context)
   241  	c.Assert(obtainedErr, gc.Equals, expectedErr)
   242  
   243  	obtainedValid := testing.Stdout(context)
   244  	c.Assert(obtainedValid, gc.Equals, expectedOut)
   245  }
   246  
   247  func (s *addSuite) runAdd(c *gc.C, args ...string) (*cmd.Context, error) {
   248  	return testing.RunCommand(c, storage.NewAddCommandForTest(s.mockAPI, s.store), args...)
   249  }
   250  
   251  func visibleErrorMessage(errMsg string) string {
   252  	return fmt.Sprintf("error: %v\n", errMsg)
   253  }
   254  
   255  type mockAddAPI struct {
   256  	addToUnitFunc func(storages []params.StorageAddParams) ([]params.ErrorResult, error)
   257  }
   258  
   259  func (s mockAddAPI) Close() error {
   260  	return nil
   261  }
   262  
   263  func (s mockAddAPI) AddToUnit(storages []params.StorageAddParams) ([]params.ErrorResult, error) {
   264  	return s.addToUnitFunc(storages)
   265  }