github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/bootloader/ubootenv/env_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-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 ubootenv_test
    21  
    22  import (
    23  	"bytes"
    24  	"hash/crc32"
    25  	"io/ioutil"
    26  	"os"
    27  	"path/filepath"
    28  	"strings"
    29  	"testing"
    30  
    31  	. "gopkg.in/check.v1"
    32  
    33  	"github.com/snapcore/snapd/bootloader/ubootenv"
    34  )
    35  
    36  // Hook up check.v1 into the "go test" runner
    37  func Test(t *testing.T) { TestingT(t) }
    38  
    39  type uenvTestSuite struct {
    40  	envFile string
    41  }
    42  
    43  var _ = Suite(&uenvTestSuite{})
    44  
    45  func (u *uenvTestSuite) SetUpTest(c *C) {
    46  	u.envFile = filepath.Join(c.MkDir(), "uboot.env")
    47  }
    48  
    49  func (u *uenvTestSuite) TestSetNoDuplicate(c *C) {
    50  	env, err := ubootenv.Create(u.envFile, 4096)
    51  	c.Assert(err, IsNil)
    52  	env.Set("foo", "bar")
    53  	env.Set("foo", "bar")
    54  	c.Assert(env.String(), Equals, "foo=bar\n")
    55  }
    56  
    57  func (u *uenvTestSuite) TestOpenEnv(c *C) {
    58  	env, err := ubootenv.Create(u.envFile, 4096)
    59  	c.Assert(err, IsNil)
    60  	env.Set("foo", "bar")
    61  	c.Assert(env.String(), Equals, "foo=bar\n")
    62  	err = env.Save()
    63  	c.Assert(err, IsNil)
    64  
    65  	env2, err := ubootenv.Open(u.envFile)
    66  	c.Assert(err, IsNil)
    67  	c.Assert(env2.String(), Equals, "foo=bar\n")
    68  }
    69  
    70  func (u *uenvTestSuite) TestOpenEnvBadEmpty(c *C) {
    71  	empty := filepath.Join(c.MkDir(), "empty.env")
    72  
    73  	err := ioutil.WriteFile(empty, nil, 0644)
    74  	c.Assert(err, IsNil)
    75  
    76  	_, err = ubootenv.Open(empty)
    77  	c.Assert(err, ErrorMatches, `cannot open ".*": smaller than expected header`)
    78  }
    79  
    80  func (u *uenvTestSuite) TestOpenEnvBadCRC(c *C) {
    81  	corrupted := filepath.Join(c.MkDir(), "corrupted.env")
    82  
    83  	buf := make([]byte, 4096)
    84  	err := ioutil.WriteFile(corrupted, buf, 0644)
    85  	c.Assert(err, IsNil)
    86  
    87  	_, err = ubootenv.Open(corrupted)
    88  	c.Assert(err, ErrorMatches, `cannot open ".*": bad CRC 0 != .*`)
    89  }
    90  
    91  func (u *uenvTestSuite) TestGetSimple(c *C) {
    92  	env, err := ubootenv.Create(u.envFile, 4096)
    93  	c.Assert(err, IsNil)
    94  	env.Set("foo", "bar")
    95  	c.Assert(env.Get("foo"), Equals, "bar")
    96  }
    97  
    98  func (u *uenvTestSuite) TestGetNoSuchEntry(c *C) {
    99  	env, err := ubootenv.Create(u.envFile, 4096)
   100  	c.Assert(err, IsNil)
   101  	c.Assert(env.Get("no-such-entry"), Equals, "")
   102  }
   103  
   104  func (u *uenvTestSuite) TestImport(c *C) {
   105  	env, err := ubootenv.Create(u.envFile, 4096)
   106  	c.Assert(err, IsNil)
   107  
   108  	r := strings.NewReader("foo=bar\n#comment\n\nbaz=baz")
   109  	err = env.Import(r)
   110  	c.Assert(err, IsNil)
   111  	// order is alphabetic
   112  	c.Assert(env.String(), Equals, "baz=baz\nfoo=bar\n")
   113  }
   114  
   115  func (u *uenvTestSuite) TestImportHasError(c *C) {
   116  	env, err := ubootenv.Create(u.envFile, 4096)
   117  	c.Assert(err, IsNil)
   118  
   119  	r := strings.NewReader("foxy")
   120  	err = env.Import(r)
   121  	c.Assert(err, ErrorMatches, "Invalid line: \"foxy\"")
   122  }
   123  
   124  func (u *uenvTestSuite) TestSetEmptyUnsets(c *C) {
   125  	env, err := ubootenv.Create(u.envFile, 4096)
   126  	c.Assert(err, IsNil)
   127  
   128  	env.Set("foo", "bar")
   129  	c.Assert(env.String(), Equals, "foo=bar\n")
   130  	env.Set("foo", "")
   131  	c.Assert(env.String(), Equals, "")
   132  }
   133  
   134  func (u *uenvTestSuite) makeUbootEnvFromData(c *C, mockData []byte) {
   135  	w := bytes.NewBuffer(nil)
   136  	crc := crc32.ChecksumIEEE(mockData)
   137  	w.Write(ubootenv.WriteUint32(crc))
   138  	w.Write([]byte{0})
   139  	w.Write(mockData)
   140  
   141  	f, err := os.Create(u.envFile)
   142  	c.Assert(err, IsNil)
   143  	defer f.Close()
   144  	_, err = f.Write(w.Bytes())
   145  	c.Assert(err, IsNil)
   146  }
   147  
   148  // ensure that the data after \0\0 is discarded (except for crc)
   149  func (u *uenvTestSuite) TestReadStopsAfterDoubleNull(c *C) {
   150  	mockData := []byte{
   151  		// foo=bar
   152  		0x66, 0x6f, 0x6f, 0x3d, 0x62, 0x61, 0x72,
   153  		// eof
   154  		0x00, 0x00,
   155  		// junk after eof as written by fw_setenv sometimes
   156  		// =b
   157  		0x3d, 62,
   158  		// empty
   159  		0xff, 0xff,
   160  	}
   161  	u.makeUbootEnvFromData(c, mockData)
   162  
   163  	env, err := ubootenv.Open(u.envFile)
   164  	c.Assert(err, IsNil)
   165  	c.Assert(env.String(), Equals, "foo=bar\n")
   166  }
   167  
   168  // ensure that the malformed data is not causing us to panic.
   169  func (u *uenvTestSuite) TestErrorOnMalformedData(c *C) {
   170  	mockData := []byte{
   171  		// foo
   172  		0x66, 0x6f, 0x6f,
   173  		// eof
   174  		0x00, 0x00,
   175  	}
   176  	u.makeUbootEnvFromData(c, mockData)
   177  
   178  	env, err := ubootenv.Open(u.envFile)
   179  	c.Assert(err, ErrorMatches, `cannot parse line "foo" as key=value pair`)
   180  	c.Assert(env, IsNil)
   181  }
   182  
   183  // ensure that the malformed data is not causing us to panic.
   184  func (u *uenvTestSuite) TestOpenBestEffort(c *C) {
   185  	testCases := map[string][]byte{"noise": {
   186  		// key1=value1
   187  		0x6b, 0x65, 0x79, 0x31, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00,
   188  		// foo
   189  		0x66, 0x6f, 0x6f, 0x00,
   190  		// key2=value2
   191  		0x6b, 0x65, 0x79, 0x32, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x00,
   192  		// eof
   193  		0x00, 0x00,
   194  	}, "no-eof": {
   195  		// key1=value1
   196  		0x6b, 0x65, 0x79, 0x31, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00,
   197  		// key2=value2
   198  		0x6b, 0x65, 0x79, 0x32, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x00,
   199  		// NO EOF!
   200  	}, "noise-eof": {
   201  		// key1=value1
   202  		0x6b, 0x65, 0x79, 0x31, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00,
   203  		// key2=value2
   204  		0x6b, 0x65, 0x79, 0x32, 0x3d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x00,
   205  		// foo
   206  		0x66, 0x6f, 0x6f, 0x00,
   207  	}}
   208  	for testName, mockData := range testCases {
   209  		u.makeUbootEnvFromData(c, mockData)
   210  
   211  		env, err := ubootenv.OpenWithFlags(u.envFile, ubootenv.OpenBestEffort)
   212  		c.Assert(err, IsNil, Commentf(testName))
   213  		c.Check(env.String(), Equals, "key1=value1\nkey2=value2\n", Commentf(testName))
   214  	}
   215  }
   216  
   217  func (u *uenvTestSuite) TestErrorOnMissingKeyInKeyValuePair(c *C) {
   218  	mockData := []byte{
   219  		// =foo
   220  		0x3d, 0x66, 0x6f, 0x6f,
   221  		// eof
   222  		0x00, 0x00,
   223  	}
   224  	u.makeUbootEnvFromData(c, mockData)
   225  
   226  	env, err := ubootenv.Open(u.envFile)
   227  	c.Assert(err, ErrorMatches, `cannot parse line "=foo" as key=value pair`)
   228  	c.Assert(env, IsNil)
   229  }
   230  
   231  func (u *uenvTestSuite) TestReadEmptyFile(c *C) {
   232  	mockData := []byte{
   233  		// eof
   234  		0x00, 0x00,
   235  		// empty
   236  		0xff, 0xff,
   237  	}
   238  	u.makeUbootEnvFromData(c, mockData)
   239  
   240  	env, err := ubootenv.Open(u.envFile)
   241  	c.Assert(err, IsNil)
   242  	c.Assert(env.String(), Equals, "")
   243  }
   244  
   245  func (u *uenvTestSuite) TestWritesEmptyFileWithDoubleNewline(c *C) {
   246  	env, err := ubootenv.Create(u.envFile, 12)
   247  	c.Assert(err, IsNil)
   248  	err = env.Save()
   249  	c.Assert(err, IsNil)
   250  
   251  	r, err := os.Open(u.envFile)
   252  	c.Assert(err, IsNil)
   253  	defer r.Close()
   254  	content, err := ioutil.ReadAll(r)
   255  	c.Assert(err, IsNil)
   256  	c.Assert(content, DeepEquals, []byte{
   257  		// crc
   258  		0x11, 0x38, 0xb3, 0x89,
   259  		// redundant
   260  		0x0,
   261  		// eof
   262  		0x0, 0x0,
   263  		// footer
   264  		0xff, 0xff, 0xff, 0xff, 0xff,
   265  	})
   266  
   267  	env, err = ubootenv.Open(u.envFile)
   268  	c.Assert(err, IsNil)
   269  	c.Assert(env.String(), Equals, "")
   270  }
   271  
   272  func (u *uenvTestSuite) TestWritesContentCorrectly(c *C) {
   273  	totalSize := 16
   274  
   275  	env, err := ubootenv.Create(u.envFile, totalSize)
   276  	c.Assert(err, IsNil)
   277  	env.Set("a", "b")
   278  	env.Set("c", "d")
   279  	err = env.Save()
   280  	c.Assert(err, IsNil)
   281  
   282  	r, err := os.Open(u.envFile)
   283  	c.Assert(err, IsNil)
   284  	defer r.Close()
   285  	content, err := ioutil.ReadAll(r)
   286  	c.Assert(err, IsNil)
   287  	c.Assert(content, DeepEquals, []byte{
   288  		// crc
   289  		0xc7, 0xd9, 0x6b, 0xc5,
   290  		// redundant
   291  		0x0,
   292  		// a=b
   293  		0x61, 0x3d, 0x62,
   294  		// eol
   295  		0x0,
   296  		// c=d
   297  		0x63, 0x3d, 0x64,
   298  		// eof
   299  		0x0, 0x0,
   300  		// footer
   301  		0xff, 0xff,
   302  	})
   303  
   304  	env, err = ubootenv.Open(u.envFile)
   305  	c.Assert(err, IsNil)
   306  	c.Assert(env.String(), Equals, "a=b\nc=d\n")
   307  	c.Assert(env.Size(), Equals, totalSize)
   308  }