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