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 }