feat: full NFSv4.2 server and client in pure Go
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
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
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user