github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/interfaces/core_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 interfaces_test
    21  
    22  import (
    23  	"fmt"
    24  	"testing"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/interfaces"
    29  	"github.com/snapcore/snapd/interfaces/builtin"
    30  	"github.com/snapcore/snapd/interfaces/ifacetest"
    31  	"github.com/snapcore/snapd/snap"
    32  	"github.com/snapcore/snapd/snap/snaptest"
    33  	"github.com/snapcore/snapd/testutil"
    34  )
    35  
    36  func Test(t *testing.T) {
    37  	TestingT(t)
    38  }
    39  
    40  type CoreSuite struct {
    41  	testutil.BaseTest
    42  }
    43  
    44  var _ = Suite(&CoreSuite{})
    45  
    46  func (s *CoreSuite) SetUpTest(c *C) {
    47  	s.BaseTest.SetUpTest(c)
    48  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    49  }
    50  
    51  func (s *CoreSuite) TearDownTest(c *C) {
    52  	s.BaseTest.TearDownTest(c)
    53  }
    54  
    55  func (s *CoreSuite) TestValidateDBusBusName(c *C) {
    56  	// https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
    57  	validNames := []string{
    58  		"a.b", "a.b.c", "a.b1", "a.b1.c2d",
    59  		"a_a.b", "a_a.b_b.c_c", "a_a.b_b1", "a_a.b_b1.c_c2d_d",
    60  		"a-a.b", "a-a.b-b.c-c", "a-a.b-b1", "a-a.b-b1.c-c2d-d",
    61  	}
    62  	for _, name := range validNames {
    63  		err := interfaces.ValidateDBusBusName(name)
    64  		c.Assert(err, IsNil)
    65  	}
    66  
    67  	invalidNames := []string{
    68  		// must not start with ':'
    69  		":a.b",
    70  		// only from [A-Z][a-z][0-9]_-
    71  		"@.a",
    72  		// elements may not start with number
    73  		"0.a",
    74  		"a.0a",
    75  		// must have more than one element
    76  		"a",
    77  		"a_a",
    78  		"a-a",
    79  		// element must not begin with '.'
    80  		".a",
    81  		// each element must be at least 1 character
    82  		"a.",
    83  		"a..b",
    84  		".a.b",
    85  		"a.b.",
    86  	}
    87  	for _, name := range invalidNames {
    88  		err := interfaces.ValidateDBusBusName(name)
    89  		c.Assert(err, ErrorMatches, `invalid DBus bus name: ".*"`)
    90  	}
    91  
    92  	// must not be empty
    93  	err := interfaces.ValidateDBusBusName("")
    94  	c.Assert(err, ErrorMatches, `DBus bus name must be set`)
    95  
    96  	// must not exceed maximum length
    97  	longName := make([]byte, 256)
    98  	for i := range longName {
    99  		longName[i] = 'b'
   100  	}
   101  	// make it look otherwise valid (a.bbbb...)
   102  	longName[0] = 'a'
   103  	longName[1] = '.'
   104  	err = interfaces.ValidateDBusBusName(string(longName))
   105  	c.Assert(err, ErrorMatches, `DBus bus name is too long \(must be <= 255\)`)
   106  }
   107  
   108  // PlugRef.String works as expected
   109  func (s *CoreSuite) TestPlugRefString(c *C) {
   110  	ref := interfaces.PlugRef{Snap: "snap", Name: "plug"}
   111  	c.Check(ref.String(), Equals, "snap:plug")
   112  	refPtr := &interfaces.PlugRef{Snap: "snap", Name: "plug"}
   113  	c.Check(refPtr.String(), Equals, "snap:plug")
   114  }
   115  
   116  // SlotRef.String works as expected
   117  func (s *CoreSuite) TestSlotRefString(c *C) {
   118  	ref := interfaces.SlotRef{Snap: "snap", Name: "slot"}
   119  	c.Check(ref.String(), Equals, "snap:slot")
   120  	refPtr := &interfaces.SlotRef{Snap: "snap", Name: "slot"}
   121  	c.Check(refPtr.String(), Equals, "snap:slot")
   122  }
   123  
   124  // ConnRef.ID works as expected
   125  func (s *CoreSuite) TestConnRefID(c *C) {
   126  	conn := &interfaces.ConnRef{
   127  		PlugRef: interfaces.PlugRef{Snap: "consumer", Name: "plug"},
   128  		SlotRef: interfaces.SlotRef{Snap: "producer", Name: "slot"},
   129  	}
   130  	c.Check(conn.ID(), Equals, "consumer:plug producer:slot")
   131  }
   132  
   133  // ParseConnRef works as expected
   134  func (s *CoreSuite) TestParseConnRef(c *C) {
   135  	ref, err := interfaces.ParseConnRef("consumer:plug producer:slot")
   136  	c.Assert(err, IsNil)
   137  	c.Check(ref, DeepEquals, &interfaces.ConnRef{
   138  		PlugRef: interfaces.PlugRef{Snap: "consumer", Name: "plug"},
   139  		SlotRef: interfaces.SlotRef{Snap: "producer", Name: "slot"},
   140  	})
   141  	_, err = interfaces.ParseConnRef("garbage")
   142  	c.Assert(err, ErrorMatches, `malformed connection identifier: "garbage"`)
   143  	_, err = interfaces.ParseConnRef("snap:plug:garbage snap:slot")
   144  	c.Assert(err, ErrorMatches, `malformed connection identifier: ".*"`)
   145  	_, err = interfaces.ParseConnRef("snap:plug snap:slot:garbage")
   146  	c.Assert(err, ErrorMatches, `malformed connection identifier: ".*"`)
   147  }
   148  
   149  type simpleIface struct {
   150  	name string
   151  }
   152  
   153  func (si simpleIface) Name() string                                              { return si.name }
   154  func (si simpleIface) AutoConnect(plug *snap.PlugInfo, slot *snap.SlotInfo) bool { return false }
   155  
   156  func (s *CoreSuite) TestByName(c *C) {
   157  	// setup a mock interface using builtin - this will also trigger init() in
   158  	// builtin package which set ByName to a real implementation
   159  	r := builtin.MockInterface(simpleIface{name: "mock-network"})
   160  	defer r()
   161  
   162  	_, err := interfaces.ByName("no-such-interface")
   163  	c.Assert(err, ErrorMatches, "interface \"no-such-interface\" not found")
   164  
   165  	iface, err := interfaces.ByName("mock-network")
   166  	c.Assert(err, IsNil)
   167  	c.Assert(iface.Name(), Equals, "mock-network")
   168  }
   169  
   170  type serviceSnippetIface struct {
   171  	simpleIface
   172  
   173  	sanitizerErr error
   174  
   175  	snips []string
   176  }
   177  
   178  func (ssi serviceSnippetIface) BeforePreparePlug(plug *snap.PlugInfo) error {
   179  	return ssi.sanitizerErr
   180  }
   181  
   182  func (ssi serviceSnippetIface) ServicePermanentPlug(plug *snap.PlugInfo) []string {
   183  	return ssi.snips
   184  }
   185  
   186  func (s *CoreSuite) TestPermanentPlugServiceSnippets(c *C) {
   187  	// setup a mock interface using builtin - this will also trigger init() in
   188  	// builtin package which set ByName to a real implementation
   189  	ssi := serviceSnippetIface{
   190  		simpleIface: simpleIface{name: "mock-service-snippets"},
   191  		snips:       []string{"foo1", "foo2"},
   192  	}
   193  	r := builtin.MockInterface(ssi)
   194  	defer r()
   195  
   196  	iface, err := interfaces.ByName("mock-service-snippets")
   197  	c.Assert(err, IsNil)
   198  	c.Assert(iface.Name(), Equals, "mock-service-snippets")
   199  
   200  	info := snaptest.MockInfo(c, `
   201  name: snap
   202  version: 0
   203  plugs:
   204    plug:
   205      interface: mock-service-snippets
   206  `, nil)
   207  	plug := info.Plugs["plug"]
   208  
   209  	snips, err := interfaces.PermanentPlugServiceSnippets(iface, plug)
   210  	c.Assert(err, IsNil)
   211  	c.Assert(snips, DeepEquals, []string{"foo1", "foo2"})
   212  }
   213  
   214  func (s *CoreSuite) TestPermanentPlugServiceSnippetsSanitizesPlugs(c *C) {
   215  	// setup a mock interface using builtin - this will also trigger init() in
   216  	// builtin package which set ByName to a real implementation
   217  	ssi := serviceSnippetIface{
   218  		simpleIface:  simpleIface{name: "unclean-service-snippets"},
   219  		sanitizerErr: fmt.Errorf("cannot sanitize: foo"),
   220  	}
   221  	r := builtin.MockInterface(ssi)
   222  	defer r()
   223  
   224  	info := snaptest.MockInfo(c, `
   225  name: snap
   226  version: 0
   227  plugs:
   228    plug:
   229      interface: unclean-service-snippets
   230  `, nil)
   231  	plug := info.Plugs["plug"]
   232  
   233  	iface, err := interfaces.ByName("unclean-service-snippets")
   234  	c.Assert(err, IsNil)
   235  	c.Assert(iface.Name(), Equals, "unclean-service-snippets")
   236  
   237  	_, err = interfaces.PermanentPlugServiceSnippets(iface, plug)
   238  	c.Assert(err, ErrorMatches, "cannot sanitize: foo")
   239  }
   240  
   241  func (s *CoreSuite) TestSanitizePlug(c *C) {
   242  	info := snaptest.MockInfo(c, `
   243  name: snap
   244  version: 0
   245  plugs:
   246    plug:
   247      interface: iface
   248  `, nil)
   249  	plug := info.Plugs["plug"]
   250  	c.Assert(interfaces.BeforePreparePlug(&ifacetest.TestInterface{
   251  		InterfaceName: "iface",
   252  	}, plug), IsNil)
   253  	c.Assert(interfaces.BeforePreparePlug(&ifacetest.TestInterface{
   254  		InterfaceName:             "iface",
   255  		BeforePreparePlugCallback: func(plug *snap.PlugInfo) error { return fmt.Errorf("broken") },
   256  	}, plug), ErrorMatches, "broken")
   257  	c.Assert(interfaces.BeforePreparePlug(&ifacetest.TestInterface{
   258  		InterfaceName: "other",
   259  	}, plug), ErrorMatches, `cannot sanitize plug "snap:plug" \(interface "iface"\) using interface "other"`)
   260  }
   261  
   262  func (s *CoreSuite) TestSanitizeSlot(c *C) {
   263  	info := snaptest.MockInfo(c, `
   264  name: snap
   265  version: 0
   266  slots:
   267    slot:
   268      interface: iface
   269  `, nil)
   270  	slot := info.Slots["slot"]
   271  	c.Assert(interfaces.BeforePrepareSlot(&ifacetest.TestInterface{
   272  		InterfaceName: "iface",
   273  	}, slot), IsNil)
   274  	c.Assert(interfaces.BeforePrepareSlot(&ifacetest.TestInterface{
   275  		InterfaceName:             "iface",
   276  		BeforePrepareSlotCallback: func(slot *snap.SlotInfo) error { return fmt.Errorf("broken") },
   277  	}, slot), ErrorMatches, "broken")
   278  	c.Assert(interfaces.BeforePrepareSlot(&ifacetest.TestInterface{
   279  		InterfaceName: "other",
   280  	}, slot), ErrorMatches, `cannot sanitize slot "snap:slot" \(interface "iface"\) using interface "other"`)
   281  }