1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
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)
|