-
Notifications
You must be signed in to change notification settings - Fork 21
/
msg_processing_spectest.go
128 lines (105 loc) · 3.99 KB
/
msg_processing_spectest.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
package tests
import (
"encoding/hex"
"fmt"
"os"
"reflect"
"testing"
"github.com/stretchr/testify/require"
"github.com/bloxapp/ssv-spec/qbft"
"github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv-spec/types/testingutils"
typescomparable "github.com/bloxapp/ssv-spec/types/testingutils/comparable"
)
// ChangeProposerFuncInstanceHeight tests with this height will return proposer operator ID 2
const ChangeProposerFuncInstanceHeight = 10
type MsgProcessingSpecTest struct {
Name string
Pre *qbft.Instance
PostRoot string
PostState types.Root `json:"-"` // Field is ignored by encoding/json
InputMessages []*qbft.SignedMessage
OutputMessages []*qbft.SignedMessage
ExpectedError string
ExpectedTimerState *testingutils.TimerState
}
func (test *MsgProcessingSpecTest) Run(t *testing.T) {
// temporary to override state comparisons from file not inputted one
test.overrideStateComparison(t)
lastErr := test.runPreTesting()
if len(test.ExpectedError) != 0 {
require.EqualError(t, lastErr, test.ExpectedError)
} else {
require.NoError(t, lastErr)
}
if test.ExpectedTimerState != nil {
// checks round timer state
timer, ok := test.Pre.GetConfig().GetTimer().(*testingutils.TestQBFTTimer)
if ok && timer != nil {
require.Equal(t, test.ExpectedTimerState.Timeouts, timer.State.Timeouts, "timer should have expected timeouts count")
require.Equal(t, test.ExpectedTimerState.Round, timer.State.Round, "timer should have expected round")
}
}
postRoot, err := test.Pre.State.GetRoot()
require.NoError(t, err)
// test output message
broadcastedSignedMsgs := test.Pre.GetConfig().GetNetwork().(*testingutils.TestingNetwork).BroadcastedMsgs
require.NoError(t, testingutils.VerifyListOfSignedSSVMessages(broadcastedSignedMsgs, test.Pre.State.Share.Committee))
broadcastedMsgs := testingutils.ConvertBroadcastedMessagesToSSVMessages(broadcastedSignedMsgs)
if len(test.OutputMessages) > 0 || len(broadcastedMsgs) > 0 {
require.Len(t, broadcastedMsgs, len(test.OutputMessages))
for i, msg := range test.OutputMessages {
r1, _ := msg.GetRoot()
msg2 := &qbft.SignedMessage{}
require.NoError(t, msg2.Decode(broadcastedMsgs[i].Data))
r2, _ := msg2.GetRoot()
require.EqualValues(t, r1, r2, fmt.Sprintf("output msg %d roots not equal", i))
}
}
// test root
if test.PostRoot != hex.EncodeToString(postRoot[:]) {
diff := typescomparable.PrintDiff(test.Pre.State, test.PostState)
require.Fail(t, fmt.Sprintf("expected root: %s\nactual root: %s\n\n", test.PostRoot, hex.EncodeToString(postRoot[:])), "post state not equal", diff)
}
}
func (test *MsgProcessingSpecTest) runPreTesting() error {
// a simple hack to change the proposer func
if test.Pre.State.Height == ChangeProposerFuncInstanceHeight {
test.Pre.GetConfig().(*qbft.Config).ProposerF = func(state *qbft.State, round qbft.Round) types.OperatorID {
return 2
}
}
var lastErr error
for _, msg := range test.InputMessages {
_, _, _, err := test.Pre.ProcessMsg(msg)
if err != nil {
lastErr = err
}
}
return lastErr
}
func (test *MsgProcessingSpecTest) TestName() string {
return "qbft message processing " + test.Name
}
func (test *MsgProcessingSpecTest) overrideStateComparison(t *testing.T) {
basedir, err := os.Getwd()
require.NoError(t, err)
test.PostState, err = typescomparable.UnmarshalStateComparison(basedir, test.TestName(),
reflect.TypeOf(test).String(),
&qbft.State{})
require.NoError(t, err)
r, err := test.PostState.GetRoot()
require.NoError(t, err)
// backwards compatability test, hard coded post root must be equal to the one loaded from file
if len(test.PostRoot) > 0 {
require.EqualValues(t, test.PostRoot, hex.EncodeToString(r[:]))
}
test.PostRoot = hex.EncodeToString(r[:])
}
func (test *MsgProcessingSpecTest) GetPostState() (interface{}, error) {
err := test.runPreTesting()
if err != nil && len(test.ExpectedError) == 0 { // only non expected errors should return error
return nil, err
}
return test.Pre.State, nil
}