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  }