describe("channel module", function() it("should load",function() require("channel") end) describe("SimpleChannel",function() local channel = require("channel") it("should exist",function() assert(channel.SimpleChannel) assert(channel.SimpleChannel()) end) it("should send messages",function() local sc = channel.SimpleChannel() assert(not sc:poll()) sc:send("Hello") assert(sc:poll()) assert(sc:recv() == "Hello") end) it("should send any string",function() local sc = channel.SimpleChannel() local rng = tostring(math.random()) sc:send(rng) assert(sc:recv() == rng) end) end) describe("FaultyChannel",function() local channel = require("channel") it("should exist",function() assert(channel.FaultyChannel) assert(channel.FaultyChannel()) end) it("can has a .time that allows it to time travel",function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ loss_std = 0, avg_latency = 5 }) fc:send("a") assert(#fc.to_deliver == 1) assert(#fc.buffer == 0) channel.FaultyChannel.time = 10 fc:pump() assert(#fc.to_deliver == 0) assert(#fc.buffer == 1) assert(fc:recv() == "a") end) it("has a normal() function that does normal distribution", function() local normal = channel.FaultyChannel.normal for i = 1, 20 do math.randomseed(i) local res = normal(nil,1,0.1) assert(res > 0.5 and res < 1.5) end end) it("can pump() with no side effects if time has not changed", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ loss = 0, avg_latency = 5 }) fc:send("a") assert(#fc.to_deliver == 1) assert(#fc.buffer == 0) fc:pump() assert(#fc.to_deliver == 1) assert(#fc.buffer == 0) channel.FaultyChannel.time = 4 fc:pump() fc:send("b") assert(#fc.to_deliver == 2) assert(#fc.buffer == 0) channel.FaultyChannel.time = 6 fc:pump() assert(#fc.to_deliver == 1) assert(#fc.buffer == 1) end) it("can be configured to not drop messages", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ avg_latency = 5, loss = 0 }) local i = 100 for _ = 1,i do fc:send("a") end channel.FaultyChannel.time = 10 local j = 0 while fc:poll() do j = j + 1 fc:recv() end assert(j == i) end) it("should drop messages sometimes",function() local fc = channel.FaultyChannel() local i = 100 for _ = 1, i do fc:send("a") end -- Time forward --channel.FaultyChannel.time = math.huge local j = 0 while fc:poll() do j = j + 1 fc:recv() end assert(j < i) end) it("should keep a queue of messages", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ loss = 0, avg_latency=0, latency_std=0, }) local i = 100 for j = 1, i do fc:send(tostring(j)) end channel.FaultyChannel.time = 1 fc:pump() assert(#fc.to_deliver == 0) assert(#fc.buffer == i) for j = 1, i do assert(tonumber(fc:recv()) == j) end assert(not fc:poll()) end) it("should deliver messages with different latencies", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ loss = 0, avg_latency = 20, latency_std = 5, }) local i = 100 for j = 1, i do fc:send(tostring(j)) end local received = 0 local increment = 0.5 local last_received = nil local found_out_of_order = false while received < i do while fc:poll() do local recv = tonumber(fc:recv()) if last_received and last_received < recv then found_out_of_order = true end last_received = recv received = received + 1 end channel.FaultyChannel.time = channel.FaultyChannel.time + increment end assert(found_out_of_order) end) end) end)