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: &params.Error{Message: "bad"},
    78  		})
    79  		results = append(results, params.FilesystemDetailsListResult{
    80  			Error: &params.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: &params.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: &params.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  }