github.com/ergo-services/ergo@v1.999.224/proto/dist/proto_test.go (about) 1 package dist 2 3 import ( 4 "bytes" 5 "math/rand" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/ergo-services/ergo/etf" 11 "github.com/ergo-services/ergo/lib" 12 ) 13 14 func TestDecodeDistHeaderAtomCache(t *testing.T) { 15 c := &distConnection{} 16 c.cache = etf.NewAtomCache() 17 a1 := etf.Atom("atom1") 18 a2 := etf.Atom("atom2") 19 c.cache.In.Atoms[1034] = &a1 20 c.cache.In.Atoms[5] = &a2 21 packet := []byte{ 22 131, 68, // start dist header 23 5, 4, 137, 9, // 5 atoms and theirs flags 24 10, 5, // already cached atom ids 25 236, 3, 114, 101, 103, // atom 'reg' 26 9, 4, 99, 97, 108, 108, //atom 'call' 27 238, 13, 115, 101, 116, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, // atom 'set_get_state' 28 104, 4, 97, 6, 103, 82, 0, 0, 0, 0, 85, 0, 0, 0, 0, 2, 82, 1, 82, 2, // message... 29 104, 3, 82, 3, 103, 82, 0, 0, 0, 0, 245, 0, 0, 0, 2, 2, 30 104, 2, 82, 4, 109, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 } 36 37 cacheExpected := []etf.Atom{"atom1", "atom2", "reg", "call", "set_get_state"} 38 cacheInExpected := c.cache.In.Atoms 39 a3 := etf.Atom("reg") 40 a4 := etf.Atom("call") 41 a5 := etf.Atom("set_get_state") 42 cacheInExpected[492] = &a3 43 cacheInExpected[9] = &a4 44 cacheInExpected[494] = &a5 45 46 packetExpected := packet[34:] 47 cache, packet1, _ := c.decodeDistHeaderAtomCache(packet[2:], nil) 48 49 if !bytes.Equal(packet1, packetExpected) { 50 t.Fatal("incorrect packet") 51 } 52 53 if !reflect.DeepEqual(c.cache.In.Atoms, cacheInExpected) { 54 t.Fatal("incorrect cacheIn") 55 } 56 57 if !reflect.DeepEqual(cache, cacheExpected) { 58 t.Fatal("incorrect cache", cache) 59 } 60 61 } 62 63 func TestEncodeDistHeaderAtomCache(t *testing.T) { 64 65 b := lib.TakeBuffer() 66 defer lib.ReleaseBuffer(b) 67 68 senderAtomCache := make(map[etf.Atom]etf.CacheItem) 69 encodingAtomCache := etf.TakeEncodingAtomCache() 70 defer etf.ReleaseEncodingAtomCache(encodingAtomCache) 71 72 senderAtomCache["reg"] = etf.CacheItem{ID: 1000, Encoded: false, Name: "reg"} 73 senderAtomCache["call"] = etf.CacheItem{ID: 499, Encoded: false, Name: "call"} 74 senderAtomCache["one_more_atom"] = etf.CacheItem{ID: 199, Encoded: true, Name: "one_more_atom"} 75 senderAtomCache["yet_another_atom"] = etf.CacheItem{ID: 2, Encoded: false, Name: "yet_another_atom"} 76 senderAtomCache["extra_atom"] = etf.CacheItem{ID: 10, Encoded: true, Name: "extra_atom"} 77 senderAtomCache["potato"] = etf.CacheItem{ID: 2017, Encoded: true, Name: "potato"} 78 79 // Encoded field is ignored here 80 encodingAtomCache.Append(etf.CacheItem{ID: 499, Name: "call"}) 81 encodingAtomCache.Append(etf.CacheItem{ID: 1000, Name: "reg"}) 82 encodingAtomCache.Append(etf.CacheItem{ID: 199, Name: "one_more_atom"}) 83 encodingAtomCache.Append(etf.CacheItem{ID: 2017, Name: "potato"}) 84 85 expected := []byte{ 86 4, 185, 112, 0, // 4 atoms and theirs flags 87 243, 4, 99, 97, 108, 108, // atom call 88 232, 3, 114, 101, 103, // atom reg 89 199, // atom one_more_atom, already encoded 90 225, // atom potato, already encoded 91 92 } 93 94 l := &distConnection{} 95 l.encodeDistHeaderAtomCache(b, senderAtomCache, encodingAtomCache) 96 97 if !reflect.DeepEqual(b.B, expected) { 98 t.Fatal("incorrect value") 99 } 100 101 b.Reset() 102 encodingAtomCache.Append(etf.CacheItem{ID: 2, Name: "yet_another_atom"}) 103 104 expected = []byte{ 105 5, 49, 112, 8, // 5 atoms and theirs flags 106 243, // atom call. already encoded 107 232, // atom reg. already encoded 108 199, // atom one_more_atom. already encoded 109 225, // atom potato. already encoded 110 2, 16, 121, 101, 116, 95, // atom yet_another_atom 111 97, 110, 111, 116, 104, 101, 112 114, 95, 97, 116, 111, 109, 113 } 114 l.encodeDistHeaderAtomCache(b, senderAtomCache, encodingAtomCache) 115 116 if !reflect.DeepEqual(b.B, expected) { 117 t.Fatal("incorrect value", b.B) 118 } 119 } 120 121 func BenchmarkDecodeDistHeaderAtomCache(b *testing.B) { 122 link := &distConnection{} 123 packet := []byte{ 124 131, 68, // start dist header 125 5, 4, 137, 9, // 5 atoms and theirs flags 126 10, 5, // already cached atom ids 127 236, 3, 114, 101, 103, // atom 'reg' 128 9, 4, 99, 97, 108, 108, //atom 'call' 129 238, 13, 115, 101, 116, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, // atom 'set_get_state' 130 104, 4, 97, 6, 103, 82, 0, 0, 0, 0, 85, 0, 0, 0, 0, 2, 82, 1, 82, 2, // message... 131 104, 3, 82, 3, 103, 82, 0, 0, 0, 0, 245, 0, 0, 0, 2, 2, 132 104, 2, 82, 4, 109, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137 } 138 b.ResetTimer() 139 for i := 0; i < b.N; i++ { 140 link.decodeDistHeaderAtomCache(packet[2:], nil) 141 } 142 } 143 144 func BenchmarkEncodeDistHeaderAtomCache(b *testing.B) { 145 link := &distConnection{} 146 buf := lib.TakeBuffer() 147 defer lib.ReleaseBuffer(buf) 148 149 senderAtomCache := make(map[etf.Atom]etf.CacheItem) 150 encodingAtomCache := etf.TakeEncodingAtomCache() 151 defer etf.ReleaseEncodingAtomCache(encodingAtomCache) 152 153 senderAtomCache["reg"] = etf.CacheItem{ID: 1000, Encoded: false, Name: "reg"} 154 senderAtomCache["call"] = etf.CacheItem{ID: 499, Encoded: false, Name: "call"} 155 senderAtomCache["one_more_atom"] = etf.CacheItem{ID: 199, Encoded: true, Name: "one_more_atom"} 156 senderAtomCache["yet_another_atom"] = etf.CacheItem{ID: 2, Encoded: false, Name: "yet_another_atom"} 157 senderAtomCache["extra_atom"] = etf.CacheItem{ID: 10, Encoded: true, Name: "extra_atom"} 158 senderAtomCache["potato"] = etf.CacheItem{ID: 2017, Encoded: true, Name: "potato"} 159 160 // Encoded field is ignored here 161 encodingAtomCache.Append(etf.CacheItem{ID: 499, Name: "call"}) 162 encodingAtomCache.Append(etf.CacheItem{ID: 1000, Name: "reg"}) 163 encodingAtomCache.Append(etf.CacheItem{ID: 199, Name: "one_more_atom"}) 164 encodingAtomCache.Append(etf.CacheItem{ID: 2017, Name: "potato"}) 165 b.ResetTimer() 166 for i := 0; i < b.N; i++ { 167 link.encodeDistHeaderAtomCache(buf, senderAtomCache, encodingAtomCache) 168 } 169 } 170 171 func TestDecodeFragment(t *testing.T) { 172 link := &distConnection{} 173 174 link.checkCleanTimeout = 50 * time.Millisecond 175 link.checkCleanDeadline = 150 * time.Millisecond 176 link.fragments = make(map[uint64]*fragmentedPacket) 177 178 // decode fragment with fragmentID=0 should return error 179 fragment0 := []byte{protoDistFragment1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3} 180 if _, e := link.decodeFragment(fragment0, nil); e == nil { 181 t.Fatal("should be error here") 182 } 183 184 fragment1 := []byte{protoDistFragment1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 2, 3} 185 fragment2 := []byte{protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 2, 4, 5, 6} 186 fragment3 := []byte{protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 7, 8, 9} 187 188 expected := []byte{68, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 189 190 // add first fragment 191 if x, e := link.decodeFragment(fragment1, nil); x != nil || e != nil { 192 t.Fatal("should be nil here", x, e) 193 } 194 // add second one 195 if x, e := link.decodeFragment(fragment2, nil); x != nil || e != nil { 196 t.Fatal("should be nil here", e) 197 } 198 // add the last one. should return *lib.Buffer with assembled packet 199 if x, e := link.decodeFragment(fragment3, nil); x == nil || e != nil { 200 t.Fatal("shouldn't be nil here", e) 201 } else { 202 // x should be *lib.Buffer 203 if !reflect.DeepEqual(expected, x.B) { 204 t.Fatal("exp:", expected, "got:", x.B) 205 } 206 lib.ReleaseBuffer(x) 207 208 // map of the fragments should be empty here 209 if len(link.fragments) > 0 { 210 t.Fatal("fragments should be empty") 211 } 212 } 213 214 link.checkCleanTimeout = 50 * time.Millisecond 215 link.checkCleanDeadline = 150 * time.Millisecond 216 // test lost fragment 217 // add the first fragment and wait 160ms 218 if x, e := link.decodeFragment(fragment1, nil); x != nil || e != nil { 219 t.Fatal("should be nil here", e) 220 } 221 if len(link.fragments) == 0 { 222 t.Fatal("fragments should have a record ") 223 } 224 // check and clean process should remove this record 225 time.Sleep(360 * time.Millisecond) 226 227 // map of the fragments should be empty here 228 if len(link.fragments) > 0 { 229 t.Fatal("fragments should be empty") 230 } 231 232 link.checkCleanTimeout = 0 233 link.checkCleanDeadline = 0 234 fragments := [][]byte{ 235 {protoDistFragment1, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 9, 0, 1, 2, 3}, 236 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 8, 4, 5, 6}, 237 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, 8, 9}, 238 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 6, 10, 11, 12}, 239 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 5, 13, 14, 15}, 240 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 4, 16, 17, 18}, 241 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 3, 19, 20, 21}, 242 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 2, 22, 23, 24}, 243 {protoDistFragmentN, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 25, 26, 27}, 244 } 245 expected = []byte{68, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} 246 247 fragmentsReverse := make([][]byte, len(fragments)) 248 l := len(fragments) 249 for i := 0; i < l; i++ { 250 fragmentsReverse[l-i-1] = fragments[i] 251 } 252 253 var result *lib.Buffer 254 var e error 255 for i := range fragmentsReverse { 256 if result, e = link.decodeFragment(fragmentsReverse[i], nil); e != nil { 257 t.Fatal(e) 258 } 259 260 } 261 if result == nil { 262 t.Fatal("got nil result") 263 } 264 if !reflect.DeepEqual(expected, result.B) { 265 t.Fatal("exp:", expected, "got:", result.B[:len(expected)]) 266 } 267 // map of the fragments should be empty here 268 if len(link.fragments) > 0 { 269 t.Fatal("fragments should be empty") 270 } 271 272 // reshuffling 100 times 273 for k := 0; k < 100; k++ { 274 result = nil 275 fragmentsShuffle := make([][]byte, l) 276 rand.Seed(time.Now().UnixNano()) 277 for i, v := range rand.Perm(l) { 278 fragmentsShuffle[v] = fragments[i] 279 } 280 281 for i := range fragmentsShuffle { 282 if result, e = link.decodeFragment(fragmentsShuffle[i], nil); e != nil { 283 t.Fatal(e) 284 } 285 286 } 287 if result == nil { 288 t.Fatal("got nil result") 289 } 290 if !reflect.DeepEqual(expected, result.B) { 291 t.Fatal("exp:", expected, "got:", result.B[:len(expected)]) 292 } 293 } 294 }