github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/interfaces/udev/spec_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2017 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package udev_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/ifacetest" 30 "github.com/snapcore/snapd/interfaces/udev" 31 "github.com/snapcore/snapd/release" 32 "github.com/snapcore/snapd/snap" 33 "github.com/snapcore/snapd/snap/snaptest" 34 ) 35 36 type specSuite struct { 37 iface *ifacetest.TestInterface 38 spec *udev.Specification 39 plugInfo *snap.PlugInfo 40 plug *interfaces.ConnectedPlug 41 slotInfo *snap.SlotInfo 42 slot *interfaces.ConnectedSlot 43 } 44 45 var _ = Suite(&specSuite{ 46 iface: &ifacetest.TestInterface{ 47 InterfaceName: "test", 48 UDevConnectedPlugCallback: func(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 49 spec.AddSnippet("connected-plug") 50 return nil 51 }, 52 UDevConnectedSlotCallback: func(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 53 spec.AddSnippet("connected-slot") 54 return nil 55 }, 56 UDevPermanentPlugCallback: func(spec *udev.Specification, plug *snap.PlugInfo) error { 57 spec.AddSnippet("permanent-plug") 58 return nil 59 }, 60 UDevPermanentSlotCallback: func(spec *udev.Specification, slot *snap.SlotInfo) error { 61 spec.AddSnippet("permanent-slot") 62 return nil 63 }, 64 }, 65 }) 66 67 func (s *specSuite) SetUpSuite(c *C) { 68 info1 := snaptest.MockInfo(c, `name: snap1 69 version: 0 70 plugs: 71 name: 72 interface: test 73 apps: 74 foo: 75 command: bin/foo 76 hooks: 77 configure: 78 `, nil) 79 info2 := snaptest.MockInfo(c, `name: snap2 80 version: 0 81 slots: 82 name: 83 interface: test 84 `, nil) 85 s.plugInfo = info1.Plugs["name"] 86 s.plug = interfaces.NewConnectedPlug(s.plugInfo, nil, nil) 87 s.slotInfo = info2.Slots["name"] 88 s.slot = interfaces.NewConnectedSlot(s.slotInfo, nil, nil) 89 } 90 91 func (s *specSuite) SetUpTest(c *C) { 92 s.spec = &udev.Specification{} 93 } 94 95 func (s *specSuite) TestAddSnippte(c *C) { 96 s.spec.AddSnippet("foo") 97 c.Assert(s.spec.Snippets(), DeepEquals, []string{"foo"}) 98 } 99 100 func (s *specSuite) testTagDevice(c *C, helperDir string) { 101 // TagDevice acts in the scope of the plug/slot (as appropriate) and 102 // affects all of the apps and hooks related to the given plug or slot 103 // (with the exception that slots cannot have hooks). 104 iface := &ifacetest.TestInterface{ 105 InterfaceName: "iface-1", 106 UDevConnectedPlugCallback: func(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 107 spec.TagDevice(`kernel="voodoo"`) 108 return nil 109 }, 110 } 111 c.Assert(s.spec.AddConnectedPlug(iface, s.plug, s.slot), IsNil) 112 113 iface = &ifacetest.TestInterface{ 114 InterfaceName: "iface-2", 115 UDevConnectedPlugCallback: func(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 116 spec.TagDevice(`kernel="hoodoo"`) 117 return nil 118 }, 119 } 120 c.Assert(s.spec.AddConnectedPlug(iface, s.plug, s.slot), IsNil) 121 122 c.Assert(s.spec.Snippets(), DeepEquals, []string{ 123 `# iface-1 124 kernel="voodoo", TAG+="snap_snap1_foo"`, 125 `# iface-2 126 kernel="hoodoo", TAG+="snap_snap1_foo"`, 127 fmt.Sprintf(`TAG=="snap_snap1_foo", RUN+="%s/snap-device-helper $env{ACTION} snap_snap1_foo $devpath $major:$minor"`, helperDir), 128 `# iface-1 129 kernel="voodoo", TAG+="snap_snap1_hook_configure"`, 130 `# iface-2 131 kernel="hoodoo", TAG+="snap_snap1_hook_configure"`, 132 fmt.Sprintf(`TAG=="snap_snap1_hook_configure", RUN+="%[1]s/snap-device-helper $env{ACTION} snap_snap1_hook_configure $devpath $major:$minor"`, helperDir), 133 }) 134 } 135 136 func (s *specSuite) TestTagDevice(c *C) { 137 defer func() { dirs.SetRootDir("") }() 138 restore := release.MockReleaseInfo(&release.OS{ID: "ubuntu"}) 139 defer restore() 140 dirs.SetRootDir("") 141 s.testTagDevice(c, "/usr/lib/snapd") 142 } 143 144 func (s *specSuite) TestTagDeviceAltLibexecdir(c *C) { 145 defer func() { dirs.SetRootDir("") }() 146 restore := release.MockReleaseInfo(&release.OS{ID: "fedora"}) 147 defer restore() 148 dirs.SetRootDir("") 149 // sanity 150 c.Check(dirs.DistroLibExecDir, Equals, "/usr/libexec/snapd") 151 s.testTagDevice(c, "/usr/libexec/snapd") 152 } 153 154 // The spec.Specification can be used through the interfaces.Specification interface 155 func (s *specSuite) TestSpecificationIface(c *C) { 156 var r interfaces.Specification = s.spec 157 c.Assert(r.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil) 158 c.Assert(r.AddConnectedSlot(s.iface, s.plug, s.slot), IsNil) 159 c.Assert(r.AddPermanentPlug(s.iface, s.plugInfo), IsNil) 160 c.Assert(r.AddPermanentSlot(s.iface, s.slotInfo), IsNil) 161 c.Assert(s.spec.Snippets(), DeepEquals, []string{"connected-plug", "connected-slot", "permanent-plug", "permanent-slot"}) 162 } 163 164 func (s *specSuite) TestControlsDeviceCgroup(c *C) { 165 c.Assert(s.spec.ControlsDeviceCgroup(), Equals, false) 166 s.spec.SetControlsDeviceCgroup() 167 c.Assert(s.spec.ControlsDeviceCgroup(), Equals, true) 168 }