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 }