go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/treenode_test.go (about) 1 package onet 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 "go.dedis.ch/onet/v3/log" 11 "go.dedis.ch/onet/v3/network" 12 ) 13 14 func init() { 15 GlobalProtocolRegister(spawnName, newSpawnProto) 16 GlobalProtocolRegister(pingPongProtoName, newPingPongProto) 17 } 18 19 func TestTreeNodeInstance_KeyPairs(t *testing.T) { 20 local := NewLocalTest(tSuite) 21 defer local.CloseAll() 22 23 _, _, tree := local.GenTree(5, true) 24 tni, err := local.NewTreeNodeInstance(tree.Root, spawnName) 25 26 require.NoError(t, err) 27 require.True(t, tni.Private().Equal(tni.Host().private)) 28 require.True(t, tni.Public().Equal(tni.Host().ServerIdentity.Public)) 29 require.True(t, tni.Public().Equal(tni.NodePublic(tni.Host().ServerIdentity))) 30 require.Equal(t, 5, len(tni.Publics())) 31 } 32 33 func TestTreeNodeCreateProtocol(t *testing.T) { 34 local := NewLocalTest(tSuite) 35 defer local.CloseAll() 36 37 hosts, _, tree := local.GenTree(1, true) 38 pi, err := hosts[0].overlay.CreateProtocol(spawnName, tree, NilServiceID) 39 log.ErrFatal(err) 40 p := pi.(*spawnProto) 41 p.spawn = true 42 go p.Start() 43 44 // wait once for the protocol just created 45 <-spawnCh 46 // wait once more for the protocol created inside the first one 47 <-spawnCh 48 49 pi.(*spawnProto).Done() 50 } 51 52 func TestTreeNodeRxTx(t *testing.T) { 53 local := NewTCPTest(tSuite) 54 testTreeNodeRxTx(t, local) 55 local.CloseAll() 56 57 local = NewLocalTest(tSuite) 58 testTreeNodeRxTx(t, local) 59 local.CloseAll() 60 } 61 62 func testTreeNodeRxTx(t *testing.T, local *LocalTest) { 63 _, _, tree := local.GenTree(2, true) 64 pi, err := local.StartProtocol(pingPongProtoName, tree) 65 require.Nil(t, err) 66 protocol := pi.(*pingPongProto) 67 68 <-protocol.done 69 require.NotZero(t, protocol.TreeNodeInstance.Rx()) 70 require.NotZero(t, protocol.TreeNodeInstance.Tx()) 71 } 72 73 func TestHandlerReturn(t *testing.T) { 74 local := NewLocalTest(tSuite) 75 defer local.CloseAll() 76 77 hosts, _, tree := local.GenTree(1, true) 78 pi, err := hosts[0].overlay.CreateProtocol(spawnName, tree, NilServiceID) 79 log.ErrFatal(err) 80 p := pi.(*spawnProto) 81 assert.NotNil(t, p.RegisterHandler(p.HandlerError1)) 82 assert.Nil(t, p.RegisterHandler(p.HandlerError2)) 83 assert.NotNil(t, p.RegisterHandler(p.HandlerError3)) 84 p.Done() 85 } 86 87 type dummyMsg struct{} 88 89 type configProcessor struct { 90 configCount int 91 expected int 92 done chan<- bool 93 sync.Mutex 94 } 95 96 func (p *configProcessor) Process(env *network.Envelope) { 97 p.Lock() 98 if env.MsgType == ConfigMsgID { 99 p.configCount++ 100 if p.configCount == p.expected { 101 p.done <- true 102 } 103 } 104 p.Unlock() 105 } 106 107 func TestConfigPropagation(t *testing.T) { 108 local := NewLocalTest(tSuite) 109 defer local.CloseAll() 110 const treeSize = 3 111 var serviceConfig = []byte{0x01, 0x02, 0x03, 0x04} 112 hosts, _, tree := local.GenTree(treeSize, true) 113 pi, err := hosts[0].overlay.CreateProtocol(spawnName, tree, NilServiceID) 114 log.ErrFatal(err) 115 116 done := make(chan bool) 117 pr := &configProcessor{expected: treeSize - 1, done: done} 118 119 for _, host := range hosts { 120 host.RegisterProcessor(pr, 121 ProtocolMsgID, 122 RequestTreeMsgID, 123 SendTreeMsgID, 124 ConfigMsgID) 125 } 126 127 network.RegisterMessage(dummyMsg{}) 128 rootInstance, _ := local.NewTreeNodeInstance(tree.Root, spawnName) 129 require.Zero(t, rootInstance.Tx()) 130 require.Zero(t, rootInstance.Rx()) 131 132 err = rootInstance.SetConfig(&GenericConfig{serviceConfig}) 133 assert.Nil(t, err) 134 err = rootInstance.SetConfig(&GenericConfig{serviceConfig}) 135 assert.NotNil(t, err) 136 137 err = rootInstance.SendToChildren(&dummyMsg{}) 138 assert.NotZero(t, rootInstance.Tx()) 139 log.ErrFatal(err) 140 // wait until the processor has processed the expected number of config messages 141 select { 142 case <-done: 143 case <-time.After(time.Second): 144 t.Fatal("Didn't receive response in time") 145 } 146 pi.(*spawnProto).Done() 147 } 148 149 func TestTreeNodeInstance_RegisterChannel(t *testing.T) { 150 local := NewLocalTest(tSuite) 151 defer local.CloseAll() 152 153 _, _, tree := local.GenTree(3, true) 154 ri, err := local.NewTreeNodeInstance(tree.Root, spawnName) 155 log.ErrFatal(err) 156 157 var c chan spawnMsg 158 log.ErrFatal(ri.RegisterChannel(&c)) 159 160 m := &ProtocolMsg{ 161 MsgType: network.RegisterMessage(&spawn{}), 162 From: &Token{ 163 TreeNodeID: ri.treeNode.ID, 164 }, 165 Msg: &spawn{I: 10}, 166 } 167 msg := []*ProtocolMsg{} 168 for i := 0; i < 101; i++ { 169 msg = append(msg, m) 170 } 171 require.NotNil(t, ri.dispatchChannel(msg)) 172 log.ErrFatal(ri.RegisterChannelLength(&c, 200)) 173 log.ErrFatal(ri.dispatchChannel(msg)) 174 } 175 176 // spawnCh is used to dispatch information from a spawnProto to the test 177 var spawnCh = make(chan bool) 178 179 const spawnName = "Spawn" 180 181 // spawnProto is a simple protocol which just spawn another protocol when 182 // started 183 type spawnProto struct { 184 *TreeNodeInstance 185 spawn bool 186 } 187 188 func newSpawnProto(tn *TreeNodeInstance) (ProtocolInstance, error) { 189 sp := &spawnProto{ 190 TreeNodeInstance: tn, 191 } 192 return sp, nil 193 } 194 195 func (s *spawnProto) Start() error { 196 defer s.Done() 197 r := s.Roster() 198 tree := r.GenerateBinaryTree() 199 spawnCh <- true 200 if !s.spawn { 201 return nil 202 } 203 proto, err := s.CreateProtocol(spawnName, tree) 204 log.ErrFatal(err) 205 go proto.Start() 206 return nil 207 } 208 209 type spawn struct { 210 I int64 211 } 212 213 type spawnMsg struct { 214 *TreeNode 215 M spawn 216 } 217 218 // Invalid handler 219 func (s *spawnProto) HandlerError1(msg spawnMsg) {} 220 221 // Valid handler 222 func (s *spawnProto) HandlerError2(msg spawnMsg) error { 223 s.Done() 224 return nil 225 } 226 227 // Invalid handler 228 func (s *spawnProto) HandlerError3(msg spawnMsg) (int, error) { 229 return 0, nil 230 } 231 232 // Simple protocol to have messages transmit between nodes 233 const pingPongProtoName = "PingPongProtoTest" 234 235 type PingPongMsg struct{} 236 237 type pingPongProto struct { 238 *TreeNodeInstance 239 done chan bool 240 pingPongChan chan struct { 241 *TreeNode 242 PingPongMsg 243 } 244 } 245 246 func newPingPongProto(tn *TreeNodeInstance) (ProtocolInstance, error) { 247 cp := &pingPongProto{ 248 TreeNodeInstance: tn, 249 done: make(chan bool, len(tn.List())), 250 } 251 err := cp.RegisterChannelsLength(len(tn.Tree().List()), &cp.pingPongChan) 252 return cp, err 253 } 254 255 func (cp *pingPongProto) Dispatch() error { 256 defer cp.Done() 257 258 select { 259 case <-cp.pingPongChan: 260 if !cp.IsRoot() { 261 cp.SendToParent(&PingPongMsg{}) 262 } 263 } 264 265 cp.done <- true 266 return nil 267 } 268 269 func (cp *pingPongProto) Start() error { 270 // only called by the root 271 err := cp.SendToChildren(&PingPongMsg{}) 272 if err != nil { 273 return err 274 } 275 276 return nil 277 }