github.com/rigado/snapd@v2.42.5-go-mod+incompatible/bootloader/lkenv/lkenv_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 lkenv_test 21 22 import ( 23 "bytes" 24 "compress/gzip" 25 . "gopkg.in/check.v1" 26 "io" 27 "io/ioutil" 28 "path/filepath" 29 "testing" 30 31 "github.com/snapcore/snapd/bootloader/lkenv" 32 ) 33 34 // Hook up check.v1 into the "go test" runner 35 func Test(t *testing.T) { TestingT(t) } 36 37 type lkenvTestSuite struct { 38 envPath string 39 envPathbak string 40 } 41 42 var _ = Suite(&lkenvTestSuite{}) 43 44 func (l *lkenvTestSuite) SetUpTest(c *C) { 45 l.envPath = filepath.Join(c.MkDir(), "snapbootsel.bin") 46 l.envPathbak = l.envPath + "bak" 47 } 48 49 // unpack test data packed with gzip 50 func unpackTestData(data []byte) (resData []byte, err error) { 51 b := bytes.NewBuffer(data) 52 var r io.Reader 53 r, err = gzip.NewReader(b) 54 if err != nil { 55 return 56 } 57 var env bytes.Buffer 58 _, err = env.ReadFrom(r) 59 if err != nil { 60 return 61 } 62 return env.Bytes(), nil 63 } 64 65 func (l *lkenvTestSuite) TestSet(c *C) { 66 env := lkenv.NewEnv(l.envPath) 67 c.Check(env, NotNil) 68 69 env.Set("snap_mode", "try") 70 c.Check(env.Get("snap_mode"), Equals, "try") 71 } 72 73 func (l *lkenvTestSuite) TestSave(c *C) { 74 buf := make([]byte, 4096) 75 err := ioutil.WriteFile(l.envPathbak, buf, 0644) 76 c.Assert(err, IsNil) 77 l.TestSaveNoBak(c) 78 } 79 80 func (l *lkenvTestSuite) TestCtoGoString(c *C) { 81 for _, t := range []struct { 82 input []byte 83 expected string 84 }{ 85 {[]byte{0, 0, 0, 0, 0}, ""}, 86 {[]byte{'a', 0, 0, 0, 0}, "a"}, 87 {[]byte{'a', 'b', 0, 0, 0}, "ab"}, 88 {[]byte{'a', 'b', 'c', 0, 0}, "abc"}, 89 {[]byte{'a', 'b', 'c', 'd', 0}, "abcd"}, 90 // no trailing \0 - assume corrupted "" ? 91 {[]byte{'a', 'b', 'c', 'd', 'e'}, ""}, 92 // first \0 is the cutof 93 {[]byte{'a', 'b', 0, 'z', 0}, "ab"}, 94 } { 95 c.Check(lkenv.CToGoString(t.input), Equals, t.expected) 96 } 97 98 } 99 100 func (l *lkenvTestSuite) TestCopyStringHappy(c *C) { 101 for _, t := range []struct { 102 input string 103 expected []byte 104 }{ 105 // input up to the size of the buffer works 106 {"", []byte{0, 0, 0, 0, 0}}, 107 {"a", []byte{'a', 0, 0, 0, 0}}, 108 {"ab", []byte{'a', 'b', 0, 0, 0}}, 109 {"abc", []byte{'a', 'b', 'c', 0, 0}}, 110 {"abcd", []byte{'a', 'b', 'c', 'd', 0}}, 111 // only what fit is copied 112 {"abcde", []byte{'a', 'b', 'c', 'd', 0}}, 113 {"abcdef", []byte{'a', 'b', 'c', 'd', 0}}, 114 // strange embedded stuff works 115 {"ab\000z", []byte{'a', 'b', 0, 'z', 0}}, 116 } { 117 b := make([]byte, 5) 118 lkenv.CopyString(b, t.input) 119 c.Check(b, DeepEquals, t.expected) 120 } 121 } 122 123 func (l *lkenvTestSuite) TestCopyStringNoPanic(c *C) { 124 // too long, string should get concatenate 125 b := make([]byte, 5) 126 defer lkenv.CopyString(b, "12345") 127 c.Assert(recover(), IsNil) 128 defer lkenv.CopyString(b, "123456") 129 c.Assert(recover(), IsNil) 130 } 131 132 func (l *lkenvTestSuite) TestSaveNoBak(c *C) { 133 buf := make([]byte, 4096) 134 err := ioutil.WriteFile(l.envPath, buf, 0644) 135 c.Assert(err, IsNil) 136 137 env := lkenv.NewEnv(l.envPath) 138 c.Check(env, NotNil) 139 140 env.Set("snap_mode", "trying") 141 env.Set("snap_kernel", "kernel-1") 142 env.Set("snap_try_kernel", "kernel-2") 143 env.Set("snap_core", "core-1") 144 env.Set("snap_try_core", "core-2") 145 env.Set("snap_gadget", "gadget-1") 146 env.Set("snap_try_gadget", "gadget-2") 147 env.Set("bootimg_file_name", "boot.img") 148 149 err = env.Save() 150 c.Assert(err, IsNil) 151 152 env2 := lkenv.NewEnv(l.envPath) 153 err = env2.Load() 154 c.Assert(err, IsNil) 155 c.Check(env2.Get("snap_mode"), Equals, "trying") 156 c.Check(env2.Get("snap_kernel"), Equals, "kernel-1") 157 c.Check(env2.Get("snap_try_kernel"), Equals, "kernel-2") 158 c.Check(env2.Get("snap_core"), Equals, "core-1") 159 c.Check(env2.Get("snap_try_core"), Equals, "core-2") 160 c.Check(env2.Get("snap_gadget"), Equals, "gadget-1") 161 c.Check(env2.Get("snap_try_gadget"), Equals, "gadget-2") 162 c.Check(env2.Get("bootimg_file_name"), Equals, "boot.img") 163 } 164 165 func (l *lkenvTestSuite) TestFailedCRC(c *C) { 166 buf := make([]byte, 4096) 167 err := ioutil.WriteFile(l.envPathbak, buf, 0644) 168 c.Assert(err, IsNil) 169 l.TestFailedCRCNoBak(c) 170 } 171 172 func (l *lkenvTestSuite) TestFailedCRCNoBak(c *C) { 173 buf := make([]byte, 4096) 174 err := ioutil.WriteFile(l.envPath, buf, 0644) 175 c.Assert(err, IsNil) 176 177 env := lkenv.NewEnv(l.envPath) 178 c.Check(env, NotNil) 179 180 err = env.Load() 181 c.Assert(err, NotNil) 182 } 183 184 func (l *lkenvTestSuite) TestFailedCRCFallBack(c *C) { 185 buf := make([]byte, 4096) 186 err := ioutil.WriteFile(l.envPath, buf, 0644) 187 c.Assert(err, IsNil) 188 err = ioutil.WriteFile(l.envPathbak, buf, 0644) 189 c.Assert(err, IsNil) 190 191 env := lkenv.NewEnv(l.envPath) 192 c.Check(env, NotNil) 193 194 env.Set("snap_mode", "trying") 195 env.Set("snap_kernel", "kernel-1") 196 env.Set("snap_try_kernel", "kernel-2") 197 err = env.Save() 198 c.Assert(err, IsNil) 199 200 // break main env file 201 err = ioutil.WriteFile(l.envPath, buf, 0644) 202 c.Assert(err, IsNil) 203 204 env2 := lkenv.NewEnv(l.envPath) 205 err = env2.Load() 206 c.Assert(err, IsNil) 207 c.Check(env2.Get("snap_mode"), Equals, "trying") 208 c.Check(env2.Get("snap_kernel"), Equals, "kernel-1") 209 c.Check(env2.Get("snap_try_kernel"), Equals, "kernel-2") 210 } 211 212 func (l *lkenvTestSuite) TestGetBootPartition(c *C) { 213 buf := make([]byte, 4096) 214 err := ioutil.WriteFile(l.envPath, buf, 0644) 215 c.Assert(err, IsNil) 216 217 env := lkenv.NewEnv(l.envPath) 218 c.Assert(err, IsNil) 219 env.ConfigureBootPartitions("boot_a", "boot_b") 220 // test no boot partition used 221 p, err := env.FindFreeBootPartition("kernel-1") 222 c.Check(p, Equals, "boot_a") 223 c.Assert(err, IsNil) 224 // set kernel-2 to boot_a partition 225 err = env.SetBootPartition("boot_a", "kernel-1") 226 c.Assert(err, IsNil) 227 // set kernel-2 to boot_a partition 228 err = env.SetBootPartition("boot_b", "kernel-2") 229 c.Assert(err, IsNil) 230 231 // 'boot_a' has 'kernel-1' revision 232 p, err = env.GetBootPartition("kernel-1") 233 c.Check(p, Equals, "boot_a") 234 c.Assert(err, IsNil) 235 // 'boot_b' has 'kernel-2' revision 236 p, err = env.GetBootPartition("kernel-2") 237 c.Check(p, Equals, "boot_b") 238 c.Assert(err, IsNil) 239 } 240 241 func (l *lkenvTestSuite) TestFindFree_Set_Free_BootPartition(c *C) { 242 buf := make([]byte, 4096) 243 err := ioutil.WriteFile(l.envPath, buf, 0644) 244 c.Assert(err, IsNil) 245 246 env := lkenv.NewEnv(l.envPath) 247 c.Assert(err, IsNil) 248 env.ConfigureBootPartitions("boot_a", "boot_b") 249 // test no boot partition used 250 p, err := env.FindFreeBootPartition("kernel-1") 251 c.Check(p, Equals, "boot_a") 252 c.Assert(err, IsNil) 253 // set kernel-2 to boot_a partition 254 err = env.SetBootPartition("boot_a", "kernel-2") 255 c.Assert(err, IsNil) 256 257 env.Set("snap_kernel", "kernel-2") 258 // kernel-2 should now return first part, as it's already there 259 p, err = env.FindFreeBootPartition("kernel-2") 260 c.Check(p, Equals, "boot_a") 261 c.Assert(err, IsNil) 262 // test kernel-1 snapd, it should now offer second partition 263 p, err = env.FindFreeBootPartition("kernel-1") 264 c.Check(p, Equals, "boot_b") 265 c.Assert(err, IsNil) 266 err = env.SetBootPartition("boot_b", "kernel-1") 267 c.Assert(err, IsNil) 268 // set boot kernel-1 269 env.Set("snap_kernel", "kernel-1") 270 // now kernel-2 should not be protected and boot_a shoild be offered 271 p, err = env.FindFreeBootPartition("kernel-3") 272 c.Check(p, Equals, "boot_a") 273 c.Assert(err, IsNil) 274 err = env.SetBootPartition("boot_a", "kernel-3") 275 c.Assert(err, IsNil) 276 // remove kernel 277 used, err := env.FreeBootPartition("kernel-3") 278 c.Assert(err, IsNil) 279 c.Check(used, Equals, true) 280 // repeated use should return false and error 281 used, err = env.FreeBootPartition("kernel-3") 282 c.Assert(err, NotNil) 283 c.Check(used, Equals, false) 284 } 285 286 func (l *lkenvTestSuite) TestZippedDataSample(c *C) { 287 // test data is generated with gadget build helper tool: 288 // $ parts/snap-boot-sel-env/build/lk-boot-env -w test.bin 289 // --snap-mode="trying" --snap-kernel="kernel-1" --snap-try-kernel="kernel-2" 290 // --snap-core="core-1" --snap-try-core="core-2" --reboot-reason="" 291 // --boot-0-part="boot_a" --boot-1-part="boot_b" --boot-0-snap="kernel-1" 292 // --boot-1-snap="kernel-3" --bootimg-file="boot.img" 293 // $ cat test.bin | gzip | xxd -i 294 gzipedData := []byte{ 295 0x1f, 0x8b, 0x08, 0x00, 0x95, 0x88, 0x77, 0x5d, 0x00, 0x03, 0xed, 0xd7, 296 0xc1, 0x09, 0xc2, 0x40, 0x10, 0x05, 0xd0, 0xa4, 0x20, 0x05, 0x63, 0x07, 297 0x96, 0xa0, 0x05, 0x88, 0x91, 0x25, 0x04, 0x35, 0x0b, 0x6b, 0x2e, 0x1e, 298 0xac, 0xcb, 0xf6, 0xc4, 0x90, 0x1e, 0x06, 0xd9, 0xf7, 0x2a, 0xf8, 0xc3, 299 0x1f, 0x18, 0xe6, 0x74, 0x78, 0xa6, 0xb6, 0x69, 0x9b, 0xb9, 0xbc, 0xc6, 300 0x69, 0x68, 0xaa, 0x75, 0xcd, 0x25, 0x6d, 0x76, 0xd1, 0x29, 0xe2, 0x2c, 301 0xf3, 0x77, 0xd1, 0x29, 0xe2, 0xdc, 0x52, 0x99, 0xd2, 0xbd, 0xde, 0x0d, 302 0x58, 0xe7, 0xaf, 0x78, 0x03, 0x80, 0x5a, 0xf5, 0x39, 0xcf, 0xe7, 0x4b, 303 0x74, 0x8a, 0x38, 0xb5, 0xdf, 0xbf, 0xa5, 0xff, 0x3e, 0x3a, 0x45, 0x9c, 304 0xb5, 0xff, 0x7d, 0x74, 0x8e, 0x28, 0xbf, 0xfe, 0xb7, 0xe3, 0xa3, 0xe2, 305 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 306 0xf8, 0x17, 0xc7, 0xf7, 0xa7, 0xfb, 0x02, 0x1c, 0xdf, 0x44, 0x21, 0x0c, 307 0x3a, 0x00, 0x00} 308 309 // uncompress test data to sample env file 310 rawData, err := unpackTestData(gzipedData) 311 c.Assert(err, IsNil) 312 err = ioutil.WriteFile(l.envPath, rawData, 0644) 313 c.Assert(err, IsNil) 314 err = ioutil.WriteFile(l.envPathbak, rawData, 0644) 315 c.Assert(err, IsNil) 316 317 env := lkenv.NewEnv(l.envPath) 318 c.Check(env, NotNil) 319 err = env.Load() 320 c.Assert(err, IsNil) 321 c.Check(env.Get("snap_mode"), Equals, "trying") 322 c.Check(env.Get("snap_kernel"), Equals, "kernel-1") 323 c.Check(env.Get("snap_try_kernel"), Equals, "kernel-2") 324 c.Check(env.Get("snap_core"), Equals, "core-1") 325 c.Check(env.Get("snap_try_core"), Equals, "core-2") 326 c.Check(env.Get("bootimg_file_name"), Equals, "boot.img") 327 c.Check(env.Get("reboot_reason"), Equals, "") 328 // first partition should be with label 'boot_a' and 'kernel-1' revision 329 p, err := env.GetBootPartition("kernel-1") 330 c.Check(p, Equals, "boot_a") 331 c.Assert(err, IsNil) 332 // test second boot partition is free with label "boot_b" 333 p, err = env.FindFreeBootPartition("kernel-2") 334 c.Check(p, Equals, "boot_b") 335 c.Assert(err, IsNil) 336 }