github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/seed/seed20_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019-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 seed_test
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  	"time"
    28  
    29  	. "gopkg.in/check.v1"
    30  
    31  	"github.com/snapcore/snapd/asserts"
    32  	"github.com/snapcore/snapd/asserts/assertstest"
    33  	"github.com/snapcore/snapd/osutil"
    34  	"github.com/snapcore/snapd/seed"
    35  	"github.com/snapcore/snapd/seed/seedtest"
    36  	"github.com/snapcore/snapd/seed/seedwriter"
    37  	"github.com/snapcore/snapd/snap"
    38  	"github.com/snapcore/snapd/snap/snaptest"
    39  	"github.com/snapcore/snapd/testutil"
    40  	"github.com/snapcore/snapd/timings"
    41  )
    42  
    43  type seed20Suite struct {
    44  	testutil.BaseTest
    45  
    46  	*seedtest.TestingSeed20
    47  	devAcct *asserts.Account
    48  
    49  	db *asserts.Database
    50  
    51  	perfTimings timings.Measurer
    52  }
    53  
    54  var _ = Suite(&seed20Suite{})
    55  
    56  func (s *seed20Suite) SetUpTest(c *C) {
    57  	s.BaseTest.SetUpTest(c)
    58  	s.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    59  
    60  	s.TestingSeed20 = &seedtest.TestingSeed20{}
    61  	s.SetupAssertSigning("canonical")
    62  	s.Brands.Register("my-brand", brandPrivKey, map[string]interface{}{
    63  		"verification": "verified",
    64  	})
    65  	// needed by TestingSeed20.MakeSeed (to work with makeSnap)
    66  
    67  	s.devAcct = assertstest.NewAccount(s.StoreSigning, "developer", map[string]interface{}{
    68  		"account-id": "developerid",
    69  	}, "")
    70  	assertstest.AddMany(s.StoreSigning, s.devAcct)
    71  
    72  	s.SeedDir = c.MkDir()
    73  
    74  	db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
    75  		Backstore: asserts.NewMemoryBackstore(),
    76  		Trusted:   s.StoreSigning.Trusted,
    77  	})
    78  	c.Assert(err, IsNil)
    79  	s.db = db
    80  
    81  	s.perfTimings = timings.New(nil)
    82  }
    83  
    84  func (s *seed20Suite) commitTo(b *asserts.Batch) error {
    85  	return b.CommitTo(s.db, nil)
    86  }
    87  
    88  func (s *seed20Suite) makeSnap(c *C, yamlKey, publisher string) {
    89  	if publisher == "" {
    90  		publisher = "canonical"
    91  	}
    92  	s.MakeAssertedSnap(c, snapYaml[yamlKey], nil, snap.R(1), publisher, s.StoreSigning.Database)
    93  }
    94  
    95  func (s *seed20Suite) expectedPath(snapName string) string {
    96  	return filepath.Join(s.SeedDir, "snaps", s.AssertedSnapInfo(snapName).Filename())
    97  }
    98  
    99  func (s *seed20Suite) TestLoadMetaCore20Minimal(c *C) {
   100  	s.makeSnap(c, "snapd", "")
   101  	s.makeSnap(c, "core20", "")
   102  	s.makeSnap(c, "pc-kernel=20", "")
   103  	s.makeSnap(c, "pc=20", "")
   104  
   105  	sysLabel := "20191018"
   106  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   107  		"display-name": "my model",
   108  		"architecture": "amd64",
   109  		"base":         "core20",
   110  		"snaps": []interface{}{
   111  			map[string]interface{}{
   112  				"name":            "pc-kernel",
   113  				"id":              s.AssertedSnapID("pc-kernel"),
   114  				"type":            "kernel",
   115  				"default-channel": "20",
   116  			},
   117  			map[string]interface{}{
   118  				"name":            "pc",
   119  				"id":              s.AssertedSnapID("pc"),
   120  				"type":            "gadget",
   121  				"default-channel": "20",
   122  			}},
   123  	}, nil)
   124  
   125  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   126  	c.Assert(err, IsNil)
   127  
   128  	err = seed20.LoadAssertions(s.db, s.commitTo)
   129  	c.Assert(err, IsNil)
   130  
   131  	err = seed20.LoadMeta(s.perfTimings)
   132  	c.Assert(err, IsNil)
   133  
   134  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
   135  
   136  	essSnaps := seed20.EssentialSnaps()
   137  	c.Check(essSnaps, HasLen, 4)
   138  
   139  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
   140  		{
   141  			Path:          s.expectedPath("snapd"),
   142  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   143  			EssentialType: snap.TypeSnapd,
   144  			Essential:     true,
   145  			Required:      true,
   146  			Channel:       "latest/stable",
   147  		}, {
   148  			Path:          s.expectedPath("pc-kernel"),
   149  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   150  			EssentialType: snap.TypeKernel,
   151  			Essential:     true,
   152  			Required:      true,
   153  			Channel:       "20",
   154  		}, {
   155  			Path:          s.expectedPath("core20"),
   156  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
   157  			EssentialType: snap.TypeBase,
   158  			Essential:     true,
   159  			Required:      true,
   160  			Channel:       "latest/stable",
   161  		}, {
   162  			Path:          s.expectedPath("pc"),
   163  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
   164  			EssentialType: snap.TypeGadget,
   165  			Essential:     true,
   166  			Required:      true,
   167  			Channel:       "20",
   168  		},
   169  	})
   170  
   171  	// check that PlaceInfo method works
   172  	pi := essSnaps[0].PlaceInfo()
   173  	c.Check(pi.Filename(), Equals, "snapd_1.snap")
   174  	pi = essSnaps[1].PlaceInfo()
   175  	c.Check(pi.Filename(), Equals, "pc-kernel_1.snap")
   176  	pi = essSnaps[2].PlaceInfo()
   177  	c.Check(pi.Filename(), Equals, "core20_1.snap")
   178  	pi = essSnaps[3].PlaceInfo()
   179  	c.Check(pi.Filename(), Equals, "pc_1.snap")
   180  
   181  	runSnaps, err := seed20.ModeSnaps("run")
   182  	c.Assert(err, IsNil)
   183  	c.Check(runSnaps, HasLen, 0)
   184  }
   185  
   186  func (s *seed20Suite) makeCore20MinimalSeed(c *C, sysLabel string) string {
   187  	s.makeSnap(c, "snapd", "")
   188  	s.makeSnap(c, "core20", "")
   189  	s.makeSnap(c, "pc-kernel=20", "")
   190  	s.makeSnap(c, "pc=20", "")
   191  
   192  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   193  		"display-name": "my model",
   194  		"architecture": "amd64",
   195  		"base":         "core20",
   196  		"snaps": []interface{}{
   197  			map[string]interface{}{
   198  				"name":            "pc-kernel",
   199  				"id":              s.AssertedSnapID("pc-kernel"),
   200  				"type":            "kernel",
   201  				"default-channel": "20",
   202  			},
   203  			map[string]interface{}{
   204  				"name":            "pc",
   205  				"id":              s.AssertedSnapID("pc"),
   206  				"type":            "gadget",
   207  				"default-channel": "20",
   208  			}},
   209  	}, nil)
   210  
   211  	return filepath.Join(s.SeedDir, "systems", sysLabel)
   212  }
   213  
   214  func (s *seed20Suite) TestLoadAssertionsModelTempDBHappy(c *C) {
   215  	r := seed.MockTrusted(s.StoreSigning.Trusted)
   216  	defer r()
   217  
   218  	sysLabel := "20191031"
   219  	s.makeCore20MinimalSeed(c, sysLabel)
   220  
   221  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   222  	c.Assert(err, IsNil)
   223  
   224  	err = seed20.LoadAssertions(nil, nil)
   225  	c.Assert(err, IsNil)
   226  
   227  	model := seed20.Model()
   228  	c.Check(model.Model(), Equals, "my-model")
   229  	c.Check(model.Base(), Equals, "core20")
   230  
   231  	brand, err := seed20.Brand()
   232  	c.Assert(err, IsNil)
   233  	c.Check(brand.AccountID(), Equals, "my-brand")
   234  	c.Check(brand.DisplayName(), Equals, "My-brand")
   235  }
   236  
   237  func (s *seed20Suite) TestLoadAssertionsMultiModels(c *C) {
   238  	sysLabel := "20191031"
   239  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   240  
   241  	err := osutil.CopyFile(filepath.Join(sysDir, "model"), filepath.Join(sysDir, "assertions", "model2"), 0)
   242  	c.Assert(err, IsNil)
   243  
   244  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   245  	c.Assert(err, IsNil)
   246  
   247  	err = seed20.LoadAssertions(s.db, s.commitTo)
   248  	c.Check(err, ErrorMatches, `system cannot have any model assertion but the one in the system model assertion file`)
   249  }
   250  
   251  func (s *seed20Suite) TestLoadAssertionsInvalidModelAssertFile(c *C) {
   252  	sysLabel := "20191031"
   253  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   254  
   255  	modelAssertFn := filepath.Join(sysDir, "model")
   256  
   257  	// copy over multiple assertions
   258  	err := osutil.CopyFile(filepath.Join(sysDir, "assertions", "model-etc"), modelAssertFn, osutil.CopyFlagOverwrite)
   259  	c.Assert(err, IsNil)
   260  
   261  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   262  	c.Assert(err, IsNil)
   263  	err = seed20.LoadAssertions(s.db, s.commitTo)
   264  	c.Check(err, ErrorMatches, `system model assertion file must contain exactly the model assertion`)
   265  
   266  	// write whatever single non model assertion
   267  	seedtest.WriteAssertions(modelAssertFn, s.AssertedSnapRevision("snapd"))
   268  
   269  	seed20, err = seed.Open(s.SeedDir, sysLabel)
   270  	c.Assert(err, IsNil)
   271  	err = seed20.LoadAssertions(s.db, s.commitTo)
   272  	c.Check(err, ErrorMatches, `system model assertion file must contain exactly the model assertion`)
   273  }
   274  
   275  func (s *seed20Suite) massageAssertions(c *C, fn string, filter func(asserts.Assertion) asserts.Assertion) {
   276  	assertions := seedtest.ReadAssertions(c, fn)
   277  	filtered := make([]asserts.Assertion, 0, len(assertions))
   278  	for _, a := range assertions {
   279  		a1 := filter(a)
   280  		if a1 != nil {
   281  			filtered = append(filtered, a1)
   282  		}
   283  	}
   284  	seedtest.WriteAssertions(fn, filtered...)
   285  }
   286  
   287  func (s *seed20Suite) TestLoadAssertionsUnbalancedDeclsAndRevs(c *C) {
   288  	sysLabel := "20191031"
   289  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   290  
   291  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   292  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("core20") {
   293  			return nil
   294  		}
   295  		return a
   296  	})
   297  
   298  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   299  	c.Assert(err, IsNil)
   300  	err = seed20.LoadAssertions(s.db, s.commitTo)
   301  	c.Check(err, ErrorMatches, `system unexpectedly holds a different number of snap-declaration than snap-revision assertions`)
   302  }
   303  
   304  func (s *seed20Suite) TestLoadAssertionsMultiSnapRev(c *C) {
   305  	sysLabel := "20191031"
   306  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   307  
   308  	spuriousRev, err := s.StoreSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{
   309  		"snap-sha3-384": strings.Repeat("B", 64),
   310  		"snap-size":     "1000",
   311  		"snap-id":       s.AssertedSnapID("core20"),
   312  		"developer-id":  "canonical",
   313  		"snap-revision": "99",
   314  		"timestamp":     time.Now().UTC().Format(time.RFC3339),
   315  	}, nil, "")
   316  	c.Assert(err, IsNil)
   317  
   318  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   319  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("snapd") {
   320  			return spuriousRev
   321  		}
   322  		return a
   323  	})
   324  
   325  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   326  	c.Assert(err, IsNil)
   327  	err = seed20.LoadAssertions(s.db, s.commitTo)
   328  	c.Check(err, ErrorMatches, fmt.Sprintf(`cannot have multiple snap-revisions for the same snap-id: %s`, s.AssertedSnapID("core20")))
   329  }
   330  
   331  func (s *seed20Suite) TestLoadAssertionsMultiSnapDecl(c *C) {
   332  	sysLabel := "20191031"
   333  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   334  
   335  	spuriousDecl, err := s.StoreSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{
   336  		"series":       "16",
   337  		"snap-id":      "idididididididididididididididid",
   338  		"publisher-id": "canonical",
   339  		"snap-name":    "core20",
   340  		"timestamp":    time.Now().UTC().Format(time.RFC3339),
   341  	}, nil, "")
   342  	c.Assert(err, IsNil)
   343  
   344  	spuriousRev, err := s.StoreSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{
   345  		"snap-sha3-384": strings.Repeat("B", 64),
   346  		"snap-size":     "1000",
   347  		"snap-id":       s.AssertedSnapID("core20"),
   348  		"developer-id":  "canonical",
   349  		"snap-revision": "99",
   350  		"timestamp":     time.Now().UTC().Format(time.RFC3339),
   351  	}, nil, "")
   352  	c.Assert(err, IsNil)
   353  
   354  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   355  		if a.Type() == asserts.SnapDeclarationType && a.HeaderString("snap-name") == "snapd" {
   356  			return spuriousDecl
   357  		}
   358  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("snapd") {
   359  			return spuriousRev
   360  		}
   361  		return a
   362  	})
   363  
   364  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   365  	c.Assert(err, IsNil)
   366  	err = seed20.LoadAssertions(s.db, s.commitTo)
   367  	c.Check(err, ErrorMatches, `cannot have multiple snap-declarations for the same snap-name: core20`)
   368  }
   369  
   370  func (s *seed20Suite) TestLoadMetaMissingSnapDeclByName(c *C) {
   371  	sysLabel := "20191031"
   372  
   373  	s.makeSnap(c, "snapd", "")
   374  	s.makeSnap(c, "core20", "")
   375  	s.makeSnap(c, "pc-kernel=20", "")
   376  	s.makeSnap(c, "pc=20", "")
   377  
   378  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   379  		"display-name": "my model",
   380  		"architecture": "amd64",
   381  		"base":         "core20",
   382  		"grade":        "dangerous",
   383  		"snaps": []interface{}{
   384  			map[string]interface{}{
   385  				"name":            "pc-kernel",
   386  				"id":              s.AssertedSnapID("pc-kernel"),
   387  				"type":            "kernel",
   388  				"default-channel": "20",
   389  			},
   390  			map[string]interface{}{
   391  				"name":            "pc",
   392  				"id":              s.AssertedSnapID("pc"),
   393  				"type":            "gadget",
   394  				"default-channel": "20",
   395  			},
   396  			map[string]interface{}{
   397  				"name": "core20",
   398  				// no id
   399  				"type": "base",
   400  			}},
   401  	}, nil)
   402  
   403  	sysDir := filepath.Join(s.SeedDir, "systems", sysLabel)
   404  
   405  	wrongDecl, err := s.StoreSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{
   406  		"series":       "16",
   407  		"snap-id":      "idididididididididididididididid",
   408  		"publisher-id": "canonical",
   409  		"snap-name":    "core20X",
   410  		"timestamp":    time.Now().UTC().Format(time.RFC3339),
   411  	}, nil, "")
   412  	c.Assert(err, IsNil)
   413  
   414  	wrongRev, err := s.StoreSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{
   415  		"snap-sha3-384": strings.Repeat("B", 64),
   416  		"snap-size":     "1000",
   417  		"snap-id":       "idididididididididididididididid",
   418  		"developer-id":  "canonical",
   419  		"snap-revision": "99",
   420  		"timestamp":     time.Now().UTC().Format(time.RFC3339),
   421  	}, nil, "")
   422  	c.Assert(err, IsNil)
   423  
   424  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   425  		if a.Type() == asserts.SnapDeclarationType && a.HeaderString("snap-name") == "core20" {
   426  			return wrongDecl
   427  		}
   428  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("core20") {
   429  			return wrongRev
   430  		}
   431  		return a
   432  	})
   433  
   434  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   435  	c.Assert(err, IsNil)
   436  
   437  	err = seed20.LoadAssertions(s.db, s.commitTo)
   438  	c.Assert(err, IsNil)
   439  
   440  	err = seed20.LoadMeta(s.perfTimings)
   441  	c.Check(err, ErrorMatches, `cannot find snap-declaration for snap name: core20`)
   442  }
   443  
   444  func (s *seed20Suite) TestLoadMetaMissingSnapDeclByID(c *C) {
   445  	sysLabel := "20191031"
   446  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   447  
   448  	wrongDecl, err := s.StoreSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{
   449  		"series":       "16",
   450  		"snap-id":      "idididididididididididididididid",
   451  		"publisher-id": "canonical",
   452  		"snap-name":    "pc",
   453  		"timestamp":    time.Now().UTC().Format(time.RFC3339),
   454  	}, nil, "")
   455  	c.Assert(err, IsNil)
   456  
   457  	wrongRev, err := s.StoreSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{
   458  		"snap-sha3-384": strings.Repeat("B", 64),
   459  		"snap-size":     "1000",
   460  		"snap-id":       "idididididididididididididididid",
   461  		"developer-id":  "canonical",
   462  		"snap-revision": "99",
   463  		"timestamp":     time.Now().UTC().Format(time.RFC3339),
   464  	}, nil, "")
   465  	c.Assert(err, IsNil)
   466  
   467  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   468  		if a.Type() == asserts.SnapDeclarationType && a.HeaderString("snap-name") == "pc" {
   469  			return wrongDecl
   470  		}
   471  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("pc") {
   472  			return wrongRev
   473  		}
   474  		return a
   475  	})
   476  
   477  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   478  	c.Assert(err, IsNil)
   479  
   480  	err = seed20.LoadAssertions(s.db, s.commitTo)
   481  	c.Assert(err, IsNil)
   482  
   483  	err = seed20.LoadMeta(s.perfTimings)
   484  	c.Check(err, ErrorMatches, `cannot find snap-declaration for snap-id: pcididididididididididididididid`)
   485  }
   486  
   487  func (s *seed20Suite) TestLoadMetaMissingSnap(c *C) {
   488  	sysLabel := "20191031"
   489  	s.makeCore20MinimalSeed(c, sysLabel)
   490  
   491  	err := os.Remove(filepath.Join(s.SeedDir, "snaps", "pc_1.snap"))
   492  	c.Assert(err, IsNil)
   493  
   494  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   495  	c.Assert(err, IsNil)
   496  
   497  	err = seed20.LoadAssertions(s.db, s.commitTo)
   498  	c.Assert(err, IsNil)
   499  
   500  	err = seed20.LoadMeta(s.perfTimings)
   501  	c.Check(err, ErrorMatches, `cannot stat snap:.*pc_1\.snap.*`)
   502  }
   503  
   504  func (s *seed20Suite) TestLoadMetaWrongSizeSnap(c *C) {
   505  	sysLabel := "20191031"
   506  	s.makeCore20MinimalSeed(c, sysLabel)
   507  
   508  	err := os.Truncate(filepath.Join(s.SeedDir, "snaps", "pc_1.snap"), 5)
   509  	c.Assert(err, IsNil)
   510  
   511  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   512  	c.Assert(err, IsNil)
   513  
   514  	err = seed20.LoadAssertions(s.db, s.commitTo)
   515  	c.Assert(err, IsNil)
   516  
   517  	err = seed20.LoadMeta(s.perfTimings)
   518  	c.Check(err, ErrorMatches, `cannot validate ".*pc_1\.snap" for snap "pc" \(snap-id "pc.*"\), wrong size`)
   519  }
   520  
   521  func (s *seed20Suite) TestLoadMetaWrongHashSnap(c *C) {
   522  	sysLabel := "20191031"
   523  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   524  
   525  	pcRev := s.AssertedSnapRevision("pc")
   526  	wrongRev, err := s.StoreSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{
   527  		"snap-sha3-384": strings.Repeat("B", 64),
   528  		"snap-size":     pcRev.HeaderString("snap-size"),
   529  		"snap-id":       s.AssertedSnapID("pc"),
   530  		"developer-id":  "canonical",
   531  		"snap-revision": pcRev.HeaderString("snap-revision"),
   532  		"timestamp":     time.Now().UTC().Format(time.RFC3339),
   533  	}, nil, "")
   534  	c.Assert(err, IsNil)
   535  
   536  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   537  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("pc") {
   538  			return wrongRev
   539  		}
   540  		return a
   541  	})
   542  
   543  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   544  	c.Assert(err, IsNil)
   545  
   546  	err = seed20.LoadAssertions(s.db, s.commitTo)
   547  	c.Assert(err, IsNil)
   548  
   549  	err = seed20.LoadMeta(s.perfTimings)
   550  	c.Check(err, ErrorMatches, `cannot validate ".*pc_1\.snap" for snap "pc" \(snap-id "pc.*"\), hash mismatch with snap-revision`)
   551  }
   552  
   553  func (s *seed20Suite) TestLoadMetaWrongGadgetBase(c *C) {
   554  	sysLabel := "20191031"
   555  	sysDir := s.makeCore20MinimalSeed(c, sysLabel)
   556  
   557  	// pc with base: core18
   558  	pc18Decl, pc18Rev := s.MakeAssertedSnap(c, snapYaml["pc=18"], nil, snap.R(2), "canonical")
   559  	err := os.Rename(s.AssertedSnap("pc"), filepath.Join(s.SeedDir, "snaps", "pc_2.snap"))
   560  	c.Assert(err, IsNil)
   561  	s.massageAssertions(c, filepath.Join(sysDir, "assertions", "snaps"), func(a asserts.Assertion) asserts.Assertion {
   562  		if a.Type() == asserts.SnapDeclarationType && a.HeaderString("snap-name") == "pc" {
   563  			return pc18Decl
   564  		}
   565  		if a.Type() == asserts.SnapRevisionType && a.HeaderString("snap-id") == s.AssertedSnapID("pc") {
   566  			return pc18Rev
   567  		}
   568  		return a
   569  	})
   570  
   571  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   572  	c.Assert(err, IsNil)
   573  
   574  	err = seed20.LoadAssertions(s.db, s.commitTo)
   575  	c.Assert(err, IsNil)
   576  
   577  	err = seed20.LoadMeta(s.perfTimings)
   578  	c.Check(err, ErrorMatches, `cannot use gadget snap because its base "core18" is different from model base "core20"`)
   579  }
   580  
   581  func (s *seed20Suite) TestLoadMetaCore20(c *C) {
   582  	s.makeSnap(c, "snapd", "")
   583  	s.makeSnap(c, "core20", "")
   584  	s.makeSnap(c, "pc-kernel=20", "")
   585  	s.makeSnap(c, "pc=20", "")
   586  	s.makeSnap(c, "required20", "developerid")
   587  
   588  	s.AssertedSnapInfo("required20").Contact = "author@example.com"
   589  
   590  	sysLabel := "20191018"
   591  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   592  		"display-name": "my model",
   593  		"architecture": "amd64",
   594  		"base":         "core20",
   595  		"snaps": []interface{}{
   596  			map[string]interface{}{
   597  				"name":            "pc-kernel",
   598  				"id":              s.AssertedSnapID("pc-kernel"),
   599  				"type":            "kernel",
   600  				"default-channel": "20",
   601  			},
   602  			map[string]interface{}{
   603  				"name":            "pc",
   604  				"id":              s.AssertedSnapID("pc"),
   605  				"type":            "gadget",
   606  				"default-channel": "20",
   607  			},
   608  			map[string]interface{}{
   609  				"name": "required20",
   610  				"id":   s.AssertedSnapID("required20"),
   611  			}},
   612  	}, nil)
   613  
   614  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   615  	c.Assert(err, IsNil)
   616  
   617  	err = seed20.LoadAssertions(s.db, s.commitTo)
   618  	c.Assert(err, IsNil)
   619  
   620  	err = seed20.LoadMeta(s.perfTimings)
   621  	c.Assert(err, IsNil)
   622  
   623  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
   624  
   625  	essSnaps := seed20.EssentialSnaps()
   626  	c.Check(essSnaps, HasLen, 4)
   627  
   628  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
   629  		{
   630  			Path:          s.expectedPath("snapd"),
   631  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   632  			EssentialType: snap.TypeSnapd,
   633  			Essential:     true,
   634  			Required:      true,
   635  			Channel:       "latest/stable",
   636  		}, {
   637  			Path:          s.expectedPath("pc-kernel"),
   638  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   639  			EssentialType: snap.TypeKernel,
   640  			Essential:     true,
   641  			Required:      true,
   642  			Channel:       "20",
   643  		}, {
   644  			Path:          s.expectedPath("core20"),
   645  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
   646  			EssentialType: snap.TypeBase,
   647  			Essential:     true,
   648  			Required:      true,
   649  			Channel:       "latest/stable",
   650  		}, {
   651  			Path:          s.expectedPath("pc"),
   652  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
   653  			EssentialType: snap.TypeGadget,
   654  			Essential:     true,
   655  			Required:      true,
   656  			Channel:       "20",
   657  		},
   658  	})
   659  
   660  	runSnaps, err := seed20.ModeSnaps("run")
   661  	c.Assert(err, IsNil)
   662  	c.Check(runSnaps, HasLen, 1)
   663  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
   664  		{
   665  			Path:     s.expectedPath("required20"),
   666  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
   667  			Required: true,
   668  			Channel:  "latest/stable",
   669  		},
   670  	})
   671  
   672  	// required20 has default modes: ["run"]
   673  	installSnaps, err := seed20.ModeSnaps("install")
   674  	c.Assert(err, IsNil)
   675  	c.Check(installSnaps, HasLen, 0)
   676  }
   677  
   678  func hideSnaps(c *C, all []*seed.Snap, keepTypes []snap.Type) (unhide func()) {
   679  	var hidden [][]string
   680  Hiding:
   681  	for _, sn := range all {
   682  		for _, t := range keepTypes {
   683  			if sn.EssentialType == t {
   684  				continue Hiding
   685  			}
   686  		}
   687  		origFn := sn.Path
   688  		hiddenFn := sn.Path + ".hidden"
   689  		err := os.Rename(origFn, hiddenFn)
   690  		c.Assert(err, IsNil)
   691  		hidden = append(hidden, []string{origFn, hiddenFn})
   692  	}
   693  	return func() {
   694  		for _, h := range hidden {
   695  			err := os.Rename(h[1], h[0])
   696  			c.Assert(err, IsNil)
   697  		}
   698  	}
   699  }
   700  
   701  func (s *seed20Suite) TestLoadEssentialMetaCore20(c *C) {
   702  	r := seed.MockTrusted(s.StoreSigning.Trusted)
   703  	defer r()
   704  
   705  	s.makeSnap(c, "snapd", "")
   706  	s.makeSnap(c, "core20", "")
   707  	s.makeSnap(c, "pc-kernel=20", "")
   708  	s.makeSnap(c, "pc=20", "")
   709  	s.makeSnap(c, "core18", "")
   710  	s.makeSnap(c, "required18", "developerid")
   711  
   712  	sysLabel := "20191018"
   713  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   714  		"display-name": "my model",
   715  		"architecture": "amd64",
   716  		"base":         "core20",
   717  		"snaps": []interface{}{
   718  			map[string]interface{}{
   719  				"name":            "pc-kernel",
   720  				"id":              s.AssertedSnapID("pc-kernel"),
   721  				"type":            "kernel",
   722  				"default-channel": "20",
   723  			},
   724  			map[string]interface{}{
   725  				"name":            "pc",
   726  				"id":              s.AssertedSnapID("pc"),
   727  				"type":            "gadget",
   728  				"default-channel": "20",
   729  			},
   730  			map[string]interface{}{
   731  				"name": "core18",
   732  				"id":   s.AssertedSnapID("core18"),
   733  				"type": "base",
   734  			},
   735  			map[string]interface{}{
   736  				"name": "required18",
   737  				"id":   s.AssertedSnapID("required18"),
   738  			}},
   739  	}, nil)
   740  
   741  	snapdSnap := &seed.Snap{
   742  		Path:          s.expectedPath("snapd"),
   743  		SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   744  		EssentialType: snap.TypeSnapd,
   745  		Essential:     true,
   746  		Required:      true,
   747  		Channel:       "latest/stable",
   748  	}
   749  	pcKernelSnap := &seed.Snap{
   750  		Path:          s.expectedPath("pc-kernel"),
   751  		SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   752  		EssentialType: snap.TypeKernel,
   753  		Essential:     true,
   754  		Required:      true,
   755  		Channel:       "20",
   756  	}
   757  	core20Snap := &seed.Snap{Path: s.expectedPath("core20"),
   758  		SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
   759  		EssentialType: snap.TypeBase,
   760  		Essential:     true,
   761  		Required:      true,
   762  		Channel:       "latest/stable",
   763  	}
   764  	pcSnap := &seed.Snap{
   765  		Path:          s.expectedPath("pc"),
   766  		SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
   767  		EssentialType: snap.TypeGadget,
   768  		Essential:     true,
   769  		Required:      true,
   770  		Channel:       "20",
   771  	}
   772  	core18Snap := &seed.Snap{
   773  		// no EssentialType, so it's always hidden, shouldn't matter
   774  		// because we should not look at it
   775  		Path: s.expectedPath("core18"),
   776  	}
   777  	required18Snap := &seed.Snap{
   778  		Path: s.expectedPath("required18"),
   779  	}
   780  
   781  	all := []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap, pcSnap, core18Snap, required18Snap}
   782  
   783  	tests := []struct {
   784  		onlyTypes []snap.Type
   785  		expected  []*seed.Snap
   786  	}{
   787  		{[]snap.Type{snap.TypeSnapd}, []*seed.Snap{snapdSnap}},
   788  		{[]snap.Type{snap.TypeKernel}, []*seed.Snap{pcKernelSnap}},
   789  		{[]snap.Type{snap.TypeBase}, []*seed.Snap{core20Snap}},
   790  		{[]snap.Type{snap.TypeGadget}, []*seed.Snap{pcSnap}},
   791  		{[]snap.Type{snap.TypeSnapd, snap.TypeKernel, snap.TypeBase}, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap}},
   792  		// the order in essentialTypes is not relevant
   793  		{[]snap.Type{snap.TypeGadget, snap.TypeKernel}, []*seed.Snap{pcKernelSnap, pcSnap}},
   794  		// degenerate case
   795  		{[]snap.Type{}, []*seed.Snap(nil)},
   796  	}
   797  
   798  	for _, t := range tests {
   799  		// hide the non-requested snaps to make sure they are not
   800  		// accessed
   801  		unhide := hideSnaps(c, all, t.onlyTypes)
   802  
   803  		seed20, err := seed.Open(s.SeedDir, sysLabel)
   804  		c.Assert(err, IsNil)
   805  
   806  		essSeed20, ok := seed20.(seed.EssentialMetaLoaderSeed)
   807  		c.Assert(ok, Equals, true)
   808  
   809  		err = essSeed20.LoadAssertions(nil, nil)
   810  		c.Assert(err, IsNil)
   811  
   812  		err = essSeed20.LoadEssentialMeta(t.onlyTypes, s.perfTimings)
   813  		c.Assert(err, IsNil)
   814  
   815  		c.Check(essSeed20.UsesSnapdSnap(), Equals, true)
   816  
   817  		essSnaps := essSeed20.EssentialSnaps()
   818  		c.Check(essSnaps, HasLen, len(t.expected))
   819  
   820  		c.Check(essSnaps, DeepEquals, t.expected)
   821  
   822  		runSnaps, err := essSeed20.ModeSnaps("run")
   823  		c.Assert(err, IsNil)
   824  		c.Check(runSnaps, HasLen, 0)
   825  
   826  		unhide()
   827  
   828  		// test short-cut helper as well
   829  		mod, essSnaps, err := seed.ReadSystemEssential(s.SeedDir, sysLabel, t.onlyTypes, s.perfTimings)
   830  		c.Assert(err, IsNil)
   831  		c.Check(mod.BrandID(), Equals, "my-brand")
   832  		c.Check(mod.Model(), Equals, "my-model")
   833  		c.Check(essSnaps, HasLen, len(t.expected))
   834  		c.Check(essSnaps, DeepEquals, t.expected)
   835  	}
   836  }
   837  
   838  func (s *seed20Suite) makeLocalSnap(c *C, yamlKey string) (fname string) {
   839  	return snaptest.MakeTestSnapWithFiles(c, snapYaml[yamlKey], nil)
   840  }
   841  
   842  func (s *seed20Suite) TestLoadMetaCore20LocalSnaps(c *C) {
   843  	s.makeSnap(c, "snapd", "")
   844  	s.makeSnap(c, "core20", "")
   845  	s.makeSnap(c, "pc-kernel=20", "")
   846  	s.makeSnap(c, "pc=20", "")
   847  	requiredFn := s.makeLocalSnap(c, "required20")
   848  
   849  	sysLabel := "20191030"
   850  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   851  		"display-name": "my model",
   852  		"architecture": "amd64",
   853  		"base":         "core20",
   854  		"grade":        "dangerous",
   855  		"snaps": []interface{}{
   856  			map[string]interface{}{
   857  				"name":            "pc-kernel",
   858  				"id":              s.AssertedSnapID("pc-kernel"),
   859  				"type":            "kernel",
   860  				"default-channel": "20",
   861  			},
   862  			map[string]interface{}{
   863  				"name":            "pc",
   864  				"id":              s.AssertedSnapID("pc"),
   865  				"type":            "gadget",
   866  				"default-channel": "20",
   867  			},
   868  			map[string]interface{}{
   869  				"name": "required20",
   870  				"id":   s.AssertedSnapID("required20"),
   871  			}},
   872  	}, []*seedwriter.OptionsSnap{
   873  		{Path: requiredFn},
   874  	})
   875  
   876  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   877  	c.Assert(err, IsNil)
   878  
   879  	err = seed20.LoadAssertions(s.db, s.commitTo)
   880  	c.Assert(err, IsNil)
   881  
   882  	err = seed20.LoadMeta(s.perfTimings)
   883  	c.Assert(err, IsNil)
   884  
   885  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
   886  
   887  	essSnaps := seed20.EssentialSnaps()
   888  	c.Check(essSnaps, HasLen, 4)
   889  
   890  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
   891  		{
   892  			Path:          s.expectedPath("snapd"),
   893  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   894  			EssentialType: snap.TypeSnapd,
   895  			Essential:     true,
   896  			Required:      true,
   897  			Channel:       "latest/stable",
   898  		}, {
   899  			Path:          s.expectedPath("pc-kernel"),
   900  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   901  			EssentialType: snap.TypeKernel,
   902  			Essential:     true,
   903  			Required:      true,
   904  			Channel:       "20",
   905  		}, {
   906  			Path:          s.expectedPath("core20"),
   907  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
   908  			EssentialType: snap.TypeBase,
   909  			Essential:     true,
   910  			Required:      true,
   911  			Channel:       "latest/stable",
   912  		}, {
   913  			Path:          s.expectedPath("pc"),
   914  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
   915  			EssentialType: snap.TypeGadget,
   916  			Essential:     true,
   917  			Required:      true,
   918  			Channel:       "20",
   919  		},
   920  	})
   921  
   922  	runSnaps, err := seed20.ModeSnaps("run")
   923  	c.Assert(err, IsNil)
   924  	c.Check(runSnaps, HasLen, 1)
   925  
   926  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
   927  		{
   928  			Path:     filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "required20_1.0.snap"),
   929  			SideInfo: &snap.SideInfo{RealName: "required20"},
   930  			Required: true,
   931  		},
   932  	})
   933  }
   934  
   935  func (s *seed20Suite) TestLoadMetaCore20ChannelOverride(c *C) {
   936  	s.makeSnap(c, "snapd", "")
   937  	s.makeSnap(c, "core20", "")
   938  	s.makeSnap(c, "pc-kernel=20", "")
   939  	s.makeSnap(c, "pc=20", "")
   940  	s.makeSnap(c, "required20", "developerid")
   941  
   942  	s.AssertedSnapInfo("required20").Contact = "author@example.com"
   943  
   944  	sysLabel := "20191018"
   945  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   946  		"display-name": "my model",
   947  		"architecture": "amd64",
   948  		"base":         "core20",
   949  		"grade":        "dangerous",
   950  		"snaps": []interface{}{
   951  			map[string]interface{}{
   952  				"name":            "pc-kernel",
   953  				"id":              s.AssertedSnapID("pc-kernel"),
   954  				"type":            "kernel",
   955  				"default-channel": "20",
   956  			},
   957  			map[string]interface{}{
   958  				"name":            "pc",
   959  				"id":              s.AssertedSnapID("pc"),
   960  				"type":            "gadget",
   961  				"default-channel": "20",
   962  			},
   963  			map[string]interface{}{
   964  				"name": "required20",
   965  				"id":   s.AssertedSnapID("required20"),
   966  			}},
   967  	}, []*seedwriter.OptionsSnap{
   968  		{Name: "pc", Channel: "20experimental/edge"},
   969  	})
   970  
   971  	seed20, err := seed.Open(s.SeedDir, sysLabel)
   972  	c.Assert(err, IsNil)
   973  
   974  	err = seed20.LoadAssertions(s.db, s.commitTo)
   975  	c.Assert(err, IsNil)
   976  
   977  	err = seed20.LoadMeta(s.perfTimings)
   978  	c.Assert(err, IsNil)
   979  
   980  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
   981  
   982  	essSnaps := seed20.EssentialSnaps()
   983  	c.Check(essSnaps, HasLen, 4)
   984  
   985  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
   986  		{
   987  			Path:          s.expectedPath("snapd"),
   988  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   989  			EssentialType: snap.TypeSnapd,
   990  			Essential:     true,
   991  			Required:      true,
   992  			Channel:       "latest/stable",
   993  		}, {
   994  			Path:          s.expectedPath("pc-kernel"),
   995  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   996  			EssentialType: snap.TypeKernel,
   997  			Essential:     true,
   998  			Required:      true,
   999  			Channel:       "20",
  1000  		}, {
  1001  			Path:          s.expectedPath("core20"),
  1002  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1003  			EssentialType: snap.TypeBase,
  1004  			Essential:     true,
  1005  			Required:      true,
  1006  			Channel:       "latest/stable",
  1007  		}, {
  1008  			Path:          s.expectedPath("pc"),
  1009  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1010  			EssentialType: snap.TypeGadget,
  1011  			Essential:     true,
  1012  			Required:      true,
  1013  			Channel:       "20experimental/edge",
  1014  		},
  1015  	})
  1016  
  1017  	runSnaps, err := seed20.ModeSnaps("run")
  1018  	c.Assert(err, IsNil)
  1019  	c.Check(runSnaps, HasLen, 1)
  1020  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1021  		{
  1022  			Path:     s.expectedPath("required20"),
  1023  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1024  			Required: true,
  1025  			Channel:  "latest/stable",
  1026  		},
  1027  	})
  1028  }
  1029  
  1030  func (s *seed20Suite) TestLoadMetaCore20ChannelOverrideSnapd(c *C) {
  1031  	s.makeSnap(c, "snapd", "")
  1032  	s.makeSnap(c, "core20", "")
  1033  	s.makeSnap(c, "pc-kernel=20", "")
  1034  	s.makeSnap(c, "pc=20", "")
  1035  	s.makeSnap(c, "required20", "developerid")
  1036  
  1037  	s.AssertedSnapInfo("required20").Contact = "author@example.com"
  1038  
  1039  	sysLabel := "20191121"
  1040  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1041  		"display-name": "my model",
  1042  		"architecture": "amd64",
  1043  		"base":         "core20",
  1044  		"grade":        "dangerous",
  1045  		"snaps": []interface{}{
  1046  			map[string]interface{}{
  1047  				"name":            "pc-kernel",
  1048  				"id":              s.AssertedSnapID("pc-kernel"),
  1049  				"type":            "kernel",
  1050  				"default-channel": "20",
  1051  			},
  1052  			map[string]interface{}{
  1053  				"name":            "pc",
  1054  				"id":              s.AssertedSnapID("pc"),
  1055  				"type":            "gadget",
  1056  				"default-channel": "20",
  1057  			},
  1058  			map[string]interface{}{
  1059  				"name": "required20",
  1060  				"id":   s.AssertedSnapID("required20"),
  1061  			}},
  1062  	}, []*seedwriter.OptionsSnap{
  1063  		{Name: "snapd", Channel: "20experimental/edge"},
  1064  	})
  1065  
  1066  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1067  	c.Assert(err, IsNil)
  1068  
  1069  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1070  	c.Assert(err, IsNil)
  1071  
  1072  	err = seed20.LoadMeta(s.perfTimings)
  1073  	c.Assert(err, IsNil)
  1074  
  1075  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1076  
  1077  	essSnaps := seed20.EssentialSnaps()
  1078  	c.Check(essSnaps, HasLen, 4)
  1079  
  1080  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1081  		{
  1082  			Path:          s.expectedPath("snapd"),
  1083  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1084  			EssentialType: snap.TypeSnapd,
  1085  			Essential:     true,
  1086  			Required:      true,
  1087  			Channel:       "20experimental/edge",
  1088  		}, {
  1089  			Path:          s.expectedPath("pc-kernel"),
  1090  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1091  			EssentialType: snap.TypeKernel,
  1092  			Essential:     true,
  1093  			Required:      true,
  1094  			Channel:       "20",
  1095  		}, {
  1096  			Path:          s.expectedPath("core20"),
  1097  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1098  			EssentialType: snap.TypeBase,
  1099  			Essential:     true,
  1100  			Required:      true,
  1101  			Channel:       "latest/stable",
  1102  		}, {
  1103  			Path:          s.expectedPath("pc"),
  1104  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1105  			EssentialType: snap.TypeGadget,
  1106  			Essential:     true,
  1107  			Required:      true,
  1108  			Channel:       "20",
  1109  		},
  1110  	})
  1111  
  1112  	runSnaps, err := seed20.ModeSnaps("run")
  1113  	c.Assert(err, IsNil)
  1114  	c.Check(runSnaps, HasLen, 1)
  1115  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1116  		{
  1117  			Path:     s.expectedPath("required20"),
  1118  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1119  			Required: true,
  1120  			Channel:  "latest/stable",
  1121  		},
  1122  	})
  1123  }
  1124  
  1125  func (s *seed20Suite) TestLoadMetaCore20LocalSnapd(c *C) {
  1126  	snapdFn := s.makeLocalSnap(c, "snapd")
  1127  	s.makeSnap(c, "core20", "")
  1128  	s.makeSnap(c, "pc-kernel=20", "")
  1129  	s.makeSnap(c, "pc=20", "")
  1130  
  1131  	sysLabel := "20191121"
  1132  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1133  		"display-name": "my model",
  1134  		"architecture": "amd64",
  1135  		"base":         "core20",
  1136  		"grade":        "dangerous",
  1137  		"snaps": []interface{}{
  1138  			map[string]interface{}{
  1139  				"name":            "pc-kernel",
  1140  				"id":              s.AssertedSnapID("pc-kernel"),
  1141  				"type":            "kernel",
  1142  				"default-channel": "20",
  1143  			},
  1144  			map[string]interface{}{
  1145  				"name":            "pc",
  1146  				"id":              s.AssertedSnapID("pc"),
  1147  				"type":            "gadget",
  1148  				"default-channel": "20",
  1149  			}},
  1150  	}, []*seedwriter.OptionsSnap{
  1151  		{Path: snapdFn},
  1152  	})
  1153  
  1154  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1155  	c.Assert(err, IsNil)
  1156  
  1157  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1158  	c.Assert(err, IsNil)
  1159  
  1160  	err = seed20.LoadMeta(s.perfTimings)
  1161  	c.Assert(err, IsNil)
  1162  
  1163  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1164  
  1165  	essSnaps := seed20.EssentialSnaps()
  1166  	c.Check(essSnaps, HasLen, 4)
  1167  
  1168  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1169  		{
  1170  			Path:          filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "snapd_1.0.snap"),
  1171  			SideInfo:      &snap.SideInfo{RealName: "snapd"},
  1172  			Essential:     true,
  1173  			EssentialType: snap.TypeSnapd,
  1174  			Required:      true,
  1175  		}, {
  1176  			Path:          s.expectedPath("pc-kernel"),
  1177  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1178  			EssentialType: snap.TypeKernel,
  1179  			Essential:     true,
  1180  			Required:      true,
  1181  			Channel:       "20",
  1182  		}, {
  1183  			Path:          s.expectedPath("core20"),
  1184  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1185  			EssentialType: snap.TypeBase,
  1186  			Essential:     true,
  1187  			Required:      true,
  1188  			Channel:       "latest/stable",
  1189  		}, {
  1190  			Path:          s.expectedPath("pc"),
  1191  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1192  			EssentialType: snap.TypeGadget,
  1193  			Essential:     true,
  1194  			Required:      true,
  1195  			Channel:       "20",
  1196  		},
  1197  	})
  1198  
  1199  	runSnaps, err := seed20.ModeSnaps("run")
  1200  	c.Assert(err, IsNil)
  1201  	c.Check(runSnaps, HasLen, 0)
  1202  }
  1203  
  1204  func (s *seed20Suite) TestLoadMetaCore20ModelOverrideSnapd(c *C) {
  1205  	s.makeSnap(c, "snapd", "")
  1206  	s.makeSnap(c, "core20", "")
  1207  	s.makeSnap(c, "pc-kernel=20", "")
  1208  	s.makeSnap(c, "pc=20", "")
  1209  
  1210  	sysLabel := "20191121"
  1211  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1212  		"display-name": "my model",
  1213  		"architecture": "amd64",
  1214  		"base":         "core20",
  1215  		"grade":        "dangerous",
  1216  		"snaps": []interface{}{
  1217  			map[string]interface{}{
  1218  				"name":            "snapd",
  1219  				"type":            "snapd",
  1220  				"default-channel": "latest/edge",
  1221  			},
  1222  			map[string]interface{}{
  1223  				"name":            "pc-kernel",
  1224  				"id":              s.AssertedSnapID("pc-kernel"),
  1225  				"type":            "kernel",
  1226  				"default-channel": "20",
  1227  			},
  1228  			map[string]interface{}{
  1229  				"name":            "pc",
  1230  				"id":              s.AssertedSnapID("pc"),
  1231  				"type":            "gadget",
  1232  				"default-channel": "20",
  1233  			}},
  1234  	}, nil)
  1235  
  1236  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1237  	c.Assert(err, IsNil)
  1238  
  1239  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1240  	c.Assert(err, IsNil)
  1241  
  1242  	err = seed20.LoadMeta(s.perfTimings)
  1243  	c.Assert(err, IsNil)
  1244  
  1245  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1246  
  1247  	essSnaps := seed20.EssentialSnaps()
  1248  	c.Check(essSnaps, HasLen, 4)
  1249  
  1250  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1251  		{
  1252  			Path:          s.expectedPath("snapd"),
  1253  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1254  			EssentialType: snap.TypeSnapd,
  1255  			Essential:     true,
  1256  			Required:      true,
  1257  			Channel:       "latest/edge",
  1258  		}, {
  1259  			Path:          s.expectedPath("pc-kernel"),
  1260  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1261  			EssentialType: snap.TypeKernel,
  1262  			Essential:     true,
  1263  			Required:      true,
  1264  			Channel:       "20",
  1265  		}, {
  1266  			Path:          s.expectedPath("core20"),
  1267  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1268  			EssentialType: snap.TypeBase,
  1269  			Essential:     true,
  1270  			Required:      true,
  1271  			Channel:       "latest/stable",
  1272  		}, {
  1273  			Path:          s.expectedPath("pc"),
  1274  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1275  			EssentialType: snap.TypeGadget,
  1276  			Essential:     true,
  1277  			Required:      true,
  1278  			Channel:       "20",
  1279  		},
  1280  	})
  1281  
  1282  	runSnaps, err := seed20.ModeSnaps("run")
  1283  	c.Assert(err, IsNil)
  1284  	c.Check(runSnaps, HasLen, 0)
  1285  }
  1286  
  1287  func (s *seed20Suite) TestLoadMetaCore20OptionalSnaps(c *C) {
  1288  	s.makeSnap(c, "snapd", "")
  1289  	s.makeSnap(c, "core20", "")
  1290  	s.makeSnap(c, "pc-kernel=20", "")
  1291  	s.makeSnap(c, "pc=20", "")
  1292  	s.makeSnap(c, "optional20-a", "developerid")
  1293  	s.makeSnap(c, "optional20-b", "developerid")
  1294  
  1295  	sysLabel := "20191122"
  1296  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1297  		"display-name": "my model",
  1298  		"architecture": "amd64",
  1299  		"base":         "core20",
  1300  		"grade":        "signed",
  1301  		"snaps": []interface{}{
  1302  			map[string]interface{}{
  1303  				"name":            "pc-kernel",
  1304  				"id":              s.AssertedSnapID("pc-kernel"),
  1305  				"type":            "kernel",
  1306  				"default-channel": "20",
  1307  			},
  1308  			map[string]interface{}{
  1309  				"name":            "pc",
  1310  				"id":              s.AssertedSnapID("pc"),
  1311  				"type":            "gadget",
  1312  				"default-channel": "20",
  1313  			},
  1314  			map[string]interface{}{
  1315  				"name":     "optional20-a",
  1316  				"id":       s.AssertedSnapID("optional20-a"),
  1317  				"presence": "optional",
  1318  			},
  1319  			map[string]interface{}{
  1320  				"name":     "optional20-b",
  1321  				"id":       s.AssertedSnapID("optional20-b"),
  1322  				"presence": "optional",
  1323  			}},
  1324  	}, []*seedwriter.OptionsSnap{
  1325  		{Name: "optional20-b"},
  1326  	})
  1327  
  1328  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1329  	c.Assert(err, IsNil)
  1330  
  1331  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1332  	c.Assert(err, IsNil)
  1333  
  1334  	err = seed20.LoadMeta(s.perfTimings)
  1335  	c.Assert(err, IsNil)
  1336  
  1337  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1338  
  1339  	essSnaps := seed20.EssentialSnaps()
  1340  	c.Check(essSnaps, HasLen, 4)
  1341  
  1342  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1343  		{
  1344  			Path:          s.expectedPath("snapd"),
  1345  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1346  			EssentialType: snap.TypeSnapd,
  1347  			Essential:     true,
  1348  			Required:      true,
  1349  			Channel:       "latest/stable",
  1350  		}, {
  1351  			Path:          s.expectedPath("pc-kernel"),
  1352  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1353  			EssentialType: snap.TypeKernel,
  1354  			Essential:     true,
  1355  			Required:      true,
  1356  			Channel:       "20",
  1357  		}, {
  1358  			Path:          s.expectedPath("core20"),
  1359  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1360  			EssentialType: snap.TypeBase,
  1361  			Essential:     true,
  1362  			Required:      true,
  1363  			Channel:       "latest/stable",
  1364  		}, {
  1365  			Path:          s.expectedPath("pc"),
  1366  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1367  			EssentialType: snap.TypeGadget,
  1368  			Essential:     true,
  1369  			Required:      true,
  1370  			Channel:       "20",
  1371  		},
  1372  	})
  1373  
  1374  	runSnaps, err := seed20.ModeSnaps("run")
  1375  	c.Assert(err, IsNil)
  1376  	c.Check(runSnaps, HasLen, 1)
  1377  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1378  		{
  1379  			Path:     s.expectedPath("optional20-b"),
  1380  			SideInfo: &s.AssertedSnapInfo("optional20-b").SideInfo,
  1381  			Required: false,
  1382  			Channel:  "latest/stable",
  1383  		},
  1384  	})
  1385  }
  1386  
  1387  func (s *seed20Suite) TestLoadMetaCore20OptionalSnapsLocal(c *C) {
  1388  	s.makeSnap(c, "snapd", "")
  1389  	s.makeSnap(c, "core20", "")
  1390  	s.makeSnap(c, "pc-kernel=20", "")
  1391  	s.makeSnap(c, "pc=20", "")
  1392  	s.makeSnap(c, "optional20-a", "developerid")
  1393  	optional20bFn := s.makeLocalSnap(c, "optional20-b")
  1394  
  1395  	sysLabel := "20191122"
  1396  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1397  		"display-name": "my model",
  1398  		"architecture": "amd64",
  1399  		"base":         "core20",
  1400  		"grade":        "dangerous",
  1401  		"snaps": []interface{}{
  1402  			map[string]interface{}{
  1403  				"name":            "pc-kernel",
  1404  				"id":              s.AssertedSnapID("pc-kernel"),
  1405  				"type":            "kernel",
  1406  				"default-channel": "20",
  1407  			},
  1408  			map[string]interface{}{
  1409  				"name":            "pc",
  1410  				"id":              s.AssertedSnapID("pc"),
  1411  				"type":            "gadget",
  1412  				"default-channel": "20",
  1413  			},
  1414  			map[string]interface{}{
  1415  				"name":     "optional20-a",
  1416  				"id":       s.AssertedSnapID("optional20-a"),
  1417  				"presence": "optional",
  1418  			},
  1419  			map[string]interface{}{
  1420  				"name":     "optional20-b",
  1421  				"id":       s.AssertedSnapID("optional20-b"),
  1422  				"presence": "optional",
  1423  			}},
  1424  	}, []*seedwriter.OptionsSnap{
  1425  		{Path: optional20bFn},
  1426  	})
  1427  
  1428  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1429  	c.Assert(err, IsNil)
  1430  
  1431  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1432  	c.Assert(err, IsNil)
  1433  
  1434  	err = seed20.LoadMeta(s.perfTimings)
  1435  	c.Assert(err, IsNil)
  1436  
  1437  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1438  
  1439  	essSnaps := seed20.EssentialSnaps()
  1440  	c.Check(essSnaps, HasLen, 4)
  1441  
  1442  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1443  		{
  1444  			Path:          s.expectedPath("snapd"),
  1445  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1446  			EssentialType: snap.TypeSnapd,
  1447  			Essential:     true,
  1448  			Required:      true,
  1449  			Channel:       "latest/stable",
  1450  		}, {
  1451  			Path:          s.expectedPath("pc-kernel"),
  1452  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1453  			EssentialType: snap.TypeKernel,
  1454  			Essential:     true,
  1455  			Required:      true,
  1456  			Channel:       "20",
  1457  		}, {
  1458  			Path:          s.expectedPath("core20"),
  1459  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1460  			EssentialType: snap.TypeBase,
  1461  			Essential:     true,
  1462  			Required:      true,
  1463  			Channel:       "latest/stable",
  1464  		}, {
  1465  			Path:          s.expectedPath("pc"),
  1466  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1467  			EssentialType: snap.TypeGadget,
  1468  			Essential:     true,
  1469  			Required:      true,
  1470  			Channel:       "20",
  1471  		},
  1472  	})
  1473  
  1474  	runSnaps, err := seed20.ModeSnaps("run")
  1475  	c.Assert(err, IsNil)
  1476  	c.Check(runSnaps, HasLen, 1)
  1477  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1478  		{
  1479  			Path:     filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "optional20-b_1.0.snap"),
  1480  			SideInfo: &snap.SideInfo{RealName: "optional20-b"},
  1481  
  1482  			Required: false,
  1483  		},
  1484  	})
  1485  }
  1486  
  1487  func (s *seed20Suite) TestLoadMetaCore20ExtraSnaps(c *C) {
  1488  	s.makeSnap(c, "snapd", "")
  1489  	s.makeSnap(c, "core20", "")
  1490  	s.makeSnap(c, "pc-kernel=20", "")
  1491  	s.makeSnap(c, "pc=20", "")
  1492  	s.makeSnap(c, "core18", "")
  1493  	s.makeSnap(c, "cont-producer", "developerid")
  1494  	contConsumerFn := s.makeLocalSnap(c, "cont-consumer")
  1495  
  1496  	sysLabel := "20191122"
  1497  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1498  		"display-name": "my model",
  1499  		"architecture": "amd64",
  1500  		"base":         "core20",
  1501  		"grade":        "dangerous",
  1502  		"snaps": []interface{}{
  1503  			map[string]interface{}{
  1504  				"name":            "pc-kernel",
  1505  				"id":              s.AssertedSnapID("pc-kernel"),
  1506  				"type":            "kernel",
  1507  				"default-channel": "20",
  1508  			},
  1509  			map[string]interface{}{
  1510  				"name":            "pc",
  1511  				"id":              s.AssertedSnapID("pc"),
  1512  				"type":            "gadget",
  1513  				"default-channel": "20",
  1514  			}},
  1515  	}, []*seedwriter.OptionsSnap{
  1516  		{Name: "cont-producer", Channel: "edge"},
  1517  		{Name: "core18"},
  1518  		{Path: contConsumerFn},
  1519  	})
  1520  
  1521  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1522  	c.Assert(err, IsNil)
  1523  
  1524  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1525  	c.Assert(err, IsNil)
  1526  
  1527  	err = seed20.LoadMeta(s.perfTimings)
  1528  	c.Assert(err, IsNil)
  1529  
  1530  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1531  
  1532  	essSnaps := seed20.EssentialSnaps()
  1533  	c.Check(essSnaps, HasLen, 4)
  1534  
  1535  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1536  		{
  1537  			Path:          s.expectedPath("snapd"),
  1538  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1539  			EssentialType: snap.TypeSnapd,
  1540  			Essential:     true,
  1541  			Required:      true,
  1542  			Channel:       "latest/stable",
  1543  		}, {
  1544  			Path:          s.expectedPath("pc-kernel"),
  1545  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1546  			EssentialType: snap.TypeKernel,
  1547  			Essential:     true,
  1548  			Required:      true,
  1549  			Channel:       "20",
  1550  		}, {
  1551  			Path:          s.expectedPath("core20"),
  1552  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1553  			EssentialType: snap.TypeBase,
  1554  			Essential:     true,
  1555  			Required:      true,
  1556  			Channel:       "latest/stable",
  1557  		}, {
  1558  			Path:          s.expectedPath("pc"),
  1559  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1560  			EssentialType: snap.TypeGadget,
  1561  			Essential:     true,
  1562  			Required:      true,
  1563  			Channel:       "20",
  1564  		},
  1565  	})
  1566  
  1567  	sysSnapsDir := filepath.Join(s.SeedDir, "systems", sysLabel, "snaps")
  1568  
  1569  	runSnaps, err := seed20.ModeSnaps("run")
  1570  	c.Assert(err, IsNil)
  1571  	c.Check(runSnaps, HasLen, 3)
  1572  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1573  		{
  1574  			Path:     filepath.Join(sysSnapsDir, "cont-producer_1.snap"),
  1575  			SideInfo: &s.AssertedSnapInfo("cont-producer").SideInfo,
  1576  			Channel:  "latest/edge",
  1577  		},
  1578  		{
  1579  			Path:     filepath.Join(sysSnapsDir, "core18_1.snap"),
  1580  			SideInfo: &s.AssertedSnapInfo("core18").SideInfo,
  1581  			Channel:  "latest/stable",
  1582  		},
  1583  		{
  1584  			Path:     filepath.Join(sysSnapsDir, "cont-consumer_1.0.snap"),
  1585  			SideInfo: &snap.SideInfo{RealName: "cont-consumer"},
  1586  		},
  1587  	})
  1588  
  1589  	recoverSnaps, err := seed20.ModeSnaps("recover")
  1590  	c.Assert(err, IsNil)
  1591  	c.Check(recoverSnaps, HasLen, 0)
  1592  }
  1593  
  1594  func (s *seed20Suite) TestLoadMetaCore20NotRunSnaps(c *C) {
  1595  	s.makeSnap(c, "snapd", "")
  1596  	s.makeSnap(c, "core20", "")
  1597  	s.makeSnap(c, "pc-kernel=20", "")
  1598  	s.makeSnap(c, "pc=20", "")
  1599  	s.makeSnap(c, "required20", "developerid")
  1600  	s.makeSnap(c, "optional20-a", "developerid")
  1601  	s.makeSnap(c, "optional20-b", "developerid")
  1602  
  1603  	sysLabel := "20191122"
  1604  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1605  		"display-name": "my model",
  1606  		"architecture": "amd64",
  1607  		"base":         "core20",
  1608  		"grade":        "signed",
  1609  		"snaps": []interface{}{
  1610  			map[string]interface{}{
  1611  				"name":            "pc-kernel",
  1612  				"id":              s.AssertedSnapID("pc-kernel"),
  1613  				"type":            "kernel",
  1614  				"default-channel": "20",
  1615  			},
  1616  			map[string]interface{}{
  1617  				"name":            "pc",
  1618  				"id":              s.AssertedSnapID("pc"),
  1619  				"type":            "gadget",
  1620  				"default-channel": "20",
  1621  			},
  1622  			map[string]interface{}{
  1623  				"name":  "required20",
  1624  				"id":    s.AssertedSnapID("required20"),
  1625  				"modes": []interface{}{"run", "ephemeral"},
  1626  			},
  1627  			map[string]interface{}{
  1628  				"name":     "optional20-a",
  1629  				"id":       s.AssertedSnapID("optional20-a"),
  1630  				"presence": "optional",
  1631  				"modes":    []interface{}{"ephemeral"},
  1632  			},
  1633  			map[string]interface{}{
  1634  				"name":     "optional20-b",
  1635  				"id":       s.AssertedSnapID("optional20-b"),
  1636  				"presence": "optional",
  1637  				"modes":    []interface{}{"install"},
  1638  			}},
  1639  	}, []*seedwriter.OptionsSnap{
  1640  		{Name: "optional20-a"},
  1641  		{Name: "optional20-b"},
  1642  	})
  1643  
  1644  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1645  	c.Assert(err, IsNil)
  1646  
  1647  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1648  	c.Assert(err, IsNil)
  1649  
  1650  	err = seed20.LoadMeta(s.perfTimings)
  1651  	c.Assert(err, IsNil)
  1652  
  1653  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1654  
  1655  	essSnaps := seed20.EssentialSnaps()
  1656  	c.Check(essSnaps, HasLen, 4)
  1657  
  1658  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1659  		{
  1660  			Path:          s.expectedPath("snapd"),
  1661  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1662  			EssentialType: snap.TypeSnapd,
  1663  			Essential:     true,
  1664  			Required:      true,
  1665  			Channel:       "latest/stable",
  1666  		}, {
  1667  			Path:          s.expectedPath("pc-kernel"),
  1668  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1669  			EssentialType: snap.TypeKernel,
  1670  			Essential:     true,
  1671  			Required:      true,
  1672  			Channel:       "20",
  1673  		}, {
  1674  			Path:          s.expectedPath("core20"),
  1675  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1676  			EssentialType: snap.TypeBase,
  1677  			Essential:     true,
  1678  			Required:      true,
  1679  			Channel:       "latest/stable",
  1680  		}, {
  1681  			Path:          s.expectedPath("pc"),
  1682  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1683  			EssentialType: snap.TypeGadget,
  1684  			Essential:     true,
  1685  			Required:      true,
  1686  			Channel:       "20",
  1687  		},
  1688  	})
  1689  
  1690  	runSnaps, err := seed20.ModeSnaps("run")
  1691  	c.Assert(err, IsNil)
  1692  	c.Check(runSnaps, HasLen, 1)
  1693  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1694  		{
  1695  			Path:     s.expectedPath("required20"),
  1696  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1697  			Required: true,
  1698  			Channel:  "latest/stable",
  1699  		},
  1700  	})
  1701  
  1702  	installSnaps, err := seed20.ModeSnaps("install")
  1703  	c.Assert(err, IsNil)
  1704  	c.Check(installSnaps, HasLen, 3)
  1705  	c.Check(installSnaps, DeepEquals, []*seed.Snap{
  1706  		{
  1707  			Path:     s.expectedPath("required20"),
  1708  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1709  			Required: true,
  1710  			Channel:  "latest/stable",
  1711  		},
  1712  		{
  1713  			Path:     s.expectedPath("optional20-a"),
  1714  			SideInfo: &s.AssertedSnapInfo("optional20-a").SideInfo,
  1715  			Required: false,
  1716  			Channel:  "latest/stable",
  1717  		},
  1718  		{
  1719  			Path:     s.expectedPath("optional20-b"),
  1720  			SideInfo: &s.AssertedSnapInfo("optional20-b").SideInfo,
  1721  			Required: false,
  1722  			Channel:  "latest/stable",
  1723  		},
  1724  	})
  1725  
  1726  	recoverSnaps, err := seed20.ModeSnaps("recover")
  1727  	c.Assert(err, IsNil)
  1728  	c.Check(recoverSnaps, HasLen, 2)
  1729  	c.Check(recoverSnaps, DeepEquals, []*seed.Snap{
  1730  		{
  1731  			Path:     s.expectedPath("required20"),
  1732  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1733  			Required: true,
  1734  			Channel:  "latest/stable",
  1735  		},
  1736  		{
  1737  			Path:     s.expectedPath("optional20-a"),
  1738  			SideInfo: &s.AssertedSnapInfo("optional20-a").SideInfo,
  1739  			Required: false,
  1740  			Channel:  "latest/stable",
  1741  		},
  1742  	})
  1743  }
  1744  
  1745  func (s *seed20Suite) TestLoadMetaCore20LocalAssertedSnaps(c *C) {
  1746  	s.makeSnap(c, "snapd", "")
  1747  	s.makeSnap(c, "core20", "")
  1748  	s.makeSnap(c, "pc-kernel=20", "")
  1749  	s.makeSnap(c, "pc=20", "")
  1750  	s.makeSnap(c, "required20", "developerid")
  1751  
  1752  	sysLabel := "20191209"
  1753  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1754  		"display-name": "my model",
  1755  		"architecture": "amd64",
  1756  		"base":         "core20",
  1757  		"grade":        "dangerous",
  1758  		"snaps": []interface{}{
  1759  			map[string]interface{}{
  1760  				"name":            "pc-kernel",
  1761  				"id":              s.AssertedSnapID("pc-kernel"),
  1762  				"type":            "kernel",
  1763  				"default-channel": "20",
  1764  			},
  1765  			map[string]interface{}{
  1766  				"name":            "pc",
  1767  				"id":              s.AssertedSnapID("pc"),
  1768  				"type":            "gadget",
  1769  				"default-channel": "20",
  1770  			}},
  1771  	}, []*seedwriter.OptionsSnap{
  1772  		{Path: s.AssertedSnap("pc"), Channel: "edge"},
  1773  		{Path: s.AssertedSnap("required20")},
  1774  	})
  1775  
  1776  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1777  	c.Assert(err, IsNil)
  1778  
  1779  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1780  	c.Assert(err, IsNil)
  1781  
  1782  	err = seed20.LoadMeta(s.perfTimings)
  1783  	c.Assert(err, IsNil)
  1784  
  1785  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1786  
  1787  	essSnaps := seed20.EssentialSnaps()
  1788  	c.Check(essSnaps, HasLen, 4)
  1789  
  1790  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1791  		{
  1792  			Path:          s.expectedPath("snapd"),
  1793  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1794  			EssentialType: snap.TypeSnapd,
  1795  			Essential:     true,
  1796  			Required:      true,
  1797  			Channel:       "latest/stable",
  1798  		}, {
  1799  			Path:          s.expectedPath("pc-kernel"),
  1800  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1801  			EssentialType: snap.TypeKernel,
  1802  			Essential:     true,
  1803  			Required:      true,
  1804  			Channel:       "20",
  1805  		}, {
  1806  			Path:          s.expectedPath("core20"),
  1807  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1808  			EssentialType: snap.TypeBase,
  1809  			Essential:     true,
  1810  			Required:      true,
  1811  			Channel:       "latest/stable",
  1812  		}, {
  1813  			Path:          s.expectedPath("pc"),
  1814  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1815  			EssentialType: snap.TypeGadget,
  1816  			Essential:     true,
  1817  			Required:      true,
  1818  			Channel:       "20/edge",
  1819  		},
  1820  	})
  1821  
  1822  	sysSnapsDir := filepath.Join(s.SeedDir, "systems", sysLabel, "snaps")
  1823  
  1824  	runSnaps, err := seed20.ModeSnaps("run")
  1825  	c.Assert(err, IsNil)
  1826  	c.Check(runSnaps, HasLen, 1)
  1827  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1828  		{
  1829  			Path:     filepath.Join(sysSnapsDir, "required20_1.snap"),
  1830  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1831  			Channel:  "latest/stable",
  1832  		},
  1833  	})
  1834  }
  1835  
  1836  func (s *seed20Suite) TestOpenInvalidLabel(c *C) {
  1837  	invalid := []string{
  1838  		// empty string not included, as it's not a UC20 seed
  1839  		"/bin",
  1840  		"../../bin/bar",
  1841  		":invalid:",
  1842  		"日本語",
  1843  	}
  1844  	for _, label := range invalid {
  1845  		seed20, err := seed.Open(s.SeedDir, label)
  1846  		c.Assert(err, ErrorMatches, fmt.Sprintf("invalid seed system label: %q", label))
  1847  		c.Assert(seed20, IsNil)
  1848  	}
  1849  }