gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/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").EditedContact = "mailto: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  		err = seed20.LoadAssertions(nil, nil)
   807  		c.Assert(err, IsNil)
   808  
   809  		err = seed20.LoadEssentialMeta(t.onlyTypes, s.perfTimings)
   810  		c.Assert(err, IsNil)
   811  
   812  		c.Check(seed20.UsesSnapdSnap(), Equals, true)
   813  
   814  		essSnaps := seed20.EssentialSnaps()
   815  		c.Check(essSnaps, HasLen, len(t.expected))
   816  
   817  		c.Check(essSnaps, DeepEquals, t.expected)
   818  
   819  		runSnaps, err := seed20.ModeSnaps("run")
   820  		c.Assert(err, IsNil)
   821  		c.Check(runSnaps, HasLen, 0)
   822  
   823  		unhide()
   824  
   825  		// test short-cut helper as well
   826  		mod, essSnaps, err := seed.ReadSystemEssential(s.SeedDir, sysLabel, t.onlyTypes, s.perfTimings)
   827  		c.Assert(err, IsNil)
   828  		c.Check(mod.BrandID(), Equals, "my-brand")
   829  		c.Check(mod.Model(), Equals, "my-model")
   830  		c.Check(essSnaps, HasLen, len(t.expected))
   831  		c.Check(essSnaps, DeepEquals, t.expected)
   832  	}
   833  }
   834  
   835  func (s *seed20Suite) TestReadSystemEssentialAndBetterEarliestTime(c *C) {
   836  	r := seed.MockTrusted(s.StoreSigning.Trusted)
   837  	defer r()
   838  
   839  	s.makeSnap(c, "snapd", "")
   840  	s.makeSnap(c, "core20", "")
   841  	s.makeSnap(c, "pc-kernel=20", "")
   842  	s.makeSnap(c, "pc=20", "")
   843  	s.makeSnap(c, "core18", "")
   844  	t0 := time.Now().UTC().Truncate(time.Second)
   845  	s.SetSnapAssertionNow(t0.Add(2 * time.Second))
   846  	s.makeSnap(c, "required18", "developerid")
   847  	s.SetSnapAssertionNow(time.Time{})
   848  
   849  	snapdSnap := &seed.Snap{
   850  		Path:          s.expectedPath("snapd"),
   851  		SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
   852  		EssentialType: snap.TypeSnapd,
   853  		Essential:     true,
   854  		Required:      true,
   855  		Channel:       "latest/stable",
   856  	}
   857  	pcKernelSnap := &seed.Snap{
   858  		Path:          s.expectedPath("pc-kernel"),
   859  		SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
   860  		EssentialType: snap.TypeKernel,
   861  		Essential:     true,
   862  		Required:      true,
   863  		Channel:       "20",
   864  	}
   865  	core20Snap := &seed.Snap{Path: s.expectedPath("core20"),
   866  		SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
   867  		EssentialType: snap.TypeBase,
   868  		Essential:     true,
   869  		Required:      true,
   870  		Channel:       "latest/stable",
   871  	}
   872  	pcSnap := &seed.Snap{
   873  		Path:          s.expectedPath("pc"),
   874  		SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
   875  		EssentialType: snap.TypeGadget,
   876  		Essential:     true,
   877  		Required:      true,
   878  		Channel:       "20",
   879  	}
   880  
   881  	tests := []struct {
   882  		onlyTypes []snap.Type
   883  		expected  []*seed.Snap
   884  	}{
   885  		{[]snap.Type{snap.TypeSnapd}, []*seed.Snap{snapdSnap}},
   886  		{[]snap.Type{snap.TypeKernel}, []*seed.Snap{pcKernelSnap}},
   887  		{[]snap.Type{snap.TypeBase}, []*seed.Snap{core20Snap}},
   888  		{[]snap.Type{snap.TypeGadget}, []*seed.Snap{pcSnap}},
   889  		{[]snap.Type{snap.TypeSnapd, snap.TypeKernel, snap.TypeBase}, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap}},
   890  		// the order in essentialTypes is not relevant
   891  		{[]snap.Type{snap.TypeGadget, snap.TypeKernel}, []*seed.Snap{pcKernelSnap, pcSnap}},
   892  		// degenerate case
   893  		{[]snap.Type{}, []*seed.Snap(nil)},
   894  	}
   895  
   896  	baseLabel := "20210315"
   897  
   898  	testReadSystemEssentialAndBetterEarliestTime := func(sysLabel string, earliestTime, modelTime, improvedTime time.Time) {
   899  		s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   900  			"display-name": "my model",
   901  			"timestamp":    modelTime.Format(time.RFC3339),
   902  			"architecture": "amd64",
   903  			"base":         "core20",
   904  			"snaps": []interface{}{
   905  				map[string]interface{}{
   906  					"name":            "pc-kernel",
   907  					"id":              s.AssertedSnapID("pc-kernel"),
   908  					"type":            "kernel",
   909  					"default-channel": "20",
   910  				},
   911  				map[string]interface{}{
   912  					"name":            "pc",
   913  					"id":              s.AssertedSnapID("pc"),
   914  					"type":            "gadget",
   915  					"default-channel": "20",
   916  				},
   917  				map[string]interface{}{
   918  					"name": "core18",
   919  					"id":   s.AssertedSnapID("core18"),
   920  					"type": "base",
   921  				},
   922  				map[string]interface{}{
   923  					"name": "required18",
   924  					"id":   s.AssertedSnapID("required18"),
   925  				}},
   926  		}, nil)
   927  
   928  		for _, t := range tests {
   929  			// test short-cut helper as well
   930  			mod, essSnaps, betterTime, err := seed.ReadSystemEssentialAndBetterEarliestTime(s.SeedDir, sysLabel, t.onlyTypes, earliestTime, s.perfTimings)
   931  			c.Assert(err, IsNil)
   932  			c.Check(mod.BrandID(), Equals, "my-brand")
   933  			c.Check(mod.Model(), Equals, "my-model")
   934  			c.Check(mod.Timestamp().Equal(modelTime), Equals, true)
   935  			c.Check(essSnaps, HasLen, len(t.expected))
   936  			c.Check(essSnaps, DeepEquals, t.expected)
   937  			c.Check(betterTime.Equal(improvedTime), Equals, true, Commentf("%v expected: %v", betterTime, improvedTime))
   938  		}
   939  	}
   940  
   941  	revsTime := s.AssertedSnapRevision("required18").Timestamp()
   942  	t2 := revsTime.Add(1 * time.Second)
   943  
   944  	timeCombos := []struct {
   945  		earliestTime, modelTime, improvedTime time.Time
   946  	}{
   947  		{time.Time{}, t0, revsTime},
   948  		{t2.AddDate(-1, 0, 0), t0, revsTime},
   949  		{t2.AddDate(-1, 0, 0), t2, t2},
   950  		{t2.AddDate(0, 1, 0), t2, t2.AddDate(0, 1, 0)},
   951  	}
   952  
   953  	for i, c := range timeCombos {
   954  		label := fmt.Sprintf("%s%d", baseLabel, i)
   955  		testReadSystemEssentialAndBetterEarliestTime(label, c.earliestTime, c.modelTime, c.improvedTime)
   956  	}
   957  }
   958  
   959  func (s *seed20Suite) TestLoadEssentialAndMetaCore20(c *C) {
   960  	r := seed.MockTrusted(s.StoreSigning.Trusted)
   961  	defer r()
   962  
   963  	s.makeSnap(c, "snapd", "")
   964  	s.makeSnap(c, "core20", "")
   965  	s.makeSnap(c, "pc-kernel=20", "")
   966  	s.makeSnap(c, "pc=20", "")
   967  	s.makeSnap(c, "core18", "")
   968  	s.makeSnap(c, "required18", "developerid")
   969  
   970  	sysLabel := "20191018"
   971  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
   972  		"display-name": "my model",
   973  		"architecture": "amd64",
   974  		"base":         "core20",
   975  		"snaps": []interface{}{
   976  			map[string]interface{}{
   977  				"name":            "pc-kernel",
   978  				"id":              s.AssertedSnapID("pc-kernel"),
   979  				"type":            "kernel",
   980  				"default-channel": "20",
   981  			},
   982  			map[string]interface{}{
   983  				"name":            "pc",
   984  				"id":              s.AssertedSnapID("pc"),
   985  				"type":            "gadget",
   986  				"default-channel": "20",
   987  			},
   988  			map[string]interface{}{
   989  				"name": "core18",
   990  				"id":   s.AssertedSnapID("core18"),
   991  				"type": "base",
   992  			},
   993  			map[string]interface{}{
   994  				"name": "required18",
   995  				"id":   s.AssertedSnapID("required18"),
   996  			}},
   997  	}, nil)
   998  
   999  	snapdSnap := &seed.Snap{
  1000  		Path:          s.expectedPath("snapd"),
  1001  		SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1002  		EssentialType: snap.TypeSnapd,
  1003  		Essential:     true,
  1004  		Required:      true,
  1005  		Channel:       "latest/stable",
  1006  	}
  1007  	pcKernelSnap := &seed.Snap{
  1008  		Path:          s.expectedPath("pc-kernel"),
  1009  		SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1010  		EssentialType: snap.TypeKernel,
  1011  		Essential:     true,
  1012  		Required:      true,
  1013  		Channel:       "20",
  1014  	}
  1015  	core20Snap := &seed.Snap{Path: s.expectedPath("core20"),
  1016  		SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1017  		EssentialType: snap.TypeBase,
  1018  		Essential:     true,
  1019  		Required:      true,
  1020  		Channel:       "latest/stable",
  1021  	}
  1022  	pcSnap := &seed.Snap{
  1023  		Path:          s.expectedPath("pc"),
  1024  		SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1025  		EssentialType: snap.TypeGadget,
  1026  		Essential:     true,
  1027  		Required:      true,
  1028  		Channel:       "20",
  1029  	}
  1030  
  1031  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1032  	c.Assert(err, IsNil)
  1033  
  1034  	err = seed20.LoadAssertions(nil, nil)
  1035  	c.Assert(err, IsNil)
  1036  
  1037  	err = seed20.LoadEssentialMeta([]snap.Type{snap.TypeGadget}, s.perfTimings)
  1038  	c.Assert(err, IsNil)
  1039  
  1040  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1041  
  1042  	essSnaps := seed20.EssentialSnaps()
  1043  	c.Check(essSnaps, DeepEquals, []*seed.Snap{pcSnap})
  1044  
  1045  	err = seed20.LoadEssentialMeta([]snap.Type{snap.TypeSnapd, snap.TypeKernel, snap.TypeBase, snap.TypeGadget}, s.perfTimings)
  1046  	c.Assert(err, IsNil)
  1047  
  1048  	essSnaps = seed20.EssentialSnaps()
  1049  	c.Check(essSnaps, DeepEquals, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap, pcSnap})
  1050  
  1051  	runSnaps, err := seed20.ModeSnaps("run")
  1052  	c.Assert(err, IsNil)
  1053  	c.Check(runSnaps, HasLen, 0)
  1054  
  1055  	// caching in place
  1056  	hideSnaps(c, []*seed.Snap{snapdSnap, core20Snap, pcKernelSnap}, nil)
  1057  
  1058  	err = seed20.LoadMeta(s.perfTimings)
  1059  	c.Assert(err, IsNil)
  1060  
  1061  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1062  
  1063  	essSnaps = seed20.EssentialSnaps()
  1064  	c.Check(essSnaps, DeepEquals, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap, pcSnap})
  1065  
  1066  	runSnaps, err = seed20.ModeSnaps("run")
  1067  	c.Assert(err, IsNil)
  1068  	c.Check(runSnaps, HasLen, 2)
  1069  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1070  		{
  1071  			Path:     s.expectedPath("core18"),
  1072  			SideInfo: &s.AssertedSnapInfo("core18").SideInfo,
  1073  			Required: true,
  1074  			Channel:  "latest/stable",
  1075  		}, {
  1076  			Path:     s.expectedPath("required18"),
  1077  			SideInfo: &s.AssertedSnapInfo("required18").SideInfo,
  1078  			Required: true,
  1079  			Channel:  "latest/stable",
  1080  		},
  1081  	})
  1082  
  1083  }
  1084  
  1085  func (s *seed20Suite) makeLocalSnap(c *C, yamlKey string) (fname string) {
  1086  	return snaptest.MakeTestSnapWithFiles(c, snapYaml[yamlKey], nil)
  1087  }
  1088  
  1089  func (s *seed20Suite) TestLoadMetaCore20LocalSnaps(c *C) {
  1090  	s.makeSnap(c, "snapd", "")
  1091  	s.makeSnap(c, "core20", "")
  1092  	s.makeSnap(c, "pc-kernel=20", "")
  1093  	s.makeSnap(c, "pc=20", "")
  1094  	requiredFn := s.makeLocalSnap(c, "required20")
  1095  
  1096  	sysLabel := "20191030"
  1097  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1098  		"display-name": "my model",
  1099  		"architecture": "amd64",
  1100  		"base":         "core20",
  1101  		"grade":        "dangerous",
  1102  		"snaps": []interface{}{
  1103  			map[string]interface{}{
  1104  				"name":            "pc-kernel",
  1105  				"id":              s.AssertedSnapID("pc-kernel"),
  1106  				"type":            "kernel",
  1107  				"default-channel": "20",
  1108  			},
  1109  			map[string]interface{}{
  1110  				"name":            "pc",
  1111  				"id":              s.AssertedSnapID("pc"),
  1112  				"type":            "gadget",
  1113  				"default-channel": "20",
  1114  			},
  1115  			map[string]interface{}{
  1116  				"name": "required20",
  1117  				"id":   s.AssertedSnapID("required20"),
  1118  			}},
  1119  	}, []*seedwriter.OptionsSnap{
  1120  		{Path: requiredFn},
  1121  	})
  1122  
  1123  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1124  	c.Assert(err, IsNil)
  1125  
  1126  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1127  	c.Assert(err, IsNil)
  1128  
  1129  	err = seed20.LoadMeta(s.perfTimings)
  1130  	c.Assert(err, IsNil)
  1131  
  1132  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1133  
  1134  	essSnaps := seed20.EssentialSnaps()
  1135  	c.Check(essSnaps, HasLen, 4)
  1136  
  1137  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1138  		{
  1139  			Path:          s.expectedPath("snapd"),
  1140  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1141  			EssentialType: snap.TypeSnapd,
  1142  			Essential:     true,
  1143  			Required:      true,
  1144  			Channel:       "latest/stable",
  1145  		}, {
  1146  			Path:          s.expectedPath("pc-kernel"),
  1147  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1148  			EssentialType: snap.TypeKernel,
  1149  			Essential:     true,
  1150  			Required:      true,
  1151  			Channel:       "20",
  1152  		}, {
  1153  			Path:          s.expectedPath("core20"),
  1154  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1155  			EssentialType: snap.TypeBase,
  1156  			Essential:     true,
  1157  			Required:      true,
  1158  			Channel:       "latest/stable",
  1159  		}, {
  1160  			Path:          s.expectedPath("pc"),
  1161  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1162  			EssentialType: snap.TypeGadget,
  1163  			Essential:     true,
  1164  			Required:      true,
  1165  			Channel:       "20",
  1166  		},
  1167  	})
  1168  
  1169  	runSnaps, err := seed20.ModeSnaps("run")
  1170  	c.Assert(err, IsNil)
  1171  	c.Check(runSnaps, HasLen, 1)
  1172  
  1173  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1174  		{
  1175  			Path:     filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "required20_1.0.snap"),
  1176  			SideInfo: &snap.SideInfo{RealName: "required20"},
  1177  			Required: true,
  1178  		},
  1179  	})
  1180  }
  1181  
  1182  func (s *seed20Suite) TestLoadMetaCore20ChannelOverride(c *C) {
  1183  	s.makeSnap(c, "snapd", "")
  1184  	s.makeSnap(c, "core20", "")
  1185  	s.makeSnap(c, "pc-kernel=20", "")
  1186  	s.makeSnap(c, "pc=20", "")
  1187  	s.makeSnap(c, "required20", "developerid")
  1188  
  1189  	s.AssertedSnapInfo("required20").EditedContact = "mailto:author@example.com"
  1190  
  1191  	sysLabel := "20191018"
  1192  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1193  		"display-name": "my model",
  1194  		"architecture": "amd64",
  1195  		"base":         "core20",
  1196  		"grade":        "dangerous",
  1197  		"snaps": []interface{}{
  1198  			map[string]interface{}{
  1199  				"name":            "pc-kernel",
  1200  				"id":              s.AssertedSnapID("pc-kernel"),
  1201  				"type":            "kernel",
  1202  				"default-channel": "20",
  1203  			},
  1204  			map[string]interface{}{
  1205  				"name":            "pc",
  1206  				"id":              s.AssertedSnapID("pc"),
  1207  				"type":            "gadget",
  1208  				"default-channel": "20",
  1209  			},
  1210  			map[string]interface{}{
  1211  				"name": "required20",
  1212  				"id":   s.AssertedSnapID("required20"),
  1213  			}},
  1214  	}, []*seedwriter.OptionsSnap{
  1215  		{Name: "pc", Channel: "20experimental/edge"},
  1216  	})
  1217  
  1218  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1219  	c.Assert(err, IsNil)
  1220  
  1221  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1222  	c.Assert(err, IsNil)
  1223  
  1224  	err = seed20.LoadMeta(s.perfTimings)
  1225  	c.Assert(err, IsNil)
  1226  
  1227  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1228  
  1229  	essSnaps := seed20.EssentialSnaps()
  1230  	c.Check(essSnaps, HasLen, 4)
  1231  
  1232  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1233  		{
  1234  			Path:          s.expectedPath("snapd"),
  1235  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1236  			EssentialType: snap.TypeSnapd,
  1237  			Essential:     true,
  1238  			Required:      true,
  1239  			Channel:       "latest/stable",
  1240  		}, {
  1241  			Path:          s.expectedPath("pc-kernel"),
  1242  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1243  			EssentialType: snap.TypeKernel,
  1244  			Essential:     true,
  1245  			Required:      true,
  1246  			Channel:       "20",
  1247  		}, {
  1248  			Path:          s.expectedPath("core20"),
  1249  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1250  			EssentialType: snap.TypeBase,
  1251  			Essential:     true,
  1252  			Required:      true,
  1253  			Channel:       "latest/stable",
  1254  		}, {
  1255  			Path:          s.expectedPath("pc"),
  1256  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1257  			EssentialType: snap.TypeGadget,
  1258  			Essential:     true,
  1259  			Required:      true,
  1260  			Channel:       "20experimental/edge",
  1261  		},
  1262  	})
  1263  
  1264  	runSnaps, err := seed20.ModeSnaps("run")
  1265  	c.Assert(err, IsNil)
  1266  	c.Check(runSnaps, HasLen, 1)
  1267  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1268  		{
  1269  			Path:     s.expectedPath("required20"),
  1270  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1271  			Required: true,
  1272  			Channel:  "latest/stable",
  1273  		},
  1274  	})
  1275  }
  1276  
  1277  func (s *seed20Suite) TestLoadMetaCore20ChannelOverrideSnapd(c *C) {
  1278  	s.makeSnap(c, "snapd", "")
  1279  	s.makeSnap(c, "core20", "")
  1280  	s.makeSnap(c, "pc-kernel=20", "")
  1281  	s.makeSnap(c, "pc=20", "")
  1282  	s.makeSnap(c, "required20", "developerid")
  1283  
  1284  	s.AssertedSnapInfo("required20").EditedContact = "mailto:author@example.com"
  1285  
  1286  	sysLabel := "20191121"
  1287  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1288  		"display-name": "my model",
  1289  		"architecture": "amd64",
  1290  		"base":         "core20",
  1291  		"grade":        "dangerous",
  1292  		"snaps": []interface{}{
  1293  			map[string]interface{}{
  1294  				"name":            "pc-kernel",
  1295  				"id":              s.AssertedSnapID("pc-kernel"),
  1296  				"type":            "kernel",
  1297  				"default-channel": "20",
  1298  			},
  1299  			map[string]interface{}{
  1300  				"name":            "pc",
  1301  				"id":              s.AssertedSnapID("pc"),
  1302  				"type":            "gadget",
  1303  				"default-channel": "20",
  1304  			},
  1305  			map[string]interface{}{
  1306  				"name": "required20",
  1307  				"id":   s.AssertedSnapID("required20"),
  1308  			}},
  1309  	}, []*seedwriter.OptionsSnap{
  1310  		{Name: "snapd", Channel: "20experimental/edge"},
  1311  	})
  1312  
  1313  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1314  	c.Assert(err, IsNil)
  1315  
  1316  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1317  	c.Assert(err, IsNil)
  1318  
  1319  	err = seed20.LoadMeta(s.perfTimings)
  1320  	c.Assert(err, IsNil)
  1321  
  1322  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1323  
  1324  	essSnaps := seed20.EssentialSnaps()
  1325  	c.Check(essSnaps, HasLen, 4)
  1326  
  1327  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1328  		{
  1329  			Path:          s.expectedPath("snapd"),
  1330  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1331  			EssentialType: snap.TypeSnapd,
  1332  			Essential:     true,
  1333  			Required:      true,
  1334  			Channel:       "20experimental/edge",
  1335  		}, {
  1336  			Path:          s.expectedPath("pc-kernel"),
  1337  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1338  			EssentialType: snap.TypeKernel,
  1339  			Essential:     true,
  1340  			Required:      true,
  1341  			Channel:       "20",
  1342  		}, {
  1343  			Path:          s.expectedPath("core20"),
  1344  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1345  			EssentialType: snap.TypeBase,
  1346  			Essential:     true,
  1347  			Required:      true,
  1348  			Channel:       "latest/stable",
  1349  		}, {
  1350  			Path:          s.expectedPath("pc"),
  1351  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1352  			EssentialType: snap.TypeGadget,
  1353  			Essential:     true,
  1354  			Required:      true,
  1355  			Channel:       "20",
  1356  		},
  1357  	})
  1358  
  1359  	runSnaps, err := seed20.ModeSnaps("run")
  1360  	c.Assert(err, IsNil)
  1361  	c.Check(runSnaps, HasLen, 1)
  1362  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1363  		{
  1364  			Path:     s.expectedPath("required20"),
  1365  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1366  			Required: true,
  1367  			Channel:  "latest/stable",
  1368  		},
  1369  	})
  1370  }
  1371  
  1372  func (s *seed20Suite) TestLoadMetaCore20LocalSnapd(c *C) {
  1373  	snapdFn := s.makeLocalSnap(c, "snapd")
  1374  	s.makeSnap(c, "core20", "")
  1375  	s.makeSnap(c, "pc-kernel=20", "")
  1376  	s.makeSnap(c, "pc=20", "")
  1377  
  1378  	sysLabel := "20191121"
  1379  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1380  		"display-name": "my model",
  1381  		"architecture": "amd64",
  1382  		"base":         "core20",
  1383  		"grade":        "dangerous",
  1384  		"snaps": []interface{}{
  1385  			map[string]interface{}{
  1386  				"name":            "pc-kernel",
  1387  				"id":              s.AssertedSnapID("pc-kernel"),
  1388  				"type":            "kernel",
  1389  				"default-channel": "20",
  1390  			},
  1391  			map[string]interface{}{
  1392  				"name":            "pc",
  1393  				"id":              s.AssertedSnapID("pc"),
  1394  				"type":            "gadget",
  1395  				"default-channel": "20",
  1396  			}},
  1397  	}, []*seedwriter.OptionsSnap{
  1398  		{Path: snapdFn},
  1399  	})
  1400  
  1401  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1402  	c.Assert(err, IsNil)
  1403  
  1404  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1405  	c.Assert(err, IsNil)
  1406  
  1407  	err = seed20.LoadMeta(s.perfTimings)
  1408  	c.Assert(err, IsNil)
  1409  
  1410  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1411  
  1412  	essSnaps := seed20.EssentialSnaps()
  1413  	c.Check(essSnaps, HasLen, 4)
  1414  
  1415  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1416  		{
  1417  			Path:          filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "snapd_1.0.snap"),
  1418  			SideInfo:      &snap.SideInfo{RealName: "snapd"},
  1419  			Essential:     true,
  1420  			EssentialType: snap.TypeSnapd,
  1421  			Required:      true,
  1422  		}, {
  1423  			Path:          s.expectedPath("pc-kernel"),
  1424  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1425  			EssentialType: snap.TypeKernel,
  1426  			Essential:     true,
  1427  			Required:      true,
  1428  			Channel:       "20",
  1429  		}, {
  1430  			Path:          s.expectedPath("core20"),
  1431  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1432  			EssentialType: snap.TypeBase,
  1433  			Essential:     true,
  1434  			Required:      true,
  1435  			Channel:       "latest/stable",
  1436  		}, {
  1437  			Path:          s.expectedPath("pc"),
  1438  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1439  			EssentialType: snap.TypeGadget,
  1440  			Essential:     true,
  1441  			Required:      true,
  1442  			Channel:       "20",
  1443  		},
  1444  	})
  1445  
  1446  	runSnaps, err := seed20.ModeSnaps("run")
  1447  	c.Assert(err, IsNil)
  1448  	c.Check(runSnaps, HasLen, 0)
  1449  }
  1450  
  1451  func (s *seed20Suite) TestLoadMetaCore20ModelOverrideSnapd(c *C) {
  1452  	s.makeSnap(c, "snapd", "")
  1453  	s.makeSnap(c, "core20", "")
  1454  	s.makeSnap(c, "pc-kernel=20", "")
  1455  	s.makeSnap(c, "pc=20", "")
  1456  
  1457  	sysLabel := "20191121"
  1458  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1459  		"display-name": "my model",
  1460  		"architecture": "amd64",
  1461  		"base":         "core20",
  1462  		"grade":        "dangerous",
  1463  		"snaps": []interface{}{
  1464  			map[string]interface{}{
  1465  				"name":            "snapd",
  1466  				"type":            "snapd",
  1467  				"default-channel": "latest/edge",
  1468  			},
  1469  			map[string]interface{}{
  1470  				"name":            "pc-kernel",
  1471  				"id":              s.AssertedSnapID("pc-kernel"),
  1472  				"type":            "kernel",
  1473  				"default-channel": "20",
  1474  			},
  1475  			map[string]interface{}{
  1476  				"name":            "pc",
  1477  				"id":              s.AssertedSnapID("pc"),
  1478  				"type":            "gadget",
  1479  				"default-channel": "20",
  1480  			}},
  1481  	}, nil)
  1482  
  1483  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1484  	c.Assert(err, IsNil)
  1485  
  1486  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1487  	c.Assert(err, IsNil)
  1488  
  1489  	err = seed20.LoadMeta(s.perfTimings)
  1490  	c.Assert(err, IsNil)
  1491  
  1492  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1493  
  1494  	essSnaps := seed20.EssentialSnaps()
  1495  	c.Check(essSnaps, HasLen, 4)
  1496  
  1497  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1498  		{
  1499  			Path:          s.expectedPath("snapd"),
  1500  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1501  			EssentialType: snap.TypeSnapd,
  1502  			Essential:     true,
  1503  			Required:      true,
  1504  			Channel:       "latest/edge",
  1505  		}, {
  1506  			Path:          s.expectedPath("pc-kernel"),
  1507  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1508  			EssentialType: snap.TypeKernel,
  1509  			Essential:     true,
  1510  			Required:      true,
  1511  			Channel:       "20",
  1512  		}, {
  1513  			Path:          s.expectedPath("core20"),
  1514  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1515  			EssentialType: snap.TypeBase,
  1516  			Essential:     true,
  1517  			Required:      true,
  1518  			Channel:       "latest/stable",
  1519  		}, {
  1520  			Path:          s.expectedPath("pc"),
  1521  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1522  			EssentialType: snap.TypeGadget,
  1523  			Essential:     true,
  1524  			Required:      true,
  1525  			Channel:       "20",
  1526  		},
  1527  	})
  1528  
  1529  	runSnaps, err := seed20.ModeSnaps("run")
  1530  	c.Assert(err, IsNil)
  1531  	c.Check(runSnaps, HasLen, 0)
  1532  }
  1533  
  1534  func (s *seed20Suite) TestLoadMetaCore20OptionalSnaps(c *C) {
  1535  	s.makeSnap(c, "snapd", "")
  1536  	s.makeSnap(c, "core20", "")
  1537  	s.makeSnap(c, "pc-kernel=20", "")
  1538  	s.makeSnap(c, "pc=20", "")
  1539  	s.makeSnap(c, "optional20-a", "developerid")
  1540  	s.makeSnap(c, "optional20-b", "developerid")
  1541  
  1542  	sysLabel := "20191122"
  1543  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1544  		"display-name": "my model",
  1545  		"architecture": "amd64",
  1546  		"base":         "core20",
  1547  		"grade":        "signed",
  1548  		"snaps": []interface{}{
  1549  			map[string]interface{}{
  1550  				"name":            "pc-kernel",
  1551  				"id":              s.AssertedSnapID("pc-kernel"),
  1552  				"type":            "kernel",
  1553  				"default-channel": "20",
  1554  			},
  1555  			map[string]interface{}{
  1556  				"name":            "pc",
  1557  				"id":              s.AssertedSnapID("pc"),
  1558  				"type":            "gadget",
  1559  				"default-channel": "20",
  1560  			},
  1561  			map[string]interface{}{
  1562  				"name":     "optional20-a",
  1563  				"id":       s.AssertedSnapID("optional20-a"),
  1564  				"presence": "optional",
  1565  			},
  1566  			map[string]interface{}{
  1567  				"name":     "optional20-b",
  1568  				"id":       s.AssertedSnapID("optional20-b"),
  1569  				"presence": "optional",
  1570  			}},
  1571  	}, []*seedwriter.OptionsSnap{
  1572  		{Name: "optional20-b"},
  1573  	})
  1574  
  1575  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1576  	c.Assert(err, IsNil)
  1577  
  1578  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1579  	c.Assert(err, IsNil)
  1580  
  1581  	err = seed20.LoadMeta(s.perfTimings)
  1582  	c.Assert(err, IsNil)
  1583  
  1584  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1585  
  1586  	essSnaps := seed20.EssentialSnaps()
  1587  	c.Check(essSnaps, HasLen, 4)
  1588  
  1589  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1590  		{
  1591  			Path:          s.expectedPath("snapd"),
  1592  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1593  			EssentialType: snap.TypeSnapd,
  1594  			Essential:     true,
  1595  			Required:      true,
  1596  			Channel:       "latest/stable",
  1597  		}, {
  1598  			Path:          s.expectedPath("pc-kernel"),
  1599  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1600  			EssentialType: snap.TypeKernel,
  1601  			Essential:     true,
  1602  			Required:      true,
  1603  			Channel:       "20",
  1604  		}, {
  1605  			Path:          s.expectedPath("core20"),
  1606  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1607  			EssentialType: snap.TypeBase,
  1608  			Essential:     true,
  1609  			Required:      true,
  1610  			Channel:       "latest/stable",
  1611  		}, {
  1612  			Path:          s.expectedPath("pc"),
  1613  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1614  			EssentialType: snap.TypeGadget,
  1615  			Essential:     true,
  1616  			Required:      true,
  1617  			Channel:       "20",
  1618  		},
  1619  	})
  1620  
  1621  	runSnaps, err := seed20.ModeSnaps("run")
  1622  	c.Assert(err, IsNil)
  1623  	c.Check(runSnaps, HasLen, 1)
  1624  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1625  		{
  1626  			Path:     s.expectedPath("optional20-b"),
  1627  			SideInfo: &s.AssertedSnapInfo("optional20-b").SideInfo,
  1628  			Required: false,
  1629  			Channel:  "latest/stable",
  1630  		},
  1631  	})
  1632  }
  1633  
  1634  func (s *seed20Suite) TestLoadMetaCore20OptionalSnapsLocal(c *C) {
  1635  	s.makeSnap(c, "snapd", "")
  1636  	s.makeSnap(c, "core20", "")
  1637  	s.makeSnap(c, "pc-kernel=20", "")
  1638  	s.makeSnap(c, "pc=20", "")
  1639  	s.makeSnap(c, "optional20-a", "developerid")
  1640  	optional20bFn := s.makeLocalSnap(c, "optional20-b")
  1641  
  1642  	sysLabel := "20191122"
  1643  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1644  		"display-name": "my model",
  1645  		"architecture": "amd64",
  1646  		"base":         "core20",
  1647  		"grade":        "dangerous",
  1648  		"snaps": []interface{}{
  1649  			map[string]interface{}{
  1650  				"name":            "pc-kernel",
  1651  				"id":              s.AssertedSnapID("pc-kernel"),
  1652  				"type":            "kernel",
  1653  				"default-channel": "20",
  1654  			},
  1655  			map[string]interface{}{
  1656  				"name":            "pc",
  1657  				"id":              s.AssertedSnapID("pc"),
  1658  				"type":            "gadget",
  1659  				"default-channel": "20",
  1660  			},
  1661  			map[string]interface{}{
  1662  				"name":     "optional20-a",
  1663  				"id":       s.AssertedSnapID("optional20-a"),
  1664  				"presence": "optional",
  1665  			},
  1666  			map[string]interface{}{
  1667  				"name":     "optional20-b",
  1668  				"id":       s.AssertedSnapID("optional20-b"),
  1669  				"presence": "optional",
  1670  			}},
  1671  	}, []*seedwriter.OptionsSnap{
  1672  		{Path: optional20bFn},
  1673  	})
  1674  
  1675  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1676  	c.Assert(err, IsNil)
  1677  
  1678  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1679  	c.Assert(err, IsNil)
  1680  
  1681  	err = seed20.LoadMeta(s.perfTimings)
  1682  	c.Assert(err, IsNil)
  1683  
  1684  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1685  
  1686  	essSnaps := seed20.EssentialSnaps()
  1687  	c.Check(essSnaps, HasLen, 4)
  1688  
  1689  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1690  		{
  1691  			Path:          s.expectedPath("snapd"),
  1692  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1693  			EssentialType: snap.TypeSnapd,
  1694  			Essential:     true,
  1695  			Required:      true,
  1696  			Channel:       "latest/stable",
  1697  		}, {
  1698  			Path:          s.expectedPath("pc-kernel"),
  1699  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1700  			EssentialType: snap.TypeKernel,
  1701  			Essential:     true,
  1702  			Required:      true,
  1703  			Channel:       "20",
  1704  		}, {
  1705  			Path:          s.expectedPath("core20"),
  1706  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1707  			EssentialType: snap.TypeBase,
  1708  			Essential:     true,
  1709  			Required:      true,
  1710  			Channel:       "latest/stable",
  1711  		}, {
  1712  			Path:          s.expectedPath("pc"),
  1713  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1714  			EssentialType: snap.TypeGadget,
  1715  			Essential:     true,
  1716  			Required:      true,
  1717  			Channel:       "20",
  1718  		},
  1719  	})
  1720  
  1721  	runSnaps, err := seed20.ModeSnaps("run")
  1722  	c.Assert(err, IsNil)
  1723  	c.Check(runSnaps, HasLen, 1)
  1724  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1725  		{
  1726  			Path:     filepath.Join(s.SeedDir, "systems", sysLabel, "snaps", "optional20-b_1.0.snap"),
  1727  			SideInfo: &snap.SideInfo{RealName: "optional20-b"},
  1728  
  1729  			Required: false,
  1730  		},
  1731  	})
  1732  }
  1733  
  1734  func (s *seed20Suite) TestLoadMetaCore20ExtraSnaps(c *C) {
  1735  	s.makeSnap(c, "snapd", "")
  1736  	s.makeSnap(c, "core20", "")
  1737  	s.makeSnap(c, "pc-kernel=20", "")
  1738  	s.makeSnap(c, "pc=20", "")
  1739  	s.makeSnap(c, "core18", "")
  1740  	s.makeSnap(c, "cont-producer", "developerid")
  1741  	contConsumerFn := s.makeLocalSnap(c, "cont-consumer")
  1742  
  1743  	sysLabel := "20191122"
  1744  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1745  		"display-name": "my model",
  1746  		"architecture": "amd64",
  1747  		"base":         "core20",
  1748  		"grade":        "dangerous",
  1749  		"snaps": []interface{}{
  1750  			map[string]interface{}{
  1751  				"name":            "pc-kernel",
  1752  				"id":              s.AssertedSnapID("pc-kernel"),
  1753  				"type":            "kernel",
  1754  				"default-channel": "20",
  1755  			},
  1756  			map[string]interface{}{
  1757  				"name":            "pc",
  1758  				"id":              s.AssertedSnapID("pc"),
  1759  				"type":            "gadget",
  1760  				"default-channel": "20",
  1761  			}},
  1762  	}, []*seedwriter.OptionsSnap{
  1763  		{Name: "cont-producer", Channel: "edge"},
  1764  		{Name: "core18"},
  1765  		{Path: contConsumerFn},
  1766  	})
  1767  
  1768  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1769  	c.Assert(err, IsNil)
  1770  
  1771  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1772  	c.Assert(err, IsNil)
  1773  
  1774  	err = seed20.LoadMeta(s.perfTimings)
  1775  	c.Assert(err, IsNil)
  1776  
  1777  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1778  
  1779  	essSnaps := seed20.EssentialSnaps()
  1780  	c.Check(essSnaps, HasLen, 4)
  1781  
  1782  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1783  		{
  1784  			Path:          s.expectedPath("snapd"),
  1785  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1786  			EssentialType: snap.TypeSnapd,
  1787  			Essential:     true,
  1788  			Required:      true,
  1789  			Channel:       "latest/stable",
  1790  		}, {
  1791  			Path:          s.expectedPath("pc-kernel"),
  1792  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1793  			EssentialType: snap.TypeKernel,
  1794  			Essential:     true,
  1795  			Required:      true,
  1796  			Channel:       "20",
  1797  		}, {
  1798  			Path:          s.expectedPath("core20"),
  1799  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1800  			EssentialType: snap.TypeBase,
  1801  			Essential:     true,
  1802  			Required:      true,
  1803  			Channel:       "latest/stable",
  1804  		}, {
  1805  			Path:          s.expectedPath("pc"),
  1806  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1807  			EssentialType: snap.TypeGadget,
  1808  			Essential:     true,
  1809  			Required:      true,
  1810  			Channel:       "20",
  1811  		},
  1812  	})
  1813  
  1814  	sysSnapsDir := filepath.Join(s.SeedDir, "systems", sysLabel, "snaps")
  1815  
  1816  	runSnaps, err := seed20.ModeSnaps("run")
  1817  	c.Assert(err, IsNil)
  1818  	c.Check(runSnaps, HasLen, 3)
  1819  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1820  		{
  1821  			Path:     filepath.Join(sysSnapsDir, "cont-producer_1.snap"),
  1822  			SideInfo: &s.AssertedSnapInfo("cont-producer").SideInfo,
  1823  			Channel:  "latest/edge",
  1824  		},
  1825  		{
  1826  			Path:     filepath.Join(sysSnapsDir, "core18_1.snap"),
  1827  			SideInfo: &s.AssertedSnapInfo("core18").SideInfo,
  1828  			Channel:  "latest/stable",
  1829  		},
  1830  		{
  1831  			Path:     filepath.Join(sysSnapsDir, "cont-consumer_1.0.snap"),
  1832  			SideInfo: &snap.SideInfo{RealName: "cont-consumer"},
  1833  		},
  1834  	})
  1835  
  1836  	recoverSnaps, err := seed20.ModeSnaps("recover")
  1837  	c.Assert(err, IsNil)
  1838  	c.Check(recoverSnaps, HasLen, 0)
  1839  }
  1840  
  1841  func (s *seed20Suite) TestLoadMetaCore20NotRunSnaps(c *C) {
  1842  	s.makeSnap(c, "snapd", "")
  1843  	s.makeSnap(c, "core20", "")
  1844  	s.makeSnap(c, "pc-kernel=20", "")
  1845  	s.makeSnap(c, "pc=20", "")
  1846  	s.makeSnap(c, "required20", "developerid")
  1847  	s.makeSnap(c, "optional20-a", "developerid")
  1848  	s.makeSnap(c, "optional20-b", "developerid")
  1849  
  1850  	sysLabel := "20191122"
  1851  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  1852  		"display-name": "my model",
  1853  		"architecture": "amd64",
  1854  		"base":         "core20",
  1855  		"grade":        "signed",
  1856  		"snaps": []interface{}{
  1857  			map[string]interface{}{
  1858  				"name":            "pc-kernel",
  1859  				"id":              s.AssertedSnapID("pc-kernel"),
  1860  				"type":            "kernel",
  1861  				"default-channel": "20",
  1862  			},
  1863  			map[string]interface{}{
  1864  				"name":            "pc",
  1865  				"id":              s.AssertedSnapID("pc"),
  1866  				"type":            "gadget",
  1867  				"default-channel": "20",
  1868  			},
  1869  			map[string]interface{}{
  1870  				"name":  "required20",
  1871  				"id":    s.AssertedSnapID("required20"),
  1872  				"modes": []interface{}{"run", "ephemeral"},
  1873  			},
  1874  			map[string]interface{}{
  1875  				"name":     "optional20-a",
  1876  				"id":       s.AssertedSnapID("optional20-a"),
  1877  				"presence": "optional",
  1878  				"modes":    []interface{}{"ephemeral"},
  1879  			},
  1880  			map[string]interface{}{
  1881  				"name":     "optional20-b",
  1882  				"id":       s.AssertedSnapID("optional20-b"),
  1883  				"presence": "optional",
  1884  				"modes":    []interface{}{"install"},
  1885  			}},
  1886  	}, []*seedwriter.OptionsSnap{
  1887  		{Name: "optional20-a"},
  1888  		{Name: "optional20-b"},
  1889  	})
  1890  
  1891  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  1892  	c.Assert(err, IsNil)
  1893  
  1894  	err = seed20.LoadAssertions(s.db, s.commitTo)
  1895  	c.Assert(err, IsNil)
  1896  
  1897  	err = seed20.LoadMeta(s.perfTimings)
  1898  	c.Assert(err, IsNil)
  1899  
  1900  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  1901  
  1902  	essSnaps := seed20.EssentialSnaps()
  1903  	c.Check(essSnaps, HasLen, 4)
  1904  
  1905  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  1906  		{
  1907  			Path:          s.expectedPath("snapd"),
  1908  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  1909  			EssentialType: snap.TypeSnapd,
  1910  			Essential:     true,
  1911  			Required:      true,
  1912  			Channel:       "latest/stable",
  1913  		}, {
  1914  			Path:          s.expectedPath("pc-kernel"),
  1915  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  1916  			EssentialType: snap.TypeKernel,
  1917  			Essential:     true,
  1918  			Required:      true,
  1919  			Channel:       "20",
  1920  		}, {
  1921  			Path:          s.expectedPath("core20"),
  1922  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  1923  			EssentialType: snap.TypeBase,
  1924  			Essential:     true,
  1925  			Required:      true,
  1926  			Channel:       "latest/stable",
  1927  		}, {
  1928  			Path:          s.expectedPath("pc"),
  1929  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  1930  			EssentialType: snap.TypeGadget,
  1931  			Essential:     true,
  1932  			Required:      true,
  1933  			Channel:       "20",
  1934  		},
  1935  	})
  1936  
  1937  	runSnaps, err := seed20.ModeSnaps("run")
  1938  	c.Assert(err, IsNil)
  1939  	c.Check(runSnaps, HasLen, 1)
  1940  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  1941  		{
  1942  			Path:     s.expectedPath("required20"),
  1943  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1944  			Required: true,
  1945  			Channel:  "latest/stable",
  1946  		},
  1947  	})
  1948  
  1949  	installSnaps, err := seed20.ModeSnaps("install")
  1950  	c.Assert(err, IsNil)
  1951  	c.Check(installSnaps, HasLen, 3)
  1952  	c.Check(installSnaps, DeepEquals, []*seed.Snap{
  1953  		{
  1954  			Path:     s.expectedPath("required20"),
  1955  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1956  			Required: true,
  1957  			Channel:  "latest/stable",
  1958  		},
  1959  		{
  1960  			Path:     s.expectedPath("optional20-a"),
  1961  			SideInfo: &s.AssertedSnapInfo("optional20-a").SideInfo,
  1962  			Required: false,
  1963  			Channel:  "latest/stable",
  1964  		},
  1965  		{
  1966  			Path:     s.expectedPath("optional20-b"),
  1967  			SideInfo: &s.AssertedSnapInfo("optional20-b").SideInfo,
  1968  			Required: false,
  1969  			Channel:  "latest/stable",
  1970  		},
  1971  	})
  1972  
  1973  	recoverSnaps, err := seed20.ModeSnaps("recover")
  1974  	c.Assert(err, IsNil)
  1975  	c.Check(recoverSnaps, HasLen, 2)
  1976  	c.Check(recoverSnaps, DeepEquals, []*seed.Snap{
  1977  		{
  1978  			Path:     s.expectedPath("required20"),
  1979  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  1980  			Required: true,
  1981  			Channel:  "latest/stable",
  1982  		},
  1983  		{
  1984  			Path:     s.expectedPath("optional20-a"),
  1985  			SideInfo: &s.AssertedSnapInfo("optional20-a").SideInfo,
  1986  			Required: false,
  1987  			Channel:  "latest/stable",
  1988  		},
  1989  	})
  1990  }
  1991  
  1992  func (s *seed20Suite) TestLoadMetaCore20LocalAssertedSnaps(c *C) {
  1993  	s.makeSnap(c, "snapd", "")
  1994  	s.makeSnap(c, "core20", "")
  1995  	s.makeSnap(c, "pc-kernel=20", "")
  1996  	s.makeSnap(c, "pc=20", "")
  1997  	s.makeSnap(c, "required20", "developerid")
  1998  
  1999  	sysLabel := "20191209"
  2000  	s.MakeSeed(c, sysLabel, "my-brand", "my-model", map[string]interface{}{
  2001  		"display-name": "my model",
  2002  		"architecture": "amd64",
  2003  		"base":         "core20",
  2004  		"grade":        "dangerous",
  2005  		"snaps": []interface{}{
  2006  			map[string]interface{}{
  2007  				"name":            "pc-kernel",
  2008  				"id":              s.AssertedSnapID("pc-kernel"),
  2009  				"type":            "kernel",
  2010  				"default-channel": "20",
  2011  			},
  2012  			map[string]interface{}{
  2013  				"name":            "pc",
  2014  				"id":              s.AssertedSnapID("pc"),
  2015  				"type":            "gadget",
  2016  				"default-channel": "20",
  2017  			}},
  2018  	}, []*seedwriter.OptionsSnap{
  2019  		{Path: s.AssertedSnap("pc"), Channel: "edge"},
  2020  		{Path: s.AssertedSnap("required20")},
  2021  	})
  2022  
  2023  	seed20, err := seed.Open(s.SeedDir, sysLabel)
  2024  	c.Assert(err, IsNil)
  2025  
  2026  	err = seed20.LoadAssertions(s.db, s.commitTo)
  2027  	c.Assert(err, IsNil)
  2028  
  2029  	err = seed20.LoadMeta(s.perfTimings)
  2030  	c.Assert(err, IsNil)
  2031  
  2032  	c.Check(seed20.UsesSnapdSnap(), Equals, true)
  2033  
  2034  	essSnaps := seed20.EssentialSnaps()
  2035  	c.Check(essSnaps, HasLen, 4)
  2036  
  2037  	c.Check(essSnaps, DeepEquals, []*seed.Snap{
  2038  		{
  2039  			Path:          s.expectedPath("snapd"),
  2040  			SideInfo:      &s.AssertedSnapInfo("snapd").SideInfo,
  2041  			EssentialType: snap.TypeSnapd,
  2042  			Essential:     true,
  2043  			Required:      true,
  2044  			Channel:       "latest/stable",
  2045  		}, {
  2046  			Path:          s.expectedPath("pc-kernel"),
  2047  			SideInfo:      &s.AssertedSnapInfo("pc-kernel").SideInfo,
  2048  			EssentialType: snap.TypeKernel,
  2049  			Essential:     true,
  2050  			Required:      true,
  2051  			Channel:       "20",
  2052  		}, {
  2053  			Path:          s.expectedPath("core20"),
  2054  			SideInfo:      &s.AssertedSnapInfo("core20").SideInfo,
  2055  			EssentialType: snap.TypeBase,
  2056  			Essential:     true,
  2057  			Required:      true,
  2058  			Channel:       "latest/stable",
  2059  		}, {
  2060  			Path:          s.expectedPath("pc"),
  2061  			SideInfo:      &s.AssertedSnapInfo("pc").SideInfo,
  2062  			EssentialType: snap.TypeGadget,
  2063  			Essential:     true,
  2064  			Required:      true,
  2065  			Channel:       "20/edge",
  2066  		},
  2067  	})
  2068  
  2069  	sysSnapsDir := filepath.Join(s.SeedDir, "systems", sysLabel, "snaps")
  2070  
  2071  	runSnaps, err := seed20.ModeSnaps("run")
  2072  	c.Assert(err, IsNil)
  2073  	c.Check(runSnaps, HasLen, 1)
  2074  	c.Check(runSnaps, DeepEquals, []*seed.Snap{
  2075  		{
  2076  			Path:     filepath.Join(sysSnapsDir, "required20_1.snap"),
  2077  			SideInfo: &s.AssertedSnapInfo("required20").SideInfo,
  2078  			Channel:  "latest/stable",
  2079  		},
  2080  	})
  2081  }
  2082  
  2083  func (s *seed20Suite) TestOpenInvalidLabel(c *C) {
  2084  	invalid := []string{
  2085  		// empty string not included, as it's not a UC20 seed
  2086  		"/bin",
  2087  		"../../bin/bar",
  2088  		":invalid:",
  2089  		"日本語",
  2090  	}
  2091  	for _, label := range invalid {
  2092  		seed20, err := seed.Open(s.SeedDir, label)
  2093  		c.Assert(err, ErrorMatches, fmt.Sprintf("invalid seed system label: %q", label))
  2094  		c.Assert(seed20, IsNil)
  2095  	}
  2096  }