go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/overlay_test.go (about) 1 package onet 2 3 import ( 4 "errors" 5 "net/http" 6 "testing" 7 "time" 8 9 "github.com/google/uuid" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 "go.dedis.ch/onet/v3/log" 13 "go.dedis.ch/onet/v3/network" 14 ) 15 16 // A checkableError is a type that implements error and also lets 17 // you find out, by reading on a channel, how many times it has been 18 // formatted using Error(). 19 type checkableError struct { 20 ch chan struct{} 21 msg string 22 } 23 24 func (ce *checkableError) Error() string { 25 ce.ch <- struct{}{} 26 return ce.msg 27 } 28 29 var dispFailErr = &checkableError{ 30 ch: make(chan struct{}, 10), 31 msg: "Dispatch failed", 32 } 33 34 type ProtocolOverlay struct { 35 *TreeNodeInstance 36 done bool 37 failDispatch bool 38 failChan chan bool 39 } 40 41 func (po *ProtocolOverlay) Start() error { 42 // no need to do anything 43 return nil 44 } 45 46 func (po *ProtocolOverlay) Dispatch() error { 47 if po.failDispatch { 48 return dispFailErr 49 } 50 return nil 51 } 52 53 func (po *ProtocolOverlay) Release() { 54 // call the Done function 55 po.Done() 56 } 57 58 func TestOverlayDispatchFailure(t *testing.T) { 59 // setup 60 failChan := make(chan bool, 1) 61 fn := func(n *TreeNodeInstance) (ProtocolInstance, error) { 62 ps := ProtocolOverlay{ 63 TreeNodeInstance: n, 64 failDispatch: true, 65 failChan: failChan, 66 } 67 return &ps, nil 68 } 69 GlobalProtocolRegister("ProtocolOverlay", fn) 70 local := NewLocalTest(tSuite) 71 defer local.CloseAll() 72 73 // Redirect output so we can check for the failure 74 log.OutputToBuf() 75 defer log.OutputToOs() 76 77 h, _, tree := local.GenTree(1, true) 78 h1 := h[0] 79 pi, err := h1.CreateProtocol("ProtocolOverlay", tree) 80 if err != nil { 81 t.Fatal("error starting new node", err) 82 } 83 84 // wait for the error message to get formatted by overlay.go 85 <-dispFailErr.ch 86 87 // This test was apparently always a bit fragile, and commit 5931349 88 // seems to have made it worse. Adding this tiny sleep makes 89 // 2000 iterations pass where before I could see errors about 1 in 20 times. 90 time.Sleep(5 * time.Millisecond) 91 92 // when using `go test -v`, the error string goes into the stderr buffer 93 // but with `go test`, it goes into the stdout buffer, so we check both 94 assert.Contains(t, log.GetStdOut()+log.GetStdErr(), "Dispatch failed") 95 pi.(*ProtocolOverlay).Done() 96 } 97 98 func TestOverlayDone(t *testing.T) { 99 log.OutputToBuf() 100 defer log.OutputToOs() 101 102 // setup 103 fn := func(n *TreeNodeInstance) (ProtocolInstance, error) { 104 ps := ProtocolOverlay{ 105 TreeNodeInstance: n, 106 } 107 return &ps, nil 108 } 109 GlobalProtocolRegister("ProtocolOverlay", fn) 110 local := NewLocalTest(tSuite) 111 defer local.CloseAll() 112 h, _, tree := local.GenTree(1, true) 113 h1 := h[0] 114 p, err := h1.CreateProtocol("ProtocolOverlay", tree) 115 if err != nil { 116 t.Fatal("error starting new node", err) 117 } 118 po := p.(*ProtocolOverlay) 119 // release the resources 120 var count int 121 po.OnDoneCallback(func() bool { 122 count++ 123 if count >= 2 { 124 return true 125 } 126 return false 127 }) 128 po.Release() 129 overlay := h1.overlay 130 if _, ok := overlay.TokenToNode(po.Token()); !ok { 131 t.Fatal("Node should exists after first call Done()") 132 } 133 po.Release() 134 if _, ok := overlay.TokenToNode(po.Token()); ok { 135 t.Fatal("Node should NOT exists after call Done()") 136 } 137 } 138 139 type protocolCatastrophic struct { 140 *TreeNodeInstance 141 142 ChannelMsg chan WrapDummyMsg 143 144 done chan bool 145 } 146 147 func (po *protocolCatastrophic) Start() error { 148 panic("start panic") 149 } 150 151 func (po *protocolCatastrophic) Dispatch() error { 152 if !po.IsRoot() { 153 <-po.ChannelMsg 154 155 po.SendToParent(&DummyMsg{}) 156 157 po.Done() 158 panic("dispatch panic") 159 } 160 161 err := po.SendToChildren(&DummyMsg{}) 162 if err != nil { 163 return err 164 } 165 166 <-po.ChannelMsg 167 <-po.ChannelMsg 168 po.done <- true 169 170 po.Done() 171 panic("root dispatch panic") 172 } 173 174 // TestOverlayCatastrophicFailure checks if a panic during a protocol could 175 // cause the server to crash 176 func TestOverlayCatastrophicFailure(t *testing.T) { 177 log.OutputToBuf() 178 defer log.OutputToOs() 179 180 fn := func(n *TreeNodeInstance) (ProtocolInstance, error) { 181 ps := protocolCatastrophic{ 182 TreeNodeInstance: n, 183 done: make(chan bool), 184 } 185 186 err := ps.RegisterChannel(&ps.ChannelMsg) 187 188 return &ps, err 189 } 190 GlobalProtocolRegister("ProtocolCatastrophic", fn) 191 local := NewLocalTest(tSuite) 192 defer local.CloseAll() 193 194 h, _, tree := local.GenTree(3, true) 195 h1 := h[0] 196 pi, err := h1.StartProtocol("ProtocolCatastrophic", tree) 197 assert.NoError(t, err) 198 199 <-pi.(*protocolCatastrophic).done 200 201 // can't have a synchronisation and a panic so we wait for the panic to be handled 202 time.Sleep(1 * time.Second) 203 204 stderr := log.GetStdErr() 205 assert.Contains(t, stderr, "Start(): start panic") 206 assert.Contains(t, stderr, "Panic in call to protocol") 207 assert.Contains(t, stderr, "Dispatch(): root dispatch panic") 208 } 209 210 // Test when a peer receives a New Roster, it can create the trees that are 211 // waiting on this specific entitiy list, to be constructed. 212 func TestOverlayPendingTreeMarshal(t *testing.T) { 213 local := NewLocalTest(tSuite) 214 hosts, el, tree := local.GenTree(2, false) 215 defer local.CloseAll() 216 h1 := hosts[0] 217 218 // Add the marshalled version of the tree 219 local.addPendingTreeMarshal(h1, tree.MakeTreeMarshal()) 220 if _, ok := h1.GetTree(tree.ID); ok { 221 t.Fatal("host 1 should not have the tree definition yet.") 222 } 223 // Now make it check 224 local.checkPendingTreeMarshal(h1, el) 225 if _, ok := h1.GetTree(tree.ID); !ok { 226 t.Fatal("Host 1 should have the tree definition now.") 227 } 228 } 229 230 // overlayProc is a Processor which handles the management packet of Overlay, 231 // i.e. Roster & Tree management. 232 // Each type of message will be sent trhough the appropriate channel 233 type overlayProc struct { 234 sendRoster chan *Roster 235 responseTree chan *ResponseTree 236 treeMarshal chan *TreeMarshal 237 requestTree chan *RequestTree 238 } 239 240 func newOverlayProc() *overlayProc { 241 return &overlayProc{ 242 sendRoster: make(chan *Roster, 1), 243 responseTree: make(chan *ResponseTree, 1), 244 treeMarshal: make(chan *TreeMarshal, 1), 245 requestTree: make(chan *RequestTree, 1), 246 } 247 } 248 249 func (op *overlayProc) Process(env *network.Envelope) { 250 switch env.MsgType { 251 case SendRosterMsgID: 252 op.sendRoster <- env.Msg.(*Roster) 253 case ResponseTreeMsgID: 254 op.responseTree <- env.Msg.(*ResponseTree) 255 case SendTreeMsgID: 256 op.treeMarshal <- env.Msg.(*TreeMarshal) 257 case RequestTreeMsgID: 258 op.requestTree <- env.Msg.(*RequestTree) 259 } 260 } 261 262 func (op *overlayProc) Types() []network.MessageTypeID { 263 return []network.MessageTypeID{TreeMarshalTypeID, SendRosterMsgID} 264 } 265 266 // Test propagation of roster - both known and unknown 267 // Deprecated: check the deprecation is still working 268 func TestOverlayRosterPropagation(t *testing.T) { 269 local := NewLocalTest(tSuite) 270 hosts, el, tree := local.GenTree(2, false) 271 defer local.CloseAll() 272 h1 := hosts[0] 273 h2 := hosts[1] 274 proc := newOverlayProc() 275 h1.RegisterProcessor(proc, proc.Types()...) 276 277 // Check that h2 sends back an empty list if it is unknown 278 sentLen, err := h1.Send(h2.ServerIdentity, &RequestRoster{RosterID: el.ID}) 279 require.Nil(t, err, "Couldn't send message to h1") 280 require.NotZero(t, sentLen) 281 282 roster := <-proc.sendRoster 283 if !roster.ID.IsNil() { 284 t.Fatal("List should be empty") 285 } 286 287 // Now add the tree to h2 and try again 288 h2.AddTree(tree) 289 sentLen, err = h1.Send(h2.ServerIdentity, &RequestRoster{RosterID: el.ID}) 290 require.Nil(t, err, "Couldn't send message to h2") 291 require.NotZero(t, sentLen) 292 293 msg := <-proc.sendRoster 294 if !msg.ID.Equal(el.ID) { 295 t.Fatal("List should be equal to original list") 296 } 297 298 sentLen, err = h1.Send(h2.ServerIdentity, &RequestRoster{RosterID: el.ID}) 299 require.Nil(t, err, "Couldn't send message to h2") 300 require.NotZero(t, sentLen) 301 } 302 303 // Test propagation of tree - both known and unknown 304 func TestOverlayTreePropagation(t *testing.T) { 305 local := NewLocalTest(tSuite) 306 hosts, _, tree := local.GenTree(2, false) 307 defer local.CloseAll() 308 h1 := hosts[0] 309 h2 := hosts[1] 310 311 proc := newOverlayProc() 312 h1.RegisterProcessor(proc, ResponseTreeMsgID) 313 // h1 needs to expect the tree 314 h1.Overlay().treeStorage.Register(tree.ID) 315 316 // Check that h2 does nothing and doesn't crash 317 sentLen, err := h1.Send(h2.ServerIdentity, &RequestTree{TreeID: tree.ID, Version: 1}) 318 require.Nil(t, err, "Couldn't send message to h2") 319 require.NotZero(t, sentLen) 320 321 // Now add the list to h2 and try again 322 h2.AddTree(tree) 323 sentLen, err = h1.Send(h2.ServerIdentity, &RequestTree{TreeID: tree.ID, Version: 1}) 324 require.Nil(t, err) 325 require.NotZero(t, sentLen) 326 327 msg := <-proc.responseTree 328 assert.Equal(t, msg.TreeMarshal.TreeID, tree.ID) 329 330 sentLen, err = h1.Send(h2.ServerIdentity, &RequestTree{TreeID: tree.ID, Version: 1}) 331 require.Nil(t, err) 332 require.NotZero(t, sentLen) 333 334 // check if we receive the tree then 335 var tm *ResponseTree 336 tm = <-proc.responseTree 337 packet := network.Envelope{ 338 ServerIdentity: h2.ServerIdentity, 339 Msg: tm, 340 MsgType: SendTreeMsgID, 341 } 342 h1.overlay.Process(&packet) 343 344 tree2, ok := h1.GetTree(tree.ID) 345 if !ok { 346 t.Fatal("List-id not found") 347 } 348 if !tree.Equal(tree2) { 349 t.Fatal("Trees do not match") 350 } 351 } 352 353 // Tests if a tree can be requested even after a failure 354 func TestOverlayTreeFailure(t *testing.T) { 355 local := NewLocalTest(tSuite) 356 hosts, _, tree := local.GenTree(3, false) 357 defer local.CloseAll() 358 359 h1 := hosts[0] 360 h1.overlay.treeStorage.Register(tree.ID) 361 h2 := hosts[1] 362 h2.AddTree(tree) 363 h3 := hosts[2] 364 h3.Close() 365 366 proc := newOverlayProc() 367 h1.RegisterProcessor(proc, ResponseTreeMsgID) 368 369 _, err := h1.Send(h3.ServerIdentity, &RequestTree{TreeID: tree.ID, Version: 1}) 370 require.NotNil(t, err) 371 372 _, err = h1.Send(h2.ServerIdentity, &RequestTree{TreeID: tree.ID, Version: 1}) 373 require.Nil(t, err) 374 375 // check if we have the tree 376 treeM := <-proc.responseTree 377 require.NotNil(t, treeM) 378 } 379 380 // Tests a tree propagation with an unknown and known roster 381 // Deprecated: check the deprecation is still working 382 func TestOverlayRosterTreePropagation(t *testing.T) { 383 local := NewLocalTest(tSuite) 384 hosts, ro, tree := local.GenTree(2, false) 385 defer local.CloseAll() 386 h1 := hosts[0] 387 h1.Overlay().treeStorage.Register(tree.ID) 388 h2 := hosts[1] 389 390 // and the tree 391 h2.AddTree(tree) 392 // make the communcation happen 393 sentLen, err := h1.Send(h2.ServerIdentity, &RequestTree{TreeID: tree.ID}) 394 require.Nil(t, err, "Could not send tree request to host2") 395 require.NotZero(t, sentLen) 396 397 proc := newOverlayProc() 398 h1.RegisterProcessor(proc, SendTreeMsgID, SendRosterMsgID) 399 400 // check if we have the tree 401 treeM := <-proc.treeMarshal 402 403 packet := network.Envelope{ 404 ServerIdentity: h2.ServerIdentity, 405 Msg: treeM, 406 MsgType: SendTreeMsgID, 407 } 408 // give it to overlay 409 h1.overlay.Process(&packet) 410 // the tree should not be there because we don't have the Roster associated 411 // yet 412 if _, ok := h1.GetTree(tree.ID); ok { 413 t.Fatal("Tree should Not be there") 414 } 415 // check if we receive the Roster then 416 roster := <-proc.sendRoster 417 418 packet = network.Envelope{ 419 ServerIdentity: h2.ServerIdentity, 420 Msg: roster, 421 MsgType: SendRosterMsgID, 422 } 423 h1.overlay.Process(&packet) 424 425 // check if we have the roster now & the tree 426 if _, ok := h1.Roster(ro.ID); !ok { 427 t.Fatal("Roster should be here") 428 } 429 if _, ok := h1.GetTree(tree.ID); !ok { 430 t.Fatal("Tree should be there") 431 } 432 433 // check it can get the tree without requesting the roster again 434 tree2 := ro.GenerateNaryTreeWithRoot(2, ro.List[1]) 435 require.False(t, tree2.ID.Equal(tree.ID)) 436 437 packet = network.Envelope{ 438 ServerIdentity: h2.ServerIdentity, 439 Msg: tree2.MakeTreeMarshal(), 440 MsgType: SendTreeMsgID, 441 } 442 443 h1.overlay.instances[TokenID{}] = &TreeNodeInstance{overlay: h1.overlay, token: &Token{TreeID: tree.ID}} 444 h1.overlay.treeStorage.Register(tree2.ID) 445 h1.overlay.Process(&packet) 446 if _, ok := h1.GetTree(tree2.ID); !ok { 447 t.Fatal("Tree should be there") 448 } 449 } 450 451 // Tests that the tree is not registered when bad parameters are provided 452 func TestOverlayHandlersBadParameters(t *testing.T) { 453 local := NewLocalTest(tSuite) 454 hosts, ro, tree := local.GenTree(1, false) 455 defer local.CloseAll() 456 h := hosts[0] 457 458 h.overlay.handleSendTree(h.ServerIdentity, &ResponseTree{}, nil) 459 h.overlay.handleSendTree(h.ServerIdentity, &ResponseTree{TreeMarshal: tree.MakeTreeMarshal()}, nil) 460 h.overlay.handleSendTree(h.ServerIdentity, &ResponseTree{TreeMarshal: tree.MakeTreeMarshal(), Roster: ro}, nil) 461 462 h.overlay.handleSendTreeMarshal(h.ServerIdentity, &TreeMarshal{}, nil) 463 h.overlay.handleSendTreeMarshal(h.ServerIdentity, tree.MakeTreeMarshal(), nil) 464 require.Equal(t, 0, len(h.overlay.treeStorage.trees)) 465 466 h.overlay.handleSendRoster(h.ServerIdentity, &Roster{}) 467 } 468 469 func TestTokenId(t *testing.T) { 470 t1 := &Token{ 471 RosterID: RosterID(uuid.Must(uuid.NewUUID())), 472 TreeID: TreeID(uuid.Must(uuid.NewUUID())), 473 ProtoID: ProtocolID(uuid.Must(uuid.NewUUID())), 474 RoundID: RoundID(uuid.Must(uuid.NewUUID())), 475 } 476 id1 := t1.ID() 477 t2 := &Token{ 478 RosterID: RosterID(uuid.Must(uuid.NewUUID())), 479 TreeID: TreeID(uuid.Must(uuid.NewUUID())), 480 ProtoID: ProtocolID(uuid.Must(uuid.NewUUID())), 481 RoundID: RoundID(uuid.Must(uuid.NewUUID())), 482 } 483 id2 := t2.ID() 484 if id1.Equal(id2) { 485 t.Fatal("Both token are the same") 486 } 487 if !id1.Equal(t1.ID()) { 488 t.Fatal("Twice the Id of the same token should be equal") 489 } 490 t3 := t1.ChangeTreeNodeID(TreeNodeID(uuid.Must(uuid.NewUUID()))) 491 if t1.TreeNodeID.Equal(t3.TreeNodeID) { 492 t.Fatal("OtherToken should modify copy") 493 } 494 } 495 496 type testNilService struct{} 497 498 func (s testNilService) NewProtocol(tni *TreeNodeInstance, cfg *GenericConfig) (ProtocolInstance, error) { 499 if cfg == nil { 500 return nil, errors.New("config should not be nil") 501 } 502 503 c := make(chan bool, 1) 504 return &DummyProtocol{TreeNodeInstance: tni, link: c}, nil 505 } 506 507 func (s testNilService) Process(*network.Envelope) {} 508 509 func (s testNilService) ProcessClientRequest(req *http.Request, handler string, msg []byte) (reply []byte, tunnel *StreamingTunnel, err error) { 510 return nil, nil, nil 511 } 512 513 func TestOverlay_ConfigInMessage(t *testing.T) { 514 local := NewLocalTest(tSuite) 515 hosts, ro, _ := local.GenTree(1, false) 516 defer local.CloseAll() 517 h := hosts[0] 518 519 tree := NewTree(ro, NewTreeNode(0, ro.List[0])) 520 h.overlay.treeStorage.Set(tree) 521 522 h.serviceManager.services[NilServiceID] = testNilService{} 523 524 cfg := &GenericConfig{Data: []byte("deadbeef")} 525 526 io := &defaultProtoIO{suite: tSuite} 527 om := &OverlayMsg{ 528 Config: cfg, 529 TreeNodeInfo: &TreeNodeInfo{ 530 To: &Token{ 531 TreeNodeID: tree.Root.ID, 532 TreeID: tree.ID, 533 }, 534 }, 535 } 536 537 env, err := io.Wrap(ro, om) 538 require.NoError(t, err) 539 require.NotNil(t, env.(*ProtocolMsg).Config) 540 541 env.(*ProtocolMsg).ServerIdentity = &network.ServerIdentity{} 542 543 err = h.overlay.TransmitMsg(env.(*ProtocolMsg), io) 544 require.NoError(t, err) 545 }