Files @ 1f78496722d1
Branch filter:

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

1f78496722d1 11.8 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
Max Henger
feat: runtime error handling
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
bf4c0ee5ba65
bf4c0ee5ba65
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
1f78496722d1
bf4c0ee5ba65
bf4c0ee5ba65
bf4c0ee5ba65
bf4c0ee5ba65
bf4c0ee5ba65
113e4349a706
113e4349a706
bf4c0ee5ba65
bf4c0ee5ba65
bf4c0ee5ba65
1f78496722d1
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
53d3950d9b6b
1f78496722d1
53d3950d9b6b
637115283740
bf4c0ee5ba65
0781cf1b7abf
0781cf1b7abf
0781cf1b7abf
3d271f7cfd7e
0ec053ef96b5
3d271f7cfd7e
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
3d271f7cfd7e
3d271f7cfd7e
3d271f7cfd7e
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
3d271f7cfd7e
3d271f7cfd7e
3d271f7cfd7e
3d271f7cfd7e
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
0b0b0a9c786b
3d271f7cfd7e
1f78496722d1
bf4c0ee5ba65
637115283740
637115283740
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
11fd959b348a
1f78496722d1
11fd959b348a
11fd959b348a
11fd959b348a
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
113e4349a706
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
1f78496722d1
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
1f78496722d1
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
637115283740
1f78496722d1
637115283740
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
1f78496722d1
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
113e4349a706
1f78496722d1
113e4349a706
53d3950d9b6b
use crate::protocol::*;
use crate::protocol::eval::*;
use crate::runtime2::runtime::*;
use crate::runtime2::component::{CompCtx, CompPDL};

mod error_handling;

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

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_pdl_component();
    let ctx = CompCtx::new(&reserved);
    let component = Box::new(CompPDL::new(prompt, 0));
    let (key, _) = rt.inner.finish_create_pdl_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"
    primitive 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_component_communication() {
    let pd = ProtocolDescription::parse(b"
    primitive sender(out<u32> o, u32 outside_loops, u32 inside_loops) {
        u32 outside_index = 0;
        while (outside_index < outside_loops) {
            u32 inside_index = 0;
            sync while (inside_index < inside_loops) {
                put(o, inside_index);
                inside_index += 1;
            }
            outside_index += 1;
        }
    }

    primitive receiver(in<u32> i, u32 outside_loops, u32 inside_loops) {
        u32 outside_index = 0;
        while (outside_index < outside_loops) {
            u32 inside_index = 0;
            sync while (inside_index < inside_loops) {
                auto val = get(i);
                while (val != inside_index) {} // infinite loop if incorrect value is received
                inside_index += 1;
            }
            outside_index += 1;
        }
    }

    composite constructor() {
        channel o_orom -> i_orom;
        channel o_mrom -> i_mrom;
        channel o_ormm -> i_ormm;
        channel o_mrmm -> i_mrmm;

        // one round, one message per round
        new sender(o_orom, 1, 1);
        new receiver(i_orom, 1, 1);

        // multiple rounds, one message per round
        new sender(o_mrom, 5, 1);
        new receiver(i_mrom, 5, 1);

        // one round, multiple messages per round
        new sender(o_ormm, 1, 5);
        new receiver(i_ormm, 1, 5);

        // multiple rounds, multiple messages per round
        new sender(o_mrmm, 5, 5);
        new receiver(i_mrmm, 5, 5);
    }").expect("compilation");
    let rt = Runtime::new(3, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor", no_args());
}

#[test]
fn test_intermediate_messenger() {
    let pd = ProtocolDescription::parse(b"
    primitive receiver<T>(in<T> rx, u32 num) {
        auto index = 0;
        while (index < num) {
            sync { auto v = get(rx); }
            index += 1;
        }
    }

    primitive middleman<T>(in<T> rx, out<T> tx, u32 num) {
        auto index = 0;
        while (index < num) {
            sync { put(tx, get(rx)); }
            index += 1;
        }
    }

    primitive sender<T>(out<T> tx, u32 num) {
        auto index = 0;
        while (index < num) {
            sync put(tx, 1337);
            index += 1;
        }
    }

    composite constructor_template<T>() {
        auto num = 0;
        channel<T> tx_a -> rx_a;
        channel tx_b -> rx_b;
        new sender(tx_a, 3);
        new middleman(rx_a, tx_b, 3);
        new receiver(rx_b, 3);
    }

    composite constructor() {
        new constructor_template<u16>();
        new constructor_template<u32>();
        new constructor_template<u64>();
        new constructor_template<s16>();
        new constructor_template<s32>();
        new constructor_template<s64>();
    }
    ").expect("compilation");
    let rt = Runtime::new(3, LOG_LEVEL, pd).unwrap();
    create_component(&rt, "", "constructor", 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 ();
    }

    primitive 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;
                }
            }
        }
    }

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

    composite 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"
    primitive constructor_outside_select() {
        u32 index = 0;
        while (index < 5) {
            sync select { auto v = () -> print(\"hello\"); }
            index += 1;
        }
    }

    primitive 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"
    primitive 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;

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

    composite 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::*;

    primitive requester(out<Cmd> cmd_tx, in<u8[]> data_rx) {
        print(\"*** TCPSocket: Sending request\");
        sync {
            put(cmd_tx, Cmd::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, Cmd::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, Cmd::Finish);
                        done_receiving = true;
                    }
                }
                index += 1;
            }
        }

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

    composite 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, true, 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,
    }

    primitive 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
            }
        }
    }

    primitive 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);
    }

    composite 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());
}