1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
Subunit Rust
============
[![subunit-rust CI][ci-image]][ci]
[![subunit on crates.io][cratesio-image]][cratesio]
[ci-image]: https://github.com/mtreinish/subunit-rust/actions/workflows/main.yml/badge.svg
[ci]: https://github.com/mtreinish/subunit-rust/actions/workflows/main.yml
[cratesio-image]: https://img.shields.io/crates/v/subunit.svg
[cratesio]: https://crates.io/crates/subunit
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](https://github.com/testing-cabal/subunit/blob/master/README.rst#version-2)
repository.
## Reading subunit packets
Reading subunit packets first requires an object implementing the Read trait
containing the subunit stream. The iter_stream() function is used to parse
the contents and return an iterator of ScannedItem enums. For example,
parsing a subunit stream from a file:
```rust,no_run
use std::fs::File;
use subunit::io::sync::iter_stream;
use subunit::types::stream::ScannedItem;
let f = File::open("results.subunit")?;
for item in iter_stream(f) {
match item? {
ScannedItem::Event(event) => {
// Process the event
println!("Got event: {:?}", event);
},
ScannedItem::Bytes(bytes) => {
// Process non-event data
println!("Got bytes: {:?}", bytes);
},
ScannedItem::Unknown(bytes, err) => {
// Handle unknown data
eprintln!("Unknown data: {:?}", err);
},
}
}
# Ok::<(), Box<dyn std::error::Error>>(())
```
In this example, the `results.subunit` file will be opened and parsed with a
ScannedItem for each packet in the file.
## Writing subunit packets
Writing a subunit packet first requires creating an event structure to describe
the contents of the packet. The Event API uses a builder pattern for
construction. For example:
```rust
use subunit::types::{event::Event, teststatus::TestStatus};
use chrono::{TimeZone, Utc};
let event_start = Event::new(TestStatus::InProgress)
.test_id("A_test_id")
.datetime(Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap())?
.tag("tag_a")
.tag("tag_b")
.build();
# Ok::<(), Box<dyn std::error::Error>>(())
```
A typical test event normally involves 2 packets though, one to mark the start
and the other to mark the finish of a test:
```rust
use subunit::types::{event::Event, teststatus::TestStatus};
use chrono::{TimeZone, Utc};
let event_end = Event::new(TestStatus::Success)
.test_id("A_test_id")
.datetime(Utc.with_ymd_and_hms(2014, 7, 8, 9, 12, 0).unwrap())?
.tag("tag_a")
.tag("tag_b")
.mime_type("text/plain;charset=utf8")
.file_content("stdout:''", b"stdout content")
.build();
# Ok::<(), Box<dyn std::error::Error>>(())
```
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<u8> to keep it in memory:
```rust
use subunit::serialize::Serializable;
use subunit::types::{event::Event, teststatus::TestStatus};
use chrono::{TimeZone, Utc};
let mut subunit_stream: Vec<u8> = Vec::new();
let event_start = Event::new(TestStatus::InProgress)
.test_id("A_test_id")
.datetime(Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap())?
.tag("tag_a")
.tag("tag_b")
.build();
let event_end = Event::new(TestStatus::Success)
.test_id("A_test_id")
.datetime(Utc.with_ymd_and_hms(2014, 7, 8, 9, 12, 0).unwrap())?
.tag("tag_a")
.tag("tag_b")
.mime_type("text/plain;charset=utf8")
.file_content("stdout:''", b"stdout content")
.build();
event_start.serialize(&mut subunit_stream)?;
event_end.serialize(&mut subunit_stream)?;
# Ok::<(), Box<dyn std::error::Error>>(())
```
With this the subunit_stream buffer will contain the contents of the subunit
stream for that test event.
|