92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
// Copyright (c) 2019, Daniel Martí <mvdan@mvdan.cc>
|
|
// See LICENSE for licensing information
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/go-quicktest/qt"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func init() {
|
|
// Here rather than in TestMain, to reuse the unix build tag.
|
|
if limit := os.Getenv("TEST_WITH_FILE_LIMIT"); limit != "" {
|
|
n, err := strconv.ParseUint(limit, 10, 64)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
rlimit := unix.Rlimit{Cur: n, Max: n}
|
|
if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit); err != nil {
|
|
panic(err)
|
|
}
|
|
os.Exit(main1())
|
|
}
|
|
}
|
|
|
|
func TestWithLowOpenFileLimit(t *testing.T) {
|
|
// Safe to run in parallel, as we only change the limit for child processes.
|
|
t.Parallel()
|
|
|
|
tempDir := t.TempDir()
|
|
testBinary, err := os.Executable()
|
|
qt.Assert(t, qt.IsNil(err))
|
|
|
|
const (
|
|
// Enough directories to run into the ulimit.
|
|
// Enough number of files in total to run into the ulimit.
|
|
numberDirs = 500
|
|
numberFilesPerDir = 20
|
|
numberFilesTotal = numberDirs * numberFilesPerDir
|
|
)
|
|
t.Logf("writing %d tiny Go files", numberFilesTotal)
|
|
var allGoFiles []string
|
|
for i := 0; i < numberDirs; i++ {
|
|
// Prefix "p", so the package name is a valid identifier.
|
|
// Add one go.mod file per directory as well,
|
|
// which will help catch data races when loading module info.
|
|
dirName := fmt.Sprintf("p%03d", i)
|
|
dirPath := filepath.Join(tempDir, dirName)
|
|
err := os.MkdirAll(dirPath, 0o777)
|
|
qt.Assert(t, qt.IsNil(err))
|
|
|
|
err = os.WriteFile(filepath.Join(dirPath, "go.mod"),
|
|
[]byte(fmt.Sprintf("module %s\n\ngo 1.16", dirName)), 0o666)
|
|
qt.Assert(t, qt.IsNil(err))
|
|
|
|
for j := 0; j < numberFilesPerDir; j++ {
|
|
filePath := filepath.Join(dirPath, fmt.Sprintf("%03d.go", j))
|
|
err := os.WriteFile(filePath,
|
|
// Extra newlines so that "-l" prints all paths.
|
|
[]byte(fmt.Sprintf("package %s\n\n\n", dirName)), 0o666)
|
|
qt.Assert(t, qt.IsNil(err))
|
|
allGoFiles = append(allGoFiles, filePath)
|
|
}
|
|
}
|
|
if len(allGoFiles) != numberFilesTotal {
|
|
panic("allGoFiles doesn't have the expected number of files?")
|
|
}
|
|
runGofmt := func(paths ...string) {
|
|
t.Logf("running with %d paths", len(paths))
|
|
cmd := exec.Command(testBinary, append([]string{"-l"}, paths...)...)
|
|
// 256 is a relatively common low limit, e.g. on Mac.
|
|
cmd.Env = append(os.Environ(), "TEST_WITH_FILE_LIMIT=256")
|
|
out, err := cmd.Output()
|
|
var stderr []byte
|
|
if err, _ := err.(*exec.ExitError); err != nil {
|
|
stderr = err.Stderr
|
|
}
|
|
qt.Assert(t, qt.IsNil(err), qt.Commentf("stderr:\n%s", stderr))
|
|
qt.Assert(t, qt.Equals(bytes.Count(out, []byte("\n")), len(allGoFiles)))
|
|
}
|
|
runGofmt(tempDir)
|
|
runGofmt(allGoFiles...)
|
|
}
|