Files @ 9206016be13b
Branch filter:

Location: CSY/reowolf/src/runtime/tests/sync_failure.rs

9206016be13b 4.5 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
Max Henger
Merge branch 'feat-tcp-listener' into 'master'

feat: tcp listener

See merge request nl-cwi-csy/reowolf!9
// sync_failure.rs
//
// Various tests to ensure that failing components fail in a consistent way.

use super::*;

#[test]
fn test_local_sync_failure() {
    // If the component exits cleanly, then the runtime exits cleanly, and the
    // test will finish
    const CODE: &'static str = "
    comp immediate_failure_inside_sync() {
        u32[] only_allows_index_0 = { 1 };
        while (true) sync { // note the infinite loop
            auto value = only_allows_index_0[1];
        }
    }

    comp immediate_failure_outside_sync() {
        u32[] only_allows_index_0 = { 1 };
        auto never_gonna_get = only_allows_index_0[1];
        while (true) sync {}
    }
    ";

    // let thing = TestTimer::new("local_sync_failure");
    run_test_in_runtime(CODE, |api| {
        api.create_connector("", "immediate_failure_outside_sync", ValueGroup::new_stack(Vec::new()))
            .expect("create component");

        api.create_connector("", "immediate_failure_inside_sync", ValueGroup::new_stack(Vec::new()))
            .expect("create component");
    })
}

const SHARED_SYNC_CODE: &'static str = "
enum Location { BeforeSync, AfterPut, AfterGet, AfterSync, Never }
comp failing_at_location(in<bool> input, out<bool> output, Location loc) {
    u32[] failure_array = {};
    while (true) {
        if (loc == Location::BeforeSync) failure_array[0];
        sync {
            put(output, true);
            if (loc == Location::AfterPut) failure_array[0];
            auto received = get(input);
            assert(received);
            if (loc == Location::AfterGet) failure_array[0];
        }
        if (loc == Location::AfterSync) failure_array[0];
    }
}

comp constructor_pair_a(Location loc) {
    channel output_a -> input_a;
    channel output_b -> input_b;
    new failing_at_location(input_b, output_a, loc);
    new failing_at_location(input_a, output_b, Location::Never);
}

comp constructor_pair_b(Location loc) {
    channel output_a -> input_a;
    channel output_b -> input_b;
    new failing_at_location(input_b, output_a, Location::Never);
    new failing_at_location(input_a, output_b, loc);
}

comp constructor_ring(u32 ring_size, u32 fail_a, Location loc_a, u32 fail_b, Location loc_b) {
    channel output_first -> input_old;
    channel output_cur -> input_new;

    u32 ring_index = 0;
    while (ring_index < ring_size) {
        auto cur_loc = Location::Never;
        if (ring_index == fail_a) cur_loc = loc_a;
        if (ring_index == fail_b) cur_loc = loc_b;

        new failing_at_location(input_old, output_cur, cur_loc);

        if (ring_index == ring_size - 2) {
            // Don't create a new channel, join up the last one
            output_cur = output_first;
            input_old = input_new;
        } else if (ring_index != ring_size - 1) {
            channel output_fresh -> input_fresh;
            input_old = input_new;
            output_cur = output_fresh;
            input_new = input_fresh;
        }

        ring_index += 1;
    }
}
";

#[test]
fn test_shared_sync_failure_pair_variant_a() {
    // One fails, the other one should somehow detect it and fail as well. This
    // variant constructs the failing component first.
    run_test_in_runtime(SHARED_SYNC_CODE, |api| {
        for variant in 0..4 { // all `Location` enum variants, except `Never`.
            // Create the channels
            api.create_connector("", "constructor_pair_a", ValueGroup::new_stack(vec![
                Value::Enum(variant)
            ])).expect("create connector");
        }
    })
}

#[test]
fn test_shared_sync_failure_pair_variant_b() {
    // One fails, the other one should somehow detect it and fail as well. This
    // variant constructs the successful component first.
    run_test_in_runtime(SHARED_SYNC_CODE, |api| {
        for variant in 0..4 {
            api.create_connector("", "constructor_pair_b", ValueGroup::new_stack(vec![
                Value::Enum(variant)
            ])).expect("create connector");
        }
    })
}

#[test]
fn test_shared_sync_failure_ring_variant_a() {
    // Only one component in the ring should fail
    const RING_SIZE: u32 = 4;
    run_test_in_runtime(SHARED_SYNC_CODE, |api| {
        for variant in 0..4 {
            api.create_connector("", "constructor_ring", ValueGroup::new_stack(vec![
                Value::UInt32(RING_SIZE),
                Value::UInt32(RING_SIZE / 2), Value::Enum(variant), // fail "halfway" the ring
                Value::UInt32(RING_SIZE), Value::Enum(0), // never occurs, index is equal to ring size
            ])).expect("create connector");
        }
    })
}