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 }