gitee.com/mysnapcore/mysnapd@v0.1.0/bootloader/bootloadertest/bootloadertest.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-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 bootloadertest
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  
    26  	"gitee.com/mysnapcore/mysnapd/bootloader"
    27  	"gitee.com/mysnapcore/mysnapd/snap"
    28  )
    29  
    30  // MockBootloader mocks the bootloader interface and records all
    31  // set/get calls.
    32  type MockBootloader struct {
    33  	MockedPresent bool
    34  	PresentErr    error
    35  
    36  	BootVars         map[string]string
    37  	SetBootVarsCalls int
    38  	SetErr           error
    39  	SetErrFunc       func() error
    40  	GetErr           error
    41  
    42  	name    string
    43  	bootdir string
    44  
    45  	ExtractKernelAssetsCalls []snap.PlaceInfo
    46  	RemoveKernelAssetsCalls  []snap.PlaceInfo
    47  
    48  	InstallBootConfigCalled []string
    49  	InstallBootConfigErr    error
    50  
    51  	enabledKernel    snap.PlaceInfo
    52  	enabledTryKernel snap.PlaceInfo
    53  
    54  	panicMethods map[string]bool
    55  }
    56  
    57  // ensure MockBootloader(s) implement the Bootloader interface
    58  var _ bootloader.Bootloader = (*MockBootloader)(nil)
    59  var _ bootloader.RecoveryAwareBootloader = (*MockRecoveryAwareBootloader)(nil)
    60  var _ bootloader.TrustedAssetsBootloader = (*MockTrustedAssetsBootloader)(nil)
    61  var _ bootloader.ExtractedRunKernelImageBootloader = (*MockExtractedRunKernelImageBootloader)(nil)
    62  var _ bootloader.ExtractedRecoveryKernelImageBootloader = (*MockExtractedRecoveryKernelImageBootloader)(nil)
    63  var _ bootloader.RecoveryAwareBootloader = (*MockRecoveryAwareTrustedAssetsBootloader)(nil)
    64  var _ bootloader.TrustedAssetsBootloader = (*MockRecoveryAwareTrustedAssetsBootloader)(nil)
    65  var _ bootloader.NotScriptableBootloader = (*MockNotScriptableBootloader)(nil)
    66  var _ bootloader.NotScriptableBootloader = (*MockExtractedRecoveryKernelNotScriptableBootloader)(nil)
    67  var _ bootloader.ExtractedRecoveryKernelImageBootloader = (*MockExtractedRecoveryKernelNotScriptableBootloader)(nil)
    68  var _ bootloader.RebootBootloader = (*MockRebootBootloader)(nil)
    69  
    70  func Mock(name, bootdir string) *MockBootloader {
    71  	return &MockBootloader{
    72  		name:    name,
    73  		bootdir: bootdir,
    74  
    75  		BootVars: make(map[string]string),
    76  
    77  		panicMethods: make(map[string]bool),
    78  	}
    79  }
    80  
    81  func (b *MockBootloader) maybePanic(which string) {
    82  	if b.panicMethods[which] {
    83  		panic(fmt.Sprintf("mocked reboot panic in %s", which))
    84  	}
    85  }
    86  
    87  func (b *MockBootloader) SetBootVars(values map[string]string) error {
    88  	b.maybePanic("SetBootVars")
    89  	b.SetBootVarsCalls++
    90  	for k, v := range values {
    91  		b.BootVars[k] = v
    92  	}
    93  	if b.SetErrFunc != nil {
    94  		return b.SetErrFunc()
    95  	}
    96  	return b.SetErr
    97  }
    98  
    99  func (b *MockBootloader) GetBootVars(keys ...string) (map[string]string, error) {
   100  	b.maybePanic("GetBootVars")
   101  
   102  	out := map[string]string{}
   103  	for _, k := range keys {
   104  		out[k] = b.BootVars[k]
   105  	}
   106  
   107  	return out, b.GetErr
   108  }
   109  
   110  func (b *MockBootloader) Name() string {
   111  	return b.name
   112  }
   113  
   114  func (b *MockBootloader) Present() (bool, error) {
   115  	return b.MockedPresent, b.PresentErr
   116  }
   117  
   118  func (b *MockBootloader) ExtractKernelAssets(s snap.PlaceInfo, snapf snap.Container) error {
   119  	b.ExtractKernelAssetsCalls = append(b.ExtractKernelAssetsCalls, s)
   120  	return nil
   121  }
   122  
   123  func (b *MockBootloader) RemoveKernelAssets(s snap.PlaceInfo) error {
   124  	b.RemoveKernelAssetsCalls = append(b.RemoveKernelAssetsCalls, s)
   125  	return nil
   126  }
   127  
   128  func (b *MockBootloader) SetEnabledKernel(s snap.PlaceInfo) (restore func()) {
   129  	oldSn := b.enabledTryKernel
   130  	oldVar := b.BootVars["snap_kernel"]
   131  	b.enabledKernel = s
   132  	b.BootVars["snap_kernel"] = s.Filename()
   133  	return func() {
   134  		b.BootVars["snap_kernel"] = oldVar
   135  		b.enabledKernel = oldSn
   136  	}
   137  }
   138  
   139  func (b *MockBootloader) SetEnabledTryKernel(s snap.PlaceInfo) (restore func()) {
   140  	oldSn := b.enabledTryKernel
   141  	oldVar := b.BootVars["snap_try_kernel"]
   142  	b.enabledTryKernel = s
   143  	b.BootVars["snap_try_kernel"] = s.Filename()
   144  	return func() {
   145  		b.BootVars["snap_try_kernel"] = oldVar
   146  		b.enabledTryKernel = oldSn
   147  	}
   148  }
   149  
   150  // InstallBootConfig installs the boot config in the gadget directory to the
   151  // mock bootloader's root directory.
   152  func (b *MockBootloader) InstallBootConfig(gadgetDir string, opts *bootloader.Options) error {
   153  	b.InstallBootConfigCalled = append(b.InstallBootConfigCalled, gadgetDir)
   154  	return b.InstallBootConfigErr
   155  }
   156  
   157  // SetMockToPanic allows setting any method in the Bootloader interface or derived
   158  // interface to panic instead of returning. This allows one to test what would
   159  // happen if the system was rebooted during execution of a particular function.
   160  // Specifically, the panic will be done immediately entering the function so
   161  // setting SetBootVars to panic will emulate a reboot before any boot vars are
   162  // set persistently
   163  func (b *MockBootloader) SetMockToPanic(f string) (restore func()) {
   164  	switch f {
   165  	// XXX: update this list as more calls in this interface or derived ones
   166  	// are added
   167  	case "SetBootVars", "GetBootVars",
   168  		"EnableKernel", "EnableTryKernel", "Kernel", "TryKernel", "DisableTryKernel":
   169  
   170  		old := b.panicMethods[f]
   171  		b.panicMethods[f] = true
   172  		return func() {
   173  			b.panicMethods[f] = old
   174  		}
   175  	default:
   176  		panic(fmt.Sprintf("unknown bootloader method %q to mock reboot via panic for", f))
   177  	}
   178  }
   179  
   180  // MockRecoveryAwareMixin implements the RecoveryAware interface.
   181  type MockRecoveryAwareMixin struct {
   182  	RecoverySystemDir      string
   183  	RecoverySystemBootVars map[string]string
   184  }
   185  
   186  // MockRecoveryAwareBootloader mocks a bootloader implementing the
   187  // RecoveryAware interface.
   188  type MockRecoveryAwareBootloader struct {
   189  	*MockBootloader
   190  	MockRecoveryAwareMixin
   191  }
   192  
   193  // RecoveryAware derives a MockRecoveryAwareBootloader from a base
   194  // MockBootloader.
   195  func (b *MockBootloader) RecoveryAware() *MockRecoveryAwareBootloader {
   196  	return &MockRecoveryAwareBootloader{MockBootloader: b}
   197  }
   198  
   199  // SetRecoverySystemEnv sets the recovery system environment bootloader
   200  // variables; part of RecoveryAwareBootloader.
   201  func (b *MockRecoveryAwareMixin) SetRecoverySystemEnv(recoverySystemDir string, blVars map[string]string) error {
   202  	if recoverySystemDir == "" {
   203  		panic("MockBootloader.SetRecoverySystemEnv called without recoverySystemDir")
   204  	}
   205  	b.RecoverySystemDir = recoverySystemDir
   206  	b.RecoverySystemBootVars = blVars
   207  	return nil
   208  }
   209  
   210  // GetRecoverySystemEnv gets the recovery system environment bootloader
   211  // variables; part of RecoveryAwareBootloader.
   212  func (b *MockRecoveryAwareMixin) GetRecoverySystemEnv(recoverySystemDir, key string) (string, error) {
   213  	if recoverySystemDir == "" {
   214  		panic("MockBootloader.GetRecoverySystemEnv called without recoverySystemDir")
   215  	}
   216  	b.RecoverySystemDir = recoverySystemDir
   217  	return b.RecoverySystemBootVars[key], nil
   218  }
   219  
   220  type ExtractedRecoveryKernelCall struct {
   221  	RecoverySystemDir string
   222  	S                 snap.PlaceInfo
   223  }
   224  
   225  // MockExtractedRecoveryKernelImageBootloader mocks a bootloader implementing
   226  // the ExtractedRecoveryKernelImage interface.
   227  type MockExtractedRecoveryKernelImageBootloader struct {
   228  	*MockBootloader
   229  
   230  	ExtractRecoveryKernelAssetsCalls []ExtractedRecoveryKernelCall
   231  }
   232  
   233  // ExtractedRecoveryKernelImage derives a MockRecoveryAwareBootloader from a base
   234  // MockBootloader.
   235  func (b *MockBootloader) ExtractedRecoveryKernelImage() *MockExtractedRecoveryKernelImageBootloader {
   236  	return &MockExtractedRecoveryKernelImageBootloader{MockBootloader: b}
   237  }
   238  
   239  // ExtractRecoveryKernelAssets extracts the kernel assets for the provided
   240  // kernel snap into the specified recovery system dir; part of
   241  // RecoveryAwareBootloader.
   242  func (b *MockExtractedRecoveryKernelImageBootloader) ExtractRecoveryKernelAssets(recoverySystemDir string, s snap.PlaceInfo, snapf snap.Container) error {
   243  	if recoverySystemDir == "" {
   244  		panic("MockBootloader.ExtractRecoveryKernelAssets called without recoverySystemDir")
   245  	}
   246  
   247  	b.ExtractRecoveryKernelAssetsCalls = append(
   248  		b.ExtractRecoveryKernelAssetsCalls,
   249  		ExtractedRecoveryKernelCall{
   250  			S:                 s,
   251  			RecoverySystemDir: recoverySystemDir},
   252  	)
   253  	return nil
   254  }
   255  
   256  // MockExtractedRunKernelImageMixin implements the
   257  // ExtractedRunKernelImageBootloader interface.
   258  type MockExtractedRunKernelImageMixin struct {
   259  	runKernelImageEnableKernelCalls    []snap.PlaceInfo
   260  	runKernelImageEnableTryKernelCalls []snap.PlaceInfo
   261  	runKernelImageEnabledKernel        snap.PlaceInfo
   262  	runKernelImageEnabledTryKernel     snap.PlaceInfo
   263  
   264  	runKernelImageMockedErrs     map[string]error
   265  	runKernelImageMockedNumCalls map[string]int
   266  
   267  	maybePanic func(name string)
   268  }
   269  
   270  // MockExtractedRunKernelImageBootloader mocks a bootloader
   271  // implementing the ExtractedRunKernelImageBootloader interface.
   272  type MockExtractedRunKernelImageBootloader struct {
   273  	*MockBootloader
   274  
   275  	MockExtractedRunKernelImageMixin
   276  }
   277  
   278  func (b *MockExtractedRunKernelImageBootloader) SetEnabledKernel(kernel snap.PlaceInfo) (restore func()) {
   279  	// pick the right implementation
   280  	return b.MockExtractedRunKernelImageMixin.SetEnabledKernel(kernel)
   281  }
   282  
   283  func (b *MockExtractedRunKernelImageBootloader) SetEnabledTryKernel(kernel snap.PlaceInfo) (restore func()) {
   284  	// pick the right implementation
   285  	return b.MockExtractedRunKernelImageMixin.SetEnabledTryKernel(kernel)
   286  }
   287  
   288  // WithExtractedRunKernelImage derives a MockExtractedRunKernelImageBootloader
   289  // from a base MockBootloader.
   290  func (b *MockBootloader) WithExtractedRunKernelImage() *MockExtractedRunKernelImageBootloader {
   291  	return &MockExtractedRunKernelImageBootloader{
   292  		MockBootloader: b,
   293  
   294  		MockExtractedRunKernelImageMixin: MockExtractedRunKernelImageMixin{
   295  			runKernelImageMockedErrs:     make(map[string]error),
   296  			runKernelImageMockedNumCalls: make(map[string]int),
   297  			maybePanic:                   b.maybePanic,
   298  		},
   299  	}
   300  }
   301  
   302  // SetEnabledKernel sets the current kernel "symlink" as returned
   303  // by Kernel(); returns' a restore function to set it back to what it was
   304  // before.
   305  func (b *MockExtractedRunKernelImageMixin) SetEnabledKernel(kernel snap.PlaceInfo) (restore func()) {
   306  	old := b.runKernelImageEnabledKernel
   307  	b.runKernelImageEnabledKernel = kernel
   308  	return func() {
   309  		b.runKernelImageEnabledKernel = old
   310  	}
   311  }
   312  
   313  // SetEnabledTryKernel sets the current try-kernel "symlink" as
   314  // returned by TryKernel(). If set to nil, TryKernel()'s second return value
   315  // will be false; returns' a restore function to set it back to what it was
   316  // before.
   317  func (b *MockExtractedRunKernelImageMixin) SetEnabledTryKernel(kernel snap.PlaceInfo) (restore func()) {
   318  	old := b.runKernelImageEnabledTryKernel
   319  	b.runKernelImageEnabledTryKernel = kernel
   320  	return func() {
   321  		b.runKernelImageEnabledTryKernel = old
   322  	}
   323  }
   324  
   325  // SetRunKernelImageFunctionError allows setting an error to be returned for the
   326  // specified function; it returns a restore function to set it back to what it
   327  // was before.
   328  func (b *MockExtractedRunKernelImageMixin) SetRunKernelImageFunctionError(f string, err error) (restore func()) {
   329  	// check the function
   330  	switch f {
   331  	case "EnableKernel", "EnableTryKernel", "Kernel", "TryKernel", "DisableTryKernel":
   332  		old := b.runKernelImageMockedErrs[f]
   333  		b.runKernelImageMockedErrs[f] = err
   334  		return func() {
   335  			b.runKernelImageMockedErrs[f] = old
   336  		}
   337  	default:
   338  		panic(fmt.Sprintf("unknown ExtractedRunKernelImageBootloader method %q to mock error for", f))
   339  	}
   340  }
   341  
   342  // GetRunKernelImageFunctionSnapCalls returns which snaps were specified during
   343  // execution, in order of calls, as well as the number of calls for methods that
   344  // don't take a snap to set.
   345  func (b *MockExtractedRunKernelImageMixin) GetRunKernelImageFunctionSnapCalls(f string) ([]snap.PlaceInfo, int) {
   346  	switch f {
   347  	case "EnableKernel":
   348  		l := b.runKernelImageEnableKernelCalls
   349  		return l, len(l)
   350  	case "EnableTryKernel":
   351  		l := b.runKernelImageEnableTryKernelCalls
   352  		return l, len(l)
   353  	case "Kernel", "TryKernel", "DisableTryKernel":
   354  		return nil, b.runKernelImageMockedNumCalls[f]
   355  	default:
   356  		panic(fmt.Sprintf("unknown ExtractedRunKernelImageBootloader method %q to return snap args for", f))
   357  	}
   358  }
   359  
   360  // EnableKernel enables the kernel; part of ExtractedRunKernelImageBootloader.
   361  func (b *MockExtractedRunKernelImageMixin) EnableKernel(s snap.PlaceInfo) error {
   362  	b.maybePanic("EnableKernel")
   363  	b.runKernelImageEnableKernelCalls = append(b.runKernelImageEnableKernelCalls, s)
   364  	b.runKernelImageEnabledKernel = s
   365  	return b.runKernelImageMockedErrs["EnableKernel"]
   366  }
   367  
   368  // EnableTryKernel enables a try-kernel; part of
   369  // ExtractedRunKernelImageBootloader.
   370  func (b *MockExtractedRunKernelImageMixin) EnableTryKernel(s snap.PlaceInfo) error {
   371  	b.maybePanic("EnableTryKernel")
   372  	b.runKernelImageEnableTryKernelCalls = append(b.runKernelImageEnableTryKernelCalls, s)
   373  	b.runKernelImageEnabledTryKernel = s
   374  	return b.runKernelImageMockedErrs["EnableTryKernel"]
   375  }
   376  
   377  // Kernel returns the current kernel set in the bootloader; part of
   378  // ExtractedRunKernelImageBootloader.
   379  func (b *MockExtractedRunKernelImageMixin) Kernel() (snap.PlaceInfo, error) {
   380  	b.maybePanic("Kernel")
   381  	b.runKernelImageMockedNumCalls["Kernel"]++
   382  	err := b.runKernelImageMockedErrs["Kernel"]
   383  	if err != nil {
   384  		return nil, err
   385  	}
   386  	return b.runKernelImageEnabledKernel, nil
   387  }
   388  
   389  // TryKernel returns the current kernel set in the bootloader; part of
   390  // ExtractedRunKernelImageBootloader.
   391  func (b *MockExtractedRunKernelImageMixin) TryKernel() (snap.PlaceInfo, error) {
   392  	b.maybePanic("TryKernel")
   393  	b.runKernelImageMockedNumCalls["TryKernel"]++
   394  	err := b.runKernelImageMockedErrs["TryKernel"]
   395  	if err != nil {
   396  		return nil, err
   397  	}
   398  	if b.runKernelImageEnabledTryKernel == nil {
   399  		return nil, bootloader.ErrNoTryKernelRef
   400  	}
   401  	return b.runKernelImageEnabledTryKernel, nil
   402  }
   403  
   404  // DisableTryKernel removes the current try-kernel "symlink" set in the
   405  // bootloader; part of ExtractedRunKernelImageBootloader.
   406  func (b *MockExtractedRunKernelImageMixin) DisableTryKernel() error {
   407  	b.maybePanic("DisableTryKernel")
   408  	b.runKernelImageMockedNumCalls["DisableTryKernel"]++
   409  	b.runKernelImageEnabledTryKernel = nil
   410  	return b.runKernelImageMockedErrs["DisableTryKernel"]
   411  }
   412  
   413  // MockTrustedAssetsMixin implements the bootloader.TrustedAssetsBootloader
   414  // interface.
   415  type MockTrustedAssetsMixin struct {
   416  	TrustedAssetsList  []string
   417  	TrustedAssetsErr   error
   418  	TrustedAssetsCalls int
   419  
   420  	RecoveryBootChainList []bootloader.BootFile
   421  	RecoveryBootChainErr  error
   422  	BootChainList         []bootloader.BootFile
   423  	BootChainErr          error
   424  
   425  	RecoveryBootChainCalls []string
   426  	BootChainRunBl         []bootloader.Bootloader
   427  	BootChainKernelPath    []string
   428  
   429  	UpdateErr                  error
   430  	UpdateCalls                int
   431  	Updated                    bool
   432  	ManagedAssetsList          []string
   433  	StaticCommandLine          string
   434  	CandidateStaticCommandLine string
   435  	CommandLineErr             error
   436  }
   437  
   438  // MockTrustedAssetsBootloader mocks a bootloader implementing the
   439  // bootloader.TrustedAssetsBootloader interface.
   440  type MockTrustedAssetsBootloader struct {
   441  	*MockBootloader
   442  
   443  	MockTrustedAssetsMixin
   444  }
   445  
   446  func (b *MockBootloader) WithTrustedAssets() *MockTrustedAssetsBootloader {
   447  	return &MockTrustedAssetsBootloader{
   448  		MockBootloader: b,
   449  	}
   450  }
   451  
   452  func (b *MockTrustedAssetsMixin) ManagedAssets() []string {
   453  	return b.ManagedAssetsList
   454  }
   455  
   456  func (b *MockTrustedAssetsMixin) UpdateBootConfig() (bool, error) {
   457  	b.UpdateCalls++
   458  	return b.Updated, b.UpdateErr
   459  }
   460  
   461  func glueCommandLine(pieces bootloader.CommandLineComponents, staticArgs string) (string, error) {
   462  	if err := pieces.Validate(); err != nil {
   463  		return "", err
   464  	}
   465  
   466  	args := []string(nil)
   467  	extraOrFull := []string{staticArgs, pieces.ExtraArgs}
   468  	if pieces.FullArgs != "" {
   469  		extraOrFull = []string{pieces.FullArgs}
   470  	}
   471  	for _, argSet := range append([]string{pieces.ModeArg, pieces.SystemArg}, extraOrFull...) {
   472  		if argSet != "" {
   473  			args = append(args, argSet)
   474  		}
   475  	}
   476  	line := strings.Join(args, " ")
   477  	return strings.TrimSpace(line), nil
   478  }
   479  
   480  func (b *MockTrustedAssetsMixin) CommandLine(pieces bootloader.CommandLineComponents) (string, error) {
   481  	if b.CommandLineErr != nil {
   482  		return "", b.CommandLineErr
   483  	}
   484  	return glueCommandLine(pieces, b.StaticCommandLine)
   485  }
   486  
   487  func (b *MockTrustedAssetsMixin) CandidateCommandLine(pieces bootloader.CommandLineComponents) (string, error) {
   488  	if b.CommandLineErr != nil {
   489  		return "", b.CommandLineErr
   490  	}
   491  	return glueCommandLine(pieces, b.CandidateStaticCommandLine)
   492  }
   493  
   494  func (b *MockTrustedAssetsMixin) TrustedAssets() ([]string, error) {
   495  	b.TrustedAssetsCalls++
   496  	return b.TrustedAssetsList, b.TrustedAssetsErr
   497  }
   498  
   499  func (b *MockTrustedAssetsMixin) RecoveryBootChain(kernelPath string) ([]bootloader.BootFile, error) {
   500  	b.RecoveryBootChainCalls = append(b.RecoveryBootChainCalls, kernelPath)
   501  	return b.RecoveryBootChainList, b.RecoveryBootChainErr
   502  }
   503  
   504  func (b *MockTrustedAssetsMixin) BootChain(runBl bootloader.Bootloader, kernelPath string) ([]bootloader.BootFile, error) {
   505  	b.BootChainRunBl = append(b.BootChainRunBl, runBl)
   506  	b.BootChainKernelPath = append(b.BootChainKernelPath, kernelPath)
   507  	return b.BootChainList, b.BootChainErr
   508  }
   509  
   510  // MockRecoveryAwareTrustedAssetsBootloader implements the
   511  // bootloader.RecoveryAwareBootloader and bootloader.TrustedAssetsBootloader
   512  // interfaces.
   513  type MockRecoveryAwareTrustedAssetsBootloader struct {
   514  	*MockBootloader
   515  
   516  	MockRecoveryAwareMixin
   517  	MockTrustedAssetsMixin
   518  }
   519  
   520  func (b *MockBootloader) WithRecoveryAwareTrustedAssets() *MockRecoveryAwareTrustedAssetsBootloader {
   521  	return &MockRecoveryAwareTrustedAssetsBootloader{
   522  		MockBootloader: b,
   523  	}
   524  }
   525  
   526  // MockNotScriptableBootloader implements the
   527  // bootloader.NotScriptableBootloader interface.
   528  type MockNotScriptableBootloader struct {
   529  	*MockBootloader
   530  }
   531  
   532  func (b *MockBootloader) WithNotScriptable() *MockNotScriptableBootloader {
   533  	return &MockNotScriptableBootloader{
   534  		MockBootloader: b,
   535  	}
   536  }
   537  
   538  func (b *MockNotScriptableBootloader) SetBootVarsFromInitramfs(values map[string]string) error {
   539  	for k, v := range values {
   540  		b.BootVars[k] = v
   541  	}
   542  	return nil
   543  }
   544  
   545  // MockExtractedRecoveryKernelNotScriptableBootloader implements the
   546  // bootloader.ExtractedRecoveryKernelImageBootloader interface and
   547  // includes MockNotScriptableBootloader
   548  type MockExtractedRecoveryKernelNotScriptableBootloader struct {
   549  	*MockNotScriptableBootloader
   550  
   551  	ExtractRecoveryKernelAssetsCalls []ExtractedRecoveryKernelCall
   552  }
   553  
   554  func (b *MockNotScriptableBootloader) WithExtractedRecoveryKernel() *MockExtractedRecoveryKernelNotScriptableBootloader {
   555  	return &MockExtractedRecoveryKernelNotScriptableBootloader{
   556  		MockNotScriptableBootloader: b,
   557  	}
   558  }
   559  
   560  // ExtractRecoveryKernelAssets extracts the kernel assets for the provided
   561  // kernel snap into the specified recovery system dir; part of
   562  // RecoveryAwareBootloader.
   563  func (b *MockExtractedRecoveryKernelNotScriptableBootloader) ExtractRecoveryKernelAssets(recoverySystemDir string, s snap.PlaceInfo, snapf snap.Container) error {
   564  	if recoverySystemDir == "" {
   565  		panic("MockBootloader.ExtractRecoveryKernelAssets called without recoverySystemDir")
   566  	}
   567  
   568  	b.ExtractRecoveryKernelAssetsCalls = append(
   569  		b.ExtractRecoveryKernelAssetsCalls,
   570  		ExtractedRecoveryKernelCall{
   571  			S:                 s,
   572  			RecoverySystemDir: recoverySystemDir},
   573  	)
   574  	return nil
   575  }
   576  
   577  // MockRebootBootloaderMixin implements the bootloader.RebootBootloader
   578  // interface.
   579  type MockRebootBootloaderMixin struct {
   580  	RebootArgs string
   581  }
   582  
   583  // MockRebootBootloader mocks a bootloader implementing the
   584  // bootloader.RebootBootloader interface.
   585  type MockRebootBootloader struct {
   586  	*MockBootloader
   587  
   588  	MockRebootBootloaderMixin
   589  }
   590  
   591  func (b *MockRebootBootloaderMixin) GetRebootArguments() (string, error) {
   592  	return b.RebootArgs, nil
   593  }
   594  
   595  func (b *MockBootloader) WithRebootBootloader() *MockRebootBootloader {
   596  	return &MockRebootBootloader{
   597  		MockBootloader: b,
   598  	}
   599  }