glorious sans-io tests

This commit is contained in:
nora 2024-08-15 15:45:16 +02:00
parent d68caf8e3c
commit 8c1f3afd89
3 changed files with 107 additions and 12 deletions

View file

@ -399,13 +399,14 @@ impl ServerChannelsState {
pub fn do_operation(&mut self, op: ChannelOperation) {
op.trace();
let channel = self
.channel(op.number)
.expect("passed channel ID that does not exist");
let Ok(channel) = self.channel(op.number) else {
debug!(number = %op.number, "Dropping operation as channel does not exist, probably because it has been closed");
return;
};
let peer = channel.peer_channel;
if channel.we_closed {
debug!("Dropping operation as channel has been closed already");
debug!(number = %op.number, "Dropping operation as channel has been closed already");
return;
}
@ -534,20 +535,88 @@ impl ChannelOperation {
#[cfg(test)]
mod tests {
use ssh_transport::packet::Packet;
use ssh_transport::{numbers, packet::Packet};
use crate::ServerChannelsState;
use crate::{ChannelNumber, ChannelOperation, ChannelOperationKind, ServerChannelsState};
fn assert_response(state: &mut ServerChannelsState, types: &[u8]) {
let response = state
.packets_to_send()
.map(|p| numbers::packet_type_to_string(p.packet_type()))
.collect::<Vec<_>>();
let expected = types
.iter()
.map(|p| numbers::packet_type_to_string(*p))
.collect::<Vec<_>>();
assert_eq!(expected, response);
}
fn open_session_channel(state: &mut ServerChannelsState) {
state
.recv_packet(Packet::new_msg_channel_open_session(
b"session", 0, 2048, 1024,
))
.unwrap();
assert_response(state, &[numbers::SSH_MSG_CHANNEL_OPEN_CONFIRMATION]);
}
#[test]
fn interactive_pty() {
let state = &mut ServerChannelsState::new();
open_session_channel(state);
state
.recv_packet(Packet::new_msg_channel_request_pty_req(
0, b"pty-req", true, b"xterm", 80, 24, 0, 0, b"",
))
.unwrap();
state.do_operation(ChannelNumber(0).construct_op(ChannelOperationKind::Success));
assert_response(state, &[numbers::SSH_MSG_CHANNEL_SUCCESS]);
state
.recv_packet(Packet::new_msg_channel_request_shell(0, b"shell", true))
.unwrap();
state.do_operation(ChannelNumber(0).construct_op(ChannelOperationKind::Success));
assert_response(state, &[numbers::SSH_MSG_CHANNEL_SUCCESS]);
state
.recv_packet(Packet::new_msg_channel_data(0, b"hello, world"))
.unwrap();
assert_response(state, &[]);
state.recv_packet(Packet::new_msg_channel_eof(0)).unwrap();
assert_response(state, &[]);
state.recv_packet(Packet::new_msg_channel_close(0)).unwrap();
assert_response(state, &[numbers::SSH_MSG_CHANNEL_CLOSE]);
}
#[test]
fn only_single_close_for_double_close_operation() {
let state = ServerChannelsState::new();
//state.recv_packet();
let state = &mut ServerChannelsState::new();
open_session_channel(state);
state.do_operation(ChannelOperation {
number: ChannelNumber(0),
kind: ChannelOperationKind::Close,
});
state.do_operation(ChannelOperation {
number: ChannelNumber(0),
kind: ChannelOperationKind::Close,
});
assert_response(state, &[numbers::SSH_MSG_CHANNEL_CLOSE]);
}
#[test]
#[should_panic]
fn panic_when_data_operation_after_close() {
let state = ServerChannelsState::new();
//state.recv_packet();
fn ignore_operation_after_close() {
let mut state = &mut ServerChannelsState::new();
open_session_channel(state);
state.recv_packet(Packet::new_msg_channel_close(0)).unwrap();
assert_response(&mut state, &[numbers::SSH_MSG_CHANNEL_CLOSE]);
state.do_operation(ChannelOperation {
number: ChannelNumber(0),
kind: ChannelOperationKind::Data(vec![0]),
});
assert_response(state, &[]);
}
}

View file

@ -148,6 +148,10 @@ pub struct Packet {
impl Packet {
pub const DEFAULT_BLOCK_SIZE: u8 = 8;
pub fn packet_type(&self) -> u8 {
self.payload[0]
}
pub(crate) fn from_full(bytes: &[u8]) -> Result<Self> {
let Some(padding_length) = bytes.first() else {
return Err(client_error!("empty packet"));

View file

@ -78,6 +78,12 @@ ctors! {
fn new_msg_request_failure(SSH_MSG_REQUEST_FAILURE;);
// 90 to 127 Channel related messages
fn new_msg_channel_open_session(SSH_MSG_CHANNEL_OPEN;
session: string,
sender_channel: u32,
initial_window_size: u32,
maximum_packet_size: u32,
);
fn new_msg_channel_open_confirmation(SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
peer_channel: u32,
sender_channel: u32,
@ -96,6 +102,22 @@ ctors! {
fn new_msg_channel_eof(SSH_MSG_CHANNEL_EOF; recipient_channel: u32);
fn new_msg_channel_close(SSH_MSG_CHANNEL_CLOSE; recipient_channel: u32);
fn new_msg_channel_request_pty_req(SSH_MSG_CHANNEL_REQUEST;
recipient_channel: u32,
kind_pty_req: string,
want_reply: bool,
term: string,
term_width_char: u32,
term_height_rows: u32,
term_width_px: u32,
term_height_px: u32,
term_modes: string,
);
fn new_msg_channel_request_shell(SSH_MSG_CHANNEL_REQUEST;
recipient_channel: u32,
kind_shell: string,
want_reply: bool,
);
fn new_msg_channel_request_exit_status(SSH_MSG_CHANNEL_REQUEST; recipient_channel: u32, kind_exit_status: string, false_: bool, exit_status: u32);
fn new_msg_channel_success(SSH_MSG_CHANNEL_SUCCESS; recipient_channel: u32);