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,83 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package rdma
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The inline frame round trips: the fixed fields, the chunk lists and
|
||||
// the payload survive the encode-decode pair. A frame whose payload is
|
||||
// nil decodes as RDMA_NOMSG.
|
||||
func TestFrameRoundTrip(t *testing.T) {
|
||||
h := Header{
|
||||
XID: 42, Credit: 16, Proc: ProcMsg,
|
||||
Reads: []ReadChunk{{Position: 8, Segment: Segment{Handle: 1, Length: 64, Offset: 512}}},
|
||||
Writes: []WriteChunk{{Segments: []Segment{
|
||||
{Handle: 2, Length: 128, Offset: 1024},
|
||||
}}},
|
||||
Reply: &WriteChunk{Segments: []Segment{{Handle: 3, Length: 256, Offset: 2048}}},
|
||||
Payload: []byte("the rpc call bytes"),
|
||||
}
|
||||
frame := AppendFrame(nil, h)
|
||||
got, err := DecodeFrame(frame)
|
||||
if err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if got.XID != 42 || got.Credit != 16 || got.Proc != ProcMsg {
|
||||
t.Fatalf("header %+v", got)
|
||||
}
|
||||
if len(got.Reads) != 1 || got.Reads[0].Position != 8 ||
|
||||
got.Reads[0].Segment.Length != 64 || got.Reads[0].Segment.Offset != 512 {
|
||||
t.Fatalf("reads %+v", got.Reads)
|
||||
}
|
||||
if len(got.Writes) != 1 || len(got.Writes[0].Segments) != 1 ||
|
||||
got.Writes[0].Segments[0].Length != 128 {
|
||||
t.Fatalf("writes %+v", got.Writes)
|
||||
}
|
||||
if got.Reply == nil || len(got.Reply.Segments) != 1 || got.Reply.Segments[0].Length != 256 {
|
||||
t.Fatalf("reply %+v", got.Reply)
|
||||
}
|
||||
if !bytes.Equal(got.Payload, h.Payload) {
|
||||
t.Fatalf("payload %q", got.Payload)
|
||||
}
|
||||
|
||||
nomsg := AppendFrame(nil, Header{XID: 7, Credit: 4, Proc: ProcNomsg})
|
||||
got, err = DecodeFrame(nomsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Proc != ProcNomsg || got.Payload != nil {
|
||||
t.Fatalf("nomsg %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The stream framing splits frames off a buffer and detects a torn or
|
||||
// corrupted stream.
|
||||
func TestStreamFraming(t *testing.T) {
|
||||
h := Header{XID: 9, Credit: 4, Proc: ProcMsg, Payload: []byte("abc")}
|
||||
frame := AppendStreamFrame(nil, h)
|
||||
got, consumed, ok, err := ReadStreamFrame(frame)
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("read: ok %v err %v", ok, err)
|
||||
}
|
||||
if consumed != len(frame) {
|
||||
t.Fatalf("consumed %d of %d", consumed, len(frame))
|
||||
}
|
||||
if hdr, derr := DecodeFrame(got); derr != nil || hdr.XID != 9 || string(hdr.Payload) != "abc" {
|
||||
t.Fatalf("frame %+v %v", hdr, derr)
|
||||
}
|
||||
|
||||
// A torn frame: not a whole frame yet.
|
||||
if _, _, ok, _ := ReadStreamFrame(frame[:len(frame)-1]); ok {
|
||||
t.Fatal("a torn frame read as whole")
|
||||
}
|
||||
// A corrupted magic.
|
||||
broken := append([]byte{}, frame...)
|
||||
broken[0] ^= 0xff
|
||||
if _, _, _, err := ReadStreamFrame(broken); err != ErrFrame {
|
||||
t.Fatalf("broken magic: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user