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