Files
nfs/internal/nfs4/dirdeleg_test.go
T

140 lines
3.9 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 (
"bytes"
"testing"
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
func TestDirDelegationShapes(t *testing.T) {
t.Parallel()
st := Stateid{1, 'D', 'D', 'E'}
args := AppendGetDirDelegationArgs(nil, true, OfBits(NotifyAddEntry),
NfsTime{Seconds: 5, Nseconds: 6}, NfsTime{Seconds: 7, Nseconds: 8},
Bitmap{}, Bitmap{})
d := xdr.NewDecoder(args[4:])
if sig, err := d.Bool(); err != nil || !sig {
t.Fatalf("signal %v: %v", sig, err)
}
if _, err := ReadBitmap(d); err != nil {
t.Fatal(err)
}
for _, want := range []NfsTime{{Seconds: 5, Nseconds: 6}, {Seconds: 7, Nseconds: 8}} {
s, err := d.Int64()
if err != nil || s != want.Seconds {
t.Fatalf("delay seconds %d: %v", s, err)
}
ns, err := d.Uint32()
if err != nil || ns != want.Nseconds {
t.Fatalf("delay nseconds %d: %v", ns, err)
}
}
if _, err := ReadBitmap(d); err != nil {
t.Fatal(err)
}
if _, err := ReadBitmap(d); err != nil {
t.Fatal(err)
}
if d.Remaining() != 0 {
t.Fatalf("%d bytes left in the dir delegation args", d.Remaining())
}
ok := AppendGetDirDelegationResOK(nil, [8]byte{9}, st,
OfBits(NotifyAddEntry), Bitmap{}, Bitmap{})
n, err := resBodyLen(OpGetDirDelegation, ErrOK, ok)
if err != nil || n != len(ok) {
t.Fatalf("resok measured %d of %d: %v", n, len(ok), err)
}
un := AppendGetDirDelegationResUnavail(nil, true)
if n, err := resBodyLen(OpGetDirDelegation, ErrOK, un); err != nil || n != len(un) {
t.Fatalf("unavail measured %d of %d: %v", n, len(un), err)
}
d = xdr.NewDecoder(un)
if s, err := d.Uint32(); err != nil || s != GddUnavail {
t.Fatalf("unavail status %d: %v", s, err)
}
}
func TestNotifyShapes(t *testing.T) {
t.Parallel()
add := AppendNotifyAdd(nil, "entry", 0, true)
d := xdr.NewDecoder(add)
if n, err := d.Uint32(); err != nil || n != 0 {
t.Fatalf("old entries %d: %v", n, err)
}
if name, err := d.String(); err != nil || name != "entry" {
t.Fatalf("name %q: %v", name, err)
}
if _, err := ReadBitmap(d); err != nil { // empty fattr bitmap
t.Fatal(err)
}
if _, err := d.VarOpaque(); err != nil { // empty fattr blob
t.Fatal(err)
}
for range 2 {
if _, err := d.Uint32(); err != nil {
t.Fatal(err)
}
}
if last, err := d.Bool(); err != nil || !last {
t.Fatalf("last %v: %v", last, err)
}
if d.Remaining() != 0 {
t.Fatalf("%d bytes left in the add body", d.Remaining())
}
rem := AppendNotifyRemove(nil, "gone", 7)
d = xdr.NewDecoder(rem)
if name, err := d.String(); err != nil || name != "gone" {
t.Fatalf("name %q: %v", name, err)
}
if _, err := ReadBitmap(d); err != nil {
t.Fatal(err)
}
if _, err := d.VarOpaque(); err != nil {
t.Fatal(err)
}
if c, err := d.Uint64(); err != nil || c != 7 {
t.Fatalf("cookie %d: %v", c, err)
}
// CB_NOTIFY args round trip through the decoder the client uses.
st := Stateid{2, 'N'}
fh := []byte("dir-fh")
changes := []Notify4{{Mask: OfBits(NotifyAddEntry), Vals: add}}
cb := AppendCBNotifyArgs(nil, st, fh, changes)
if n, err := resBodyLenCB(OpCBSequence, ErrOK, make([]byte, 32)); err != nil {
t.Fatal(err)
} else if n != 32 {
t.Fatalf("cb sequence body %d", n)
}
got, err := DecodeCBNotifyArgs(xdr.NewDecoder(cb[4:]))
if err != nil {
t.Fatal(err)
}
if got.Stateid != st || !bytes.Equal(got.FH, fh) || len(got.Changes) != 1 {
t.Fatalf("decoded %+v", got)
}
if !got.Changes[0].Mask.Has(NotifyAddEntry) {
t.Fatalf("mask %v", got.Changes[0].Mask)
}
// CB_NOTIFY_LOCK args round trip.
nl := AppendCBNotifyLockArgs(nil, fh, 0x77, []byte("owner"))
lock, err := DecodeCBNotifyLockArgs(xdr.NewDecoder(nl[4:]))
if err != nil {
t.Fatal(err)
}
if lock.Clientid != 0x77 || string(lock.Owner) != "owner" || !bytes.Equal(lock.FH, fh) {
t.Fatalf("decoded %+v", lock)
}
if n, err := resBodyLenCB(OpCBNotifyLock, ErrOK, nil); err != nil || n != 0 {
t.Fatalf("notify lock res body %d: %v", n, err)
}
}