github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/configstate/configcore/picfg_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 "io/ioutil" 24 "os" 25 "path/filepath" 26 "strings" 27 28 . "gopkg.in/check.v1" 29 30 "github.com/snapcore/snapd/boot" 31 "github.com/snapcore/snapd/dirs" 32 "github.com/snapcore/snapd/osutil" 33 "github.com/snapcore/snapd/overlord/configstate/configcore" 34 "github.com/snapcore/snapd/release" 35 "github.com/snapcore/snapd/testutil" 36 ) 37 38 type piCfgSuite struct { 39 configcoreSuite 40 41 mockConfigPath string 42 } 43 44 var _ = Suite(&piCfgSuite{}) 45 46 var mockConfigTxt = ` 47 # For more options and information see 48 # http://www.raspberrypi.org/documentation/configuration/config-txt.md 49 #hdmi_group=1 50 # uncomment this if your display has a black border of unused pixels visible 51 # and your display can output without overscan 52 #disable_overscan=1 53 unrelated_options=are-kept 54 #gpu_mem_512=true 55 ` 56 57 func (s *piCfgSuite) SetUpTest(c *C) { 58 s.configcoreSuite.SetUpTest(c) 59 c.Assert(os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "etc"), 0755), IsNil) 60 61 s.mockConfigPath = filepath.Join(dirs.GlobalRootDir, "/boot/uboot/config.txt") 62 err := os.MkdirAll(filepath.Dir(s.mockConfigPath), 0755) 63 c.Assert(err, IsNil) 64 s.mockConfig(c, mockConfigTxt) 65 } 66 67 func (s *piCfgSuite) mockConfig(c *C, txt string) { 68 err := ioutil.WriteFile(s.mockConfigPath, []byte(txt), 0644) 69 c.Assert(err, IsNil) 70 } 71 72 func (s *piCfgSuite) checkMockConfig(c *C, expected string) { 73 c.Check(s.mockConfigPath, testutil.FileEquals, expected) 74 } 75 76 func (s *piCfgSuite) TestConfigurePiConfigUncommentExisting(c *C) { 77 err := configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"disable_overscan": "1"}) 78 c.Assert(err, IsNil) 79 80 expected := strings.Replace(mockConfigTxt, "#disable_overscan=1", "disable_overscan=1", -1) 81 s.checkMockConfig(c, expected) 82 } 83 84 func (s *piCfgSuite) TestConfigurePiConfigCommentExisting(c *C) { 85 s.mockConfig(c, mockConfigTxt+"avoid_warnings=1\n") 86 87 err := configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"avoid_warnings": ""}) 88 c.Assert(err, IsNil) 89 90 expected := mockConfigTxt + "#avoid_warnings=1\n" 91 s.checkMockConfig(c, expected) 92 } 93 94 func (s *piCfgSuite) TestConfigurePiConfigAddNewOption(c *C) { 95 err := configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"framebuffer_depth": "16"}) 96 c.Assert(err, IsNil) 97 98 expected := mockConfigTxt + "framebuffer_depth=16\n" 99 s.checkMockConfig(c, expected) 100 101 // add again, verify its not added twice but updated 102 err = configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"framebuffer_depth": "32"}) 103 c.Assert(err, IsNil) 104 expected = mockConfigTxt + "framebuffer_depth=32\n" 105 s.checkMockConfig(c, expected) 106 } 107 108 func (s *piCfgSuite) TestConfigurePiConfigNoChangeUnset(c *C) { 109 // ensure we cannot write to the dir to test that we really 110 // do not update the file 111 err := os.Chmod(filepath.Dir(s.mockConfigPath), 0500) 112 c.Assert(err, IsNil) 113 defer os.Chmod(filepath.Dir(s.mockConfigPath), 0755) 114 115 err = configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"hdmi_group": ""}) 116 c.Assert(err, IsNil) 117 } 118 119 func (s *piCfgSuite) TestConfigurePiConfigNoChangeSet(c *C) { 120 // ensure we cannot write to the dir to test that we really 121 // do not update the file 122 err := os.Chmod(filepath.Dir(s.mockConfigPath), 0500) 123 c.Assert(err, IsNil) 124 defer os.Chmod(filepath.Dir(s.mockConfigPath), 0755) 125 126 err = configcore.UpdatePiConfig(s.mockConfigPath, map[string]string{"unrelated_options": "cannot-be-set"}) 127 c.Assert(err, ErrorMatches, `cannot set unsupported configuration value "unrelated_options"`) 128 } 129 130 func (s *piCfgSuite) TestConfigurePiConfigIntegration(c *C) { 131 restore := release.MockOnClassic(false) 132 defer restore() 133 134 err := configcore.Run(&mockConf{ 135 state: s.state, 136 conf: map[string]interface{}{ 137 "pi-config.disable-overscan": 1, 138 }, 139 }) 140 c.Assert(err, IsNil) 141 142 expected := strings.Replace(mockConfigTxt, "#disable_overscan=1", "disable_overscan=1", -1) 143 s.checkMockConfig(c, expected) 144 145 err = configcore.Run(&mockConf{ 146 state: s.state, 147 conf: map[string]interface{}{ 148 "pi-config.disable-overscan": "", 149 }, 150 }) 151 c.Assert(err, IsNil) 152 153 s.checkMockConfig(c, mockConfigTxt) 154 } 155 156 func (s *piCfgSuite) TestConfigurePiConfigRegression(c *C) { 157 restore := release.MockOnClassic(false) 158 defer restore() 159 160 err := configcore.Run(&mockConf{ 161 state: s.state, 162 conf: map[string]interface{}{ 163 "pi-config.gpu-mem-512": true, 164 }, 165 }) 166 c.Assert(err, IsNil) 167 expected := strings.Replace(mockConfigTxt, "#gpu_mem_512=true", "gpu_mem_512=true", -1) 168 s.checkMockConfig(c, expected) 169 } 170 171 func (s *piCfgSuite) TestUpdateConfigUC20RunMode(c *C) { 172 restore := release.MockOnClassic(false) 173 defer restore() 174 175 // mock the device as uc20 run mode 176 mockCmdline := filepath.Join(dirs.GlobalRootDir, "cmdline") 177 err := ioutil.WriteFile(mockCmdline, []byte("snapd_recovery_mode=run"), 0644) 178 c.Assert(err, IsNil) 179 restore = osutil.MockProcCmdline(mockCmdline) 180 defer restore() 181 182 // write default config at both the uc18 style runtime location and uc20 run 183 // mode location to show that we only modify the uc20 one 184 piCfg := filepath.Join(boot.InitramfsUbuntuSeedDir, "config.txt") 185 uc18PiCfg := filepath.Join(dirs.GlobalRootDir, "/boot/uboot/config.txt") 186 187 err = os.MkdirAll(filepath.Dir(piCfg), 0755) 188 c.Assert(err, IsNil) 189 err = os.MkdirAll(filepath.Dir(uc18PiCfg), 0755) 190 c.Assert(err, IsNil) 191 192 err = ioutil.WriteFile(piCfg, []byte(mockConfigTxt), 0644) 193 c.Assert(err, IsNil) 194 err = ioutil.WriteFile(uc18PiCfg, []byte(mockConfigTxt), 0644) 195 c.Assert(err, IsNil) 196 197 // apply the config 198 err = configcore.Run(&mockConf{ 199 state: s.state, 200 conf: map[string]interface{}{ 201 "pi-config.gpu-mem-512": true, 202 }, 203 }) 204 c.Assert(err, IsNil) 205 206 // make sure that the original pi config.txt in /boot/uboot/config.txt 207 // didn't change 208 c.Check(uc18PiCfg, testutil.FileEquals, mockConfigTxt) 209 210 // but the real one did change* 211 expected := strings.Replace(mockConfigTxt, "#gpu_mem_512=true", "gpu_mem_512=true", -1) 212 c.Check(piCfg, testutil.FileEquals, expected) 213 } 214 215 func (s *piCfgSuite) testUpdateConfigUC20NonRunMode(c *C, mode string) { 216 restore := release.MockOnClassic(false) 217 defer restore() 218 219 // mock the device as the specified uc20 mode 220 mockCmdline := filepath.Join(dirs.GlobalRootDir, "cmdline") 221 err := ioutil.WriteFile(mockCmdline, []byte("snapd_recovery_mode="+mode), 0644) 222 c.Assert(err, IsNil) 223 restore = osutil.MockProcCmdline(mockCmdline) 224 defer restore() 225 226 piCfg := filepath.Join(boot.InitramfsUbuntuSeedDir, "config.txt") 227 228 err = os.MkdirAll(filepath.Dir(piCfg), 0755) 229 c.Assert(err, IsNil) 230 231 err = ioutil.WriteFile(piCfg, []byte(mockConfigTxt), 0644) 232 c.Assert(err, IsNil) 233 234 // apply the config 235 err = configcore.Run(&mockConf{ 236 state: s.state, 237 conf: map[string]interface{}{ 238 "pi-config.gpu-mem-512": true, 239 }, 240 }) 241 c.Assert(err, IsNil) 242 243 // the config.txt didn't change at all 244 c.Check(piCfg, testutil.FileEquals, mockConfigTxt) 245 } 246 247 func (s *piCfgSuite) TestUpdateConfigUC20RecoverModeDoesNothing(c *C) { 248 s.testUpdateConfigUC20NonRunMode(c, "recover") 249 } 250 251 func (s *piCfgSuite) TestUpdateConfigUC20InstallModeDoesNothing(c *C) { 252 s.testUpdateConfigUC20NonRunMode(c, "install") 253 } 254 255 func (s *piCfgSuite) TestFilesystemOnlyApply(c *C) { 256 conf := configcore.PlainCoreConfig(map[string]interface{}{ 257 "pi-config.gpu-mem-512": true, 258 }) 259 260 tmpDir := c.MkDir() 261 c.Assert(os.MkdirAll(filepath.Join(tmpDir, "/boot/uboot"), 0755), IsNil) 262 263 // write default config 264 piCfg := filepath.Join(tmpDir, "/boot/uboot/config.txt") 265 c.Assert(ioutil.WriteFile(piCfg, []byte(mockConfigTxt), 0644), IsNil) 266 267 c.Assert(configcore.FilesystemOnlyApply(tmpDir, conf, nil), IsNil) 268 269 expected := strings.Replace(mockConfigTxt, "#gpu_mem_512=true", "gpu_mem_512=true", -1) 270 c.Check(piCfg, testutil.FileEquals, expected) 271 }