github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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/cmd/cmdtesting" 11 "github.com/juju/errors" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 goyaml "gopkg.in/yaml.v2" 15 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/cmd/juju/storage" 18 "github.com/juju/juju/core/status" 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 var emptyMockAPI mockListAPI 76 results, _ := emptyMockAPI.ListFilesystems(nil) 77 results = append(results, params.FilesystemDetailsListResult{ 78 Error: ¶ms.Error{Message: "bad"}, 79 }) 80 results = append(results, params.FilesystemDetailsListResult{ 81 Error: ¶ms.Error{Message: "ness"}, 82 }) 83 return results, nil 84 } 85 // we should see the error in stderr, but it should not 86 // otherwise affect the rendering of valid results. 87 s.assertUnmarshalledOutput(c, json.Unmarshal, "bad\nness\n", "--format", "json") 88 s.assertUnmarshalledOutput(c, goyaml.Unmarshal, "bad\nness\n", "--format", "yaml") 89 } 90 91 var expectedFilesystemListTabular = ` 92 Machine Unit Storage id Id Volume Provider id Mountpoint Size State Message 93 0 abc/0 db-dir/1001 0/0 0/1 provider-supplied-filesystem-0-0 /mnt/fuji 512MiB attached 94 0 transcode/0 shared-fs/0 4 provider-supplied-filesystem-4 /mnt/doom 1.0GiB attached 95 0 1 provider-supplied-filesystem-1 2.0GiB attaching failed to attach, will retry 96 1 transcode/1 shared-fs/0 4 provider-supplied-filesystem-4 /mnt/huang 1.0GiB attached 97 1 2 provider-supplied-filesystem-2 /mnt/zion 3.0MiB attached 98 1 3 42MiB pending 99 100 `[1:] 101 102 func (s *ListSuite) TestFilesystemListTabular(c *gc.C) { 103 s.assertValidFilesystemList(c, []string{}, expectedFilesystemListTabular) 104 105 // Do it again, reversing the results returned by the API. 106 // We should get everything sorted in the appropriate order. 107 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 108 results, _ := mockListAPI{}.ListFilesystems(nil) 109 n := len(results) 110 for i := 0; i < n/2; i++ { 111 results[i], results[n-i-1] = results[n-i-1], results[i] 112 } 113 return results, nil 114 } 115 s.assertValidFilesystemList(c, []string{}, expectedFilesystemListTabular) 116 } 117 118 var expectedCAASFilesystemListTabular = ` 119 Unit Storage id Id Provider id Mountpoint Size State Message 120 mysql/0 db-dir/1001 0/0 provider-supplied-filesystem-0-0 /mnt/fuji 512MiB attached 121 122 `[1:] 123 124 func (s *ListSuite) TestCAASFilesystemListTabular(c *gc.C) { 125 s.assertValidFilesystemList(c, []string{}, expectedFilesystemListTabular) 126 127 // Do it again, reversing the results returned by the API. 128 // We should get everything sorted in the appropriate order. 129 s.mockAPI.listFilesystems = func([]string) ([]params.FilesystemDetailsListResult, error) { 130 results := []params.FilesystemDetailsListResult{{Result: []params.FilesystemDetails{ 131 { 132 FilesystemTag: "filesystem-0-0", 133 Info: params.FilesystemInfo{ 134 FilesystemId: "provider-supplied-filesystem-0-0", 135 Size: 512, 136 }, 137 Life: "alive", 138 Status: createTestStatus(status.Attached, "", s.mockAPI.time), 139 UnitAttachments: map[string]params.FilesystemAttachmentDetails{ 140 "unit-mysql-0": { 141 Life: "alive", 142 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 143 MountPoint: "/mnt/fuji", 144 }, 145 }, 146 }, 147 Storage: ¶ms.StorageDetails{ 148 StorageTag: "storage-db-dir-1001", 149 OwnerTag: "unit-abc-0", 150 Kind: params.StorageKindBlock, 151 Life: "alive", 152 Status: createTestStatus(status.Attached, "", s.mockAPI.time), 153 Attachments: map[string]params.StorageAttachmentDetails{ 154 "unit-mysql-0": { 155 StorageTag: "storage-db-dir-1001", 156 UnitTag: "unit-abc-0", 157 MachineTag: "machine-0", 158 Location: "/mnt/fuji", 159 }, 160 }, 161 }, 162 }, 163 }}} 164 return results, nil 165 } 166 s.assertValidFilesystemList(c, []string{}, expectedCAASFilesystemListTabular) 167 } 168 169 func (s *ListSuite) assertUnmarshalledOutput(c *gc.C, unmarshal unmarshaller, expectedErr string, args ...string) { 170 context, err := s.runFilesystemList(c, args...) 171 c.Assert(err, jc.ErrorIsNil) 172 173 var result struct { 174 Filesystems map[string]storage.FilesystemInfo 175 } 176 err = unmarshal([]byte(cmdtesting.Stdout(context)), &result) 177 c.Assert(err, jc.ErrorIsNil) 178 179 expected := s.expect(c, nil) 180 c.Assert(result.Filesystems, jc.DeepEquals, expected) 181 182 obtainedErr := cmdtesting.Stderr(context) 183 c.Assert(obtainedErr, gc.Equals, expectedErr) 184 } 185 186 // expect returns the FilesystemInfo mapping we should expect to unmarshal 187 // from rendered YAML or JSON. 188 func (s *ListSuite) expect(c *gc.C, machines []string) map[string]storage.FilesystemInfo { 189 all, err := s.mockAPI.ListFilesystems(machines) 190 c.Assert(err, jc.ErrorIsNil) 191 192 var valid []params.FilesystemDetails 193 for _, result := range all { 194 if result.Error == nil { 195 valid = append(valid, result.Result...) 196 } 197 } 198 result, err := storage.ConvertToFilesystemInfo(valid) 199 c.Assert(err, jc.ErrorIsNil) 200 return result 201 } 202 203 func (s *ListSuite) assertValidFilesystemList(c *gc.C, args []string, expectedOut string) { 204 context, err := s.runFilesystemList(c, args...) 205 c.Assert(err, jc.ErrorIsNil) 206 s.assertUserFacingOutput(c, context, expectedOut, "") 207 } 208 209 func (s *ListSuite) runFilesystemList(c *gc.C, args ...string) (*cmd.Context, error) { 210 return cmdtesting.RunCommand(c, 211 storage.NewListCommandForTest(s.mockAPI, s.store), append(args, "--filesystem")...) 212 } 213 214 func (s *ListSuite) assertUserFacingOutput(c *gc.C, context *cmd.Context, expectedOut, expectedErr string) { 215 obtainedOut := cmdtesting.Stdout(context) 216 c.Assert(obtainedOut, gc.Equals, expectedOut) 217 218 obtainedErr := cmdtesting.Stderr(context) 219 c.Assert(obtainedErr, gc.Equals, expectedErr) 220 } 221 222 func (s mockListAPI) ListFilesystems(machines []string) ([]params.FilesystemDetailsListResult, error) { 223 if s.listFilesystems != nil { 224 return s.listFilesystems(machines) 225 } 226 results := []params.FilesystemDetailsListResult{{Result: []params.FilesystemDetails{ 227 // filesystem 0/0 is attached to machine 0, assigned to 228 // storage db-dir/1001, which is attached to unit 229 // abc/0. 230 { 231 FilesystemTag: "filesystem-0-0", 232 VolumeTag: "volume-0-1", 233 Info: params.FilesystemInfo{ 234 FilesystemId: "provider-supplied-filesystem-0-0", 235 Size: 512, 236 }, 237 Life: "alive", 238 Status: createTestStatus(status.Attached, "", s.time), 239 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 240 "machine-0": { 241 Life: "alive", 242 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 243 MountPoint: "/mnt/fuji", 244 }, 245 }, 246 }, 247 Storage: ¶ms.StorageDetails{ 248 StorageTag: "storage-db-dir-1001", 249 OwnerTag: "unit-abc-0", 250 Kind: params.StorageKindBlock, 251 Life: "alive", 252 Status: createTestStatus(status.Attached, "", s.time), 253 Attachments: map[string]params.StorageAttachmentDetails{ 254 "unit-abc-0": { 255 StorageTag: "storage-db-dir-1001", 256 UnitTag: "unit-abc-0", 257 MachineTag: "machine-0", 258 Location: "/mnt/fuji", 259 }, 260 }, 261 }, 262 }, 263 // filesystem 1 is attaching to machine 0, but is not assigned 264 // to any storage. 265 { 266 FilesystemTag: "filesystem-1", 267 Info: params.FilesystemInfo{ 268 FilesystemId: "provider-supplied-filesystem-1", 269 Size: 2048, 270 }, 271 Status: createTestStatus(status.Attaching, "failed to attach, will retry", s.time), 272 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 273 "machine-0": {}, 274 }, 275 }, 276 // filesystem 3 is due to be attached to machine 1, but is not 277 // assigned to any storage and has not yet been provisioned. 278 { 279 FilesystemTag: "filesystem-3", 280 Info: params.FilesystemInfo{ 281 Size: 42, 282 }, 283 Status: createTestStatus(status.Pending, "", s.time), 284 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 285 "machine-1": {}, 286 }, 287 }, 288 // filesystem 2 is due to be attached to machine 1, but is not 289 // assigned to any storage. 290 { 291 FilesystemTag: "filesystem-2", 292 Info: params.FilesystemInfo{ 293 FilesystemId: "provider-supplied-filesystem-2", 294 Size: 3, 295 }, 296 Status: createTestStatus(status.Attached, "", s.time), 297 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 298 "machine-1": { 299 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 300 MountPoint: "/mnt/zion", 301 }, 302 }, 303 }, 304 }, 305 // filesystem 4 is attached to machines 0 and 1, and is assigned 306 // to shared storage. 307 { 308 FilesystemTag: "filesystem-4", 309 Info: params.FilesystemInfo{ 310 FilesystemId: "provider-supplied-filesystem-4", 311 Pool: "radiance", 312 Size: 1024, 313 }, 314 Status: createTestStatus(status.Attached, "", s.time), 315 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 316 "machine-0": { 317 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 318 MountPoint: "/mnt/doom", 319 ReadOnly: true, 320 }, 321 }, 322 "machine-1": { 323 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 324 MountPoint: "/mnt/huang", 325 ReadOnly: true, 326 }, 327 }, 328 }, 329 Storage: ¶ms.StorageDetails{ 330 StorageTag: "storage-shared-fs-0", 331 OwnerTag: "application-transcode", 332 Kind: params.StorageKindBlock, 333 Status: createTestStatus(status.Attached, "", s.time), 334 Attachments: map[string]params.StorageAttachmentDetails{ 335 "unit-transcode-0": { 336 StorageTag: "storage-shared-fs-0", 337 UnitTag: "unit-transcode-0", 338 MachineTag: "machine-0", 339 Location: "/mnt/bits", 340 }, 341 "unit-transcode-1": { 342 StorageTag: "storage-shared-fs-0", 343 UnitTag: "unit-transcode-1", 344 MachineTag: "machine-1", 345 Location: "/mnt/pieces", 346 }, 347 }, 348 }, 349 }, { 350 // filesystem 5 is assigned to db-dir/1100, but is not yet 351 // attached to any machines. 352 FilesystemTag: "filesystem-5", 353 Info: params.FilesystemInfo{ 354 FilesystemId: "provider-supplied-filesystem-5", 355 Size: 3, 356 }, 357 Status: createTestStatus(status.Attached, "", s.time), 358 Storage: ¶ms.StorageDetails{ 359 StorageTag: "storage-db-dir-1100", 360 OwnerTag: "unit-abc-0", 361 Kind: params.StorageKindBlock, 362 Life: "alive", 363 Status: createTestStatus(status.Attached, "", s.time), 364 Attachments: map[string]params.StorageAttachmentDetails{ 365 "unit-abc-0": { 366 StorageTag: "storage-db-dir-1100", 367 UnitTag: "unit-abc-0", 368 Location: "/mnt/fuji", 369 }, 370 }, 371 }, 372 }, 373 }}} 374 if s.omitPool { 375 for _, result := range results { 376 for i, details := range result.Result { 377 details.Info.Pool = "" 378 result.Result[i] = details 379 } 380 } 381 } 382 return results, nil 383 }