-
Notifications
You must be signed in to change notification settings - Fork 2
/
route_test.go
126 lines (114 loc) · 2.99 KB
/
route_test.go
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
package main
import (
"bytes"
"io/ioutil"
"sync"
"testing"
"time"
)
type fakeInstance struct {
requestChan chan *request
responseChan chan *response
fakeTime time.Duration
}
func newFakeInstance() *fakeInstance {
return &fakeInstance{
requestChan: make(chan *request, 1),
responseChan: make(chan *response, 1),
}
}
func (fi *fakeInstance) Send(destination int, contents []byte) {
fi.fakeTime++
fi.requestChan <- &request{
requestType: requestSend,
time: fi.fakeTime,
destination: destination,
message: contents,
}
}
func (fi *fakeInstance) RecvFrom(source int) *Message {
fi.fakeTime++
fi.requestChan <- &request{
requestType: requestRecv,
time: fi.fakeTime,
source: source,
}
resp := <-fi.responseChan
if resp.message.SendTime > fi.fakeTime {
fi.fakeTime = resp.message.SendTime
}
resp.message.SendTime = 0
return resp.message
}
func (fi *fakeInstance) Recv() *Message {
fi.fakeTime++
fi.requestChan <- &request{
requestType: requestRecvAny,
time: fi.fakeTime,
}
resp := <-fi.responseChan
if resp.message.SendTime > fi.fakeTime {
fi.fakeTime = resp.message.SendTime
}
resp.message.SendTime = 0
return resp.message
}
func (fi *fakeInstance) Close() {
close(fi.requestChan)
}
func setupFakes(n int) []*fakeInstance {
fis := make([]*fakeInstance, n)
for i := range fis {
fis[i] = newFakeInstance()
}
return fis
}
func routeFakes(fis []*fakeInstance) error {
requestChans := make([]<-chan *request, len(fis))
responseChans := make([]chan<- *response, len(fis))
for i, fi := range fis {
requestChans[i] = fi.requestChan
responseChans[i] = fi.responseChan
}
return RouteMessages(requestChans, responseChans, ioutil.Discard)
}
// equivalentMessages returns true if the two messages are equal or differ in the SendTime only
func equivalentMessages(a, b *Message) bool {
return a.Source == b.Source && a.Target == b.Target && bytes.Equal(a.Message, b.Message)
}
func TestRouterSimple(t *testing.T) {
fakes := setupFakes(2)
done := make(chan bool)
go func() {
if err := routeFakes(fakes); err != nil {
t.Errorf("RouteMessages unexcpectedly failed: %v", err)
}
close(done)
}()
var wg sync.WaitGroup
wg.Add(1)
go func() {
fakes[0].Send(1, []byte("foobar"))
fakes[0].Send(0, []byte("foobaz"))
if got, want := fakes[0].RecvFrom(0), (&Message{Source: 0, Target: 0, Message: []byte("foobaz")}); !equivalentMessages(got, want) {
t.Errorf("unexpected message received: got=%+v, want=%+v", got, want)
}
if got, want := fakes[0].Recv(), (&Message{Source: 1, Target: 0, Message: []byte("barbaz")}); !equivalentMessages(got, want) {
t.Errorf("unexpected message received: got=%+v, want=%+v", got, want)
}
fakes[0].Close()
wg.Done()
}()
wg.Add(1)
go func() {
fakes[1].Send(0, []byte("barbaz"))
fakes[1].Recv()
fakes[1].Close()
wg.Done()
}()
wg.Wait()
<-done
}
// TODO: test the timestamp-ordering mechanism
// TODO: test deadlock detection (check for false positives too)
// TODO: test remaining messages detection