github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/interfaces/builtin/serial_port_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 builtin_test 21 22 import ( 23 "fmt" 24 25 . "gopkg.in/check.v1" 26 27 "github.com/snapcore/snapd/dirs" 28 "github.com/snapcore/snapd/interfaces" 29 "github.com/snapcore/snapd/interfaces/apparmor" 30 "github.com/snapcore/snapd/interfaces/builtin" 31 "github.com/snapcore/snapd/interfaces/hotplug" 32 "github.com/snapcore/snapd/interfaces/udev" 33 "github.com/snapcore/snapd/snap" 34 "github.com/snapcore/snapd/snap/snaptest" 35 "github.com/snapcore/snapd/testutil" 36 ) 37 38 type SerialPortInterfaceSuite struct { 39 testutil.BaseTest 40 iface interfaces.Interface 41 42 // OS Snap 43 testSlot1 *interfaces.ConnectedSlot 44 testSlot1Info *snap.SlotInfo 45 testSlot2 *interfaces.ConnectedSlot 46 testSlot2Info *snap.SlotInfo 47 testSlot3 *interfaces.ConnectedSlot 48 testSlot3Info *snap.SlotInfo 49 testSlot4 *interfaces.ConnectedSlot 50 testSlot4Info *snap.SlotInfo 51 testSlot5 *interfaces.ConnectedSlot 52 testSlot5Info *snap.SlotInfo 53 testSlot6 *interfaces.ConnectedSlot 54 testSlot6Info *snap.SlotInfo 55 testSlot7 *interfaces.ConnectedSlot 56 testSlot7Info *snap.SlotInfo 57 testSlot8 *interfaces.ConnectedSlot 58 testSlot8Info *snap.SlotInfo 59 testSlot9 *interfaces.ConnectedSlot 60 testSlot9Info *snap.SlotInfo 61 testSlot10 *interfaces.ConnectedSlot 62 testSlot10Info *snap.SlotInfo 63 testSlot11 *interfaces.ConnectedSlot 64 testSlot11Info *snap.SlotInfo 65 testSlotCleaned *interfaces.ConnectedSlot 66 testSlotCleanedInfo *snap.SlotInfo 67 missingPathSlot *interfaces.ConnectedSlot 68 missingPathSlotInfo *snap.SlotInfo 69 badPathSlot1 *interfaces.ConnectedSlot 70 badPathSlot1Info *snap.SlotInfo 71 badPathSlot2 *interfaces.ConnectedSlot 72 badPathSlot2Info *snap.SlotInfo 73 badPathSlot3 *interfaces.ConnectedSlot 74 badPathSlot3Info *snap.SlotInfo 75 badPathSlot4 *interfaces.ConnectedSlot 76 badPathSlot4Info *snap.SlotInfo 77 badPathSlot5 *interfaces.ConnectedSlot 78 badPathSlot5Info *snap.SlotInfo 79 badPathSlot6 *interfaces.ConnectedSlot 80 badPathSlot6Info *snap.SlotInfo 81 badPathSlot7 *interfaces.ConnectedSlot 82 badPathSlot7Info *snap.SlotInfo 83 badPathSlot8 *interfaces.ConnectedSlot 84 badPathSlot8Info *snap.SlotInfo 85 badPathSlot9 *interfaces.ConnectedSlot 86 badPathSlot9Info *snap.SlotInfo 87 badPathSlot10 *interfaces.ConnectedSlot 88 badPathSlot10Info *snap.SlotInfo 89 badPathSlot11 *interfaces.ConnectedSlot 90 badPathSlot11Info *snap.SlotInfo 91 badPathSlot12 *interfaces.ConnectedSlot 92 badPathSlot12Info *snap.SlotInfo 93 badPathSlot13 *interfaces.ConnectedSlot 94 badPathSlot13Info *snap.SlotInfo 95 badInterfaceSlot *interfaces.ConnectedSlot 96 badInterfaceSlotInfo *snap.SlotInfo 97 98 // Gadget Snap 99 testUDev1 *interfaces.ConnectedSlot 100 testUDev1Info *snap.SlotInfo 101 testUDev2 *interfaces.ConnectedSlot 102 testUDev2Info *snap.SlotInfo 103 testUDev3 *interfaces.ConnectedSlot 104 testUDev3Info *snap.SlotInfo 105 testUDevBadValue1 *interfaces.ConnectedSlot 106 testUDevBadValue1Info *snap.SlotInfo 107 testUDevBadValue2Info *snap.SlotInfo 108 testUDevBadValue3 *interfaces.ConnectedSlot 109 testUDevBadValue3Info *snap.SlotInfo 110 testUDevBadValue4 *interfaces.ConnectedSlot 111 testUDevBadValue4Info *snap.SlotInfo 112 testUDevBadValue5 *interfaces.ConnectedSlot 113 testUDevBadValue5Info *snap.SlotInfo 114 115 // Consuming Snap 116 testPlugPort1 *interfaces.ConnectedPlug 117 testPlugPort1Info *snap.PlugInfo 118 testPlugPort2 *interfaces.ConnectedPlug 119 testPlugPort2Info *snap.PlugInfo 120 testPlugPort3 *interfaces.ConnectedPlug 121 testPlugPort3Info *snap.PlugInfo 122 } 123 124 var _ = Suite(&SerialPortInterfaceSuite{ 125 iface: builtin.MustInterface("serial-port"), 126 }) 127 128 func (s *SerialPortInterfaceSuite) SetUpTest(c *C) { 129 osSnapInfo := snaptest.MockInfo(c, ` 130 name: ubuntu-core 131 version: 0 132 type: os 133 slots: 134 test-port-1: 135 interface: serial-port 136 path: /dev/ttyS0 137 test-port-2: 138 interface: serial-port 139 path: /dev/ttyUSB927 140 test-port-3: 141 interface: serial-port 142 path: /dev/ttyS42 143 test-port-4: 144 interface: serial-port 145 path: /dev/ttyO0 146 test-port-5: 147 interface: serial-port 148 path: /dev/ttyACM0 149 test-port-6: 150 interface: serial-port 151 path: /dev/ttyAMA0 152 test-port-7: 153 interface: serial-port 154 path: /dev/ttyXRUSB0 155 test-port-8: 156 interface: serial-port 157 path: /dev/ttymxc2 158 test-port-9: 159 interface: serial-port 160 path: /dev/ttySC0 161 test-port-10: 162 interface: serial-port 163 path: /dev/ttyMSM0 164 test-port-11: 165 interface: serial-port 166 path: /dev/ttyHS0 167 test-port-unclean: 168 interface: serial-port 169 path: /dev/./././ttyS1//// 170 missing-path: serial-port 171 bad-path-1: 172 interface: serial-port 173 path: path 174 bad-path-2: 175 interface: serial-port 176 path: /dev/tty 177 bad-path-3: 178 interface: serial-port 179 path: /dev/tty0 180 bad-path-4: 181 interface: serial-port 182 path: /dev/tty63 183 bad-path-5: 184 interface: serial-port 185 path: /dev/ttyUSB 186 bad-path-6: 187 interface: serial-port 188 path: /dev/usb 189 bad-path-7: 190 interface: serial-port 191 path: /dev/ttyprintk 192 bad-path-8: 193 interface: serial-port 194 path: /dev/ttyO 195 bad-path-9: 196 interface: serial-port 197 path: /dev/ttyS 198 bad-path-10: 199 interface: serial-port 200 path: /dev/ttySC 201 bad-path-11: 202 interface: serial-port 203 path: /dev/ttyMSM 204 bad-path-12: 205 interface: serial-port 206 path: /dev/ttyHS 207 bad-path-13: 208 interface: serial-port 209 path: /dev/ttyillegal0 210 bad-interface: other-interface 211 `, nil) 212 s.testSlot1Info = osSnapInfo.Slots["test-port-1"] 213 s.testSlot1 = interfaces.NewConnectedSlot(s.testSlot1Info, nil, nil) 214 s.testSlot2Info = osSnapInfo.Slots["test-port-2"] 215 s.testSlot2 = interfaces.NewConnectedSlot(s.testSlot2Info, nil, nil) 216 s.testSlot3Info = osSnapInfo.Slots["test-port-3"] 217 s.testSlot3 = interfaces.NewConnectedSlot(s.testSlot3Info, nil, nil) 218 s.testSlot4Info = osSnapInfo.Slots["test-port-4"] 219 s.testSlot4 = interfaces.NewConnectedSlot(s.testSlot4Info, nil, nil) 220 s.testSlot5Info = osSnapInfo.Slots["test-port-5"] 221 s.testSlot5 = interfaces.NewConnectedSlot(s.testSlot5Info, nil, nil) 222 s.testSlot6Info = osSnapInfo.Slots["test-port-6"] 223 s.testSlot6 = interfaces.NewConnectedSlot(s.testSlot6Info, nil, nil) 224 s.testSlot7Info = osSnapInfo.Slots["test-port-7"] 225 s.testSlot7 = interfaces.NewConnectedSlot(s.testSlot7Info, nil, nil) 226 s.testSlot8Info = osSnapInfo.Slots["test-port-8"] 227 s.testSlot8 = interfaces.NewConnectedSlot(s.testSlot8Info, nil, nil) 228 s.testSlot9Info = osSnapInfo.Slots["test-port-9"] 229 s.testSlot9 = interfaces.NewConnectedSlot(s.testSlot9Info, nil, nil) 230 s.testSlot10Info = osSnapInfo.Slots["test-port-10"] 231 s.testSlot10 = interfaces.NewConnectedSlot(s.testSlot10Info, nil, nil) 232 s.testSlot11Info = osSnapInfo.Slots["test-port-11"] 233 s.testSlot11 = interfaces.NewConnectedSlot(s.testSlot11Info, nil, nil) 234 s.testSlotCleanedInfo = osSnapInfo.Slots["test-port-unclean"] 235 s.testSlotCleaned = interfaces.NewConnectedSlot(s.testSlotCleanedInfo, nil, nil) 236 s.missingPathSlotInfo = osSnapInfo.Slots["missing-path"] 237 s.missingPathSlot = interfaces.NewConnectedSlot(s.missingPathSlotInfo, nil, nil) 238 s.badPathSlot1Info = osSnapInfo.Slots["bad-path-1"] 239 s.badPathSlot1 = interfaces.NewConnectedSlot(s.badPathSlot1Info, nil, nil) 240 s.badPathSlot2Info = osSnapInfo.Slots["bad-path-2"] 241 s.badPathSlot2 = interfaces.NewConnectedSlot(s.badPathSlot2Info, nil, nil) 242 s.badPathSlot3Info = osSnapInfo.Slots["bad-path-3"] 243 s.badPathSlot3 = interfaces.NewConnectedSlot(s.badPathSlot3Info, nil, nil) 244 s.badPathSlot4Info = osSnapInfo.Slots["bad-path-4"] 245 s.badPathSlot4 = interfaces.NewConnectedSlot(s.badPathSlot4Info, nil, nil) 246 s.badPathSlot5Info = osSnapInfo.Slots["bad-path-5"] 247 s.badPathSlot5 = interfaces.NewConnectedSlot(s.badPathSlot5Info, nil, nil) 248 s.badPathSlot6Info = osSnapInfo.Slots["bad-path-6"] 249 s.badPathSlot6 = interfaces.NewConnectedSlot(s.badPathSlot6Info, nil, nil) 250 s.badPathSlot7Info = osSnapInfo.Slots["bad-path-7"] 251 s.badPathSlot7 = interfaces.NewConnectedSlot(s.badPathSlot7Info, nil, nil) 252 s.badPathSlot8Info = osSnapInfo.Slots["bad-path-8"] 253 s.badPathSlot8 = interfaces.NewConnectedSlot(s.badPathSlot8Info, nil, nil) 254 s.badPathSlot9Info = osSnapInfo.Slots["bad-path-9"] 255 s.badPathSlot9 = interfaces.NewConnectedSlot(s.badPathSlot9Info, nil, nil) 256 s.badPathSlot10Info = osSnapInfo.Slots["bad-path-10"] 257 s.badPathSlot10 = interfaces.NewConnectedSlot(s.badPathSlot10Info, nil, nil) 258 s.badPathSlot11Info = osSnapInfo.Slots["bad-path-11"] 259 s.badPathSlot11 = interfaces.NewConnectedSlot(s.badPathSlot11Info, nil, nil) 260 s.badPathSlot12Info = osSnapInfo.Slots["bad-path-12"] 261 s.badPathSlot12 = interfaces.NewConnectedSlot(s.badPathSlot12Info, nil, nil) 262 s.badPathSlot13Info = osSnapInfo.Slots["bad-path-13"] 263 s.badPathSlot13 = interfaces.NewConnectedSlot(s.badPathSlot13Info, nil, nil) 264 s.badInterfaceSlotInfo = osSnapInfo.Slots["bad-interface"] 265 s.badInterfaceSlot = interfaces.NewConnectedSlot(s.badInterfaceSlotInfo, nil, nil) 266 267 gadgetSnapInfo := snaptest.MockInfo(c, ` 268 name: some-device 269 version: 0 270 type: gadget 271 slots: 272 test-udev-1: 273 interface: serial-port 274 usb-vendor: 0x0001 275 usb-product: 0x0001 276 path: /dev/serial-port-zigbee 277 test-udev-2: 278 interface: serial-port 279 usb-vendor: 0xffff 280 usb-product: 0xffff 281 path: /dev/serial-port-mydevice 282 test-udev-3: 283 interface: serial-port 284 usb-vendor: 0xabcd 285 usb-product: 0x1234 286 usb-interface-number: 0 287 path: /dev/serial-port-myserial 288 test-udev-bad-value-1: 289 interface: serial-port 290 usb-vendor: -1 291 usb-product: 0xffff 292 path: /dev/serial-port-mydevice 293 test-udev-bad-value-2: 294 interface: serial-port 295 usb-vendor: 0x1234 296 usb-product: 0x10000 297 path: /dev/serial-port-mydevice 298 test-udev-bad-value-3: 299 interface: serial-port 300 usb-vendor: 0x789a 301 usb-product: 0x4321 302 path: /dev/my-device 303 test-udev-bad-value-4: 304 interface: serial-port 305 usb-vendor: 0x1234 306 usb-product: 0x4321 307 usb-interface-number: -1 308 path: /dev/serial-port-mybadinterface 309 test-udev-bad-value-5: 310 interface: serial-port 311 usb-vendor: 0x1234 312 usb-product: 0x4321 313 usb-interface-number: 32 314 path: /dev/serial-port-overinterfacenumber 315 `, nil) 316 s.testUDev1Info = gadgetSnapInfo.Slots["test-udev-1"] 317 s.testUDev1 = interfaces.NewConnectedSlot(s.testUDev1Info, nil, nil) 318 s.testUDev2Info = gadgetSnapInfo.Slots["test-udev-2"] 319 s.testUDev2 = interfaces.NewConnectedSlot(s.testUDev2Info, nil, nil) 320 s.testUDev3Info = gadgetSnapInfo.Slots["test-udev-3"] 321 s.testUDev3 = interfaces.NewConnectedSlot(s.testUDev3Info, nil, nil) 322 s.testUDevBadValue1Info = gadgetSnapInfo.Slots["test-udev-bad-value-1"] 323 s.testUDevBadValue1 = interfaces.NewConnectedSlot(s.testUDevBadValue1Info, nil, nil) 324 s.testUDevBadValue2Info = gadgetSnapInfo.Slots["test-udev-bad-value-2"] 325 s.testUDevBadValue3 = interfaces.NewConnectedSlot(s.testUDevBadValue2Info, nil, nil) 326 s.testUDevBadValue3Info = gadgetSnapInfo.Slots["test-udev-bad-value-3"] 327 s.testUDevBadValue3 = interfaces.NewConnectedSlot(s.testUDevBadValue3Info, nil, nil) 328 s.testUDevBadValue4Info = gadgetSnapInfo.Slots["test-udev-bad-value-4"] 329 s.testUDevBadValue4 = interfaces.NewConnectedSlot(s.testUDevBadValue4Info, nil, nil) 330 s.testUDevBadValue5Info = gadgetSnapInfo.Slots["test-udev-bad-value-5"] 331 s.testUDevBadValue5 = interfaces.NewConnectedSlot(s.testUDevBadValue5Info, nil, nil) 332 333 consumingSnapInfo := snaptest.MockInfo(c, ` 334 name: client-snap 335 version: 0 336 plugs: 337 plug-for-port-1: 338 interface: serial-port 339 plug-for-port-2: 340 interface: serial-port 341 plug-for-port-3: 342 interface: serial-port 343 344 apps: 345 app-accessing-1-port: 346 command: foo 347 plugs: [serial-port] 348 app-accessing-2-ports: 349 command: bar 350 plugs: [plug-for-port-1, plug-for-port-2] 351 app-accessing-3rd-port: 352 command: foo 353 plugs: [plug-for-port-3] 354 `, nil) 355 s.testPlugPort1Info = consumingSnapInfo.Plugs["plug-for-port-1"] 356 s.testPlugPort1 = interfaces.NewConnectedPlug(s.testPlugPort1Info, nil, nil) 357 s.testPlugPort2Info = consumingSnapInfo.Plugs["plug-for-port-2"] 358 s.testPlugPort2 = interfaces.NewConnectedPlug(s.testPlugPort2Info, nil, nil) 359 s.testPlugPort3Info = consumingSnapInfo.Plugs["plug-for-port-3"] 360 s.testPlugPort3 = interfaces.NewConnectedPlug(s.testPlugPort3Info, nil, nil) 361 } 362 363 func (s *SerialPortInterfaceSuite) TestName(c *C) { 364 c.Assert(s.iface.Name(), Equals, "serial-port") 365 } 366 367 func (s *SerialPortInterfaceSuite) TestSanitizeCoreSnapSlots(c *C) { 368 for _, slot := range []*snap.SlotInfo{s.testSlot1Info, s.testSlot2Info, s.testSlot3Info, s.testSlot4Info, s.testSlot5Info, s.testSlot6Info, s.testSlot7Info, s.testSlot8Info, s.testSlot9Info, s.testSlot10Info, s.testSlot11Info} { 369 c.Assert(interfaces.BeforePrepareSlot(s.iface, slot), IsNil) 370 } 371 } 372 373 func (s *SerialPortInterfaceSuite) TestSanitizeBadCoreSnapSlots(c *C) { 374 // Slots without the "path" attribute are rejected. 375 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.missingPathSlotInfo), ErrorMatches, `serial-port slot must have a path attribute`) 376 377 // Slots with incorrect value of the "path" attribute are rejected. 378 for _, slot := range []*snap.SlotInfo{s.badPathSlot1Info, s.badPathSlot2Info, s.badPathSlot3Info, s.badPathSlot4Info, s.badPathSlot5Info, s.badPathSlot6Info, s.badPathSlot7Info, s.badPathSlot8Info, s.badPathSlot9Info, s.badPathSlot10Info, s.badPathSlot11Info, s.badPathSlot12Info, s.badPathSlot13Info} { 379 c.Assert(interfaces.BeforePrepareSlot(s.iface, slot), ErrorMatches, "serial-port path attribute must be a valid device node") 380 } 381 } 382 383 func (s *SerialPortInterfaceSuite) TestSanitizeGadgetSnapSlots(c *C) { 384 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDev1Info), IsNil) 385 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDev2Info), IsNil) 386 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDev3Info), IsNil) 387 } 388 389 func (s *SerialPortInterfaceSuite) TestSanitizeBadGadgetSnapSlots(c *C) { 390 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue1Info), ErrorMatches, "serial-port usb-vendor attribute not valid: -1") 391 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue2Info), ErrorMatches, "serial-port usb-product attribute not valid: 65536") 392 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue3Info), ErrorMatches, "serial-port path attribute specifies invalid symlink location") 393 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue4Info), ErrorMatches, "serial-port usb-interface-number attribute cannot be negative or larger than 31") 394 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue5Info), ErrorMatches, "serial-port usb-interface-number attribute cannot be negative or larger than 31") 395 } 396 397 func (s *SerialPortInterfaceSuite) TestPermanentSlotUDevSnippets(c *C) { 398 spec := &udev.Specification{} 399 for _, slot := range []*snap.SlotInfo{s.testSlot1Info, s.testSlot2Info, s.testSlot3Info, s.testSlot4Info} { 400 err := spec.AddPermanentSlot(s.iface, slot) 401 c.Assert(err, IsNil) 402 c.Assert(spec.Snippets(), HasLen, 0) 403 } 404 405 expectedSnippet1 := `# serial-port 406 IMPORT{builtin}="usb_id" 407 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", SYMLINK+="serial-port-zigbee"` 408 err := spec.AddPermanentSlot(s.iface, s.testUDev1Info) 409 c.Assert(err, IsNil) 410 c.Assert(spec.Snippets(), HasLen, 1) 411 snippet := spec.Snippets()[0] 412 c.Assert(snippet, Equals, expectedSnippet1) 413 414 spec = &udev.Specification{} 415 expectedSnippet2 := `# serial-port 416 IMPORT{builtin}="usb_id" 417 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", SYMLINK+="serial-port-mydevice"` 418 err = spec.AddPermanentSlot(s.iface, s.testUDev2Info) 419 c.Assert(err, IsNil) 420 c.Assert(spec.Snippets(), HasLen, 1) 421 snippet = spec.Snippets()[0] 422 c.Assert(snippet, Equals, expectedSnippet2) 423 424 spec = &udev.Specification{} 425 // The ENV{ID_USB_INTERFACE_NUM} is set to two hex digits 426 // For instance, the expectedSnippet3 is set to 00 427 expectedSnippet3 := `# serial-port 428 IMPORT{builtin}="usb_id" 429 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="abcd", ATTRS{idProduct}=="1234", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="serial-port-myserial"` 430 err = spec.AddPermanentSlot(s.iface, s.testUDev3Info) 431 c.Assert(err, IsNil) 432 c.Assert(spec.Snippets(), HasLen, 1) 433 snippet = spec.Snippets()[0] 434 c.Assert(snippet, Equals, expectedSnippet3) 435 } 436 437 func (s *SerialPortInterfaceSuite) TestConnectedPlugUDevSnippets(c *C) { 438 // add the plug for the slot with just path 439 spec := &udev.Specification{} 440 err := spec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testSlot1) 441 c.Assert(err, IsNil) 442 c.Assert(spec.Snippets(), HasLen, 2) 443 snippet := spec.Snippets()[0] 444 expectedSnippet1 := `# serial-port 445 SUBSYSTEM=="tty", KERNEL=="ttyS0", TAG+="snap_client-snap_app-accessing-2-ports"` 446 c.Assert(snippet, Equals, expectedSnippet1) 447 extraSnippet := spec.Snippets()[1] 448 expectedExtraSnippet1 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-2-ports", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-ports $devpath $major:$minor"`, dirs.DistroLibExecDir) 449 c.Assert(extraSnippet, Equals, expectedExtraSnippet1) 450 451 // add plug for the first slot with product and vendor ids 452 spec = &udev.Specification{} 453 err = spec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testUDev1) 454 c.Assert(err, IsNil) 455 c.Assert(spec.Snippets(), HasLen, 2) 456 snippet = spec.Snippets()[0] 457 expectedSnippet2 := `# serial-port 458 IMPORT{builtin}="usb_id" 459 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", TAG+="snap_client-snap_app-accessing-2-ports"` 460 c.Assert(snippet, Equals, expectedSnippet2) 461 extraSnippet = spec.Snippets()[1] 462 expectedExtraSnippet2 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-2-ports", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-ports $devpath $major:$minor"`, dirs.DistroLibExecDir) 463 c.Assert(extraSnippet, Equals, expectedExtraSnippet2) 464 465 // add plug for the first slot with product and vendor ids 466 spec = &udev.Specification{} 467 err = spec.AddConnectedPlug(s.iface, s.testPlugPort2, s.testUDev2) 468 c.Assert(err, IsNil) 469 c.Assert(spec.Snippets(), HasLen, 2) 470 snippet = spec.Snippets()[0] 471 expectedSnippet3 := `# serial-port 472 IMPORT{builtin}="usb_id" 473 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", TAG+="snap_client-snap_app-accessing-2-ports"` 474 c.Assert(snippet, Equals, expectedSnippet3) 475 extraSnippet = spec.Snippets()[1] 476 expectedExtraSnippet3 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-2-ports", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-ports $devpath $major:$minor"`, dirs.DistroLibExecDir) 477 c.Assert(extraSnippet, Equals, expectedExtraSnippet3) 478 479 // add plug for the first slot with product and vendor ids and usb interface number 480 spec = &udev.Specification{} 481 err = spec.AddConnectedPlug(s.iface, s.testPlugPort2, s.testUDev3) 482 c.Assert(err, IsNil) 483 c.Assert(spec.Snippets(), HasLen, 2) 484 snippet = spec.Snippets()[0] 485 expectedSnippet4 := `# serial-port 486 IMPORT{builtin}="usb_id" 487 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="abcd", ATTRS{idProduct}=="1234", ENV{ID_USB_INTERFACE_NUM}=="00", TAG+="snap_client-snap_app-accessing-2-ports"` 488 c.Assert(snippet, Equals, expectedSnippet4) 489 extraSnippet = spec.Snippets()[1] 490 expectedExtraSnippet4 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-2-ports", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-ports $devpath $major:$minor"`, dirs.DistroLibExecDir) 491 c.Assert(extraSnippet, Equals, expectedExtraSnippet4) 492 } 493 494 func (s *SerialPortInterfaceSuite) TestConnectedPlugAppArmorSnippets(c *C) { 495 checkConnectedPlugSnippet := func(plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot, expectedSnippet string) { 496 apparmorSpec := &apparmor.Specification{} 497 err := apparmorSpec.AddConnectedPlug(s.iface, plug, slot) 498 c.Assert(err, IsNil) 499 500 c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.client-snap.app-accessing-2-ports"}) 501 snippet := apparmorSpec.SnippetForTag("snap.client-snap.app-accessing-2-ports") 502 c.Assert(snippet, DeepEquals, expectedSnippet) 503 } 504 505 expectedSnippet1 := `/dev/ttyS0 rwk,` 506 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot1, expectedSnippet1) 507 expectedSnippet2 := `/dev/ttyUSB927 rwk,` 508 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot2, expectedSnippet2) 509 510 expectedSnippet3 := `/dev/ttyS42 rwk,` 511 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot3, expectedSnippet3) 512 513 expectedSnippet4 := `/dev/ttyO0 rwk,` 514 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot4, expectedSnippet4) 515 516 expectedSnippet5 := `/dev/ttyACM0 rwk,` 517 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot5, expectedSnippet5) 518 519 expectedSnippet6 := `/dev/ttyAMA0 rwk,` 520 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot6, expectedSnippet6) 521 522 expectedSnippet7 := `/dev/ttyXRUSB0 rwk,` 523 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot7, expectedSnippet7) 524 525 expectedSnippet8 := `/dev/ttymxc2 rwk,` 526 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot8, expectedSnippet8) 527 528 expectedSnippet9 := `/dev/ttySC0 rwk,` 529 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot9, expectedSnippet9) 530 531 expectedSnippet10 := `/dev/ttyMSM0 rwk,` 532 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot10, expectedSnippet10) 533 534 expectedSnippet11 := `/dev/ttyHS0 rwk,` 535 checkConnectedPlugSnippet(s.testPlugPort1, s.testSlot11, expectedSnippet11) 536 537 expectedSnippet12 := `/dev/tty[A-Z]*[0-9] rwk,` 538 checkConnectedPlugSnippet(s.testPlugPort1, s.testUDev1, expectedSnippet12) 539 540 expectedSnippet13 := `/dev/tty[A-Z]*[0-9] rwk,` 541 checkConnectedPlugSnippet(s.testPlugPort2, s.testUDev2, expectedSnippet13) 542 543 expectedSnippet14 := `/dev/tty[A-Z]*[0-9] rwk,` 544 checkConnectedPlugSnippet(s.testPlugPort2, s.testUDev3, expectedSnippet14) 545 } 546 547 func (s *SerialPortInterfaceSuite) TestConnectedPlugUDevSnippetsForPath(c *C) { 548 checkConnectedPlugSnippet := func(plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot, expectedSnippet string, expectedExtraSnippet string) { 549 udevSpec := &udev.Specification{} 550 err := udevSpec.AddConnectedPlug(s.iface, plug, slot) 551 c.Assert(err, IsNil) 552 553 c.Assert(udevSpec.Snippets(), HasLen, 2) 554 snippet := udevSpec.Snippets()[0] 555 c.Assert(snippet, Equals, expectedSnippet) 556 extraSnippet := udevSpec.Snippets()[1] 557 c.Assert(extraSnippet, Equals, expectedExtraSnippet) 558 } 559 560 // these have only path 561 expectedSnippet1 := `# serial-port 562 SUBSYSTEM=="tty", KERNEL=="ttyS0", TAG+="snap_client-snap_app-accessing-3rd-port"` 563 expectedExtraSnippet1 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 564 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot1, expectedSnippet1, expectedExtraSnippet1) 565 566 expectedSnippet2 := `# serial-port 567 SUBSYSTEM=="tty", KERNEL=="ttyUSB927", TAG+="snap_client-snap_app-accessing-3rd-port"` 568 expectedExtraSnippet2 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 569 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot2, expectedSnippet2, expectedExtraSnippet2) 570 571 expectedSnippet3 := `# serial-port 572 SUBSYSTEM=="tty", KERNEL=="ttyS42", TAG+="snap_client-snap_app-accessing-3rd-port"` 573 expectedExtraSnippet3 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 574 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot3, expectedSnippet3, expectedExtraSnippet3) 575 576 expectedSnippet4 := `# serial-port 577 SUBSYSTEM=="tty", KERNEL=="ttyO0", TAG+="snap_client-snap_app-accessing-3rd-port"` 578 expectedExtraSnippet4 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 579 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot4, expectedSnippet4, expectedExtraSnippet4) 580 581 expectedSnippet5 := `# serial-port 582 SUBSYSTEM=="tty", KERNEL=="ttyACM0", TAG+="snap_client-snap_app-accessing-3rd-port"` 583 expectedExtraSnippet5 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 584 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot5, expectedSnippet5, expectedExtraSnippet5) 585 586 expectedSnippet6 := `# serial-port 587 SUBSYSTEM=="tty", KERNEL=="ttyAMA0", TAG+="snap_client-snap_app-accessing-3rd-port"` 588 expectedExtraSnippet6 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 589 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot6, expectedSnippet6, expectedExtraSnippet6) 590 591 expectedSnippet7 := `# serial-port 592 SUBSYSTEM=="tty", KERNEL=="ttyXRUSB0", TAG+="snap_client-snap_app-accessing-3rd-port"` 593 expectedExtraSnippet7 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 594 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot7, expectedSnippet7, expectedExtraSnippet7) 595 596 expectedSnippet8 := `# serial-port 597 SUBSYSTEM=="tty", KERNEL=="ttymxc2", TAG+="snap_client-snap_app-accessing-3rd-port"` 598 expectedExtraSnippet8 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 599 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot8, expectedSnippet8, expectedExtraSnippet8) 600 601 expectedSnippet9 := `# serial-port 602 SUBSYSTEM=="tty", KERNEL=="ttySC0", TAG+="snap_client-snap_app-accessing-3rd-port"` 603 expectedExtraSnippet9 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 604 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot9, expectedSnippet9, expectedExtraSnippet9) 605 606 expectedSnippet10 := `# serial-port 607 SUBSYSTEM=="tty", KERNEL=="ttyMSM0", TAG+="snap_client-snap_app-accessing-3rd-port"` 608 expectedExtraSnippet10 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 609 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot10, expectedSnippet10, expectedExtraSnippet10) 610 611 expectedSnippet11 := `# serial-port 612 SUBSYSTEM=="tty", KERNEL=="ttyHS0", TAG+="snap_client-snap_app-accessing-3rd-port"` 613 expectedExtraSnippet11 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 614 checkConnectedPlugSnippet(s.testPlugPort3, s.testSlot11, expectedSnippet11, expectedExtraSnippet11) 615 616 // these have product and vendor ids 617 expectedSnippet12 := `# serial-port 618 IMPORT{builtin}="usb_id" 619 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", TAG+="snap_client-snap_app-accessing-3rd-port"` 620 expectedExtraSnippet12 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 621 checkConnectedPlugSnippet(s.testPlugPort3, s.testUDev1, expectedSnippet12, expectedExtraSnippet12) 622 623 expectedSnippet13 := `# serial-port 624 IMPORT{builtin}="usb_id" 625 SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", TAG+="snap_client-snap_app-accessing-3rd-port"` 626 expectedExtraSnippet13 := fmt.Sprintf(`TAG=="snap_client-snap_app-accessing-3rd-port", RUN+="%v/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-3rd-port $devpath $major:$minor"`, dirs.DistroLibExecDir) 627 checkConnectedPlugSnippet(s.testPlugPort3, s.testUDev2, expectedSnippet13, expectedExtraSnippet13) 628 } 629 630 func (s *SerialPortInterfaceSuite) TestHotplugDeviceDetected(c *C) { 631 hotplugIface := s.iface.(hotplug.Definer) 632 di, err := hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/ttyUSB0", "ID_VENDOR_ID": "1234", "ID_MODEL_ID": "5678", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 633 c.Assert(err, IsNil) 634 proposedSlot, err := hotplugIface.HotplugDeviceDetected(di) 635 c.Assert(err, IsNil) 636 c.Assert(proposedSlot, DeepEquals, &hotplug.ProposedSlot{Attrs: map[string]interface{}{"path": "/dev/ttyUSB0", "usb-vendor": "1234", "usb-product": "5678"}}) 637 } 638 639 func (s *SerialPortInterfaceSuite) TestHotplugDeviceDetectedNotSerialPort(c *C) { 640 hotplugIface := s.iface.(hotplug.Definer) 641 di, err := hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/other", "ID_VENDOR_ID": "1234", "ID_MODEL_ID": "5678", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 642 c.Assert(err, IsNil) 643 proposedSlot, err := hotplugIface.HotplugDeviceDetected(di) 644 c.Assert(err, IsNil) 645 c.Assert(proposedSlot, IsNil) 646 } 647 648 func (s *SerialPortInterfaceSuite) TestHotplugHandledByGadget(c *C) { 649 byGadgetPred := s.iface.(hotplug.HandledByGadgetPredicate) 650 di, err := hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/ttyXRUSB0", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 651 c.Assert(err, IsNil) 652 653 c.Assert(byGadgetPred.HandledByGadget(di, s.testSlot5Info), Equals, false) 654 // matching path /dev/ttyXRUSB0 655 c.Assert(byGadgetPred.HandledByGadget(di, s.testSlot7Info), Equals, true) 656 657 // matching on vendor, model, usb interface num 658 di, err = hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/path", "ID_VENDOR_ID": "abcd", "ID_MODEL_ID": "1234", "ID_USB_INTERFACE_NUM": "00", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 659 c.Assert(err, IsNil) 660 c.Assert(byGadgetPred.HandledByGadget(di, s.testUDev3Info), Equals, true) 661 // model doesn't match, everything else matches 662 di, err = hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/path", "ID_VENDOR_ID": "abcd", "ID_MODEL_ID": "ffff", "ID_USB_INTERFACE_NUM": "00", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 663 c.Assert(err, IsNil) 664 c.Assert(byGadgetPred.HandledByGadget(di, s.testUDev3Info), Equals, false) 665 // vendor doesn't match, everything else matches 666 di, err = hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/path", "ID_VENDOR_ID": "eeee", "ID_MODEL_ID": "1234", "ID_USB_INTERFACE_NUM": "00", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 667 c.Assert(err, IsNil) 668 c.Assert(byGadgetPred.HandledByGadget(di, s.testUDev3Info), Equals, false) 669 // usb interface doesn't match, everything else matches 670 di, err = hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/path", "ID_VENDOR_ID": "abcd", "ID_MODEL_ID": "1234", "ID_USB_INTERFACE_NUM": "ff", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 671 c.Assert(err, IsNil) 672 c.Assert(byGadgetPred.HandledByGadget(di, s.testUDev3Info), Equals, false) 673 674 // usb interface num is optional, match on vendor/model 675 di, err = hotplug.NewHotplugDeviceInfo(map[string]string{"DEVPATH": "/sys/foo/bar", "DEVNAME": "/dev/path", "ID_VENDOR_ID": "ffff", "ID_MODEL_ID": "ffff", "ACTION": "add", "SUBSYSTEM": "tty", "ID_BUS": "usb"}) 676 c.Assert(err, IsNil) 677 c.Assert(byGadgetPred.HandledByGadget(di, s.testUDev2Info), Equals, true) 678 } 679 680 func (s *SerialPortInterfaceSuite) TestInterfaces(c *C) { 681 c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface) 682 }