...

Source file src/github.com/containerd/fifo/raw_test.go

Documentation: github.com/containerd/fifo

     1  //go:build !windows
     2  
     3  /*
     4     Copyright The containerd Authors.
     5  
     6     Licensed under the Apache License, Version 2.0 (the "License");
     7     you may not use this file except in compliance with the License.
     8     You may obtain a copy of the License at
     9  
    10         http://www.apache.org/licenses/LICENSE-2.0
    11  
    12     Unless required by applicable law or agreed to in writing, software
    13     distributed under the License is distributed on an "AS IS" BASIS,
    14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15     See the License for the specific language governing permissions and
    16     limitations under the License.
    17  */
    18  
    19  package fifo
    20  
    21  import (
    22  	"bytes"
    23  	"context"
    24  	"io"
    25  	"os"
    26  	"path"
    27  	"path/filepath"
    28  	"syscall"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  func TestRawReadWrite(t *testing.T) {
    36  	tmpdir, err := os.MkdirTemp("", "fifos")
    37  	assert.NoError(t, err)
    38  	defer os.RemoveAll(tmpdir)
    39  
    40  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    41  	defer cancel()
    42  
    43  	r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
    44  	assert.NoError(t, err)
    45  	defer r.Close()
    46  	rawR := makeRawConn(t, r, false)
    47  	assert.Error(t, rawR.Write(func(uintptr) bool { return true }))
    48  
    49  	w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
    50  	assert.NoError(t, err)
    51  	defer w.Close()
    52  	rawW := makeRawConn(t, w, false)
    53  	assert.Error(t, rawW.Read(func(uintptr) bool { return true }))
    54  
    55  	data := []byte("hello world")
    56  	rawWrite(t, rawW, data)
    57  
    58  	dataR := make([]byte, len(data))
    59  	rawRead(t, rawR, dataR)
    60  	assert.True(t, bytes.Equal(data, dataR))
    61  }
    62  
    63  func TestRawWriteUserRead(t *testing.T) {
    64  	tmpdir, err := os.MkdirTemp("", "fifos")
    65  	assert.NoError(t, err)
    66  	defer os.RemoveAll(tmpdir)
    67  
    68  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    69  	defer cancel()
    70  
    71  	w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
    72  	assert.NoError(t, err)
    73  	defer w.Close()
    74  	rawW := makeRawConn(t, w, false)
    75  
    76  	r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
    77  	assert.NoError(t, err)
    78  	defer r.Close()
    79  
    80  	data := []byte("hello world!")
    81  	rawWrite(t, rawW, data)
    82  	w.Close()
    83  
    84  	buf := make([]byte, len(data))
    85  	n, err := io.ReadFull(r, buf)
    86  	assert.NoError(t, err)
    87  	assert.True(t, bytes.Equal(data, buf[:n]))
    88  }
    89  
    90  func TestUserWriteRawRead(t *testing.T) {
    91  	tmpdir, err := os.MkdirTemp("", "fifos")
    92  	assert.NoError(t, err)
    93  	defer os.RemoveAll(tmpdir)
    94  
    95  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    96  	defer cancel()
    97  
    98  	w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
    99  	assert.NoError(t, err)
   100  	defer w.Close()
   101  
   102  	r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
   103  	assert.NoError(t, err)
   104  	defer r.Close()
   105  	rawR := makeRawConn(t, r, false)
   106  
   107  	data := []byte("hello world!")
   108  	n, err := w.Write(data)
   109  	assert.NoError(t, err)
   110  	assert.Equal(t, n, len(data))
   111  	w.Close()
   112  
   113  	buf := make([]byte, len(data))
   114  	rawRead(t, rawR, buf)
   115  	assert.True(t, bytes.Equal(data, buf[:n]))
   116  }
   117  
   118  func TestRawCloseError(t *testing.T) {
   119  	tmpdir, err := os.MkdirTemp("", "fifos")
   120  	assert.NoError(t, err)
   121  	defer os.RemoveAll(tmpdir)
   122  
   123  	t.Run("SyscallConnAfterClose", func(t *testing.T) {
   124  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   125  		defer cancel()
   126  
   127  		f, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDWR|syscall.O_CREAT, 0600)
   128  		assert.NoError(t, err)
   129  
   130  		f.Close()
   131  
   132  		makeRawConn(t, f, true)
   133  	})
   134  
   135  	t.Run("RawOpsAfterClose", func(t *testing.T) {
   136  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   137  		defer cancel()
   138  		f, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDWR|syscall.O_CREAT, 0600)
   139  		assert.NoError(t, err)
   140  		defer f.Close()
   141  
   142  		raw := makeRawConn(t, f, false)
   143  
   144  		f.Close()
   145  
   146  		assert.Error(t, raw.Control(func(uintptr) {}))
   147  		dummy := func(uintptr) bool { return true }
   148  		assert.Error(t, raw.Write(dummy))
   149  		assert.Error(t, raw.Read(dummy))
   150  	})
   151  
   152  	t.Run("NonBlockRawOpsAfterClose", func(t *testing.T) {
   153  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   154  		defer cancel()
   155  		dummy := func(uintptr) bool { return true }
   156  		r, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
   157  		assert.NoError(t, err)
   158  		defer r.Close()
   159  		rawR := makeRawConn(t, r, false)
   160  		r.Close()
   161  
   162  		assert.Equal(t, ErrCtrlClosed, rawR.Control(func(uintptr) {}))
   163  		assert.Equal(t, ErrReadClosed, rawR.Read(dummy))
   164  
   165  		w, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
   166  		assert.NoError(t, err)
   167  		defer w.Close()
   168  		rawW := makeRawConn(t, w, false)
   169  		w.Close()
   170  
   171  		assert.Equal(t, ErrCtrlClosed, rawW.Control(func(uintptr) {}))
   172  		assert.Equal(t, ErrWriteClosed, rawW.Write(dummy))
   173  	})
   174  }
   175  
   176  func TestRawWrongRdWrError(t *testing.T) {
   177  	tmpdir, err := os.MkdirTemp("", "fifos")
   178  	assert.NoError(t, err)
   179  	defer os.RemoveAll(tmpdir)
   180  
   181  	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   182  	defer cancel()
   183  	dummy := func(uintptr) bool { return true }
   184  	r, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
   185  	assert.NoError(t, err)
   186  	defer r.Close()
   187  	rawR := makeRawConn(t, r, false)
   188  
   189  	assert.Equal(t, ErrWrToRDONLY, rawR.Write(dummy))
   190  
   191  	w, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600)
   192  	assert.NoError(t, err)
   193  	defer w.Close()
   194  	rawW := makeRawConn(t, w, false)
   195  
   196  	assert.Equal(t, ErrRdFrmWRONLY, rawW.Read(dummy))
   197  }
   198  
   199  func makeRawConn(t *testing.T, fifo io.ReadWriteCloser, expectError bool) syscall.RawConn {
   200  	sc, ok := fifo.(syscall.Conn)
   201  	assert.True(t, ok, "not a syscall.Conn")
   202  
   203  	raw, err := sc.SyscallConn()
   204  	if !expectError {
   205  		assert.NoError(t, err)
   206  	} else {
   207  		assert.Error(t, err)
   208  	}
   209  
   210  	return raw
   211  }
   212  
   213  func rawWrite(t *testing.T, rc syscall.RawConn, data []byte) {
   214  	var written int
   215  	var wErr error
   216  
   217  	err := rc.Write(func(fd uintptr) bool {
   218  		var n int
   219  		n, wErr = syscall.Write(int(fd), data[written:])
   220  		written += n
   221  		if wErr != nil || n == 0 || written == len(data) {
   222  			return true
   223  		}
   224  		return false
   225  	})
   226  	assert.NoError(t, err)
   227  	assert.NoError(t, wErr)
   228  	assert.Equal(t, written, len(data))
   229  }
   230  
   231  func rawRead(t *testing.T, rc syscall.RawConn, data []byte) {
   232  	var (
   233  		rErr error
   234  		read int
   235  	)
   236  
   237  	err := rc.Read(func(fd uintptr) bool {
   238  		var n int
   239  		n, rErr = syscall.Read(int(fd), data[read:])
   240  		read += n
   241  		if rErr != nil || n == 0 || read == len(data) {
   242  			return true
   243  		}
   244  		return false
   245  	})
   246  	assert.NoError(t, err)
   247  	assert.NoError(t, rErr)
   248  	assert.Equal(t, read, len(data))
   249  }
   250  

View as plain text