25.1.6. Unit tests - Rust

25.1.6.1. Rust tests with Cargo check

Rust offers a built-in tool for running unit and integration tests. To do so, one makes usage of:

cargo test [options][testname][-- test-options]

The Cargo Book explains all options in more detail.

For testing a specific Rust module from Suricata, it suffices to go to the rust directory and run the above command, specifying the desired module (like http2).

cargo test http2

The line above will make rustc compile the Rust side of Suricata and run unit tests in the http2 rust module.

For running all Suricata unit tests from our Rust codebase, just run cargo test.

25.1.6.2. Adding unit tests

Note

If you want to understand when to use a unit test, please read the devguide section on Testing Suricata.

In general, it is preferable to have the unit tests in the same file that they test. At the end of the file, after all other functions. Add a tests module, if there isn’t one yet, and add the #[test] attribute before the unit test function. It is also necessary to import (use) the module to test, as well as any other modules used. As seen in the example below:

25.1.6.2.1. Example

From nfs > rpc_records.rs:

mod tests {
     use crate::nfs::rpc_records::*;
     use nom::Err::Incomplete;
     use nom::Needed::Size;

     #[test]
     fn test_partial_input_ok() {
         let buf: &[u8] = &[
             0x80, 0x00, 0x00, 0x9c, // flags
             0x8e, 0x28, 0x02, 0x7e, // xid
             0x00, 0x00, 0x00, 0x01, // msgtype
             0x00, 0x00, 0x00, 0x02, // rpcver
             0x00, 0x00, 0x00, 0x03, // program
             0x00, 0x00, 0x00, 0x04, // progver
             0x00, 0x00, 0x00, 0x05, // procedure
         ];
         let expected = RpcRequestPacketPartial {
             hdr: RpcPacketHeader {
                     frag_is_last: true,
                     frag_len: 156,
                     xid: 2384986750,
                     msgtype: 1
                 },
             rpcver: 2,
             program: 3,
             progver: 4,
             procedure: 5
         };
         let r = parse_rpc_request_partial(buf);
         match r {
             Ok((rem, hdr)) => {
                 assert_eq!(rem.len(), 0);
                 assert_eq!(hdr, expected);
             },
             _ => { panic!("failed {:?}",r); }
         }
     }
}

Once that is done, Rust should recognize the new test. If you want to check a single test, run:

cargo test module::file_name::tests::test_name

Where tests refers to mod tests. If you know the test name is unique, you can even run:

cargo test test_name

Following the same idea, it is also possible to test specific modules or submodules. For instance:

cargo test nfs::rpc_records