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 }