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 }