github.com/yggdrasil-network/yggdrasil-go@v0.5.6/src/core/core_test.go (about)

     1  package core
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"net/url"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/gologme/log"
    12  	"github.com/yggdrasil-network/yggdrasil-go/src/config"
    13  )
    14  
    15  // GetLoggerWithPrefix creates a new logger instance with prefix.
    16  // If verbose is set to true, three log levels are enabled: "info", "warn", "error".
    17  func GetLoggerWithPrefix(prefix string, verbose bool) *log.Logger {
    18  	l := log.New(os.Stderr, prefix, log.Flags())
    19  	if !verbose {
    20  		return l
    21  	}
    22  	l.EnableLevel("info")
    23  	l.EnableLevel("warn")
    24  	l.EnableLevel("error")
    25  	return l
    26  }
    27  
    28  // CreateAndConnectTwo creates two nodes. nodeB connects to nodeA.
    29  // Verbosity flag is passed to logger.
    30  func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) {
    31  	var err error
    32  
    33  	cfgA, cfgB := config.GenerateConfig(), config.GenerateConfig()
    34  	if err = cfgA.GenerateSelfSignedCertificate(); err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	if err = cfgB.GenerateSelfSignedCertificate(); err != nil {
    38  		t.Fatal(err)
    39  	}
    40  
    41  	logger := GetLoggerWithPrefix("", false)
    42  	logger.EnableLevel("debug")
    43  
    44  	if nodeA, err = New(cfgA.Certificate, logger); err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	if nodeB, err = New(cfgB.Certificate, logger); err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	nodeAListenURL, err := url.Parse("tcp://localhost:0")
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	nodeAListener, err := nodeA.Listen(nodeAListenURL, "")
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	nodeAURL, err := url.Parse("tcp://" + nodeAListener.Addr().String())
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	if err = nodeB.CallPeer(nodeAURL, ""); err != nil {
    64  		t.Fatal(err)
    65  	}
    66  
    67  	time.Sleep(100 * time.Millisecond)
    68  
    69  	if l := len(nodeA.GetPeers()); l != 1 {
    70  		t.Fatal("unexpected number of peers", l)
    71  	}
    72  	if l := len(nodeB.GetPeers()); l != 1 {
    73  		t.Fatal("unexpected number of peers", l)
    74  	}
    75  
    76  	return nodeA, nodeB
    77  }
    78  
    79  // WaitConnected blocks until either nodes negotiated DHT or 5 seconds passed.
    80  func WaitConnected(nodeA, nodeB *Core) bool {
    81  	// It may take up to 3 seconds, but let's wait 5.
    82  	for i := 0; i < 50; i++ {
    83  		time.Sleep(100 * time.Millisecond)
    84  		/*
    85  			if len(nodeA.GetPeers()) > 0 && len(nodeB.GetPeers()) > 0 {
    86  				return true
    87  			}
    88  		*/
    89  		if len(nodeA.GetTree()) > 1 && len(nodeB.GetTree()) > 1 {
    90  			time.Sleep(3 * time.Second) // FIXME hack, there's still stuff happening internally
    91  			return true
    92  		}
    93  	}
    94  	return false
    95  }
    96  
    97  // CreateEchoListener creates a routine listening on nodeA. It expects repeats messages of length bufLen.
    98  // It returns a channel used to synchronize the routine with caller.
    99  func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan struct{} {
   100  	// Start routine
   101  	done := make(chan struct{})
   102  	go func() {
   103  		buf := make([]byte, bufLen)
   104  		res := make([]byte, bufLen)
   105  		for i := 0; i < repeats; i++ {
   106  			n, from, err := nodeA.ReadFrom(buf)
   107  			if err != nil {
   108  				t.Error(err)
   109  				return
   110  			}
   111  			if n != bufLen {
   112  				t.Error("missing data")
   113  				return
   114  			}
   115  			copy(res, buf)
   116  			copy(res[8:24], buf[24:40])
   117  			copy(res[24:40], buf[8:24])
   118  			_, err = nodeA.WriteTo(res, from)
   119  			if err != nil {
   120  				t.Error(err)
   121  			}
   122  		}
   123  		done <- struct{}{}
   124  	}()
   125  
   126  	return done
   127  }
   128  
   129  // TestCore_Start_Connect checks if two nodes can connect together.
   130  func TestCore_Start_Connect(t *testing.T) {
   131  	CreateAndConnectTwo(t, true)
   132  }
   133  
   134  // TestCore_Start_Transfer checks that messages can be passed between nodes (in both directions).
   135  func TestCore_Start_Transfer(t *testing.T) {
   136  	nodeA, nodeB := CreateAndConnectTwo(t, true)
   137  	defer nodeA.Stop()
   138  	defer nodeB.Stop()
   139  
   140  	msgLen := 1500
   141  	done := CreateEchoListener(t, nodeA, msgLen, 1)
   142  
   143  	if !WaitConnected(nodeA, nodeB) {
   144  		t.Fatal("nodes did not connect")
   145  	}
   146  
   147  	// Send
   148  	msg := make([]byte, msgLen)
   149  	_, _ = rand.Read(msg[40:])
   150  	msg[0] = 0x60
   151  	copy(msg[8:24], nodeB.Address())
   152  	copy(msg[24:40], nodeA.Address())
   153  	_, err := nodeB.WriteTo(msg, nodeA.LocalAddr())
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	buf := make([]byte, msgLen)
   158  	_, _, err = nodeB.ReadFrom(buf)
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	if !bytes.Equal(msg[40:], buf[40:]) {
   163  		t.Fatal("expected echo")
   164  	}
   165  	<-done
   166  }
   167  
   168  // BenchmarkCore_Start_Transfer estimates the possible transfer between nodes (in MB/s).
   169  func BenchmarkCore_Start_Transfer(b *testing.B) {
   170  	nodeA, nodeB := CreateAndConnectTwo(b, false)
   171  
   172  	msgLen := 1500 // typical MTU
   173  	done := CreateEchoListener(b, nodeA, msgLen, b.N)
   174  
   175  	if !WaitConnected(nodeA, nodeB) {
   176  		b.Fatal("nodes did not connect")
   177  	}
   178  
   179  	// Send
   180  	msg := make([]byte, msgLen)
   181  	_, _ = rand.Read(msg[40:])
   182  	msg[0] = 0x60
   183  	copy(msg[8:24], nodeB.Address())
   184  	copy(msg[24:40], nodeA.Address())
   185  
   186  	buf := make([]byte, msgLen)
   187  
   188  	b.SetBytes(int64(msgLen))
   189  	b.ResetTimer()
   190  
   191  	addr := nodeA.LocalAddr()
   192  	for i := 0; i < b.N; i++ {
   193  		_, err := nodeB.WriteTo(msg, addr)
   194  		if err != nil {
   195  			b.Fatal(err)
   196  		}
   197  		_, _, err = nodeB.ReadFrom(buf)
   198  		if err != nil {
   199  			b.Fatal(err)
   200  		}
   201  	}
   202  	<-done
   203  }