github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/snapstate/handlers_discard_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 snapstate_test 21 22 import ( 23 . "gopkg.in/check.v1" 24 25 "github.com/snapcore/snapd/interfaces" 26 "github.com/snapcore/snapd/overlord/ifacestate/ifacerepo" 27 "github.com/snapcore/snapd/overlord/servicestate" 28 "github.com/snapcore/snapd/overlord/snapstate" 29 "github.com/snapcore/snapd/overlord/snapstate/snapstatetest" 30 "github.com/snapcore/snapd/overlord/state" 31 "github.com/snapcore/snapd/snap" 32 ) 33 34 type discardSnapSuite struct { 35 baseHandlerSuite 36 } 37 38 var _ = Suite(&discardSnapSuite{}) 39 40 func (s *discardSnapSuite) SetUpTest(c *C) { 41 s.setup(c, nil) 42 43 s.state.Lock() 44 defer s.state.Unlock() 45 repo := interfaces.NewRepository() 46 ifacerepo.Replace(s.state, repo) 47 oldSnapStateEnsureSnapAbsentFromQuotaGroup := snapstate.EnsureSnapAbsentFromQuotaGroup 48 snapstate.EnsureSnapAbsentFromQuotaGroup = servicestate.EnsureSnapAbsentFromQuota 49 s.AddCleanup(func() { 50 snapstate.EnsureSnapAbsentFromQuotaGroup = oldSnapStateEnsureSnapAbsentFromQuotaGroup 51 }) 52 53 s.AddCleanup(snapstatetest.MockDeviceModel(DefaultModel())) 54 } 55 56 func (s *discardSnapSuite) TestDoDiscardSnapSuccess(c *C) { 57 s.state.Lock() 58 snapstate.Set(s.state, "foo", &snapstate.SnapState{ 59 Sequence: []*snap.SideInfo{ 60 {RealName: "foo", Revision: snap.R(3)}, 61 {RealName: "foo", Revision: snap.R(33)}, 62 }, 63 Current: snap.R(33), 64 SnapType: "app", 65 }) 66 t := s.state.NewTask("discard-snap", "test") 67 t.Set("snap-setup", &snapstate.SnapSetup{ 68 SideInfo: &snap.SideInfo{ 69 RealName: "foo", 70 Revision: snap.R(33), 71 }, 72 }) 73 s.state.NewChange("dummy", "...").AddTask(t) 74 75 s.state.Unlock() 76 77 s.se.Ensure() 78 s.se.Wait() 79 80 s.state.Lock() 81 defer s.state.Unlock() 82 var snapst snapstate.SnapState 83 err := snapstate.Get(s.state, "foo", &snapst) 84 c.Assert(err, IsNil) 85 86 c.Check(snapst.Sequence, HasLen, 1) 87 c.Check(snapst.Current, Equals, snap.R(3)) 88 c.Check(t.Status(), Equals, state.DoneStatus) 89 } 90 91 func (s *discardSnapSuite) TestDoDiscardSnapInQuotaGroup(c *C) { 92 s.state.Lock() 93 94 old := snapstate.EnsureSnapAbsentFromQuotaGroup 95 defer func() { 96 snapstate.EnsureSnapAbsentFromQuotaGroup = old 97 }() 98 99 ensureSnapAbsentFromQuotaGroupCalls := 0 100 snapstate.EnsureSnapAbsentFromQuotaGroup = func(st *state.State, snap string) error { 101 ensureSnapAbsentFromQuotaGroupCalls++ 102 c.Assert(snap, Equals, "foo") 103 return nil 104 } 105 defer func() { c.Assert(ensureSnapAbsentFromQuotaGroupCalls, Equals, 1) }() 106 107 snapstate.Set(s.state, "foo", &snapstate.SnapState{ 108 Sequence: []*snap.SideInfo{ 109 {RealName: "foo", Revision: snap.R(3)}, 110 }, 111 Current: snap.R(3), 112 SnapType: "app", 113 }) 114 t := s.state.NewTask("discard-snap", "test") 115 t.Set("snap-setup", &snapstate.SnapSetup{ 116 SideInfo: &snap.SideInfo{ 117 RealName: "foo", 118 Revision: snap.R(33), 119 }, 120 }) 121 s.state.NewChange("dummy", "...").AddTask(t) 122 123 s.state.Unlock() 124 125 s.se.Ensure() 126 s.se.Wait() 127 128 s.state.Lock() 129 defer s.state.Unlock() 130 var snapst snapstate.SnapState 131 err := snapstate.Get(s.state, "foo", &snapst) 132 c.Assert(err, Equals, state.ErrNoState) 133 134 c.Check(t.Status(), Equals, state.DoneStatus) 135 } 136 137 func (s *discardSnapSuite) TestDoDiscardSnapToEmpty(c *C) { 138 s.state.Lock() 139 snapstate.Set(s.state, "foo", &snapstate.SnapState{ 140 Sequence: []*snap.SideInfo{ 141 {RealName: "foo", Revision: snap.R(3)}, 142 }, 143 Current: snap.R(3), 144 SnapType: "app", 145 }) 146 t := s.state.NewTask("discard-snap", "test") 147 t.Set("snap-setup", &snapstate.SnapSetup{ 148 SideInfo: &snap.SideInfo{ 149 RealName: "foo", 150 Revision: snap.R(33), 151 }, 152 }) 153 s.state.NewChange("dummy", "...").AddTask(t) 154 155 s.state.Unlock() 156 157 s.se.Ensure() 158 s.se.Wait() 159 160 s.state.Lock() 161 defer s.state.Unlock() 162 var snapst snapstate.SnapState 163 err := snapstate.Get(s.state, "foo", &snapst) 164 c.Assert(err, Equals, state.ErrNoState) 165 } 166 167 func (s *discardSnapSuite) TestDoDiscardSnapErrorsForActive(c *C) { 168 s.state.Lock() 169 snapstate.Set(s.state, "foo", &snapstate.SnapState{ 170 Sequence: []*snap.SideInfo{ 171 {RealName: "foo", Revision: snap.R(3)}, 172 }, 173 Current: snap.R(3), 174 Active: true, 175 SnapType: "app", 176 }) 177 t := s.state.NewTask("discard-snap", "test") 178 t.Set("snap-setup", &snapstate.SnapSetup{ 179 SideInfo: &snap.SideInfo{ 180 RealName: "foo", 181 Revision: snap.R(3), 182 }, 183 }) 184 chg := s.state.NewChange("dummy", "...") 185 chg.AddTask(t) 186 187 s.state.Unlock() 188 189 s.se.Ensure() 190 s.se.Wait() 191 192 s.state.Lock() 193 defer s.state.Unlock() 194 195 c.Check(chg.Status(), Equals, state.ErrorStatus) 196 c.Check(chg.Err(), ErrorMatches, `(?s).*internal error: cannot discard snap "foo": still active.*`) 197 } 198 199 func (s *discardSnapSuite) TestDoDiscardSnapNoErrorsForActive(c *C) { 200 s.state.Lock() 201 snapstate.Set(s.state, "foo", &snapstate.SnapState{ 202 Sequence: []*snap.SideInfo{ 203 {RealName: "foo", Revision: snap.R(3)}, 204 {RealName: "foo", Revision: snap.R(33)}, 205 }, 206 Current: snap.R(33), 207 Active: true, 208 SnapType: "app", 209 }) 210 t := s.state.NewTask("discard-snap", "test") 211 t.Set("snap-setup", &snapstate.SnapSetup{ 212 SideInfo: &snap.SideInfo{ 213 RealName: "foo", 214 Revision: snap.R(3), 215 }, 216 }) 217 chg := s.state.NewChange("dummy", "...") 218 chg.AddTask(t) 219 220 s.state.Unlock() 221 222 s.se.Ensure() 223 s.se.Wait() 224 225 s.state.Lock() 226 defer s.state.Unlock() 227 228 var snapst snapstate.SnapState 229 err := snapstate.Get(s.state, "foo", &snapst) 230 c.Assert(err, IsNil) 231 232 c.Assert(chg.Err(), IsNil) 233 c.Check(snapst.Sequence, HasLen, 1) 234 c.Check(snapst.Current, Equals, snap.R(33)) 235 c.Check(t.Status(), Equals, state.DoneStatus) 236 } 237 238 func (s *discardSnapSuite) TestDoDiscardSnapdRemovesLate(c *C) { 239 var removeLateCalledFor [][]string 240 restore := snapstate.MockSecurityProfilesDiscardLate(func(snapName string, rev snap.Revision, typ snap.Type) error { 241 removeLateCalledFor = append(removeLateCalledFor, []string{ 242 snapName, rev.String(), string(typ), 243 }) 244 return nil 245 }) 246 defer restore() 247 248 s.state.Lock() 249 250 snapstate.Set(s.state, "snapd", &snapstate.SnapState{ 251 Sequence: []*snap.SideInfo{ 252 {RealName: "snapd", Revision: snap.R(3)}, 253 {RealName: "snapd", Revision: snap.R(33)}, 254 }, 255 Current: snap.R(33), 256 SnapType: "snapd", 257 }) 258 t := s.state.NewTask("discard-snap", "test") 259 t.Set("snap-setup", &snapstate.SnapSetup{ 260 SideInfo: &snap.SideInfo{ 261 RealName: "snapd", 262 Revision: snap.R(33), 263 }, 264 Type: snap.TypeSnapd, 265 }) 266 s.state.NewChange("dummy", "...").AddTask(t) 267 268 s.state.Unlock() 269 270 s.se.Ensure() 271 s.se.Wait() 272 273 s.state.Lock() 274 defer s.state.Unlock() 275 var snapst snapstate.SnapState 276 err := snapstate.Get(s.state, "snapd", &snapst) 277 c.Assert(err, IsNil) 278 279 c.Check(snapst.Sequence, HasLen, 1) 280 c.Check(snapst.Current, Equals, snap.R(3)) 281 c.Check(t.Status(), Equals, state.DoneStatus) 282 c.Check(removeLateCalledFor, DeepEquals, [][]string{ 283 {"snapd", "33", "snapd"}, 284 }) 285 }