github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/snapstate/dbus_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 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 snapstate_test 21 22 import ( 23 "context" 24 "fmt" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/overlord/configstate/config" 29 "github.com/snapcore/snapd/overlord/snapstate" 30 "github.com/snapcore/snapd/snap" 31 ) 32 33 const ( 34 dbusSessionYamlTemplate = `name: %s 35 slots: 36 dbus-slot: 37 interface: dbus 38 bus: session 39 name: org.example.Foo 40 apps: 41 daemon: 42 daemon: simple 43 daemon-scope: user 44 activates-on: [dbus-slot] 45 ` 46 dbusSystemYamlTemplate = `name: %s 47 slots: 48 dbus-slot: 49 interface: dbus 50 bus: system 51 name: org.example.Foo 52 apps: 53 daemon: 54 daemon: simple 55 activates-on: [dbus-slot] 56 ` 57 ) 58 59 func (s *snapmgrTestSuite) TestCheckDBusServiceConflictsSystem(c *C) { 60 someSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "some-snap"))) 61 c.Assert(err, IsNil) 62 otherSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "other-snap"))) 63 c.Assert(err, IsNil) 64 65 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 66 switch name { 67 case "some-snap": 68 return someSnap, nil 69 case "other-snap": 70 return otherSnap, nil 71 default: 72 return s.fakeBackend.ReadInfo(name, si) 73 } 74 }) 75 defer restore() 76 77 s.state.Lock() 78 defer s.state.Unlock() 79 si := &snap.SideInfo{ 80 RealName: "other-snap", 81 Revision: snap.R(-42), 82 } 83 snapstate.Set(s.state, "other-snap", &snapstate.SnapState{ 84 Active: true, 85 Sequence: []*snap.SideInfo{si}, 86 Current: si.Revision, 87 SnapType: "app", 88 }) 89 90 err = snapstate.CheckDBusServiceConflicts(s.state, someSnap) 91 c.Assert(err, ErrorMatches, `snap "some-snap" requesting to activate on system bus name "org.example.Foo" conflicts with snap "other-snap" use`) 92 } 93 94 func (s *snapmgrTestSuite) TestCheckDBusServiceConflictsSession(c *C) { 95 someSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSessionYamlTemplate, "some-snap"))) 96 c.Assert(err, IsNil) 97 otherSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSessionYamlTemplate, "other-snap"))) 98 c.Assert(err, IsNil) 99 100 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 101 switch name { 102 case "some-snap": 103 return someSnap, nil 104 case "other-snap": 105 return otherSnap, nil 106 default: 107 return s.fakeBackend.ReadInfo(name, si) 108 } 109 }) 110 defer restore() 111 112 s.state.Lock() 113 defer s.state.Unlock() 114 si := &snap.SideInfo{ 115 RealName: "other-snap", 116 Revision: snap.R(-42), 117 } 118 snapstate.Set(s.state, "other-snap", &snapstate.SnapState{ 119 Active: true, 120 Sequence: []*snap.SideInfo{si}, 121 Current: si.Revision, 122 SnapType: "app", 123 }) 124 125 err = snapstate.CheckDBusServiceConflicts(s.state, someSnap) 126 c.Assert(err, ErrorMatches, `snap "some-snap" requesting to activate on session bus name "org.example.Foo" conflicts with snap "other-snap" use`) 127 } 128 129 func (s *snapmgrTestSuite) TestCheckDBusServiceConflictsDifferentBuses(c *C) { 130 sessionSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSessionYamlTemplate, "session-snap"))) 131 c.Assert(err, IsNil) 132 systemSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "system-snap"))) 133 c.Assert(err, IsNil) 134 135 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 136 switch name { 137 case "session-snap": 138 return sessionSnap, nil 139 case "system-snap": 140 return systemSnap, nil 141 default: 142 return s.fakeBackend.ReadInfo(name, si) 143 } 144 }) 145 defer restore() 146 147 s.state.Lock() 148 defer s.state.Unlock() 149 150 // A snap claiming a name on the system bus does not conflict 151 // with a snap providing the same name on the session bus. 152 si := &snap.SideInfo{ 153 RealName: "system-snap", 154 Revision: snap.R(-42), 155 } 156 snapstate.Set(s.state, "system-snap", &snapstate.SnapState{ 157 Active: true, 158 Sequence: []*snap.SideInfo{si}, 159 Current: si.Revision, 160 SnapType: "app", 161 }) 162 err = snapstate.CheckDBusServiceConflicts(s.state, sessionSnap) 163 c.Check(err, IsNil) 164 165 // ... and the reverse 166 snapstate.Set(s.state, "system-snap", nil) 167 si = &snap.SideInfo{ 168 RealName: "session-snap", 169 Revision: snap.R(-42), 170 } 171 snapstate.Set(s.state, "session-snap", &snapstate.SnapState{ 172 Active: true, 173 Sequence: []*snap.SideInfo{si}, 174 Current: si.Revision, 175 SnapType: "app", 176 }) 177 err = snapstate.CheckDBusServiceConflicts(s.state, systemSnap) 178 c.Check(err, IsNil) 179 } 180 181 func (s *snapmgrTestSuite) TestCheckDBusServiceConflictsNoConflictWithSelf(c *C) { 182 info, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSessionYamlTemplate, "some-snap"))) 183 c.Assert(err, IsNil) 184 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 185 switch name { 186 case "some-snap": 187 return info, nil 188 default: 189 return s.fakeBackend.ReadInfo(name, si) 190 } 191 }) 192 defer restore() 193 194 s.state.Lock() 195 defer s.state.Unlock() 196 197 // No conflicts on first installation 198 err = snapstate.CheckDBusServiceConflicts(s.state, info) 199 c.Assert(err, IsNil) 200 201 // Snap does not conflict against itself 202 si := &snap.SideInfo{ 203 RealName: "some-snap", 204 Revision: snap.R(-42), 205 } 206 snapstate.Set(s.state, "some-snap", &snapstate.SnapState{ 207 Active: true, 208 Sequence: []*snap.SideInfo{si}, 209 Current: si.Revision, 210 SnapType: "app", 211 }) 212 err = snapstate.CheckDBusServiceConflicts(s.state, info) 213 c.Assert(err, IsNil) 214 } 215 216 func (s *snapmgrTestSuite) TestInstallDBusActivationConflicts(c *C) { 217 someSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "some-snap"))) 218 c.Assert(err, IsNil) 219 otherSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "other-snap"))) 220 c.Assert(err, IsNil) 221 222 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 223 switch name { 224 case "some-snap": 225 return someSnap, nil 226 case "other-snap": 227 return otherSnap, nil 228 default: 229 return s.fakeBackend.ReadInfo(name, si) 230 } 231 }) 232 defer restore() 233 234 s.state.Lock() 235 defer s.state.Unlock() 236 237 si := &snap.SideInfo{ 238 RealName: "other-snap", 239 Revision: snap.R(-42), 240 } 241 snapstate.Set(s.state, "other-snap", &snapstate.SnapState{ 242 Active: true, 243 Sequence: []*snap.SideInfo{si}, 244 Current: si.Revision, 245 SnapType: "app", 246 }) 247 248 tr := config.NewTransaction(s.state) 249 tr.Set("core", "experimental.dbus-activation", true) 250 tr.Commit() 251 252 opts := &snapstate.RevisionOptions{Channel: "channel-for-dbus-activation"} 253 _, err = snapstate.Install(context.Background(), s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) 254 c.Check(err, ErrorMatches, `snap "some-snap" requesting to activate on system bus name "org.example.Foo" conflicts with snap "other-snap" use`) 255 } 256 257 func (s *snapmgrTestSuite) TestInstallManyDBusActivationConflicts(c *C) { 258 someSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "some-snap"))) 259 c.Assert(err, IsNil) 260 otherSnap, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(dbusSystemYamlTemplate, "other-snap"))) 261 c.Assert(err, IsNil) 262 263 restore := snapstate.MockSnapReadInfo(func(name string, si *snap.SideInfo) (*snap.Info, error) { 264 switch name { 265 case "some-snap": 266 return someSnap, nil 267 case "other-snap": 268 return otherSnap, nil 269 default: 270 return s.fakeBackend.ReadInfo(name, si) 271 } 272 }) 273 defer restore() 274 275 s.state.Lock() 276 defer s.state.Unlock() 277 278 tr := config.NewTransaction(s.state) 279 tr.Set("core", "experimental.dbus-activation", true) 280 tr.Commit() 281 282 snapNames := []string{"some-snap", "other-snap"} 283 _, tss, err := snapstate.InstallMany(s.state, snapNames, s.user.ID) 284 c.Assert(err, IsNil) 285 286 chg := s.state.NewChange("install", "install two snaps") 287 for _, ts := range tss { 288 chg.AddAll(ts) 289 } 290 291 s.state.Unlock() 292 s.settle(c) 293 s.state.Lock() 294 295 // The order of installation is indeterminant, but one will fail 296 c.Check(chg.Err(), ErrorMatches, `cannot perform the following tasks:\n- Make snap "(some|other)-snap" \(11\) available to the system \(snap "(some|other)-snap" requesting to activate on system bus name "org.example.Foo" conflicts with snap "(some|other)-snap" use\)`) 297 }