A subunit v2 protocol implementation in Rust

5 releases

Uses old Rust 2015

0.2.0 May 10, 2022
0.1.3 Mar 25, 2020
0.1.2 Jun 9, 2018
0.1.1 Jun 7, 2018
0.1.0 May 14, 2018

#81 in Testing

Download history 24/week @ 2022-04-24 34/week @ 2022-05-01 59/week @ 2022-05-08 92/week @ 2022-05-15 30/week @ 2022-05-22 44/week @ 2022-05-29 32/week @ 2022-06-05 12/week @ 2022-06-12 11/week @ 2022-06-19 16/week @ 2022-06-26 4/week @ 2022-07-03 14/week @ 2022-07-10 18/week @ 2022-07-17 14/week @ 2022-07-24 17/week @ 2022-07-31 13/week @ 2022-08-07

64 downloads per month
Used in junitxml2subunit


494 lines

Subunit Rust

subunit-rust on Travis CI subunit-rust on crates.io subunit-rust on Appveyor CI

This repo contains a implementation of the subunit v2 protocol in Rust. It provides an interface for both writing and reading subunit streams natively in rust. The subunit v2 protocol is documented in the testing-cabal/subunit repository.

Reading subunit packets

Reading subunit packets first requires an object implementing the Read trait containing the subunit stream. The parse_subunit() function is used to first buffer the entire stream in memory, and then parse the contents and return a vector of Event structs. For example, parsing a subunit stream from a file:

    let mut f = File::open("results.subunit")?;
    let events = parse_subunit(f).unwrap();

In this example, the results.subunit file will be opened and parsed with an Event struct in the events vector for each subunit packet in the file.

Writing subunit packets

Writing a subunit packet first requires creating an event structure to describe the contents of the packet. For example:

    let mut event_start = Event {
        status: Some("inprogress".to_string()),
        test_id: Some("A_test_id".to_string()),
        timestamp: Some(Utc.ymd(2014, 7, 8).and_hms(9, 10, 11)),
        tags: Some(vec!["tag_a".to_string(), "tag_b".to_string()]),
        file_content: None,
        file_name: None,
        mime_type: None,
        route_code: None

A typical test event normally involves 2 packets though, one to mark the start and the other to mark the finish of a test:

    let mut event_end = Event {
        status: Some("success".to_string()),
        test_id: Some("A_test_id".to_string()),
        timestamp: Some(Utc.ymd(2014, 7, 8).and_hms(9, 12, 0)),
        tags: Some(vec!["tag_a".to_string(), "tag_b".to_string()]),
        file_content: Some("stdout content".to_string().into_bytes()),
        file_name: Some("stdout:''".to_string()),
        mime_type: Some("text/plain;charset=utf8".to_string()),
        route_code: None

Then you'll want to write the packet out to something. Anything that implements the std::io::Write trait can be used for the packets, including things like a File and a TCPStream. In this case we'll use Vec to keep it in memory:

    let mut subunit_stream: Vec<u8> = Vec::new();

    subunit_stream = event_start.write(subunit_stream)?;
    subunit_stream = event_end.write(subunit_stream)?;

With this the subunit_stream buffer will contain the contents of the subunit stream for that test event.


~18K SLoC