gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/overlord/patch/patch6_2_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019 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  	"bytes"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"github.com/snapcore/snapd/dirs"
    28  	"github.com/snapcore/snapd/overlord/patch"
    29  	"github.com/snapcore/snapd/overlord/snapstate"
    30  	"github.com/snapcore/snapd/overlord/state"
    31  	"github.com/snapcore/snapd/snap"
    32  )
    33  
    34  type patch62Suite struct{}
    35  
    36  var _ = Suite(&patch62Suite{})
    37  
    38  // State with snapd snap marked as 'app' (to be converted to 'snapd'
    39  // type) and a regular 'other' snap, plus three tasks - two of them
    40  // need to have their SnapSetup migrated to 'snapd' type.
    41  var statePatch6_2JSON = []byte(`
    42  {
    43  	"data": {
    44  		"patch-level": 6,
    45  		"snaps": {
    46  		  "snapd": {
    47  			"type": "app",
    48  			"sequence": [
    49  			  {
    50  				"name": "snapd",
    51  				"snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
    52  				"revision": "2"
    53  			  }
    54  			],
    55  			"active": true,
    56  			"current": "2",
    57  			"channel": "stable"
    58  		  },
    59  		  "other": {
    60  			"type": "app",
    61  			"sequence": [
    62  			  {
    63  				"name": "snapd",
    64  				"snap-id": "foo",
    65  				"revision": "2"
    66  			  }
    67  			],
    68  			"active": true,
    69  			"current": "2",
    70  			"channel": "stable"
    71  		  }
    72  		}
    73  	  },
    74  	  "changes": {
    75  			"6": {
    76  				"id": "6",
    77  				"kind": "auto-refresh",
    78  				"summary": "...",
    79  				"status": 0,
    80  				"clean": true,
    81  				"data": {
    82  				"api-data": {
    83  					"snap-names": ["snapd"]
    84  				},
    85  				"snap-names": ["snapd"]
    86  				},
    87  				"task-ids": ["1", "8"]
    88  			},
    89  			"9": {
    90  				"id": "9",
    91  				"kind": "auto-refresh",
    92  				"summary": "...",
    93  				"status": 4,
    94  				"clean": true,
    95  				"data": {
    96  				"api-data": {
    97  					"snap-names": ["snapd"]
    98  				},
    99  				"snap-names": ["snapd"]
   100  				},
   101  				"task-ids": ["10"]
   102  			}
   103  	  },
   104  	  "tasks": {
   105  		"1": {
   106  			"id": "1",
   107  			"kind": "download-snap",
   108  			"summary": "...",
   109  			"status": 2,
   110  			"clean": true,
   111  			"data": {
   112  			  "snap-setup": {
   113  				"channel": "stable",
   114  				"type": "app",
   115  				"is-auto-refresh": true,
   116  				"snap-path": "/path",
   117  				"download-info": {
   118  				  "download-url": "foo",
   119  				  "size": 1234,
   120  				  "sha3-384": "123456",
   121  				  "deltas": [
   122  					{
   123  					  "from-revision": 10934,
   124  					  "to-revision": 10972,
   125  					  "format": "xdelta3",
   126  					  "download-url": "foo",
   127  					  "size": 16431136,
   128  					  "sha3-384": "1"
   129  					}
   130  				  ]
   131  				},
   132  				"side-info": {
   133  				  "name": "snapd",
   134  				  "snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   135  				  "revision": "1",
   136  				  "channel": "stable",
   137  				  "title": "snapd"
   138  				},
   139  				"media": [
   140  				  {
   141  					"type": "icon",
   142  					"url": "a"
   143  				  },
   144  				  {
   145  					"type": "screenshot",
   146  					"url": "2"
   147  				  },
   148  				  {
   149  					"type": "screenshot",
   150  					"url": "3"
   151  				  },
   152  				  {
   153  					"type": "screenshot",
   154  					"url": "4"
   155  				  },
   156  				  {
   157  					"type": "video",
   158  					"url": "5"
   159  				  }
   160  				]
   161  			  }
   162  			},
   163  			"change": "6"
   164  		  },
   165  		  "8": {
   166  			"id": "8",
   167  			"kind": "other",
   168  			"summary": "",
   169  			"status": 4,
   170  			"data": {
   171  			  "snap-setup": {
   172  				"channel": "stable",
   173  				"type": "app",
   174  				"snap-path": "/path",
   175  				"side-info": {
   176  				  "name": "snapd",
   177  				  "snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   178  				  "revision": "1",
   179  				  "channel": "stable",
   180  				  "title": "snapd"
   181  				}
   182  			  }
   183  			},
   184  			"change": "6"
   185  		  },
   186  		  "10": {
   187  			"id": "10",
   188  			"kind": "other",
   189  			"summary": "",
   190  			"status": 4,
   191  			"data": {
   192  			  "snap-setup": {
   193  				"channel": "stable",
   194  				"type": "app",
   195  				"snap-path": "/path",
   196  				"side-info": {
   197  				  "name": "snapd",
   198  				  "snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   199  				  "revision": "1",
   200  				  "channel": "stable",
   201  				  "title": "snapd"
   202  				}
   203  			  }
   204  			},
   205  			"change": "9"
   206  		  }
   207  		}
   208  	  }
   209  	}
   210  }`)
   211  
   212  // State with 'snapd' snap with proper snap type, and an extra 'other'
   213  // snap with snapd snap-id (PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4) but
   214  // improper 'app' type.
   215  var statePatch6_2JSONWithSnapd = []byte(`
   216  {
   217  	"data": {
   218  		"patch-level": 6,
   219  		"snaps": {
   220  		  "snapd": {
   221  			"type": "snapd",
   222  			"sequence": [
   223  			  {
   224  				"name": "snapd",
   225  				"snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   226  				"revision": "2"
   227  			  }
   228  			],
   229  			"active": true,
   230  			"current": "2",
   231  			"channel": "stable"
   232  		  },
   233  		  "other": {
   234  			"type": "app",
   235  			"sequence": [
   236  			  {
   237  				"name": "other",
   238  				"snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   239  				"revision": "1"
   240  			  }
   241  			],
   242  			"active": true,
   243  			"current": "1",
   244  			"channel": "stable"
   245  		  }
   246  		}
   247  	  },
   248  	  "changes": {}
   249  	  },
   250  	  "tasks": {}
   251  	}
   252  }`)
   253  
   254  // State with two snaps with snapd snap-id
   255  // (PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4) and improper snap types
   256  var statePatch6_2JSONWithSnapd2 = []byte(`
   257  {
   258  	"data": {
   259  		"patch-level": 6,
   260  		"snaps": {
   261  		  "snapd": {
   262  			"type": "app",
   263  			"sequence": [
   264  			  {
   265  				"name": "snapd",
   266  				"snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   267  				"revision": "2"
   268  			  }
   269  			],
   270  			"active": true,
   271  			"current": "2",
   272  			"channel": "stable"
   273  		  },
   274  		  "other": {
   275  			"type": "app",
   276  			"sequence": [
   277  			  {
   278  				"name": "other",
   279  				"snap-id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4",
   280  				"revision": "1"
   281  			  }
   282  			],
   283  			"active": true,
   284  			"current": "1",
   285  			"channel": "stable"
   286  		  }
   287  		}
   288  	  },
   289  	  "changes": {}
   290  	  },
   291  	  "tasks": {}
   292  	}
   293  }`)
   294  
   295  func (s *patch62Suite) SetUpTest(c *C) {
   296  	dirs.SetRootDir(c.MkDir())
   297  	snap.MockSanitizePlugsSlots(func(*snap.Info) {})
   298  }
   299  
   300  func (s *patch62Suite) TestPatch62(c *C) {
   301  	restore1 := patch.MockLevel(6, 2)
   302  	defer restore1()
   303  
   304  	r := bytes.NewReader(statePatch6_2JSON)
   305  	st, err := state.ReadState(nil, r)
   306  	c.Assert(err, IsNil)
   307  
   308  	c.Assert(patch.Apply(st), IsNil)
   309  	st.Lock()
   310  	defer st.Unlock()
   311  
   312  	// our mocks are correct
   313  	c.Assert(st.Changes(), HasLen, 2)
   314  	c.Assert(st.Tasks(), HasLen, 3)
   315  
   316  	var snapst snapstate.SnapState
   317  	c.Assert(snapstate.Get(st, "snapd", &snapst), IsNil)
   318  	c.Check(snapst.SnapType, Equals, "snapd")
   319  
   320  	// sanity check - "other" is untouched
   321  	c.Assert(snapstate.Get(st, "other", &snapst), IsNil)
   322  	c.Check(snapst.SnapType, Equals, "app")
   323  
   324  	// check tasks
   325  	task := st.Task("1")
   326  	c.Assert(task, NotNil)
   327  
   328  	var snapsup snapstate.SnapSetup
   329  	err = task.Get("snap-setup", &snapsup)
   330  	c.Assert(err, IsNil)
   331  	c.Check(snapsup.Type, Equals, snap.TypeSnapd)
   332  
   333  	// sanity check, structures not defined explicitly via patch62* are preserved
   334  	c.Check(snapsup.Flags.IsAutoRefresh, Equals, true)
   335  	c.Assert(snapsup.Media, HasLen, 5)
   336  	c.Check(snapsup.Media[0].URL, Equals, "a")
   337  	c.Assert(snapsup.DownloadInfo, NotNil)
   338  	c.Check(snapsup.DownloadInfo.DownloadURL, Equals, "foo")
   339  	c.Check(snapsup.DownloadInfo.Deltas, HasLen, 1)
   340  
   341  	task = st.Task("8")
   342  	c.Assert(task, NotNil)
   343  	c.Assert(task.Get("snap-setup", &snapsup), IsNil)
   344  	c.Check(snapsup.Type, Equals, snap.TypeSnapd)
   345  
   346  	// task 10 not updated because the change is ready
   347  	task = st.Task("10")
   348  	c.Assert(task, NotNil)
   349  	c.Assert(task.Get("snap-setup", &snapsup), IsNil)
   350  	c.Check(snapsup.Type, Equals, snap.TypeApp)
   351  }
   352  
   353  func (s *patch62Suite) TestPatch62StopsAfterFirstSnapd(c *C) {
   354  	restore1 := patch.MockLevel(6, 2)
   355  	defer restore1()
   356  
   357  	for i, sj := range [][]byte{statePatch6_2JSONWithSnapd, statePatch6_2JSONWithSnapd2} {
   358  		// sanity check
   359  		c.Assert(patch.Level, Equals, 6)
   360  		c.Assert(patch.Sublevel, Equals, 2)
   361  
   362  		r := bytes.NewReader(sj)
   363  		st, err := state.ReadState(nil, r)
   364  		c.Assert(err, IsNil)
   365  
   366  		c.Assert(patch.Apply(st), IsNil)
   367  		st.Lock()
   368  		defer st.Unlock()
   369  
   370  		var snapdCount int
   371  		for _, name := range []string{"snapd", "other"} {
   372  			var snapst snapstate.SnapState
   373  			c.Assert(snapstate.Get(st, name, &snapst), IsNil)
   374  			if snapst.SnapType == "snapd" {
   375  				snapdCount++
   376  			}
   377  		}
   378  		c.Check(snapdCount, Equals, 1, Commentf("#%d", i))
   379  	}
   380  }