// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Not all systems have syscall.Mkfifo. //go:build !aix && !plan9 && !solaris && !wasm && !windows package wasi_test import ( "bufio" "fmt" "io" "math/rand" "os" "os/exec" "path/filepath" "syscall" "testing" ) // This test creates a set of FIFOs and writes to them in reverse order. It // checks that the output order matches the write order. The test binary opens // the FIFOs in their original order and spawns a goroutine for each that reads // from the FIFO and writes the result to stderr. If I/O was blocking, all // goroutines would be blocked waiting for one read call to return, and the // output order wouldn't match. type fifo struct { file *os.File path string } func TestNonblock(t *testing.T) { if target != "wasip1/wasm" { t.Skip() } switch os.Getenv("GOWASIRUNTIME") { case "wasmer": t.Skip("wasmer does not support non-blocking I/O") } for _, mode := range []string{"os.OpenFile", "os.NewFile"} { t.Run(mode, func(t *testing.T) { args := []string{"run", "./testdata/nonblock.go", mode} fifos := make([]*fifo, 8) for i := range fifos { path := filepath.Join(t.TempDir(), fmt.Sprintf("wasip1-nonblock-fifo-%d-%d", rand.Uint32(), i)) if err := syscall.Mkfifo(path, 0666); err != nil { t.Fatal(err) } file, err := os.OpenFile(path, os.O_RDWR, 0) if err != nil { t.Fatal(err) } defer file.Close() args = append(args, path) fifos[len(fifos)-i-1] = &fifo{file, path} } subProcess := exec.Command("go", args...) subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm") pr, pw := io.Pipe() defer pw.Close() subProcess.Stderr = pw if err := subProcess.Start(); err != nil { t.Fatal(err) } scanner := bufio.NewScanner(pr) if !scanner.Scan() { t.Fatal("expected line:", scanner.Err()) } else if scanner.Text() != "waiting" { t.Fatal("unexpected output:", scanner.Text()) } for _, fifo := range fifos { if _, err := fifo.file.WriteString(fifo.path + "\n"); err != nil { t.Fatal(err) } if !scanner.Scan() { t.Fatal("expected line:", scanner.Err()) } else if scanner.Text() != fifo.path { t.Fatal("unexpected line:", scanner.Text()) } } if err := subProcess.Wait(); err != nil { t.Fatal(err) } }) } }