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  }