summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/pipe/node_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/kernel/pipe/node_test.go')
-rw-r--r--pkg/sentry/kernel/pipe/node_test.go320
1 files changed, 0 insertions, 320 deletions
diff --git a/pkg/sentry/kernel/pipe/node_test.go b/pkg/sentry/kernel/pipe/node_test.go
deleted file mode 100644
index adbad7764..000000000
--- a/pkg/sentry/kernel/pipe/node_test.go
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package pipe
-
-import (
- "testing"
- "time"
-
- "gvisor.dev/gvisor/pkg/sentry/context"
- "gvisor.dev/gvisor/pkg/sentry/context/contexttest"
- "gvisor.dev/gvisor/pkg/sentry/fs"
- "gvisor.dev/gvisor/pkg/sentry/usermem"
- "gvisor.dev/gvisor/pkg/syserror"
-)
-
-type sleeper struct {
- context.Context
- ch chan struct{}
-}
-
-func newSleeperContext(t *testing.T) context.Context {
- return &sleeper{
- Context: contexttest.Context(t),
- ch: make(chan struct{}),
- }
-}
-
-func (s *sleeper) SleepStart() <-chan struct{} {
- return s.ch
-}
-
-func (s *sleeper) SleepFinish(bool) {
-}
-
-func (s *sleeper) Cancel() {
- s.ch <- struct{}{}
-}
-
-func (s *sleeper) Interrupted() bool {
- return len(s.ch) != 0
-}
-
-type openResult struct {
- *fs.File
- error
-}
-
-var perms fs.FilePermissions = fs.FilePermissions{
- User: fs.PermMask{Read: true, Write: true},
-}
-
-func testOpenOrDie(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, doneChan chan<- struct{}) (*fs.File, error) {
- inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe})
- d := fs.NewDirent(ctx, inode, "pipe")
- file, err := n.GetFile(ctx, d, flags)
- if err != nil {
- t.Fatalf("open with flags %+v failed: %v", flags, err)
- }
- if doneChan != nil {
- doneChan <- struct{}{}
- }
- return file, err
-}
-
-func testOpen(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, resChan chan<- openResult) (*fs.File, error) {
- inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe})
- d := fs.NewDirent(ctx, inode, "pipe")
- file, err := n.GetFile(ctx, d, flags)
- if resChan != nil {
- resChan <- openResult{file, err}
- }
- return file, err
-}
-
-func newNamedPipe(t *testing.T) *Pipe {
- return NewPipe(contexttest.Context(t), true, DefaultPipeSize, usermem.PageSize)
-}
-
-func newAnonPipe(t *testing.T) *Pipe {
- return NewPipe(contexttest.Context(t), false, DefaultPipeSize, usermem.PageSize)
-}
-
-// assertRecvBlocks ensures that a recv attempt on c blocks for at least
-// blockDuration. This is useful for checking that a goroutine that is supposed
-// to be executing a blocking operation is actually blocking.
-func assertRecvBlocks(t *testing.T, c <-chan struct{}, blockDuration time.Duration, failMsg string) {
- select {
- case <-c:
- t.Fatalf(failMsg)
- case <-time.After(blockDuration):
- // Ok, blocked for the required duration.
- }
-}
-
-func TestReadOpenBlocksForWriteOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone)
-
- // Verify that the open for read is blocking.
- assertRecvBlocks(t, rDone, time.Millisecond*100,
- "open for read not blocking with no writers")
-
- wDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
-
- <-wDone
- <-rDone
-}
-
-func TestWriteOpenBlocksForReadOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- wDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
-
- // Verify that the open for write is blocking
- assertRecvBlocks(t, wDone, time.Millisecond*100,
- "open for write not blocking with no readers")
-
- rDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone)
-
- <-rDone
- <-wDone
-}
-
-func TestMultipleWriteOpenDoesntCountAsReadOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rDone1 := make(chan struct{})
- rDone2 := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone1)
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone2)
-
- assertRecvBlocks(t, rDone1, time.Millisecond*100,
- "open for read didn't block with no writers")
- assertRecvBlocks(t, rDone2, time.Millisecond*100,
- "open for read didn't block with no writers")
-
- wDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
-
- <-wDone
- <-rDone2
- <-rDone1
-}
-
-func TestClosedReaderBlocksWriteOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rFile, _ := testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true, NonBlocking: true}, nil)
- rFile.DecRef()
-
- wDone := make(chan struct{})
- // This open for write should block because the reader is now gone.
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
- assertRecvBlocks(t, wDone, time.Millisecond*100,
- "open for write didn't block with no concurrent readers")
-
- // Open for read again. This should unblock the open for write.
- rDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone)
-
- <-rDone
- <-wDone
-}
-
-func TestReadWriteOpenNeverBlocks(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rwDone := make(chan struct{})
- // Open for read-write never wait for a reader or writer, even if the
- // nonblocking flag is not set.
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true, Write: true, NonBlocking: false}, rwDone)
- <-rwDone
-}
-
-func TestReadWriteOpenUnblocksReadOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone)
-
- rwDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true, Write: true}, rwDone)
-
- <-rwDone
- <-rDone
-}
-
-func TestReadWriteOpenUnblocksWriteOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- wDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
-
- rwDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true, Write: true}, rwDone)
-
- <-rwDone
- <-wDone
-}
-
-func TestBlockedOpenIsCancellable(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- done := make(chan openResult)
- go testOpen(ctx, t, f, fs.FileFlags{Read: true}, done)
- select {
- case <-done:
- t.Fatalf("open for read didn't block with no writers")
- case <-time.After(time.Millisecond * 100):
- // Ok.
- }
-
- ctx.(*sleeper).Cancel()
- // If the cancel on the sleeper didn't work, the open for read would never
- // return.
- res := <-done
- if res.error != syserror.ErrInterrupted {
- t.Fatalf("Cancellation didn't cause GetFile to return fs.ErrInterrupted, got %v.",
- res.error)
- }
-}
-
-func TestNonblockingReadOpenFileNoWriters(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Read: true, NonBlocking: true}, nil); err != nil {
- t.Fatalf("Nonblocking open for read failed with error %v.", err)
- }
-}
-
-func TestNonblockingWriteOpenFileNoReaders(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Write: true, NonBlocking: true}, nil); err != syserror.ENXIO {
- t.Fatalf("Nonblocking open for write failed unexpected error %v.", err)
- }
-}
-
-func TestNonBlockingReadOpenWithWriter(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- wDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Write: true}, wDone)
-
- // Open for write blocks since there are no readers yet.
- assertRecvBlocks(t, wDone, time.Millisecond*100,
- "Open for write didn't block with no reader.")
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Read: true, NonBlocking: true}, nil); err != nil {
- t.Fatalf("Nonblocking open for read failed with error %v.", err)
- }
-
- // Open for write should now be unblocked.
- <-wDone
-}
-
-func TestNonBlockingWriteOpenWithReader(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newNamedPipe(t))
-
- rDone := make(chan struct{})
- go testOpenOrDie(ctx, t, f, fs.FileFlags{Read: true}, rDone)
-
- // Open for write blocked, since no reader yet.
- assertRecvBlocks(t, rDone, time.Millisecond*100,
- "Open for reader didn't block with no writer.")
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Write: true, NonBlocking: true}, nil); err != nil {
- t.Fatalf("Nonblocking open for write failed with error %v.", err)
- }
-
- // Open for write should now be unblocked.
- <-rDone
-}
-
-func TestAnonReadOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newAnonPipe(t))
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Read: true}, nil); err != nil {
- t.Fatalf("open anon pipe for read failed: %v", err)
- }
-}
-
-func TestAnonWriteOpen(t *testing.T) {
- ctx := newSleeperContext(t)
- f := NewInodeOperations(ctx, perms, newAnonPipe(t))
-
- if _, err := testOpen(ctx, t, f, fs.FileFlags{Write: true}, nil); err != nil {
- t.Fatalf("open anon pipe for write failed: %v", err)
- }
-}