diff --git a/src/runtime2/tests/internet.rs b/src/runtime2/tests/internet.rs new file mode 100644 index 0000000000000000000000000000000000000000..6cb03b954005b551198ecc3add8df9f94a6e9786 --- /dev/null +++ b/src/runtime2/tests/internet.rs @@ -0,0 +1,196 @@ +use super::*; + +// silly test to make sure that the PDL will never be an issue when doing TCP +// stuff with the actual components +#[test] +fn test_stdlib_file() { + compile_and_create_component(" + import std.internet as inet; + + comp fake_listener_once(out tx) { + channel cmd_tx -> cmd_rx; + channel data_tx -> data_rx; + new fake_socket(cmd_rx, data_tx); + sync put(tx, inet::TcpConnection{ + tx: cmd_tx, + rx: data_rx, + }); + } + + comp fake_socket(in cmds, out tx) { + auto to_send = {}; + + auto shutdown = false; + while (!shutdown) { + auto keep_going = true; + sync { + while (keep_going) { + auto cmd = get(cmds); + if (let inet::ClientCmd::Send(data) = cmd) { + to_send = data; + keep_going = false; + } else if (let inet::ClientCmd::Receive = cmd) { + put(tx, to_send); + } else if (let inet::ClientCmd::Finish = cmd) { + keep_going = false; + } else if (let inet::ClientCmd::Shutdown = cmd) { + keep_going = false; + shutdown = true; + } + } + } + } + } + + comp fake_client(inet::TcpConnection conn) { + sync put(conn.tx, inet::ClientCmd::Send({1, 3, 3, 7})); + sync { + put(conn.tx, inet::ClientCmd::Receive); + auto val = get(conn.rx); + while (val[0] != 1 || val[1] != 3 || val[2] != 3 || val[3] != 7) { + print(\"this is going very wrong\"); + } + put(conn.tx, inet::ClientCmd::Finish); + } + sync put(conn.tx, inet::ClientCmd::Shutdown); + } + + comp constructor() { + channel conn_tx -> conn_rx; + new fake_listener_once(conn_tx); + + // Same crap as before: + channel cmd_tx -> unused_cmd_rx; + channel unused_data_tx -> data_rx; + auto connection = inet::TcpConnection{ tx: cmd_tx, rx: data_rx }; + + sync { + connection = get(conn_rx); + } + + new fake_client(connection); + } + ", "constructor", no_args()); +} + +#[test] +fn test_tcp_listener_and_client() { + compile_and_create_component(" + import std.internet::*; + + func listen_port() -> u16 { + return 2392; + } + + comp server(u32 num_connections, in<()> shutdown) { + // Start tcp listener + channel listen_cmd_tx -> listen_cmd_rx; + channel listen_conn_tx -> listen_conn_rx; + new tcp_listener({}, listen_port(), listen_cmd_rx, listen_conn_tx); + + // Fake channels such that we can create a dummy connection variable + channel client_cmd_tx -> unused_client_cmd_rx; + channel unused_client_data_tx -> client_data_rx; + auto new_connection = TcpConnection{ + tx: client_cmd_tx, + rx: client_data_rx, + }; + + auto connection_counter = 0; + while (connection_counter < num_connections) { + // Wait until we get a connection + print(\"server: waiting for an accepted connection\"); + sync { + put(listen_cmd_tx, ListenerCmd::Accept); + new_connection = get(listen_conn_rx); + } + + // We have a new connection, spawn an 'echoer' for it + print(\"server: spawning an echo'ing component\"); + new echo_machine(new_connection); + connection_counter += 1; + } + + // Shut down the listener + print(\"server: shutting down listener\"); + sync auto v = get(shutdown); + sync put(listen_cmd_tx, ListenerCmd::Shutdown); + } + + // Waits for a single TCP byte (to simplify potentially having to + // concatenate requests) and echos it + comp echo_machine(TcpConnection conn) { + auto data_to_echo = {}; + + // Wait for a message + sync { + print(\"echo: receiving data\"); + put(conn.tx, ClientCmd::Receive); + data_to_echo = get(conn.rx); + put(conn.tx, ClientCmd::Finish); + } + + // Echo the message + print(\"echo: sending back data\"); + sync put(conn.tx, ClientCmd::Send(data_to_echo)); + + // Ask the tcp connection to shut down + print(\"echo: shutting down\"); + sync put(conn.tx, ClientCmd::Shutdown); + } + + comp echo_requester(u8 byte_to_send, out<()> done) { + channel cmd_tx -> cmd_rx; + channel data_tx -> data_rx; + new tcp_client({127, 0, 0, 1}, listen_port(), cmd_rx, data_tx); + + // Send the message + print(\"requester: sending bytes\"); + sync put(cmd_tx, ClientCmd::Send({ byte_to_send })); + + // Receive the echo'd byte + auto received_byte = byte_to_send + 1; + sync { + print(\"requester: receiving echo response\"); + put(cmd_tx, ClientCmd::Receive); + received_byte = get(data_rx)[0]; + put(cmd_tx, ClientCmd::Finish); + } + + // Silly check, as always + while (byte_to_send != received_byte) { + print(\"requester: Oh no! The echo is an otherworldly distorter\"); + } + + // Shut down the TCP connection + print(\"requester: shutting down TCP component\"); + sync put(cmd_tx, ClientCmd::Shutdown); + sync put(done, ()); + } + + comp constructor() { + auto num_connections = 1; + channel shutdown_listener_tx -> shutdown_listener_rx; + new server(num_connections, shutdown_listener_rx); + + auto connection_index = 0; + auto all_done = {}; + while (connection_index < num_connections) { + channel done_tx -> done_rx; + new echo_requester(cast(connection_index), done_tx); + connection_index += 1; + all_done @= {done_rx}; + } + + auto counter = 0; + while (counter < length(all_done)) { + print(\"constructor: waiting for requester to exit\"); + sync auto v = get(all_done[counter]); + counter += 1; + } + + print(\"constructor: instructing listener to exit\"); + sync put(shutdown_listener_tx, ()); + } + ", "constructor", no_args()); +} \ No newline at end of file