]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
nfs3-records: add unittests to nom7 parsers
authorSam Muhammed <ghostinthehive.vx@gmail.com>
Sun, 2 Jan 2022 05:31:34 +0000 (07:31 +0200)
committerVictor Julien <vjulien@oisf.net>
Thu, 13 Jan 2022 07:16:02 +0000 (08:16 +0100)
Task #4866

rust/src/nfs/nfs3_records.rs

index e7e5f96896c4bf3941d0b8b2d154b9ffc802d222..66c02cf07db0a4d62ffee3b57cf9e1af53b885e1 100644 (file)
@@ -388,3 +388,590 @@ pub fn parse_nfs3_reply_read(i: &[u8]) -> IResult<&[u8], NfsReplyRead> {
     };
     Ok((i, reply))
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::nfs::nfs3_records::*;
+
+    #[test]
+    fn test_nfs3_response_create() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x00, /*Status: NFS3_OK (0)*/
+            0x00, 0x00, 0x00, 0x01, /*handle_follows: (1)*/
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x54,
+            0x00, 0x00, 0x00, 0x1b, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[8..]).unwrap();
+
+        let (_, response) = parse_nfs3_response_create(buf).unwrap();
+        assert_eq!(response.status, 0);
+        assert_eq!(response.handle, Some(expected_handle));
+    }
+
+    #[test]
+    fn test_nfs2_response_lookup() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x00, /*Status: NFS3_OK (0)*/
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xec,
+            0x00, 0x00, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[4..]).unwrap();
+
+        let (_, response) = parse_nfs3_response_lookup(buf).unwrap();
+        assert_eq!(response.status, 0);
+        assert_eq!(response.handle, expected_handle);
+    }
+
+    #[test]
+    fn test_nfs3_request_create() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xe7,
+            0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [name]
+            0x00, 0x00, 0x00, 0x01, /*name_len: (1)*/
+            0x68, /*name_contents: (h)*/
+            0x00, 0x00, 0x00, /*_fill_bytes*/
+            0x00, 0x00, 0x00, 0x00, /*create_mode: UNCHECKED (0)*/
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xa4, /*verifier*/
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_create(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.name_len, 1);
+                assert_eq!(request.create_mode, 0);
+                assert_eq!(request.verifier.len(), 44);
+                assert_eq!(request.name_vec, br#"h"#.to_vec());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_remove() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xe7,
+            0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [name]
+            0x00, 0x00, 0x00, 0x01, /*name_len: (1)*/
+            0x68, /*name_contents: (h)*/
+            0x00, 0x00, 0x00, /*_fill_bytes*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_remove(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.name_len, 1);
+                assert_eq!(request.name_vec, br#"h"#.to_vec());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_rmdir() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        //[handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [name]
+            0x00, 0x00, 0x00, 0x01, /*name_len: (1)*/
+            0x64, /*name_contents: (d)*/
+            0x00, 0x00, 0x00, /*_fill_bytes*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_rmdir(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.name_vec, br#"d"#.to_vec());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_mkdir() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [name]
+            0x00, 0x00, 0x00, 0x01, /*name_len: (1)*/
+            0x64, /*name_contents: (d)*/
+            0x00, 0x00, 0x00, /*_fill_bytes*/
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xed, /*attributes*/
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_mkdir(buf).unwrap();
+        match result {
+            (_r, request) => {
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.name_vec, br#"d"#.to_vec());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_rename() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [from_handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [from_name]
+            0x00, 0x00, 0x00, 0x01, /*name_len: (1)*/
+            0x61, /*name: (a)*/
+            0x00, 0x00, 0x00, /*_fill_bytes*/
+        // [to_handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [to_name]
+            0x00, 0x00, 0x00, 0x02, /*name_len: (2)*/
+            0x61, 0x6d, /*name: (am)*/
+            0x00, 0x00, /*_fill_bytes*/
+        ];
+
+        let (_, expected_from_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+        let (_, expected_to_handle) = parse_nfs3_handle(&buf[44..80]).unwrap();
+
+        let result = parse_nfs3_request_rename(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+
+                assert_eq!(request.from_handle, expected_from_handle);
+                assert_eq!(request.from_name_vec, br#"a"#.to_vec());
+
+                assert_eq!(request.to_handle, expected_to_handle);
+                assert_eq!(request.to_name_vec, br#"am"#.to_vec());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_getattr() {
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(buf).unwrap();
+
+        let result = parse_nfs3_request_getattr(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_access() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x54,
+            0x00, 0x00, 0x00, 0x1b, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+            0x00, 0x00, 0x00, 0x0c, /*check_access: (12)*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_access(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.check_access, 12);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_commit() {
+
+        // packet_bytes -- used [READ Call] message digest
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5d,
+            0x00, 0x00, 0x00, 0x2a, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*offset: (0)*/
+            0x00, 0x00, 0x40, 0x00, /*count:*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_commit(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_read() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5d,
+            0x00, 0x00, 0x00, 0x2a, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*offset: (0)*/
+            0x00, 0x00, 0x40, 0x00, /*_count*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_read(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.offset, 0);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_lookup() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x5a,
+            0x00, 0x00, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+        // [name]
+            0x00, 0x00, 0x00, 0x03, /*name_len: (3)*/
+            0x62, 0x6c, 0x6e, /*name: (bln)*/
+            0x00, /*_fill_bytes*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_lookup(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.name_vec, br#"bln"#);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_response_readdirplus() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x00, /*status*/
+            0x00, 0x00, 0x00, 0x01, /*dir_attr_follows*/
+            0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x41, 0xc0, /*_dir_attr*/
+            0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0xe8,
+            0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x63, 0xc3, 0x9d, 0x1a,
+            0x66, 0xf3, 0x85, 0x5e, 0x00, 0x00, 0x00, 0x00,
+            0x0c, 0x66, 0x00, 0x03, 0x59, 0x39, 0x5a, 0x3a,
+            0x18, 0x13, 0x9c, 0xb2, 0x55, 0xe1, 0x59, 0xd4,
+            0x0e, 0xa0, 0xc0, 0x41, 0x55, 0xe1, 0x59, 0xd4,
+            0x0e, 0xa0, 0xc0, 0x41,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*_verifier*/
+        // [data]
+            0x00, 0x00, 0x00, 0x01, /*value_follows*/
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x01, /*entry0*/
+            0x00, 0x00, 0x00, 0x02, 0x2e, 0x2e, 0x00, 0x00, /*name_contents: \2e\2e */
+            0x00, 0x00, 0x00, 0x00, 0x7c, 0x1b, 0xc6, 0xaf,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+            0x00, 0x00, 0x41, 0xc0, 0x00, 0x00, 0x00, 0x05,
+            0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x03, 0xe8,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x63, 0xc3, 0x9d, 0x1a, 0x66, 0xf3, 0x85, 0x5e,
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x01,
+            0x59, 0x38, 0xa1, 0xa1, 0x04, 0x29, 0xd9, 0x59,
+            0x4e, 0xbf, 0xf1, 0x51, 0x09, 0x2c, 0xa1, 0xda,
+            0x4e, 0xbf, 0xf1, 0x51, 0x09, 0x2c, 0xa1, 0xda,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24,
+            0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0xd4, 0x09, /*handle*/
+            0x00, 0x00, 0x00, 0x00, 0x5e, 0x85, 0xf3, 0x66,
+            0x1a, 0x9d, 0xc3, 0x63, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, 0x0c,
+            0x4a, 0xff, 0x6b, 0x99,
+            0x00, 0x00, 0x00, 0x01, /*value_follows*/
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x03, /*entry1*/
+            0x00, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+            0x00, 0x00, 0x41, 0xc0, 0x00, 0x00, 0x00, 0x02,
+            0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x03, 0xe8,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x63, 0xc3, 0x9d, 0x1a, 0x66, 0xf3, 0x85, 0x5e,
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x03,
+            0x59, 0x39, 0x5a, 0x3a, 0x18, 0x13, 0x9c, 0xb2,
+            0x55, 0xe1, 0x59, 0xd4, 0x0e, 0xa0, 0xc0, 0x41,
+            0x55, 0xe1, 0x59, 0xd4, 0x0e, 0xa0, 0xc0, 0x41,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24,
+            0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0xd4, 0x09, /*handle*/
+            0x00, 0x00, 0x00, 0x00, 0x5e, 0x85, 0xf3, 0x66,
+            0x1a, 0x9d, 0xc3, 0x63, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x66, 0x0c,
+            0x4c, 0xff, 0x6b, 0x99, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01,
+        ];
+
+        let data_buf = &buf[100..];
+
+        let (_, response) = parse_nfs3_response_readdirplus(buf).unwrap();
+        assert_eq!(response.status, 0);
+        assert_eq!(response.data, data_buf);
+
+        // test for multiple entries
+        let entry0_buf = &data_buf[4..160];
+        let entry1_buf = &data_buf[164..320];
+
+        let (_, entry0) = parse_nfs3_response_readdirplus_entry(entry0_buf).unwrap();
+        let (_, entry1) = parse_nfs3_response_readdirplus_entry(entry1_buf).unwrap();
+
+        let response = many0_nfs3_response_readdirplus_entries(data_buf).unwrap();
+        match response {
+            (r, entries) => {
+                assert_eq!(r.len(), 4);
+                assert_eq!(entries[0], Nfs3ResponseReaddirplusEntry { entry: Some(entry0) });
+                assert_eq!(entries[1], Nfs3ResponseReaddirplusEntry { entry: Some(entry1) });
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_response_readdirplus_entry() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x01, /*value_follows*/
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x03, /*entry*/
+            0x00, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x00, 0x00, /*name_contents: 2e*/
+            0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+            0x00, 0x00, 0x41, 0xc0, 0x00, 0x00, 0x00, 0x02,
+            0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x03, 0xe8,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x63, 0xc3, 0x9d, 0x1a, 0x66, 0xf3, 0x85, 0x5e,
+            0x00, 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x03,
+            0x59, 0x39, 0x5a, 0x3a, 0x18, 0x13, 0x9c, 0xb2,
+            0x55, 0xe1, 0x59, 0xd4, 0x0e, 0xa0, 0xc0, 0x41,
+            0x55, 0xe1, 0x59, 0xd4, 0x0e, 0xa0, 0xc0, 0x41,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24,
+            0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0xd4, 0x09, /*handle*/
+            0x00, 0x00, 0x00, 0x00, 0x5e, 0x85, 0xf3, 0x66,
+            0x1a, 0x9d, 0xc3, 0x63, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x66, 0x0c,
+            0x4c, 0xff, 0x6b, 0x99,
+        ];
+
+        let (_, entry_handle) = parse_nfs3_handle(&buf[120..]).unwrap();
+        assert_eq!(entry_handle.len, 36);
+        assert_eq!(entry_handle.value, &buf[124..]);
+
+        let (_, response) = parse_nfs3_response_readdirplus_entry_cond(buf).unwrap();
+        match response {
+            Nfs3ResponseReaddirplusEntry { entry: Some(entry_c) } => {
+                assert_eq!(entry_c.name_vec, ".".as_bytes());
+                assert_eq!(entry_c.handle, Some(entry_handle));
+            }
+            _ => { panic!("Failure"); }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_readdirplus() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x24, /*handle_len*/
+            0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0xd4, 0x09, /*handle*/
+            0x00, 0x00, 0x00, 0x00, 0x5e, 0x85, 0xf3, 0x66,
+            0x1a, 0x9d, 0xc3, 0x63, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x66, 0x0c,
+            0x4c, 0xff, 0x6b, 0x99,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*cookie*/
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*verifier*/
+            0x00, 0x00, 0x02, 0x00, /*dircount*/
+            0x00, 0x00, 0x10, 0x00, /*maxcount*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..40]).unwrap();
+        assert_eq!(expected_handle.len, 36);
+        assert_eq!(expected_handle.value, &buf[4..40]);
+
+        let result = parse_nfs3_request_readdirplus(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.cookie, 0);
+                assert_eq!(request.verifier, "\0\0\0\0\0\0\0\0".as_bytes());
+                assert_eq!(request.verifier.len(), 8);
+                assert_eq!(request.dircount, 512);
+                assert_eq!(request.maxcount, 4096);
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_request_write() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+        // [handle]
+            0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x03, 0xe7, /*handle*/
+            0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x54,
+            0x00, 0x00, 0x00, 0x1b, 0x00, 0x0a, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5a, 0x00, 0x00, 0x00, 0x29,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*offset: (0)*/
+            0x00, 0x00, 0x00, 0x11, /*count: (17)*/
+            0x00, 0x00, 0x00, 0x01, /*stable: <DATA_SYNC> (1)*/
+        // [data]
+            0x00, 0x00, 0x00, 0x11, /*file_len: (17)*/
+            0x68, 0x61, 0x6c, 0x6c, 0x6f, 0x0a, 0x74, 0x68, /*file_data: ("hallo\nthe b file\n")*/
+            0x65, 0x20, 0x62, 0x20, 0x66, 0x69, 0x6c, 0x65,
+            0x0a,
+            0x00, 0x00, 0x00, /*_data_padding*/
+        ];
+
+        let (_, expected_handle) = parse_nfs3_handle(&buf[..36]).unwrap();
+
+        let result = parse_nfs3_request_write(buf).unwrap();
+        match result {
+            (r, request) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(request.handle, expected_handle);
+                assert_eq!(request.offset, 0);
+                assert_eq!(request.count, 17);
+                assert_eq!(request.stable, 1);
+                assert_eq!(request.file_len, 17);
+                assert_eq!(request.file_data, "hallo\nthe b file\n".as_bytes());
+            }
+        }
+    }
+
+    #[test]
+    fn test_nfs3_reply_read() {
+
+        #[rustfmt::skip]
+        let buf: &[u8] = &[
+            0x00, 0x00, 0x00, 0x00, /*Status: NFS3_OK (0)*/
+            0x00, 0x00, 0x00, 0x01, /*attributes_follows: (1)*/
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x81, 0xa4, /*attr_blob*/
+            0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x10, 0x10, 0x85, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0xb2, 0x5d, 0x38, 0x47, 0x76, 0x25,
+            0x23, 0xc3, 0x46, 0x00, 0x38, 0x47, 0x71, 0xc4,
+            0x21, 0xf9, 0x82, 0x80, 0x38, 0x47, 0x76, 0x25,
+            0x1e, 0x65, 0xfb, 0x81,
+            0x00, 0x00, 0x00, 0x0b, /*count: (11)*/
+            0x00, 0x00, 0x00, 0x01, /*EOF: (true)*/
+        // [data]
+            0x00, 0x00, 0x00, 0x0b, /*data_len: (11)*/
+            0x74, 0x68, 0x65, 0x20, 0x62, 0x20, 0x66, 0x69,
+            0x6c, 0x65, 0x0a, /*data: ("the b file\n")*/
+            0x00, /*_data_padding*/
+        ];
+
+        let result = parse_nfs3_reply_read(buf).unwrap();
+        match result {
+            (r, reply) => {
+                assert_eq!(r.len(), 0);
+                assert_eq!(reply.status, 0);
+                assert_eq!(reply.attr_follows, 1);
+                assert_eq!(reply.attr_blob.len(), 84);
+                assert_eq!(reply.count, 11);
+                assert_eq!(reply.eof, true);
+                assert_eq!(reply.data_len, 11);
+                assert_eq!(reply.data, "the b file\n".as_bytes());
+            }
+        }
+    }
+}