File size: 4,382 Bytes
ea39c0e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use pretty_assertions::assert_eq;
use serde_json::json;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;

use super::EncodedFrame;
use super::FramedReader;
use super::FramedWriter;
use super::MAX_FRAME_BYTES;

#[test]
fn complete_frame_round_trips_without_a_byte_stream() {
    let value = json!({"type": "session/open", "sessionId": "session-1"});
    let bytes = EncodedFrame::encode(&value)
        .expect("encode frame")
        .into_framed_bytes();

    assert_eq!(
        EncodedFrame::decode_framed::<serde_json::Value>(&bytes).expect("decode frame"),
        value
    );
}

#[test]
fn complete_frame_rejects_truncated_and_trailing_payloads() {
    let value = json!({"value": 1});
    let bytes = EncodedFrame::encode(&value)
        .expect("encode frame")
        .into_framed_bytes();

    let truncated = &bytes[..bytes.len() - 1];
    let truncated_error = EncodedFrame::decode_framed::<serde_json::Value>(truncated)
        .expect_err("truncated frame should fail");
    assert_eq!(truncated_error.kind(), std::io::ErrorKind::InvalidData);

    let mut trailing = bytes;
    trailing.push(0);
    let trailing_error = EncodedFrame::decode_framed::<serde_json::Value>(&trailing)
        .expect_err("frame with trailing bytes should fail");
    assert_eq!(trailing_error.kind(), std::io::ErrorKind::InvalidData);
}

#[tokio::test]
async fn frame_wire_format_is_little_endian_length_prefixed_json() {
    let (writer, mut reader) = tokio::io::duplex(/*max_buf_size*/ 128);
    let write = tokio::spawn(async move {
        FramedWriter::new(writer)
            .write(&json!({"value": 1}))
            .await
            .expect("write frame");
    });

    let mut bytes = Vec::new();
    reader.read_to_end(&mut bytes).await.expect("read bytes");
    write.await.expect("writer task");

    let payload = br#"{"value":1}"#;
    let mut expected = (payload.len() as u32).to_le_bytes().to_vec();
    expected.extend_from_slice(payload);
    assert_eq!(bytes, expected);
}

#[tokio::test]
async fn fragmented_frame_round_trips() {
    let value = json!({"type": "session/open", "sessionId": "session-1"});
    let payload = serde_json::to_vec(&value).expect("serialize");
    let mut bytes = (payload.len() as u32).to_le_bytes().to_vec();
    bytes.extend(payload);

    let (mut writer, reader) = tokio::io::duplex(/*max_buf_size*/ 128);
    let write = tokio::spawn(async move {
        for byte in bytes {
            writer.write_all(&[byte]).await.expect("write byte");
            tokio::task::yield_now().await;
        }
    });

    assert_eq!(
        FramedReader::new(reader)
            .read::<serde_json::Value>()
            .await
            .expect("read frame"),
        Some(value)
    );
    write.await.expect("writer task");
}

#[tokio::test]
async fn eof_is_clean_only_at_a_frame_boundary() {
    let (writer, reader) = tokio::io::duplex(/*max_buf_size*/ 16);
    drop(writer);
    assert_eq!(
        FramedReader::new(reader)
            .read::<serde_json::Value>()
            .await
            .expect("clean eof"),
        None
    );

    let (mut writer, reader) = tokio::io::duplex(/*max_buf_size*/ 16);
    writer
        .write_all(&[1, 0])
        .await
        .expect("write partial header");
    drop(writer);
    let err = FramedReader::new(reader)
        .read::<serde_json::Value>()
        .await
        .expect_err("truncated header");
    assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
}

#[tokio::test]
async fn oversized_and_malformed_frames_are_rejected() {
    let (mut writer, reader) = tokio::io::duplex(/*max_buf_size*/ 16);
    writer
        .write_all(&((MAX_FRAME_BYTES as u32) + 1).to_le_bytes())
        .await
        .expect("write oversized header");
    let err = FramedReader::new(reader)
        .read::<serde_json::Value>()
        .await
        .expect_err("oversized frame");
    assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);

    let (mut writer, reader) = tokio::io::duplex(/*max_buf_size*/ 16);
    writer
        .write_all(&(1_u32).to_le_bytes())
        .await
        .expect("write length");
    writer.write_all(b"{").await.expect("write malformed json");
    let err = FramedReader::new(reader)
        .read::<serde_json::Value>()
        .await
        .expect_err("malformed frame");
    assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
}