github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/storage/poollist_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  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  
    11  	"github.com/juju/cmd"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  	goyaml "gopkg.in/yaml.v1"
    15  
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cmd/envcmd"
    18  	"github.com/juju/juju/cmd/juju/storage"
    19  	_ "github.com/juju/juju/provider/dummy"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  type poolListSuite struct {
    24  	SubStorageSuite
    25  	mockAPI *mockPoolListAPI
    26  }
    27  
    28  var _ = gc.Suite(&poolListSuite{})
    29  
    30  func (s *poolListSuite) SetUpTest(c *gc.C) {
    31  	s.SubStorageSuite.SetUpTest(c)
    32  
    33  	s.mockAPI = &mockPoolListAPI{
    34  		attrs: map[string]interface{}{"key": "value", "one": "1", "two": 2},
    35  	}
    36  	s.PatchValue(storage.GetPoolListAPI,
    37  		func(c *storage.PoolListCommand) (storage.PoolListAPI, error) {
    38  			return s.mockAPI, nil
    39  		})
    40  
    41  }
    42  
    43  func runPoolList(c *gc.C, args []string) (*cmd.Context, error) {
    44  	return testing.RunCommand(c,
    45  		envcmd.Wrap(&storage.PoolListCommand{}), args...)
    46  }
    47  
    48  func (s *poolListSuite) TestPoolListEmpty(c *gc.C) {
    49  	// Both arguments - names and provider types - are optional.
    50  	// When none are supplied, all registered pools are listed.
    51  	// As this test uses mock api, no pools are registered by default.
    52  	// Returned list should be empty.
    53  	s.assertValidList(
    54  		c,
    55  		[]string{""},
    56  		"",
    57  	)
    58  }
    59  
    60  const (
    61  	providerA = "a"
    62  	providerB = "b"
    63  
    64  	nameABC = "abc"
    65  	nameXYZ = "xyz"
    66  )
    67  
    68  func (s *poolListSuite) TestPoolList(c *gc.C) {
    69  	s.assertUnmarshalledOutput(c, goyaml.Unmarshal,
    70  		"--provider", providerA,
    71  		"--provider", providerB,
    72  		"--name", nameABC,
    73  		"--name", nameXYZ)
    74  }
    75  
    76  func (s *poolListSuite) TestPoolListJSON(c *gc.C) {
    77  	s.assertUnmarshalledOutput(c, json.Unmarshal,
    78  		"--provider", providerA,
    79  		"--provider", providerB,
    80  		"--name", nameABC,
    81  		"--name", nameXYZ,
    82  		"--format", "json")
    83  }
    84  
    85  func (s *poolListSuite) TestPoolListTabular(c *gc.C) {
    86  	s.assertValidList(
    87  		c,
    88  		[]string{"--provider", "a", "--provider", "b",
    89  			"--name", "xyz", "--name", "abc",
    90  			"--format", "tabular"},
    91  		`
    92  NAME       PROVIDER  ATTRS
    93  abc        testType  key=value one=1 two=2
    94  testName0  a         key=value one=1 two=2
    95  testName1  b         key=value one=1 two=2
    96  xyz        testType  key=value one=1 two=2
    97  
    98  `[1:])
    99  }
   100  
   101  func (s *poolListSuite) TestPoolListTabularSortedWithAttrs(c *gc.C) {
   102  	s.mockAPI.attrs = map[string]interface{}{
   103  		"a": true, "c": "well", "b": "maybe"}
   104  
   105  	s.assertValidList(
   106  		c,
   107  		[]string{"--name", "myaw", "--name", "xyz", "--name", "abc",
   108  			"--format", "tabular"},
   109  		`
   110  NAME  PROVIDER  ATTRS
   111  abc   testType  a=true b=maybe c=well
   112  myaw  testType  a=true b=maybe c=well
   113  xyz   testType  a=true b=maybe c=well
   114  
   115  `[1:])
   116  }
   117  
   118  type unmarshaller func(in []byte, out interface{}) (err error)
   119  
   120  func (s *poolListSuite) assertUnmarshalledOutput(c *gc.C, unmarshall unmarshaller, args ...string) {
   121  
   122  	context, err := runPoolList(c, args)
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	var result map[string]storage.PoolInfo
   125  	err = unmarshall(context.Stdout.(*bytes.Buffer).Bytes(), &result)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	expected := s.expect(c,
   128  		[]string{providerA, providerB},
   129  		[]string{nameABC, nameXYZ})
   130  	// This comparison cannot rely on gc.DeepEquals as
   131  	// json.Unmarshal unmarshalls the number as a float64,
   132  	// rather than an int
   133  	s.assertSamePoolInfos(c, result, expected)
   134  }
   135  
   136  func (s poolListSuite) assertSamePoolInfos(c *gc.C, one, two map[string]storage.PoolInfo) {
   137  	c.Assert(one, gc.HasLen, len(two))
   138  
   139  	sameAttributes := func(a, b map[string]interface{}) {
   140  		c.Assert(a, gc.HasLen, len(b))
   141  		for ka, va := range a {
   142  			vb, okb := b[ka]
   143  			c.Assert(okb, jc.IsTrue)
   144  			// As some types may have been unmarshalled incorrectly, for example
   145  			// int versus float64, compare values' string representations
   146  			c.Assert(fmt.Sprintf("%v", va), jc.DeepEquals, fmt.Sprintf("%v", vb))
   147  		}
   148  	}
   149  
   150  	for key, v1 := range one {
   151  		v2, ok := two[key]
   152  		c.Assert(ok, jc.IsTrue)
   153  		c.Assert(v1.Provider, gc.Equals, v2.Provider)
   154  		sameAttributes(v1.Attrs, v2.Attrs)
   155  	}
   156  }
   157  
   158  func (s poolListSuite) expect(c *gc.C, types, names []string) map[string]storage.PoolInfo {
   159  	all, err := s.mockAPI.ListPools(types, names)
   160  	c.Assert(err, jc.ErrorIsNil)
   161  	result := make(map[string]storage.PoolInfo, len(all))
   162  	for _, one := range all {
   163  		result[one.Name] = storage.PoolInfo{one.Provider, one.Attrs}
   164  	}
   165  	return result
   166  }
   167  
   168  func (s *poolListSuite) assertValidList(c *gc.C, args []string, expected string) {
   169  	context, err := runPoolList(c, args)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  
   172  	obtained := testing.Stdout(context)
   173  	c.Assert(obtained, gc.Equals, expected)
   174  }
   175  
   176  type mockPoolListAPI struct {
   177  	attrs map[string]interface{}
   178  }
   179  
   180  func (s mockPoolListAPI) Close() error {
   181  	return nil
   182  }
   183  
   184  func (s mockPoolListAPI) ListPools(types []string, names []string) ([]params.StoragePool, error) {
   185  	results := make([]params.StoragePool, len(types)+len(names))
   186  	var index int
   187  	addInstance := func(aname, atype string) {
   188  		results[index] = s.createTestPoolInstance(aname, atype)
   189  		index++
   190  	}
   191  	for i, atype := range types {
   192  		addInstance(fmt.Sprintf("testName%v", i), atype)
   193  	}
   194  	for _, aname := range names {
   195  		addInstance(aname, "testType")
   196  	}
   197  	return results, nil
   198  }
   199  
   200  func (s mockPoolListAPI) createTestPoolInstance(aname, atype string) params.StoragePool {
   201  	return params.StoragePool{
   202  		Name:     aname,
   203  		Provider: atype,
   204  		Attrs:    s.attrs,
   205  	}
   206  }