github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/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 "io" 26 "io/ioutil" 27 "path/filepath" 28 "testing" 29 30 . "gopkg.in/check.v1" 31 32 "github.com/snapcore/snapd/boot" 33 "github.com/snapcore/snapd/bootloader/lkenv" 34 ) 35 36 // Hook up check.v1 into the "go test" runner 37 func Test(t *testing.T) { TestingT(t) } 38 39 type lkenvTestSuite struct { 40 envPath string 41 envPathbak string 42 } 43 44 var _ = Suite(&lkenvTestSuite{}) 45 46 func (l *lkenvTestSuite) SetUpTest(c *C) { 47 l.envPath = filepath.Join(c.MkDir(), "snapbootsel.bin") 48 l.envPathbak = l.envPath + "bak" 49 } 50 51 // unpack test data packed with gzip 52 func unpackTestData(data []byte) (resData []byte, err error) { 53 b := bytes.NewBuffer(data) 54 var r io.Reader 55 r, err = gzip.NewReader(b) 56 if err != nil { 57 return 58 } 59 var env bytes.Buffer 60 _, err = env.ReadFrom(r) 61 if err != nil { 62 return 63 } 64 return env.Bytes(), nil 65 } 66 67 func (l *lkenvTestSuite) TestSet(c *C) { 68 env := lkenv.NewEnv(l.envPath) 69 c.Check(env, NotNil) 70 71 env.Set("snap_mode", boot.TryStatus) 72 c.Check(env.Get("snap_mode"), Equals, boot.TryStatus) 73 } 74 75 func (l *lkenvTestSuite) TestSave(c *C) { 76 buf := make([]byte, 4096) 77 err := ioutil.WriteFile(l.envPathbak, buf, 0644) 78 c.Assert(err, IsNil) 79 l.TestSaveNoBak(c) 80 } 81 82 func (l *lkenvTestSuite) TestCtoGoString(c *C) { 83 for _, t := range []struct { 84 input []byte 85 expected string 86 }{ 87 {[]byte{0, 0, 0, 0, 0}, ""}, 88 {[]byte{'a', 0, 0, 0, 0}, "a"}, 89 {[]byte{'a', 'b', 0, 0, 0}, "ab"}, 90 {[]byte{'a', 'b', 'c', 0, 0}, "abc"}, 91 {[]byte{'a', 'b', 'c', 'd', 0}, "abcd"}, 92 // no trailing \0 - assume corrupted "" ? 93 {[]byte{'a', 'b', 'c', 'd', 'e'}, ""}, 94 // first \0 is the cutof 95 {[]byte{'a', 'b', 0, 'z', 0}, "ab"}, 96 } { 97 c.Check(lkenv.CToGoString(t.input), Equals, t.expected) 98 } 99 100 } 101 102 func (l *lkenvTestSuite) TestCopyStringHappy(c *C) { 103 for _, t := range []struct { 104 input string 105 expected []byte 106 }{ 107 // input up to the size of the buffer works 108 {"", []byte{0, 0, 0, 0, 0}}, 109 {"a", []byte{'a', 0, 0, 0, 0}}, 110 {"ab", []byte{'a', 'b', 0, 0, 0}}, 111 {"abc", []byte{'a', 'b', 'c', 0, 0}}, 112 {"abcd", []byte{'a', 'b', 'c', 'd', 0}}, 113 // only what fit is copied 114 {"abcde", []byte{'a', 'b', 'c', 'd', 0}}, 115 {"abcdef", []byte{'a', 'b', 'c', 'd', 0}}, 116 // strange embedded stuff works 117 {"ab\000z", []byte{'a', 'b', 0, 'z', 0}}, 118 } { 119 b := make([]byte, 5) 120 lkenv.CopyString(b, t.input) 121 c.Check(b, DeepEquals, t.expected) 122 } 123 } 124 125 func (l *lkenvTestSuite) TestCopyStringNoPanic(c *C) { 126 // too long, string should get concatenate 127 b := make([]byte, 5) 128 defer lkenv.CopyString(b, "12345") 129 c.Assert(recover(), IsNil) 130 defer lkenv.CopyString(b, "123456") 131 c.Assert(recover(), IsNil) 132 } 133 134 func (l *lkenvTestSuite) TestSaveNoBak(c *C) { 135 buf := make([]byte, 4096) 136 err := ioutil.WriteFile(l.envPath, buf, 0644) 137 c.Assert(err, IsNil) 138 139 env := lkenv.NewEnv(l.envPath) 140 c.Check(env, NotNil) 141 142 env.Set("snap_mode", "trying") 143 env.Set("snap_kernel", "kernel-1") 144 env.Set("snap_try_kernel", "kernel-2") 145 env.Set("snap_core", "core-1") 146 env.Set("snap_try_core", "core-2") 147 env.Set("snap_gadget", "gadget-1") 148 env.Set("snap_try_gadget", "gadget-2") 149 env.Set("bootimg_file_name", "boot.img") 150 151 err = env.Save() 152 c.Assert(err, IsNil) 153 154 env2 := lkenv.NewEnv(l.envPath) 155 err = env2.Load() 156 c.Assert(err, IsNil) 157 c.Check(env2.Get("snap_mode"), Equals, "trying") 158 c.Check(env2.Get("snap_kernel"), Equals, "kernel-1") 159 c.Check(env2.Get("snap_try_kernel"), Equals, "kernel-2") 160 c.Check(env2.Get("snap_core"), Equals, "core-1") 161 c.Check(env2.Get("snap_try_core"), Equals, "core-2") 162 c.Check(env2.Get("snap_gadget"), Equals, "gadget-1") 163 c.Check(env2.Get("snap_try_gadget"), Equals, "gadget-2") 164 c.Check(env2.Get("bootimg_file_name"), Equals, "boot.img") 165 } 166 167 func (l *lkenvTestSuite) TestFailedCRC(c *C) { 168 buf := make([]byte, 4096) 169 err := ioutil.WriteFile(l.envPathbak, buf, 0644) 170 c.Assert(err, IsNil) 171 l.TestFailedCRCNoBak(c) 172 } 173 174 func (l *lkenvTestSuite) TestFailedCRCNoBak(c *C) { 175 buf := make([]byte, 4096) 176 err := ioutil.WriteFile(l.envPath, buf, 0644) 177 c.Assert(err, IsNil) 178 179 env := lkenv.NewEnv(l.envPath) 180 c.Check(env, NotNil) 181 182 err = env.Load() 183 c.Assert(err, NotNil) 184 } 185 186 func (l *lkenvTestSuite) TestFailedCRCFallBack(c *C) { 187 buf := make([]byte, 4096) 188 err := ioutil.WriteFile(l.envPath, buf, 0644) 189 c.Assert(err, IsNil) 190 err = ioutil.WriteFile(l.envPathbak, buf, 0644) 191 c.Assert(err, IsNil) 192 193 env := lkenv.NewEnv(l.envPath) 194 c.Check(env, NotNil) 195 196 env.Set("snap_mode", "trying") 197 env.Set("snap_kernel", "kernel-1") 198 env.Set("snap_try_kernel", "kernel-2") 199 err = env.Save() 200 c.Assert(err, IsNil) 201 202 // break main env file 203 err = ioutil.WriteFile(l.envPath, buf, 0644) 204 c.Assert(err, IsNil) 205 206 env2 := lkenv.NewEnv(l.envPath) 207 err = env2.Load() 208 c.Assert(err, IsNil) 209 c.Check(env2.Get("snap_mode"), Equals, "trying") 210 c.Check(env2.Get("snap_kernel"), Equals, "kernel-1") 211 c.Check(env2.Get("snap_try_kernel"), Equals, "kernel-2") 212 } 213 214 func (l *lkenvTestSuite) TestGetBootPartition(c *C) { 215 buf := make([]byte, 4096) 216 err := ioutil.WriteFile(l.envPath, buf, 0644) 217 c.Assert(err, IsNil) 218 219 env := lkenv.NewEnv(l.envPath) 220 c.Assert(err, IsNil) 221 env.ConfigureBootPartitions("boot_a", "boot_b") 222 // test no boot partition used 223 p, err := env.FindFreeBootPartition("kernel-1") 224 c.Check(p, Equals, "boot_a") 225 c.Assert(err, IsNil) 226 // set kernel-2 to boot_a partition 227 err = env.SetBootPartition("boot_a", "kernel-1") 228 c.Assert(err, IsNil) 229 // set kernel-2 to boot_a partition 230 err = env.SetBootPartition("boot_b", "kernel-2") 231 c.Assert(err, IsNil) 232 233 // 'boot_a' has 'kernel-1' revision 234 p, err = env.GetBootPartition("kernel-1") 235 c.Check(p, Equals, "boot_a") 236 c.Assert(err, IsNil) 237 // 'boot_b' has 'kernel-2' revision 238 p, err = env.GetBootPartition("kernel-2") 239 c.Check(p, Equals, "boot_b") 240 c.Assert(err, IsNil) 241 } 242 243 func (l *lkenvTestSuite) TestFindFree_Set_Free_BootPartition(c *C) { 244 buf := make([]byte, 4096) 245 err := ioutil.WriteFile(l.envPath, buf, 0644) 246 c.Assert(err, IsNil) 247 248 env := lkenv.NewEnv(l.envPath) 249 c.Assert(err, IsNil) 250 env.ConfigureBootPartitions("boot_a", "boot_b") 251 // test no boot partition used 252 p, err := env.FindFreeBootPartition("kernel-1") 253 c.Check(p, Equals, "boot_a") 254 c.Assert(err, IsNil) 255 // set kernel-2 to boot_a partition 256 err = env.SetBootPartition("boot_a", "kernel-2") 257 c.Assert(err, IsNil) 258 259 env.Set("snap_kernel", "kernel-2") 260 // kernel-2 should now return first part, as it's already there 261 p, err = env.FindFreeBootPartition("kernel-2") 262 c.Check(p, Equals, "boot_a") 263 c.Assert(err, IsNil) 264 // test kernel-1 snapd, it should now offer second partition 265 p, err = env.FindFreeBootPartition("kernel-1") 266 c.Check(p, Equals, "boot_b") 267 c.Assert(err, IsNil) 268 err = env.SetBootPartition("boot_b", "kernel-1") 269 c.Assert(err, IsNil) 270 // set boot kernel-1 271 env.Set("snap_kernel", "kernel-1") 272 // now kernel-2 should not be protected and boot_a shoild be offered 273 p, err = env.FindFreeBootPartition("kernel-3") 274 c.Check(p, Equals, "boot_a") 275 c.Assert(err, IsNil) 276 err = env.SetBootPartition("boot_a", "kernel-3") 277 c.Assert(err, IsNil) 278 // remove kernel 279 err = env.RemoveKernelRevisionFromBootPartition("kernel-3") 280 c.Assert(err, IsNil) 281 // repeated use should return false and error 282 err = env.RemoveKernelRevisionFromBootPartition("kernel-3") 283 c.Assert(err, NotNil) 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 }