Files
nfs/internal/nfsfs/local_cache_linux_test.go
T
petrbalvin a9b8039ef7
Test / test (push) Successful in 2m4s
Release / gates (push) Successful in 2m5s
Release / build (amd64, freebsd) (push) Successful in 1m27s
Release / build (amd64, linux) (push) Successful in 1m22s
Release / build (amd64, netbsd) (push) Successful in 1m19s
Release / build (amd64, openbsd) (push) Successful in 1m20s
Release / build (arm64, darwin) (push) Successful in 1m21s
Release / build (arm64, freebsd) (push) Successful in 1m26s
Release / build (arm64, linux) (push) Successful in 1m25s
Release / build (arm64, netbsd) (push) Successful in 1m31s
Release / build (arm64, openbsd) (push) Successful in 1m27s
Release / build (loong64, linux) (push) Successful in 1m37s
Release / build (riscv64, linux) (push) Successful in 1m21s
Release / release (push) Successful in 40s
feat: full NFSv4.2 server and client in pure Go
Assisted-by: GLM 5.3 Flash
2026-09-21 18:51:17 +02:00

74 lines
1.9 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package nfsfs
import (
"fmt"
"os"
"path/filepath"
"testing"
)
// openFDs counts the descriptors the process holds through /proc. The
// count is a lower bound of live descriptors and good enough to prove a
// cache does not leak: a thousand operations over one file must not add a
// thousand descriptors.
func openFDs(t *testing.T) int {
t.Helper()
entries, err := os.ReadDir("/proc/self/fd")
if err != nil {
t.Skipf("/proc/self/fd is unavailable: %v", err)
}
return len(entries)
}
// TestCacheNoDescriptorLeak drives more operations over one file than the
// cache can hold and requires the process descriptor count to stay flat.
func TestCacheNoDescriptorLeak(t *testing.T) {
l, h, _ := cacheTestRoot(t, "leak")
before := openFDs(t)
for range 1000 {
if _, err := l.Read(h, 0, 4); err != nil {
t.Fatalf("Read: %v", err)
}
}
after := openFDs(t)
if after-before > 8 {
t.Fatalf("descriptors grew from %d to %d over 1000 reads", before, after)
}
}
// TestCacheBound holds when many distinct files flow through: after
// touching twice the bound, at most the bound of cache entries may remain.
func TestCacheBound(t *testing.T) {
root := t.TempDir()
l, err := NewLocal(root)
if err != nil {
t.Fatalf("NewLocal: %v", err)
}
rh, err := l.Root()
if err != nil {
t.Fatalf("Root: %v", err)
}
for i := range 2 * fdCacheLimit {
name := fmt.Sprintf("f%d", i)
if err := os.WriteFile(filepath.Join(root, name), []byte("x"), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
h, _, err := l.Lookup(rh, name)
if err != nil {
t.Fatalf("Lookup: %v", err)
}
if _, err := l.Read(h, 0, 1); err != nil {
t.Fatalf("Read %s: %v", name, err)
}
}
l.fdMu.Lock()
n := len(l.fds)
l.fdMu.Unlock()
if n > fdCacheLimit {
t.Fatalf("cache holds %d entries, bound is %d", n, fdCacheLimit)
}
}