Source file src/internal/runtime/wasitest/nonblock_test.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Not all systems have syscall.Mkfifo.
     6  //go:build !aix && !plan9 && !solaris && !wasm && !windows
     7  
     8  package wasi_test
     9  
    10  import (
    11  	"bufio"
    12  	"fmt"
    13  	"internal/testenv"
    14  	"io"
    15  	"math/rand"
    16  	"os"
    17  	"os/exec"
    18  	"path/filepath"
    19  	"syscall"
    20  	"testing"
    21  )
    22  
    23  // This test creates a set of FIFOs and writes to them in reverse order. It
    24  // checks that the output order matches the write order. The test binary opens
    25  // the FIFOs in their original order and spawns a goroutine for each that reads
    26  // from the FIFO and writes the result to stderr. If I/O was blocking, all
    27  // goroutines would be blocked waiting for one read call to return, and the
    28  // output order wouldn't match.
    29  
    30  type fifo struct {
    31  	file *os.File
    32  	path string
    33  }
    34  
    35  func TestNonblock(t *testing.T) {
    36  	if target != "wasip1/wasm" {
    37  		t.Skip()
    38  	}
    39  
    40  	switch os.Getenv("GOWASIRUNTIME") {
    41  	case "wasmer":
    42  		t.Skip("wasmer does not support non-blocking I/O")
    43  	}
    44  
    45  	testenv.MustHaveGoRun(t)
    46  
    47  	for _, mode := range []string{"os.OpenFile", "os.NewFile"} {
    48  		t.Run(mode, func(t *testing.T) {
    49  			args := []string{"run", "./testdata/nonblock.go", mode}
    50  
    51  			fifos := make([]*fifo, 8)
    52  			for i := range fifos {
    53  				path := filepath.Join(t.TempDir(), fmt.Sprintf("wasip1-nonblock-fifo-%d-%d", rand.Uint32(), i))
    54  				if err := syscall.Mkfifo(path, 0666); err != nil {
    55  					t.Fatal(err)
    56  				}
    57  
    58  				file, err := os.OpenFile(path, os.O_RDWR, 0)
    59  				if err != nil {
    60  					t.Fatal(err)
    61  				}
    62  				defer file.Close()
    63  
    64  				args = append(args, path)
    65  				fifos[len(fifos)-i-1] = &fifo{file, path}
    66  			}
    67  
    68  			subProcess := exec.Command(testenv.GoToolPath(t), args...)
    69  
    70  			subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
    71  
    72  			pr, pw := io.Pipe()
    73  			defer pw.Close()
    74  
    75  			subProcess.Stderr = pw
    76  
    77  			if err := subProcess.Start(); err != nil {
    78  				t.Fatal(err)
    79  			}
    80  
    81  			scanner := bufio.NewScanner(pr)
    82  			if !scanner.Scan() {
    83  				t.Fatal("expected line:", scanner.Err())
    84  			} else if scanner.Text() != "waiting" {
    85  				t.Fatal("unexpected output:", scanner.Text())
    86  			}
    87  
    88  			for _, fifo := range fifos {
    89  				if _, err := fifo.file.WriteString(fifo.path + "\n"); err != nil {
    90  					t.Fatal(err)
    91  				}
    92  				if !scanner.Scan() {
    93  					t.Fatal("expected line:", scanner.Err())
    94  				} else if scanner.Text() != fifo.path {
    95  					t.Fatal("unexpected line:", scanner.Text())
    96  				}
    97  			}
    98  
    99  			if err := subProcess.Wait(); err != nil {
   100  				t.Fatal(err)
   101  			}
   102  		})
   103  	}
   104  }
   105  

View as plain text