/
utils.go
141 lines (130 loc) · 3.81 KB
/
utils.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 rpctest
import (
"reflect"
"time"
"github.com/p9c/monorepo/pkg/chainhash"
"github.com/p9c/monorepo/pkg/rpcclient"
)
// JoinType is an enum representing a particular type of "node join". A node
// join is a synchronization tool used to wait until a subset of nodes have a
// consistent state with respect to an attribute.
type JoinType uint8
const (
// Blocks is a JoinType which waits until all nodes share the same block
// height.
Blocks JoinType = iota
// Mempools is a JoinType which blocks until all nodes have identical mempool.
Mempools
)
// JoinNodes is a synchronization tool used to block until all passed nodes are
// fully synced with respect to an attribute. This function will block for a
// period of time, finally returning once all nodes are synced according to the
// passed JoinType. This function be used to to ensure all active test harnesses
// are at a consistent state before proceeding to an assertion or check within
// rpc tests.
func JoinNodes(nodes []*Harness, joinType JoinType) (e error) {
switch joinType {
case Blocks:
return syncBlocks(nodes)
case Mempools:
return syncMempools(nodes)
}
return nil
}
// syncMempools blocks until all nodes have identical mempools.
func syncMempools(nodes []*Harness) (e error) {
poolsMatch := false
retry:
for !poolsMatch {
firstPool, e := nodes[0].Node.GetRawMempool()
if e != nil {
return e
}
// If all nodes have an identical mempool with respect to the first node,
// then we're done. Otherwise drop back to the top of the loop and retry
// after a short wait period.
for _, node := range nodes[1:] {
nodePool, e := node.Node.GetRawMempool()
if e != nil {
return e
}
if !reflect.DeepEqual(firstPool, nodePool) {
time.Sleep(time.Millisecond * 100)
continue retry
}
}
poolsMatch = true
}
return nil
}
// syncBlocks blocks until all nodes report the same best chain.
func syncBlocks(nodes []*Harness) (e error) {
blocksMatch := false
retry:
for !blocksMatch {
var prevHash *chainhash.Hash
var prevHeight int32
for _, node := range nodes {
blockHash, blockHeight, e := node.Node.GetBestBlock()
if e != nil {
return e
}
if prevHash != nil && (*blockHash != *prevHash ||
blockHeight != prevHeight) {
time.Sleep(time.Millisecond * 100)
continue retry
}
prevHash, prevHeight = blockHash, blockHeight
}
blocksMatch = true
}
return nil
}
// ConnectNode establishes a new peer-to-peer connection between the "from" harness and the "to" harness. The connection
// made is flagged as persistent therefore in the case of disconnects, "from" will attempt to reestablish a connection
// to the "to" harness.
func ConnectNode(from *Harness, to *Harness) (e error) {
peerInfo, e := from.Node.GetPeerInfo()
if e != nil {
return e
}
numPeers := len(peerInfo)
targetAddr := to.node.config.listen
if e = from.Node.AddNode(targetAddr, rpcclient.ANAdd); E.Chk(e) {
return e
}
// Block until a new connection has been established.
peerInfo, e = from.Node.GetPeerInfo()
if e != nil {
return e
}
for len(peerInfo) <= numPeers {
peerInfo, e = from.Node.GetPeerInfo()
if e != nil {
return e
}
}
return nil
}
// TearDownAll tears down all active test harnesses.
func TearDownAll() (e error) {
harnessStateMtx.Lock()
defer harnessStateMtx.Unlock()
for _, harness := range testInstances {
if e := harness.tearDown(); E.Chk(e) {
return e
}
}
return nil
}
// ActiveHarnesses returns a slice of all currently active test harnesses. A test harness if considered "active" if it
// has been created, but not yet torn down.
func ActiveHarnesses() []*Harness {
harnessStateMtx.RLock()
defer harnessStateMtx.RUnlock()
activeNodes := make([]*Harness, 0, len(testInstances))
for _, harness := range testInstances {
activeNodes = append(activeNodes, harness)
}
return activeNodes
}