github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/runtime/internal/wasitest/nonblock_test.go (about)

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