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  }