Files @ 390da0a44204
Branch filter:

Location: CSY/reowolf/src/runtime2/tests/mod.rs

390da0a44204 8.9 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
mh
Update to tests
use crate::protocol::*;
use crate::protocol::eval::*;
use crate::runtime2::runtime::*;
use crate::runtime2::component::{CompCtx, CompPDL};

mod messaging;
mod error_handling;
mod transfer_ports;
mod internet;

const LOG_LEVEL: LogLevel = LogLevel::Debug;
const NUM_THREADS: u32 = 1;

pub(crate) fn compile_and_create_component(source: &str, routine_name: &str, args: ValueGroup) {
    let protocol = ProtocolDescription::parse(source.as_bytes())
        .expect("successful compilation");
    let runtime = Runtime::new(NUM_THREADS, LOG_LEVEL, protocol)
        .expect("successful runtime startup");
    create_component(&runtime, "", routine_name, args);
}

pub(crate) fn create_component(rt: &Runtime, module_name: &str, routine_name: &str, args: ValueGroup) {
    let prompt = rt.inner.protocol.new_component(
        module_name.as_bytes(), routine_name.as_bytes(), args
    ).expect("create prompt");
    let reserved = rt.inner.start_create_component();
    let ctx = CompCtx::new(&reserved);
    let component = Box::new(CompPDL::new(prompt, 0));
    let (key, _) = rt.inner.finish_create_component(reserved, component, ctx, false);
    rt.inner.enqueue_work(key);
}

pub(crate) fn no_args() -> ValueGroup { ValueGroup::new_stack(Vec::new()) }

#[test]
fn test_component_creation() {
    let pd = ProtocolDescription::parse(b"
    comp nothing_at_all() {
        s32 a = 5;
        auto b = 5 + a;
    }
    ").expect("compilation");
    let rt = Runtime::new(1, LOG_LEVEL, pd).unwrap();

    for _i in 0..20 {
        create_component(&rt, "", "nothing_at_all", no_args());
    }
}

#[test]
fn test_simple_select() {
    let pd = ProtocolDescription::parse(b"
    func infinite_assert<T>(T val, T expected) -> () {
        while (val != expected) { print(\"nope!\"); }
        return ();
    }

    comp receiver(in<u32> in_a, in<u32> in_b, u32 num_sends) {
        auto num_from_a = 0;
        auto num_from_b = 0;
        while (num_from_a + num_from_b < 2 * num_sends) {
            sync select {
                auto v = get(in_a) -> {
                    print(\"got something from A\");
                    auto _ = infinite_assert(v, num_from_a);
                    num_from_a += 1;
                }
                auto v = get(in_b) -> {
                    print(\"got something from B\");
                    auto _ = infinite_assert(v, num_from_b);
                    num_from_b += 1;
                }
            }
        }
    }

    comp sender(out<u32> tx, u32 num_sends) {
        auto index = 0;
        while (index < num_sends) {
            sync {
                put(tx, index);
                index += 1;
            }
        }
    }

    comp constructor() {
        auto num_sends = 1;
        channel tx_a -> rx_a;
        channel tx_b -> rx_b;
        new sender(tx_a, num_sends);
        new receiver(rx_a, rx_b, num_sends);
        new sender(tx_b, num_sends);
    }
    ").expect("compilation");
    let rt = Runtime::new(3, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor", no_args());
}

#[test]
fn test_unguarded_select() {
    let pd = ProtocolDescription::parse(b"
    comp constructor_outside_select() {
        u32 index = 0;
        while (index < 5) {
            sync select { auto v = () -> print(\"hello\"); }
            index += 1;
        }
    }

    comp constructor_inside_select() {
        u32 index = 0;
        while (index < 5) {
            sync select { auto v = () -> index += 1; }
        }
    }
    ").expect("compilation");
    let rt = Runtime::new(3, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor_outside_select", no_args());
    create_component(&rt, "", "constructor_inside_select", no_args());
}

#[test]
fn test_empty_select() {
    let pd = ProtocolDescription::parse(b"
    comp constructor() {
        u32 index = 0;
        while (index < 5) {
            sync select {}
            index += 1;
        }
    }
    ").expect("compilation");
    let rt = Runtime::new(3, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor", no_args());
}

#[test]
fn test_random_u32_temporary_thingo() {
    let pd = ProtocolDescription::parse(b"
    import std.random::random_u32;

    comp random_taker(in<u32> generator, u32 num_values) {
        auto i = 0;
        while (i < num_values) {
            sync {
                auto a = get(generator);
            }
            i += 1;
        }
    }

    comp constructor() {
        channel tx -> rx;
        auto num_values = 25;
        new random_u32(tx, 1, 100, num_values);
        new random_taker(rx, num_values);
    }
    ").expect("compilation");
    let rt = Runtime::new(1, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor", no_args());
}

#[test]
fn test_tcp_socket_http_request() {
    let _pd = ProtocolDescription::parse(b"
    import std.internet::*;

    comp requester(out<ClientCmd> cmd_tx, in<u8[]> data_rx) {
        print(\"*** TCPSocket: Sending request\");
        sync {
            put(cmd_tx, ClientCmd::Send(b\"GET / HTTP/1.1\\r\\n\\r\\n\"));
        }

        print(\"*** TCPSocket: Receiving response\");
        auto buffer = {};
        auto done_receiving = false;
        sync while (!done_receiving) {
            put(cmd_tx, ClientCmd::Receive);
            auto data = get(data_rx);
            buffer @= data;

            // Completely crap detection of end-of-document. But here we go, we
            // try to detect the trailing </html>. Proper way would be to parse
            // for 'content-length' or 'content-encoding'
            s32 index = 0;
            s32 partial_length = cast(length(data) - 7);
            while (index < partial_length) {
                // No string conversion yet, so check byte buffer one byte at
                // a time.
                auto c1 = data[index];
                if (c1 == cast('<')) {
                    auto c2 = data[index + 1];
                    auto c3 = data[index + 2];
                    auto c4 = data[index + 3];
                    auto c5 = data[index + 4];
                    auto c6 = data[index + 5];
                    auto c7 = data[index + 6];
                    if ( // i.e. if (data[index..] == '</html>'
                        c2 == cast('/') && c3 == cast('h') && c4 == cast('t') &&
                        c5 == cast('m') && c6 == cast('l') && c7 == cast('>')
                    ) {
                        print(\"*** TCPSocket: Detected </html>\");
                        put(cmd_tx, ClientCmd::Finish);
                        done_receiving = true;
                    }
                }
                index += 1;
            }
        }

        print(\"*** TCPSocket: Requesting shutdown\");
        sync {
            put(cmd_tx, ClientCmd::Shutdown);
        }
    }

    comp main() {
        channel cmd_tx -> cmd_rx;
        channel data_tx -> data_rx;
        new tcp_client({142, 250, 179, 163}, 80, cmd_rx, data_tx); // port 80 of google
        new requester(cmd_tx, data_rx);
    }
    ").expect("compilation");

    // This test is disabled because it performs a HTTP request to google.
    // let rt = Runtime::new(1, LOG_LEVEL, _pd).unwrap();
    // create_component(&rt, "", "main", no_args());
}

#[test]
fn test_sending_receiving_union() {
    let pd = ProtocolDescription::parse(b"
    union Cmd {
        Set(u8[]),
        Get,
        Shutdown,
    }

    comp database(in<Cmd> rx, out<u8[]> tx) {
        auto stored = {};
        auto done = false;
        while (!done) {
            sync {
                auto command = get(rx);
                if (let Cmd::Set(bytes) = command) {
                    print(\"database: storing value\");
                    stored = bytes;
                } else if (let Cmd::Get = command) {
                    print(\"database: returning value\");
                    put(tx, stored);
                } else if (let Cmd::Shutdown = command) {
                    print(\"database: shutting down\");
                    done = true;
                } else while (true) print(\"impossible\"); // no other case possible
            }
        }
    }

    comp client(out<Cmd> tx, in<u8[]> rx, u32 num_rounds) {
        auto round = 0;
        while (round < num_rounds) {
            auto set_value = b\"hello there\";
            print(\"client: putting a value\");
            sync put(tx, Cmd::Set(set_value));

            auto retrieved = {};
            print(\"client: retrieving what was sent\");
            sync {
                put(tx, Cmd::Get);
                retrieved = get(rx);
            }

            if (set_value != retrieved) while (true) print(\"wrong!\");

            round += 1;
        }

        sync put(tx, Cmd::Shutdown);
    }

    comp main() {
        auto num_rounds = 5;
        channel cmd_tx -> cmd_rx;
        channel data_tx -> data_rx;
        new database(cmd_rx, data_tx);
        new client(cmd_tx, data_rx, num_rounds);
    }
    ").expect("compilation");
    let rt = Runtime::new(1, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "main", no_args());
}