-
Notifications
You must be signed in to change notification settings - Fork 303
/
testing_store.go
141 lines (117 loc) · 3.1 KB
/
testing_store.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package store
import (
"fmt"
"reflect"
"sync"
"testing"
"time"
)
var _ RStore = &TestingStore{}
type TestingStore struct {
state *EngineState
stateMu sync.RWMutex
actions []Action
actionsMu sync.RWMutex
}
func NewTestingStore() *TestingStore {
return &TestingStore{
state: NewState(),
}
}
func (s *TestingStore) LockMutableStateForTesting() *EngineState {
s.stateMu.Lock()
return s.state
}
func (s *TestingStore) UnlockMutableState() {
s.stateMu.Unlock()
}
func (s *TestingStore) SetState(state EngineState) {
s.stateMu.Lock()
defer s.stateMu.Unlock()
s.state = &state
}
func (s *TestingStore) WithState(f func(state *EngineState)) {
s.stateMu.Lock()
defer s.stateMu.Unlock()
f(s.state)
}
func (s *TestingStore) StateMutex() *sync.RWMutex {
return &s.stateMu
}
func (s *TestingStore) RLockState() EngineState {
s.stateMu.RLock()
return *(s.state)
}
func (s *TestingStore) RUnlockState() {
s.stateMu.RUnlock()
}
func (s *TestingStore) Dispatch(action Action) {
s.actionsMu.Lock()
defer s.actionsMu.Unlock()
s.actions = append(s.actions, action)
}
func (s *TestingStore) ClearActions() {
s.actionsMu.Lock()
defer s.actionsMu.Unlock()
s.actions = nil
}
func (s *TestingStore) Actions() []Action {
s.actionsMu.RLock()
defer s.actionsMu.RUnlock()
return append([]Action{}, s.actions...)
}
func (s *TestingStore) AssertNoErrorActions(t testing.TB) bool {
t.Helper()
s.actionsMu.RLock()
defer s.actionsMu.RUnlock()
for _, action := range s.actions {
errAction, ok := action.(ErrorAction)
if ok {
t.Errorf("Error action: %s", errAction)
return false
}
}
return true
}
func (s *TestingStore) WaitForAction(t testing.TB, typ reflect.Type) Action {
return WaitForAction(t, typ, s.Actions)
}
// for use by tests (with a real channel-based store, NOT a TestingStore), to wait until
// an action of the specified type comes out of the given chan at some point we might want
// it to return the index it was found at, and then take an index, so that we can start
// searching from the next index
func WaitForAction(t testing.TB, typ reflect.Type, getActions func() []Action) Action {
start := time.Now()
timeout := 500 * time.Millisecond
for time.Since(start) < timeout {
actions := getActions()
for _, a := range actions {
if reflect.TypeOf(a) == typ {
return a
} else if la, ok := a.(LogAction); ok {
fmt.Println(string(la.Message()))
}
}
}
t.Fatalf("timed out waiting for action of type %s. Saw the following actions while waiting: %+v",
typ.Name(),
getActions())
return nil
}
// for use by tests (with a real channel-based store, NOT a TestingStore). Assert that
// we don't see an action of the given type
func AssertNoActionOfType(t testing.TB, typ reflect.Type, getActions func() []Action) Action {
start := time.Now()
timeout := 300 * time.Millisecond
for time.Since(start) < timeout {
actions := getActions()
for _, a := range actions {
if reflect.TypeOf(a) == typ {
t.Fatalf("Found action of type %s where none was expected: %+v", typ.Name(), a)
} else if la, ok := a.(LogAction); ok {
fmt.Println(string(la.Message()))
}
}
}
return nil
}