github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap/cmd_interface_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package main_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"net/http"
    25  	"os"
    26  
    27  	"github.com/jessevdk/go-flags"
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/client"
    31  	. "github.com/snapcore/snapd/cmd/snap"
    32  )
    33  
    34  func (s *SnapSuite) TestInterfaceHelp(c *C) {
    35  	msg := `Usage:
    36    snap.test interface [interface-OPTIONS] [<interface>]
    37  
    38  The interface command shows details of snap interfaces.
    39  
    40  If no interface name is provided, a list of interface names with at least
    41  one connection is shown, or a list of all interfaces if --all is provided.
    42  
    43  [interface command options]
    44        --attrs          Show interface attributes
    45        --all            Include unused interfaces
    46  
    47  [interface command arguments]
    48    <interface>:         Show details of a specific interface
    49  `
    50  	s.testSubCommandHelp(c, "interface", msg)
    51  }
    52  
    53  func (s *SnapSuite) TestInterfaceListEmpty(c *C) {
    54  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
    55  		c.Check(r.Method, Equals, "GET")
    56  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
    57  		c.Check(r.URL.RawQuery, Equals, "select=connected")
    58  		body, err := ioutil.ReadAll(r.Body)
    59  		c.Check(err, IsNil)
    60  		c.Check(body, DeepEquals, []byte{})
    61  		EncodeResponseBody(c, w, map[string]interface{}{
    62  			"type":   "sync",
    63  			"result": []*client.Interface{},
    64  		})
    65  	})
    66  	rest, err := Parser(Client()).ParseArgs([]string{"interface"})
    67  	c.Assert(err, ErrorMatches, "no interfaces currently connected")
    68  	c.Assert(rest, DeepEquals, []string{"interface"})
    69  	c.Assert(s.Stdout(), Equals, "")
    70  	c.Assert(s.Stderr(), Equals, "")
    71  }
    72  
    73  func (s *SnapSuite) TestInterfaceListAllEmpty(c *C) {
    74  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
    75  		c.Check(r.Method, Equals, "GET")
    76  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
    77  		c.Check(r.URL.RawQuery, Equals, "select=all")
    78  		body, err := ioutil.ReadAll(r.Body)
    79  		c.Check(err, IsNil)
    80  		c.Check(body, DeepEquals, []byte{})
    81  		EncodeResponseBody(c, w, map[string]interface{}{
    82  			"type":   "sync",
    83  			"result": []*client.Interface{},
    84  		})
    85  	})
    86  	rest, err := Parser(Client()).ParseArgs([]string{"interface", "--all"})
    87  	c.Assert(err, ErrorMatches, "no interfaces found")
    88  	c.Assert(rest, DeepEquals, []string{"--all"}) // XXX: feels like a bug in go-flags.
    89  	c.Assert(s.Stdout(), Equals, "")
    90  	c.Assert(s.Stderr(), Equals, "")
    91  }
    92  
    93  func (s *SnapSuite) TestInterfaceList(c *C) {
    94  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
    95  		c.Check(r.Method, Equals, "GET")
    96  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
    97  		c.Check(r.URL.RawQuery, Equals, "select=connected")
    98  		body, err := ioutil.ReadAll(r.Body)
    99  		c.Check(err, IsNil)
   100  		c.Check(body, DeepEquals, []byte{})
   101  		EncodeResponseBody(c, w, map[string]interface{}{
   102  			"type": "sync",
   103  			"result": []*client.Interface{{
   104  				Name:    "network",
   105  				Summary: "allows access to the network",
   106  			}, {
   107  				Name:    "network-bind",
   108  				Summary: "allows providing services on the network",
   109  			}},
   110  		})
   111  	})
   112  	rest, err := Parser(Client()).ParseArgs([]string{"interface"})
   113  	c.Assert(err, IsNil)
   114  	c.Assert(rest, DeepEquals, []string{})
   115  	expectedStdout := "" +
   116  		"Name          Summary\n" +
   117  		"network       allows access to the network\n" +
   118  		"network-bind  allows providing services on the network\n"
   119  	c.Assert(s.Stdout(), Equals, expectedStdout)
   120  	c.Assert(s.Stderr(), Equals, "")
   121  }
   122  
   123  func (s *SnapSuite) TestInterfaceListAll(c *C) {
   124  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   125  		c.Check(r.Method, Equals, "GET")
   126  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
   127  		c.Check(r.URL.RawQuery, Equals, "select=all")
   128  		body, err := ioutil.ReadAll(r.Body)
   129  		c.Check(err, IsNil)
   130  		c.Check(body, DeepEquals, []byte{})
   131  		EncodeResponseBody(c, w, map[string]interface{}{
   132  			"type": "sync",
   133  			"result": []*client.Interface{{
   134  				Name:    "network",
   135  				Summary: "allows access to the network",
   136  			}, {
   137  				Name:    "network-bind",
   138  				Summary: "allows providing services on the network",
   139  			}, {
   140  				Name:    "unused",
   141  				Summary: "just an unused interface, nothing to see here",
   142  			}},
   143  		})
   144  	})
   145  	rest, err := Parser(Client()).ParseArgs([]string{"interface", "--all"})
   146  	c.Assert(err, IsNil)
   147  	c.Assert(rest, DeepEquals, []string{})
   148  	expectedStdout := "" +
   149  		"Name          Summary\n" +
   150  		"network       allows access to the network\n" +
   151  		"network-bind  allows providing services on the network\n" +
   152  		"unused        just an unused interface, nothing to see here\n"
   153  	c.Assert(s.Stdout(), Equals, expectedStdout)
   154  	c.Assert(s.Stderr(), Equals, "")
   155  }
   156  
   157  func (s *SnapSuite) TestInterfaceDetails(c *C) {
   158  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   159  		c.Check(r.Method, Equals, "GET")
   160  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
   161  		c.Check(r.URL.RawQuery, Equals, "doc=true&names=network&plugs=true&select=all&slots=true")
   162  		body, err := ioutil.ReadAll(r.Body)
   163  		c.Check(err, IsNil)
   164  		c.Check(body, DeepEquals, []byte{})
   165  		EncodeResponseBody(c, w, map[string]interface{}{
   166  			"type": "sync",
   167  			"result": []*client.Interface{{
   168  				Name:    "network",
   169  				Summary: "allows access to the network",
   170  				DocURL:  "http://example.org/about-the-network-interface",
   171  				Plugs: []client.Plug{
   172  					{Snap: "deepin-music", Name: "network"},
   173  					{Snap: "http", Name: "network"},
   174  				},
   175  				Slots: []client.Slot{{Snap: "system", Name: "network"}},
   176  			}},
   177  		})
   178  	})
   179  	rest, err := Parser(Client()).ParseArgs([]string{"interface", "network"})
   180  	c.Assert(err, IsNil)
   181  	c.Assert(rest, DeepEquals, []string{})
   182  	expectedStdout := "" +
   183  		"name:          network\n" +
   184  		"summary:       allows access to the network\n" +
   185  		"documentation: http://example.org/about-the-network-interface\n" +
   186  		"plugs:\n" +
   187  		"  - deepin-music\n" +
   188  		"  - http\n" +
   189  		"slots:\n" +
   190  		"  - system\n"
   191  	c.Assert(s.Stdout(), Equals, expectedStdout)
   192  	c.Assert(s.Stderr(), Equals, "")
   193  }
   194  
   195  func (s *SnapSuite) TestInterfaceDetailsAndAttrs(c *C) {
   196  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   197  		c.Check(r.Method, Equals, "GET")
   198  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
   199  		c.Check(r.URL.RawQuery, Equals, "doc=true&names=serial-port&plugs=true&select=all&slots=true")
   200  		body, err := ioutil.ReadAll(r.Body)
   201  		c.Check(err, IsNil)
   202  		c.Check(body, DeepEquals, []byte{})
   203  		EncodeResponseBody(c, w, map[string]interface{}{
   204  			"type": "sync",
   205  			"result": []*client.Interface{{
   206  				Name:    "serial-port",
   207  				Summary: "allows providing or using a specific serial port",
   208  				Plugs: []client.Plug{
   209  					{Snap: "minicom", Name: "serial-port"},
   210  				},
   211  				Slots: []client.Slot{{
   212  					Snap:  "gizmo-gadget",
   213  					Name:  "debug-serial-port",
   214  					Label: "serial port for debugging",
   215  					Attrs: map[string]interface{}{
   216  						"header":   "pin-array",
   217  						"location": "internal",
   218  						"path":     "/dev/ttyS0",
   219  						"number":   1,
   220  					},
   221  				}},
   222  			}},
   223  		})
   224  	})
   225  	rest, err := Parser(Client()).ParseArgs([]string{"interface", "--attrs", "serial-port"})
   226  	c.Assert(err, IsNil)
   227  	c.Assert(rest, DeepEquals, []string{})
   228  	expectedStdout := "" +
   229  		"name:    serial-port\n" +
   230  		"summary: allows providing or using a specific serial port\n" +
   231  		"plugs:\n" +
   232  		"  - minicom\n" +
   233  		"slots:\n" +
   234  		"  - gizmo-gadget:debug-serial-port (serial port for debugging):\n" +
   235  		"      header:   pin-array\n" +
   236  		"      location: internal\n" +
   237  		"      number:   1\n" +
   238  		"      path:     /dev/ttyS0\n"
   239  	c.Assert(s.Stdout(), Equals, expectedStdout)
   240  	c.Assert(s.Stderr(), Equals, "")
   241  }
   242  
   243  func (s *SnapSuite) TestInterfaceCompletion(c *C) {
   244  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   245  		c.Assert(r.Method, Equals, "GET")
   246  		c.Check(r.URL.Path, Equals, "/v2/interfaces")
   247  		c.Check(r.URL.RawQuery, Equals, "select=all")
   248  		EncodeResponseBody(c, w, map[string]interface{}{
   249  			"type": "sync",
   250  			"result": []*client.Interface{{
   251  				Name:    "network",
   252  				Summary: "allows access to the network",
   253  			}, {
   254  				Name:    "network-bind",
   255  				Summary: "allows providing services on the network",
   256  			}},
   257  		})
   258  	})
   259  	os.Setenv("GO_FLAGS_COMPLETION", "verbose")
   260  	defer os.Unsetenv("GO_FLAGS_COMPLETION")
   261  
   262  	expected := []flags.Completion{}
   263  	parser := Parser(Client())
   264  	parser.CompletionHandler = func(obtained []flags.Completion) {
   265  		c.Check(obtained, DeepEquals, expected)
   266  	}
   267  
   268  	expected = []flags.Completion{
   269  		{Item: "network", Description: "allows access to the network"},
   270  		{Item: "network-bind", Description: "allows providing services on the network"},
   271  	}
   272  	_, err := parser.ParseArgs([]string{"interface", ""})
   273  	c.Assert(err, IsNil)
   274  
   275  	expected = []flags.Completion{
   276  		{Item: "network-bind", Description: "allows providing services on the network"},
   277  	}
   278  	_, err = parser.ParseArgs([]string{"interface", "network-"})
   279  	c.Assert(err, IsNil)
   280  
   281  	expected = []flags.Completion{}
   282  	_, err = parser.ParseArgs([]string{"interface", "bogus"})
   283  	c.Assert(err, IsNil)
   284  
   285  	c.Assert(s.Stdout(), Equals, "")
   286  	c.Assert(s.Stderr(), Equals, "")
   287  }