forked from benalexau/ibconnect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generic_feed_test.go
115 lines (100 loc) · 2.8 KB
/
generic_feed_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
package gateway
import (
"github.com/benalexau/ibconnect/core"
"github.com/gofinance/ib"
"github.com/gorhill/cronexpr"
"testing"
"time"
)
func TestGenericHourlyFeed(t *testing.T) {
if err := runGenericFeedTest(t, nil, cronexpr.MustParse("@hourly"), 1*time.Second, 1); err != nil {
t.Fatal(err)
}
}
func TestGenericFeedRefreshInterval(t *testing.T) {
oncePerSecond := "* * * * * * *"
if err := runGenericFeedTest(t, nil, cronexpr.MustParse(oncePerSecond), 3*time.Second, 2); err != nil {
t.Fatal(err)
}
}
func TestGenericFeedFiredOnRefreshAllEvent(t *testing.T) {
done := false
fun := func(ctx *FeedContext) {
if !done {
done = true
ctx.N.Publish(core.NtRefreshAll, 0)
}
}
// expect 2 events (1 due to startup, 1 due to NtRefreshAll request)
if err := runGenericFeedTest(t, fun, cronexpr.MustParse("@hourly"), 1*time.Second, 2); err != nil {
t.Fatal(err)
}
}
func TestGenericFeedKilledNotificationSystem(t *testing.T) {
fun := func(ctx *FeedContext) {
ctx.N.Close() // easiest way to kill it
}
if err := runGenericFeedTest(t, fun, cronexpr.MustParse("@hourly"), 1*time.Second, 100000); err == nil {
t.Fatal("killing notifier should have reported back an error")
}
}
// runGenericFeedTest returns any error reported to the error channel. It fails
// the test if the expected count is not reached within one second of loading.
func runGenericFeedTest(t *testing.T, fun func(*FeedContext), cronRefresh *cronexpr.Expression, waitTime time.Duration, expectedCount int) error {
c := core.NewTestConfig(t)
ctx, err := core.NewContext(c)
if err != nil {
t.Fatal(err)
}
defer ctx.Close()
errors := make(chan FeedError)
var lastError error
terminateErrors := make(chan struct{})
defer close(terminateErrors)
go func() {
for {
select {
case e := <-errors:
lastError = e.Error
case <-terminateErrors:
return
}
}
}()
var engine *ib.Engine
fc := &FeedContext{errors, ctx.DB, ctx.N, engine}
gft := newTestGenericFeed(t, fc, fun, cronRefresh)
defer gft.Close()
killAt := time.Now().Add(waitTime)
for gft.counter < expectedCount {
if lastError != nil {
return lastError
}
if time.Now().After(killAt) {
t.Fatal("Insufficient callbacks (%d) before timeout", gft.counter)
}
}
gft.Close()
return lastError
}
type TestGenericFeed struct {
fun func(*FeedContext)
generic *GenericFeed
counter int
}
func newTestGenericFeed(t *testing.T, ctx *FeedContext, fun func(*FeedContext), cronRefresh *cronexpr.Expression) *TestGenericFeed {
g := &TestGenericFeed{}
notifications := []core.NtType{core.NtRefreshAll}
g.fun = fun
g.generic = NewGenericFeed(ctx, cronRefresh, notifications, g.callback)
return g
}
func (g *TestGenericFeed) callback(ctx *FeedContext) {
g.counter++
if g.fun != nil {
g.fun(ctx)
}
}
func (g *TestGenericFeed) Close() {
g.generic.Close()
}