github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/testutil/lowlevel_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 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 testutil_test
    21  
    22  import (
    23  	"github.com/snapcore/snapd/testutil"
    24  
    25  	"fmt"
    26  	"os"
    27  	"syscall"
    28  
    29  	"gopkg.in/check.v1"
    30  )
    31  
    32  type lowLevelSuite struct {
    33  	sys *testutil.SyscallRecorder
    34  }
    35  
    36  var _ = check.Suite(&lowLevelSuite{})
    37  
    38  func (s *lowLevelSuite) SetUpTest(c *check.C) {
    39  	s.sys = &testutil.SyscallRecorder{}
    40  }
    41  
    42  func (s *lowLevelSuite) TestFakeFileInfo(c *check.C) {
    43  	ffi := testutil.FakeFileInfo("name", 0755)
    44  	c.Assert(ffi.Name(), check.Equals, "name")
    45  	c.Assert(ffi.Mode(), check.Equals, os.FileMode(0755))
    46  
    47  	c.Assert(testutil.FileInfoFile.Mode().IsDir(), check.Equals, false)
    48  	c.Assert(testutil.FileInfoFile.Mode().IsRegular(), check.Equals, true)
    49  	c.Assert(testutil.FileInfoFile.IsDir(), check.Equals, false)
    50  
    51  	c.Assert(testutil.FileInfoDir.Mode().IsDir(), check.Equals, true)
    52  	c.Assert(testutil.FileInfoDir.Mode().IsRegular(), check.Equals, false)
    53  	c.Assert(testutil.FileInfoDir.IsDir(), check.Equals, true)
    54  
    55  	c.Assert(testutil.FileInfoSymlink.Mode().IsDir(), check.Equals, false)
    56  	c.Assert(testutil.FileInfoSymlink.Mode().IsRegular(), check.Equals, false)
    57  	c.Assert(testutil.FileInfoSymlink.IsDir(), check.Equals, false)
    58  }
    59  
    60  func (s *lowLevelSuite) TestOpenSuccess(c *check.C) {
    61  	// By default system calls succeed and get recorded for inspection.
    62  	fd, err := s.sys.Open("/some/path", syscall.O_NOFOLLOW|syscall.O_CLOEXEC|syscall.O_RDWR|syscall.O_CREAT|syscall.O_EXCL, 0)
    63  	c.Assert(err, check.IsNil)
    64  	c.Assert(fd, check.Equals, 3)
    65  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
    66  		`open "/some/path" O_NOFOLLOW|O_CLOEXEC|O_RDWR|O_CREAT|O_EXCL 0`, // -> 3
    67  	})
    68  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
    69  		{C: `open "/some/path" O_NOFOLLOW|O_CLOEXEC|O_RDWR|O_CREAT|O_EXCL 0`, R: 3},
    70  	})
    71  }
    72  
    73  func (s *lowLevelSuite) TestOpenFailure(c *check.C) {
    74  	// Any call can be made to fail using InsertFault()
    75  	s.sys.InsertFault(`open "/some/path" 0 0`, syscall.ENOENT)
    76  	fd, err := s.sys.Open("/some/path", 0, 0)
    77  	c.Assert(err, check.ErrorMatches, "no such file or directory")
    78  	c.Assert(fd, check.Equals, -1)
    79  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
    80  		`open "/some/path" 0 0`, // -> ENOENT
    81  	})
    82  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
    83  		{C: `open "/some/path" 0 0`, E: syscall.ENOENT},
    84  	})
    85  }
    86  
    87  func (s *lowLevelSuite) TestOpenVariableFailure(c *check.C) {
    88  	// The way a particular call fails may vary over time.
    89  	// Subsequent errors are returned on subsequent calls.
    90  	s.sys.InsertFault(`open "/some/path" O_RDWR 0`, syscall.ENOENT, syscall.EPERM)
    91  	fd, err := s.sys.Open("/some/path", syscall.O_RDWR, 0)
    92  	c.Assert(err, check.ErrorMatches, "no such file or directory")
    93  	c.Assert(fd, check.Equals, -1)
    94  	// 2nd attempt
    95  	fd, err = s.sys.Open("/some/path", syscall.O_RDWR, 0)
    96  	c.Assert(err, check.ErrorMatches, "operation not permitted")
    97  	c.Assert(fd, check.Equals, -1)
    98  	// 3rd attempt
    99  	fd, err = s.sys.Open("/some/path", syscall.O_RDWR, 0)
   100  	c.Assert(err, check.IsNil)
   101  	c.Assert(fd, check.Equals, 3)
   102  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   103  		`open "/some/path" O_RDWR 0`, // -> ENOENT
   104  		`open "/some/path" O_RDWR 0`, // -> EPERM
   105  		`open "/some/path" O_RDWR 0`, // -> 3
   106  	})
   107  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   108  		{C: `open "/some/path" O_RDWR 0`, E: syscall.ENOENT},
   109  		{C: `open "/some/path" O_RDWR 0`, E: syscall.EPERM},
   110  		{C: `open "/some/path" O_RDWR 0`, R: 3},
   111  	})
   112  }
   113  
   114  func (s *lowLevelSuite) TestOpenCustomFailure(c *check.C) {
   115  	// The way a particular call may also be arbitrarily programmed.
   116  	n := 3
   117  	s.sys.InsertFaultFunc(`open "/some/path" O_RDWR 0`, func() error {
   118  		if n > 0 {
   119  			err := fmt.Errorf("%d more", n)
   120  			n--
   121  			return err
   122  		}
   123  		return nil
   124  	})
   125  	_, err := s.sys.Open("/some/path", syscall.O_RDWR, 0)
   126  	c.Assert(err, check.ErrorMatches, "3 more")
   127  	_, err = s.sys.Open("/some/path", syscall.O_RDWR, 0)
   128  	c.Assert(err, check.ErrorMatches, "2 more")
   129  	_, err = s.sys.Open("/some/path", syscall.O_RDWR, 0)
   130  	c.Assert(err, check.ErrorMatches, "1 more")
   131  	fd, err := s.sys.Open("/some/path", syscall.O_RDWR, 0)
   132  	c.Assert(err, check.IsNil)
   133  	c.Assert(fd, check.Equals, 3)
   134  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   135  		`open "/some/path" O_RDWR 0`, // -> 3 more
   136  		`open "/some/path" O_RDWR 0`, // -> 2 more
   137  		`open "/some/path" O_RDWR 0`, // -> 1 more
   138  		`open "/some/path" O_RDWR 0`, // -> 3
   139  	})
   140  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   141  		{C: `open "/some/path" O_RDWR 0`, E: fmt.Errorf("3 more")},
   142  		{C: `open "/some/path" O_RDWR 0`, E: fmt.Errorf("2 more")},
   143  		{C: `open "/some/path" O_RDWR 0`, E: fmt.Errorf("1 more")},
   144  		{C: `open "/some/path" O_RDWR 0`, R: 3},
   145  	})
   146  }
   147  
   148  func (s *lowLevelSuite) TestUnclosedFile(c *check.C) {
   149  	// Open file descriptors can be detected in suite teardown using either
   150  	// StrayDescriptorError or CheckForStrayDescriptors.
   151  	fd, err := s.sys.Open("/some/path", syscall.O_RDWR, 0)
   152  	c.Assert(err, check.IsNil)
   153  	c.Assert(fd, check.Equals, 3)
   154  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   155  		`open "/some/path" O_RDWR 0`, // -> 3
   156  	})
   157  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   158  		{C: `open "/some/path" O_RDWR 0`, R: 3},
   159  	})
   160  	c.Assert(s.sys.StrayDescriptorsError(), check.ErrorMatches,
   161  		`unclosed file descriptor 3 \(open "/some/path" O_RDWR 0\)`)
   162  }
   163  
   164  func (s *lowLevelSuite) TestUnopenedFile(c *check.C) {
   165  	// Closing unopened file descriptors is an error.
   166  	err := s.sys.Close(7)
   167  	c.Assert(err, check.ErrorMatches, "attempting to close a closed file descriptor 7")
   168  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`close 7`})
   169  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   170  		{C: `close 7`, E: fmt.Errorf("attempting to close a closed file descriptor 7")},
   171  	})
   172  }
   173  
   174  func (s *lowLevelSuite) TestCloseSuccess(c *check.C) {
   175  	// Closing file descriptors handles the bookkeeping.
   176  	fd, err := s.sys.Open("/some/path", syscall.O_RDWR, 0)
   177  	c.Assert(err, check.IsNil)
   178  	err = s.sys.Close(fd)
   179  	c.Assert(err, check.IsNil)
   180  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   181  		`open "/some/path" O_RDWR 0`, // -> 3
   182  		`close 3`,
   183  	})
   184  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   185  		{C: `open "/some/path" O_RDWR 0`, R: 3},
   186  		{C: `close 3`},
   187  	})
   188  	c.Assert(s.sys.StrayDescriptorsError(), check.IsNil)
   189  }
   190  
   191  func (s *lowLevelSuite) TestCloseFailure(c *check.C) {
   192  	// Close can be made to fail just like any other function.
   193  	s.sys.InsertFault(`close 3`, syscall.ENOSYS)
   194  	err := s.sys.Close(3)
   195  	c.Assert(err, check.ErrorMatches, "function not implemented")
   196  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   197  		`close 3`,
   198  	})
   199  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   200  		{C: `close 3`, E: syscall.ENOSYS},
   201  	})
   202  }
   203  
   204  func (s *lowLevelSuite) TestOpenatSuccess(c *check.C) {
   205  	dirfd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   206  	c.Assert(err, check.IsNil)
   207  	fd, err := s.sys.Openat(dirfd, "foo", syscall.O_DIRECTORY, 0)
   208  	c.Assert(err, check.IsNil)
   209  	c.Assert(s.sys.Close(fd), check.IsNil)
   210  	c.Assert(s.sys.Close(dirfd), check.IsNil)
   211  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   212  		`open "/" O_DIRECTORY 0`,       // -> 3
   213  		`openat 3 "foo" O_DIRECTORY 0`, // -> 4
   214  		`close 4`,
   215  		`close 3`,
   216  	})
   217  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   218  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   219  		{C: `openat 3 "foo" O_DIRECTORY 0`, R: 4},
   220  		{C: `close 4`},
   221  		{C: `close 3`},
   222  	})
   223  }
   224  
   225  func (s *lowLevelSuite) TestOpenatFailure(c *check.C) {
   226  	dirfd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   227  	c.Assert(err, check.IsNil)
   228  	s.sys.InsertFault(`openat 3 "foo" O_DIRECTORY 0`, syscall.ENOENT)
   229  	fd, err := s.sys.Openat(dirfd, "foo", syscall.O_DIRECTORY, 0)
   230  	c.Assert(err, check.ErrorMatches, "no such file or directory")
   231  	c.Assert(fd, check.Equals, -1)
   232  	c.Assert(s.sys.Close(dirfd), check.IsNil)
   233  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   234  		`open "/" O_DIRECTORY 0`,       // -> 3
   235  		`openat 3 "foo" O_DIRECTORY 0`, // -> ENOENT
   236  		`close 3`,
   237  	})
   238  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   239  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   240  		{C: `openat 3 "foo" O_DIRECTORY 0`, E: syscall.ENOENT},
   241  		{C: `close 3`},
   242  	})
   243  }
   244  
   245  func (s *lowLevelSuite) TestOpenatBadFd(c *check.C) {
   246  	fd, err := s.sys.Openat(3, "foo", syscall.O_DIRECTORY, 0)
   247  	c.Assert(err, check.ErrorMatches, "attempting to openat with an invalid file descriptor 3")
   248  	c.Assert(fd, check.Equals, -1)
   249  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   250  		`openat 3 "foo" O_DIRECTORY 0`, // -> error
   251  	})
   252  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   253  		{C: `openat 3 "foo" O_DIRECTORY 0`, E: fmt.Errorf("attempting to openat with an invalid file descriptor 3")},
   254  	})
   255  }
   256  
   257  func (s *lowLevelSuite) TestFchownSuccess(c *check.C) {
   258  	fd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   259  	c.Assert(err, check.IsNil)
   260  	err = s.sys.Fchown(fd, 0, 0)
   261  	c.Assert(err, check.IsNil)
   262  	c.Assert(s.sys.Close(fd), check.IsNil)
   263  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   264  		`open "/" O_DIRECTORY 0`, // -> 3
   265  		`fchown 3 0 0`,
   266  		`close 3`,
   267  	})
   268  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   269  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   270  		{C: `fchown 3 0 0`},
   271  		{C: `close 3`},
   272  	})
   273  }
   274  
   275  func (s *lowLevelSuite) TestFchownFailure(c *check.C) {
   276  	fd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   277  	c.Assert(err, check.IsNil)
   278  	s.sys.InsertFault(`fchown 3 0 0`, syscall.EPERM)
   279  	err = s.sys.Fchown(fd, 0, 0)
   280  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   281  	c.Assert(s.sys.Close(fd), check.IsNil)
   282  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   283  		`open "/" O_DIRECTORY 0`, // -> 3
   284  		`fchown 3 0 0`,           // -> EPERM
   285  		`close 3`,
   286  	})
   287  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   288  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   289  		{C: `fchown 3 0 0`, E: syscall.EPERM},
   290  		{C: `close 3`},
   291  	})
   292  }
   293  
   294  func (s *lowLevelSuite) TestFchownBadFd(c *check.C) {
   295  	err := s.sys.Fchown(3, 0, 0)
   296  	c.Assert(err, check.ErrorMatches, "attempting to fchown an invalid file descriptor 3")
   297  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   298  		`fchown 3 0 0`,
   299  	})
   300  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   301  		{C: `fchown 3 0 0`, E: fmt.Errorf("attempting to fchown an invalid file descriptor 3")},
   302  	})
   303  }
   304  
   305  func (s *lowLevelSuite) TestMkdiratSuccess(c *check.C) {
   306  	fd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   307  	c.Assert(err, check.IsNil)
   308  	err = s.sys.Mkdirat(fd, "foo", 0755)
   309  	c.Assert(err, check.IsNil)
   310  	c.Assert(s.sys.Close(fd), check.IsNil)
   311  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   312  		`open "/" O_DIRECTORY 0`, // -> 3
   313  		`mkdirat 3 "foo" 0755`,
   314  		`close 3`,
   315  	})
   316  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   317  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   318  		{C: `mkdirat 3 "foo" 0755`},
   319  		{C: `close 3`},
   320  	})
   321  }
   322  
   323  func (s *lowLevelSuite) TestMkdiratFailure(c *check.C) {
   324  	fd, err := s.sys.Open("/", syscall.O_DIRECTORY, 0)
   325  	c.Assert(err, check.IsNil)
   326  	s.sys.InsertFault(`mkdirat 3 "foo" 0755`, syscall.EPERM)
   327  	err = s.sys.Mkdirat(fd, "foo", 0755)
   328  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   329  	c.Assert(s.sys.Close(fd), check.IsNil)
   330  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   331  		`open "/" O_DIRECTORY 0`, // -> 3
   332  		`mkdirat 3 "foo" 0755`,   // -> EPERM
   333  		`close 3`,
   334  	})
   335  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   336  		{C: `open "/" O_DIRECTORY 0`, R: 3},
   337  		{C: `mkdirat 3 "foo" 0755`, E: syscall.EPERM},
   338  		{C: `close 3`},
   339  	})
   340  }
   341  
   342  func (s *lowLevelSuite) TestMkdiratBadFd(c *check.C) {
   343  	err := s.sys.Mkdirat(3, "foo", 0755)
   344  	c.Assert(err, check.ErrorMatches, "attempting to mkdirat with an invalid file descriptor 3")
   345  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   346  		`mkdirat 3 "foo" 0755`,
   347  	})
   348  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   349  		{C: `mkdirat 3 "foo" 0755`, E: fmt.Errorf("attempting to mkdirat with an invalid file descriptor 3")},
   350  	})
   351  }
   352  
   353  func (s *lowLevelSuite) TestMountSuccess(c *check.C) {
   354  	err := s.sys.Mount("source", "target", "fstype", syscall.MS_BIND|syscall.MS_REC|syscall.MS_RDONLY, "")
   355  	c.Assert(err, check.IsNil)
   356  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   357  		`mount "source" "target" "fstype" MS_BIND|MS_REC|MS_RDONLY ""`,
   358  	})
   359  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   360  		{C: `mount "source" "target" "fstype" MS_BIND|MS_REC|MS_RDONLY ""`},
   361  	})
   362  }
   363  
   364  func (s *lowLevelSuite) TestMountPropagation(c *check.C) {
   365  	c.Assert(s.sys.Mount("", "target", "", syscall.MS_SHARED, ""), check.IsNil)
   366  	c.Assert(s.sys.Mount("", "target", "", syscall.MS_SLAVE, ""), check.IsNil)
   367  	c.Assert(s.sys.Mount("", "target", "", syscall.MS_PRIVATE, ""), check.IsNil)
   368  	c.Assert(s.sys.Mount("", "target", "", syscall.MS_UNBINDABLE, ""), check.IsNil)
   369  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   370  		`mount "" "target" "" MS_SHARED ""`,
   371  		`mount "" "target" "" MS_SLAVE ""`,
   372  		`mount "" "target" "" MS_PRIVATE ""`,
   373  		`mount "" "target" "" MS_UNBINDABLE ""`,
   374  	})
   375  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   376  		{C: `mount "" "target" "" MS_SHARED ""`},
   377  		{C: `mount "" "target" "" MS_SLAVE ""`},
   378  		{C: `mount "" "target" "" MS_PRIVATE ""`},
   379  		{C: `mount "" "target" "" MS_UNBINDABLE ""`},
   380  	})
   381  }
   382  
   383  func (s *lowLevelSuite) TestMountFailure(c *check.C) {
   384  	s.sys.InsertFault(`mount "source" "target" "fstype" 0 ""`, syscall.EPERM)
   385  	err := s.sys.Mount("source", "target", "fstype", 0, "")
   386  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   387  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   388  		`mount "source" "target" "fstype" 0 ""`,
   389  	})
   390  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   391  		{C: `mount "source" "target" "fstype" 0 ""`, E: syscall.EPERM},
   392  	})
   393  }
   394  
   395  func (s *lowLevelSuite) TestUnmountSuccess(c *check.C) {
   396  	err := s.sys.Unmount("target", testutil.UmountNoFollow|syscall.MNT_DETACH)
   397  	c.Assert(err, check.IsNil)
   398  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`unmount "target" UMOUNT_NOFOLLOW|MNT_DETACH`})
   399  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   400  		{C: `unmount "target" UMOUNT_NOFOLLOW|MNT_DETACH`},
   401  	})
   402  }
   403  
   404  func (s *lowLevelSuite) TestUnmountFailure(c *check.C) {
   405  	s.sys.InsertFault(`unmount "target" 0`, syscall.EPERM)
   406  	err := s.sys.Unmount("target", 0)
   407  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   408  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`unmount "target" 0`})
   409  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   410  		{C: `unmount "target" 0`, E: syscall.EPERM},
   411  	})
   412  }
   413  
   414  func (s *lowLevelSuite) TestOsLstat(c *check.C) {
   415  	// When a function returns some data it must be fed either an error or a result.
   416  	c.Assert(func() { s.sys.OsLstat("/foo") }, check.PanicMatches,
   417  		`one of InsertOsLstatResult\(\) or InsertFault\(\) for lstat "/foo" must be used`)
   418  }
   419  
   420  func (s *lowLevelSuite) TestOsLstatSuccess(c *check.C) {
   421  	// The fed data is returned in absence of errors.
   422  	s.sys.InsertOsLstatResult(`lstat "/foo"`, testutil.FileInfoFile)
   423  	fi, err := s.sys.OsLstat("/foo")
   424  	c.Assert(err, check.IsNil)
   425  	c.Assert(fi, check.DeepEquals, testutil.FileInfoFile)
   426  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`lstat "/foo"`})
   427  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   428  		{C: `lstat "/foo"`, R: testutil.FileInfoFile},
   429  	})
   430  }
   431  
   432  func (s *lowLevelSuite) TestOsLstatFailure(c *check.C) {
   433  	// Errors take priority over data.
   434  	s.sys.InsertOsLstatResult(`lstat "/foo"`, testutil.FileInfoFile)
   435  	s.sys.InsertFault(`lstat "/foo"`, syscall.ENOENT)
   436  	fi, err := s.sys.OsLstat("/foo")
   437  	c.Assert(err, check.ErrorMatches, "no such file or directory")
   438  	c.Assert(fi, check.IsNil)
   439  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`lstat "/foo"`})
   440  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   441  		{C: `lstat "/foo"`, E: syscall.ENOENT},
   442  	})
   443  }
   444  
   445  func (s *lowLevelSuite) TestSysLstat(c *check.C) {
   446  	// When a function returns some data it must be fed either an error or a result.
   447  	var buf syscall.Stat_t
   448  	c.Assert(func() { s.sys.SysLstat("/foo", &buf) }, check.PanicMatches,
   449  		`one of InsertSysLstatResult\(\) or InsertFault\(\) for lstat "/foo" <ptr> must be used`)
   450  }
   451  
   452  func (s *lowLevelSuite) TestSysLstatSuccess(c *check.C) {
   453  	// The fed data is returned in absence of errors.
   454  	var buf syscall.Stat_t
   455  	s.sys.InsertSysLstatResult(`lstat "/foo" <ptr>`, syscall.Stat_t{Uid: 123})
   456  	err := s.sys.SysLstat("/foo", &buf)
   457  	c.Assert(err, check.IsNil)
   458  	c.Assert(buf, check.DeepEquals, syscall.Stat_t{Uid: 123})
   459  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   460  		`lstat "/foo" <ptr>`,
   461  	})
   462  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   463  		{C: `lstat "/foo" <ptr>`, R: syscall.Stat_t{Uid: 123}},
   464  	})
   465  }
   466  
   467  func (s *lowLevelSuite) TestSysLstatFailure(c *check.C) {
   468  	// Errors take priority over data.
   469  	var buf syscall.Stat_t
   470  	s.sys.InsertSysLstatResult(`lstat "/foo" <ptr>`, syscall.Stat_t{Uid: 123})
   471  	s.sys.InsertFault(`lstat "/foo" <ptr>`, syscall.ENOENT)
   472  	err := s.sys.SysLstat("/foo", &buf)
   473  	c.Assert(err, check.ErrorMatches, "no such file or directory")
   474  	c.Assert(buf, check.DeepEquals, syscall.Stat_t{})
   475  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   476  		`lstat "/foo" <ptr>`, // -> ENOENT
   477  	})
   478  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   479  		{C: `lstat "/foo" <ptr>`, E: syscall.ENOENT},
   480  	})
   481  }
   482  
   483  func (s *lowLevelSuite) TestFstat(c *check.C) {
   484  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   485  	c.Assert(err, check.IsNil)
   486  	var buf syscall.Stat_t
   487  	c.Assert(func() { s.sys.Fstat(fd, &buf) }, check.PanicMatches,
   488  		`one of InsertFstatResult\(\) or InsertFault\(\) for fstat 3 <ptr> must be used`)
   489  }
   490  
   491  func (s *lowLevelSuite) TestFstatBadFd(c *check.C) {
   492  	var buf syscall.Stat_t
   493  	err := s.sys.Fstat(3, &buf)
   494  	c.Assert(err, check.ErrorMatches, "attempting to fstat with an invalid file descriptor 3")
   495  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   496  		`fstat 3 <ptr>`,
   497  	})
   498  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   499  		{C: `fstat 3 <ptr>`, E: fmt.Errorf("attempting to fstat with an invalid file descriptor 3")},
   500  	})
   501  }
   502  
   503  func (s *lowLevelSuite) TestFstatSuccess(c *check.C) {
   504  	s.sys.InsertFstatResult(`fstat 3 <ptr>`, syscall.Stat_t{Dev: 0xC0FE})
   505  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   506  	c.Assert(err, check.IsNil)
   507  	var buf syscall.Stat_t
   508  	err = s.sys.Fstat(fd, &buf)
   509  	c.Assert(err, check.IsNil)
   510  	c.Assert(buf, check.Equals, syscall.Stat_t{Dev: 0xC0FE})
   511  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   512  		`open "/foo" 0 0`, // -> 3
   513  		`fstat 3 <ptr>`,
   514  	})
   515  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   516  		{C: `open "/foo" 0 0`, R: 3},
   517  		{C: `fstat 3 <ptr>`, R: syscall.Stat_t{Dev: 0xC0FE}},
   518  	})
   519  }
   520  
   521  func (s *lowLevelSuite) TestFstatFailure(c *check.C) {
   522  	s.sys.InsertFault(`fstat 3 <ptr>`, syscall.EPERM)
   523  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   524  	c.Assert(err, check.IsNil)
   525  	var buf syscall.Stat_t
   526  	err = s.sys.Fstat(fd, &buf)
   527  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   528  	c.Assert(buf, check.Equals, syscall.Stat_t{})
   529  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   530  		`open "/foo" 0 0`, // -> 3
   531  		`fstat 3 <ptr>`,   // -> EPERM
   532  	})
   533  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   534  		{C: `open "/foo" 0 0`, R: 3},
   535  		{C: `fstat 3 <ptr>`, E: syscall.EPERM},
   536  	})
   537  }
   538  
   539  func (s *lowLevelSuite) TestFstatfs(c *check.C) {
   540  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   541  	c.Assert(err, check.IsNil)
   542  	var buf syscall.Statfs_t
   543  	c.Assert(func() { s.sys.Fstatfs(fd, &buf) }, check.PanicMatches,
   544  		`one of InsertFstatfsResult\(\) or InsertFault\(\) for fstatfs 3 <ptr> must be used`)
   545  }
   546  
   547  func (s *lowLevelSuite) TestFstatfsBadFd(c *check.C) {
   548  	var buf syscall.Statfs_t
   549  	err := s.sys.Fstatfs(3, &buf)
   550  	c.Assert(err, check.ErrorMatches, "attempting to fstatfs with an invalid file descriptor 3")
   551  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`fstatfs 3 <ptr>`})
   552  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   553  		{C: `fstatfs 3 <ptr>`, E: fmt.Errorf("attempting to fstatfs with an invalid file descriptor 3")},
   554  	})
   555  }
   556  
   557  func (s *lowLevelSuite) TestFstatfsSuccess(c *check.C) {
   558  	s.sys.InsertFstatfsResult(`fstatfs 3 <ptr>`, syscall.Statfs_t{Type: 0x123})
   559  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   560  	c.Assert(err, check.IsNil)
   561  	var buf syscall.Statfs_t
   562  	err = s.sys.Fstatfs(fd, &buf)
   563  	c.Assert(err, check.IsNil)
   564  	c.Assert(buf, check.Equals, syscall.Statfs_t{Type: 0x123})
   565  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   566  		`open "/foo" 0 0`, // -> 3
   567  		`fstatfs 3 <ptr>`, // -> Type: 0x123
   568  	})
   569  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   570  		{C: `open "/foo" 0 0`, R: 3},
   571  		{C: `fstatfs 3 <ptr>`, R: syscall.Statfs_t{Type: 0x123}},
   572  	})
   573  }
   574  
   575  func (s *lowLevelSuite) TestFstatfsChain(c *check.C) {
   576  	s.sys.InsertFstatfsResult(`fstatfs 3 <ptr>`,
   577  		syscall.Statfs_t{Type: 0x123}, syscall.Statfs_t{Type: 0x456})
   578  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   579  	c.Assert(err, check.IsNil)
   580  	var buf syscall.Statfs_t
   581  	err = s.sys.Fstatfs(fd, &buf)
   582  	c.Assert(err, check.IsNil)
   583  	c.Assert(buf, check.Equals, syscall.Statfs_t{Type: 0x123})
   584  	err = s.sys.Fstatfs(fd, &buf)
   585  	c.Assert(err, check.IsNil)
   586  	c.Assert(buf, check.Equals, syscall.Statfs_t{Type: 0x456})
   587  	err = s.sys.Fstatfs(fd, &buf)
   588  	c.Assert(err, check.IsNil)
   589  	c.Assert(buf, check.Equals, syscall.Statfs_t{Type: 0x456})
   590  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   591  		`open "/foo" 0 0`, // -> 3
   592  		`fstatfs 3 <ptr>`, // -> Type: 0x123
   593  		`fstatfs 3 <ptr>`, // -> Type: 0x456
   594  		`fstatfs 3 <ptr>`, // -> Type: 0x456
   595  	})
   596  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   597  		{C: `open "/foo" 0 0`, R: 3},
   598  		{C: `fstatfs 3 <ptr>`, R: syscall.Statfs_t{Type: 0x123}},
   599  		{C: `fstatfs 3 <ptr>`, R: syscall.Statfs_t{Type: 0x456}},
   600  		{C: `fstatfs 3 <ptr>`, R: syscall.Statfs_t{Type: 0x456}},
   601  	})
   602  }
   603  
   604  func (s *lowLevelSuite) TestFstatfsFailure(c *check.C) {
   605  	s.sys.InsertFault(`fstatfs 3 <ptr>`, syscall.EPERM)
   606  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   607  	c.Assert(err, check.IsNil)
   608  	var buf syscall.Statfs_t
   609  	err = s.sys.Fstatfs(fd, &buf)
   610  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   611  	c.Assert(buf, check.Equals, syscall.Statfs_t{})
   612  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   613  		`open "/foo" 0 0`, // -> 3
   614  		`fstatfs 3 <ptr>`, // -> EPERM
   615  	})
   616  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   617  		{C: `open "/foo" 0 0`, R: 3},
   618  		{C: `fstatfs 3 <ptr>`, E: syscall.EPERM},
   619  	})
   620  }
   621  
   622  func (s *lowLevelSuite) TestReadDir(c *check.C) {
   623  	c.Assert(func() { s.sys.ReadDir("/foo") }, check.PanicMatches,
   624  		`one of InsertReadDirResult\(\) or InsertFault\(\) for readdir "/foo" must be used`)
   625  }
   626  
   627  func (s *lowLevelSuite) TestReadDirSuccess(c *check.C) {
   628  	files := []os.FileInfo{
   629  		testutil.FakeFileInfo("file", 0644),
   630  		testutil.FakeFileInfo("dir", 0755|os.ModeDir),
   631  	}
   632  	s.sys.InsertReadDirResult(`readdir "/foo"`, files)
   633  	files, err := s.sys.ReadDir("/foo")
   634  	c.Assert(err, check.IsNil)
   635  	c.Assert(files, check.HasLen, 2)
   636  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   637  		`readdir "/foo"`,
   638  	})
   639  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   640  		{C: `readdir "/foo"`, R: files},
   641  	})
   642  }
   643  
   644  func (s *lowLevelSuite) TestReadDirFailure(c *check.C) {
   645  	s.sys.InsertFault(`readdir "/foo"`, syscall.ENOENT)
   646  	files, err := s.sys.ReadDir("/foo")
   647  	c.Assert(err, check.ErrorMatches, "no such file or directory")
   648  	c.Assert(files, check.IsNil)
   649  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   650  		`readdir "/foo"`, // -> ENOENT
   651  	})
   652  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   653  		{C: `readdir "/foo"`, E: syscall.ENOENT},
   654  	})
   655  }
   656  
   657  func (s *lowLevelSuite) TestSymlinkSuccess(c *check.C) {
   658  	err := s.sys.Symlink("oldname", "newname")
   659  	c.Assert(err, check.IsNil)
   660  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   661  		`symlink "newname" -> "oldname"`,
   662  	})
   663  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   664  		{C: `symlink "newname" -> "oldname"`},
   665  	})
   666  }
   667  
   668  func (s *lowLevelSuite) TestSymlinkFailure(c *check.C) {
   669  	s.sys.InsertFault(`symlink "newname" -> "oldname"`, syscall.EPERM)
   670  	err := s.sys.Symlink("oldname", "newname")
   671  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   672  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   673  		`symlink "newname" -> "oldname"`, // -> EPERM
   674  	})
   675  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   676  		{C: `symlink "newname" -> "oldname"`, E: syscall.EPERM},
   677  	})
   678  }
   679  
   680  func (s *lowLevelSuite) TestRemoveSuccess(c *check.C) {
   681  	err := s.sys.Remove("file")
   682  	c.Assert(err, check.IsNil)
   683  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   684  		`remove "file"`,
   685  	})
   686  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   687  		{C: `remove "file"`},
   688  	})
   689  }
   690  
   691  func (s *lowLevelSuite) TestRemoveFailure(c *check.C) {
   692  	s.sys.InsertFault(`remove "file"`, syscall.EPERM)
   693  	err := s.sys.Remove("file")
   694  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   695  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{`remove "file"`})
   696  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   697  		`remove "file"`, // -> EPERM
   698  	})
   699  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   700  		{C: `remove "file"`, E: syscall.EPERM},
   701  	})
   702  }
   703  
   704  func (s *lowLevelSuite) TestSymlinkatBadFd(c *check.C) {
   705  	err := s.sys.Symlinkat("/old", 3, "new")
   706  	c.Assert(err, check.ErrorMatches, "attempting to symlinkat with an invalid file descriptor 3")
   707  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   708  		`symlinkat "/old" 3 "new"`,
   709  	})
   710  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   711  		{C: `symlinkat "/old" 3 "new"`, E: fmt.Errorf("attempting to symlinkat with an invalid file descriptor 3")},
   712  	})
   713  }
   714  
   715  func (s *lowLevelSuite) TestSymlinkatSuccess(c *check.C) {
   716  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   717  	c.Assert(err, check.IsNil)
   718  	err = s.sys.Symlinkat("/old", fd, "new")
   719  	c.Assert(err, check.IsNil)
   720  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   721  		`open "/foo" 0 0`,
   722  		`symlinkat "/old" 3 "new"`,
   723  	})
   724  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   725  		{C: `open "/foo" 0 0`, R: 3},
   726  		{C: `symlinkat "/old" 3 "new"`},
   727  	})
   728  }
   729  
   730  func (s *lowLevelSuite) TestSymlinkatFailure(c *check.C) {
   731  	s.sys.InsertFault(`symlinkat "/old" 3 "new"`, syscall.EPERM)
   732  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   733  	c.Assert(err, check.IsNil)
   734  	err = s.sys.Symlinkat("/old", fd, "new")
   735  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   736  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   737  		`open "/foo" 0 0`, // -> 3
   738  		`symlinkat "/old" 3 "new"`,
   739  	})
   740  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   741  		{C: `open "/foo" 0 0`, R: 3},
   742  		{C: `symlinkat "/old" 3 "new"`, E: syscall.EPERM},
   743  	})
   744  }
   745  
   746  func (s *lowLevelSuite) TestReadlinkat(c *check.C) {
   747  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   748  	c.Assert(err, check.IsNil)
   749  	buf := make([]byte, 10)
   750  	c.Assert(func() { s.sys.Readlinkat(fd, "new", buf) }, check.PanicMatches,
   751  		`one of InsertReadlinkatResult\(\) or InsertFault\(\) for readlinkat 3 "new" <ptr> must be used`)
   752  }
   753  
   754  func (s *lowLevelSuite) TestReadlinkatBadFd(c *check.C) {
   755  	buf := make([]byte, 10)
   756  	n, err := s.sys.Readlinkat(3, "new", buf)
   757  	c.Assert(err, check.ErrorMatches, "attempting to readlinkat with an invalid file descriptor 3")
   758  	c.Assert(n, check.Equals, 0)
   759  	c.Assert(s.sys.Calls(), check.DeepEquals, []string{
   760  		`readlinkat 3 "new" <ptr>`,
   761  	})
   762  	c.Assert(s.sys.RCalls(), check.DeepEquals, []testutil.CallResultError{
   763  		{C: `readlinkat 3 "new" <ptr>`, E: fmt.Errorf("attempting to readlinkat with an invalid file descriptor 3")},
   764  	})
   765  }
   766  
   767  func (s *lowLevelSuite) TestReadlinkatSuccess(c *check.C) {
   768  	s.sys.InsertReadlinkatResult(`readlinkat 3 "new" <ptr>`, "/old")
   769  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   770  	c.Assert(err, check.IsNil)
   771  
   772  	// Buffer has enough room
   773  	buf := make([]byte, 10)
   774  	n, err := s.sys.Readlinkat(fd, "new", buf)
   775  	c.Assert(err, check.IsNil)
   776  	c.Assert(n, check.Equals, 4)
   777  	c.Assert(buf, check.DeepEquals, []byte{'/', 'o', 'l', 'd', 0, 0, 0, 0, 0, 0})
   778  
   779  	// Buffer is too short
   780  	buf = make([]byte, 2)
   781  	n, err = s.sys.Readlinkat(fd, "new", buf)
   782  	c.Assert(err, check.IsNil)
   783  	c.Assert(n, check.Equals, 2)
   784  	c.Assert(buf, check.DeepEquals, []byte{'/', 'o'})
   785  }
   786  
   787  func (s *lowLevelSuite) TestReadlinkatFailure(c *check.C) {
   788  	s.sys.InsertFault(`readlinkat 3 "new" <ptr>`, syscall.EPERM)
   789  	fd, err := s.sys.Open("/foo", syscall.O_RDONLY, 0)
   790  	c.Assert(err, check.IsNil)
   791  
   792  	buf := make([]byte, 10)
   793  	n, err := s.sys.Readlinkat(fd, "new", buf)
   794  	c.Assert(err, check.ErrorMatches, "operation not permitted")
   795  	c.Assert(n, check.Equals, 0)
   796  	c.Assert(buf, check.DeepEquals, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
   797  }