-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_server.go
251 lines (211 loc) · 7.47 KB
/
test_server.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package instestconveyor
import (
"context"
"github.com/gojuno/minimock/v3"
"github.com/stretchr/testify/require"
"github.com/insolar/assured-ledger/ledger-core/appctl/beat"
"github.com/insolar/assured-ledger/ledger-core/configuration"
"github.com/insolar/assured-ledger/ledger-core/crypto/legacyadapter"
"github.com/insolar/assured-ledger/ledger-core/cryptography/keystore"
"github.com/insolar/assured-ledger/ledger-core/cryptography/platformpolicy"
"github.com/insolar/assured-ledger/ledger-core/cryptography/secrets"
"github.com/insolar/assured-ledger/ledger-core/instrumentation/convlog"
"github.com/insolar/assured-ledger/ledger-core/instrumentation/insapp"
"github.com/insolar/assured-ledger/ledger-core/instrumentation/insconveyor"
"github.com/insolar/assured-ledger/ledger-core/instrumentation/inslogger/instestlogger"
"github.com/insolar/assured-ledger/ledger-core/log/logcommon"
"github.com/insolar/assured-ledger/ledger-core/network/consensus/gcpv2/api/member"
"github.com/insolar/assured-ledger/ledger-core/network/messagesender"
"github.com/insolar/assured-ledger/ledger-core/pulse"
"github.com/insolar/assured-ledger/ledger-core/reference"
"github.com/insolar/assured-ledger/ledger-core/testutils"
"github.com/insolar/assured-ledger/ledger-core/testutils/gen"
"github.com/insolar/assured-ledger/ledger-core/testutils/testpop"
"github.com/insolar/assured-ledger/ledger-core/vanilla/atomickit"
"github.com/insolar/assured-ledger/ledger-core/vanilla/injector"
"github.com/insolar/assured-ledger/ledger-core/vanilla/throw"
)
func NewTestServerTemplate(t logcommon.TestingLogger, filterFn logcommon.ErrorFilterFunc) *ServerTemplate {
instestlogger.SetTestOutputWithErrorFilter(t, filterFn)
s := &ServerTemplate{t: t.(minimock.Tester)}
pop := testpop.CreateManyNodePopulationMock(s.t, 1, member.PrimaryRoleLightMaterial)
s.pg = testutils.NewPulseGenerator(10, pop, nil)
s.pg.Generate()
return s
}
type ServerTemplate struct {
// set by constructor
t minimock.Tester
appFn AppCompartmentFunc
appImposeFn insconveyor.ImposerFunc
pg *testutils.PulseGenerator
// set by setters
cfg configuration.Configuration
ac *insapp.AppComponents
fn insconveyor.ImposerFunc
// set by init
app *insconveyor.AppCompartment
ctxCancelFn context.CancelFunc
state atomickit.StartStopFlag
}
func (p *ServerTemplate) T() minimock.Tester {
return p.t
}
type AppCompartmentFunc = func(configuration.Configuration, insapp.AppComponents) *insconveyor.AppCompartment
// InitTemplate is used to set up a default behavior for a test server. Can only be called once.
// Handler (appFn) must be provided to create an app compartment.
// Handler (appImposeFn) is optional and will be invoked before a handler set by SetImposer().
// Handler (appImposeFn) can set insconveyor.ImposerFunc.ComponentInterceptFn.
func (p *ServerTemplate) InitTemplate(appFn AppCompartmentFunc, appImposeFn insconveyor.ImposerFunc) {
switch {
case p.state.WasStarted():
panic(throw.IllegalState())
case p.appFn != nil:
panic(throw.IllegalState())
}
p.appFn = appFn
p.appImposeFn = appImposeFn
}
// SetConfig updates config. Can only be called before the server is initialized / started.
func (p *ServerTemplate) SetConfig(cfg configuration.Configuration) {
if p.state.WasStarted() {
panic(throw.IllegalState())
}
p.cfg = cfg
}
// SetImposer sets per-test override logic. Can only be called once and before the server is initialized / started.
// Handler is NOT allowed to set insconveyor.ImposerFunc.ComponentInterceptFn.
func (p *ServerTemplate) SetImposer(fn insconveyor.ImposerFunc) {
switch {
case p.state.WasStarted():
panic(throw.IllegalState())
case fn == nil:
panic(throw.IllegalValue())
case p.fn != nil:
panic(throw.IllegalState())
}
p.fn = fn
}
// SetAppComponents sets per-test overrides for app components. Nil values will be replaced by default.
// Can only be called once and before the server is initialized / started.
func (p *ServerTemplate) SetAppComponents(ac insapp.AppComponents) {
switch {
case p.state.WasStarted():
panic(throw.IllegalState())
case p.ac != nil:
panic(throw.IllegalState())
}
p.ac = &ac
}
// Start initializes and starts the test server.
func (p *ServerTemplate) Start() {
switch {
case p.state.WasStarted():
panic(throw.IllegalState())
case p.appFn == nil:
panic(throw.IllegalState())
}
var ac insapp.AppComponents
if p.ac != nil {
ac = *p.ac
}
if ac.MessageSender == nil {
ac.MessageSender = messagesender.NewServiceMock(p.t)
}
if ac.CryptoScheme == nil {
pcs := platformpolicy.NewPlatformCryptographyScheme()
kp := platformpolicy.NewKeyProcessor()
sk, err := secrets.GenerateKeyPair()
require.NoError(p.t, err)
ac.CryptoScheme = legacyadapter.New(pcs, kp, keystore.NewInplaceKeyStore(sk.Private))
}
if reference.IsEmpty(ac.LocalNodeRef) {
ac.LocalNodeRef = gen.UniqueGlobalRefWithPulse(pulse.MinTimePulse)
}
ctx := context.Background()
ctx, p.ctxCancelFn = context.WithCancel(ctx)
p.app = p.appFn(p.cfg, ac)
require.NotNil(p.t, p.app)
p.app.SetImposer(func(params *insconveyor.ImposedParams) {
params.CompartmentSetup.ConveyorConfig.ConveyorMachineConfig.SlotMachineLogger = nil
sml := ¶ms.CompartmentSetup.ConveyorConfig.SlotMachineConfig.SlotMachineLogger
*sml = nil
if p.appImposeFn != nil {
// set params.ComponentInterceptFn here to do post-checks on components
p.appImposeFn(params)
p.appImposeFn = nil
}
if p.fn != nil {
cif := params.ComponentInterceptFn
params.ComponentInterceptFn = nil
p.fn(params)
p.fn = nil
if params.ComponentInterceptFn != nil {
// Individual tests should not use params.ComponentInterceptFn
panic(throw.IllegalState())
}
params.ComponentInterceptFn = cif
}
switch {
case *sml != nil:
case convlog.UseTextConvLog():
*sml = convlog.MachineLogger{}
default:
*sml = insconveyor.ConveyorLoggerFactory{}
}
if params.EventJournal != nil {
*sml = params.EventJournal.InterceptSlotMachineLog(*sml, params.InitContext.Done())
}
})
err := p.app.Init(ctx)
require.NoError(p.t, err)
if !p.state.Start() {
panic(throw.IllegalState())
}
err = p.app.Start(ctx)
require.NoError(p.t, err)
}
// IncrementPulse generates and applies next pulse.
func (p *ServerTemplate) IncrementPulse() {
p.pg.Generate()
if !p.state.IsActive() {
return
}
bd := p.app.GetBeatDispatcher()
ack, _ := beat.NewAck(func(beat.AckData) {})
bd.PrepareBeat(ack)
bd.CommitBeat(p.pg.GetLastBeat())
}
// Stop cancels context and initiates stop of the app compartment.
func (p *ServerTemplate) Stop() {
p.state.DoDiscard(func() {
// not started
}, func() {
ctx := context.Background()
p.ctxCancelFn()
err := p.app.Stop(ctx)
require.NoError(p.t, err)
})
}
// App returns app compartment. Panics when wasn't started.
func (p *ServerTemplate) App() *insconveyor.AppCompartment {
if p.app == nil {
panic(throw.IllegalState())
}
return p.app
}
// Injector returns a dependency injector with dependencies available for the app compartment.
// There is NO access to dependencies added by pulse slots. Panics when wasn't started.
func (p *ServerTemplate) Injector() injector.DependencyInjector {
return injector.NewDependencyInjector(struct{}{}, p.App().Conveyor(), nil)
}
// Pulsar returns a pulse generator. Panics when zero.
func (p *ServerTemplate) Pulsar() *testutils.PulseGenerator {
if p.pg == nil {
panic(throw.IllegalState())
}
return p.pg
}
func (p *ServerTemplate) LastPulseNumber() pulse.Number {
return p.Pulsar().GetLastPulseData().PulseNumber
}