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