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
140 lines
3.9 KiB
Go
140 lines
3.9 KiB
Go
// 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)
|
|
}
|
|
}
|