github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/storage/filesystemlist_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 "encoding/json" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 goyaml "gopkg.in/yaml.v2" 14 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/cmd/juju/storage" 17 "github.com/juju/juju/status" 18 "github.com/juju/juju/testing" 19 ) 20 21 func (s *ListSuite) TestFilesystemListEmpty(c *gc.C) { 22 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 23 return nil, nil 24 } 25 s.assertValidFilesystemList( 26 c, 27 []string{"--format", "yaml"}, 28 "", 29 ) 30 } 31 32 func (s *ListSuite) TestFilesystemListError(c *gc.C) { 33 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 34 return nil, errors.New("just my luck") 35 } 36 context, err := s.runFilesystemList(c, "--format", "yaml") 37 c.Assert(errors.Cause(err), gc.ErrorMatches, "just my luck") 38 s.assertUserFacingOutput(c, context, "", "") 39 } 40 41 func (s *ListSuite) TestFilesystemListArgs(c *gc.C) { 42 var called bool 43 expectedArgs := []string{"a", "b", "c"} 44 s.mockAPI.listFilesystems = func(arg []string) ([]params.FilesystemDetailsListResult, error) { 45 c.Assert(arg, jc.DeepEquals, expectedArgs) 46 called = true 47 return nil, nil 48 } 49 s.assertValidFilesystemList( 50 c, 51 append([]string{"--format", "yaml"}, expectedArgs...), 52 "", 53 ) 54 c.Assert(called, jc.IsTrue) 55 } 56 57 func (s *ListSuite) TestFilesystemListYaml(c *gc.C) { 58 s.assertUnmarshalledOutput( 59 c, 60 goyaml.Unmarshal, 61 "", // no error 62 "--format", "yaml") 63 } 64 65 func (s *ListSuite) TestFilesystemListJSON(c *gc.C) { 66 s.assertUnmarshalledOutput( 67 c, 68 json.Unmarshal, 69 "", // no error 70 "--format", "json") 71 } 72 73 func (s *ListSuite) TestFilesystemListWithErrorResults(c *gc.C) { 74 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 75 results, _ := mockListAPI{}.ListFilesystems(nil) 76 results = append(results, params.FilesystemDetailsListResult{ 77 Error: ¶ms.Error{Message: "bad"}, 78 }) 79 results = append(results, params.FilesystemDetailsListResult{ 80 Error: ¶ms.Error{Message: "ness"}, 81 }) 82 return results, nil 83 } 84 // we should see the error in stderr, but it should not 85 // otherwise affect the rendering of valid results. 86 s.assertUnmarshalledOutput(c, json.Unmarshal, "bad\nness\n", "--format", "json") 87 s.assertUnmarshalledOutput(c, goyaml.Unmarshal, "bad\nness\n", "--format", "yaml") 88 } 89 90 var expectedFilesystemListTabular = ` 91 MACHINE UNIT STORAGE ID VOLUME PROVIDER-ID MOUNTPOINT SIZE STATE MESSAGE 92 0 abc/0 db-dir/1001 0/0 0/1 provider-supplied-filesystem-0-0 /mnt/fuji 512MiB attached 93 0 transcode/0 shared-fs/0 4 provider-supplied-filesystem-4 /mnt/doom 1.0GiB attached 94 0 1 provider-supplied-filesystem-1 2.0GiB attaching failed to attach, will retry 95 1 transcode/1 shared-fs/0 4 provider-supplied-filesystem-4 /mnt/huang 1.0GiB attached 96 1 2 provider-supplied-filesystem-2 /mnt/zion 3.0MiB attached 97 1 3 42MiB pending 98 99 `[1:] 100 101 func (s *ListSuite) TestFilesystemListTabular(c *gc.C) { 102 s.assertValidFilesystemList(c, []string{}, expectedFilesystemListTabular) 103 104 // Do it again, reversing the results returned by the API. 105 // We should get everything sorted in the appropriate order. 106 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 107 results, _ := mockListAPI{}.ListFilesystems(nil) 108 n := len(results) 109 for i := 0; i < n/2; i++ { 110 results[i], results[n-i-1] = results[n-i-1], results[i] 111 } 112 return results, nil 113 } 114 s.assertValidFilesystemList(c, []string{}, expectedFilesystemListTabular) 115 } 116 117 func (s *ListSuite) assertUnmarshalledOutput(c *gc.C, unmarshal unmarshaller, expectedErr string, args ...string) { 118 context, err := s.runFilesystemList(c, args...) 119 c.Assert(err, jc.ErrorIsNil) 120 121 var result struct { 122 Filesystems map[string]storage.FilesystemInfo 123 } 124 err = unmarshal([]byte(testing.Stdout(context)), &result) 125 c.Assert(err, jc.ErrorIsNil) 126 127 expected := s.expect(c, nil) 128 c.Assert(result.Filesystems, jc.DeepEquals, expected) 129 130 obtainedErr := testing.Stderr(context) 131 c.Assert(obtainedErr, gc.Equals, expectedErr) 132 } 133 134 // expect returns the FilesystemInfo mapping we should expect to unmarshal 135 // from rendered YAML or JSON. 136 func (s *ListSuite) expect(c *gc.C, machines []string) map[string]storage.FilesystemInfo { 137 all, err := s.mockAPI.ListFilesystems(machines) 138 c.Assert(err, jc.ErrorIsNil) 139 140 var valid []params.FilesystemDetails 141 for _, result := range all { 142 if result.Error == nil { 143 valid = append(valid, result.Result...) 144 } 145 } 146 result, err := storage.ConvertToFilesystemInfo(valid) 147 c.Assert(err, jc.ErrorIsNil) 148 return result 149 } 150 151 func (s *ListSuite) assertValidFilesystemList(c *gc.C, args []string, expectedOut string) { 152 context, err := s.runFilesystemList(c, args...) 153 c.Assert(err, jc.ErrorIsNil) 154 s.assertUserFacingOutput(c, context, expectedOut, "") 155 } 156 157 func (s *ListSuite) runFilesystemList(c *gc.C, args ...string) (*cmd.Context, error) { 158 return testing.RunCommand(c, 159 storage.NewListCommandForTest(s.mockAPI, s.store), append(args, "--filesystem")...) 160 } 161 162 func (s *ListSuite) assertUserFacingOutput(c *gc.C, context *cmd.Context, expectedOut, expectedErr string) { 163 obtainedOut := testing.Stdout(context) 164 c.Assert(obtainedOut, gc.Equals, expectedOut) 165 166 obtainedErr := testing.Stderr(context) 167 c.Assert(obtainedErr, gc.Equals, expectedErr) 168 } 169 170 func (s mockListAPI) ListFilesystems(machines []string) ([]params.FilesystemDetailsListResult, error) { 171 if s.listFilesystems != nil { 172 return s.listFilesystems(machines) 173 } 174 results := []params.FilesystemDetailsListResult{{Result: []params.FilesystemDetails{ 175 // filesystem 0/0 is attached to machine 0, assigned to 176 // storage db-dir/1001, which is attached to unit 177 // abc/0. 178 { 179 FilesystemTag: "filesystem-0-0", 180 VolumeTag: "volume-0-1", 181 Info: params.FilesystemInfo{ 182 FilesystemId: "provider-supplied-filesystem-0-0", 183 Size: 512, 184 }, 185 Status: createTestStatus(status.StatusAttached, ""), 186 MachineAttachments: map[string]params.FilesystemAttachmentInfo{ 187 "machine-0": params.FilesystemAttachmentInfo{ 188 MountPoint: "/mnt/fuji", 189 }, 190 }, 191 Storage: ¶ms.StorageDetails{ 192 StorageTag: "storage-db-dir-1001", 193 OwnerTag: "unit-abc-0", 194 Kind: params.StorageKindBlock, 195 Status: createTestStatus(status.StatusAttached, ""), 196 Attachments: map[string]params.StorageAttachmentDetails{ 197 "unit-abc-0": params.StorageAttachmentDetails{ 198 StorageTag: "storage-db-dir-1001", 199 UnitTag: "unit-abc-0", 200 MachineTag: "machine-0", 201 Location: "/mnt/fuji", 202 }, 203 }, 204 }, 205 }, 206 // filesystem 1 is attaching to machine 0, but is not assigned 207 // to any storage. 208 { 209 FilesystemTag: "filesystem-1", 210 Info: params.FilesystemInfo{ 211 FilesystemId: "provider-supplied-filesystem-1", 212 Size: 2048, 213 }, 214 Status: createTestStatus(status.StatusAttaching, "failed to attach, will retry"), 215 MachineAttachments: map[string]params.FilesystemAttachmentInfo{ 216 "machine-0": params.FilesystemAttachmentInfo{}, 217 }, 218 }, 219 // filesystem 3 is due to be attached to machine 1, but is not 220 // assigned to any storage and has not yet been provisioned. 221 { 222 FilesystemTag: "filesystem-3", 223 Info: params.FilesystemInfo{ 224 Size: 42, 225 }, 226 Status: createTestStatus(status.StatusPending, ""), 227 MachineAttachments: map[string]params.FilesystemAttachmentInfo{ 228 "machine-1": params.FilesystemAttachmentInfo{}, 229 }, 230 }, 231 // filesystem 2 is due to be attached to machine 1, but is not 232 // assigned to any storage. 233 { 234 FilesystemTag: "filesystem-2", 235 Info: params.FilesystemInfo{ 236 FilesystemId: "provider-supplied-filesystem-2", 237 Size: 3, 238 }, 239 Status: createTestStatus(status.StatusAttached, ""), 240 MachineAttachments: map[string]params.FilesystemAttachmentInfo{ 241 "machine-1": params.FilesystemAttachmentInfo{ 242 MountPoint: "/mnt/zion", 243 }, 244 }, 245 }, 246 // filesystem 4 is attached to machines 0 and 1, and is assigned 247 // to shared storage. 248 { 249 FilesystemTag: "filesystem-4", 250 Info: params.FilesystemInfo{ 251 FilesystemId: "provider-supplied-filesystem-4", 252 Size: 1024, 253 }, 254 Status: createTestStatus(status.StatusAttached, ""), 255 MachineAttachments: map[string]params.FilesystemAttachmentInfo{ 256 "machine-0": params.FilesystemAttachmentInfo{ 257 MountPoint: "/mnt/doom", 258 ReadOnly: true, 259 }, 260 "machine-1": params.FilesystemAttachmentInfo{ 261 MountPoint: "/mnt/huang", 262 ReadOnly: true, 263 }, 264 }, 265 Storage: ¶ms.StorageDetails{ 266 StorageTag: "storage-shared-fs-0", 267 OwnerTag: "service-transcode", 268 Kind: params.StorageKindBlock, 269 Status: createTestStatus(status.StatusAttached, ""), 270 Attachments: map[string]params.StorageAttachmentDetails{ 271 "unit-transcode-0": params.StorageAttachmentDetails{ 272 StorageTag: "storage-shared-fs-0", 273 UnitTag: "unit-transcode-0", 274 MachineTag: "machine-0", 275 Location: "/mnt/bits", 276 }, 277 "unit-transcode-1": params.StorageAttachmentDetails{ 278 StorageTag: "storage-shared-fs-0", 279 UnitTag: "unit-transcode-1", 280 MachineTag: "machine-1", 281 Location: "/mnt/pieces", 282 }, 283 }, 284 }, 285 }, 286 }}} 287 return results, nil 288 }