github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/patch/patch4_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 patch_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/overlord/patch" 31 "github.com/snapcore/snapd/overlord/state" 32 ) 33 34 type patch4Suite struct{} 35 36 var _ = Suite(&patch4Suite{}) 37 38 var statePatch4JSON = []byte(` 39 { 40 "last-task-id": 999, 41 "last-change-id": 99, 42 43 "data": { 44 "patch-level": 3, 45 "snaps": { 46 "a": { 47 "sequence": [ 48 {"name": "", "revision": "1"}, 49 {"name": "", "revision": "2"}, 50 {"name": "", "revision": "3"}], 51 "current": "2"}, 52 "b": { 53 "sequence": [ 54 {"name": "", "revision": "1"}, 55 {"name": "", "revision": "2"}], 56 "current": "2"} 57 } 58 }, 59 "changes": { 60 "1": { 61 "id": "1", 62 "kind": "revert-snap", 63 "summary": "revert a snap", 64 "status": 2, 65 "data": {"snap-names": ["a"]}, 66 "task-ids": ["1","2","3","4"] 67 }, 68 "2": { 69 "id": "2", 70 "kind": "refresh-snap", 71 "summary": "refresh b snap", 72 "status": 2, 73 "data": {"snap-names": ["b"]}, 74 "task-ids": ["10","11","12","13","14","15","16"] 75 }, 76 "3": { 77 "id": "3", 78 "kind": "install-snap", 79 "summary": "install c snap", 80 "status": 0, 81 "data": {"snap-names": ["c"]}, 82 "task-ids": ["17", "18"] 83 } 84 }, 85 "tasks": { 86 "1": { 87 "id": "1", 88 "kind": "prepare-snap", 89 "summary": "", 90 "status": 4, 91 "data": { 92 "snap-setup": { 93 "side-info": {"revision": "2", "name": "a"} 94 } 95 }, 96 "halt-tasks": ["2"], 97 "change": "1" 98 }, 99 "2": { 100 "id": "2", 101 "kind": "unlink-current-snap", 102 "summary": "", 103 "status": 4, 104 "data": { 105 "snap-setup-task": "1" 106 }, 107 "wait-tasks": ["1"], 108 "halt-tasks": ["3"], 109 "change": "1" 110 }, 111 "3": { 112 "id": "3", 113 "kind": "setup-profiles", 114 "summary": "", 115 "status": 4, 116 "data": { 117 "snap-setup-task": "1" 118 }, 119 "wait-tasks": ["2"], 120 "halt-tasks": ["4"], 121 "change": "1" 122 }, 123 "4": { 124 "id": "4", 125 "kind": "link-snap", 126 "summary": "make snap avaiblabla", 127 "status": 4, 128 "data": { 129 "had-candidate": true, 130 "snap-setup-task": "1" 131 }, 132 "wait-tasks": ["3"], 133 "change": "1" 134 }, 135 136 "10": { 137 "id": "10", 138 "kind": "download-snap", 139 "summary": "... download ...", 140 "status": 4, 141 "data": {"snap-setup": {"side-info": {"revision": "2", "name": "a"}}}, 142 "halt-tasks": ["11"], 143 "change": "2" 144 }, "11": { 145 "id": "11", 146 "kind": "validate-snap", 147 "summary": "... check asserts...", 148 "status": 4, 149 "data": {"snap-setup-task": "10"}, 150 "wait-tasks": ["10"], 151 "halt-tasks": ["12"], 152 "change": "2" 153 }, "12": { 154 "id": "12", 155 "kind": "mount-snap", 156 "summary": "... mount...", 157 "status": 4, 158 "data": {"snap-setup-task": "10", "snap-type": "app"}, 159 "wait-tasks": ["11"], 160 "halt-tasks": ["13"], 161 "change": "2" 162 }, "13": { 163 "id": "13", 164 "kind": "unlink-current-snap", 165 "summary": "... unlink...", 166 "status": 4, 167 "data": {"snap-setup-task": "10"}, 168 "wait-tasks": ["12"], 169 "halt-tasks": ["14"], 170 "change": "2" 171 }, "14": { 172 "id": "14", 173 "kind": "copy-snap-data", 174 "summary": "... copy...", 175 "status": 0, 176 "data": {"snap-setup-task": "10"}, 177 "wait-tasks": ["13"], 178 "halt-tasks": ["15"], 179 "change": "2" 180 }, "15": { 181 "id": "15", 182 "kind": "setup-profiles", 183 "summary": "... set up profile...", 184 "status": 0, 185 "data": {"snap-setup-task": "10"}, 186 "wait-tasks": ["14"], 187 "halt-tasks": ["16"], 188 "change": "2" 189 }, "16": { 190 "id": "16", 191 "kind": "link-snap", 192 "summary": "... link...", 193 "status": 0, 194 "data": {"snap-setup-task": "10", "had-candidate": false}, 195 "wait-tasks": ["15"], 196 "change": "2" 197 }, 198 199 "17": { 200 "id": "17", 201 "kind": "prepare-snap", 202 "summary": "", 203 "status": 4, 204 "data": { 205 "snap-setup": { 206 "side-info": {"revision": "1", "name": "c"} 207 } 208 }, 209 "halt-tasks": ["18"], 210 "change": "1" 211 }, "18": { 212 "id": "18", 213 "kind": "link-snap", 214 "summary": "make snap avaiblabla", 215 "status": 0, 216 "data": { 217 "snap-setup-task": "17" 218 }, 219 "wait-tasks": ["17"], 220 "change": "3" 221 } 222 } 223 } 224 `) 225 226 func (s *patch4Suite) SetUpTest(c *C) { 227 dirs.SetRootDir(c.MkDir()) 228 229 err := os.MkdirAll(filepath.Dir(dirs.SnapStateFile), 0755) 230 c.Assert(err, IsNil) 231 err = ioutil.WriteFile(dirs.SnapStateFile, statePatch4JSON, 0644) 232 c.Assert(err, IsNil) 233 } 234 235 func (s *patch4Suite) TestPatch4OnReverts(c *C) { 236 restorer := patch.MockLevel(4, 1) 237 defer restorer() 238 239 r, err := os.Open(dirs.SnapStateFile) 240 c.Assert(err, IsNil) 241 defer r.Close() 242 st, err := state.ReadState(nil, r) 243 c.Assert(err, IsNil) 244 245 func() { 246 st.Lock() 247 defer st.Unlock() 248 249 // simulate that the task was running (but the change 250 // is not fully done yet) 251 task := st.Task("4") 252 c.Assert(task, NotNil) 253 task.SetStatus(state.DoneStatus) 254 255 snapsup, err := patch.Patch4TaskSnapSetup(task) 256 c.Assert(err, IsNil) 257 c.Check(snapsup.Flags.Revert(), Equals, false) 258 259 var had bool 260 var idx int 261 c.Check(task.Get("had-candidate", &had), IsNil) 262 c.Check(had, Equals, true) 263 c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) 264 c.Check(len(task.Change().Tasks()), Equals, 4) 265 }() 266 267 // go from patch level 3 -> 4 268 err = patch.Apply(st) 269 c.Assert(err, IsNil) 270 271 st.Lock() 272 defer st.Unlock() 273 274 task := st.Task("4") 275 c.Assert(task, NotNil) 276 277 snapsup, err := patch.Patch4TaskSnapSetup(task) 278 c.Assert(err, IsNil) 279 c.Check(snapsup.Flags.Revert(), Equals, true) 280 281 var had bool 282 var idx int 283 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 284 c.Check(task.Get("old-candidate-index", &idx), IsNil) 285 c.Check(idx, Equals, 1) 286 c.Check(len(task.Change().Tasks()), Equals, 4) 287 } 288 289 func (s *patch4Suite) TestPatch4OnRevertsNoCandidateYet(c *C) { 290 restorer := patch.MockLevel(4, 1) 291 defer restorer() 292 293 r, err := os.Open(dirs.SnapStateFile) 294 c.Assert(err, IsNil) 295 defer r.Close() 296 st, err := state.ReadState(nil, r) 297 c.Assert(err, IsNil) 298 299 func() { 300 st.Lock() 301 defer st.Unlock() 302 303 task := st.Task("4") 304 c.Assert(task, NotNil) 305 // its ready to run but has not run yet 306 task.Clear("had-candidate") 307 task.SetStatus(state.DoStatus) 308 309 snapsup, err := patch.Patch4TaskSnapSetup(task) 310 c.Assert(err, IsNil) 311 c.Check(snapsup.Flags.Revert(), Equals, false) 312 313 var had bool 314 var idx int 315 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 316 c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) 317 c.Check(len(task.Change().Tasks()), Equals, 4) 318 }() 319 320 // go from patch level 3 -> 4 321 err = patch.Apply(st) 322 c.Assert(err, IsNil) 323 324 st.Lock() 325 defer st.Unlock() 326 327 task := st.Task("4") 328 c.Assert(task, NotNil) 329 330 snapsup, err := patch.Patch4TaskSnapSetup(task) 331 c.Assert(err, IsNil) 332 c.Check(snapsup.Flags.Revert(), Equals, true) 333 334 var had bool 335 var idx int 336 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 337 c.Check(task.Get("old-candidate-index", &idx), IsNil) 338 c.Check(idx, Equals, 1) 339 c.Check(len(task.Change().Tasks()), Equals, 4) 340 } 341 342 func (s *patch4Suite) TestPatch4OnRefreshes(c *C) { 343 restorer := patch.MockLevel(4, 1) 344 defer restorer() 345 346 r, err := os.Open(dirs.SnapStateFile) 347 c.Assert(err, IsNil) 348 defer r.Close() 349 st, err := state.ReadState(nil, r) 350 c.Assert(err, IsNil) 351 352 func() { 353 st.Lock() 354 defer st.Unlock() 355 356 task := st.Task("16") 357 c.Assert(task, NotNil) 358 // simulate that the task was running (but the change 359 // is not fully done yet) 360 task.SetStatus(state.DoneStatus) 361 362 snapsup, err := patch.Patch4TaskSnapSetup(task) 363 c.Assert(err, IsNil) 364 c.Check(snapsup.Flags.Revert(), Equals, false) 365 366 var had bool 367 var idx int 368 c.Check(task.Get("had-candidate", &had), IsNil) 369 c.Check(had, Equals, false) 370 c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) 371 c.Check(len(task.Change().Tasks()), Equals, 7) 372 }() 373 374 // go from patch level 3 -> 4 375 err = patch.Apply(st) 376 c.Assert(err, IsNil) 377 378 st.Lock() 379 defer st.Unlock() 380 381 task := st.Task("16") 382 c.Assert(task, NotNil) 383 384 snapsup, err := patch.Patch4TaskSnapSetup(task) 385 c.Assert(err, IsNil) 386 c.Check(snapsup.Flags.Revert(), Equals, false) 387 388 var had bool 389 var idx int 390 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 391 c.Check(task.Get("old-candidate-index", &idx), IsNil) 392 c.Check(idx, Equals, 1) 393 // we added cleanup 394 c.Check(len(task.Change().Tasks()), Equals, 7+1) 395 } 396 397 // This test simulates a link-snap task that is scheduled but has not 398 // run yet. It has no "had-candidate" data set yet. 399 func (s *patch4Suite) TestPatch4OnRefreshesNoHadCandidateYet(c *C) { 400 restorer := patch.MockLevel(4, 1) 401 defer restorer() 402 403 r, err := os.Open(dirs.SnapStateFile) 404 c.Assert(err, IsNil) 405 defer r.Close() 406 st, err := state.ReadState(nil, r) 407 c.Assert(err, IsNil) 408 409 func() { 410 st.Lock() 411 defer st.Unlock() 412 413 task := st.Task("16") 414 c.Assert(task, NotNil) 415 // its ready to run but has not run yet 416 task.Clear("had-candidate") 417 task.SetStatus(state.DoStatus) 418 419 snapsup, err := patch.Patch4TaskSnapSetup(task) 420 c.Assert(err, IsNil) 421 c.Check(snapsup.Flags.Revert(), Equals, false) 422 423 var had bool 424 var idx int 425 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 426 c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) 427 c.Check(len(task.Change().Tasks()), Equals, 7) 428 }() 429 430 // go from patch level 3 -> 4 431 err = patch.Apply(st) 432 c.Assert(err, IsNil) 433 434 st.Lock() 435 defer st.Unlock() 436 437 task := st.Task("16") 438 c.Assert(task, NotNil) 439 440 snapsup, err := patch.Patch4TaskSnapSetup(task) 441 c.Assert(err, IsNil) 442 c.Check(snapsup.Flags.Revert(), Equals, false) 443 444 var had bool 445 var idx int 446 c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) 447 c.Check(task.Get("old-candidate-index", &idx), IsNil) 448 c.Check(idx, Equals, 1) 449 // we added cleanup 450 c.Check(len(task.Change().Tasks()), Equals, 7+1) 451 }