Files
nfs/internal/nfs4/cover_extra_test.go
T

101 lines
3.5 KiB
Go
Raw Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package nfs4
import (
"testing"
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
// The numbered session id: the prefix, the number and the client id
// halves, RFC 8881 section 18.36.
func TestMakeNumberedSessionID(t *testing.T) {
id := MakeNumberedSessionID([4]byte{9, 9, 9, 9}, 0x11223344, 0x5566778899aabbcc)
if id[0] != 9 || id[3] != 9 {
t.Fatalf("prefix % x", id[:4])
}
if id[4] != 0x11 || id[7] != 0x44 {
t.Fatalf("number % x", id[4:8])
}
if id.ClientIDOf() != 0x5566778899aabbcc {
t.Fatalf("clientid %x", id.ClientIDOf())
}
// Every number mints a distinct id.
if MakeNumberedSessionID([4]byte{}, 1, 5) == MakeNumberedSessionID([4]byte{}, 2, 5) {
t.Fatal("two numbers minted the same session id")
}
}
// NegotiateChannel clamps each value to the smaller of the request and
// the limit and leaves a zero request at zero.
func TestNegotiateChannel(t *testing.T) {
got := NegotiateChannel(
ChannelAttrs{MaxRequest: 1 << 30, MaxResponse: 1 << 10, MaxRespResourced: 1 << 10,
MaxOperations: 64, MaxRequests: 0},
ChannelAttrs{MaxRequest: 1 << 22, MaxResponse: 1 << 22, MaxRespResourced: 1 << 22,
MaxOperations: 16, MaxRequests: 8},
)
want := ChannelAttrs{MaxRequest: 1 << 22, MaxResponse: 1 << 10, MaxRespResourced: 1 << 10,
MaxOperations: 16, MaxRequests: 0}
if got.MaxRequest != want.MaxRequest || got.MaxResponse != want.MaxResponse ||
got.MaxRespResourced != want.MaxRespResourced || got.MaxOperations != want.MaxOperations ||
got.MaxRequests != want.MaxRequests {
t.Fatalf("negotiated %+v, want %+v", got, want)
}
}
// The EXCLUSIVE4_1 open args round trip: guarded create, verifier
// consumed, mode carried.
func TestOpenArgsExclusive41RoundTrip(t *testing.T) {
arg := AppendOpenArgsExclusive41(nil, 0x77, []byte("ex"),
[8]byte{1, 2, 3, 4, 5, 6, 7, 8}, 0o640, "ex41.txt")
d := xdr.NewDecoder(arg)
if op, err := d.Uint32(); err != nil || op != OpOpen {
t.Fatalf("op %d %v", op, err)
}
a, err := DecodeOpenArgs(d)
if err != nil {
t.Fatal(err)
}
if !a.Create || !a.Guarded || a.Truncate || a.Perm != 0o640 || a.Name != "ex41.txt" ||
a.ClientID != 0x77 || string(a.Owner) != "ex" {
t.Fatalf("args %+v", a)
}
if d.Remaining() != 0 {
t.Fatalf("%d bytes left", d.Remaining())
}
// The guarded form sets the flag the same way.
arg = AppendOpenArgs(nil, 1, []byte("o"), ShareAccessRead, 0, true, 0o600, "g.txt")
if _, err := DecodeOpenArgs(xdr.NewDecoder(arg[4:])); err != nil {
t.Fatal(err)
}
}
// The OPEN result measurement walks the write delegation with its space
// limit union and the permissions ace.
func TestResBodyLenOpenDelegations(t *testing.T) {
var st Stateid
st[0] = 1
write := AppendOpenResDeleg(nil, st, OpenDelegWrite, st)
if n, err := resBodyLen(OpOpen, ErrOK, write); err != nil || n != len(write) {
t.Fatalf("write deleg measured %d of %d: %v", n, len(write), err)
}
read := AppendOpenResDeleg(nil, st, OpenDelegRead, st)
if n, err := resBodyLen(OpOpen, ErrOK, read); err != nil || n != len(read) {
t.Fatalf("read deleg measured %d of %d: %v", n, len(read), err)
}
none := AppendOpenRes(nil, st)
if n, err := resBodyLen(OpOpen, ErrOK, none); err != nil || n != len(none) {
t.Fatalf("no deleg measured %d of %d: %v", n, len(none), err)
}
// A truncated body of any of the three fails instead of measuring
// past the payload.
for n := 0; n < len(write); n += 4 {
if _, err := resBodyLen(OpOpen, ErrOK, write[:n]); err == nil {
t.Fatalf("a %d byte prefix measured cleanly", n)
}
}
}