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