github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/configstate/configcore/corecfg_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 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 configcore_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"path/filepath"
    26  	"reflect"
    27  	"testing"
    28  
    29  	. "gopkg.in/check.v1"
    30  
    31  	"github.com/snapcore/snapd/dirs"
    32  	"github.com/snapcore/snapd/osutil"
    33  	"github.com/snapcore/snapd/overlord/configstate/config"
    34  	"github.com/snapcore/snapd/overlord/configstate/configcore"
    35  	"github.com/snapcore/snapd/overlord/state"
    36  	"github.com/snapcore/snapd/snap"
    37  	"github.com/snapcore/snapd/systemd"
    38  	"github.com/snapcore/snapd/testutil"
    39  )
    40  
    41  func Test(t *testing.T) { TestingT(t) }
    42  
    43  type mockConf struct {
    44  	state   *state.State
    45  	conf    map[string]interface{}
    46  	changes map[string]interface{}
    47  	err     error
    48  }
    49  
    50  func (cfg *mockConf) Get(snapName, key string, result interface{}) error {
    51  	if snapName != "core" {
    52  		return fmt.Errorf("mockConf only knows about core")
    53  	}
    54  
    55  	var value interface{}
    56  	value = cfg.changes[key]
    57  	if value == nil {
    58  		value = cfg.conf[key]
    59  	}
    60  	if value != nil {
    61  		v1 := reflect.ValueOf(result)
    62  		v2 := reflect.Indirect(v1)
    63  		v2.Set(reflect.ValueOf(value))
    64  	}
    65  	return cfg.err
    66  }
    67  
    68  func (cfg *mockConf) GetMaybe(snapName, key string, result interface{}) error {
    69  	err := cfg.Get(snapName, key, result)
    70  	if err != nil && !config.IsNoOption(err) {
    71  		return err
    72  	}
    73  	return nil
    74  }
    75  
    76  func (cfg *mockConf) GetPristine(snapName, key string, result interface{}) error {
    77  	if snapName != "core" {
    78  		return fmt.Errorf("mockConf only knows about core")
    79  	}
    80  
    81  	var value interface{}
    82  	value = cfg.conf[key]
    83  	if value != nil {
    84  		v1 := reflect.ValueOf(result)
    85  		v2 := reflect.Indirect(v1)
    86  		v2.Set(reflect.ValueOf(value))
    87  	}
    88  	return cfg.err
    89  }
    90  
    91  func (cfg *mockConf) GetPristineMaybe(snapName, key string, result interface{}) error {
    92  	err := cfg.GetPristine(snapName, key, result)
    93  	if err != nil && !config.IsNoOption(err) {
    94  		return err
    95  	}
    96  	return nil
    97  }
    98  
    99  func (cfg *mockConf) Set(snapName, key string, v interface{}) error {
   100  	if snapName != "core" {
   101  		return fmt.Errorf("mockConf only knows about core")
   102  	}
   103  	if cfg.conf == nil {
   104  		cfg.conf = make(map[string]interface{})
   105  	}
   106  	cfg.conf[key] = v
   107  	return nil
   108  }
   109  
   110  func (cfg *mockConf) Changes() []string {
   111  	out := make([]string, 0, len(cfg.changes))
   112  	for k := range cfg.changes {
   113  		out = append(out, "core."+k)
   114  	}
   115  	return out
   116  }
   117  
   118  func (cfg *mockConf) State() *state.State {
   119  	return cfg.state
   120  }
   121  
   122  // configcoreSuite is the base for all the configcore tests
   123  type configcoreSuite struct {
   124  	testutil.BaseTest
   125  
   126  	state *state.State
   127  
   128  	systemctlOutput   func(args ...string) []byte
   129  	systemctlArgs     [][]string
   130  	systemdSysctlArgs [][]string
   131  }
   132  
   133  var _ = Suite(&configcoreSuite{})
   134  
   135  func (s *configcoreSuite) SetUpTest(c *C) {
   136  	s.BaseTest.SetUpTest(c)
   137  
   138  	dirs.SetRootDir(c.MkDir())
   139  	s.AddCleanup(func() { dirs.SetRootDir("") })
   140  
   141  	s.systemctlOutput = func(args ...string) []byte {
   142  		return []byte("ActiveState=inactive")
   143  	}
   144  
   145  	s.AddCleanup(systemd.MockSystemctl(func(args ...string) ([]byte, error) {
   146  		s.systemctlArgs = append(s.systemctlArgs, args[:])
   147  		return s.systemctlOutput(args...), nil
   148  	}))
   149  	s.systemctlArgs = nil
   150  	s.AddCleanup(systemd.MockSystemdSysctl(func(args ...string) error {
   151  		s.systemdSysctlArgs = append(s.systemdSysctlArgs, args[:])
   152  		return nil
   153  	}))
   154  	s.systemdSysctlArgs = nil
   155  
   156  	s.state = state.New(nil)
   157  
   158  	restore := snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})
   159  	s.AddCleanup(restore)
   160  
   161  	// mock an empty cmdline since we check the cmdline to check whether we are
   162  	// in install mode or uc20 run mode, etc. and we don't want to use the
   163  	// host's proc/cmdline
   164  	mockCmdline := filepath.Join(dirs.GlobalRootDir, "cmdline")
   165  	err := ioutil.WriteFile(mockCmdline, nil, 0644)
   166  	c.Assert(err, IsNil)
   167  	restore = osutil.MockProcCmdline(mockCmdline)
   168  	s.AddCleanup(restore)
   169  }
   170  
   171  // runCfgSuite tests configcore.Run()
   172  type runCfgSuite struct {
   173  	configcoreSuite
   174  }
   175  
   176  var _ = Suite(&runCfgSuite{})
   177  
   178  func (r *runCfgSuite) TestConfigureUnknownOption(c *C) {
   179  	conf := &mockConf{
   180  		state: r.state,
   181  		changes: map[string]interface{}{
   182  			"unknown.option": "1",
   183  		},
   184  	}
   185  
   186  	err := configcore.Run(conf)
   187  	c.Check(err, ErrorMatches, `cannot set "core.unknown.option": unsupported system option`)
   188  }
   189  
   190  // applyCfgSuite tests configcore.Apply()
   191  type applyCfgSuite struct {
   192  	tmpDir string
   193  }
   194  
   195  var _ = Suite(&applyCfgSuite{})
   196  
   197  func (s *applyCfgSuite) SetUpTest(c *C) {
   198  	s.tmpDir = c.MkDir()
   199  	dirs.SetRootDir(s.tmpDir)
   200  }
   201  
   202  func (s *applyCfgSuite) TearDownTest(c *C) {
   203  	dirs.SetRootDir("")
   204  }
   205  
   206  func (s *applyCfgSuite) TestEmptyRootDir(c *C) {
   207  	err := configcore.FilesystemOnlyApply("", nil, nil)
   208  	c.Check(err, ErrorMatches, `internal error: root directory for configcore.FilesystemOnlyApply\(\) not set`)
   209  }
   210  
   211  func (s *applyCfgSuite) TestSmoke(c *C) {
   212  	c.Assert(configcore.FilesystemOnlyApply(s.tmpDir, map[string]interface{}{}, nil), IsNil)
   213  }
   214  
   215  func (s *applyCfgSuite) TestPlainCoreConfigGetErrorIfNotCore(c *C) {
   216  	conf := configcore.PlainCoreConfig(map[string]interface{}{})
   217  	var val interface{}
   218  	c.Assert(conf.Get("some-snap", "a", &val), ErrorMatches, `internal error: expected core snap in Get\(\), "some-snap" was requested`)
   219  }
   220  
   221  func (s *applyCfgSuite) TestPlainCoreConfigGet(c *C) {
   222  	conf := configcore.PlainCoreConfig(map[string]interface{}{"foo": "bar"})
   223  	var val interface{}
   224  	c.Assert(conf.Get("core", "a", &val), DeepEquals, &config.NoOptionError{SnapName: "core", Key: "a"})
   225  	c.Assert(conf.Get("core", "foo", &val), IsNil)
   226  	c.Check(val, DeepEquals, "bar")
   227  }
   228  
   229  func (s *applyCfgSuite) TestPlainCoreConfigGetMaybe(c *C) {
   230  	conf := configcore.PlainCoreConfig(map[string]interface{}{"foo": "bar"})
   231  	var val interface{}
   232  	c.Assert(conf.GetMaybe("core", "a", &val), IsNil)
   233  	c.Assert(val, IsNil)
   234  	c.Assert(conf.Get("core", "foo", &val), IsNil)
   235  	c.Check(val, DeepEquals, "bar")
   236  }
   237  
   238  func (s *applyCfgSuite) TestNilHandlePanics(c *C) {
   239  	c.Assert(func() { configcore.AddFSOnlyHandler(nil, nil, nil) },
   240  		Panics, "cannot have nil handle with fsOnlyHandler")
   241  
   242  	c.Assert(func() { configcore.AddWithStateHandler(nil, nil, nil) },
   243  		Panics, "cannot have nil handle with addWithStateHandler if validatedOnlyStateConfig flag is not set")
   244  }