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  }