github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/space/list_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package space_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"github.com/juju/errors"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/cmd/juju/space"
    18  )
    19  
    20  type ListSuite struct {
    21  	BaseSpaceSuite
    22  }
    23  
    24  var _ = gc.Suite(&ListSuite{})
    25  
    26  func (s *ListSuite) SetUpTest(c *gc.C) {
    27  	s.BaseSpaceSuite.SetUpTest(c)
    28  	s.newCommand = space.NewListCommand
    29  }
    30  
    31  func (s *ListSuite) TestInit(c *gc.C) {
    32  	for i, test := range []struct {
    33  		about        string
    34  		args         []string
    35  		expectShort  bool
    36  		expectFormat string
    37  		expectErr    string
    38  	}{{
    39  		about:        "unrecognized arguments",
    40  		args:         s.Strings("foo"),
    41  		expectErr:    `unrecognized args: \["foo"\]`,
    42  		expectFormat: "tabular",
    43  	}, {
    44  		about:        "invalid format",
    45  		args:         s.Strings("--format", "foo"),
    46  		expectErr:    `invalid value "foo" for option --format: unknown format "foo"`,
    47  		expectFormat: "tabular",
    48  	}, {
    49  		about:        "invalid format (value is case-sensitive)",
    50  		args:         s.Strings("--format", "JSON"),
    51  		expectErr:    `invalid value "JSON" for option --format: unknown format "JSON"`,
    52  		expectFormat: "tabular",
    53  	}, {
    54  		about:        "json format",
    55  		args:         s.Strings("--format", "json"),
    56  		expectFormat: "json",
    57  	}, {
    58  		about:        "yaml format",
    59  		args:         s.Strings("--format", "yaml"),
    60  		expectFormat: "yaml",
    61  	}, {
    62  		about:        "tabular format",
    63  		args:         s.Strings("--format", "tabular"),
    64  		expectFormat: "tabular",
    65  	}, {
    66  		// --output and -o are tested separately in TestOutputFormats.
    67  		about:        "both --output and -o specified (latter overrides former)",
    68  		args:         s.Strings("--output", "foo", "-o", "bar"),
    69  		expectFormat: "tabular",
    70  	}} {
    71  		c.Logf("test #%d: %s", i, test.about)
    72  		command, err := s.InitCommand(c, test.args...)
    73  		if test.expectErr != "" {
    74  			c.Check(err, gc.ErrorMatches, test.expectErr)
    75  		} else {
    76  			c.Check(err, jc.ErrorIsNil)
    77  			command := command.(*space.ListCommand)
    78  			c.Check(command.ListFormat(), gc.Equals, test.expectFormat)
    79  			c.Check(command.Short, gc.Equals, test.expectShort)
    80  		}
    81  
    82  		// No API calls should be recorded at this stage.
    83  		s.api.CheckCallNames(c)
    84  	}
    85  }
    86  
    87  func (s *ListSuite) TestOutputFormats(c *gc.C) {
    88  	outDir := c.MkDir()
    89  	expectedYAML := `
    90  spaces:
    91    space1:
    92      2001:db8::/32:
    93        type: ipv6
    94        provider-id: subnet-public
    95        status: terminating
    96        zones:
    97        - zone2
    98      invalid:
    99        type: unknown
   100        provider-id: no-such
   101        status: 'error: invalid subnet CIDR: invalid'
   102        zones:
   103        - zone1
   104    space2:
   105      4.3.2.0/28:
   106        type: ipv4
   107        provider-id: vlan-42
   108        status: terminating
   109        zones:
   110        - zone1
   111      10.1.2.0/24:
   112        type: ipv4
   113        provider-id: subnet-private
   114        status: in-use
   115        zones:
   116        - zone1
   117        - zone2
   118  `[1:]
   119  	unwrap := regexp.MustCompile(`[\s+\n]`)
   120  	expectedJSON := unwrap.ReplaceAllLiteralString(`
   121  {
   122    "spaces": {
   123      "space1": {
   124        "2001:db8::/32": {
   125          "type": "ipv6",
   126          "provider-id": "subnet-public",
   127          "status": "terminating",
   128          "zones": ["zone2"]
   129        },
   130        "invalid": {
   131          "type": "unknown",
   132          "provider-id": "no-such",
   133          "status": "error: invalid subnet CIDR: invalid",
   134          "zones": ["zone1"]
   135        }
   136      },
   137      "space2": {
   138        "10.1.2.0/24": {
   139          "type": "ipv4",
   140          "provider-id": "subnet-private",
   141          "status": "in-use",
   142          "zones": ["zone1","zone2"]
   143        },
   144        "4.3.2.0/28": {
   145          "type": "ipv4",
   146          "provider-id": "vlan-42",
   147          "status": "terminating",
   148          "zones": ["zone1"]
   149        }
   150      }
   151    }
   152  }
   153  `, "") + "\n"
   154  	// Work around the big unwrap hammer above.
   155  	expectedJSON = strings.Replace(
   156  		expectedJSON,
   157  		"error:invalidsubnetCIDR:invalid",
   158  		"error: invalid subnet CIDR: invalid",
   159  		1,
   160  	)
   161  	expectedShortYAML := `
   162  spaces:
   163  - space1
   164  - space2
   165  `[1:]
   166  
   167  	expectedShortJSON := unwrap.ReplaceAllLiteralString(`
   168  {
   169    "spaces": [
   170      "space1",
   171      "space2"
   172    ]
   173  }
   174  `, "") + "\n"
   175  
   176  	expectedTabular := `Space   Subnets
   177  space1  2001:db8::/32
   178          invalid
   179  space2  10.1.2.0/24
   180          4.3.2.0/28
   181  
   182  `
   183  	expectedShortTabular := `Space
   184  space1
   185  space2
   186  
   187  `
   188  
   189  	assertAPICalls := func() {
   190  		// Verify the API calls and reset the recorded calls.
   191  		s.api.CheckCallNames(c, "ListSpaces", "Close")
   192  		s.api.ResetCalls()
   193  	}
   194  	makeArgs := func(format string, short bool, extraArgs ...string) []string {
   195  		args := s.Strings(extraArgs...)
   196  		if format != "" {
   197  			args = append(args, "--format", format)
   198  		}
   199  		if short == true {
   200  			args = append(args, "--short")
   201  		}
   202  		return args
   203  	}
   204  	assertOutput := func(format, expected string, short bool) {
   205  		outFile := filepath.Join(outDir, "output")
   206  		c.Assert(outFile, jc.DoesNotExist)
   207  		defer os.Remove(outFile)
   208  		// Check -o works.
   209  		var args []string
   210  		args = makeArgs(format, short, "-o", outFile)
   211  		s.AssertRunSucceeds(c, "", "", args...)
   212  		assertAPICalls()
   213  
   214  		data, err := ioutil.ReadFile(outFile)
   215  		c.Assert(err, jc.ErrorIsNil)
   216  		c.Assert(string(data), gc.Equals, expected)
   217  
   218  		// Check the last output argument takes precedence when both
   219  		// -o and --output are given (and also that --output works the
   220  		// same as -o).
   221  		outFile1 := filepath.Join(outDir, "output1")
   222  		c.Assert(outFile1, jc.DoesNotExist)
   223  		defer os.Remove(outFile1)
   224  		outFile2 := filepath.Join(outDir, "output2")
   225  		c.Assert(outFile2, jc.DoesNotExist)
   226  		defer os.Remove(outFile2)
   227  		// Write something in outFile2 to verify its contents are
   228  		// overwritten.
   229  		err = ioutil.WriteFile(outFile2, []byte("some contents"), 0644)
   230  		c.Assert(err, jc.ErrorIsNil)
   231  
   232  		args = makeArgs(format, short, "-o", outFile1, "--output", outFile2)
   233  		s.AssertRunSucceeds(c, "", "", args...)
   234  		// Check only the last output file was used, and the output
   235  		// file was overwritten.
   236  		c.Assert(outFile1, jc.DoesNotExist)
   237  		data, err = ioutil.ReadFile(outFile2)
   238  		c.Assert(err, jc.ErrorIsNil)
   239  		c.Assert(string(data), gc.Equals, expected)
   240  		assertAPICalls()
   241  
   242  		// Finally, check without --output.
   243  		args = makeArgs(format, short)
   244  		s.AssertRunSucceeds(c, "", expected, args...)
   245  		assertAPICalls()
   246  	}
   247  
   248  	for i, test := range []struct {
   249  		format   string
   250  		expected string
   251  		short    bool
   252  	}{
   253  		{"", expectedTabular, false}, // default format is tabular
   254  		{"tabular", expectedTabular, false},
   255  		{"yaml", expectedYAML, false},
   256  		{"json", expectedJSON, false},
   257  		{"", expectedShortTabular, true}, // default format is tabular
   258  		{"tabular", expectedShortTabular, true},
   259  		{"yaml", expectedShortYAML, true},
   260  		{"json", expectedShortJSON, true},
   261  	} {
   262  		c.Logf("test #%d: format %q, short %v", i, test.format, test.short)
   263  		assertOutput(test.format, test.expected, test.short)
   264  	}
   265  }
   266  
   267  func (s *ListSuite) TestRunWhenNoSpacesExistSucceeds(c *gc.C) {
   268  	s.api.Spaces = s.api.Spaces[0:0]
   269  
   270  	s.AssertRunSucceeds(c,
   271  		`no spaces to display\n`,
   272  		"", // empty stdout.
   273  	)
   274  
   275  	s.api.CheckCallNames(c, "ListSpaces", "Close")
   276  	s.api.CheckCall(c, 0, "ListSpaces")
   277  }
   278  
   279  func (s *ListSuite) TestRunWhenNoSpacesExistSucceedsWithProperFormat(c *gc.C) {
   280  	s.api.Spaces = s.api.Spaces[0:0]
   281  
   282  	s.AssertRunSucceeds(c,
   283  		`no spaces to display\n`,
   284  		"{\"spaces\":{}}\n", // json formatted stdout.
   285  		"--format=json",
   286  	)
   287  
   288  	s.AssertRunSucceeds(c,
   289  		`no spaces to display\n`,
   290  		"spaces: {}\n", // yaml formatted stdout.
   291  		"--format=yaml",
   292  	)
   293  
   294  	s.api.CheckCallNames(c, "ListSpaces", "Close", "ListSpaces", "Close")
   295  	s.api.CheckCall(c, 0, "ListSpaces")
   296  	s.api.CheckCall(c, 2, "ListSpaces")
   297  }
   298  
   299  func (s *ListSuite) TestRunWhenSpacesNotSupported(c *gc.C) {
   300  	s.api.SetErrors(errors.NewNotSupported(nil, "spaces not supported"))
   301  
   302  	err := s.AssertRunSpacesNotSupported(c, "cannot list spaces: spaces not supported")
   303  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   304  
   305  	s.api.CheckCallNames(c, "ListSpaces", "Close")
   306  	s.api.CheckCall(c, 0, "ListSpaces")
   307  }
   308  
   309  func (s *ListSuite) TestRunWhenSpacesAPIFails(c *gc.C) {
   310  	s.api.SetErrors(errors.New("boom"))
   311  
   312  	s.AssertRunFails(c, "cannot list spaces: boom")
   313  
   314  	s.api.CheckCallNames(c, "ListSpaces", "Close")
   315  	s.api.CheckCall(c, 0, "ListSpaces")
   316  }