go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/protocol_test.go (about)

     1  package onet
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/uuid"
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  	"go.dedis.ch/onet/v3/log"
    10  	"go.dedis.ch/onet/v3/network"
    11  	"golang.org/x/xerrors"
    12  )
    13  
    14  var testProto = "test"
    15  
    16  func init() {
    17  	network.RegisterMessage(SimpleMessage{})
    18  }
    19  
    20  // ProtocolTest is the most simple protocol to be implemented, ignoring
    21  // everything it receives.
    22  type ProtocolTest struct {
    23  	*TreeNodeInstance
    24  	StartMsg chan string
    25  	DispMsg  chan string
    26  }
    27  
    28  // NewProtocolTest is used to create a new protocolTest-instance
    29  func NewProtocolTest(n *TreeNodeInstance) (ProtocolInstance, error) {
    30  	return &ProtocolTest{
    31  		TreeNodeInstance: n,
    32  		StartMsg:         make(chan string, 1),
    33  		DispMsg:          make(chan string),
    34  	}, nil
    35  }
    36  
    37  // Dispatch is used to send the messages further - here everything is
    38  // copied to /dev/null
    39  func (p *ProtocolTest) Dispatch() error {
    40  	log.Lvl2("ProtocolTest.Dispatch()")
    41  	p.DispMsg <- "Dispatch"
    42  	p.Done()
    43  	return nil
    44  }
    45  
    46  func (p *ProtocolTest) Start() error {
    47  	log.Lvl2("ProtocolTest.Start()")
    48  	p.StartMsg <- "Start"
    49  	p.Done()
    50  	return nil
    51  }
    52  
    53  type SimpleProtocol struct {
    54  	// chan to get back to testing
    55  	Chan  chan bool
    56  	Error error
    57  	*TreeNodeInstance
    58  }
    59  
    60  // Sends a simple message to its first children
    61  func (p *SimpleProtocol) Start() error {
    62  	err := p.SendTo(p.Children()[0], &SimpleMessage{10})
    63  	if err != nil {
    64  		return err
    65  	}
    66  	p.Chan <- true
    67  	return nil
    68  }
    69  
    70  // Dispatch analyses the message and does nothing else
    71  func (p *SimpleProtocol) ReceiveMessage(msg MsgSimpleMessage) error {
    72  	if msg.I != 10 {
    73  		return xerrors.New("Not the value expected")
    74  	}
    75  	p.Chan <- true
    76  	p.Done()
    77  	return nil
    78  }
    79  
    80  // ReturnError sends a message to the parent, and if it's the parent
    81  // receiving the message, it triggers the channel
    82  func (p *SimpleProtocol) ReturnError(msg MsgSimpleMessage) error {
    83  	if msg.I == 10 {
    84  		p.SendToParent(&SimpleMessage{9})
    85  	} else {
    86  		p.Chan <- true
    87  	}
    88  	p.Done()
    89  	return p.Error
    90  }
    91  
    92  type SimpleMessage struct {
    93  	I int64
    94  }
    95  
    96  type MsgSimpleMessage struct {
    97  	*TreeNode
    98  	SimpleMessage
    99  }
   100  
   101  // Test simple protocol-implementation
   102  // - registration
   103  func TestProtocolRegistration(t *testing.T) {
   104  	testProtoName := "testProto"
   105  	testProtoID, err := GlobalProtocolRegister(testProtoName, NewProtocolTest)
   106  	log.ErrFatal(err)
   107  	_, err = GlobalProtocolRegister(testProtoName, NewProtocolTest)
   108  	require.NotNil(t, err)
   109  	if !protocols.ProtocolExists(testProtoID) {
   110  		t.Fatal("Test should exist now")
   111  	}
   112  	if !ProtocolNameToID(testProtoName).Equal(testProtoID) {
   113  		t.Fatal("Not correct translation from string to ID")
   114  	}
   115  	require.Equal(t, "", protocols.ProtocolIDToName(ProtocolID(uuid.Nil)))
   116  	if protocols.ProtocolIDToName(testProtoID) != testProtoName {
   117  		t.Fatal("Not correct translation from ID to String")
   118  	}
   119  }
   120  
   121  // This makes h2 the leader, so it creates a tree and entity list
   122  // and start a protocol. H1 should receive that message and request the entity
   123  // list and the treelist and then instantiate the protocol.
   124  func TestProtocolAutomaticInstantiation(t *testing.T) {
   125  	var simpleProto = "simpleAI"
   126  
   127  	// setup
   128  	chanH1 := make(chan bool)
   129  	chanH2 := make(chan bool)
   130  	chans := []chan bool{chanH1, chanH2}
   131  	id := 0
   132  	// custom creation function so we know the step due to the channels
   133  	fn := func(n *TreeNodeInstance) (ProtocolInstance, error) {
   134  		ps := SimpleProtocol{
   135  			TreeNodeInstance: n,
   136  			Chan:             chans[id],
   137  		}
   138  		log.ErrFatal(ps.RegisterHandler(ps.ReceiveMessage))
   139  		id++
   140  		return &ps, nil
   141  	}
   142  
   143  	_, err := GlobalProtocolRegister(simpleProto, fn)
   144  	require.Nil(t, err)
   145  	local := NewLocalTest(tSuite)
   146  	defer local.CloseAll()
   147  	h, _, tree := local.GenTree(2, true)
   148  	h1 := h[0]
   149  	var pi ProtocolInstance
   150  	started := make(chan bool)
   151  	// start the protocol
   152  	go func() {
   153  		var err error
   154  		pi, err = h1.StartProtocol(simpleProto, tree)
   155  		require.NoError(t, err, "Could not start protocol")
   156  		started <- true
   157  	}()
   158  
   159  	// we are supposed to receive something from host1 from Start()
   160  	<-chanH1
   161  
   162  	// Then we are supposed to receive from h2 after he got the tree and the
   163  	// entity list from h1
   164  	<-chanH2
   165  	<-started
   166  	pi.(*SimpleProtocol).Done()
   167  }
   168  
   169  func TestProtocolError(t *testing.T) {
   170  	var simpleProto = "simplePE"
   171  	done := make(chan bool)
   172  	// The simplePE-protocol sends a message from the root to its
   173  	// children, which sends a message back and returns an error.
   174  	// When the root receives the message back, the second message
   175  	// is sent through the 'done'-channel. Like this we're sure that
   176  	// the children-message-handler had the time to return an error.
   177  	var protocolError error
   178  	fn := func(n *TreeNodeInstance) (ProtocolInstance, error) {
   179  		ps := SimpleProtocol{
   180  			TreeNodeInstance: n,
   181  			Chan:             done,
   182  		}
   183  		ps.Error = protocolError
   184  		log.ErrFatal(ps.RegisterHandler(ps.ReturnError))
   185  		return &ps, nil
   186  	}
   187  
   188  	_, err := GlobalProtocolRegister(simpleProto, fn)
   189  	require.Nil(t, err)
   190  	local := NewLocalTest(tSuite)
   191  	h, _, tree := local.GenTree(2, true)
   192  	h1 := h[0]
   193  
   194  	oldlvl := log.DebugVisible()
   195  	// The error won't show if the DebugVisible is < 1
   196  	if oldlvl < 1 {
   197  		log.SetDebugVisible(1)
   198  	}
   199  	// Redirecting stderr, so we can catch the error
   200  	log.OutputToBuf()
   201  	defer func() {
   202  		log.OutputToOs()
   203  		log.SetDebugVisible(oldlvl)
   204  	}()
   205  	// Empty it of previous messages before running our test.
   206  	_ = log.GetStdErr()
   207  
   208  	// start the protocol
   209  	go func() {
   210  		_, err := h1.StartProtocol(simpleProto, tree)
   211  		assert.NoError(t, err, "Could not start protocol")
   212  	}()
   213  	// Start is finished
   214  	<-done
   215  	// Return message is received
   216  	<-done
   217  	assert.Equal(t, "", log.GetStdErr(), "This should yield no error")
   218  
   219  	protocolError = xerrors.New("Protocol Error")
   220  	// start the protocol
   221  	go func() {
   222  		_, err := h1.StartProtocol(simpleProto, tree)
   223  		require.NoError(t, err, "Could not start protocol")
   224  	}()
   225  	// Start is finished
   226  	<-done
   227  	// Return message is received
   228  	<-done
   229  	local.CloseAll()
   230  
   231  	str := log.GetStdErr()
   232  	assert.NotEqual(t, "", str, "No error output")
   233  
   234  }
   235  
   236  func TestGlobalProtocolRegisterTooLate(t *testing.T) {
   237  	var simpleProto = "simplePE"
   238  	done := make(chan bool)
   239  	fn := func(n *TreeNodeInstance) (ProtocolInstance, error) {
   240  		ps := SimpleProtocol{
   241  			TreeNodeInstance: n,
   242  			Chan:             done,
   243  		}
   244  		log.ErrFatal(ps.RegisterHandler(ps.ReturnError))
   245  		return &ps, nil
   246  	}
   247  
   248  	local := NewLocalTest(tSuite)
   249  	defer local.CloseAll()
   250  	local.GenTree(2, true)
   251  	fnShouldPanic := func() {
   252  		GlobalProtocolRegister(simpleProto, fn)
   253  	}
   254  	assert.Panics(t, fnShouldPanic)
   255  }
   256  
   257  func TestMessageProxyFactory(t *testing.T) {
   258  	defer eraseAllMessageProxy()
   259  	RegisterMessageProxy(NewTestMessageProxyChan)
   260  	assert.True(t, len(messageProxyFactory.factories) == 1)
   261  }
   262  
   263  func TestMessageProxyStore(t *testing.T) {
   264  	defer eraseAllMessageProxy()
   265  	local := NewLocalTest(tSuite)
   266  	defer local.CloseAll()
   267  
   268  	RegisterMessageProxy(NewTestMessageProxy)
   269  	_, err := GlobalProtocolRegister(testProtoIOName, newTestProtocolInstance)
   270  	require.Nil(t, err)
   271  	h, _, tree := local.GenTree(2, true)
   272  
   273  	go func() {
   274  		// first time to wrap
   275  		res := <-chanProtoIOFeedback
   276  		require.Equal(t, "", res)
   277  		// second time to unwrap
   278  		res = <-chanProtoIOFeedback
   279  		require.Equal(t, "", res)
   280  
   281  	}()
   282  	pi, err := h[0].StartProtocol(testProtoIOName, tree)
   283  	require.Nil(t, err)
   284  
   285  	res := <-chanTestProtoInstance
   286  	assert.True(t, res)
   287  	pi.(*TestProtocolInstance).Done()
   288  }
   289  
   290  // MessageProxy part
   291  var chanProtoIOCreation = make(chan bool)
   292  var chanProtoIOFeedback = make(chan string)
   293  
   294  const testProtoIOName = "TestIO"
   295  
   296  type OuterPacket struct {
   297  	Info  *OverlayMsg
   298  	Inner *SimpleMessage
   299  }
   300  
   301  var OuterPacketType = network.RegisterMessage(OuterPacket{})
   302  
   303  type TestMessageProxy struct{}
   304  
   305  func NewTestMessageProxyChan() MessageProxy {
   306  	chanProtoIOCreation <- true
   307  	return &TestMessageProxy{}
   308  }
   309  
   310  func NewTestMessageProxy() MessageProxy {
   311  	return &TestMessageProxy{}
   312  }
   313  
   314  func eraseAllMessageProxy() {
   315  	messageProxyFactory.factories = nil
   316  }
   317  
   318  func (t *TestMessageProxy) Wrap(msg interface{}, info *OverlayMsg) (interface{}, error) {
   319  	outer := &OuterPacket{}
   320  	inner, ok := msg.(*SimpleMessage)
   321  	if !ok {
   322  		chanProtoIOFeedback <- "wrong message type in wrap"
   323  	}
   324  	outer.Inner = inner
   325  	outer.Info = info
   326  	chanProtoIOFeedback <- ""
   327  	return outer, nil
   328  }
   329  
   330  func (t *TestMessageProxy) Unwrap(msg interface{}) (interface{}, *OverlayMsg, error) {
   331  	if msg == nil {
   332  		chanProtoIOFeedback <- "message nil!"
   333  		return nil, nil, xerrors.New("message nil")
   334  	}
   335  
   336  	real, ok := msg.(*OuterPacket)
   337  	if !ok {
   338  		chanProtoIOFeedback <- "wrong type of message in unwrap"
   339  		return nil, nil, xerrors.New("wrong message")
   340  	}
   341  	chanProtoIOFeedback <- ""
   342  	return real.Inner, real.Info, nil
   343  }
   344  
   345  func (t *TestMessageProxy) PacketType() network.MessageTypeID {
   346  	return OuterPacketType
   347  }
   348  
   349  func (t *TestMessageProxy) Name() string {
   350  	return testProtoIOName
   351  }
   352  
   353  var chanTestProtoInstance = make(chan bool)
   354  
   355  // ProtocolInstance part
   356  type TestProtocolInstance struct {
   357  	*TreeNodeInstance
   358  }
   359  
   360  func newTestProtocolInstance(n *TreeNodeInstance) (ProtocolInstance, error) {
   361  	pi := &TestProtocolInstance{n}
   362  	n.RegisterHandler(pi.handleSimpleMessage)
   363  	return pi, nil
   364  }
   365  
   366  func (t *TestProtocolInstance) Start() error {
   367  	t.SendTo(t.Root(), &SimpleMessage{12})
   368  	return nil
   369  }
   370  
   371  type SimpleMessageHandler struct {
   372  	*TreeNode
   373  	SimpleMessage
   374  }
   375  
   376  func (t TestProtocolInstance) handleSimpleMessage(h SimpleMessageHandler) error {
   377  	chanTestProtoInstance <- h.SimpleMessage.I == 12
   378  	return nil
   379  }