github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/sys/sys_test.go (about)

     1  package sys
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  	"time"
     7  
     8  	experimentalsys "github.com/wasilibs/wazerox/experimental/sys"
     9  	"github.com/wasilibs/wazerox/internal/fstest"
    10  	"github.com/wasilibs/wazerox/internal/platform"
    11  	"github.com/wasilibs/wazerox/internal/sysfs"
    12  	"github.com/wasilibs/wazerox/internal/testing/require"
    13  	"github.com/wasilibs/wazerox/sys"
    14  )
    15  
    16  func TestContext_WalltimeNanos(t *testing.T) {
    17  	sysCtx := DefaultContext(nil)
    18  
    19  	require.Equal(t, int64(1640995200000000000), sysCtx.WalltimeNanos())
    20  }
    21  
    22  func TestDefaultSysContext(t *testing.T) {
    23  	testFS := &sysfs.AdaptFS{FS: fstest.FS}
    24  
    25  	sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{testFS}, []string{"/"}, nil)
    26  	require.NoError(t, err)
    27  
    28  	require.Nil(t, sysCtx.Args())
    29  	require.Zero(t, sysCtx.ArgsSize())
    30  	require.Nil(t, sysCtx.Environ())
    31  	require.Zero(t, sysCtx.EnvironSize())
    32  	// To compare functions, we can only compare pointers, but the pointer will
    33  	// change. Hence, we have to compare the results instead.
    34  	sec, _ := sysCtx.Walltime()
    35  	require.Equal(t, platform.FakeEpochNanos/time.Second.Nanoseconds(), sec)
    36  	require.Equal(t, sys.ClockResolution(1_000), sysCtx.WalltimeResolution())
    37  	require.Zero(t, sysCtx.Nanotime()) // See above on functions.
    38  	require.Equal(t, sys.ClockResolution(1), sysCtx.NanotimeResolution())
    39  	require.Equal(t, platform.FakeNanosleep, sysCtx.nanosleep)
    40  	require.Equal(t, platform.NewFakeRandSource(), sysCtx.RandSource())
    41  
    42  	expected := FileTable{}
    43  	noopStdin, _ := stdinFileEntry(nil)
    44  	expected.Insert(noopStdin)
    45  	noopStdout, _ := stdioWriterFileEntry("stdout", nil)
    46  	expected.Insert(noopStdout)
    47  	noopStderr, _ := stdioWriterFileEntry("stderr", nil)
    48  	expected.Insert(noopStderr)
    49  	expected.Insert(&FileEntry{
    50  		IsPreopen: true,
    51  		Name:      "/",
    52  		FS:        testFS,
    53  		File:      &lazyDir{fs: testFS},
    54  	})
    55  	require.Equal(t, expected, sysCtx.FS().openedFiles)
    56  }
    57  
    58  func TestNewContext_Args(t *testing.T) {
    59  	tests := []struct {
    60  		name         string
    61  		args         [][]byte
    62  		maxSize      uint32
    63  		expectedSize uint32
    64  		expectedErr  string
    65  	}{
    66  		{
    67  			name:         "ok",
    68  			maxSize:      10,
    69  			args:         [][]byte{[]byte("a"), []byte("bc")},
    70  			expectedSize: 5,
    71  		},
    72  		{
    73  			name:        "exceeds max count",
    74  			maxSize:     1,
    75  			args:        [][]byte{[]byte("a"), []byte("bc")},
    76  			expectedErr: "args invalid: exceeds maximum count",
    77  		},
    78  		{
    79  			name:        "exceeds max size",
    80  			maxSize:     4,
    81  			args:        [][]byte{[]byte("a"), []byte("bc")},
    82  			expectedErr: "args invalid: exceeds maximum size",
    83  		},
    84  		{
    85  			name:        "null character",
    86  			maxSize:     10,
    87  			args:        [][]byte{[]byte("a"), {'b', 0}},
    88  			expectedErr: "args invalid: contains NUL character",
    89  		},
    90  	}
    91  
    92  	for _, tt := range tests {
    93  		tc := tt
    94  
    95  		t.Run(tc.name, func(t *testing.T) {
    96  			sysCtx, err := NewContext(tc.maxSize, tc.args, nil, bytes.NewReader(make([]byte, 0)), nil, nil, nil, nil, 0, nil, 0, nil, nil, nil, nil, nil)
    97  			if tc.expectedErr == "" {
    98  				require.Nil(t, err)
    99  				require.Equal(t, tc.args, sysCtx.Args())
   100  				require.Equal(t, tc.expectedSize, sysCtx.ArgsSize())
   101  			} else {
   102  				require.EqualError(t, err, tc.expectedErr)
   103  			}
   104  		})
   105  	}
   106  }
   107  
   108  func TestNewContext_Environ(t *testing.T) {
   109  	tests := []struct {
   110  		name         string
   111  		environ      [][]byte
   112  		maxSize      uint32
   113  		expectedSize uint32
   114  		expectedErr  string
   115  	}{
   116  		{
   117  			name:         "ok",
   118  			maxSize:      10,
   119  			environ:      [][]byte{[]byte("a=b"), []byte("c=de")},
   120  			expectedSize: 9,
   121  		},
   122  		{
   123  			name:        "exceeds max count",
   124  			maxSize:     1,
   125  			environ:     [][]byte{[]byte("a=b"), []byte("c=de")},
   126  			expectedErr: "environ invalid: exceeds maximum count",
   127  		},
   128  		{
   129  			name:        "exceeds max size",
   130  			maxSize:     4,
   131  			environ:     [][]byte{[]byte("a=b"), []byte("c=de")},
   132  			expectedErr: "environ invalid: exceeds maximum size",
   133  		},
   134  		{
   135  			name:        "null character",
   136  			maxSize:     10,
   137  			environ:     [][]byte{[]byte("a=b"), append([]byte("c=d"), 0)},
   138  			expectedErr: "environ invalid: contains NUL character",
   139  		},
   140  	}
   141  
   142  	for _, tt := range tests {
   143  		tc := tt
   144  
   145  		t.Run(tc.name, func(t *testing.T) {
   146  			sysCtx, err := NewContext(tc.maxSize, nil, tc.environ, bytes.NewReader(make([]byte, 0)), nil, nil, nil, nil, 0, nil, 0, nil, nil, nil, nil, nil)
   147  			if tc.expectedErr == "" {
   148  				require.Nil(t, err)
   149  				require.Equal(t, tc.environ, sysCtx.Environ())
   150  				require.Equal(t, tc.expectedSize, sysCtx.EnvironSize())
   151  			} else {
   152  				require.EqualError(t, err, tc.expectedErr)
   153  			}
   154  		})
   155  	}
   156  }
   157  
   158  func TestNewContext_Walltime(t *testing.T) {
   159  	tests := []struct {
   160  		name        string
   161  		time        sys.Walltime
   162  		resolution  sys.ClockResolution
   163  		expectedErr string
   164  	}{
   165  		{
   166  			name:       "ok",
   167  			time:       platform.NewFakeWalltime(),
   168  			resolution: 3,
   169  		},
   170  		{
   171  			name:        "invalid resolution",
   172  			time:        platform.NewFakeWalltime(),
   173  			resolution:  0,
   174  			expectedErr: "invalid Walltime resolution: 0",
   175  		},
   176  	}
   177  
   178  	for _, tt := range tests {
   179  		tc := tt
   180  
   181  		t.Run(tc.name, func(t *testing.T) {
   182  			sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, tc.time, tc.resolution, nil, 0, nil, nil, nil, nil, nil)
   183  			if tc.expectedErr == "" {
   184  				require.Nil(t, err)
   185  				require.Equal(t, tc.time, sysCtx.walltime)
   186  				require.Equal(t, tc.resolution, sysCtx.WalltimeResolution())
   187  			} else {
   188  				require.EqualError(t, err, tc.expectedErr)
   189  			}
   190  		})
   191  	}
   192  }
   193  
   194  func TestNewContext_Nanotime(t *testing.T) {
   195  	tests := []struct {
   196  		name        string
   197  		time        sys.Nanotime
   198  		resolution  sys.ClockResolution
   199  		expectedErr string
   200  	}{
   201  		{
   202  			name:       "ok",
   203  			time:       platform.NewFakeNanotime(),
   204  			resolution: 3,
   205  		},
   206  		{
   207  			name:        "invalid resolution",
   208  			time:        platform.NewFakeNanotime(),
   209  			resolution:  0,
   210  			expectedErr: "invalid Nanotime resolution: 0",
   211  		},
   212  	}
   213  
   214  	for _, tt := range tests {
   215  		tc := tt
   216  
   217  		t.Run(tc.name, func(t *testing.T) {
   218  			sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, tc.time, tc.resolution, nil, nil, nil, nil, nil)
   219  			if tc.expectedErr == "" {
   220  				require.Nil(t, err)
   221  				require.Equal(t, tc.time, sysCtx.nanotime)
   222  				require.Equal(t, tc.resolution, sysCtx.NanotimeResolution())
   223  			} else {
   224  				require.EqualError(t, err, tc.expectedErr)
   225  			}
   226  		})
   227  	}
   228  }
   229  
   230  func Test_clockResolutionInvalid(t *testing.T) {
   231  	tests := []struct {
   232  		name       string
   233  		resolution sys.ClockResolution
   234  		expected   bool
   235  	}{
   236  		{
   237  			name:       "ok",
   238  			resolution: 1,
   239  		},
   240  		{
   241  			name:       "zero",
   242  			resolution: 0,
   243  			expected:   true,
   244  		},
   245  		{
   246  			name:       "too big",
   247  			resolution: sys.ClockResolution(time.Hour.Nanoseconds() * 2),
   248  			expected:   true,
   249  		},
   250  	}
   251  
   252  	for _, tt := range tests {
   253  		tc := tt
   254  
   255  		t.Run(tc.name, func(t *testing.T) {
   256  			require.Equal(t, tc.expected, clockResolutionInvalid(tc.resolution))
   257  		})
   258  	}
   259  }
   260  
   261  func TestNewContext_Nanosleep(t *testing.T) {
   262  	var aNs sys.Nanosleep = func(int64) {}
   263  	sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, aNs, nil, nil, nil, nil)
   264  	require.Nil(t, err)
   265  	require.Equal(t, aNs, sysCtx.nanosleep)
   266  }
   267  
   268  func TestNewContext_Osyield(t *testing.T) {
   269  	var oy sys.Osyield = func() {}
   270  	sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, oy, nil, nil, nil)
   271  	require.Nil(t, err)
   272  	require.Equal(t, oy, sysCtx.osyield)
   273  }