gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/connection_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 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  	"errors"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"gitee.com/mysnapcore/mysnapd/interfaces"
    28  	"gitee.com/mysnapcore/mysnapd/interfaces/utils"
    29  	"gitee.com/mysnapcore/mysnapd/snap"
    30  	"gitee.com/mysnapcore/mysnapd/snap/snaptest"
    31  	"gitee.com/mysnapcore/mysnapd/testutil"
    32  )
    33  
    34  type connSuite struct {
    35  	testutil.BaseTest
    36  	plug *snap.PlugInfo
    37  	slot *snap.SlotInfo
    38  }
    39  
    40  var _ = Suite(&connSuite{})
    41  
    42  func (s *connSuite) SetUpTest(c *C) {
    43  	s.BaseTest.SetUpTest(c)
    44  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    45  	consumer := snaptest.MockInfo(c, `
    46  name: consumer
    47  version: 0
    48  apps:
    49      app:
    50  plugs:
    51      plug:
    52          interface: interface
    53          attr: value
    54          complex:
    55              c: d
    56  `, nil)
    57  	s.plug = consumer.Plugs["plug"]
    58  	producer := snaptest.MockInfo(c, `
    59  name: producer
    60  version: 0
    61  apps:
    62      app:
    63  slots:
    64      slot:
    65          interface: interface
    66          attr: value
    67          number: 100
    68          complex:
    69              a: b
    70  `, nil)
    71  	s.slot = producer.Slots["slot"]
    72  }
    73  
    74  func (s *connSuite) TearDownTest(c *C) {
    75  	s.BaseTest.TearDownTest(c)
    76  }
    77  
    78  // Make sure ConnectedPlug,ConnectedSlot, PlugInfo, SlotInfo implement Attrer.
    79  var _ interfaces.Attrer = (*interfaces.ConnectedPlug)(nil)
    80  var _ interfaces.Attrer = (*interfaces.ConnectedSlot)(nil)
    81  var _ interfaces.Attrer = (*snap.PlugInfo)(nil)
    82  var _ interfaces.Attrer = (*snap.SlotInfo)(nil)
    83  
    84  func (s *connSuite) TestStaticSlotAttrs(c *C) {
    85  	slot := interfaces.NewConnectedSlot(s.slot, nil, nil)
    86  	c.Assert(slot, NotNil)
    87  
    88  	var val string
    89  	var intVal int
    90  	c.Assert(slot.StaticAttr("unknown", &val), ErrorMatches, `snap "producer" does not have attribute "unknown" for interface "interface"`)
    91  
    92  	attrs := slot.StaticAttrs()
    93  	c.Assert(attrs, DeepEquals, map[string]interface{}{
    94  		"attr":    "value",
    95  		"number":  int64(100),
    96  		"complex": map[string]interface{}{"a": "b"},
    97  	})
    98  	slot.StaticAttr("attr", &val)
    99  	c.Assert(val, Equals, "value")
   100  
   101  	c.Assert(slot.StaticAttr("unknown", &val), ErrorMatches, `snap "producer" does not have attribute "unknown" for interface "interface"`)
   102  	c.Check(slot.StaticAttr("attr", &intVal), ErrorMatches, `snap "producer" has interface "interface" with invalid value type string for "attr" attribute: \*int`)
   103  	c.Check(slot.StaticAttr("attr", val), ErrorMatches, `internal error: cannot get "attr" attribute of interface "interface" with non-pointer value`)
   104  
   105  	// static attributes passed via args take precedence over slot.Attrs
   106  	slot2 := interfaces.NewConnectedSlot(s.slot, map[string]interface{}{"foo": "bar"}, nil)
   107  	slot2.StaticAttr("foo", &val)
   108  	c.Assert(val, Equals, "bar")
   109  }
   110  
   111  func (s *connSuite) TestSlotRef(c *C) {
   112  	slot := interfaces.NewConnectedSlot(s.slot, nil, nil)
   113  	c.Assert(slot, NotNil)
   114  	c.Assert(*slot.Ref(), DeepEquals, interfaces.SlotRef{Snap: "producer", Name: "slot"})
   115  }
   116  
   117  func (s *connSuite) TestPlugRef(c *C) {
   118  	plug := interfaces.NewConnectedPlug(s.plug, nil, nil)
   119  	c.Assert(plug, NotNil)
   120  	c.Assert(*plug.Ref(), DeepEquals, interfaces.PlugRef{Snap: "consumer", Name: "plug"})
   121  }
   122  
   123  func (s *connSuite) TestStaticPlugAttrs(c *C) {
   124  	plug := interfaces.NewConnectedPlug(s.plug, nil, nil)
   125  	c.Assert(plug, NotNil)
   126  
   127  	var val string
   128  	var intVal int
   129  	c.Assert(plug.StaticAttr("unknown", &val), ErrorMatches, `snap "consumer" does not have attribute "unknown" for interface "interface"`)
   130  
   131  	attrs := plug.StaticAttrs()
   132  	c.Assert(attrs, DeepEquals, map[string]interface{}{
   133  		"attr":    "value",
   134  		"complex": map[string]interface{}{"c": "d"},
   135  	})
   136  	plug.StaticAttr("attr", &val)
   137  	c.Assert(val, Equals, "value")
   138  
   139  	c.Assert(plug.StaticAttr("unknown", &val), ErrorMatches, `snap "consumer" does not have attribute "unknown" for interface "interface"`)
   140  	c.Check(plug.StaticAttr("attr", &intVal), ErrorMatches, `snap "consumer" has interface "interface" with invalid value type string for "attr" attribute: \*int`)
   141  	c.Check(plug.StaticAttr("attr", val), ErrorMatches, `internal error: cannot get "attr" attribute of interface "interface" with non-pointer value`)
   142  
   143  	// static attributes passed via args take precedence over plug.Attrs
   144  	plug2 := interfaces.NewConnectedPlug(s.plug, map[string]interface{}{"foo": "bar"}, nil)
   145  	plug2.StaticAttr("foo", &val)
   146  	c.Assert(val, Equals, "bar")
   147  }
   148  
   149  func (s *connSuite) TestDynamicSlotAttrs(c *C) {
   150  	attrs := map[string]interface{}{
   151  		"foo":    "bar",
   152  		"number": int(100),
   153  	}
   154  	slot := interfaces.NewConnectedSlot(s.slot, nil, attrs)
   155  	c.Assert(slot, NotNil)
   156  
   157  	var strVal string
   158  	var intVal int64
   159  	var mapVal map[string]interface{}
   160  
   161  	c.Assert(slot.Attr("foo", &strVal), IsNil)
   162  	c.Assert(strVal, Equals, "bar")
   163  
   164  	c.Assert(slot.Attr("attr", &strVal), IsNil)
   165  	c.Assert(strVal, Equals, "value")
   166  
   167  	c.Assert(slot.Attr("number", &intVal), IsNil)
   168  	c.Assert(intVal, Equals, int64(100))
   169  
   170  	err := slot.SetAttr("other", map[string]interface{}{"number-two": int(222)})
   171  	c.Assert(err, IsNil)
   172  	c.Assert(slot.Attr("other", &mapVal), IsNil)
   173  	num := mapVal["number-two"]
   174  	c.Assert(num, Equals, int64(222))
   175  
   176  	c.Check(slot.Attr("unknown", &strVal), ErrorMatches, `snap "producer" does not have attribute "unknown" for interface "interface"`)
   177  	c.Check(slot.Attr("foo", &intVal), ErrorMatches, `snap "producer" has interface "interface" with invalid value type string for "foo" attribute: \*int64`)
   178  	c.Check(slot.Attr("number", intVal), ErrorMatches, `internal error: cannot get "number" attribute of interface "interface" with non-pointer value`)
   179  }
   180  
   181  func (s *connSuite) TestDottedPathSlot(c *C) {
   182  	attrs := map[string]interface{}{
   183  		"nested": map[string]interface{}{
   184  			"foo": "bar",
   185  		},
   186  	}
   187  	var strVal string
   188  
   189  	slot := interfaces.NewConnectedSlot(s.slot, nil, attrs)
   190  	c.Assert(slot, NotNil)
   191  
   192  	// static attribute complex.a
   193  	c.Assert(slot.Attr("complex.a", &strVal), IsNil)
   194  	c.Assert(strVal, Equals, "b")
   195  
   196  	v, ok := slot.Lookup("complex.a")
   197  	c.Assert(ok, Equals, true)
   198  	c.Assert(v, Equals, "b")
   199  
   200  	// dynamic attribute nested.foo
   201  	c.Assert(slot.Attr("nested.foo", &strVal), IsNil)
   202  	c.Assert(strVal, Equals, "bar")
   203  
   204  	v, ok = slot.Lookup("nested.foo")
   205  	c.Assert(ok, Equals, true)
   206  	c.Assert(v, Equals, "bar")
   207  
   208  	_, ok = slot.Lookup("..")
   209  	c.Assert(ok, Equals, false)
   210  }
   211  
   212  func (s *connSuite) TestDottedPathPlug(c *C) {
   213  	attrs := map[string]interface{}{
   214  		"a": "b",
   215  		"nested": map[string]interface{}{
   216  			"foo": "bar",
   217  		},
   218  	}
   219  	var strVal string
   220  
   221  	plug := interfaces.NewConnectedPlug(s.plug, nil, attrs)
   222  	c.Assert(plug, NotNil)
   223  
   224  	v, ok := plug.Lookup("a")
   225  	c.Assert(ok, Equals, true)
   226  	c.Assert(v, Equals, "b")
   227  
   228  	// static attribute complex.c
   229  	c.Assert(plug.Attr("complex.c", &strVal), IsNil)
   230  	c.Assert(strVal, Equals, "d")
   231  
   232  	v, ok = plug.Lookup("complex.c")
   233  	c.Assert(ok, Equals, true)
   234  	c.Assert(v, Equals, "d")
   235  
   236  	// dynamic attribute nested.foo
   237  	c.Assert(plug.Attr("nested.foo", &strVal), IsNil)
   238  	c.Assert(strVal, Equals, "bar")
   239  
   240  	v, ok = plug.Lookup("nested.foo")
   241  	c.Assert(ok, Equals, true)
   242  	c.Assert(v, Equals, "bar")
   243  
   244  	_, ok = plug.Lookup("nested.x")
   245  	c.Assert(ok, Equals, false)
   246  
   247  	_, ok = plug.Lookup("nested.foo.y")
   248  	c.Assert(ok, Equals, false)
   249  
   250  	_, ok = plug.Lookup("..")
   251  	c.Assert(ok, Equals, false)
   252  }
   253  
   254  func (s *connSuite) TestLookupFailure(c *C) {
   255  	attrs := map[string]interface{}{}
   256  
   257  	slot := interfaces.NewConnectedSlot(s.slot, nil, attrs)
   258  	c.Assert(slot, NotNil)
   259  	plug := interfaces.NewConnectedPlug(s.plug, nil, attrs)
   260  	c.Assert(plug, NotNil)
   261  
   262  	v, ok := slot.Lookup("a")
   263  	c.Assert(ok, Equals, false)
   264  	c.Assert(v, IsNil)
   265  
   266  	v, ok = plug.Lookup("a")
   267  	c.Assert(ok, Equals, false)
   268  	c.Assert(v, IsNil)
   269  }
   270  
   271  func (s *connSuite) TestDynamicPlugAttrs(c *C) {
   272  	attrs := map[string]interface{}{
   273  		"foo":    "bar",
   274  		"number": int(100),
   275  	}
   276  	plug := interfaces.NewConnectedPlug(s.plug, nil, attrs)
   277  	c.Assert(plug, NotNil)
   278  
   279  	var strVal string
   280  	var intVal int64
   281  	var mapVal map[string]interface{}
   282  
   283  	c.Assert(plug.Attr("foo", &strVal), IsNil)
   284  	c.Assert(strVal, Equals, "bar")
   285  
   286  	c.Assert(plug.Attr("attr", &strVal), IsNil)
   287  	c.Assert(strVal, Equals, "value")
   288  
   289  	c.Assert(plug.Attr("number", &intVal), IsNil)
   290  	c.Assert(intVal, Equals, int64(100))
   291  
   292  	err := plug.SetAttr("other", map[string]interface{}{"number-two": int(222)})
   293  	c.Assert(err, IsNil)
   294  	c.Assert(plug.Attr("other", &mapVal), IsNil)
   295  	num := mapVal["number-two"]
   296  	c.Assert(num, Equals, int64(222))
   297  
   298  	c.Check(plug.Attr("unknown", &strVal), ErrorMatches, `snap "consumer" does not have attribute "unknown" for interface "interface"`)
   299  	c.Check(plug.Attr("foo", &intVal), ErrorMatches, `snap "consumer" has interface "interface" with invalid value type string for "foo" attribute: \*int64`)
   300  	c.Check(plug.Attr("number", intVal), ErrorMatches, `internal error: cannot get "number" attribute of interface "interface" with non-pointer value`)
   301  }
   302  
   303  func (s *connSuite) TestOverwriteStaticAttrError(c *C) {
   304  	attrs := map[string]interface{}{}
   305  
   306  	plug := interfaces.NewConnectedPlug(s.plug, nil, attrs)
   307  	c.Assert(plug, NotNil)
   308  	slot := interfaces.NewConnectedSlot(s.slot, nil, attrs)
   309  	c.Assert(slot, NotNil)
   310  
   311  	err := plug.SetAttr("attr", "overwrite")
   312  	c.Assert(err, NotNil)
   313  	c.Assert(err, ErrorMatches, `cannot change attribute "attr" as it was statically specified in the snap details`)
   314  
   315  	err = slot.SetAttr("attr", "overwrite")
   316  	c.Assert(err, NotNil)
   317  	c.Assert(err, ErrorMatches, `cannot change attribute "attr" as it was statically specified in the snap details`)
   318  }
   319  
   320  func (s *connSuite) TestCopyAttributes(c *C) {
   321  	orig := map[string]interface{}{
   322  		"a": "A",
   323  		"b": true,
   324  		"c": int(100),
   325  		"d": []interface{}{"x", "y", true},
   326  		"e": map[string]interface{}{"e1": "E1"},
   327  	}
   328  
   329  	cpy := utils.CopyAttributes(orig)
   330  	c.Check(cpy, DeepEquals, orig)
   331  
   332  	cpy["d"].([]interface{})[0] = 999
   333  	c.Check(orig["d"].([]interface{})[0], Equals, "x")
   334  	cpy["e"].(map[string]interface{})["e1"] = "x"
   335  	c.Check(orig["e"].(map[string]interface{})["e1"], Equals, "E1")
   336  }
   337  
   338  func (s *connSuite) TestNewConnectedPlugExplicitStaticAttrs(c *C) {
   339  	staticAttrs := map[string]interface{}{
   340  		"baz": "boom",
   341  	}
   342  	dynAttrs := map[string]interface{}{
   343  		"foo": "bar",
   344  	}
   345  	plug := interfaces.NewConnectedPlug(s.plug, staticAttrs, dynAttrs)
   346  	c.Assert(plug, NotNil)
   347  	c.Assert(plug.StaticAttrs(), DeepEquals, map[string]interface{}{"baz": "boom"})
   348  	c.Assert(plug.DynamicAttrs(), DeepEquals, map[string]interface{}{"foo": "bar"})
   349  }
   350  
   351  func (s *connSuite) TestNewConnectedSlotExplicitStaticAttrs(c *C) {
   352  	staticAttrs := map[string]interface{}{
   353  		"baz": "boom",
   354  	}
   355  	dynAttrs := map[string]interface{}{
   356  		"foo": "bar",
   357  	}
   358  	slot := interfaces.NewConnectedSlot(s.slot, staticAttrs, dynAttrs)
   359  	c.Assert(slot, NotNil)
   360  	c.Assert(slot.StaticAttrs(), DeepEquals, map[string]interface{}{"baz": "boom"})
   361  	c.Assert(slot.DynamicAttrs(), DeepEquals, map[string]interface{}{"foo": "bar"})
   362  }
   363  
   364  func (s *connSuite) TestGetAttributeUnhappy(c *C) {
   365  	attrs := map[string]interface{}{}
   366  	var stringVal string
   367  	err := interfaces.GetAttribute("snap0", "iface0", attrs, attrs, "non-existent", &stringVal)
   368  	c.Check(stringVal, Equals, "")
   369  	c.Check(err, ErrorMatches, `snap "snap0" does not have attribute "non-existent" for interface "iface0"`)
   370  	c.Check(errors.Is(err, snap.AttributeNotFoundError{}), Equals, true)
   371  }
   372  
   373  func (s *connSuite) TestGetAttributeHappy(c *C) {
   374  	staticAttrs := map[string]interface{}{
   375  		"attr0": "a string",
   376  		"attr1": 12,
   377  	}
   378  	dynamicAttrs := map[string]interface{}{
   379  		"attr0": "second string",
   380  		"attr1": 42,
   381  	}
   382  	var intVal int
   383  	err := interfaces.GetAttribute("snap0", "iface0", staticAttrs, dynamicAttrs, "attr1", &intVal)
   384  	c.Check(err, IsNil)
   385  	c.Check(intVal, Equals, 42)
   386  }