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 }